From 063d8b2057d7e3dec274cff5c41a4c3c0423610c Mon Sep 17 00:00:00 2001 From: Domen Grabec Date: Thu, 4 Apr 2024 22:44:40 +0200 Subject: [PATCH 001/273] initial commit of the native staking strategy --- .../contracts/interfaces/ISSVNetwork.sol | 173 +++++++++++++++ contracts/contracts/proxies/Proxies.sol | 14 ++ .../NativeStaking/FeeAccumulator.sol | 51 +++++ .../NativeStakingSSVStrategy.sol | 205 ++++++++++++++++++ contracts/deploy/091_native_ssv_staking.js | 118 ++++++++++ .../strategies/nativeSsvStaking.fork-test.js | 43 ++++ contracts/utils/addresses.js | 4 + 7 files changed, 608 insertions(+) create mode 100644 contracts/contracts/interfaces/ISSVNetwork.sol create mode 100644 contracts/contracts/strategies/NativeStaking/FeeAccumulator.sol create mode 100644 contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol create mode 100644 contracts/deploy/091_native_ssv_staking.js create mode 100644 contracts/test/strategies/nativeSsvStaking.fork-test.js diff --git a/contracts/contracts/interfaces/ISSVNetwork.sol b/contracts/contracts/interfaces/ISSVNetwork.sol new file mode 100644 index 0000000000..12177b8b8c --- /dev/null +++ b/contracts/contracts/interfaces/ISSVNetwork.sol @@ -0,0 +1,173 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +struct Cluster { + uint32 validatorCount; + uint64 networkFeeIndex; + uint64 index; + bool active; + uint256 balance; +} + +interface ISSVNetwork { + error ApprovalNotWithinTimeframe(); + error CallerNotOwner(); + error CallerNotWhitelisted(); + error ClusterAlreadyEnabled(); + error ClusterDoesNotExists(); + error ClusterIsLiquidated(); + error ClusterNotLiquidatable(); + error ExceedValidatorLimit(); + error FeeExceedsIncreaseLimit(); + error FeeIncreaseNotAllowed(); + error FeeTooHigh(); + error FeeTooLow(); + error IncorrectClusterState(); + error IncorrectValidatorState(); + error InsufficientBalance(); + error InvalidOperatorIdsLength(); + error InvalidPublicKeyLength(); + error MaxValueExceeded(); + error NewBlockPeriodIsBelowMinimum(); + error NoFeeDeclared(); + error NotAuthorized(); + error OperatorAlreadyExists(); + error OperatorDoesNotExist(); + error OperatorsListNotUnique(); + error SameFeeChangeNotAllowed(); + error TargetModuleDoesNotExist(); + error TokenTransferFailed(); + error UnsortedOperatorsList(); + error ValidatorAlreadyExists(); + error ValidatorDoesNotExist(); + + event AdminChanged(address previousAdmin, address newAdmin); + event BeaconUpgraded(address indexed beacon); + event ClusterDeposited(address indexed owner, uint64[] operatorIds, uint256 value, Cluster cluster); + event ClusterLiquidated(address indexed owner, uint64[] operatorIds, Cluster cluster); + event ClusterReactivated(address indexed owner, uint64[] operatorIds, Cluster cluster); + event ClusterWithdrawn(address indexed owner, uint64[] operatorIds, uint256 value, Cluster cluster); + event DeclareOperatorFeePeriodUpdated(uint64 value); + event ExecuteOperatorFeePeriodUpdated(uint64 value); + event FeeRecipientAddressUpdated(address indexed owner, address recipientAddress); + event Initialized(uint8 version); + event LiquidationThresholdPeriodUpdated(uint64 value); + event MinimumLiquidationCollateralUpdated(uint256 value); + event NetworkEarningsWithdrawn(uint256 value, address recipient); + event NetworkFeeUpdated(uint256 oldFee, uint256 newFee); + event OperatorAdded(uint64 indexed operatorId, address indexed owner, bytes publicKey, uint256 fee); + event OperatorFeeDeclarationCancelled(address indexed owner, uint64 indexed operatorId); + event OperatorFeeDeclared(address indexed owner, uint64 indexed operatorId, uint256 blockNumber, uint256 fee); + event OperatorFeeExecuted(address indexed owner, uint64 indexed operatorId, uint256 blockNumber, uint256 fee); + event OperatorFeeIncreaseLimitUpdated(uint64 value); + event OperatorMaximumFeeUpdated(uint64 maxFee); + event OperatorRemoved(uint64 indexed operatorId); + event OperatorWhitelistUpdated(uint64 indexed operatorId, address whitelisted); + event OperatorWithdrawn(address indexed owner, uint64 indexed operatorId, uint256 value); + event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner); + event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + event Upgraded(address indexed implementation); + event ValidatorAdded(address indexed owner, uint64[] operatorIds, bytes publicKey, bytes shares, Cluster cluster); + event ValidatorExited(address indexed owner, uint64[] operatorIds, bytes publicKey); + event ValidatorRemoved(address indexed owner, uint64[] operatorIds, bytes publicKey, Cluster cluster); + + fallback() external; + + function acceptOwnership() external; + + function cancelDeclaredOperatorFee(uint64 operatorId) external; + + function declareOperatorFee(uint64 operatorId, uint256 fee) external; + + function deposit( + address clusterOwner, + uint64[] memory operatorIds, + uint256 amount, + Cluster memory cluster + ) + external; + + function executeOperatorFee(uint64 operatorId) external; + + function exitValidator(bytes memory publicKey, uint64[] memory operatorIds) external; + + function getVersion() external pure returns (string memory version); + + function initialize( + address token_, + address ssvOperators_, + address ssvClusters_, + address ssvDAO_, + address ssvViews_, + uint64 minimumBlocksBeforeLiquidation_, + uint256 minimumLiquidationCollateral_, + uint32 validatorsPerOperatorLimit_, + uint64 declareOperatorFeePeriod_, + uint64 executeOperatorFeePeriod_, + uint64 operatorMaxFeeIncrease_ + ) + external; + + function liquidate(address clusterOwner, uint64[] memory operatorIds, Cluster memory cluster) external; + + function owner() external view returns (address); + + function pendingOwner() external view returns (address); + + function proxiableUUID() external view returns (bytes32); + + function reactivate(uint64[] memory operatorIds, uint256 amount, Cluster memory cluster) external; + + function reduceOperatorFee(uint64 operatorId, uint256 fee) external; + + function registerOperator(bytes memory publicKey, uint256 fee) external returns (uint64 id); + + function registerValidator( + bytes memory publicKey, + uint64[] memory operatorIds, + bytes memory sharesData, + uint256 amount, + Cluster memory cluster + ) + external; + + function removeOperator(uint64 operatorId) external; + + function removeValidator(bytes memory publicKey, uint64[] memory operatorIds, Cluster memory cluster) external; + + function renounceOwnership() external; + + function setFeeRecipientAddress(address recipientAddress) external; + + function setOperatorWhitelist(uint64 operatorId, address whitelisted) external; + + function transferOwnership(address newOwner) external; + + function updateDeclareOperatorFeePeriod(uint64 timeInSeconds) external; + + function updateExecuteOperatorFeePeriod(uint64 timeInSeconds) external; + + function updateLiquidationThresholdPeriod(uint64 blocks) external; + + function updateMaximumOperatorFee(uint64 maxFee) external; + + function updateMinimumLiquidationCollateral(uint256 amount) external; + + function updateModule(uint8 moduleId, address moduleAddress) external; + + function updateNetworkFee(uint256 fee) external; + + function updateOperatorFeeIncreaseLimit(uint64 percentage) external; + + function upgradeTo(address newImplementation) external; + + function upgradeToAndCall(address newImplementation, bytes memory data) external payable; + + function withdraw(uint64[] memory operatorIds, uint256 amount, Cluster memory cluster) external; + + function withdrawAllOperatorEarnings(uint64 operatorId) external; + + function withdrawNetworkEarnings(uint256 amount) external; + + function withdrawOperatorEarnings(uint64 operatorId, uint256 amount) external; +} diff --git a/contracts/contracts/proxies/Proxies.sol b/contracts/contracts/proxies/Proxies.sol index b564900de9..b69a4ce3b9 100644 --- a/contracts/contracts/proxies/Proxies.sol +++ b/contracts/contracts/proxies/Proxies.sol @@ -209,3 +209,17 @@ contract OETHBuybackProxy is InitializeGovernedUpgradeabilityProxy { contract BridgedWOETHProxy is InitializeGovernedUpgradeabilityProxy { } + +/** + * @notice NativeStakingSSVStrategyProxy delegates calls to NativeStakingSSVStrategy implementation + */ +contract NativeStakingSSVStrategyProxy is InitializeGovernedUpgradeabilityProxy { + +} + +/** + * @notice NativeStakingFeeAccumulatorProxy delegates calls to NativeStakingFeeCollector implementation + */ +contract NativeStakingFeeAccumulatorProxy is InitializeGovernedUpgradeabilityProxy { + +} diff --git a/contracts/contracts/strategies/NativeStaking/FeeAccumulator.sol b/contracts/contracts/strategies/NativeStaking/FeeAccumulator.sol new file mode 100644 index 0000000000..0a73bf4d44 --- /dev/null +++ b/contracts/contracts/strategies/NativeStaking/FeeAccumulator.sol @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import { Governable } from "../../governance/Governable.sol"; +import { IWETH9 } from "../../interfaces/IWETH9.sol"; + +/** + * @title Fee Accumulator for Native Staking SSV Strategy + * @notice This contract is setup to receive fees from processing transactions on the beacon chain + * which includes priority fees and any MEV rewards + * @author Origin Protocol Inc + */ +contract FeeAccumulator is Governable { + /// @dev ETH is sent to the collector address + address public immutable COLLECTOR; + /// @notice WETH token address + address public immutable WETH_TOKEN_ADDRESS; + + error CallerNotCollector(address caller, address expectedCaller); + + // For future use + uint256[50] private __gap; + + /** + * @param _collector Address of the contract that collects the fees + */ + constructor(address _collector, address _weth) + { + COLLECTOR = _collector; + WETH_TOKEN_ADDRESS = _weth; + } + + /* + * @notice Asserts that the caller is the collector + */ + function _assertIsCollector() internal view { + if(msg.sender != COLLECTOR) { + revert CallerNotCollector(msg.sender, COLLECTOR); + } + } + + /* + * @notice Send all the ETH to the collector + */ + function collect() external returns (uint256 wethReturned) { + _assertIsCollector(); + wethReturned = address(this).balance; + IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: wethReturned}(); + IWETH9(WETH_TOKEN_ADDRESS).transfer(COLLECTOR, wethReturned); + } +} diff --git a/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol b/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol new file mode 100644 index 0000000000..4b807e7460 --- /dev/null +++ b/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol @@ -0,0 +1,205 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; + +import { InitializableAbstractStrategy } from "../../utils/InitializableAbstractStrategy.sol"; +import { IWETH9 } from "../../interfaces/IWETH9.sol"; +import { FeeAccumulator } from "./FeeAccumulator.sol"; + +/** + * @title Native Staking SSV Strategy + * @notice Strategy to deploy funds into DVT validators powered by the SSV Network + * @author Origin Protocol Inc + */ +contract NativeStakingSSVStrategy is InitializableAbstractStrategy { + using SafeERC20 for IERC20; + /// @dev The Wrapped ETH (WETH) contract address + address public immutable WETH_TOKEN_ADDRESS; + /// @dev SSV ERC20 token that serves as a payment for operating SSV validators + address public immutable SSV_TOKEN_ADDRESS; + /// @dev SSV Network contract used to interface with + address public immutable SSV_NETWORK_ADDRESS; + /// @dev Fee collector address + address public immutable FEE_ACCUMULATOR_ADDRESS; + + // For future use + uint256[50] private __gap; + + error EmptyDeposit(); + error EmptyWithdrawal(); + error EmptyRecipient(); + + /** + * @param _baseConfig Base strategy config with platformAddress (ERC-4626 Vault contract), eg sfrxETH or sDAI, + * and vaultAddress (OToken Vault contract), eg VaultProxy or OETHVaultProxy + * @param _wethAddress Address of the Erc20 WETH Token contract + * @param _ssvToken Address of the Erc20 SSV Token contract + * @param _ssvNetwork Address of the SSV Network contract + */ + constructor(BaseStrategyConfig memory _baseConfig, address _wethAddress, address _ssvToken, address _ssvNetwork, address _feeAccumulator) + InitializableAbstractStrategy(_baseConfig) + { + WETH_TOKEN_ADDRESS = _wethAddress; + SSV_TOKEN_ADDRESS = _ssvToken; + SSV_NETWORK_ADDRESS = _ssvNetwork; + FEE_ACCUMULATOR_ADDRESS = _feeAccumulator; + } + + /** + * @notice initialize function, to set up initial internal state + * @param _rewardTokenAddresses Address of reward token for platform + * @param _assets Addresses of initial supported assets + * @param _pTokens Platform Token corresponding addresses + */ + function initialize( + address[] memory _rewardTokenAddresses, + address[] memory _assets, + address[] memory _pTokens + ) external onlyGovernor initializer { + InitializableAbstractStrategy._initialize( + _rewardTokenAddresses, + _assets, + _pTokens + ); + } + + /** + * @notice Collect accumulated WETH & SSV tokens and send to the Harvester. + */ + function collectRewardTokens() + external + virtual + override + onlyHarvester + nonReentrant + { + // collect ETH from fee collector and wrap it into WETH + uint256 ethCollected = FeeAccumulator(FEE_ACCUMULATOR_ADDRESS).collect(); + IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: ethCollected }(); + _collectRewardTokens(); + } + + /** + * @notice Deposit asset into the underlying platform + * @param _asset Address of asset to deposit + * @param _amount Amount of assets to deposit + */ + function deposit(address _asset, uint256 _amount) + external + override + onlyVault + nonReentrant + { + + _deposit(_asset, _amount); + } + + /** + * @dev Deposit WETH to this contract to enable automated action to stake it + * @param _asset Address of WETH + * @param _amount Amount of WETH to deposit + */ + function _deposit(address _asset, uint256 _amount) internal { + if (_amount == 0) { + revert EmptyDeposit(); + } + /* + * We could do a check here that would revert when "_amount % 32 ether != 0". With the idea of + * not allowing deposits that will result in WETH sitting on the strategy after all the possible batches + * of 32ETH have been staked. But someone could DOS our strategy by sending some WETH dust to it. + * for that reason the check is left out. + * + * WETH sitting on the strategy won't interfere with the accounting since accounting only operates on ETH. + */ + emit Deposit(_asset, address(0), _amount); + } + + /** + * @notice Deposit the entire balance of WETH asset in the strategy into the underlying platform + */ + function depositAll() external override onlyVault nonReentrant { + uint256 wethBalance = IERC20(WETH_TOKEN_ADDRESS).balanceOf(address(this)); + if (wethBalance > 0) { + _deposit(WETH_TOKEN_ADDRESS, wethBalance); + } + } + + /** + * @notice Withdraw WETH from this contract. Used only if some WETH for is lingering on the contract. That + * can happen when: + * - the deposit was not a multiple of 32 WETH + * - someone sent WETH directly to this contract + * @param _recipient Address to receive withdrawn assets + * @param _asset WETH to withdraw + * @param _amount Amount of WETH to withdraw + */ + function withdraw( + address _recipient, + address _asset, + uint256 _amount + ) external override onlyVault nonReentrant { + _withdraw(_recipient, _asset, _amount); + } + + function _withdraw( + address _recipient, + address _asset, + uint256 _amount + ) internal { + if (_amount == 0) { + revert EmptyWithdrawal(); + } + if (_recipient == address(0)) { + revert EmptyRecipient(); + } + + emit Withdrawal(_asset, address(0), _amount); + IERC20(_asset).safeTransfer(_recipient, _amount); + } + + + /** + * @notice Remove all supported assets from the underlying platform and send them to Vault contract. + */ + function withdrawAll() external override onlyVaultOrGovernor nonReentrant { + uint256 wethBalance = IERC20(WETH_TOKEN_ADDRESS).balanceOf(address(this)); + if (wethBalance > 0) { + _withdraw(vaultAddress, WETH_TOKEN_ADDRESS, wethBalance); + } + } + + function _abstractSetPToken(address _asset, address) internal override {} + + /** + * @notice Get the total asset value held in the underlying platform + * This includes any interest that was generated since depositing. + * The exchange rate between the cToken and asset gradually increases, + * causing the cToken to be worth more corresponding asset. + * @param _asset Address of the asset + * @return balance Total value of the asset in the platform + */ + function checkBalance(address _asset) + external + view + override + returns (uint256 balance) + { + balance = 0; + } + + + /** + * @dev Retuns bool indicating whether asset is supported by strategy + * @param _asset Address of the asset + */ + function supportsAsset(address _asset) public view override returns (bool) { + return _asset == WETH_TOKEN_ADDRESS; + } + + /** + * @notice Approve the spending of all assets + */ + function safeApproveAllTokens() external override {} +} diff --git a/contracts/deploy/091_native_ssv_staking.js b/contracts/deploy/091_native_ssv_staking.js new file mode 100644 index 0000000000..068ca1d760 --- /dev/null +++ b/contracts/deploy/091_native_ssv_staking.js @@ -0,0 +1,118 @@ +const { deploymentWithGovernanceProposal } = require("../utils/deploy"); +const addresses = require("../utils/addresses"); + +module.exports = deploymentWithGovernanceProposal( + { + deployName: "091_native_ssv_staking", + forceDeploy: false, + //forceSkip: true, + deployerIsProposer: false, + // proposalId: + // "", + }, + async ({ deployWithConfirmation, ethers, getTxOpts, withConfirmation }) => { + const { deployerAddr } = await getNamedAccounts(); + const sDeployer = await ethers.provider.getSigner(deployerAddr); + + // Current contracts + const cVaultProxy = await ethers.getContract("OETHVaultProxy"); + const cVaultAdmin = await ethers.getContractAt( + "VaultAdmin", + cVaultProxy.address + ); + + // Deployer Actions + // ---------------- + + // 1. Deploy the new strategy proxy + const dStrategyProxy = await deployWithConfirmation( + "NativeStakingSSVStrategyProxy" + ); + const cStrategyProxy = await ethers.getContractAt( + "NativeStakingSSVStrategyProxy", + dStrategyProxy.address + ); + + // 2. Deploy the new fee accumulator proxy + const dFeeAccumulatorProxy = await deployWithConfirmation( + "NativeStakingFeeAccumulatorProxy" + ); + const cFeeAccumulatorProxy = await ethers.getContractAt( + "NativeStakingFeeAccumulatorProxy", + dFeeAccumulatorProxy.address + ); + + // 3. Deploy the new strategy implementation + const dStrategyImpl = await deployWithConfirmation("NativeStakingSSVStrategy", [ + [addresses.zero, cVaultProxy.address], //_baseConfig + addresses.mainnet.WETH, // wethAddress + addresses.mainnet.SSV, // ssvToken + addresses.mainnet.SsvNetwork, // ssvNetwork + dFeeAccumulatorProxy.address // feeAccumulator + ]); + const cStrategyImpl = await ethers.getContractAt( + "NativeStakingSSVStrategy", + dStrategyImpl.address + ); + + // 3. Initialize Proxy with new implementation and strategy initialization + const initData = cStrategyImpl.interface.encodeFunctionData( + "initialize(address[],address[],address[])", + [ + [addresses.mainnet.WETH, addresses.mainnet.SSV], // reward token addresses + /* no need to specify WETH as an asset, since we have that overriden in the "supportsAsset" + * function on the strategy + */ + [], // asset token addresses + [], // platform tokens addresses + ] + ); + + // 4. Init the proxy to point at the implementation, set the governor, and call initialize + const proxyInitFunction = "initialize(address,address,bytes)"; + await withConfirmation( + cStrategyProxy.connect(sDeployer)[proxyInitFunction]( + cStrategyImpl.address, // implementation address + addresses.mainnet.Timelock, // governance + initData, // data for call to the initialize function on the strategy + await getTxOpts() + ) + ); + + // 5. Deploy the new fee accumulator implementation + const dFeeAccumulator = await deployWithConfirmation("FeeAccumulator", [ + cStrategyProxy.address, // _collector + addresses.mainnet.WETH // _weth + ]); + const cFeeAccumulator = await ethers.getContractAt( + "FeeAccumulator", + dFeeAccumulator.address + ); + + // 6. Init the fee accumulator proxy to point at the implementation, set the governor + await withConfirmation( + cFeeAccumulatorProxy.connect(sDeployer)[proxyInitFunction]( + cFeeAccumulator.address, // implementation address + addresses.mainnet.Timelock, // governance + "0x", // do not call any initialize functions + await getTxOpts() + ) + ); + + console.log("Native Staking SSV Strategy address: ", cStrategyProxy.address); + + // Governance Actions + // ---------------- + return { + name: "Deploy new OETH FrxEth Redeem Strategy\n\nThis proposal adds a new FrxEth Redeem Strategy to the OETH vault. The strategy will be used to convert FrxEth tokens to Eth during transition from a multi-asset OETH to simplifed OETH backed only by ETH.", + actions: [ + // 1. Add new strategy to vault + { + contract: cVaultAdmin, + signature: "approveStrategy(address)", + args: [cStrategyProxy.address], + }, + ], + }; + } +); diff --git a/contracts/test/strategies/nativeSsvStaking.fork-test.js b/contracts/test/strategies/nativeSsvStaking.fork-test.js new file mode 100644 index 0000000000..0b30013655 --- /dev/null +++ b/contracts/test/strategies/nativeSsvStaking.fork-test.js @@ -0,0 +1,43 @@ +const hre = require("hardhat"); +const { expect } = require("chai"); + +const { units, oethUnits, isCI } = require("../helpers"); + +const { + createFixtureLoader, + //fraxETHStrategyFixture, +} = require("./../_fixture"); +const { impersonateAndFund } = require("../../utils/signers"); +const { setERC20TokenBalance } = require("../_fund"); + +//const loadFixture = createFixtureLoader(fraxETHStrategyFixture); + +describe("ForkTest: Native SSV Staking Strategy", function () { + this.timeout(0); + + // Retry up to 3 times on CI + this.retries(isCI ? 3 : 0); + + let fixture; + beforeEach(async () => { + fixture = await loadFixture(); + }); + + describe("Initial setup", function () { + // this needs to be a unit test + it.skip("Should not allow sending of ETH to the strategy via a transaction", async () => { + + }); + }); + + describe("Deposit/Allocation", function () { + + }); + + describe("Withdraw", function () { + + }); + + describe("Balance/Assets", function () { + }); +}); diff --git a/contracts/utils/addresses.js b/contracts/utils/addresses.js index 9cb338e9bd..968c3dfa1a 100644 --- a/contracts/utils/addresses.js +++ b/contracts/utils/addresses.js @@ -240,6 +240,10 @@ addresses.mainnet.FrxEthWethDualOracle = addresses.mainnet.CurveTriPool = "0x4ebdf703948ddcea3b11f675b4d1fba9d2414a14"; addresses.mainnet.CurveCVXPool = "0xB576491F1E6e5E62f1d8F26062Ee822B40B0E0d4"; +// SSV network +addresses.mainnet.SSV = "0x9D65fF81a3c488d585bBfb0Bfe3c7707c7917f54"; +addresses.mainnet.SsvNetwork = "0xDD9BC35aE942eF0cFa76930954a156B3fF30a4E1"; + // Arbitrum One addresses.arbitrumOne = {}; addresses.arbitrumOne.WOETHProxy = "0xD8724322f44E5c58D7A815F542036fb17DbbF839"; From 6e8332b004c77c0ab1f31d65c30431b7abb5ea1e Mon Sep 17 00:00:00 2001 From: Domen Grabec Date: Thu, 4 Apr 2024 22:47:39 +0200 Subject: [PATCH 002/273] fix text --- contracts/deploy/091_native_ssv_staking.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/contracts/deploy/091_native_ssv_staking.js b/contracts/deploy/091_native_ssv_staking.js index 068ca1d760..7f848758c2 100644 --- a/contracts/deploy/091_native_ssv_staking.js +++ b/contracts/deploy/091_native_ssv_staking.js @@ -100,11 +100,12 @@ module.exports = deploymentWithGovernanceProposal( ); console.log("Native Staking SSV Strategy address: ", cStrategyProxy.address); + console.log("Fee accumulator address: ", cFeeAccumulator.address); // Governance Actions // ---------------- return { - name: "Deploy new OETH FrxEth Redeem Strategy\n\nThis proposal adds a new FrxEth Redeem Strategy to the OETH vault. The strategy will be used to convert FrxEth tokens to Eth during transition from a multi-asset OETH to simplifed OETH backed only by ETH.", + name: "Deploy new OETH Native Staking Strategy\n\nThis is going to become the main strategy to power the reward accrual of OETH by staking ETH into SSV validators.", actions: [ // 1. Add new strategy to vault { From b933f22cfa3642263bd13ed148b98099c5d232c3 Mon Sep 17 00:00:00 2001 From: Domen Grabec Date: Wed, 10 Apr 2024 15:17:23 +0200 Subject: [PATCH 003/273] add some more functionality --- contracts/contracts/mocks/MockSSV.sol | 8 + contracts/contracts/mocks/MockSSVNetwork.sol | 6 + .../NativeStakingSSVStrategy.sol | 101 +++++++++-- .../NativeStaking/ValidatorRegistrator.sol | 92 ++++++++++ contracts/deploy/000_mock.js | 10 ++ contracts/deploy/001_core.js | 108 ++++++++++++ contracts/deploy/088_upgrade_woeth_on_arb.js | 28 --- contracts/deploy/089_1inch_buyback.js | 118 ------------- contracts/deploy/089_simplified_oeth_vault.js | 47 ----- contracts/deploy/090_disable_compound.js | 32 ---- contracts/deploy/091_native_ssv_staking.js | 27 ++- contracts/test/_fixture.js | 51 ++++++ contracts/test/_hot-deploy.js | 24 ++- contracts/test/helpers.js | 4 + contracts/test/strategies/nativeSSVStaking.js | 165 ++++++++++++++++++ .../strategies/nativeSsvStaking.fork-test.js | 21 ++- contracts/utils/addresses.js | 2 +- 17 files changed, 595 insertions(+), 249 deletions(-) create mode 100644 contracts/contracts/mocks/MockSSV.sol create mode 100644 contracts/contracts/mocks/MockSSVNetwork.sol create mode 100644 contracts/contracts/strategies/NativeStaking/ValidatorRegistrator.sol delete mode 100644 contracts/deploy/088_upgrade_woeth_on_arb.js delete mode 100644 contracts/deploy/089_1inch_buyback.js delete mode 100644 contracts/deploy/089_simplified_oeth_vault.js delete mode 100644 contracts/deploy/090_disable_compound.js create mode 100644 contracts/test/strategies/nativeSSVStaking.js diff --git a/contracts/contracts/mocks/MockSSV.sol b/contracts/contracts/mocks/MockSSV.sol new file mode 100644 index 0000000000..3ca806f2a1 --- /dev/null +++ b/contracts/contracts/mocks/MockSSV.sol @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "./MintableERC20.sol"; + +contract MockSSV is MintableERC20 { + constructor() ERC20("SSV Token", "SSV") {} +} diff --git a/contracts/contracts/mocks/MockSSVNetwork.sol b/contracts/contracts/mocks/MockSSVNetwork.sol new file mode 100644 index 0000000000..b2ef1e8509 --- /dev/null +++ b/contracts/contracts/mocks/MockSSVNetwork.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +contract MockSSVNetwork { + constructor() {} +} diff --git a/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol b/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol index 4b807e7460..27e6504c65 100644 --- a/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol +++ b/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol @@ -6,29 +6,61 @@ import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.s import { InitializableAbstractStrategy } from "../../utils/InitializableAbstractStrategy.sol"; import { IWETH9 } from "../../interfaces/IWETH9.sol"; +import { ISSVNetwork, Cluster } from "../../interfaces/ISSVNetwork.sol"; import { FeeAccumulator } from "./FeeAccumulator.sol"; +import { ValidatorRegistrator } from "./ValidatorRegistrator.sol"; + +struct ValidatorStakeData { + bytes pubkey; + bytes signature; + bytes32 depositDataRoot; +} /** * @title Native Staking SSV Strategy * @notice Strategy to deploy funds into DVT validators powered by the SSV Network * @author Origin Protocol Inc */ -contract NativeStakingSSVStrategy is InitializableAbstractStrategy { +contract NativeStakingSSVStrategy is ValidatorRegistrator, InitializableAbstractStrategy { using SafeERC20 for IERC20; - /// @dev The Wrapped ETH (WETH) contract address + + /// @notice The Wrapped ETH (WETH) contract address address public immutable WETH_TOKEN_ADDRESS; - /// @dev SSV ERC20 token that serves as a payment for operating SSV validators + /// @notice SSV ERC20 token that serves as a payment for operating SSV validators address public immutable SSV_TOKEN_ADDRESS; - /// @dev SSV Network contract used to interface with + /// @notice SSV Network contract used to interface with address public immutable SSV_NETWORK_ADDRESS; - /// @dev Fee collector address + /// @notice Fee collector address address public immutable FEE_ACCUMULATOR_ADDRESS; + /// @dev The WETH present on this contract will come from 2 sources: + /// - as a result of deposits from the VaultAdmin + /// - accounting function converting beaconChain rewards from ETH to WETH + /// + /// We need to be able to keep a separate accounting of the WETH so we understand how much we can pass oh to + /// the harvester as a consequence of rewards harvesting and how much registrator can pick up as a result of WETH + /// deposit into the strategy contract. + /// To achieve this the beacon chain rewards are accounted for using below variable, all other WETH is assumed to be + /// present as a result of a deposit. + uint256 beaconChainRewardWETH = 0; + + /// This notion page offers a good explanation of the bottom and top intervals for fuses: + /// https://www.notion.so/originprotocol/Limited-simplified-native-staking-accounting-67a217c8420d40678eb943b9da0ee77d + /// In short after dividing by 32 if the ETH remaining on the contract falls between 0 and fuseIntervalStart the accounting + /// function will treat that ETH as a Beacon Chain Reward ETH. + /// On the contrary if after dividing by 32 the ETH remaining on the contract falls between fuseIntervalEnd and 32 the + /// accounting function will treat that as a validator slashing. + /// + /// @dev start of fuse interval + uint256 fuseIntervalStart = 0; + /// @dev end of fuse interval + uint256 fuseIntervalEnd = 0; // For future use uint256[50] private __gap; - error EmptyDeposit(); - error EmptyWithdrawal(); + event FuseIntervalUpdated(uint256 oldStart, uint256 oldEnd, uint256 start, uint256 end); + + error FuseIntervalValuesIncorrect(); error EmptyRecipient(); /** @@ -65,6 +97,15 @@ contract NativeStakingSSVStrategy is InitializableAbstractStrategy { ); } + /// @notice return the WETH balance on the contract that can be used to for beacon chain + /// staking - staking on the validators. Because WETH on this contract can be present as + /// a result of deposits and beacon chain rewards this function needs to return only WETH + /// that is present due to deposits. + function getWETHBalanceEligibleForStaking() public override returns(uint256 _amount){ + // if below amount results in a negative number there is a bug with accounting + _amount = IWETH9(WETH_TOKEN_ADDRESS).balanceOf(address(this)) - beaconChainRewardWETH; + } + /** * @notice Collect accumulated WETH & SSV tokens and send to the Harvester. */ @@ -102,14 +143,13 @@ contract NativeStakingSSVStrategy is InitializableAbstractStrategy { * @param _amount Amount of WETH to deposit */ function _deposit(address _asset, uint256 _amount) internal { - if (_amount == 0) { - revert EmptyDeposit(); - } + require(_amount > 0, "Must deposit something"); /* * We could do a check here that would revert when "_amount % 32 ether != 0". With the idea of * not allowing deposits that will result in WETH sitting on the strategy after all the possible batches - * of 32ETH have been staked. But someone could DOS our strategy by sending some WETH dust to it. - * for that reason the check is left out. + * of 32ETH have been staked. + * But someone could mess with our strategy by sending some WETH to it. And we might want to deposit just + * enough WETH to add it up to 32 so it can be staked. For that reason the check is left out. * * WETH sitting on the strategy won't interfere with the accounting since accounting only operates on ETH. */ @@ -148,9 +188,7 @@ contract NativeStakingSSVStrategy is InitializableAbstractStrategy { address _asset, uint256 _amount ) internal { - if (_amount == 0) { - revert EmptyWithdrawal(); - } + require(_amount > 0, "Must withdraw something"); if (_recipient == address(0)) { revert EmptyRecipient(); } @@ -200,6 +238,37 @@ contract NativeStakingSSVStrategy is InitializableAbstractStrategy { /** * @notice Approve the spending of all assets + * @dev Approves the SSV Network contract to transfer SSV tokens for deposits + */ + function safeApproveAllTokens() external override { + /// @dev Approves the SSV Network contract to transfer SSV tokens for deposits + IERC20(SSV_TOKEN_ADDRESS).approve(SSV_NETWORK_ADDRESS, type(uint256).max); + } + + /// @dev Deposits more SSV Tokens to the SSV Network contract which is used to pay the SSV Operators + /// A SSV cluster is defined by the SSVOwnerAddress and the set of operatorIds + function depositSSV(uint64[] memory operatorIds, uint256 amount, Cluster memory cluster) external { + // address SSV_NETWORK_ADDRESS = lrtConfig.getContract(LRTConstants.SSV_NETWORK); + // ISSVNetwork(SSV_NETWORK_ADDRESS).deposit(address(this), operatorIds, amount, cluster); + } + + /** + * @notice set fuse interval values */ - function safeApproveAllTokens() external override {} + function setFuseInterval(uint256 _fuseIntervalStart, uint256 _fuseIntervalEnd) external onlyGovernor { + if ( + _fuseIntervalStart > _fuseIntervalEnd || + _fuseIntervalStart >= 32 ether || + _fuseIntervalEnd >= 32 ether || + _fuseIntervalEnd - _fuseIntervalStart < 4 ether + + ) { + revert FuseIntervalValuesIncorrect(); + } + + emit FuseIntervalUpdated(fuseIntervalStart, fuseIntervalEnd, _fuseIntervalStart, _fuseIntervalEnd); + + fuseIntervalStart = _fuseIntervalStart; + fuseIntervalEnd = _fuseIntervalEnd; + } } diff --git a/contracts/contracts/strategies/NativeStaking/ValidatorRegistrator.sol b/contracts/contracts/strategies/NativeStaking/ValidatorRegistrator.sol new file mode 100644 index 0000000000..4fd377df69 --- /dev/null +++ b/contracts/contracts/strategies/NativeStaking/ValidatorRegistrator.sol @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import { Governable } from "../../governance/Governable.sol"; + +/** + * @title Registrator of the validators + * @notice This contract implements all the required functionality to register validators + * @author Origin Protocol Inc + */ +abstract contract ValidatorRegistrator is Governable { + /// @notice Address of the registrator - allowed to register, exit and remove validators + address public validatorRegistrator; + /// @notice The number of validators that have 32 (!) ETH actively deposited. When a new deposit + /// to a validator happens this number increases, when a validator exit is detected this number + /// decreases. + uint256 activeDepositedValidators; + // For future use + uint256[50] private __gap; + + event RegistratorAddressChanged(address oldAddress, address newAddress); + + /** + * @dev Throws if called by any account other than the Registrator + */ + modifier onlyRegistrator() { + require(msg.sender == validatorRegistrator, "Caller is not the Registrator"); + _; + } + + /** + * @notice Set the address of the registrator + */ + function setRegistratorAddress(address _address) external onlyGovernor { + emit RegistratorAddressChanged(validatorRegistrator, _address); + validatorRegistrator = _address; + } + + /// @notice return the WETH balance on the contract that can be used to for beacon chain + /// staking - staking on the validators + function getWETHBalanceEligibleForStaking() public virtual returns(uint256 _amount); + + // /// @notice Stakes WETH to the NDC to the Node validators + // /// @param validators A list of validator data needed to stake. + // /// The ValidatorStakeData struct contains the pubkey, signature and depositDataRoot. + // /// @dev Only accounts with the Operator role can call this function. + // function stakeEth(ValidatorStakeData[] calldata validators) external { + // // Yield from the validators will come as native ETH. + // uint256 ethBalance = address(this).balance; + // uint256 requiredETH = validators.length * 32 ether; + // if (ethBalance < requiredETH) { + // // If not enough native ETH, convert WETH to native ETH + // uint256 wethBalance = getWETHBalanceEligibleForStaking(); + // if (wethBalance + ethBalance < requiredETH) { + // revert InsufficientWETH(wethBalance + ethBalance); + // } + // // Convert WETH asset to native ETH + // IWETH(WETH_TOKEN_ADDRESS).withdraw(requiredETH - ethBalance); + // } + + // // For each validator + // for (uint256 i = 0; i < validators.length;) { + // bytes32 pubkeyHash = keccak256(validators[i].pubkey); + + // if (validatorsStaked[pubkeyHash]) { + // revert ValidatorAlreadyStaked(validators[i].pubkey); + // } + + // _stakeEth(validators[i].pubkey, validators[i].signature, validators[i].depositDataRoot); + // validatorsStaked[pubkeyHash] = true; + + // unchecked { + // ++i; + // } + // } + // } + + // /// @dev Stake WETH and ETH in NDC in EigenLayer. It calls the `stake` function on the EigenPodManager + // /// which calls `stake` on the EigenPod contract which calls `stake` on the Beacon DepositContract. + // /// @dev The public functions that call this internal function are responsible for access control. + // function _stakeEth(bytes calldata pubkey, bytes calldata signature, bytes32 depositDataRoot) internal { + // // Call the stake function in the EigenPodManager + // IEigenPodManager eigenPodManager = IEigenPodManager(lrtConfig.getContract(LRTConstants.EIGEN_POD_MANAGER)); + // eigenPodManager.stake{ value: 32 ether }(pubkey, signature, depositDataRoot); + + // // Increment the staked but not verified ETH + // stakedButNotVerifiedEth += 32 ether; + // activeDepositedValidators += 1; + + // emit ETHStaked(pubkey, 32 ether); + // } +} diff --git a/contracts/deploy/000_mock.js b/contracts/deploy/000_mock.js index 824a69f8a5..eda17e4a71 100644 --- a/contracts/deploy/000_mock.js +++ b/contracts/deploy/000_mock.js @@ -120,6 +120,16 @@ const deployMocks = async ({ getNamedAccounts, deployments }) => { from: governorAddr, }); + // Mock SSV token + await deploy("MockSSV", { + from: deployerAddr, + }); + + // Mock SSV Network + await deploy("MockSSVNetwork", { + from: deployerAddr, + }); + const dai = await ethers.getContract("MockDAI"); const usdc = await ethers.getContract("MockUSDC"); const usdt = await ethers.getContract("MockUSDT"); diff --git a/contracts/deploy/001_core.js b/contracts/deploy/001_core.js index 2577e0fd9f..d933c72540 100644 --- a/contracts/deploy/001_core.js +++ b/contracts/deploy/001_core.js @@ -646,6 +646,18 @@ const configureStrategies = async (harvesterProxy, oethHarvesterProxy) => { .connect(sGovernor) .setHarvesterAddress(oethHarvesterProxy.address) ); + + const nativeStakingSSVStrategyProxy = await ethers.getContract("NativeStakingSSVStrategyProxy"); + const nativeStakingSSVStrategy = await ethers.getContractAt( + "NativeStakingSSVStrategy", + nativeStakingSSVStrategyProxy.address + ); + + await withConfirmation( + nativeStakingSSVStrategy + .connect(sGovernor) + .setHarvesterAddress(oethHarvesterProxy.address) + ); }; const deployDripper = async () => { @@ -713,6 +725,101 @@ const deployFraxEthStrategy = async () => { return cFraxETHStrategy; }; +/** + * Deploy NativeStakingSSVStrategy + * Deploys a proxy, the actual strategy, initializes the proxy and initializes + * the strategy. + */ +const deployNativeStakingSSVStrategy = async () => { + const assetAddresses = await getAssetAddresses(deployments); + const { governorAddr, deployerAddr } = await getNamedAccounts(); + const sDeployer = await ethers.provider.getSigner(deployerAddr); + const cOETHVaultProxy = await ethers.getContract("OETHVaultProxy"); + + log("Deploy NativeStakingSSVStrategyProxy"); + const dNativeStakingSSVStrategyProxy = await deployWithConfirmation( + "NativeStakingSSVStrategyProxy" + ); + const cNativeStakingSSVStrategyProxy = await ethers.getContract( + "NativeStakingSSVStrategyProxy" + ); + + log("Deploy FeeAccumulator proxy"); + const dFeeAccumulatorProxy = await deployWithConfirmation( + "NativeStakingFeeAccumulatorProxy" + ); + const cFeeAccumulatorProxy = await ethers.getContractAt( + "NativeStakingFeeAccumulatorProxy", + dFeeAccumulatorProxy.address + ); + + + log("Deploy NativeStakingSSVStrategy"); + const dStrategyImpl = await deployWithConfirmation("NativeStakingSSVStrategy", [ + [addresses.zero, cOETHVaultProxy.address], //_baseConfig + assetAddresses.WETH, // wethAddress + assetAddresses.SSV, // ssvToken + assetAddresses.SSVNetwork, // ssvNetwork + dFeeAccumulatorProxy.address // feeAccumulator + ]); + const cStrategyImpl = await ethers.getContractAt( + "NativeStakingSSVStrategy", + dStrategyImpl.address + ); + const cStrategy = await ethers.getContractAt( + "NativeStakingSSVStrategy", + dNativeStakingSSVStrategyProxy.address + ); + + log("Deploy encode initialize function of the strategy contract"); + const initData = cStrategyImpl.interface.encodeFunctionData( + "initialize(address[],address[],address[])", + [ + [assetAddresses.WETH, assetAddresses.SSV], // reward token addresses + /* no need to specify WETH as an asset, since we have that overriden in the "supportsAsset" + * function on the strategy + */ + [], // asset token addresses + [], // platform tokens addresses + ] + ); + + log("Initialize the proxy and execute the initialize strategy function"); + await withConfirmation( + cNativeStakingSSVStrategyProxy.connect(sDeployer)["initialize(address,address,bytes)"]( + cStrategyImpl.address, // implementation address + governorAddr, // governance + initData, // data for call to the initialize function on the strategy + ) + ); + + log("Approve spending of the SSV token"); + await cStrategy + .connect(sDeployer) + .safeApproveAllTokens(); + + log("Deploy fee accumulator implementation"); + const dFeeAccumulator = await deployWithConfirmation("FeeAccumulator", [ + cNativeStakingSSVStrategyProxy.address, // _collector + assetAddresses.WETH // _weth + ]); + const cFeeAccumulator = await ethers.getContractAt( + "FeeAccumulator", + dFeeAccumulator.address + ); + + log("Init fee accumulator proxy"); + await withConfirmation( + cFeeAccumulatorProxy.connect(sDeployer)["initialize(address,address,bytes)"]( + cFeeAccumulator.address, // implementation address + governorAddr, // governance + "0x", // do not call any initialize functions + ) + ); + + return cStrategy; +}; + /** * Deploy the OracleRouter and initialise it with Chainlink sources. */ @@ -1231,6 +1338,7 @@ const main = async () => { await deployConvexStrategy(); await deployConvexOUSDMetaStrategy(); await deployConvexLUSDMetaStrategy(); + await deployNativeStakingSSVStrategy(); await deployFraxEthStrategy(); const [harvesterProxy, oethHarvesterProxy] = await deployHarvesters(); await configureVault(); diff --git a/contracts/deploy/088_upgrade_woeth_on_arb.js b/contracts/deploy/088_upgrade_woeth_on_arb.js deleted file mode 100644 index 8478268f04..0000000000 --- a/contracts/deploy/088_upgrade_woeth_on_arb.js +++ /dev/null @@ -1,28 +0,0 @@ -const { isFork } = require("../test/helpers"); -const { deployOnArb } = require("../utils/delpoy-l2"); -const { deployWithConfirmation } = require("../utils/deploy"); -const { impersonateAndFund } = require("../utils/signers"); - -module.exports = deployOnArb( - { - deployName: "088_upgrade_woeth_on_arb", - }, - async ({ ethers }) => { - const cWOETHProxy = await ethers.getContract("BridgedWOETHProxy"); - - // Deploy Bridged WOETH Token implementation - await deployWithConfirmation("BridgedWOETH", []); - - const cWOETHImpl = await ethers.getContract("BridgedWOETH"); - console.log("BridgedWOETH address:", cWOETHImpl.address); - - if (isFork) { - console.log("Simulating upgrade on fork"); - - const governorAddr = await cWOETHProxy.governor(); - const sGovernor = await impersonateAndFund(governorAddr); - - await cWOETHProxy.connect(sGovernor).upgradeTo(cWOETHImpl.address); - } - } -); diff --git a/contracts/deploy/089_1inch_buyback.js b/contracts/deploy/089_1inch_buyback.js deleted file mode 100644 index 571dd012f5..0000000000 --- a/contracts/deploy/089_1inch_buyback.js +++ /dev/null @@ -1,118 +0,0 @@ -const addresses = require("../utils/addresses"); -const { - deploymentWithGovernanceProposal, - deployWithConfirmation, -} = require("../utils/deploy"); - -module.exports = deploymentWithGovernanceProposal( - { - deployName: "089_1inch_buyback", - // forceSkip: true, - // onlyOnFork: true, // this is only executed in forked environment - // reduceQueueTime: true, // just to solve the issue of later active proposals failing - proposalId: - "19953986745691218316817489613719564552439805381746724170485904355958039770871", - }, - async ({ ethers }) => { - const cOETHBuybackProxy = await ethers.getContract("OETHBuybackProxy"); - const cOUSDBuybackProxy = await ethers.getContract("BuybackProxy"); - - const cSwapper = await ethers.getContract("Swapper1InchV5"); - - // Deploy new OETHBuyback implementation - const dOETHBuybackImpl = await deployWithConfirmation( - "OETHBuyback", - [ - addresses.mainnet.OETHProxy, - addresses.mainnet.OGV, - addresses.mainnet.CVX, - addresses.mainnet.CVXLocker, - ], - undefined, - true - ); - - // Deploy new OUSDBuyback implementation - const dOUSDBuybackImpl = await deployWithConfirmation( - "OUSDBuyback", - [ - addresses.mainnet.OUSDProxy, - addresses.mainnet.OGV, - addresses.mainnet.CVX, - addresses.mainnet.CVXLocker, - ], - undefined, - true - ); - - const cOETHBuyback = await ethers.getContractAt( - "OETHBuyback", - cOETHBuybackProxy.address - ); - const cOUSDBuyback = await ethers.getContractAt( - "OUSDBuyback", - cOUSDBuybackProxy.address - ); - - await cSwapper.approveAssets([ - addresses.mainnet.OGV, - addresses.mainnet.CVX, - addresses.mainnet.OUSDProxy, - addresses.mainnet.OETHProxy, - ]); - - return { - name: "Upgrade Buyback contracts to use 1inch", - actions: [ - // 1. Upgrade OUSD Buyback to new implementation - { - contract: cOUSDBuybackProxy, - signature: "upgradeTo(address)", - args: [dOUSDBuybackImpl.address], - }, - // 2. Update swap router address on OUSD Buyback - { - contract: cOUSDBuyback, - signature: "setSwapRouter(address)", - args: [cSwapper.address], - }, - // 3. Set splits for CVX - { - contract: cOUSDBuyback, - signature: "setCVXShareBps(uint256)", - args: [5000], // 50% - }, - // 4. Compute buyback splits - { - contract: cOUSDBuyback, - signature: "updateBuybackSplits()", - args: [], - }, - // 5. Upgrade OETH Buyback to new implementation - { - contract: cOETHBuybackProxy, - signature: "upgradeTo(address)", - args: [dOETHBuybackImpl.address], - }, - // 6. Update swap router address on OETH Buyback - { - contract: cOETHBuyback, - signature: "setSwapRouter(address)", - args: [cSwapper.address], - }, - // 7. Set splits for CVX - { - contract: cOETHBuyback, - signature: "setCVXShareBps(uint256)", - args: [5000], // 50% - }, - // 8. Compute buyback splits - { - contract: cOETHBuyback, - signature: "updateBuybackSplits()", - args: [], - }, - ], - }; - } -); diff --git a/contracts/deploy/089_simplified_oeth_vault.js b/contracts/deploy/089_simplified_oeth_vault.js deleted file mode 100644 index 59a28ba3bf..0000000000 --- a/contracts/deploy/089_simplified_oeth_vault.js +++ /dev/null @@ -1,47 +0,0 @@ -const addresses = require("../utils/addresses"); -const { - deploymentWithGovernanceProposal, - deployWithConfirmation, -} = require("../utils/deploy"); - -module.exports = deploymentWithGovernanceProposal( - { - deployName: "089_simplified_oeth_vault", - forceDeploy: false, - // forceSkip: true, - // onlyOnFork: true, // this is only executed in forked environment - // reduceQueueTime: true, // just to solve the issue of later active proposals failing - proposalId: "", - }, - async ({ ethers }) => { - const cOETHVaultProxy = await ethers.getContract("OETHVaultProxy"); - - // Deploy VaultCore implementation - await deployWithConfirmation("OETHVaultCore", [addresses.mainnet.WETH]); - const dVaultImpl = await ethers.getContract("OETHVaultCore"); - - const cOETHVault = await ethers.getContractAt( - "IVault", - addresses.mainnet.OETHVaultProxy - ); - - return { - name: "Simplified OETH mint and redeem\n\ - \n\ - Part of simplified OETH proposal. Trims down mint and redeem complexity on OETH Vault. Set redeem fees to zero. \ - ", - actions: [ - { - contract: cOETHVaultProxy, - signature: "upgradeTo(address)", - args: [dVaultImpl.address], - }, - { - contract: cOETHVault, - signature: "cacheWETHAssetIndex()", - args: [], - }, - ], - }; - } -); diff --git a/contracts/deploy/090_disable_compound.js b/contracts/deploy/090_disable_compound.js deleted file mode 100644 index 2f2fbc880d..0000000000 --- a/contracts/deploy/090_disable_compound.js +++ /dev/null @@ -1,32 +0,0 @@ -const addresses = require("../utils/addresses"); -const { deploymentWithGovernanceProposal } = require("../utils/deploy"); - -module.exports = deploymentWithGovernanceProposal( - { - deployName: "090_disable_compound", - forceDeploy: false, - // forceSkip: true, - // onlyOnFork: true, // this is only executed in forked environment - // reduceQueueTime: true, // just to solve the issue of later active proposals failing - proposalId: - "540302155888465131843465904203767906417865895567367577074989857543481682425", - }, - async ({ ethers }) => { - // Current contracts - const cVaultProxy = await ethers.getContract("VaultProxy"); - const cVault = await ethers.getContractAt("IVault", cVaultProxy.address); - - // Governance Actions - // ---------------- - return { - name: "Remove Morpho Compound Strategy from OUSD", - actions: [ - { - contract: cVault, - signature: "removeStrategy(address)", - args: [addresses.mainnet.MorphoStrategyProxy], - }, - ], - }; - } -); diff --git a/contracts/deploy/091_native_ssv_staking.js b/contracts/deploy/091_native_ssv_staking.js index 7f848758c2..ce904977bd 100644 --- a/contracts/deploy/091_native_ssv_staking.js +++ b/contracts/deploy/091_native_ssv_staking.js @@ -17,10 +17,16 @@ module.exports = deploymentWithGovernanceProposal( // Current contracts const cVaultProxy = await ethers.getContract("OETHVaultProxy"); const cVaultAdmin = await ethers.getContractAt( - "VaultAdmin", + "OETHVaultAdmin", cVaultProxy.address ); + const cHarvesterProxy = await ethers.getContract("OETHHarvesterProxy"); + const cHarvester = await ethers.getContractAt( + "OETHHarvester", + cHarvesterProxy.address + ); + // Deployer Actions // ---------------- @@ -47,13 +53,17 @@ module.exports = deploymentWithGovernanceProposal( [addresses.zero, cVaultProxy.address], //_baseConfig addresses.mainnet.WETH, // wethAddress addresses.mainnet.SSV, // ssvToken - addresses.mainnet.SsvNetwork, // ssvNetwork + addresses.mainnet.SSVNetwork, // ssvNetwork dFeeAccumulatorProxy.address // feeAccumulator ]); const cStrategyImpl = await ethers.getContractAt( "NativeStakingSSVStrategy", dStrategyImpl.address ); + const cStrategy = await ethers.getContractAt( + "NativeStakingSSVStrategy", + dStrategyProxy.address + ); // 3. Initialize Proxy with new implementation and strategy initialization const initData = cStrategyImpl.interface.encodeFunctionData( @@ -99,6 +109,9 @@ module.exports = deploymentWithGovernanceProposal( ) ); + // 7. Safe approve SSV token spending + await cStrategy.connect(sDeployer).safeApproveAllTokens(); + console.log("Native Staking SSV Strategy address: ", cStrategyProxy.address); console.log("Fee accumulator address: ", cFeeAccumulator.address); @@ -113,6 +126,16 @@ module.exports = deploymentWithGovernanceProposal( signature: "approveStrategy(address)", args: [cStrategyProxy.address], }, + { + contract: cHarvester, + signature: "setSupportedStrategy(address,bool)", + args: [cStrategyProxy.address, true], + }, + { + contract: cStrategy, + signature: "setHarvesterAddress(address)", + args: [cHarvesterProxy.address], + }, ], }; } diff --git a/contracts/test/_fixture.js b/contracts/test/_fixture.js index 1bfe4a4ecb..983a74fa2b 100644 --- a/contracts/test/_fixture.js +++ b/contracts/test/_fixture.js @@ -183,6 +183,7 @@ const defaultFixture = deployments.createFixture(async () => { LUSD, fdai, fusdt, + ssv, fusdc; let chainlinkOracleFeedDAI, @@ -224,6 +225,7 @@ const defaultFixture = deployments.createFixture(async () => { mock1InchSwapRouter, convexEthMetaStrategy, fluxStrategy, + nativeStakingSSVStrategy, vaultValueChecker, oethVaultValueChecker; @@ -261,6 +263,7 @@ const defaultFixture = deployments.createFixture(async () => { aura = await ethers.getContractAt(erc20Abi, addresses.mainnet.AURA); bal = await ethers.getContractAt(erc20Abi, addresses.mainnet.BAL); ogv = await ethers.getContractAt(erc20Abi, addresses.mainnet.OGV); + ssv = await ethers.getContractAt(erc20Abi, addresses.mainnet.SSV); crvMinter = await ethers.getContractAt( crvMinterAbi, @@ -359,6 +362,12 @@ const defaultFixture = deployments.createFixture(async () => { fluxStrategyProxy.address ); + const nativeStakingStrategyProxy = await ethers.getContract("NativeStakingSSVStrategyProxy"); + nativeStakingSSVStrategy = await ethers.getContractAt( + "NativeStakingSSVStrategy", + nativeStakingStrategyProxy.address + ); + vaultValueChecker = await ethers.getContract("VaultValueChecker"); oethVaultValueChecker = await ethers.getContract("OETHVaultValueChecker"); } else { @@ -376,6 +385,7 @@ const defaultFixture = deployments.createFixture(async () => { sDAI = await ethers.getContract("MocksfrxETH"); stETH = await ethers.getContract("MockstETH"); nonStandardToken = await ethers.getContract("MockNonStandardToken"); + ssv = await ethers.getContract("MockSSV"); cdai = await ethers.getContract("MockCDAI"); cusdt = await ethers.getContract("MockCUSDT"); @@ -456,6 +466,11 @@ const defaultFixture = deployments.createFixture(async () => { fraxEthStrategyProxy.address ); + const nativeStakingStrategyProxy = await ethers.getContract("NativeStakingSSVStrategyProxy"); + nativeStakingSSVStrategy = await ethers.getContractAt( + "NativeStakingSSVStrategy", + nativeStakingStrategyProxy.address + ); swapper = await ethers.getContract("MockSwapper"); mockSwapper = await ethers.getContract("MockSwapper"); swapper1Inch = await ethers.getContract("Swapper1InchV5"); @@ -540,6 +555,7 @@ const defaultFixture = deployments.createFixture(async () => { tusd, usdc, ogn, + ssv, LUSD, weth, ogv, @@ -603,6 +619,7 @@ const defaultFixture = deployments.createFixture(async () => { sfrxETH, sDAI, fraxEthStrategy, + nativeStakingSSVStrategy, frxEthRedeemStrategy, balancerREthStrategy, oethMorphoAaveStrategy, @@ -1385,6 +1402,39 @@ async function fraxETHStrategyFixture() { return fixture; } +/** + * NativeStakingSSVStrategy fixture + */ +async function nativeStakingSSVStrategyFixture() { + const fixture = await oethDefaultFixture(); + await hotDeployOption(fixture, "nativeStakingSSVStrategyFixture", { + isOethFixture: true, + }); + + if (isFork) { + const { oethVault, weth, nativeStakingSSVStrategy, timelock } = fixture; + await oethVault + .connect(timelock) + .setAssetDefaultStrategy(weth.address, nativeStakingSSVStrategy.address); + } else { + const { governorAddr } = await getNamedAccounts(); + const { oethVault, weth, nativeStakingSSVStrategy } = fixture; + const sGovernor = await ethers.provider.getSigner(governorAddr); + + // Approve Strategy + await oethVault.connect(sGovernor).approveStrategy(nativeStakingSSVStrategy.address); + + console.log("nativeStakingSSVStrategy.address", nativeStakingSSVStrategy.address) + + // Set as default + await oethVault + .connect(sGovernor) + .setAssetDefaultStrategy(weth.address, nativeStakingSSVStrategy.address); + } + + return fixture; +} + /** * Generalized strategy fixture that works only in forked environment * @@ -2179,6 +2229,7 @@ module.exports = { untiltBalancerMetaStableWETHPool, fraxETHStrategyFixture, frxEthRedeemStrategyFixture, + nativeStakingSSVStrategyFixture, oethMorphoAaveFixture, oeth1InchSwapperFixture, oethCollateralSwapFixture, diff --git a/contracts/test/_hot-deploy.js b/contracts/test/_hot-deploy.js index d0ba5b83ab..de1858caee 100644 --- a/contracts/test/_hot-deploy.js +++ b/contracts/test/_hot-deploy.js @@ -17,10 +17,10 @@ const { impersonateAndFund } = require("../utils/signers"); const log = require("../utils/logger")("test:fixtures:hot-deploy"); // based on a contract name create new implementation -async function constructNewContract(fixture, implContractName) { +async function constructNewContract(fixture, fixtureStrategyVarName, implContractName) { const { deploy } = deployments; - const getConstructorArguments = () => { + const getConstructorArguments = async () => { if ( ["BalancerMetaPoolTestStrategy", "BalancerMetaPoolStrategy"].includes( implContractName @@ -79,6 +79,17 @@ async function constructNewContract(fixture, implContractName) { addresses.mainnet.WETH, ], ]; + } else if (implContractName === "NativeStakingSSVStrategy") { + const feeAccumulatorAddress = await fixture[fixtureStrategyVarName].FEE_ACCUMULATOR_ADDRESS(); + return [ + [addresses.zero, addresses.mainnet.OETHVaultProxy], + [ + addresses.mainnet.WETH, + addresses.mainnet.SSV, + addresses.mainnet.SSVNetwork, + addresses.mainnet.feeAccumulatorAddress + ], + ]; } }; @@ -88,7 +99,7 @@ async function constructNewContract(fixture, implContractName) { await deploy(implContractName, { from: addresses.mainnet.Timelock, // doesn't matter which address deploys it contract: implContractName, - args: getConstructorArguments(), + args: await getConstructorArguments(), }); log(`Deployed`); @@ -147,6 +158,12 @@ async function hotDeployOption( "convexEthMetaStrategy", // fixtureStrategyVarName "ConvexEthMetaStrategy" // implContractName ); + } else if (fixtureName === "nativeStakingSSVStrategyFixture") { + await hotDeployFixture( + fixture, // fixture + "nativeStakingStrategy", // fixtureStrategyVarName + "NativeStakingSSVStrategy" // implContractName + ); } } @@ -325,6 +342,7 @@ async function hotDeployFixture( const newlyCompiledImplContract = await constructNewContract( fixture, + fixtureStrategyVarName, implContractName ); log(`New contract deployed at ${newlyCompiledImplContract.address}`); diff --git a/contracts/test/helpers.js b/contracts/test/helpers.js index a85f3dc675..8fb965b2b5 100644 --- a/contracts/test/helpers.js +++ b/contracts/test/helpers.js @@ -425,6 +425,8 @@ const getAssetAddresses = async (deployments) => { auraWeightedOraclePool: addresses.mainnet.AuraWeightedOraclePool, AURA: addresses.mainnet.AURA, BAL: addresses.mainnet.BAL, + SSV: addresses.mainnet.SSV, + SSVNetwork: addresses.mainnet.SSVNetwork, }; } else { const addressMap = { @@ -470,6 +472,8 @@ const getAssetAddresses = async (deployments) => { .address, AURA: (await deployments.get("MockAura")).address, BAL: (await deployments.get("MockBAL")).address, + SSV: (await deployments.get("MockSSV")).address, + SSVNetwork: (await deployments.get("MockSSVNetwork")).address }; try { diff --git a/contracts/test/strategies/nativeSSVStaking.js b/contracts/test/strategies/nativeSSVStaking.js new file mode 100644 index 0000000000..51068ddfa3 --- /dev/null +++ b/contracts/test/strategies/nativeSSVStaking.js @@ -0,0 +1,165 @@ +const hre = require("hardhat"); +const { expect } = require("chai"); +const ethers = require("ethers"); +const utils = ethers.utils; +const addresses = require("../../utils/addresses"); + +const { units, oethUnits, isCI } = require("../helpers"); +const { shouldBehaveLikeGovernable } = require("../behaviour/governable"); +const { shouldBehaveLikeHarvestable } = require("../behaviour/harvestable"); +const { shouldBehaveLikeStrategy } = require("../behaviour/strategy"); +const { MAX_UINT256 } = require("../../utils/constants"); + +const { + createFixtureLoader, + nativeStakingSSVStrategyFixture, +} = require("./../_fixture"); +const { impersonateAndFund } = require("../../utils/signers"); +const { setERC20TokenBalance } = require("../_fund"); + +const loadFixture = createFixtureLoader(nativeStakingSSVStrategyFixture); + +describe.only("ForkTest: Native SSV Staking Strategy", function () { + this.timeout(0); + + // Retry up to 3 times on CI + this.retries(isCI ? 3 : 0); + + let fixture; + beforeEach(async () => { + fixture = await loadFixture(); + }); + + shouldBehaveLikeGovernable(() => ({ + ...fixture, + strategy: fixture.nativeStakingSSVStrategy, + })); + + shouldBehaveLikeHarvestable(() => ({ + ...fixture, + harvester: fixture.oethHarvester, + strategy: fixture.nativeStakingSSVStrategy, + })); + + shouldBehaveLikeStrategy(() => ({ + ...fixture, + strategy: fixture.nativeStakingSSVStrategy, + assets: [fixture.weth], + valueAssets: [], + harvester: fixture.oethHarvester, + vault: fixture.oethVault, + })); + + describe("Initial setup", function () { + it("Should not allow sending of ETH to the strategy via a transaction", async () => { + const { nativeStakingSSVStrategy, strategist } = fixture; + + const signer = nativeStakingSSVStrategy.provider.getSigner(strategist.address); + tx = { + to: nativeStakingSSVStrategy.address, + value: ethers.utils.parseEther('2', 'ether') + }; + + await expect( + signer.sendTransaction(tx) + ).to.be.revertedWith("function selector was not recognized and there's no fallback nor receive function"); + }); + + it("SSV network should have allowance to spend SSV tokens of the strategy", async () => { + const { nativeStakingSSVStrategy, ssv } = fixture; + + const ssvNetworkAddress = await nativeStakingSSVStrategy.SSV_NETWORK_ADDRESS(); + await expect(await ssv.allowance(nativeStakingSSVStrategy.address, ssvNetworkAddress)).to.equal(MAX_UINT256); + }); + }); + + describe.only("Configuring the strategy", function () { + it("Governor should be able to change the registrator address", async () => { + const { nativeStakingSSVStrategy, governor, strategist } = fixture; + + const tx = await nativeStakingSSVStrategy + .connect(governor) + .setRegistratorAddress(strategist.address); + + const events = (await tx.wait()).events || []; + const RegistratorAddressChangedEvent = events.find((e) => e.event === "RegistratorAddressChanged"); + + expect(RegistratorAddressChangedEvent).to.not.be.undefined; + expect(RegistratorAddressChangedEvent.event).to.equal("RegistratorAddressChanged"); + expect(RegistratorAddressChangedEvent.args[0]).to.equal(addresses.zero); + expect(RegistratorAddressChangedEvent.args[1]).to.equal(strategist.address); + }); + + it("Non governor should not be able to change the registrator address", async () => { + const { nativeStakingSSVStrategy, governor, strategist } = fixture; + + await expect(nativeStakingSSVStrategy + .connect(strategist) + .setRegistratorAddress(strategist.address) + ).to.be.revertedWith("Caller is not the Governor"); + }); + + it("Non governor should not be able to update the fuse intervals", async () => { + const { nativeStakingSSVStrategy, governor, strategist } = fixture; + + await expect(nativeStakingSSVStrategy + .connect(strategist) + .setFuseInterval(utils.parseEther("21.6"), utils.parseEther("25.6")) + ).to.be.revertedWith("Caller is not the Governor"); + }); + + it("Fuse interval start needs to be larger than fuse end", async () => { + const { nativeStakingSSVStrategy, governor } = fixture; + + await expect(nativeStakingSSVStrategy + .connect(governor) + .setFuseInterval(utils.parseEther("25.6"), utils.parseEther("21.6")) + ).to.be.revertedWith("FuseIntervalValuesIncorrect"); + }); + + it("There should be at least 4 ETH between interval start and interval end", async () => { + const { nativeStakingSSVStrategy, governor } = fixture; + + await expect(nativeStakingSSVStrategy + .connect(governor) + .setFuseInterval(utils.parseEther("21.6"), utils.parseEther("25.5")) + ).to.be.revertedWith("FuseIntervalValuesIncorrect"); + }); + + it("Revert when fuse intervals are larger than 32 ether", async () => { + const { nativeStakingSSVStrategy, governor } = fixture; + + await expect(nativeStakingSSVStrategy + .connect(governor) + .setFuseInterval(utils.parseEther("32.1"), utils.parseEther("32.1")) + ).to.be.revertedWith("FuseIntervalValuesIncorrect"); + }); + + it("Governor should be able to change the registrator address", async () => { + const { nativeStakingSSVStrategy, governor } = fixture; + + const tx = nativeStakingSSVStrategy + .connect(governor) + .setFuseInterval(utils.parseEther("32.1"), utils.parseEther("32.1")); + + const events = (await tx.wait()).events || []; + const FuseIntervalUpdated = events.find((e) => e.event === "FuseIntervalUpdated"); + + expect(FuseIntervalUpdated).to.not.be.undefined; + expect(FuseIntervalUpdated.event).to.equal("FuseIntervalUpdated"); + expect(FuseIntervalUpdated.args[0]).to.equal(addresses.zero); + expect(FuseIntervalUpdated.args[1]).to.equal(strategist.address); + }); + }); + + describe("Deposit/Allocation", function () { + + }); + + describe("Withdraw", function () { + + }); + + describe("Balance/Assets", function () { + }); +}); diff --git a/contracts/test/strategies/nativeSsvStaking.fork-test.js b/contracts/test/strategies/nativeSsvStaking.fork-test.js index 0b30013655..a466327504 100644 --- a/contracts/test/strategies/nativeSsvStaking.fork-test.js +++ b/contracts/test/strategies/nativeSsvStaking.fork-test.js @@ -2,15 +2,16 @@ const hre = require("hardhat"); const { expect } = require("chai"); const { units, oethUnits, isCI } = require("../helpers"); +const addresses = require("../../utils/addresses"); const { createFixtureLoader, - //fraxETHStrategyFixture, + nativeStakingSSVStrategyFixture, } = require("./../_fixture"); const { impersonateAndFund } = require("../../utils/signers"); const { setERC20TokenBalance } = require("../_fund"); -//const loadFixture = createFixtureLoader(fraxETHStrategyFixture); +const loadFixture = createFixtureLoader(nativeStakingSSVStrategyFixture); describe("ForkTest: Native SSV Staking Strategy", function () { this.timeout(0); @@ -24,6 +25,22 @@ describe("ForkTest: Native SSV Staking Strategy", function () { }); describe("Initial setup", function () { + it("Should verify the initial state", async () => { + const { weth, nativeStakingSSVStrategy } = fixture; + await expect(await nativeStakingSSVStrategy.WETH_TOKEN_ADDRESS()).to.equal( + addresses.mainnet.WETH, + "Incorrect WETH address set" + ); + await expect(await nativeStakingSSVStrategy.SSV_TOKEN_ADDRESS()).to.equal( + addresses.mainnet.SSV, + "Incorrect SSV Token address" + ); + await expect(await nativeStakingSSVStrategy.SSV_NETWORK_ADDRESS()).to.equal( + addresses.mainnet.SSVNetwork, + "Incorrect SSV Network address" + ); + }); + // this needs to be a unit test it.skip("Should not allow sending of ETH to the strategy via a transaction", async () => { diff --git a/contracts/utils/addresses.js b/contracts/utils/addresses.js index 968c3dfa1a..23a3bb4be5 100644 --- a/contracts/utils/addresses.js +++ b/contracts/utils/addresses.js @@ -242,7 +242,7 @@ addresses.mainnet.CurveCVXPool = "0xB576491F1E6e5E62f1d8F26062Ee822B40B0E0d4"; // SSV network addresses.mainnet.SSV = "0x9D65fF81a3c488d585bBfb0Bfe3c7707c7917f54"; -addresses.mainnet.SsvNetwork = "0xDD9BC35aE942eF0cFa76930954a156B3fF30a4E1"; +addresses.mainnet.SSVNetwork = "0xDD9BC35aE942eF0cFa76930954a156B3fF30a4E1"; // Arbitrum One addresses.arbitrumOne = {}; From 0a43d145c85ee771919e7e91c7cee1758f5c0be1 Mon Sep 17 00:00:00 2001 From: Domen Grabec Date: Thu, 11 Apr 2024 10:01:40 +0200 Subject: [PATCH 004/273] finish up the fuse interval test, update deploy script --- contracts/deploy/091_native_ssv_staking.js | 8 ++++++++ contracts/test/strategies/nativeSSVStaking.js | 15 ++++++++++----- .../test/strategies/nativeSsvStaking.fork-test.js | 3 +-- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/contracts/deploy/091_native_ssv_staking.js b/contracts/deploy/091_native_ssv_staking.js index ce904977bd..cc2d732aa8 100644 --- a/contracts/deploy/091_native_ssv_staking.js +++ b/contracts/deploy/091_native_ssv_staking.js @@ -126,16 +126,24 @@ module.exports = deploymentWithGovernanceProposal( signature: "approveStrategy(address)", args: [cStrategyProxy.address], }, + // 2. configure Harvester to support the strategy { contract: cHarvester, signature: "setSupportedStrategy(address,bool)", args: [cStrategyProxy.address, true], }, + // 3. set harvester to the strategy { contract: cStrategy, signature: "setHarvesterAddress(address)", args: [cHarvesterProxy.address], }, + // 4. configure the fuse interval + { + contract: cStrategy, + signature: "setFuseInterval(uint256, uint256)", + args: [ethers.utils.parseEther("21.6"), ethers.utils.parseEther("25.6")], + }, ], }; } diff --git a/contracts/test/strategies/nativeSSVStaking.js b/contracts/test/strategies/nativeSSVStaking.js index 51068ddfa3..c9533e9c55 100644 --- a/contracts/test/strategies/nativeSSVStaking.js +++ b/contracts/test/strategies/nativeSSVStaking.js @@ -73,7 +73,7 @@ describe.only("ForkTest: Native SSV Staking Strategy", function () { }); }); - describe.only("Configuring the strategy", function () { + describe("Configuring the strategy", function () { it("Governor should be able to change the registrator address", async () => { const { nativeStakingSSVStrategy, governor, strategist } = fixture; @@ -138,17 +138,22 @@ describe.only("ForkTest: Native SSV Staking Strategy", function () { it("Governor should be able to change the registrator address", async () => { const { nativeStakingSSVStrategy, governor } = fixture; - const tx = nativeStakingSSVStrategy + const fuseStartBn = utils.parseEther("21.6"); + const fuseEndBn = utils.parseEther("25.6"); + + const tx = await nativeStakingSSVStrategy .connect(governor) - .setFuseInterval(utils.parseEther("32.1"), utils.parseEther("32.1")); + .setFuseInterval(fuseStartBn, fuseEndBn); const events = (await tx.wait()).events || []; const FuseIntervalUpdated = events.find((e) => e.event === "FuseIntervalUpdated"); expect(FuseIntervalUpdated).to.not.be.undefined; expect(FuseIntervalUpdated.event).to.equal("FuseIntervalUpdated"); - expect(FuseIntervalUpdated.args[0]).to.equal(addresses.zero); - expect(FuseIntervalUpdated.args[1]).to.equal(strategist.address); + expect(FuseIntervalUpdated.args[0]).to.equal(addresses.zero); // prev fuse start + expect(FuseIntervalUpdated.args[1]).to.equal(addresses.zero); // prev fuse end + expect(FuseIntervalUpdated.args[2]).to.equal(fuseStartBn); // fuse start + expect(FuseIntervalUpdated.args[3]).to.equal(fuseEndBn); // fuse end }); }); diff --git a/contracts/test/strategies/nativeSsvStaking.fork-test.js b/contracts/test/strategies/nativeSsvStaking.fork-test.js index a466327504..5b2ef52a62 100644 --- a/contracts/test/strategies/nativeSsvStaking.fork-test.js +++ b/contracts/test/strategies/nativeSsvStaking.fork-test.js @@ -41,8 +41,7 @@ describe("ForkTest: Native SSV Staking Strategy", function () { ); }); - // this needs to be a unit test - it.skip("Should not allow sending of ETH to the strategy via a transaction", async () => { + it.skip("Should check that the fuse interval is configured correctly", async () => { }); }); From d31fe30d40923d33520831089d96967779ae517e Mon Sep 17 00:00:00 2001 From: Domen Grabec Date: Thu, 11 Apr 2024 10:23:06 +0200 Subject: [PATCH 005/273] some natspec and refactoring --- .../NativeStakingSSVStrategy.sol | 153 +++++------------- .../NativeStaking/ValidatorAccountant.sol | 62 +++++++ .../NativeStaking/ValidatorRegistrator.sol | 10 +- 3 files changed, 107 insertions(+), 118 deletions(-) create mode 100644 contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol diff --git a/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol b/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol index 27e6504c65..4edcd40058 100644 --- a/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol +++ b/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol @@ -8,7 +8,7 @@ import { InitializableAbstractStrategy } from "../../utils/InitializableAbstract import { IWETH9 } from "../../interfaces/IWETH9.sol"; import { ISSVNetwork, Cluster } from "../../interfaces/ISSVNetwork.sol"; import { FeeAccumulator } from "./FeeAccumulator.sol"; -import { ValidatorRegistrator } from "./ValidatorRegistrator.sol"; +import { ValidatorAccountant } from "./ValidatorAccountant.sol"; struct ValidatorStakeData { bytes pubkey; @@ -16,12 +16,10 @@ struct ValidatorStakeData { bytes32 depositDataRoot; } -/** - * @title Native Staking SSV Strategy - * @notice Strategy to deploy funds into DVT validators powered by the SSV Network - * @author Origin Protocol Inc - */ -contract NativeStakingSSVStrategy is ValidatorRegistrator, InitializableAbstractStrategy { +/// @title Native Staking SSV Strategy +/// @notice Strategy to deploy funds into DVT validators powered by the SSV Network +/// @author Origin Protocol Inc +contract NativeStakingSSVStrategy is ValidatorAccountant, InitializableAbstractStrategy { using SafeERC20 for IERC20; /// @notice The Wrapped ETH (WETH) contract address @@ -32,44 +30,17 @@ contract NativeStakingSSVStrategy is ValidatorRegistrator, InitializableAbstract address public immutable SSV_NETWORK_ADDRESS; /// @notice Fee collector address address public immutable FEE_ACCUMULATOR_ADDRESS; - /// @dev The WETH present on this contract will come from 2 sources: - /// - as a result of deposits from the VaultAdmin - /// - accounting function converting beaconChain rewards from ETH to WETH - /// - /// We need to be able to keep a separate accounting of the WETH so we understand how much we can pass oh to - /// the harvester as a consequence of rewards harvesting and how much registrator can pick up as a result of WETH - /// deposit into the strategy contract. - /// To achieve this the beacon chain rewards are accounted for using below variable, all other WETH is assumed to be - /// present as a result of a deposit. - uint256 beaconChainRewardWETH = 0; - - /// This notion page offers a good explanation of the bottom and top intervals for fuses: - /// https://www.notion.so/originprotocol/Limited-simplified-native-staking-accounting-67a217c8420d40678eb943b9da0ee77d - /// In short after dividing by 32 if the ETH remaining on the contract falls between 0 and fuseIntervalStart the accounting - /// function will treat that ETH as a Beacon Chain Reward ETH. - /// On the contrary if after dividing by 32 the ETH remaining on the contract falls between fuseIntervalEnd and 32 the - /// accounting function will treat that as a validator slashing. - /// - /// @dev start of fuse interval - uint256 fuseIntervalStart = 0; - /// @dev end of fuse interval - uint256 fuseIntervalEnd = 0; // For future use uint256[50] private __gap; - event FuseIntervalUpdated(uint256 oldStart, uint256 oldEnd, uint256 start, uint256 end); - - error FuseIntervalValuesIncorrect(); error EmptyRecipient(); - - /** - * @param _baseConfig Base strategy config with platformAddress (ERC-4626 Vault contract), eg sfrxETH or sDAI, - * and vaultAddress (OToken Vault contract), eg VaultProxy or OETHVaultProxy - * @param _wethAddress Address of the Erc20 WETH Token contract - * @param _ssvToken Address of the Erc20 SSV Token contract - * @param _ssvNetwork Address of the SSV Network contract - */ + + /// @param _baseConfig Base strategy config with platformAddress (ERC-4626 Vault contract), eg sfrxETH or sDAI, + /// and vaultAddress (OToken Vault contract), eg VaultProxy or OETHVaultProxy + /// @param _wethAddress Address of the Erc20 WETH Token contract + /// @param _ssvToken Address of the Erc20 SSV Token contract + /// @param _ssvNetwork Address of the SSV Network contract constructor(BaseStrategyConfig memory _baseConfig, address _wethAddress, address _ssvToken, address _ssvNetwork, address _feeAccumulator) InitializableAbstractStrategy(_baseConfig) { @@ -79,12 +50,10 @@ contract NativeStakingSSVStrategy is ValidatorRegistrator, InitializableAbstract FEE_ACCUMULATOR_ADDRESS = _feeAccumulator; } - /** - * @notice initialize function, to set up initial internal state - * @param _rewardTokenAddresses Address of reward token for platform - * @param _assets Addresses of initial supported assets - * @param _pTokens Platform Token corresponding addresses - */ + /// @notice initialize function, to set up initial internal state + /// @param _rewardTokenAddresses Address of reward token for platform + /// @param _assets Addresses of initial supported assets + /// @param _pTokens Platform Token corresponding addresses function initialize( address[] memory _rewardTokenAddresses, address[] memory _assets, @@ -101,14 +70,12 @@ contract NativeStakingSSVStrategy is ValidatorRegistrator, InitializableAbstract /// staking - staking on the validators. Because WETH on this contract can be present as /// a result of deposits and beacon chain rewards this function needs to return only WETH /// that is present due to deposits. - function getWETHBalanceEligibleForStaking() public override returns(uint256 _amount){ + function getWETHBalanceEligibleForStaking() public override view returns(uint256 _amount){ // if below amount results in a negative number there is a bug with accounting _amount = IWETH9(WETH_TOKEN_ADDRESS).balanceOf(address(this)) - beaconChainRewardWETH; } - /** - * @notice Collect accumulated WETH & SSV tokens and send to the Harvester. - */ + /// @notice Collect accumulated WETH & SSV tokens and send to the Harvester. function collectRewardTokens() external virtual @@ -122,11 +89,9 @@ contract NativeStakingSSVStrategy is ValidatorRegistrator, InitializableAbstract _collectRewardTokens(); } - /** - * @notice Deposit asset into the underlying platform - * @param _asset Address of asset to deposit - * @param _amount Amount of assets to deposit - */ + /// @notice Deposit asset into the underlying platform + /// @param _asset Address of asset to deposit + /// @param _amount Amount of assets to deposit function deposit(address _asset, uint256 _amount) external override @@ -137,11 +102,9 @@ contract NativeStakingSSVStrategy is ValidatorRegistrator, InitializableAbstract _deposit(_asset, _amount); } - /** - * @dev Deposit WETH to this contract to enable automated action to stake it - * @param _asset Address of WETH - * @param _amount Amount of WETH to deposit - */ + /// @dev Deposit WETH to this contract to enable automated action to stake it + /// @param _asset Address of WETH + /// @param _amount Amount of WETH to deposit function _deposit(address _asset, uint256 _amount) internal { require(_amount > 0, "Must deposit something"); /* @@ -156,9 +119,7 @@ contract NativeStakingSSVStrategy is ValidatorRegistrator, InitializableAbstract emit Deposit(_asset, address(0), _amount); } - /** - * @notice Deposit the entire balance of WETH asset in the strategy into the underlying platform - */ + /// @notice Deposit the entire balance of WETH asset in the strategy into the underlying platform function depositAll() external override onlyVault nonReentrant { uint256 wethBalance = IERC20(WETH_TOKEN_ADDRESS).balanceOf(address(this)); if (wethBalance > 0) { @@ -166,15 +127,13 @@ contract NativeStakingSSVStrategy is ValidatorRegistrator, InitializableAbstract } } - /** - * @notice Withdraw WETH from this contract. Used only if some WETH for is lingering on the contract. That - * can happen when: - * - the deposit was not a multiple of 32 WETH - * - someone sent WETH directly to this contract - * @param _recipient Address to receive withdrawn assets - * @param _asset WETH to withdraw - * @param _amount Amount of WETH to withdraw - */ + /// @notice Withdraw WETH from this contract. Used only if some WETH for is lingering on the contract. That + /// can happen when: + /// - the deposit was not a multiple of 32 WETH + /// - someone sent WETH directly to this contract + /// @param _recipient Address to receive withdrawn assets + /// @param _asset WETH to withdraw + /// @param _amount Amount of WETH to withdraw function withdraw( address _recipient, address _asset, @@ -198,9 +157,7 @@ contract NativeStakingSSVStrategy is ValidatorRegistrator, InitializableAbstract } - /** - * @notice Remove all supported assets from the underlying platform and send them to Vault contract. - */ + /// @notice Remove all supported assets from the underlying platform and send them to Vault contract. function withdrawAll() external override onlyVaultOrGovernor nonReentrant { uint256 wethBalance = IERC20(WETH_TOKEN_ADDRESS).balanceOf(address(this)); if (wethBalance > 0) { @@ -210,14 +167,12 @@ contract NativeStakingSSVStrategy is ValidatorRegistrator, InitializableAbstract function _abstractSetPToken(address _asset, address) internal override {} - /** - * @notice Get the total asset value held in the underlying platform - * This includes any interest that was generated since depositing. - * The exchange rate between the cToken and asset gradually increases, - * causing the cToken to be worth more corresponding asset. - * @param _asset Address of the asset - * @return balance Total value of the asset in the platform - */ + /// @notice Get the total asset value held in the underlying platform + /// This includes any interest that was generated since depositing. + /// The exchange rate between the cToken and asset gradually increases, + /// causing the cToken to be worth more corresponding asset. + /// @param _asset Address of the asset + /// @return balance Total value of the asset in the platform function checkBalance(address _asset) external view @@ -228,18 +183,14 @@ contract NativeStakingSSVStrategy is ValidatorRegistrator, InitializableAbstract } - /** - * @dev Retuns bool indicating whether asset is supported by strategy - * @param _asset Address of the asset - */ + /// @dev Retuns bool indicating whether asset is supported by strategy + /// @param _asset Address of the asset function supportsAsset(address _asset) public view override returns (bool) { return _asset == WETH_TOKEN_ADDRESS; } - /** - * @notice Approve the spending of all assets - * @dev Approves the SSV Network contract to transfer SSV tokens for deposits - */ + /// @notice Approve the spending of all assets + /// @dev Approves the SSV Network contract to transfer SSV tokens for deposits function safeApproveAllTokens() external override { /// @dev Approves the SSV Network contract to transfer SSV tokens for deposits IERC20(SSV_TOKEN_ADDRESS).approve(SSV_NETWORK_ADDRESS, type(uint256).max); @@ -251,24 +202,4 @@ contract NativeStakingSSVStrategy is ValidatorRegistrator, InitializableAbstract // address SSV_NETWORK_ADDRESS = lrtConfig.getContract(LRTConstants.SSV_NETWORK); // ISSVNetwork(SSV_NETWORK_ADDRESS).deposit(address(this), operatorIds, amount, cluster); } - - /** - * @notice set fuse interval values - */ - function setFuseInterval(uint256 _fuseIntervalStart, uint256 _fuseIntervalEnd) external onlyGovernor { - if ( - _fuseIntervalStart > _fuseIntervalEnd || - _fuseIntervalStart >= 32 ether || - _fuseIntervalEnd >= 32 ether || - _fuseIntervalEnd - _fuseIntervalStart < 4 ether - - ) { - revert FuseIntervalValuesIncorrect(); - } - - emit FuseIntervalUpdated(fuseIntervalStart, fuseIntervalEnd, _fuseIntervalStart, _fuseIntervalEnd); - - fuseIntervalStart = _fuseIntervalStart; - fuseIntervalEnd = _fuseIntervalEnd; - } } diff --git a/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol b/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol new file mode 100644 index 0000000000..5359bd43eb --- /dev/null +++ b/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol @@ -0,0 +1,62 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import { ValidatorRegistrator } from "./ValidatorRegistrator.sol"; + +/// @title Accountant of the rewards Beacon Chain ETH +/// @notice This contract contains the logic to attribute the Beacon Chain swept ETH either to full +/// or partial withdrawals +/// @author Origin Protocol Inc +abstract contract ValidatorAccountant is ValidatorRegistrator { + /// @dev The WETH present on this contract will come from 2 sources: + /// - as a result of deposits from the VaultAdmin + /// - accounting function converting beaconChain rewards from ETH to WETH + /// + /// We need to be able to keep a separate accounting of the WETH so we understand how much we can pass oh to + /// the harvester as a consequence of rewards harvesting and how much registrator can pick up as a result of WETH + /// deposit into the strategy contract. + /// To achieve this the beacon chain rewards are accounted for using below variable, all other WETH is assumed to be + /// present as a result of a deposit. + uint256 beaconChainRewardWETH = 0; + + /// @dev start of fuse interval + uint256 fuseIntervalStart = 0; + /// @dev end of fuse interval + uint256 fuseIntervalEnd = 0; + + uint256[50] private __gap; + + event FuseIntervalUpdated(uint256 oldStart, uint256 oldEnd, uint256 start, uint256 end); + + error FuseIntervalValuesIncorrect(); + + /// @notice set fuse interval values + function setFuseInterval(uint256 _fuseIntervalStart, uint256 _fuseIntervalEnd) external onlyGovernor { + if ( + _fuseIntervalStart > _fuseIntervalEnd || + _fuseIntervalStart >= 32 ether || + _fuseIntervalEnd >= 32 ether || + _fuseIntervalEnd - _fuseIntervalStart < 4 ether + + ) { + revert FuseIntervalValuesIncorrect(); + } + + emit FuseIntervalUpdated(fuseIntervalStart, fuseIntervalEnd, _fuseIntervalStart, _fuseIntervalEnd); + + fuseIntervalStart = _fuseIntervalStart; + fuseIntervalEnd = _fuseIntervalEnd; + } + + /// This notion page offers a good explanation of how the accounting functions + /// https://www.notion.so/originprotocol/Limited-simplified-native-staking-accounting-67a217c8420d40678eb943b9da0ee77d + /// In short after dividing by 32 if the ETH remaining on the contract falls between 0 and fuseIntervalStart the accounting + /// function will treat that ETH as a Beacon Chain Reward ETH. + /// On the contrary if after dividing by 32 the ETH remaining on the contract falls between fuseIntervalEnd and 32 the + /// accounting function will treat that as a validator slashing. + /// @notice Perform the accounting attributing beacon chain ETH to either full or partial withdrawals. Returns true when + /// accounting is valid and fuse isn't "blown". Returns false when fuse is blown + function doAccounting() external returns (bool){ + + } +} diff --git a/contracts/contracts/strategies/NativeStaking/ValidatorRegistrator.sol b/contracts/contracts/strategies/NativeStaking/ValidatorRegistrator.sol index 4fd377df69..457530eb45 100644 --- a/contracts/contracts/strategies/NativeStaking/ValidatorRegistrator.sol +++ b/contracts/contracts/strategies/NativeStaking/ValidatorRegistrator.sol @@ -20,17 +20,13 @@ abstract contract ValidatorRegistrator is Governable { event RegistratorAddressChanged(address oldAddress, address newAddress); - /** - * @dev Throws if called by any account other than the Registrator - */ + /// @dev Throws if called by any account other than the Registrator modifier onlyRegistrator() { require(msg.sender == validatorRegistrator, "Caller is not the Registrator"); _; } - /** - * @notice Set the address of the registrator - */ + /// @notice Set the address of the registrator function setRegistratorAddress(address _address) external onlyGovernor { emit RegistratorAddressChanged(validatorRegistrator, _address); validatorRegistrator = _address; @@ -38,7 +34,7 @@ abstract contract ValidatorRegistrator is Governable { /// @notice return the WETH balance on the contract that can be used to for beacon chain /// staking - staking on the validators - function getWETHBalanceEligibleForStaking() public virtual returns(uint256 _amount); + function getWETHBalanceEligibleForStaking() public virtual view returns(uint256 _amount); // /// @notice Stakes WETH to the NDC to the Node validators // /// @param validators A list of validator data needed to stake. From 03c544cab114e46e7d867af03c55df5cca85db15 Mon Sep 17 00:00:00 2001 From: Domen Grabec Date: Thu, 11 Apr 2024 16:05:19 +0200 Subject: [PATCH 006/273] add some more accounting logic --- .../NativeStakingSSVStrategy.sol | 36 ++++++++- .../NativeStaking/ValidatorAccountant.sol | 78 +++++++++++++++++-- .../utils/InitializableAbstractStrategy.sol | 2 +- 3 files changed, 107 insertions(+), 9 deletions(-) diff --git a/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol b/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol index 4edcd40058..14bebeaf7a 100644 --- a/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol +++ b/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol @@ -22,8 +22,6 @@ struct ValidatorStakeData { contract NativeStakingSSVStrategy is ValidatorAccountant, InitializableAbstractStrategy { using SafeERC20 for IERC20; - /// @notice The Wrapped ETH (WETH) contract address - address public immutable WETH_TOKEN_ADDRESS; /// @notice SSV ERC20 token that serves as a payment for operating SSV validators address public immutable SSV_TOKEN_ADDRESS; /// @notice SSV Network contract used to interface with @@ -35,6 +33,7 @@ contract NativeStakingSSVStrategy is ValidatorAccountant, InitializableAbstractS uint256[50] private __gap; error EmptyRecipient(); + error InsuffiscientWethBalance(uint256 requiredBalance, uint256 availableBalance); /// @param _baseConfig Base strategy config with platformAddress (ERC-4626 Vault contract), eg sfrxETH or sDAI, /// and vaultAddress (OToken Vault contract), eg VaultProxy or OETHVaultProxy @@ -43,8 +42,8 @@ contract NativeStakingSSVStrategy is ValidatorAccountant, InitializableAbstractS /// @param _ssvNetwork Address of the SSV Network contract constructor(BaseStrategyConfig memory _baseConfig, address _wethAddress, address _ssvToken, address _ssvNetwork, address _feeAccumulator) InitializableAbstractStrategy(_baseConfig) + ValidatorAccountant(_wethAddress, _baseConfig.vaultAddress) { - WETH_TOKEN_ADDRESS = _wethAddress; SSV_TOKEN_ADDRESS = _ssvToken; SSV_NETWORK_ADDRESS = _ssvNetwork; FEE_ACCUMULATOR_ADDRESS = _feeAccumulator; @@ -86,9 +85,40 @@ contract NativeStakingSSVStrategy is ValidatorAccountant, InitializableAbstractS // collect ETH from fee collector and wrap it into WETH uint256 ethCollected = FeeAccumulator(FEE_ACCUMULATOR_ADDRESS).collect(); IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: ethCollected }(); + _collectRewardTokens(); } + /// @dev Need to override this function since the strategy doesn't allow for all the WETH + /// to be collected. Some might be there as a result of deposit and is waiting for the Registrar + /// to be deposited to the validators. + function _collectRewardTokens() internal override { + uint256 rewardTokenCount = rewardTokenAddresses.length; + for (uint256 i = 0; i < rewardTokenCount; ++i) { + IERC20 rewardToken = IERC20(rewardTokenAddresses[i]); + uint256 balance = rewardToken.balanceOf(address(this)); + if (balance > 0) { + if(address(rewardToken) == WETH_TOKEN_ADDRESS) { + if (beaconChainRewardWETH < balance) { + revert InsuffiscientWethBalance(beaconChainRewardWETH, balance); + } + + // only allow for the WETH that is part of beacon chain rewards to be harvested + balance = beaconChainRewardWETH; + // reset the counter keeping track of beacon chain WETH rewards + beaconChainRewardWETH = 0; + } + + emit RewardTokenCollected( + harvesterAddress, + address(rewardToken), + balance + ); + rewardToken.safeTransfer(harvesterAddress, balance); + } + } + } + /// @notice Deposit asset into the underlying platform /// @param _asset Address of asset to deposit /// @param _amount Amount of assets to deposit diff --git a/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol b/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol index 5359bd43eb..9b7774b2ed 100644 --- a/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol +++ b/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol @@ -1,13 +1,19 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; +import { Pausable } from "@openzeppelin/contracts/security/Pausable.sol"; import { ValidatorRegistrator } from "./ValidatorRegistrator.sol"; +import { IWETH9 } from "../../interfaces/IWETH9.sol"; /// @title Accountant of the rewards Beacon Chain ETH /// @notice This contract contains the logic to attribute the Beacon Chain swept ETH either to full /// or partial withdrawals /// @author Origin Protocol Inc -abstract contract ValidatorAccountant is ValidatorRegistrator { +abstract contract ValidatorAccountant is ValidatorRegistrator, Pausable { + /// @notice The Wrapped ETH (WETH) contract address + address public immutable WETH_TOKEN_ADDRESS; + address public immutable VAULT_ADDRESS; + /// @dev The WETH present on this contract will come from 2 sources: /// - as a result of deposits from the VaultAdmin /// - accounting function converting beaconChain rewards from ETH to WETH @@ -17,18 +23,41 @@ abstract contract ValidatorAccountant is ValidatorRegistrator { /// deposit into the strategy contract. /// To achieve this the beacon chain rewards are accounted for using below variable, all other WETH is assumed to be /// present as a result of a deposit. - uint256 beaconChainRewardWETH = 0; + uint256 public beaconChainRewardWETH = 0; /// @dev start of fuse interval - uint256 fuseIntervalStart = 0; + uint256 public fuseIntervalStart = 0; /// @dev end of fuse interval - uint256 fuseIntervalEnd = 0; + uint256 public fuseIntervalEnd = 0; + /// @dev Governor that can manually correct the accounting + address public accountingGovernor; uint256[50] private __gap; event FuseIntervalUpdated(uint256 oldStart, uint256 oldEnd, uint256 start, uint256 end); + event AccuntingFullyWithdrawnValidator(uint256 noOfValidators, uint256 remainingValidators, uint256 wethSentToVault); + event AccountingGovernorAddressChanged(address oldAddress, address newAddress); error FuseIntervalValuesIncorrect(); + error UnexpectedEthAccountingInterval(uint256 errorneousEthAmount); + + /// @dev Throws if called by any account other than the Accounting Governor + modifier onlyAccountingGovernor() { + require(msg.sender == accountingGovernor, "Caller is not the Accounting Governor"); + _; + } + + /// @param _wethAddress Address of the Erc20 WETH Token contract + constructor(address _wethAddress, address _vaultAddress) + { + WETH_TOKEN_ADDRESS = _wethAddress; + VAULT_ADDRESS = _vaultAddress; + } + + function setAccountingGovernor(address _address) external onlyGovernor { + emit AccountingGovernorAddressChanged(accountingGovernor, _address); + accountingGovernor = _address; + } /// @notice set fuse interval values function setFuseInterval(uint256 _fuseIntervalStart, uint256 _fuseIntervalEnd) external onlyGovernor { @@ -56,7 +85,46 @@ abstract contract ValidatorAccountant is ValidatorRegistrator { /// accounting function will treat that as a validator slashing. /// @notice Perform the accounting attributing beacon chain ETH to either full or partial withdrawals. Returns true when /// accounting is valid and fuse isn't "blown". Returns false when fuse is blown - function doAccounting() external returns (bool){ + /// @dev This function could in theory be permission-less but lets allow only the Registrator (Defender Action) to call it + /// for now + function doAccounting() external onlyRegistrator returns (bool) { + uint256 ethBalance = address(this).balance; + uint256 MAX_STAKE = 32 ether; + + if (ethBalance >= MAX_STAKE) { + uint256 fullyWithdrawnValidators = ethBalance / MAX_STAKE; + activeDepositedValidators -= fullyWithdrawnValidators; + + uint256 wethToVault = MAX_STAKE * fullyWithdrawnValidators; + IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: wethToVault }(); + IWETH9(WETH_TOKEN_ADDRESS).transfer(VAULT_ADDRESS, wethToVault); + + emit AccuntingFullyWithdrawnValidator(fullyWithdrawnValidators, activeDepositedValidators, wethToVault); + } + + uint256 ethRemaining = address(this).balance; + // should never happen + if (ethRemaining > 32 ether) { + revert UnexpectedEthAccountingInterval(ethRemaining); + } + + // Beacon chain rewards swept + if (ethRemaining <= fuseIntervalStart) { + + } + // Beacon chain rewards swept but also a slashed validator fully exited + else if (fuseIntervalEnd >= fuseIntervalEnd) { + + } + // Oh no... Fuse is blown. The governor (Multisig not OGV Governor) needs to set the + // record straight by manually set the accounting values. + else { + _pause(); + } + + } + + function manuallyFixAccounting() external onlyAccountingGovernor { } } diff --git a/contracts/contracts/utils/InitializableAbstractStrategy.sol b/contracts/contracts/utils/InitializableAbstractStrategy.sol index 9daff9c8c0..19bb0df836 100644 --- a/contracts/contracts/utils/InitializableAbstractStrategy.sol +++ b/contracts/contracts/utils/InitializableAbstractStrategy.sol @@ -114,7 +114,7 @@ abstract contract InitializableAbstractStrategy is Initializable, Governable { } /** - * @dev Default implementation that transfers reward tokens to the Vault. + * @dev Default implementation that transfers reward tokens to the Harvester * Implementing strategies need to add custom logic to collect the rewards. */ function _collectRewardTokens() internal virtual { From 9aa0d739a29da2b7ec18d3217012b9bfa79802e5 Mon Sep 17 00:00:00 2001 From: Domen Grabec Date: Fri, 12 Apr 2024 14:15:17 +0200 Subject: [PATCH 007/273] finish up accounting and add tests for it --- .../contracts/interfaces/ISSVNetwork.sol | 149 +++++++-- contracts/contracts/proxies/Proxies.sol | 8 +- .../NativeStaking/FeeAccumulator.sol | 7 +- .../NativeStakingSSVStrategy.sol | 75 +++-- .../NativeStaking/ValidatorAccountant.sol | 124 ++++++-- .../NativeStaking/ValidatorRegistrator.sol | 13 +- contracts/deploy/001_core.js | 52 +-- contracts/deploy/091_native_ssv_staking.js | 41 ++- contracts/test/_fixture.js | 38 ++- contracts/test/_hot-deploy.js | 12 +- contracts/test/helpers.js | 2 +- contracts/test/strategies/nativeSSVStaking.js | 299 +++++++++++++++--- .../strategies/nativeSsvStaking.fork-test.js | 29 +- 13 files changed, 661 insertions(+), 188 deletions(-) diff --git a/contracts/contracts/interfaces/ISSVNetwork.sol b/contracts/contracts/interfaces/ISSVNetwork.sol index 12177b8b8c..9f37388663 100644 --- a/contracts/contracts/interfaces/ISSVNetwork.sol +++ b/contracts/contracts/interfaces/ISSVNetwork.sol @@ -43,33 +43,100 @@ interface ISSVNetwork { event AdminChanged(address previousAdmin, address newAdmin); event BeaconUpgraded(address indexed beacon); - event ClusterDeposited(address indexed owner, uint64[] operatorIds, uint256 value, Cluster cluster); - event ClusterLiquidated(address indexed owner, uint64[] operatorIds, Cluster cluster); - event ClusterReactivated(address indexed owner, uint64[] operatorIds, Cluster cluster); - event ClusterWithdrawn(address indexed owner, uint64[] operatorIds, uint256 value, Cluster cluster); + event ClusterDeposited( + address indexed owner, + uint64[] operatorIds, + uint256 value, + Cluster cluster + ); + event ClusterLiquidated( + address indexed owner, + uint64[] operatorIds, + Cluster cluster + ); + event ClusterReactivated( + address indexed owner, + uint64[] operatorIds, + Cluster cluster + ); + event ClusterWithdrawn( + address indexed owner, + uint64[] operatorIds, + uint256 value, + Cluster cluster + ); event DeclareOperatorFeePeriodUpdated(uint64 value); event ExecuteOperatorFeePeriodUpdated(uint64 value); - event FeeRecipientAddressUpdated(address indexed owner, address recipientAddress); + event FeeRecipientAddressUpdated( + address indexed owner, + address recipientAddress + ); event Initialized(uint8 version); event LiquidationThresholdPeriodUpdated(uint64 value); event MinimumLiquidationCollateralUpdated(uint256 value); event NetworkEarningsWithdrawn(uint256 value, address recipient); event NetworkFeeUpdated(uint256 oldFee, uint256 newFee); - event OperatorAdded(uint64 indexed operatorId, address indexed owner, bytes publicKey, uint256 fee); - event OperatorFeeDeclarationCancelled(address indexed owner, uint64 indexed operatorId); - event OperatorFeeDeclared(address indexed owner, uint64 indexed operatorId, uint256 blockNumber, uint256 fee); - event OperatorFeeExecuted(address indexed owner, uint64 indexed operatorId, uint256 blockNumber, uint256 fee); + event OperatorAdded( + uint64 indexed operatorId, + address indexed owner, + bytes publicKey, + uint256 fee + ); + event OperatorFeeDeclarationCancelled( + address indexed owner, + uint64 indexed operatorId + ); + event OperatorFeeDeclared( + address indexed owner, + uint64 indexed operatorId, + uint256 blockNumber, + uint256 fee + ); + event OperatorFeeExecuted( + address indexed owner, + uint64 indexed operatorId, + uint256 blockNumber, + uint256 fee + ); event OperatorFeeIncreaseLimitUpdated(uint64 value); event OperatorMaximumFeeUpdated(uint64 maxFee); event OperatorRemoved(uint64 indexed operatorId); - event OperatorWhitelistUpdated(uint64 indexed operatorId, address whitelisted); - event OperatorWithdrawn(address indexed owner, uint64 indexed operatorId, uint256 value); - event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner); - event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + event OperatorWhitelistUpdated( + uint64 indexed operatorId, + address whitelisted + ); + event OperatorWithdrawn( + address indexed owner, + uint64 indexed operatorId, + uint256 value + ); + event OwnershipTransferStarted( + address indexed previousOwner, + address indexed newOwner + ); + event OwnershipTransferred( + address indexed previousOwner, + address indexed newOwner + ); event Upgraded(address indexed implementation); - event ValidatorAdded(address indexed owner, uint64[] operatorIds, bytes publicKey, bytes shares, Cluster cluster); - event ValidatorExited(address indexed owner, uint64[] operatorIds, bytes publicKey); - event ValidatorRemoved(address indexed owner, uint64[] operatorIds, bytes publicKey, Cluster cluster); + event ValidatorAdded( + address indexed owner, + uint64[] operatorIds, + bytes publicKey, + bytes shares, + Cluster cluster + ); + event ValidatorExited( + address indexed owner, + uint64[] operatorIds, + bytes publicKey + ); + event ValidatorRemoved( + address indexed owner, + uint64[] operatorIds, + bytes publicKey, + Cluster cluster + ); fallback() external; @@ -84,12 +151,12 @@ interface ISSVNetwork { uint64[] memory operatorIds, uint256 amount, Cluster memory cluster - ) - external; + ) external; function executeOperatorFee(uint64 operatorId) external; - function exitValidator(bytes memory publicKey, uint64[] memory operatorIds) external; + function exitValidator(bytes memory publicKey, uint64[] memory operatorIds) + external; function getVersion() external pure returns (string memory version); @@ -105,10 +172,13 @@ interface ISSVNetwork { uint64 declareOperatorFeePeriod_, uint64 executeOperatorFeePeriod_, uint64 operatorMaxFeeIncrease_ - ) - external; + ) external; - function liquidate(address clusterOwner, uint64[] memory operatorIds, Cluster memory cluster) external; + function liquidate( + address clusterOwner, + uint64[] memory operatorIds, + Cluster memory cluster + ) external; function owner() external view returns (address); @@ -116,11 +186,17 @@ interface ISSVNetwork { function proxiableUUID() external view returns (bytes32); - function reactivate(uint64[] memory operatorIds, uint256 amount, Cluster memory cluster) external; + function reactivate( + uint64[] memory operatorIds, + uint256 amount, + Cluster memory cluster + ) external; function reduceOperatorFee(uint64 operatorId, uint256 fee) external; - function registerOperator(bytes memory publicKey, uint256 fee) external returns (uint64 id); + function registerOperator(bytes memory publicKey, uint256 fee) + external + returns (uint64 id); function registerValidator( bytes memory publicKey, @@ -128,18 +204,22 @@ interface ISSVNetwork { bytes memory sharesData, uint256 amount, Cluster memory cluster - ) - external; + ) external; function removeOperator(uint64 operatorId) external; - function removeValidator(bytes memory publicKey, uint64[] memory operatorIds, Cluster memory cluster) external; + function removeValidator( + bytes memory publicKey, + uint64[] memory operatorIds, + Cluster memory cluster + ) external; function renounceOwnership() external; function setFeeRecipientAddress(address recipientAddress) external; - function setOperatorWhitelist(uint64 operatorId, address whitelisted) external; + function setOperatorWhitelist(uint64 operatorId, address whitelisted) + external; function transferOwnership(address newOwner) external; @@ -161,13 +241,20 @@ interface ISSVNetwork { function upgradeTo(address newImplementation) external; - function upgradeToAndCall(address newImplementation, bytes memory data) external payable; + function upgradeToAndCall(address newImplementation, bytes memory data) + external + payable; - function withdraw(uint64[] memory operatorIds, uint256 amount, Cluster memory cluster) external; + function withdraw( + uint64[] memory operatorIds, + uint256 amount, + Cluster memory cluster + ) external; function withdrawAllOperatorEarnings(uint64 operatorId) external; function withdrawNetworkEarnings(uint256 amount) external; - function withdrawOperatorEarnings(uint64 operatorId, uint256 amount) external; + function withdrawOperatorEarnings(uint64 operatorId, uint256 amount) + external; } diff --git a/contracts/contracts/proxies/Proxies.sol b/contracts/contracts/proxies/Proxies.sol index b69a4ce3b9..68763d5c8e 100644 --- a/contracts/contracts/proxies/Proxies.sol +++ b/contracts/contracts/proxies/Proxies.sol @@ -213,13 +213,17 @@ contract BridgedWOETHProxy is InitializeGovernedUpgradeabilityProxy { /** * @notice NativeStakingSSVStrategyProxy delegates calls to NativeStakingSSVStrategy implementation */ -contract NativeStakingSSVStrategyProxy is InitializeGovernedUpgradeabilityProxy { +contract NativeStakingSSVStrategyProxy is + InitializeGovernedUpgradeabilityProxy +{ } /** * @notice NativeStakingFeeAccumulatorProxy delegates calls to NativeStakingFeeCollector implementation */ -contract NativeStakingFeeAccumulatorProxy is InitializeGovernedUpgradeabilityProxy { +contract NativeStakingFeeAccumulatorProxy is + InitializeGovernedUpgradeabilityProxy +{ } diff --git a/contracts/contracts/strategies/NativeStaking/FeeAccumulator.sol b/contracts/contracts/strategies/NativeStaking/FeeAccumulator.sol index 0a73bf4d44..b951d1b4b8 100644 --- a/contracts/contracts/strategies/NativeStaking/FeeAccumulator.sol +++ b/contracts/contracts/strategies/NativeStaking/FeeAccumulator.sol @@ -24,8 +24,7 @@ contract FeeAccumulator is Governable { /** * @param _collector Address of the contract that collects the fees */ - constructor(address _collector, address _weth) - { + constructor(address _collector, address _weth) { COLLECTOR = _collector; WETH_TOKEN_ADDRESS = _weth; } @@ -34,7 +33,7 @@ contract FeeAccumulator is Governable { * @notice Asserts that the caller is the collector */ function _assertIsCollector() internal view { - if(msg.sender != COLLECTOR) { + if (msg.sender != COLLECTOR) { revert CallerNotCollector(msg.sender, COLLECTOR); } } @@ -45,7 +44,7 @@ contract FeeAccumulator is Governable { function collect() external returns (uint256 wethReturned) { _assertIsCollector(); wethReturned = address(this).balance; - IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: wethReturned}(); + IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: wethReturned }(); IWETH9(WETH_TOKEN_ADDRESS).transfer(COLLECTOR, wethReturned); } } diff --git a/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol b/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol index 14bebeaf7a..918fbcef7f 100644 --- a/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol +++ b/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol @@ -19,12 +19,15 @@ struct ValidatorStakeData { /// @title Native Staking SSV Strategy /// @notice Strategy to deploy funds into DVT validators powered by the SSV Network /// @author Origin Protocol Inc -contract NativeStakingSSVStrategy is ValidatorAccountant, InitializableAbstractStrategy { +contract NativeStakingSSVStrategy is + ValidatorAccountant, + InitializableAbstractStrategy +{ using SafeERC20 for IERC20; /// @notice SSV ERC20 token that serves as a payment for operating SSV validators address public immutable SSV_TOKEN_ADDRESS; - /// @notice SSV Network contract used to interface with + /// @notice SSV Network contract used to interface with address public immutable SSV_NETWORK_ADDRESS; /// @notice Fee collector address address public immutable FEE_ACCUMULATOR_ADDRESS; @@ -33,14 +36,23 @@ contract NativeStakingSSVStrategy is ValidatorAccountant, InitializableAbstractS uint256[50] private __gap; error EmptyRecipient(); - error InsuffiscientWethBalance(uint256 requiredBalance, uint256 availableBalance); - + error InsuffiscientWethBalance( + uint256 requiredBalance, + uint256 availableBalance + ); + /// @param _baseConfig Base strategy config with platformAddress (ERC-4626 Vault contract), eg sfrxETH or sDAI, /// and vaultAddress (OToken Vault contract), eg VaultProxy or OETHVaultProxy /// @param _wethAddress Address of the Erc20 WETH Token contract /// @param _ssvToken Address of the Erc20 SSV Token contract /// @param _ssvNetwork Address of the SSV Network contract - constructor(BaseStrategyConfig memory _baseConfig, address _wethAddress, address _ssvToken, address _ssvNetwork, address _feeAccumulator) + constructor( + BaseStrategyConfig memory _baseConfig, + address _wethAddress, + address _ssvToken, + address _ssvNetwork, + address _feeAccumulator + ) InitializableAbstractStrategy(_baseConfig) ValidatorAccountant(_wethAddress, _baseConfig.vaultAddress) { @@ -66,12 +78,19 @@ contract NativeStakingSSVStrategy is ValidatorAccountant, InitializableAbstractS } /// @notice return the WETH balance on the contract that can be used to for beacon chain - /// staking - staking on the validators. Because WETH on this contract can be present as + /// staking - staking on the validators. Because WETH on this contract can be present as /// a result of deposits and beacon chain rewards this function needs to return only WETH /// that is present due to deposits. - function getWETHBalanceEligibleForStaking() public override view returns(uint256 _amount){ + function getWETHBalanceEligibleForStaking() + public + view + override + returns (uint256 _amount) + { // if below amount results in a negative number there is a bug with accounting - _amount = IWETH9(WETH_TOKEN_ADDRESS).balanceOf(address(this)) - beaconChainRewardWETH; + _amount = + IWETH9(WETH_TOKEN_ADDRESS).balanceOf(address(this)) - + beaconChainRewardWETH; } /// @notice Collect accumulated WETH & SSV tokens and send to the Harvester. @@ -83,7 +102,8 @@ contract NativeStakingSSVStrategy is ValidatorAccountant, InitializableAbstractS nonReentrant { // collect ETH from fee collector and wrap it into WETH - uint256 ethCollected = FeeAccumulator(FEE_ACCUMULATOR_ADDRESS).collect(); + uint256 ethCollected = FeeAccumulator(FEE_ACCUMULATOR_ADDRESS) + .collect(); IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: ethCollected }(); _collectRewardTokens(); @@ -98,9 +118,12 @@ contract NativeStakingSSVStrategy is ValidatorAccountant, InitializableAbstractS IERC20 rewardToken = IERC20(rewardTokenAddresses[i]); uint256 balance = rewardToken.balanceOf(address(this)); if (balance > 0) { - if(address(rewardToken) == WETH_TOKEN_ADDRESS) { + if (address(rewardToken) == WETH_TOKEN_ADDRESS) { if (beaconChainRewardWETH < balance) { - revert InsuffiscientWethBalance(beaconChainRewardWETH, balance); + revert InsuffiscientWethBalance( + beaconChainRewardWETH, + balance + ); } // only allow for the WETH that is part of beacon chain rewards to be harvested @@ -128,7 +151,6 @@ contract NativeStakingSSVStrategy is ValidatorAccountant, InitializableAbstractS onlyVault nonReentrant { - _deposit(_asset, _amount); } @@ -137,12 +159,12 @@ contract NativeStakingSSVStrategy is ValidatorAccountant, InitializableAbstractS /// @param _amount Amount of WETH to deposit function _deposit(address _asset, uint256 _amount) internal { require(_amount > 0, "Must deposit something"); - /* + /* * We could do a check here that would revert when "_amount % 32 ether != 0". With the idea of * not allowing deposits that will result in WETH sitting on the strategy after all the possible batches - * of 32ETH have been staked. + * of 32ETH have been staked. * But someone could mess with our strategy by sending some WETH to it. And we might want to deposit just - * enough WETH to add it up to 32 so it can be staked. For that reason the check is left out. + * enough WETH to add it up to 32 so it can be staked. For that reason the check is left out. * * WETH sitting on the strategy won't interfere with the accounting since accounting only operates on ETH. */ @@ -151,7 +173,9 @@ contract NativeStakingSSVStrategy is ValidatorAccountant, InitializableAbstractS /// @notice Deposit the entire balance of WETH asset in the strategy into the underlying platform function depositAll() external override onlyVault nonReentrant { - uint256 wethBalance = IERC20(WETH_TOKEN_ADDRESS).balanceOf(address(this)); + uint256 wethBalance = IERC20(WETH_TOKEN_ADDRESS).balanceOf( + address(this) + ); if (wethBalance > 0) { _deposit(WETH_TOKEN_ADDRESS, wethBalance); } @@ -186,10 +210,11 @@ contract NativeStakingSSVStrategy is ValidatorAccountant, InitializableAbstractS IERC20(_asset).safeTransfer(_recipient, _amount); } - /// @notice Remove all supported assets from the underlying platform and send them to Vault contract. function withdrawAll() external override onlyVaultOrGovernor nonReentrant { - uint256 wethBalance = IERC20(WETH_TOKEN_ADDRESS).balanceOf(address(this)); + uint256 wethBalance = IERC20(WETH_TOKEN_ADDRESS).balanceOf( + address(this) + ); if (wethBalance > 0) { _withdraw(vaultAddress, WETH_TOKEN_ADDRESS, wethBalance); } @@ -212,6 +237,9 @@ contract NativeStakingSSVStrategy is ValidatorAccountant, InitializableAbstractS balance = 0; } + function pause() external onlyStrategist { + _pause(); + } /// @dev Retuns bool indicating whether asset is supported by strategy /// @param _asset Address of the asset @@ -223,12 +251,19 @@ contract NativeStakingSSVStrategy is ValidatorAccountant, InitializableAbstractS /// @dev Approves the SSV Network contract to transfer SSV tokens for deposits function safeApproveAllTokens() external override { /// @dev Approves the SSV Network contract to transfer SSV tokens for deposits - IERC20(SSV_TOKEN_ADDRESS).approve(SSV_NETWORK_ADDRESS, type(uint256).max); + IERC20(SSV_TOKEN_ADDRESS).approve( + SSV_NETWORK_ADDRESS, + type(uint256).max + ); } /// @dev Deposits more SSV Tokens to the SSV Network contract which is used to pay the SSV Operators /// A SSV cluster is defined by the SSVOwnerAddress and the set of operatorIds - function depositSSV(uint64[] memory operatorIds, uint256 amount, Cluster memory cluster) external { + function depositSSV( + uint64[] memory operatorIds, + uint256 amount, + Cluster memory cluster + ) external { // address SSV_NETWORK_ADDRESS = lrtConfig.getContract(LRTConstants.SSV_NETWORK); // ISSVNetwork(SSV_NETWORK_ADDRESS).deposit(address(this), operatorIds, amount, cluster); } diff --git a/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol b/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol index 9b7774b2ed..8f9cbdeaf6 100644 --- a/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol +++ b/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol @@ -17,9 +17,9 @@ abstract contract ValidatorAccountant is ValidatorRegistrator, Pausable { /// @dev The WETH present on this contract will come from 2 sources: /// - as a result of deposits from the VaultAdmin /// - accounting function converting beaconChain rewards from ETH to WETH - /// - /// We need to be able to keep a separate accounting of the WETH so we understand how much we can pass oh to - /// the harvester as a consequence of rewards harvesting and how much registrator can pick up as a result of WETH + /// + /// We need to be able to keep a separate accounting of the WETH so we understand how much we can pass oh to + /// the harvester as a consequence of rewards harvesting and how much registrator can pick up as a result of WETH /// deposit into the strategy contract. /// To achieve this the beacon chain rewards are accounted for using below variable, all other WETH is assumed to be /// present as a result of a deposit. @@ -31,25 +31,56 @@ abstract contract ValidatorAccountant is ValidatorRegistrator, Pausable { uint256 public fuseIntervalEnd = 0; /// @dev Governor that can manually correct the accounting address public accountingGovernor; + /// @dev Strategist that can pause the accounting + address public strategist; uint256[50] private __gap; - event FuseIntervalUpdated(uint256 oldStart, uint256 oldEnd, uint256 start, uint256 end); - event AccuntingFullyWithdrawnValidator(uint256 noOfValidators, uint256 remainingValidators, uint256 wethSentToVault); - event AccountingGovernorAddressChanged(address oldAddress, address newAddress); + event FuseIntervalUpdated( + uint256 oldStart, + uint256 oldEnd, + uint256 start, + uint256 end + ); + event AccuntingFullyWithdrawnValidator( + uint256 noOfValidators, + uint256 remainingValidators, + uint256 wethSentToVault + ); + event AccuntingValidatorSlashed( + uint256 remainingValidators, + uint256 wethSentToVault + ); + event AccountingGovernorAddressChanged( + address oldAddress, + address newAddress + ); + event StrategistAddressChanged( + address oldStrategist, + address newStrategist + ); + event AccountingBeaconChainRewards(uint256 amount); error FuseIntervalValuesIncorrect(); error UnexpectedEthAccountingInterval(uint256 errorneousEthAmount); /// @dev Throws if called by any account other than the Accounting Governor modifier onlyAccountingGovernor() { - require(msg.sender == accountingGovernor, "Caller is not the Accounting Governor"); + require( + msg.sender == accountingGovernor, + "Caller is not the Accounting Governor" + ); + _; + } + + /// @dev Throws if called by any account other than the Strategist + modifier onlyStrategist() { + require(msg.sender == strategist, "Caller is not the Strategist"); _; } /// @param _wethAddress Address of the Erc20 WETH Token contract - constructor(address _wethAddress, address _vaultAddress) - { + constructor(address _wethAddress, address _vaultAddress) { WETH_TOKEN_ADDRESS = _wethAddress; VAULT_ADDRESS = _vaultAddress; } @@ -59,19 +90,31 @@ abstract contract ValidatorAccountant is ValidatorRegistrator, Pausable { accountingGovernor = _address; } + function setStrategist(address _address) external onlyGovernor { + emit StrategistAddressChanged(strategist, _address); + strategist = _address; + } + /// @notice set fuse interval values - function setFuseInterval(uint256 _fuseIntervalStart, uint256 _fuseIntervalEnd) external onlyGovernor { + function setFuseInterval( + uint256 _fuseIntervalStart, + uint256 _fuseIntervalEnd + ) external onlyGovernor { if ( _fuseIntervalStart > _fuseIntervalEnd || - _fuseIntervalStart >= 32 ether || - _fuseIntervalEnd >= 32 ether || + _fuseIntervalStart >= 32 ether || + _fuseIntervalEnd >= 32 ether || _fuseIntervalEnd - _fuseIntervalStart < 4 ether - ) { revert FuseIntervalValuesIncorrect(); } - emit FuseIntervalUpdated(fuseIntervalStart, fuseIntervalEnd, _fuseIntervalStart, _fuseIntervalEnd); + emit FuseIntervalUpdated( + fuseIntervalStart, + fuseIntervalEnd, + _fuseIntervalStart, + _fuseIntervalEnd + ); fuseIntervalStart = _fuseIntervalStart; fuseIntervalEnd = _fuseIntervalEnd; @@ -81,9 +124,9 @@ abstract contract ValidatorAccountant is ValidatorRegistrator, Pausable { /// https://www.notion.so/originprotocol/Limited-simplified-native-staking-accounting-67a217c8420d40678eb943b9da0ee77d /// In short after dividing by 32 if the ETH remaining on the contract falls between 0 and fuseIntervalStart the accounting /// function will treat that ETH as a Beacon Chain Reward ETH. - /// On the contrary if after dividing by 32 the ETH remaining on the contract falls between fuseIntervalEnd and 32 the + /// On the contrary if after dividing by 32 the ETH remaining on the contract falls between fuseIntervalEnd and 32 the /// accounting function will treat that as a validator slashing. - /// @notice Perform the accounting attributing beacon chain ETH to either full or partial withdrawals. Returns true when + /// @notice Perform the accounting attributing beacon chain ETH to either full or partial withdrawals. Returns true when /// accounting is valid and fuse isn't "blown". Returns false when fuse is blown /// @dev This function could in theory be permission-less but lets allow only the Registrator (Defender Action) to call it /// for now @@ -91,6 +134,7 @@ abstract contract ValidatorAccountant is ValidatorRegistrator, Pausable { uint256 ethBalance = address(this).balance; uint256 MAX_STAKE = 32 ether; + // send the WETH that is from fully withdrawn validators to the Vault if (ethBalance >= MAX_STAKE) { uint256 fullyWithdrawnValidators = ethBalance / MAX_STAKE; activeDepositedValidators -= fullyWithdrawnValidators; @@ -99,7 +143,11 @@ abstract contract ValidatorAccountant is ValidatorRegistrator, Pausable { IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: wethToVault }(); IWETH9(WETH_TOKEN_ADDRESS).transfer(VAULT_ADDRESS, wethToVault); - emit AccuntingFullyWithdrawnValidator(fullyWithdrawnValidators, activeDepositedValidators, wethToVault); + emit AccuntingFullyWithdrawnValidator( + fullyWithdrawnValidators, + activeDepositedValidators, + wethToVault + ); } uint256 ethRemaining = address(this).balance; @@ -108,23 +156,47 @@ abstract contract ValidatorAccountant is ValidatorRegistrator, Pausable { revert UnexpectedEthAccountingInterval(ethRemaining); } - // Beacon chain rewards swept + // Beacon chain rewards swept (partial validator withdrawals) if (ethRemaining <= fuseIntervalStart) { - - } + IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: ethRemaining }(); + beaconChainRewardWETH += ethRemaining; + emit AccountingBeaconChainRewards(ethRemaining); + } // Beacon chain rewards swept but also a slashed validator fully exited - else if (fuseIntervalEnd >= fuseIntervalEnd) { - - } - // Oh no... Fuse is blown. The governor (Multisig not OGV Governor) needs to set the + else if (ethRemaining >= fuseIntervalEnd) { + IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: ethRemaining }(); + IWETH9(WETH_TOKEN_ADDRESS).transfer(VAULT_ADDRESS, ethRemaining); + activeDepositedValidators -= 1; + + emit AccuntingValidatorSlashed( + activeDepositedValidators, + ethRemaining + ); + } + // Oh no... Fuse is blown. The governor (Multisig not OGV Governor) needs to set the // record straight by manually set the accounting values. else { + // will emit a paused event _pause(); } - } - function manuallyFixAccounting() external onlyAccountingGovernor { + function manuallyFixAccounting( + uint256 _activeDepositedValidators, + uint256 _ethToWeth, + uint256 _WethToBeSentToVault + ) external onlyAccountingGovernor { + activeDepositedValidators = _activeDepositedValidators; + if (_ethToWeth > 0) { + IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: _ethToWeth }(); + } + if (_WethToBeSentToVault > 0) { + IWETH9(WETH_TOKEN_ADDRESS).transfer( + VAULT_ADDRESS, + _WethToBeSentToVault + ); + } + _unpause(); } } diff --git a/contracts/contracts/strategies/NativeStaking/ValidatorRegistrator.sol b/contracts/contracts/strategies/NativeStaking/ValidatorRegistrator.sol index 457530eb45..c65d2c2526 100644 --- a/contracts/contracts/strategies/NativeStaking/ValidatorRegistrator.sol +++ b/contracts/contracts/strategies/NativeStaking/ValidatorRegistrator.sol @@ -13,7 +13,7 @@ abstract contract ValidatorRegistrator is Governable { address public validatorRegistrator; /// @notice The number of validators that have 32 (!) ETH actively deposited. When a new deposit /// to a validator happens this number increases, when a validator exit is detected this number - /// decreases. + /// decreases. uint256 activeDepositedValidators; // For future use uint256[50] private __gap; @@ -22,7 +22,10 @@ abstract contract ValidatorRegistrator is Governable { /// @dev Throws if called by any account other than the Registrator modifier onlyRegistrator() { - require(msg.sender == validatorRegistrator, "Caller is not the Registrator"); + require( + msg.sender == validatorRegistrator, + "Caller is not the Registrator" + ); _; } @@ -34,7 +37,11 @@ abstract contract ValidatorRegistrator is Governable { /// @notice return the WETH balance on the contract that can be used to for beacon chain /// staking - staking on the validators - function getWETHBalanceEligibleForStaking() public virtual view returns(uint256 _amount); + function getWETHBalanceEligibleForStaking() + public + view + virtual + returns (uint256 _amount); // /// @notice Stakes WETH to the NDC to the Node validators // /// @param validators A list of validator data needed to stake. diff --git a/contracts/deploy/001_core.js b/contracts/deploy/001_core.js index d933c72540..a02d1e6442 100644 --- a/contracts/deploy/001_core.js +++ b/contracts/deploy/001_core.js @@ -647,7 +647,9 @@ const configureStrategies = async (harvesterProxy, oethHarvesterProxy) => { .setHarvesterAddress(oethHarvesterProxy.address) ); - const nativeStakingSSVStrategyProxy = await ethers.getContract("NativeStakingSSVStrategyProxy"); + const nativeStakingSSVStrategyProxy = await ethers.getContract( + "NativeStakingSSVStrategyProxy" + ); const nativeStakingSSVStrategy = await ethers.getContractAt( "NativeStakingSSVStrategy", nativeStakingSSVStrategyProxy.address @@ -753,15 +755,17 @@ const deployNativeStakingSSVStrategy = async () => { dFeeAccumulatorProxy.address ); - log("Deploy NativeStakingSSVStrategy"); - const dStrategyImpl = await deployWithConfirmation("NativeStakingSSVStrategy", [ - [addresses.zero, cOETHVaultProxy.address], //_baseConfig - assetAddresses.WETH, // wethAddress - assetAddresses.SSV, // ssvToken - assetAddresses.SSVNetwork, // ssvNetwork - dFeeAccumulatorProxy.address // feeAccumulator - ]); + const dStrategyImpl = await deployWithConfirmation( + "NativeStakingSSVStrategy", + [ + [addresses.zero, cOETHVaultProxy.address], //_baseConfig + assetAddresses.WETH, // wethAddress + assetAddresses.SSV, // ssvToken + assetAddresses.SSVNetwork, // ssvNetwork + dFeeAccumulatorProxy.address, // feeAccumulator + ] + ); const cStrategyImpl = await ethers.getContractAt( "NativeStakingSSVStrategy", dStrategyImpl.address @@ -786,22 +790,22 @@ const deployNativeStakingSSVStrategy = async () => { log("Initialize the proxy and execute the initialize strategy function"); await withConfirmation( - cNativeStakingSSVStrategyProxy.connect(sDeployer)["initialize(address,address,bytes)"]( - cStrategyImpl.address, // implementation address - governorAddr, // governance - initData, // data for call to the initialize function on the strategy - ) + cNativeStakingSSVStrategyProxy + .connect(sDeployer) + ["initialize(address,address,bytes)"]( + cStrategyImpl.address, // implementation address + governorAddr, // governance + initData // data for call to the initialize function on the strategy + ) ); log("Approve spending of the SSV token"); - await cStrategy - .connect(sDeployer) - .safeApproveAllTokens(); + await cStrategy.connect(sDeployer).safeApproveAllTokens(); log("Deploy fee accumulator implementation"); const dFeeAccumulator = await deployWithConfirmation("FeeAccumulator", [ cNativeStakingSSVStrategyProxy.address, // _collector - assetAddresses.WETH // _weth + assetAddresses.WETH, // _weth ]); const cFeeAccumulator = await ethers.getContractAt( "FeeAccumulator", @@ -810,11 +814,13 @@ const deployNativeStakingSSVStrategy = async () => { log("Init fee accumulator proxy"); await withConfirmation( - cFeeAccumulatorProxy.connect(sDeployer)["initialize(address,address,bytes)"]( - cFeeAccumulator.address, // implementation address - governorAddr, // governance - "0x", // do not call any initialize functions - ) + cFeeAccumulatorProxy + .connect(sDeployer) + ["initialize(address,address,bytes)"]( + cFeeAccumulator.address, // implementation address + governorAddr, // governance + "0x" // do not call any initialize functions + ) ); return cStrategy; diff --git a/contracts/deploy/091_native_ssv_staking.js b/contracts/deploy/091_native_ssv_staking.js index cc2d732aa8..c7cb0403c4 100644 --- a/contracts/deploy/091_native_ssv_staking.js +++ b/contracts/deploy/091_native_ssv_staking.js @@ -49,13 +49,16 @@ module.exports = deploymentWithGovernanceProposal( ); // 3. Deploy the new strategy implementation - const dStrategyImpl = await deployWithConfirmation("NativeStakingSSVStrategy", [ - [addresses.zero, cVaultProxy.address], //_baseConfig - addresses.mainnet.WETH, // wethAddress - addresses.mainnet.SSV, // ssvToken - addresses.mainnet.SSVNetwork, // ssvNetwork - dFeeAccumulatorProxy.address // feeAccumulator - ]); + const dStrategyImpl = await deployWithConfirmation( + "NativeStakingSSVStrategy", + [ + [addresses.zero, cVaultProxy.address], //_baseConfig + addresses.mainnet.WETH, // wethAddress + addresses.mainnet.SSV, // ssvToken + addresses.mainnet.SSVNetwork, // ssvNetwork + dFeeAccumulatorProxy.address, // feeAccumulator + ] + ); const cStrategyImpl = await ethers.getContractAt( "NativeStakingSSVStrategy", dStrategyImpl.address @@ -92,7 +95,7 @@ module.exports = deploymentWithGovernanceProposal( // 5. Deploy the new fee accumulator implementation const dFeeAccumulator = await deployWithConfirmation("FeeAccumulator", [ cStrategyProxy.address, // _collector - addresses.mainnet.WETH // _weth + addresses.mainnet.WETH, // _weth ]); const cFeeAccumulator = await ethers.getContractAt( "FeeAccumulator", @@ -112,7 +115,10 @@ module.exports = deploymentWithGovernanceProposal( // 7. Safe approve SSV token spending await cStrategy.connect(sDeployer).safeApproveAllTokens(); - console.log("Native Staking SSV Strategy address: ", cStrategyProxy.address); + console.log( + "Native Staking SSV Strategy address: ", + cStrategyProxy.address + ); console.log("Fee accumulator address: ", cFeeAccumulator.address); // Governance Actions @@ -142,7 +148,22 @@ module.exports = deploymentWithGovernanceProposal( { contract: cStrategy, signature: "setFuseInterval(uint256, uint256)", - args: [ethers.utils.parseEther("21.6"), ethers.utils.parseEther("25.6")], + args: [ + ethers.utils.parseEther("21.6"), + ethers.utils.parseEther("25.6"), + ], + }, + // 5. configure the fuse interval + { + contract: cStrategy, + signature: "setAccountingGovernor(address)", + args: [strategistAddr], // TODO: change this to the defender action + }, + // 6. configure the fuse interval + { + contract: cStrategy, + signature: "setStrategist(address)", + args: [strategistAddr], }, ], }; diff --git a/contracts/test/_fixture.js b/contracts/test/_fixture.js index 983a74fa2b..a3c4b13836 100644 --- a/contracts/test/_fixture.js +++ b/contracts/test/_fixture.js @@ -362,7 +362,9 @@ const defaultFixture = deployments.createFixture(async () => { fluxStrategyProxy.address ); - const nativeStakingStrategyProxy = await ethers.getContract("NativeStakingSSVStrategyProxy"); + const nativeStakingStrategyProxy = await ethers.getContract( + "NativeStakingSSVStrategyProxy" + ); nativeStakingSSVStrategy = await ethers.getContractAt( "NativeStakingSSVStrategy", nativeStakingStrategyProxy.address @@ -466,7 +468,9 @@ const defaultFixture = deployments.createFixture(async () => { fraxEthStrategyProxy.address ); - const nativeStakingStrategyProxy = await ethers.getContract("NativeStakingSSVStrategyProxy"); + const nativeStakingStrategyProxy = await ethers.getContract( + "NativeStakingSSVStrategyProxy" + ); nativeStakingSSVStrategy = await ethers.getContractAt( "NativeStakingSSVStrategy", nativeStakingStrategyProxy.address @@ -1418,18 +1422,42 @@ async function nativeStakingSSVStrategyFixture() { .setAssetDefaultStrategy(weth.address, nativeStakingSSVStrategy.address); } else { const { governorAddr } = await getNamedAccounts(); - const { oethVault, weth, nativeStakingSSVStrategy } = fixture; + const { oethVault, weth, nativeStakingSSVStrategy, strategist } = fixture; const sGovernor = await ethers.provider.getSigner(governorAddr); // Approve Strategy - await oethVault.connect(sGovernor).approveStrategy(nativeStakingSSVStrategy.address); + await oethVault + .connect(sGovernor) + .approveStrategy(nativeStakingSSVStrategy.address); - console.log("nativeStakingSSVStrategy.address", nativeStakingSSVStrategy.address) + console.log( + "nativeStakingSSVStrategy.address", + nativeStakingSSVStrategy.address + ); + + const fuseStartBn = ethers.utils.parseEther("21.6"); + const fuseEndBn = ethers.utils.parseEther("25.6"); // Set as default await oethVault .connect(sGovernor) .setAssetDefaultStrategy(weth.address, nativeStakingSSVStrategy.address); + + await nativeStakingSSVStrategy + .connect(sGovernor) + .setFuseInterval(fuseStartBn, fuseEndBn); + + await nativeStakingSSVStrategy + .connect(sGovernor) + .setRegistratorAddress(governorAddr); + + await nativeStakingSSVStrategy + .connect(sGovernor) + .setAccountingGovernor(governorAddr); + + await nativeStakingSSVStrategy + .connect(sGovernor) + .setStrategist(strategist.address); } return fixture; diff --git a/contracts/test/_hot-deploy.js b/contracts/test/_hot-deploy.js index de1858caee..aff2caaf9f 100644 --- a/contracts/test/_hot-deploy.js +++ b/contracts/test/_hot-deploy.js @@ -17,7 +17,11 @@ const { impersonateAndFund } = require("../utils/signers"); const log = require("../utils/logger")("test:fixtures:hot-deploy"); // based on a contract name create new implementation -async function constructNewContract(fixture, fixtureStrategyVarName, implContractName) { +async function constructNewContract( + fixture, + fixtureStrategyVarName, + implContractName +) { const { deploy } = deployments; const getConstructorArguments = async () => { @@ -80,14 +84,16 @@ async function constructNewContract(fixture, fixtureStrategyVarName, implContrac ], ]; } else if (implContractName === "NativeStakingSSVStrategy") { - const feeAccumulatorAddress = await fixture[fixtureStrategyVarName].FEE_ACCUMULATOR_ADDRESS(); + const feeAccumulatorAddress = await fixture[ + fixtureStrategyVarName + ].FEE_ACCUMULATOR_ADDRESS(); return [ [addresses.zero, addresses.mainnet.OETHVaultProxy], [ addresses.mainnet.WETH, addresses.mainnet.SSV, addresses.mainnet.SSVNetwork, - addresses.mainnet.feeAccumulatorAddress + addresses.mainnet.feeAccumulatorAddress, ], ]; } diff --git a/contracts/test/helpers.js b/contracts/test/helpers.js index 8fb965b2b5..5bd9aeb785 100644 --- a/contracts/test/helpers.js +++ b/contracts/test/helpers.js @@ -473,7 +473,7 @@ const getAssetAddresses = async (deployments) => { AURA: (await deployments.get("MockAura")).address, BAL: (await deployments.get("MockBAL")).address, SSV: (await deployments.get("MockSSV")).address, - SSVNetwork: (await deployments.get("MockSSVNetwork")).address + SSVNetwork: (await deployments.get("MockSSVNetwork")).address, }; try { diff --git a/contracts/test/strategies/nativeSSVStaking.js b/contracts/test/strategies/nativeSSVStaking.js index c9533e9c55..613b262c10 100644 --- a/contracts/test/strategies/nativeSSVStaking.js +++ b/contracts/test/strategies/nativeSSVStaking.js @@ -1,8 +1,9 @@ const hre = require("hardhat"); const { expect } = require("chai"); const ethers = require("ethers"); -const utils = ethers.utils; +const { utils, BigNumber } = ethers; const addresses = require("../../utils/addresses"); +const { setBalance } = require("@nomicfoundation/hardhat-network-helpers"); const { units, oethUnits, isCI } = require("../helpers"); const { shouldBehaveLikeGovernable } = require("../behaviour/governable"); @@ -54,22 +55,27 @@ describe.only("ForkTest: Native SSV Staking Strategy", function () { it("Should not allow sending of ETH to the strategy via a transaction", async () => { const { nativeStakingSSVStrategy, strategist } = fixture; - const signer = nativeStakingSSVStrategy.provider.getSigner(strategist.address); + const signer = nativeStakingSSVStrategy.provider.getSigner( + strategist.address + ); tx = { - to: nativeStakingSSVStrategy.address, - value: ethers.utils.parseEther('2', 'ether') + to: nativeStakingSSVStrategy.address, + value: ethers.utils.parseEther("2", "ether"), }; - await expect( - signer.sendTransaction(tx) - ).to.be.revertedWith("function selector was not recognized and there's no fallback nor receive function"); + await expect(signer.sendTransaction(tx)).to.be.revertedWith( + "function selector was not recognized and there's no fallback nor receive function" + ); }); it("SSV network should have allowance to spend SSV tokens of the strategy", async () => { const { nativeStakingSSVStrategy, ssv } = fixture; - const ssvNetworkAddress = await nativeStakingSSVStrategy.SSV_NETWORK_ADDRESS(); - await expect(await ssv.allowance(nativeStakingSSVStrategy.address, ssvNetworkAddress)).to.equal(MAX_UINT256); + const ssvNetworkAddress = + await nativeStakingSSVStrategy.SSV_NETWORK_ADDRESS(); + await expect( + await ssv.allowance(nativeStakingSSVStrategy.address, ssvNetworkAddress) + ).to.equal(MAX_UINT256); }); }); @@ -82,89 +88,300 @@ describe.only("ForkTest: Native SSV Staking Strategy", function () { .setRegistratorAddress(strategist.address); const events = (await tx.wait()).events || []; - const RegistratorAddressChangedEvent = events.find((e) => e.event === "RegistratorAddressChanged"); + const RegistratorAddressChangedEvent = events.find( + (e) => e.event === "RegistratorAddressChanged" + ); expect(RegistratorAddressChangedEvent).to.not.be.undefined; - expect(RegistratorAddressChangedEvent.event).to.equal("RegistratorAddressChanged"); - expect(RegistratorAddressChangedEvent.args[0]).to.equal(addresses.zero); - expect(RegistratorAddressChangedEvent.args[1]).to.equal(strategist.address); + expect(RegistratorAddressChangedEvent.event).to.equal( + "RegistratorAddressChanged" + ); + expect(RegistratorAddressChangedEvent.args[0]).to.equal(governor.address); + expect(RegistratorAddressChangedEvent.args[1]).to.equal( + strategist.address + ); }); it("Non governor should not be able to change the registrator address", async () => { const { nativeStakingSSVStrategy, governor, strategist } = fixture; - await expect(nativeStakingSSVStrategy - .connect(strategist) - .setRegistratorAddress(strategist.address) + await expect( + nativeStakingSSVStrategy + .connect(strategist) + .setRegistratorAddress(strategist.address) ).to.be.revertedWith("Caller is not the Governor"); }); it("Non governor should not be able to update the fuse intervals", async () => { const { nativeStakingSSVStrategy, governor, strategist } = fixture; - await expect(nativeStakingSSVStrategy - .connect(strategist) - .setFuseInterval(utils.parseEther("21.6"), utils.parseEther("25.6")) + await expect( + nativeStakingSSVStrategy + .connect(strategist) + .setFuseInterval(utils.parseEther("21.6"), utils.parseEther("25.6")) ).to.be.revertedWith("Caller is not the Governor"); }); it("Fuse interval start needs to be larger than fuse end", async () => { const { nativeStakingSSVStrategy, governor } = fixture; - await expect(nativeStakingSSVStrategy - .connect(governor) - .setFuseInterval(utils.parseEther("25.6"), utils.parseEther("21.6")) + await expect( + nativeStakingSSVStrategy + .connect(governor) + .setFuseInterval(utils.parseEther("25.6"), utils.parseEther("21.6")) ).to.be.revertedWith("FuseIntervalValuesIncorrect"); }); it("There should be at least 4 ETH between interval start and interval end", async () => { const { nativeStakingSSVStrategy, governor } = fixture; - await expect(nativeStakingSSVStrategy - .connect(governor) - .setFuseInterval(utils.parseEther("21.6"), utils.parseEther("25.5")) + await expect( + nativeStakingSSVStrategy + .connect(governor) + .setFuseInterval(utils.parseEther("21.6"), utils.parseEther("25.5")) ).to.be.revertedWith("FuseIntervalValuesIncorrect"); }); it("Revert when fuse intervals are larger than 32 ether", async () => { const { nativeStakingSSVStrategy, governor } = fixture; - await expect(nativeStakingSSVStrategy - .connect(governor) - .setFuseInterval(utils.parseEther("32.1"), utils.parseEther("32.1")) + await expect( + nativeStakingSSVStrategy + .connect(governor) + .setFuseInterval(utils.parseEther("32.1"), utils.parseEther("32.1")) ).to.be.revertedWith("FuseIntervalValuesIncorrect"); }); - it("Governor should be able to change the registrator address", async () => { + it("Governor should be able to change fuse interval", async () => { const { nativeStakingSSVStrategy, governor } = fixture; - const fuseStartBn = utils.parseEther("21.6"); - const fuseEndBn = utils.parseEther("25.6"); + const oldFuseStartBn = utils.parseEther("21.6"); + const oldFuseEndBn = utils.parseEther("25.6"); + const fuseStartBn = utils.parseEther("22.6"); + const fuseEndBn = utils.parseEther("26.6"); const tx = await nativeStakingSSVStrategy .connect(governor) .setFuseInterval(fuseStartBn, fuseEndBn); const events = (await tx.wait()).events || []; - const FuseIntervalUpdated = events.find((e) => e.event === "FuseIntervalUpdated"); + const FuseIntervalUpdated = events.find( + (e) => e.event === "FuseIntervalUpdated" + ); expect(FuseIntervalUpdated).to.not.be.undefined; expect(FuseIntervalUpdated.event).to.equal("FuseIntervalUpdated"); - expect(FuseIntervalUpdated.args[0]).to.equal(addresses.zero); // prev fuse start - expect(FuseIntervalUpdated.args[1]).to.equal(addresses.zero); // prev fuse end + expect(FuseIntervalUpdated.args[0]).to.equal(oldFuseStartBn); // prev fuse start + expect(FuseIntervalUpdated.args[1]).to.equal(oldFuseEndBn); // prev fuse end expect(FuseIntervalUpdated.args[2]).to.equal(fuseStartBn); // fuse start expect(FuseIntervalUpdated.args[3]).to.equal(fuseEndBn); // fuse end }); - }); - describe("Deposit/Allocation", function () { - - }); + it("Only accounting governor can call accounting", async () => {}); + + it("Only governor can change the accounting governor", async () => { + const { nativeStakingSSVStrategy, governor, strategist } = fixture; + + await expect( + nativeStakingSSVStrategy + .connect(strategist) + .setAccountingGovernor(strategist.address) + ).to.be.revertedWith("Caller is not the Governor"); + }); + + it("Only governor can change the strategist", async () => { + const { nativeStakingSSVStrategy, governor, strategist } = fixture; - describe("Withdraw", function () { - + await expect( + nativeStakingSSVStrategy + .connect(strategist) + .setStrategist(strategist.address) + ).to.be.revertedWith("Caller is not the Governor"); + }); + + it("Change the accounting governor", async () => { + const { nativeStakingSSVStrategy, governor, strategist } = fixture; + + const tx = await nativeStakingSSVStrategy + .connect(governor) + .setAccountingGovernor(strategist.address); + + const events = (await tx.wait()).events || []; + const AccountingGovernorChangedEvent = events.find( + (e) => e.event === "AccountingGovernorAddressChanged" + ); + + expect(AccountingGovernorChangedEvent).to.not.be.undefined; + expect(AccountingGovernorChangedEvent.event).to.equal( + "AccountingGovernorAddressChanged" + ); + expect(AccountingGovernorChangedEvent.args[0]).to.equal(governor.address); + expect(AccountingGovernorChangedEvent.args[1]).to.equal( + strategist.address + ); + }); + + it("Change the strategist", async () => { + const { nativeStakingSSVStrategy, governor, strategist } = fixture; + + const tx = await nativeStakingSSVStrategy + .connect(governor) + .setStrategist(governor.address); + + const events = (await tx.wait()).events || []; + const strategistAddressChanged = events.find( + (e) => e.event === "StrategistAddressChanged" + ); + + expect(strategistAddressChanged).to.not.be.undefined; + expect(strategistAddressChanged.event).to.equal( + "StrategistAddressChanged" + ); + expect(strategistAddressChanged.args[0]).to.equal(strategist.address); + expect(strategistAddressChanged.args[1]).to.equal(governor.address); + }); }); - describe("Balance/Assets", function () { + describe("Accounting", function () { + const testCases = [ + { + ethBalance: utils.parseEther("14"), + expectedRewards: utils.parseEther("14"), + expectedValidatorsFullWithdrawals: 0, + slashDetected: false, + fuseBlown: false, + }, + { + ethBalance: utils.parseEther("34"), + expectedRewards: utils.parseEther("2"), + expectedValidatorsFullWithdrawals: 1, + slashDetected: false, + fuseBlown: false, + }, + { + ethBalance: utils.parseEther("276"), + expectedRewards: utils.parseEther("20"), + expectedValidatorsFullWithdrawals: 8, + slashDetected: false, + fuseBlown: false, + }, + { + ethBalance: utils.parseEther("22"), + expectedRewards: utils.parseEther("0"), + expectedValidatorsFullWithdrawals: 0, + slashDetected: false, + fuseBlown: true, + }, + { + ethBalance: utils.parseEther("54"), + expectedRewards: utils.parseEther("0"), + expectedValidatorsFullWithdrawals: 1, + slashDetected: false, + fuseBlown: true, + }, + { + ethBalance: utils.parseEther("26.6"), + expectedRewards: utils.parseEther("0"), + expectedValidatorsFullWithdrawals: 0, + slashDetected: true, + fuseBlown: false, + }, + { + ethBalance: utils.parseEther("58.6"), // 26.6 + 32 + expectedRewards: utils.parseEther("0"), + expectedValidatorsFullWithdrawals: 1, + slashDetected: true, + fuseBlown: false, + }, + ]; + + for (const testCase of testCases) { + const { + ethBalance, + expectedRewards, + expectedValidatorsFullWithdrawals, + slashDetected, + fuseBlown, + } = testCase; + it.only(`Expect that ${utils.formatUnits( + ethBalance + )} ETH will result in ${utils.formatUnits( + expectedRewards + )} ETH rewards and ${expectedValidatorsFullWithdrawals} validators withdrawn.`, async () => { + const { nativeStakingSSVStrategy, governor, strategist } = fixture; + + // setup state + await setBalance(nativeStakingSSVStrategy.address, ethBalance); + // pause, so manuallyFixAccounting can be called + await nativeStakingSSVStrategy.connect(strategist).pause(); + await nativeStakingSSVStrategy.connect(governor).manuallyFixAccounting( + BigNumber.from("30"), // activeDepositedValidators + BigNumber.from("0"), // ethToWeth + BigNumber.from("0") // WethToBeSentToVault + ); + + // check accounting values + const tx = await nativeStakingSSVStrategy + .connect(governor) + .doAccounting(); + + const events = (await tx.wait()).events || []; + + const BeaconRewardsEvent = events.find( + (e) => e.event === "AccountingBeaconChainRewards" + ); + if (expectedRewards.gt(BigNumber.from("0"))) { + expect(BeaconRewardsEvent).to.not.be.undefined; + expect(BeaconRewardsEvent.args[0]).to.equal(expectedRewards); + } else { + expect(BeaconRewardsEvent).to.be.undefined; + } + + const WithdrawnEvent = events.find( + (e) => e.event === "AccuntingFullyWithdrawnValidator" + ); + if (expectedValidatorsFullWithdrawals > 0) { + expect(WithdrawnEvent).to.not.be.undefined; + expect(WithdrawnEvent.args[0]).to.equal( + BigNumber.from(`${expectedValidatorsFullWithdrawals}`) + ); + // still active validators + expect(WithdrawnEvent.args[1]).to.equal( + BigNumber.from(`${30 - expectedValidatorsFullWithdrawals}`) + ); + // weth sent to vault + expect(WithdrawnEvent.args[2]).to.equal( + utils + .parseEther("32") + .mul(BigNumber.from(`${expectedValidatorsFullWithdrawals}`)) + ); + } else { + expect(WithdrawnEvent).to.be.undefined; + } + + const PausedEvent = events.find((e) => e.event === "Paused"); + if (fuseBlown) { + expect(PausedEvent).to.not.be.undefined; + } else { + expect(PausedEvent).to.be.undefined; + } + + const SlashEvent = events.find( + (e) => e.event === "AccuntingValidatorSlashed" + ); + if (slashDetected) { + expect(SlashEvent).to.not.be.undefined; + expect(SlashEvent.args[0]).to.equal( + BigNumber.from(`${30 - expectedValidatorsFullWithdrawals - 1}`) + ); + } else { + expect(SlashEvent).to.be.undefined; + } + }); + } }); + + describe("Withdraw", function () {}); + + describe("Balance/Assets", function () {}); }); diff --git a/contracts/test/strategies/nativeSsvStaking.fork-test.js b/contracts/test/strategies/nativeSsvStaking.fork-test.js index 5b2ef52a62..f5d6b1512d 100644 --- a/contracts/test/strategies/nativeSsvStaking.fork-test.js +++ b/contracts/test/strategies/nativeSsvStaking.fork-test.js @@ -27,33 +27,24 @@ describe("ForkTest: Native SSV Staking Strategy", function () { describe("Initial setup", function () { it("Should verify the initial state", async () => { const { weth, nativeStakingSSVStrategy } = fixture; - await expect(await nativeStakingSSVStrategy.WETH_TOKEN_ADDRESS()).to.equal( - addresses.mainnet.WETH, - "Incorrect WETH address set" - ); + await expect( + await nativeStakingSSVStrategy.WETH_TOKEN_ADDRESS() + ).to.equal(addresses.mainnet.WETH, "Incorrect WETH address set"); await expect(await nativeStakingSSVStrategy.SSV_TOKEN_ADDRESS()).to.equal( addresses.mainnet.SSV, "Incorrect SSV Token address" ); - await expect(await nativeStakingSSVStrategy.SSV_NETWORK_ADDRESS()).to.equal( - addresses.mainnet.SSVNetwork, - "Incorrect SSV Network address" - ); + await expect( + await nativeStakingSSVStrategy.SSV_NETWORK_ADDRESS() + ).to.equal(addresses.mainnet.SSVNetwork, "Incorrect SSV Network address"); }); - it.skip("Should check that the fuse interval is configured correctly", async () => { - - }); + it.skip("Should check that the fuse interval is configured correctly", async () => {}); }); - describe("Deposit/Allocation", function () { - - }); + describe("Deposit/Allocation", function () {}); - describe("Withdraw", function () { - - }); + describe("Withdraw", function () {}); - describe("Balance/Assets", function () { - }); + describe("Balance/Assets", function () {}); }); From e99f86ca2fbee108a0303481be0e705bd9a03bbe Mon Sep 17 00:00:00 2001 From: Domen Grabec Date: Mon, 15 Apr 2024 11:01:13 +0200 Subject: [PATCH 008/273] add some comments --- contracts/test/strategies/nativeSSVStaking.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/contracts/test/strategies/nativeSSVStaking.js b/contracts/test/strategies/nativeSSVStaking.js index 613b262c10..49e831be69 100644 --- a/contracts/test/strategies/nativeSSVStaking.js +++ b/contracts/test/strategies/nativeSSVStaking.js @@ -244,6 +244,7 @@ describe.only("ForkTest: Native SSV Staking Strategy", function () { describe("Accounting", function () { const testCases = [ + // normal beacon chain rewards { ethBalance: utils.parseEther("14"), expectedRewards: utils.parseEther("14"), @@ -251,6 +252,7 @@ describe.only("ForkTest: Native SSV Staking Strategy", function () { slashDetected: false, fuseBlown: false, }, + // normal beacon chain rewards + 1 withdrawn validator { ethBalance: utils.parseEther("34"), expectedRewards: utils.parseEther("2"), @@ -258,6 +260,7 @@ describe.only("ForkTest: Native SSV Staking Strategy", function () { slashDetected: false, fuseBlown: false, }, + // 8 withdrawn validators + beacon chain rewards { ethBalance: utils.parseEther("276"), expectedRewards: utils.parseEther("20"), @@ -265,6 +268,7 @@ describe.only("ForkTest: Native SSV Staking Strategy", function () { slashDetected: false, fuseBlown: false, }, + // fuse blown { ethBalance: utils.parseEther("22"), expectedRewards: utils.parseEther("0"), @@ -272,6 +276,7 @@ describe.only("ForkTest: Native SSV Staking Strategy", function () { slashDetected: false, fuseBlown: true, }, + // fuse blown + 1 full withdrawal { ethBalance: utils.parseEther("54"), expectedRewards: utils.parseEther("0"), @@ -279,6 +284,7 @@ describe.only("ForkTest: Native SSV Staking Strategy", function () { slashDetected: false, fuseBlown: true, }, + // 1 validator slashed { ethBalance: utils.parseEther("26.6"), expectedRewards: utils.parseEther("0"), @@ -286,6 +292,7 @@ describe.only("ForkTest: Native SSV Staking Strategy", function () { slashDetected: true, fuseBlown: false, }, + // 1 validator fully withdrawn + 1 slashed { ethBalance: utils.parseEther("58.6"), // 26.6 + 32 expectedRewards: utils.parseEther("0"), From 52ba11ea29dcb4bc052dc603e3bcce2132f589c5 Mon Sep 17 00:00:00 2001 From: Domen Grabec Date: Mon, 15 Apr 2024 14:26:32 +0200 Subject: [PATCH 009/273] add tests for manually fixing accounting --- .../NativeStaking/ValidatorAccountant.sol | 58 +++++++- contracts/test/strategies/nativeSSVStaking.js | 133 +++++++++++++++++- 2 files changed, 182 insertions(+), 9 deletions(-) diff --git a/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol b/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol index 8f9cbdeaf6..9f7f0abf8f 100644 --- a/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol +++ b/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol @@ -55,14 +55,26 @@ abstract contract ValidatorAccountant is ValidatorRegistrator, Pausable { address oldAddress, address newAddress ); + event AccountingBeaconChainRewards(uint256 amount); event StrategistAddressChanged( address oldStrategist, address newStrategist ); - event AccountingBeaconChainRewards(uint256 amount); - error FuseIntervalValuesIncorrect(); + event AccountingManuallyFixed( + uint256 oldActiveDepositedValidators, + uint256 activeDepositedValidators, + uint256 oldBeaconChainRewardWETH, + uint256 beaconChainRewardWETH, + uint256 ethToWeth, + uint256 wethToBeSentToVault + ); + error UnexpectedEthAccountingInterval(uint256 errorneousEthAmount); + error ManualFixAccountingThresholdReached(); + error FuseIntervalValuesIncorrect(); + error NotPaused(); + error InsuffiscientETHbalance(); /// @dev Throws if called by any account other than the Accounting Governor modifier onlyAccountingGovernor() { @@ -181,19 +193,55 @@ abstract contract ValidatorAccountant is ValidatorRegistrator, Pausable { } } + /// @dev allow the accounting governor to fix the accounting of this strategy and unpause + /// @param _activeDepositedValidators the override value of activeDepositedValidators + /// @param _ethToWeth the amount of ETH to be converted to WETH + /// @param _wethToBeSentToVault the amount of WETH to be sent to the Vault + /// @param _beaconChainRewardWETH the override value for beaconChainRewardWETH + /// @param _ethThresholdCheck maximum allowed ETH balance on the contract for the function to run + /// @param _wethThresholdCheck maximum allowed WETH balance on the contract for the function to run + /// the above 2 checks are done so transaction doesn't get front run and cause + /// unexpected behaviour function manuallyFixAccounting( uint256 _activeDepositedValidators, uint256 _ethToWeth, - uint256 _WethToBeSentToVault + uint256 _wethToBeSentToVault, + uint256 _beaconChainRewardWETH, + uint256 _ethThresholdCheck, + uint256 _wethThresholdCheck ) external onlyAccountingGovernor { + if (!paused()) { + revert NotPaused(); + } + + uint256 ethBalance = address(this).balance; + uint256 wethBalance = IWETH9(WETH_TOKEN_ADDRESS).balanceOf(address(this)); + + if (ethBalance > _ethThresholdCheck || wethBalance > _wethThresholdCheck) { + revert ManualFixAccountingThresholdReached(); + } + + emit AccountingManuallyFixed( + activeDepositedValidators, + _activeDepositedValidators, + beaconChainRewardWETH, + _beaconChainRewardWETH, + _ethToWeth, + _wethToBeSentToVault + ); + activeDepositedValidators = _activeDepositedValidators; + beaconChainRewardWETH = _beaconChainRewardWETH; if (_ethToWeth > 0) { + if (ethBalance < _ethToWeth) { + revert InsuffiscientETHbalance(); + } IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: _ethToWeth }(); } - if (_WethToBeSentToVault > 0) { + if (_wethToBeSentToVault > 0) { IWETH9(WETH_TOKEN_ADDRESS).transfer( VAULT_ADDRESS, - _WethToBeSentToVault + _wethToBeSentToVault ); } diff --git a/contracts/test/strategies/nativeSSVStaking.js b/contracts/test/strategies/nativeSSVStaking.js index 49e831be69..22b7d10ea2 100644 --- a/contracts/test/strategies/nativeSSVStaking.js +++ b/contracts/test/strategies/nativeSSVStaking.js @@ -310,7 +310,7 @@ describe.only("ForkTest: Native SSV Staking Strategy", function () { slashDetected, fuseBlown, } = testCase; - it.only(`Expect that ${utils.formatUnits( + it(`Expect that ${utils.formatUnits( ethBalance )} ETH will result in ${utils.formatUnits( expectedRewards @@ -322,9 +322,12 @@ describe.only("ForkTest: Native SSV Staking Strategy", function () { // pause, so manuallyFixAccounting can be called await nativeStakingSSVStrategy.connect(strategist).pause(); await nativeStakingSSVStrategy.connect(governor).manuallyFixAccounting( - BigNumber.from("30"), // activeDepositedValidators - BigNumber.from("0"), // ethToWeth - BigNumber.from("0") // WethToBeSentToVault + 30, // activeDepositedValidators + ethers.utils.parseEther("0", "ether"), //_ethToWeth + ethers.utils.parseEther("0", "ether"), //_wethToBeSentToVault + ethers.utils.parseEther("0", "ether"), //_beaconChainRewardWETH + ethers.utils.parseEther("3000", "ether"), //_ethThresholdCheck + ethers.utils.parseEther("3000", "ether"), //_wethThresholdCheck ); // check accounting values @@ -386,6 +389,128 @@ describe.only("ForkTest: Native SSV Staking Strategy", function () { } }); } + + it("Only accounting governor is allowed to manually fix accounting", async () => { + const { nativeStakingSSVStrategy, governor, strategist } = fixture; + + await nativeStakingSSVStrategy.connect(strategist).pause(); + // unit test fixture sets OUSD governor as accounting governor + await expect( + nativeStakingSSVStrategy + .connect(strategist) + .manuallyFixAccounting( + 10, //_activeDepositedValidators + ethers.utils.parseEther("2", "ether"), //_ethToWeth + ethers.utils.parseEther("2", "ether"), //_wethToBeSentToVault + ethers.utils.parseEther("2", "ether"), //_beaconChainRewardWETH + ethers.utils.parseEther("0", "ether"), //_ethThresholdCheck + ethers.utils.parseEther("0", "ether"), //_wethThresholdCheck + ) + ).to.be.revertedWith("Caller is not the Accounting Governor"); + }); + + it("Accounting needs to be paused in order to call fix accounting function", async () => { + const { nativeStakingSSVStrategy, governor } = fixture; + + // unit test fixture sets OUSD governor as accounting governor + await expect( + nativeStakingSSVStrategy + .connect(governor) + .manuallyFixAccounting( + 10, //_activeDepositedValidators + ethers.utils.parseEther("2", "ether"), //_ethToWeth + ethers.utils.parseEther("2", "ether"), //_wethToBeSentToVault + ethers.utils.parseEther("2", "ether"), //_beaconChainRewardWETH + ethers.utils.parseEther("1", "ether"), //_ethThresholdCheck + ethers.utils.parseEther("0", "ether"), //_wethThresholdCheck + ) + ).to.be.revertedWith("NotPaused"); + }); + + it("Should not execute manual recovery if eth threshold reached", async () => { + const { nativeStakingSSVStrategy, strategist, governor, josh, weth } = fixture; + + await setBalance(nativeStakingSSVStrategy.address, ethers.utils.parseEther("6", "ether")); + await weth + .connect(josh) + .transfer(nativeStakingSSVStrategy.address, ethers.utils.parseEther("5", "ether")); + + await nativeStakingSSVStrategy.connect(strategist).pause(); + await expect( + nativeStakingSSVStrategy + .connect(governor) + .manuallyFixAccounting( + 10, //_activeDepositedValidators + ethers.utils.parseEther("2", "ether"), //_ethToWeth + ethers.utils.parseEther("2", "ether"), //_wethToBeSentToVault + ethers.utils.parseEther("2", "ether"), //_beaconChainRewardWETH + ethers.utils.parseEther("5", "ether"), //_ethThresholdCheck + ethers.utils.parseEther("5", "ether"), //_wethThresholdCheck + ) + ).to.be.revertedWith("ManualFixAccountingThresholdReached"); + }); + + it("Should not execute manual recovery if weth threshold reached", async () => { + const { nativeStakingSSVStrategy, strategist, governor, josh, weth } = fixture; + + await setBalance(nativeStakingSSVStrategy.address, ethers.utils.parseEther("5", "ether")); + await weth + .connect(josh) + .transfer(nativeStakingSSVStrategy.address, ethers.utils.parseEther("6", "ether")); + + await nativeStakingSSVStrategy.connect(strategist).pause(); + await expect( + nativeStakingSSVStrategy + .connect(governor) + .manuallyFixAccounting( + 10, //_activeDepositedValidators + ethers.utils.parseEther("2", "ether"), //_ethToWeth + ethers.utils.parseEther("2", "ether"), //_wethToBeSentToVault + ethers.utils.parseEther("2", "ether"), //_beaconChainRewardWETH + ethers.utils.parseEther("5", "ether"), //_ethThresholdCheck + ethers.utils.parseEther("5", "ether"), //_wethThresholdCheck + ) + ).to.be.revertedWith("ManualFixAccountingThresholdReached"); + }); + + it("Should allow 5/8 governor to recover paused contract and correct the accounting state", async () => { + const { nativeStakingSSVStrategy, strategist, governor, josh, weth } = fixture; + + await setBalance(nativeStakingSSVStrategy.address, ethers.utils.parseEther("5", "ether")); + await weth + .connect(josh) + .transfer(nativeStakingSSVStrategy.address, ethers.utils.parseEther("5", "ether")); + + await nativeStakingSSVStrategy.connect(strategist).pause(); + // unit test fixture sets OUSD governor as accounting governor + const tx = await nativeStakingSSVStrategy + .connect(governor) + .manuallyFixAccounting( + 3, //_activeDepositedValidators + ethers.utils.parseEther("2.1", "ether"), //_ethToWeth + ethers.utils.parseEther("2.2", "ether"), //_wethToBeSentToVault + ethers.utils.parseEther("2.3", "ether"), //_beaconChainRewardWETH + ethers.utils.parseEther("5", "ether"), //_ethThresholdCheck + ethers.utils.parseEther("5", "ether"), //_wethThresholdCheck + ); + + const events = (await tx.wait()).events || []; + const AccountingManuallyFixedEvent = events.find( + (e) => e.event === "AccountingManuallyFixed" + ); + + expect(AccountingManuallyFixedEvent).to.not.be.undefined; + expect(AccountingManuallyFixedEvent.event).to.equal( + "AccountingManuallyFixed" + ); + expect(AccountingManuallyFixedEvent.args[0]).to.equal(0); // oldActiveDepositedValidators + expect(AccountingManuallyFixedEvent.args[1]).to.equal(3); // activeDepositedValidators + expect(AccountingManuallyFixedEvent.args[2]).to.equal(ethers.utils.parseEther("0", "ether")); // oldBeaconChainRewardWETH + expect(AccountingManuallyFixedEvent.args[3]).to.equal(ethers.utils.parseEther("2.3", "ether")); // beaconChainRewardWETH + expect(AccountingManuallyFixedEvent.args[4]).to.equal(ethers.utils.parseEther("2.1", "ether")); // ethToWeth + expect(AccountingManuallyFixedEvent.args[5]).to.equal(ethers.utils.parseEther("2.2", "ether")); // wethToBeSentToVault + + }); }); describe("Withdraw", function () {}); From e656ecb1dbcccbc5f589ab30176f8475ecc240a6 Mon Sep 17 00:00:00 2001 From: Domen Grabec Date: Mon, 15 Apr 2024 14:34:21 +0200 Subject: [PATCH 010/273] lint and prettier --- .../NativeStaking/ValidatorAccountant.sol | 12 +- contracts/deploy/001_core.js | 30 ++-- contracts/deploy/091_native_ssv_staking.js | 4 +- contracts/test/_hot-deploy.js | 2 +- contracts/test/strategies/nativeSSVStaking.js | 166 ++++++++++-------- 5 files changed, 118 insertions(+), 96 deletions(-) diff --git a/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol b/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol index 9f7f0abf8f..794003b216 100644 --- a/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol +++ b/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol @@ -198,8 +198,8 @@ abstract contract ValidatorAccountant is ValidatorRegistrator, Pausable { /// @param _ethToWeth the amount of ETH to be converted to WETH /// @param _wethToBeSentToVault the amount of WETH to be sent to the Vault /// @param _beaconChainRewardWETH the override value for beaconChainRewardWETH - /// @param _ethThresholdCheck maximum allowed ETH balance on the contract for the function to run - /// @param _wethThresholdCheck maximum allowed WETH balance on the contract for the function to run + /// @param _ethThresholdCheck maximum allowed ETH balance on the contract for the function to run + /// @param _wethThresholdCheck maximum allowed WETH balance on the contract for the function to run /// the above 2 checks are done so transaction doesn't get front run and cause /// unexpected behaviour function manuallyFixAccounting( @@ -215,9 +215,13 @@ abstract contract ValidatorAccountant is ValidatorRegistrator, Pausable { } uint256 ethBalance = address(this).balance; - uint256 wethBalance = IWETH9(WETH_TOKEN_ADDRESS).balanceOf(address(this)); + uint256 wethBalance = IWETH9(WETH_TOKEN_ADDRESS).balanceOf( + address(this) + ); - if (ethBalance > _ethThresholdCheck || wethBalance > _wethThresholdCheck) { + if ( + ethBalance > _ethThresholdCheck || wethBalance > _wethThresholdCheck + ) { revert ManualFixAccountingThresholdReached(); } diff --git a/contracts/deploy/001_core.js b/contracts/deploy/001_core.js index a02d1e6442..6a634cc642 100644 --- a/contracts/deploy/001_core.js +++ b/contracts/deploy/001_core.js @@ -790,13 +790,14 @@ const deployNativeStakingSSVStrategy = async () => { log("Initialize the proxy and execute the initialize strategy function"); await withConfirmation( - cNativeStakingSSVStrategyProxy - .connect(sDeployer) - ["initialize(address,address,bytes)"]( - cStrategyImpl.address, // implementation address - governorAddr, // governance - initData // data for call to the initialize function on the strategy - ) + cNativeStakingSSVStrategyProxy.connect(sDeployer)[ + // eslint-disable-next-line no-unexpected-multiline + "initialize(address,address,bytes)" + ]( + cStrategyImpl.address, // implementation address + governorAddr, // governance + initData // data for call to the initialize function on the strategy + ) ); log("Approve spending of the SSV token"); @@ -814,13 +815,14 @@ const deployNativeStakingSSVStrategy = async () => { log("Init fee accumulator proxy"); await withConfirmation( - cFeeAccumulatorProxy - .connect(sDeployer) - ["initialize(address,address,bytes)"]( - cFeeAccumulator.address, // implementation address - governorAddr, // governance - "0x" // do not call any initialize functions - ) + cFeeAccumulatorProxy.connect(sDeployer)[ + // eslint-disable-next-line no-unexpected-multiline + "initialize(address,address,bytes)" + ]( + cFeeAccumulator.address, // implementation address + governorAddr, // governance + "0x" // do not call any initialize functions + ) ); return cStrategy; diff --git a/contracts/deploy/091_native_ssv_staking.js b/contracts/deploy/091_native_ssv_staking.js index c7cb0403c4..60aecc157a 100644 --- a/contracts/deploy/091_native_ssv_staking.js +++ b/contracts/deploy/091_native_ssv_staking.js @@ -157,13 +157,13 @@ module.exports = deploymentWithGovernanceProposal( { contract: cStrategy, signature: "setAccountingGovernor(address)", - args: [strategistAddr], // TODO: change this to the defender action + args: [deployerAddr], // TODO: change this to the defender action }, // 6. configure the fuse interval { contract: cStrategy, signature: "setStrategist(address)", - args: [strategistAddr], + args: [deployerAddr], }, ], }; diff --git a/contracts/test/_hot-deploy.js b/contracts/test/_hot-deploy.js index aff2caaf9f..dfcdde466d 100644 --- a/contracts/test/_hot-deploy.js +++ b/contracts/test/_hot-deploy.js @@ -93,7 +93,7 @@ async function constructNewContract( addresses.mainnet.WETH, addresses.mainnet.SSV, addresses.mainnet.SSVNetwork, - addresses.mainnet.feeAccumulatorAddress, + feeAccumulatorAddress, ], ]; } diff --git a/contracts/test/strategies/nativeSSVStaking.js b/contracts/test/strategies/nativeSSVStaking.js index 22b7d10ea2..61c023d65f 100644 --- a/contracts/test/strategies/nativeSSVStaking.js +++ b/contracts/test/strategies/nativeSSVStaking.js @@ -1,11 +1,9 @@ -const hre = require("hardhat"); const { expect } = require("chai"); const ethers = require("ethers"); const { utils, BigNumber } = ethers; -const addresses = require("../../utils/addresses"); const { setBalance } = require("@nomicfoundation/hardhat-network-helpers"); -const { units, oethUnits, isCI } = require("../helpers"); +const { isCI } = require("../helpers"); const { shouldBehaveLikeGovernable } = require("../behaviour/governable"); const { shouldBehaveLikeHarvestable } = require("../behaviour/harvestable"); const { shouldBehaveLikeStrategy } = require("../behaviour/strategy"); @@ -15,8 +13,6 @@ const { createFixtureLoader, nativeStakingSSVStrategyFixture, } = require("./../_fixture"); -const { impersonateAndFund } = require("../../utils/signers"); -const { setERC20TokenBalance } = require("../_fund"); const loadFixture = createFixtureLoader(nativeStakingSSVStrategyFixture); @@ -58,7 +54,7 @@ describe.only("ForkTest: Native SSV Staking Strategy", function () { const signer = nativeStakingSSVStrategy.provider.getSigner( strategist.address ); - tx = { + const tx = { to: nativeStakingSSVStrategy.address, value: ethers.utils.parseEther("2", "ether"), }; @@ -103,7 +99,7 @@ describe.only("ForkTest: Native SSV Staking Strategy", function () { }); it("Non governor should not be able to change the registrator address", async () => { - const { nativeStakingSSVStrategy, governor, strategist } = fixture; + const { nativeStakingSSVStrategy, strategist } = fixture; await expect( nativeStakingSSVStrategy @@ -113,7 +109,7 @@ describe.only("ForkTest: Native SSV Staking Strategy", function () { }); it("Non governor should not be able to update the fuse intervals", async () => { - const { nativeStakingSSVStrategy, governor, strategist } = fixture; + const { nativeStakingSSVStrategy, strategist } = fixture; await expect( nativeStakingSSVStrategy @@ -180,7 +176,7 @@ describe.only("ForkTest: Native SSV Staking Strategy", function () { it("Only accounting governor can call accounting", async () => {}); it("Only governor can change the accounting governor", async () => { - const { nativeStakingSSVStrategy, governor, strategist } = fixture; + const { nativeStakingSSVStrategy, strategist } = fixture; await expect( nativeStakingSSVStrategy @@ -190,7 +186,7 @@ describe.only("ForkTest: Native SSV Staking Strategy", function () { }); it("Only governor can change the strategist", async () => { - const { nativeStakingSSVStrategy, governor, strategist } = fixture; + const { nativeStakingSSVStrategy, strategist } = fixture; await expect( nativeStakingSSVStrategy @@ -327,7 +323,7 @@ describe.only("ForkTest: Native SSV Staking Strategy", function () { ethers.utils.parseEther("0", "ether"), //_wethToBeSentToVault ethers.utils.parseEther("0", "ether"), //_beaconChainRewardWETH ethers.utils.parseEther("3000", "ether"), //_ethThresholdCheck - ethers.utils.parseEther("3000", "ether"), //_wethThresholdCheck + ethers.utils.parseEther("3000", "ether") //_wethThresholdCheck ); // check accounting values @@ -391,21 +387,19 @@ describe.only("ForkTest: Native SSV Staking Strategy", function () { } it("Only accounting governor is allowed to manually fix accounting", async () => { - const { nativeStakingSSVStrategy, governor, strategist } = fixture; + const { nativeStakingSSVStrategy, strategist } = fixture; await nativeStakingSSVStrategy.connect(strategist).pause(); // unit test fixture sets OUSD governor as accounting governor await expect( - nativeStakingSSVStrategy - .connect(strategist) - .manuallyFixAccounting( - 10, //_activeDepositedValidators - ethers.utils.parseEther("2", "ether"), //_ethToWeth - ethers.utils.parseEther("2", "ether"), //_wethToBeSentToVault - ethers.utils.parseEther("2", "ether"), //_beaconChainRewardWETH - ethers.utils.parseEther("0", "ether"), //_ethThresholdCheck - ethers.utils.parseEther("0", "ether"), //_wethThresholdCheck - ) + nativeStakingSSVStrategy.connect(strategist).manuallyFixAccounting( + 10, //_activeDepositedValidators + ethers.utils.parseEther("2", "ether"), //_ethToWeth + ethers.utils.parseEther("2", "ether"), //_wethToBeSentToVault + ethers.utils.parseEther("2", "ether"), //_beaconChainRewardWETH + ethers.utils.parseEther("0", "ether"), //_ethThresholdCheck + ethers.utils.parseEther("0", "ether") //_wethThresholdCheck + ) ).to.be.revertedWith("Caller is not the Accounting Governor"); }); @@ -414,85 +408,100 @@ describe.only("ForkTest: Native SSV Staking Strategy", function () { // unit test fixture sets OUSD governor as accounting governor await expect( - nativeStakingSSVStrategy - .connect(governor) - .manuallyFixAccounting( - 10, //_activeDepositedValidators - ethers.utils.parseEther("2", "ether"), //_ethToWeth - ethers.utils.parseEther("2", "ether"), //_wethToBeSentToVault - ethers.utils.parseEther("2", "ether"), //_beaconChainRewardWETH - ethers.utils.parseEther("1", "ether"), //_ethThresholdCheck - ethers.utils.parseEther("0", "ether"), //_wethThresholdCheck - ) + nativeStakingSSVStrategy.connect(governor).manuallyFixAccounting( + 10, //_activeDepositedValidators + ethers.utils.parseEther("2", "ether"), //_ethToWeth + ethers.utils.parseEther("2", "ether"), //_wethToBeSentToVault + ethers.utils.parseEther("2", "ether"), //_beaconChainRewardWETH + ethers.utils.parseEther("1", "ether"), //_ethThresholdCheck + ethers.utils.parseEther("0", "ether") //_wethThresholdCheck + ) ).to.be.revertedWith("NotPaused"); }); it("Should not execute manual recovery if eth threshold reached", async () => { - const { nativeStakingSSVStrategy, strategist, governor, josh, weth } = fixture; + const { nativeStakingSSVStrategy, strategist, governor, josh, weth } = + fixture; - await setBalance(nativeStakingSSVStrategy.address, ethers.utils.parseEther("6", "ether")); + await setBalance( + nativeStakingSSVStrategy.address, + ethers.utils.parseEther("6", "ether") + ); await weth .connect(josh) - .transfer(nativeStakingSSVStrategy.address, ethers.utils.parseEther("5", "ether")); + .transfer( + nativeStakingSSVStrategy.address, + ethers.utils.parseEther("5", "ether") + ); await nativeStakingSSVStrategy.connect(strategist).pause(); await expect( - nativeStakingSSVStrategy - .connect(governor) - .manuallyFixAccounting( - 10, //_activeDepositedValidators - ethers.utils.parseEther("2", "ether"), //_ethToWeth - ethers.utils.parseEther("2", "ether"), //_wethToBeSentToVault - ethers.utils.parseEther("2", "ether"), //_beaconChainRewardWETH - ethers.utils.parseEther("5", "ether"), //_ethThresholdCheck - ethers.utils.parseEther("5", "ether"), //_wethThresholdCheck - ) + nativeStakingSSVStrategy.connect(governor).manuallyFixAccounting( + 10, //_activeDepositedValidators + ethers.utils.parseEther("2", "ether"), //_ethToWeth + ethers.utils.parseEther("2", "ether"), //_wethToBeSentToVault + ethers.utils.parseEther("2", "ether"), //_beaconChainRewardWETH + ethers.utils.parseEther("5", "ether"), //_ethThresholdCheck + ethers.utils.parseEther("5", "ether") //_wethThresholdCheck + ) ).to.be.revertedWith("ManualFixAccountingThresholdReached"); }); it("Should not execute manual recovery if weth threshold reached", async () => { - const { nativeStakingSSVStrategy, strategist, governor, josh, weth } = fixture; + const { nativeStakingSSVStrategy, strategist, governor, josh, weth } = + fixture; - await setBalance(nativeStakingSSVStrategy.address, ethers.utils.parseEther("5", "ether")); + await setBalance( + nativeStakingSSVStrategy.address, + ethers.utils.parseEther("5", "ether") + ); await weth .connect(josh) - .transfer(nativeStakingSSVStrategy.address, ethers.utils.parseEther("6", "ether")); + .transfer( + nativeStakingSSVStrategy.address, + ethers.utils.parseEther("6", "ether") + ); await nativeStakingSSVStrategy.connect(strategist).pause(); await expect( - nativeStakingSSVStrategy - .connect(governor) - .manuallyFixAccounting( - 10, //_activeDepositedValidators - ethers.utils.parseEther("2", "ether"), //_ethToWeth - ethers.utils.parseEther("2", "ether"), //_wethToBeSentToVault - ethers.utils.parseEther("2", "ether"), //_beaconChainRewardWETH - ethers.utils.parseEther("5", "ether"), //_ethThresholdCheck - ethers.utils.parseEther("5", "ether"), //_wethThresholdCheck - ) + nativeStakingSSVStrategy.connect(governor).manuallyFixAccounting( + 10, //_activeDepositedValidators + ethers.utils.parseEther("2", "ether"), //_ethToWeth + ethers.utils.parseEther("2", "ether"), //_wethToBeSentToVault + ethers.utils.parseEther("2", "ether"), //_beaconChainRewardWETH + ethers.utils.parseEther("5", "ether"), //_ethThresholdCheck + ethers.utils.parseEther("5", "ether") //_wethThresholdCheck + ) ).to.be.revertedWith("ManualFixAccountingThresholdReached"); }); it("Should allow 5/8 governor to recover paused contract and correct the accounting state", async () => { - const { nativeStakingSSVStrategy, strategist, governor, josh, weth } = fixture; + const { nativeStakingSSVStrategy, strategist, governor, josh, weth } = + fixture; - await setBalance(nativeStakingSSVStrategy.address, ethers.utils.parseEther("5", "ether")); + await setBalance( + nativeStakingSSVStrategy.address, + ethers.utils.parseEther("5", "ether") + ); await weth .connect(josh) - .transfer(nativeStakingSSVStrategy.address, ethers.utils.parseEther("5", "ether")); + .transfer( + nativeStakingSSVStrategy.address, + ethers.utils.parseEther("5", "ether") + ); await nativeStakingSSVStrategy.connect(strategist).pause(); // unit test fixture sets OUSD governor as accounting governor const tx = await nativeStakingSSVStrategy - .connect(governor) - .manuallyFixAccounting( - 3, //_activeDepositedValidators - ethers.utils.parseEther("2.1", "ether"), //_ethToWeth - ethers.utils.parseEther("2.2", "ether"), //_wethToBeSentToVault - ethers.utils.parseEther("2.3", "ether"), //_beaconChainRewardWETH - ethers.utils.parseEther("5", "ether"), //_ethThresholdCheck - ethers.utils.parseEther("5", "ether"), //_wethThresholdCheck - ); + .connect(governor) + .manuallyFixAccounting( + 3, //_activeDepositedValidators + ethers.utils.parseEther("2.1", "ether"), //_ethToWeth + ethers.utils.parseEther("2.2", "ether"), //_wethToBeSentToVault + ethers.utils.parseEther("2.3", "ether"), //_beaconChainRewardWETH + ethers.utils.parseEther("5", "ether"), //_ethThresholdCheck + ethers.utils.parseEther("5", "ether") //_wethThresholdCheck + ); const events = (await tx.wait()).events || []; const AccountingManuallyFixedEvent = events.find( @@ -505,11 +514,18 @@ describe.only("ForkTest: Native SSV Staking Strategy", function () { ); expect(AccountingManuallyFixedEvent.args[0]).to.equal(0); // oldActiveDepositedValidators expect(AccountingManuallyFixedEvent.args[1]).to.equal(3); // activeDepositedValidators - expect(AccountingManuallyFixedEvent.args[2]).to.equal(ethers.utils.parseEther("0", "ether")); // oldBeaconChainRewardWETH - expect(AccountingManuallyFixedEvent.args[3]).to.equal(ethers.utils.parseEther("2.3", "ether")); // beaconChainRewardWETH - expect(AccountingManuallyFixedEvent.args[4]).to.equal(ethers.utils.parseEther("2.1", "ether")); // ethToWeth - expect(AccountingManuallyFixedEvent.args[5]).to.equal(ethers.utils.parseEther("2.2", "ether")); // wethToBeSentToVault - + expect(AccountingManuallyFixedEvent.args[2]).to.equal( + ethers.utils.parseEther("0", "ether") + ); // oldBeaconChainRewardWETH + expect(AccountingManuallyFixedEvent.args[3]).to.equal( + ethers.utils.parseEther("2.3", "ether") + ); // beaconChainRewardWETH + expect(AccountingManuallyFixedEvent.args[4]).to.equal( + ethers.utils.parseEther("2.1", "ether") + ); // ethToWeth + expect(AccountingManuallyFixedEvent.args[5]).to.equal( + ethers.utils.parseEther("2.2", "ether") + ); // wethToBeSentToVault }); }); From fe113a5fae400593094052d41cb914e5785ba63d Mon Sep 17 00:00:00 2001 From: Domen Grabec Date: Mon, 15 Apr 2024 15:30:58 +0200 Subject: [PATCH 011/273] undo file delete --- contracts/deploy/088_upgrade_woeth_on_arb.js | 28 +++++ contracts/deploy/089_1inch_buyback.js | 118 ++++++++++++++++++ contracts/deploy/089_simplified_oeth_vault.js | 47 +++++++ contracts/deploy/090_disable_compound.js | 32 +++++ 4 files changed, 225 insertions(+) create mode 100644 contracts/deploy/088_upgrade_woeth_on_arb.js create mode 100644 contracts/deploy/089_1inch_buyback.js create mode 100644 contracts/deploy/089_simplified_oeth_vault.js create mode 100644 contracts/deploy/090_disable_compound.js diff --git a/contracts/deploy/088_upgrade_woeth_on_arb.js b/contracts/deploy/088_upgrade_woeth_on_arb.js new file mode 100644 index 0000000000..8478268f04 --- /dev/null +++ b/contracts/deploy/088_upgrade_woeth_on_arb.js @@ -0,0 +1,28 @@ +const { isFork } = require("../test/helpers"); +const { deployOnArb } = require("../utils/delpoy-l2"); +const { deployWithConfirmation } = require("../utils/deploy"); +const { impersonateAndFund } = require("../utils/signers"); + +module.exports = deployOnArb( + { + deployName: "088_upgrade_woeth_on_arb", + }, + async ({ ethers }) => { + const cWOETHProxy = await ethers.getContract("BridgedWOETHProxy"); + + // Deploy Bridged WOETH Token implementation + await deployWithConfirmation("BridgedWOETH", []); + + const cWOETHImpl = await ethers.getContract("BridgedWOETH"); + console.log("BridgedWOETH address:", cWOETHImpl.address); + + if (isFork) { + console.log("Simulating upgrade on fork"); + + const governorAddr = await cWOETHProxy.governor(); + const sGovernor = await impersonateAndFund(governorAddr); + + await cWOETHProxy.connect(sGovernor).upgradeTo(cWOETHImpl.address); + } + } +); diff --git a/contracts/deploy/089_1inch_buyback.js b/contracts/deploy/089_1inch_buyback.js new file mode 100644 index 0000000000..571dd012f5 --- /dev/null +++ b/contracts/deploy/089_1inch_buyback.js @@ -0,0 +1,118 @@ +const addresses = require("../utils/addresses"); +const { + deploymentWithGovernanceProposal, + deployWithConfirmation, +} = require("../utils/deploy"); + +module.exports = deploymentWithGovernanceProposal( + { + deployName: "089_1inch_buyback", + // forceSkip: true, + // onlyOnFork: true, // this is only executed in forked environment + // reduceQueueTime: true, // just to solve the issue of later active proposals failing + proposalId: + "19953986745691218316817489613719564552439805381746724170485904355958039770871", + }, + async ({ ethers }) => { + const cOETHBuybackProxy = await ethers.getContract("OETHBuybackProxy"); + const cOUSDBuybackProxy = await ethers.getContract("BuybackProxy"); + + const cSwapper = await ethers.getContract("Swapper1InchV5"); + + // Deploy new OETHBuyback implementation + const dOETHBuybackImpl = await deployWithConfirmation( + "OETHBuyback", + [ + addresses.mainnet.OETHProxy, + addresses.mainnet.OGV, + addresses.mainnet.CVX, + addresses.mainnet.CVXLocker, + ], + undefined, + true + ); + + // Deploy new OUSDBuyback implementation + const dOUSDBuybackImpl = await deployWithConfirmation( + "OUSDBuyback", + [ + addresses.mainnet.OUSDProxy, + addresses.mainnet.OGV, + addresses.mainnet.CVX, + addresses.mainnet.CVXLocker, + ], + undefined, + true + ); + + const cOETHBuyback = await ethers.getContractAt( + "OETHBuyback", + cOETHBuybackProxy.address + ); + const cOUSDBuyback = await ethers.getContractAt( + "OUSDBuyback", + cOUSDBuybackProxy.address + ); + + await cSwapper.approveAssets([ + addresses.mainnet.OGV, + addresses.mainnet.CVX, + addresses.mainnet.OUSDProxy, + addresses.mainnet.OETHProxy, + ]); + + return { + name: "Upgrade Buyback contracts to use 1inch", + actions: [ + // 1. Upgrade OUSD Buyback to new implementation + { + contract: cOUSDBuybackProxy, + signature: "upgradeTo(address)", + args: [dOUSDBuybackImpl.address], + }, + // 2. Update swap router address on OUSD Buyback + { + contract: cOUSDBuyback, + signature: "setSwapRouter(address)", + args: [cSwapper.address], + }, + // 3. Set splits for CVX + { + contract: cOUSDBuyback, + signature: "setCVXShareBps(uint256)", + args: [5000], // 50% + }, + // 4. Compute buyback splits + { + contract: cOUSDBuyback, + signature: "updateBuybackSplits()", + args: [], + }, + // 5. Upgrade OETH Buyback to new implementation + { + contract: cOETHBuybackProxy, + signature: "upgradeTo(address)", + args: [dOETHBuybackImpl.address], + }, + // 6. Update swap router address on OETH Buyback + { + contract: cOETHBuyback, + signature: "setSwapRouter(address)", + args: [cSwapper.address], + }, + // 7. Set splits for CVX + { + contract: cOETHBuyback, + signature: "setCVXShareBps(uint256)", + args: [5000], // 50% + }, + // 8. Compute buyback splits + { + contract: cOETHBuyback, + signature: "updateBuybackSplits()", + args: [], + }, + ], + }; + } +); diff --git a/contracts/deploy/089_simplified_oeth_vault.js b/contracts/deploy/089_simplified_oeth_vault.js new file mode 100644 index 0000000000..59a28ba3bf --- /dev/null +++ b/contracts/deploy/089_simplified_oeth_vault.js @@ -0,0 +1,47 @@ +const addresses = require("../utils/addresses"); +const { + deploymentWithGovernanceProposal, + deployWithConfirmation, +} = require("../utils/deploy"); + +module.exports = deploymentWithGovernanceProposal( + { + deployName: "089_simplified_oeth_vault", + forceDeploy: false, + // forceSkip: true, + // onlyOnFork: true, // this is only executed in forked environment + // reduceQueueTime: true, // just to solve the issue of later active proposals failing + proposalId: "", + }, + async ({ ethers }) => { + const cOETHVaultProxy = await ethers.getContract("OETHVaultProxy"); + + // Deploy VaultCore implementation + await deployWithConfirmation("OETHVaultCore", [addresses.mainnet.WETH]); + const dVaultImpl = await ethers.getContract("OETHVaultCore"); + + const cOETHVault = await ethers.getContractAt( + "IVault", + addresses.mainnet.OETHVaultProxy + ); + + return { + name: "Simplified OETH mint and redeem\n\ + \n\ + Part of simplified OETH proposal. Trims down mint and redeem complexity on OETH Vault. Set redeem fees to zero. \ + ", + actions: [ + { + contract: cOETHVaultProxy, + signature: "upgradeTo(address)", + args: [dVaultImpl.address], + }, + { + contract: cOETHVault, + signature: "cacheWETHAssetIndex()", + args: [], + }, + ], + }; + } +); diff --git a/contracts/deploy/090_disable_compound.js b/contracts/deploy/090_disable_compound.js new file mode 100644 index 0000000000..2f2fbc880d --- /dev/null +++ b/contracts/deploy/090_disable_compound.js @@ -0,0 +1,32 @@ +const addresses = require("../utils/addresses"); +const { deploymentWithGovernanceProposal } = require("../utils/deploy"); + +module.exports = deploymentWithGovernanceProposal( + { + deployName: "090_disable_compound", + forceDeploy: false, + // forceSkip: true, + // onlyOnFork: true, // this is only executed in forked environment + // reduceQueueTime: true, // just to solve the issue of later active proposals failing + proposalId: + "540302155888465131843465904203767906417865895567367577074989857543481682425", + }, + async ({ ethers }) => { + // Current contracts + const cVaultProxy = await ethers.getContract("VaultProxy"); + const cVault = await ethers.getContractAt("IVault", cVaultProxy.address); + + // Governance Actions + // ---------------- + return { + name: "Remove Morpho Compound Strategy from OUSD", + actions: [ + { + contract: cVault, + signature: "removeStrategy(address)", + args: [addresses.mainnet.MorphoStrategyProxy], + }, + ], + }; + } +); From 71ad71ffe82ec9b7d616f890e9e925f1fb33af32 Mon Sep 17 00:00:00 2001 From: Domen Grabec Date: Tue, 16 Apr 2024 21:31:50 +0200 Subject: [PATCH 012/273] implement the collect rewards function and add tests for it --- .../NativeStaking/FeeAccumulator.sol | 6 +- .../NativeStakingSSVStrategy.sol | 19 +++- contracts/test/strategies/nativeSSVStaking.js | 104 +++++++++++++++++- 3 files changed, 120 insertions(+), 9 deletions(-) diff --git a/contracts/contracts/strategies/NativeStaking/FeeAccumulator.sol b/contracts/contracts/strategies/NativeStaking/FeeAccumulator.sol index b951d1b4b8..6a9abd7046 100644 --- a/contracts/contracts/strategies/NativeStaking/FeeAccumulator.sol +++ b/contracts/contracts/strategies/NativeStaking/FeeAccumulator.sol @@ -44,7 +44,9 @@ contract FeeAccumulator is Governable { function collect() external returns (uint256 wethReturned) { _assertIsCollector(); wethReturned = address(this).balance; - IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: wethReturned }(); - IWETH9(WETH_TOKEN_ADDRESS).transfer(COLLECTOR, wethReturned); + if (wethReturned > 0) { + IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: wethReturned }(); + IWETH9(WETH_TOKEN_ADDRESS).transfer(COLLECTOR, wethReturned); + } } } diff --git a/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol b/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol index 918fbcef7f..9e0c254811 100644 --- a/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol +++ b/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol @@ -30,6 +30,10 @@ contract NativeStakingSSVStrategy is /// @notice SSV Network contract used to interface with address public immutable SSV_NETWORK_ADDRESS; /// @notice Fee collector address + /// @dev this address will receive Execution layer rewards - These are rewards earned for + /// executing transactions on the Ethereum network as part of block proposals. They include + /// priority fees (fees paid by users for their transactions to be included) and MEV rewards + /// (rewards for arranging transactions in a way that benefits the validator). address public immutable FEE_ACCUMULATOR_ADDRESS; // For future use @@ -101,11 +105,15 @@ contract NativeStakingSSVStrategy is onlyHarvester nonReentrant { - // collect ETH from fee collector and wrap it into WETH - uint256 ethCollected = FeeAccumulator(FEE_ACCUMULATOR_ADDRESS) + // collect WETH from fee collector and wrap it into WETH + uint256 wethCollected = FeeAccumulator(FEE_ACCUMULATOR_ADDRESS) .collect(); - IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: ethCollected }(); + /* add up the WETH collected from the fee accumulator to beaconChainRewardWETH + * so it can be sent to the harvester in one swoop in the "_collectRewardTokens" + * step. + */ + beaconChainRewardWETH += wethCollected; _collectRewardTokens(); } @@ -119,7 +127,7 @@ contract NativeStakingSSVStrategy is uint256 balance = rewardToken.balanceOf(address(this)); if (balance > 0) { if (address(rewardToken) == WETH_TOKEN_ADDRESS) { - if (beaconChainRewardWETH < balance) { + if (beaconChainRewardWETH > balance) { revert InsuffiscientWethBalance( beaconChainRewardWETH, balance @@ -234,6 +242,9 @@ contract NativeStakingSSVStrategy is override returns (uint256 balance) { + //activeDepositedValidators * 32 ETH + // + all the weth on the contract + balance = 0; } diff --git a/contracts/test/strategies/nativeSSVStaking.js b/contracts/test/strategies/nativeSSVStaking.js index 61c023d65f..d846ea5dfb 100644 --- a/contracts/test/strategies/nativeSSVStaking.js +++ b/contracts/test/strategies/nativeSSVStaking.js @@ -8,6 +8,7 @@ const { shouldBehaveLikeGovernable } = require("../behaviour/governable"); const { shouldBehaveLikeHarvestable } = require("../behaviour/harvestable"); const { shouldBehaveLikeStrategy } = require("../behaviour/strategy"); const { MAX_UINT256 } = require("../../utils/constants"); +const { impersonateAndFund } = require("../../utils/signers"); const { createFixtureLoader, @@ -16,7 +17,7 @@ const { const loadFixture = createFixtureLoader(nativeStakingSSVStrategyFixture); -describe.only("ForkTest: Native SSV Staking Strategy", function () { +describe("ForkTest: Native SSV Staking Strategy", function () { this.timeout(0); // Retry up to 3 times on CI @@ -529,7 +530,104 @@ describe.only("ForkTest: Native SSV Staking Strategy", function () { }); }); - describe("Withdraw", function () {}); + describe("General functionality", function () { + const rewardTestCases = [ + { + feeAccumulatorEth: utils.parseEther("2.2"), + beaconChainRewardEth: utils.parseEther("16.3"), + wethFromDeposits: utils.parseEther("100"), + expectedEthSentToHarvester: utils.parseEther("18.5"), + }, + { + feeAccumulatorEth: utils.parseEther("10.2"), + beaconChainRewardEth: utils.parseEther("21.6"), + wethFromDeposits: utils.parseEther("0"), + expectedEthSentToHarvester: utils.parseEther("31.8"), + }, + { + feeAccumulatorEth: utils.parseEther("0"), + beaconChainRewardEth: utils.parseEther("0"), + wethFromDeposits: utils.parseEther("0"), + expectedEthSentToHarvester: utils.parseEther("0"), + }, + ]; + + for (const testCase of rewardTestCases) { + it("Collecting rewards should correctly account for WETH", async () => { + const { + nativeStakingSSVStrategy, + governor, + strategist, + oethHarvester, + weth, + josh, + } = fixture; + const { + feeAccumulatorEth, + beaconChainRewardEth, + wethFromDeposits, + expectedEthSentToHarvester, + } = testCase; + const feeAccumulatorAddress = + await nativeStakingSSVStrategy.FEE_ACCUMULATOR_ADDRESS(); + const sHarvester = await impersonateAndFund(oethHarvester.address); - describe("Balance/Assets", function () {}); + // setup state + if (beaconChainRewardEth.gt(BigNumber.from("0"))) { + // set the reward eth on the strategy + await setBalance( + nativeStakingSSVStrategy.address, + beaconChainRewardEth + ); + } + if (feeAccumulatorEth.gt(BigNumber.from("0"))) { + // set execution layer rewards on the fee accumulator + await setBalance(feeAccumulatorAddress, feeAccumulatorEth); + } + if (wethFromDeposits.gt(BigNumber.from("0"))) { + // send eth to the strategy as if Vault would send it via a Deposit function + await weth + .connect(josh) + .transfer(nativeStakingSSVStrategy.address, wethFromDeposits); + } + + // run the accounting + await nativeStakingSSVStrategy.connect(governor).doAccounting(); + + const harvesterWethBalance = await weth.balanceOf( + oethHarvester.address + ); + const tx = await nativeStakingSSVStrategy + .connect(sHarvester) + .collectRewardTokens(); + const events = (await tx.wait()).events || []; + + const harvesterBalanceDiff = ( + await weth.balanceOf(oethHarvester.address) + ).sub(harvesterWethBalance); + expect(harvesterBalanceDiff).to.equal(expectedEthSentToHarvester); + + const rewardTokenCollectedEvent = events.find( + (e) => e.event === "RewardTokenCollected" + ); + + if (expectedEthSentToHarvester.gt(BigNumber.from("0"))) { + expect(rewardTokenCollectedEvent).to.not.be.undefined; + expect(rewardTokenCollectedEvent.event).to.equal( + "RewardTokenCollected" + ); + expect(rewardTokenCollectedEvent.args[1]).to.equal(weth.address); + expect(rewardTokenCollectedEvent.args[2]).to.equal( + expectedEthSentToHarvester + ); + } else { + expect(rewardTokenCollectedEvent).to.be.undefined; + } + }); + } + + it("Should be able to collect the SSV reward token", async () => {}); + + it("Check balance should report correct values", async () => {}); + }); }); From 2c448bb821235ef2838d01c9c6373378f848aa12 Mon Sep 17 00:00:00 2001 From: Domen Grabec Date: Tue, 16 Apr 2024 22:04:17 +0200 Subject: [PATCH 013/273] implement and test checkBalance --- .../NativeStakingSSVStrategy.sol | 20 +++--- contracts/test/strategies/nativeSSVStaking.js | 72 ++++++++++++++++++- 2 files changed, 82 insertions(+), 10 deletions(-) diff --git a/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol b/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol index 9e0c254811..02df278590 100644 --- a/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol +++ b/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol @@ -40,6 +40,7 @@ contract NativeStakingSSVStrategy is uint256[50] private __gap; error EmptyRecipient(); + error NotWeth(); error InsuffiscientWethBalance( uint256 requiredBalance, uint256 availableBalance @@ -230,22 +231,23 @@ contract NativeStakingSSVStrategy is function _abstractSetPToken(address _asset, address) internal override {} - /// @notice Get the total asset value held in the underlying platform - /// This includes any interest that was generated since depositing. - /// The exchange rate between the cToken and asset gradually increases, - /// causing the cToken to be worth more corresponding asset. - /// @param _asset Address of the asset - /// @return balance Total value of the asset in the platform + /// @notice Returns the total value of (W)ETH that is staked to the validators + /// and also present on the native staking and fee accumulator contracts + /// @param _asset Address of weth asset + /// @return balance Total value of (W)ETH function checkBalance(address _asset) external view override returns (uint256 balance) { - //activeDepositedValidators * 32 ETH - // + all the weth on the contract + if (_asset != WETH_TOKEN_ADDRESS) { + revert NotWeth(); + } - balance = 0; + balance = activeDepositedValidators * 32 ether; + balance += beaconChainRewardWETH; + balance += FEE_ACCUMULATOR_ADDRESS.balance; } function pause() external onlyStrategist { diff --git a/contracts/test/strategies/nativeSSVStaking.js b/contracts/test/strategies/nativeSSVStaking.js index d846ea5dfb..22eac6e183 100644 --- a/contracts/test/strategies/nativeSSVStaking.js +++ b/contracts/test/strategies/nativeSSVStaking.js @@ -536,24 +536,34 @@ describe("ForkTest: Native SSV Staking Strategy", function () { feeAccumulatorEth: utils.parseEther("2.2"), beaconChainRewardEth: utils.parseEther("16.3"), wethFromDeposits: utils.parseEther("100"), + nrOfActiveDepositedValidators: 7, expectedEthSentToHarvester: utils.parseEther("18.5"), }, { feeAccumulatorEth: utils.parseEther("10.2"), beaconChainRewardEth: utils.parseEther("21.6"), wethFromDeposits: utils.parseEther("0"), + nrOfActiveDepositedValidators: 5, + expectedEthSentToHarvester: utils.parseEther("31.8"), + }, + { + feeAccumulatorEth: utils.parseEther("10.2"), + beaconChainRewardEth: utils.parseEther("21.6"), + wethFromDeposits: utils.parseEther("1"), + nrOfActiveDepositedValidators: 0, expectedEthSentToHarvester: utils.parseEther("31.8"), }, { feeAccumulatorEth: utils.parseEther("0"), beaconChainRewardEth: utils.parseEther("0"), wethFromDeposits: utils.parseEther("0"), + nrOfActiveDepositedValidators: 0, expectedEthSentToHarvester: utils.parseEther("0"), }, ]; for (const testCase of rewardTestCases) { - it("Collecting rewards should correctly account for WETH", async () => { + it("Collecting rewards and should correctly account for WETH", async () => { const { nativeStakingSSVStrategy, governor, @@ -626,6 +636,66 @@ describe("ForkTest: Native SSV Staking Strategy", function () { }); } + for (const testCase of rewardTestCases) { + it("Checking balance should return the correct values", async () => { + const { + nativeStakingSSVStrategy, + governor, + strategist, + oethHarvester, + weth, + josh, + } = fixture; + const { + feeAccumulatorEth, + beaconChainRewardEth, + wethFromDeposits, + expectedEthSentToHarvester, + nrOfActiveDepositedValidators + } = testCase; + const feeAccumulatorAddress = + await nativeStakingSSVStrategy.FEE_ACCUMULATOR_ADDRESS(); + const sHarvester = await impersonateAndFund(oethHarvester.address); + + // setup state + if (beaconChainRewardEth.gt(BigNumber.from("0"))) { + // set the reward eth on the strategy + await setBalance( + nativeStakingSSVStrategy.address, + beaconChainRewardEth + ); + } + if (feeAccumulatorEth.gt(BigNumber.from("0"))) { + // set execution layer rewards on the fee accumulator + await setBalance(feeAccumulatorAddress, feeAccumulatorEth); + } + if (wethFromDeposits.gt(BigNumber.from("0"))) { + // send eth to the strategy as if Vault would send it via a Deposit function + await weth + .connect(josh) + .transfer(nativeStakingSSVStrategy.address, wethFromDeposits); + } + + // set the correct amount of staked validators + await nativeStakingSSVStrategy.connect(strategist).pause(); + await nativeStakingSSVStrategy.connect(governor).manuallyFixAccounting( + nrOfActiveDepositedValidators, // activeDepositedValidators + ethers.utils.parseEther("0", "ether"), //_ethToWeth + ethers.utils.parseEther("0", "ether"), //_wethToBeSentToVault + ethers.utils.parseEther("0", "ether"), //_beaconChainRewardWETH + ethers.utils.parseEther("3000", "ether"), //_ethThresholdCheck + ethers.utils.parseEther("3000", "ether") //_wethThresholdCheck + ); + + // run the accounting + await nativeStakingSSVStrategy.connect(governor).doAccounting(); + + expect(await nativeStakingSSVStrategy.checkBalance(weth.address)).to.equal( + expectedEthSentToHarvester.add(BigNumber.from(`${nrOfActiveDepositedValidators}`).mul(utils.parseEther("32"))) + ); + }); + } + it("Should be able to collect the SSV reward token", async () => {}); it("Check balance should report correct values", async () => {}); From 5d5e9cb7e388d363ead2b87be7414e496c716b04 Mon Sep 17 00:00:00 2001 From: Domen Grabec Date: Thu, 18 Apr 2024 17:15:48 +0200 Subject: [PATCH 014/273] add functions to register and exit/remove the ssv validator --- .../contracts/interfaces/IDepositContract.sol | 34 +++ .../mocks/BeaconChainDepositContractMock.sol | 37 ++++ .../NativeStakingSSVStrategy.sol | 22 +- .../NativeStaking/ValidatorAccountant.sol | 15 +- .../NativeStaking/ValidatorRegistrator.sol | 207 +++++++++++++----- contracts/deploy/000_mock.js | 4 + contracts/deploy/001_core.js | 1 + contracts/deploy/091_native_ssv_staking.js | 11 +- contracts/test/_hot-deploy.js | 13 +- contracts/test/helpers.js | 3 + contracts/test/strategies/nativeSSVStaking.js | 4 +- contracts/utils/addresses.js | 1 + 12 files changed, 272 insertions(+), 80 deletions(-) create mode 100644 contracts/contracts/interfaces/IDepositContract.sol create mode 100644 contracts/contracts/mocks/BeaconChainDepositContractMock.sol diff --git a/contracts/contracts/interfaces/IDepositContract.sol b/contracts/contracts/interfaces/IDepositContract.sol new file mode 100644 index 0000000000..9d62b5d776 --- /dev/null +++ b/contracts/contracts/interfaces/IDepositContract.sol @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +interface IDepositContract { + /// @notice A processed deposit event. + event DepositEvent( + bytes pubkey, + bytes withdrawal_credentials, + bytes amount, + bytes signature, + bytes index + ); + + /// @notice Submit a Phase 0 DepositData object. + /// @param pubkey A BLS12-381 public key. + /// @param withdrawal_credentials Commitment to a public key for withdrawals. + /// @param signature A BLS12-381 signature. + /// @param deposit_data_root The SHA-256 hash of the SSZ-encoded DepositData object. + /// Used as a protection against malformed input. + function deposit( + bytes calldata pubkey, + bytes calldata withdrawal_credentials, + bytes calldata signature, + bytes32 deposit_data_root + ) external payable; + + /// @notice Query the current deposit root hash. + /// @return The deposit root hash. + function get_deposit_root() external view returns (bytes32); + + /// @notice Query the current deposit count. + /// @return The deposit count encoded as a little endian 64-bit number. + function get_deposit_count() external view returns (bytes memory); +} \ No newline at end of file diff --git a/contracts/contracts/mocks/BeaconChainDepositContractMock.sol b/contracts/contracts/mocks/BeaconChainDepositContractMock.sol new file mode 100644 index 0000000000..d2e148cf46 --- /dev/null +++ b/contracts/contracts/mocks/BeaconChainDepositContractMock.sol @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +contract BeaconChainDepositContractMock { + /// @notice A processed deposit event. + event DepositEvent( + bytes pubkey, + bytes withdrawal_credentials, + bytes amount, + bytes signature, + bytes index + ); + + /// @notice Submit a Phase 0 DepositData object. + /// @param pubkey A BLS12-381 public key. + /// @param withdrawal_credentials Commitment to a public key for withdrawals. + /// @param signature A BLS12-381 signature. + /// @param deposit_data_root The SHA-256 hash of the SSZ-encoded DepositData object. + /// Used as a protection against malformed input. + function deposit( + bytes calldata pubkey, + bytes calldata withdrawal_credentials, + bytes calldata signature, + bytes32 deposit_data_root + ) external payable { + // Extended ABI length checks since dynamic types are used. + require(pubkey.length == 48, "DepositContract: invalid pubkey length"); + require(withdrawal_credentials.length == 32, "DepositContract: invalid withdrawal_credentials length"); + require(signature.length == 96, "DepositContract: invalid signature length"); + + // Check deposit amount + require(msg.value >= 1 ether, "DepositContract: deposit value too low"); + require(msg.value % 1 gwei == 0, "DepositContract: deposit value not multiple of gwei"); + uint deposit_amount = msg.value / 1 gwei; + require(deposit_amount <= type(uint64).max, "DepositContract: deposit value too high"); + } +} \ No newline at end of file diff --git a/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol b/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol index 02df278590..7d06295e35 100644 --- a/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol +++ b/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol @@ -6,9 +6,9 @@ import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.s import { InitializableAbstractStrategy } from "../../utils/InitializableAbstractStrategy.sol"; import { IWETH9 } from "../../interfaces/IWETH9.sol"; -import { ISSVNetwork, Cluster } from "../../interfaces/ISSVNetwork.sol"; import { FeeAccumulator } from "./FeeAccumulator.sol"; import { ValidatorAccountant } from "./ValidatorAccountant.sol"; +import { Cluster } from "../../interfaces/ISSVNetwork.sol"; struct ValidatorStakeData { bytes pubkey; @@ -27,8 +27,6 @@ contract NativeStakingSSVStrategy is /// @notice SSV ERC20 token that serves as a payment for operating SSV validators address public immutable SSV_TOKEN_ADDRESS; - /// @notice SSV Network contract used to interface with - address public immutable SSV_NETWORK_ADDRESS; /// @notice Fee collector address /// @dev this address will receive Execution layer rewards - These are rewards earned for /// executing transactions on the Ethereum network as part of block proposals. They include @@ -51,18 +49,20 @@ contract NativeStakingSSVStrategy is /// @param _wethAddress Address of the Erc20 WETH Token contract /// @param _ssvToken Address of the Erc20 SSV Token contract /// @param _ssvNetwork Address of the SSV Network contract + /// @param _feeAccumulator Address of the fee accumulator receiving execution layer validator rewards + /// @param _beaconChainDepositContract Address of the beacon chain deposit contract constructor( BaseStrategyConfig memory _baseConfig, address _wethAddress, address _ssvToken, address _ssvNetwork, - address _feeAccumulator + address _feeAccumulator, + address _beaconChainDepositContract ) InitializableAbstractStrategy(_baseConfig) - ValidatorAccountant(_wethAddress, _baseConfig.vaultAddress) + ValidatorAccountant(_wethAddress, _baseConfig.vaultAddress, _beaconChainDepositContract, _ssvNetwork) { SSV_TOKEN_ADDRESS = _ssvToken; - SSV_NETWORK_ADDRESS = _ssvNetwork; FEE_ACCUMULATOR_ADDRESS = _feeAccumulator; } @@ -270,13 +270,17 @@ contract NativeStakingSSVStrategy is ); } - /// @dev Deposits more SSV Tokens to the SSV Network contract which is used to pay the SSV Operators - /// A SSV cluster is defined by the SSVOwnerAddress and the set of operatorIds + /// @notice Deposits more SSV Tokens to the SSV Network contract which is used to pay the SSV Operators. + /// @dev A SSV cluster is defined by the SSVOwnerAddress and the set of operatorIds + /// uses "onlyStrategist" modifier so continuous fron-running can't DOS our maintenance service + /// that tries to top us SSV tokens. function depositSSV( uint64[] memory operatorIds, uint256 amount, Cluster memory cluster - ) external { + ) + onlyStrategist + external { // address SSV_NETWORK_ADDRESS = lrtConfig.getContract(LRTConstants.SSV_NETWORK); // ISSVNetwork(SSV_NETWORK_ADDRESS).deposit(address(this), operatorIds, amount, cluster); } diff --git a/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol b/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol index 794003b216..e85b808129 100644 --- a/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol +++ b/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol @@ -9,9 +9,7 @@ import { IWETH9 } from "../../interfaces/IWETH9.sol"; /// @notice This contract contains the logic to attribute the Beacon Chain swept ETH either to full /// or partial withdrawals /// @author Origin Protocol Inc -abstract contract ValidatorAccountant is ValidatorRegistrator, Pausable { - /// @notice The Wrapped ETH (WETH) contract address - address public immutable WETH_TOKEN_ADDRESS; +abstract contract ValidatorAccountant is ValidatorRegistrator { address public immutable VAULT_ADDRESS; /// @dev The WETH present on this contract will come from 2 sources: @@ -92,8 +90,11 @@ abstract contract ValidatorAccountant is ValidatorRegistrator, Pausable { } /// @param _wethAddress Address of the Erc20 WETH Token contract - constructor(address _wethAddress, address _vaultAddress) { - WETH_TOKEN_ADDRESS = _wethAddress; + /// @param _vaultAddress Address of the Vault + /// @param _beaconChainDepositContract Address of the beacon chain deposit contract + /// @param _ssvNetwork Address of the SSV Network contract + constructor(address _wethAddress, address _vaultAddress, address _beaconChainDepositContract, address _ssvNetwork) + ValidatorRegistrator(_wethAddress, _beaconChainDepositContract, _ssvNetwork) { VAULT_ADDRESS = _vaultAddress; } @@ -142,9 +143,10 @@ abstract contract ValidatorAccountant is ValidatorRegistrator, Pausable { /// accounting is valid and fuse isn't "blown". Returns false when fuse is blown /// @dev This function could in theory be permission-less but lets allow only the Registrator (Defender Action) to call it /// for now - function doAccounting() external onlyRegistrator returns (bool) { + function doAccounting() external onlyRegistrator returns (bool accountingValid) { uint256 ethBalance = address(this).balance; uint256 MAX_STAKE = 32 ether; + accountingValid = true; // send the WETH that is from fully withdrawn validators to the Vault if (ethBalance >= MAX_STAKE) { @@ -190,6 +192,7 @@ abstract contract ValidatorAccountant is ValidatorRegistrator, Pausable { else { // will emit a paused event _pause(); + accountingValid = false; } } diff --git a/contracts/contracts/strategies/NativeStaking/ValidatorRegistrator.sol b/contracts/contracts/strategies/NativeStaking/ValidatorRegistrator.sol index c65d2c2526..2ee2a87fa1 100644 --- a/contracts/contracts/strategies/NativeStaking/ValidatorRegistrator.sol +++ b/contracts/contracts/strategies/NativeStaking/ValidatorRegistrator.sol @@ -1,24 +1,58 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; +import { Pausable } from "@openzeppelin/contracts/security/Pausable.sol"; import { Governable } from "../../governance/Governable.sol"; +import { IDepositContract } from "../../interfaces/IDepositContract.sol"; +import { IWETH9 } from "../../interfaces/IWETH9.sol"; +import { ISSVNetwork, Cluster } from "../../interfaces/ISSVNetwork.sol"; + +struct ValidatorStakeData { + bytes pubkey; + bytes signature; + bytes32 depositDataRoot; +} /** * @title Registrator of the validators * @notice This contract implements all the required functionality to register validators * @author Origin Protocol Inc */ -abstract contract ValidatorRegistrator is Governable { +abstract contract ValidatorRegistrator is Governable, Pausable { + /// @notice The Wrapped ETH (WETH) contract address + address public immutable WETH_TOKEN_ADDRESS; + /// @notice Address of the beacon chain deposit contract + address public immutable BEACON_CHAIN_DEPOSIT_CONTRACT; + /// @notice SSV Network contract used to interface with + address public immutable SSV_NETWORK_ADDRESS; + /// @notice Address of the registrator - allowed to register, exit and remove validators address public validatorRegistrator; /// @notice The number of validators that have 32 (!) ETH actively deposited. When a new deposit /// to a validator happens this number increases, when a validator exit is detected this number /// decreases. uint256 activeDepositedValidators; + /// @notice State of the validators keccak256(pubKey) => state + mapping(bytes32 => VALIDATOR_STATE) public validatorsStates; + // For future use uint256[50] private __gap; + enum VALIDATOR_STATE { + REGISTERED, // validator is registered on the SSV network + STAKED, // validator has funds staked + EXITING, // exit message has been posted and validator is in the process of exiting + EXIT_COMPLETE // validator has funds withdrawn to the EigenPod and is removed from the SSV + } + event RegistratorAddressChanged(address oldAddress, address newAddress); + event ETHStaked(bytes pubkey, uint256 amount, bytes withdrawal_credentials); + event SSVValidatorRegistered(bytes pubkey, uint64[] operatorIds); + event SSVValidatorExitInitiated(bytes pubkey, uint64[] operatorIds); + event SSVValidatorExitCompleted(bytes pubkey, uint64[] operatorIds); + + error InsufficientWETH(uint256 wethBalance, uint256 requiredWethBalance); + error ValidatorInUnexpectedState(bytes pubkey, VALIDATOR_STATE state); /// @dev Throws if called by any account other than the Registrator modifier onlyRegistrator() { @@ -29,6 +63,15 @@ abstract contract ValidatorRegistrator is Governable { _; } + /// @param _wethAddress Address of the Erc20 WETH Token contract + /// @param _beaconChainDepositContract Address of the beacon chain deposit contract + /// @param _ssvNetwork Address of the SSV Network contract + constructor(address _wethAddress, address _beaconChainDepositContract, address _ssvNetwork) { + WETH_TOKEN_ADDRESS = _wethAddress; + BEACON_CHAIN_DEPOSIT_CONTRACT = _beaconChainDepositContract; + SSV_NETWORK_ADDRESS = _ssvNetwork; + } + /// @notice Set the address of the registrator function setRegistratorAddress(address _address) external onlyGovernor { emit RegistratorAddressChanged(validatorRegistrator, _address); @@ -43,53 +86,117 @@ abstract contract ValidatorRegistrator is Governable { virtual returns (uint256 _amount); - // /// @notice Stakes WETH to the NDC to the Node validators - // /// @param validators A list of validator data needed to stake. - // /// The ValidatorStakeData struct contains the pubkey, signature and depositDataRoot. - // /// @dev Only accounts with the Operator role can call this function. - // function stakeEth(ValidatorStakeData[] calldata validators) external { - // // Yield from the validators will come as native ETH. - // uint256 ethBalance = address(this).balance; - // uint256 requiredETH = validators.length * 32 ether; - // if (ethBalance < requiredETH) { - // // If not enough native ETH, convert WETH to native ETH - // uint256 wethBalance = getWETHBalanceEligibleForStaking(); - // if (wethBalance + ethBalance < requiredETH) { - // revert InsufficientWETH(wethBalance + ethBalance); - // } - // // Convert WETH asset to native ETH - // IWETH(WETH_TOKEN_ADDRESS).withdraw(requiredETH - ethBalance); - // } - - // // For each validator - // for (uint256 i = 0; i < validators.length;) { - // bytes32 pubkeyHash = keccak256(validators[i].pubkey); - - // if (validatorsStaked[pubkeyHash]) { - // revert ValidatorAlreadyStaked(validators[i].pubkey); - // } - - // _stakeEth(validators[i].pubkey, validators[i].signature, validators[i].depositDataRoot); - // validatorsStaked[pubkeyHash] = true; - - // unchecked { - // ++i; - // } - // } - // } - - // /// @dev Stake WETH and ETH in NDC in EigenLayer. It calls the `stake` function on the EigenPodManager - // /// which calls `stake` on the EigenPod contract which calls `stake` on the Beacon DepositContract. - // /// @dev The public functions that call this internal function are responsible for access control. - // function _stakeEth(bytes calldata pubkey, bytes calldata signature, bytes32 depositDataRoot) internal { - // // Call the stake function in the EigenPodManager - // IEigenPodManager eigenPodManager = IEigenPodManager(lrtConfig.getContract(LRTConstants.EIGEN_POD_MANAGER)); - // eigenPodManager.stake{ value: 32 ether }(pubkey, signature, depositDataRoot); - - // // Increment the staked but not verified ETH - // stakedButNotVerifiedEth += 32 ether; - // activeDepositedValidators += 1; - - // emit ETHStaked(pubkey, 32 ether); - // } + /// @notice Stakes WETH to the node validators + /// @param validators A list of validator data needed to stake. + /// The ValidatorStakeData struct contains the pubkey, signature and depositDataRoot. + /// @dev Only accounts with the Operator role can call this function. + function stakeEth(ValidatorStakeData[] calldata validators) + onlyRegistrator + whenNotPaused + external { + uint256 requiredWETH = validators.length * 32 ether; + uint256 wethBalance = getWETHBalanceEligibleForStaking(); + if (wethBalance < requiredWETH) { + revert InsufficientWETH(wethBalance, requiredWETH); + } + + // Convert WETH asset to native ETH + IWETH9(WETH_TOKEN_ADDRESS).withdraw(wethBalance); + + // For each validator + for (uint256 i = 0; i < validators.length;) { + bytes32 pubkeyHash = keccak256(validators[i].pubkey); + VALIDATOR_STATE currentState = validatorsStates[pubkeyHash]; + + if (currentState != VALIDATOR_STATE.REGISTERED) { + revert ValidatorInUnexpectedState(validators[i].pubkey, currentState); + } + + _stakeEth(validators[i].pubkey, validators[i].signature, validators[i].depositDataRoot); + validatorsStates[pubkeyHash] = VALIDATOR_STATE.STAKED; + + unchecked { + ++i; + } + } + } + + /// @dev Deposit WETH to the beacon chain deposit contract + /// @dev The public functions that call this internal function are responsible for access control. + function _stakeEth(bytes calldata pubkey, bytes calldata signature, bytes32 depositDataRoot) internal { + /* 0x01 to indicate that withdrawal credentials will contain an EOA address that the sweeping function + * can sweep funds to. + * bytes11(0) to fill up the required zeros + * remaining bytes20 are for the address + */ + bytes memory withdrawal_credentials = abi.encodePacked(bytes1(0x01), bytes11(0), address(this)); + IDepositContract(BEACON_CHAIN_DEPOSIT_CONTRACT).deposit( + pubkey, withdrawal_credentials, signature, depositDataRoot + ); + + activeDepositedValidators += 1; + emit ETHStaked(pubkey, 32 ether, withdrawal_credentials); + + } + + /// @dev Registers a new validator in the SSV Cluster + function registerSsvValidator( + bytes calldata publicKey, + uint64[] calldata operatorIds, + bytes calldata sharesData, + uint256 amount, + Cluster calldata cluster + ) + external + onlyRegistrator + whenNotPaused + { + ISSVNetwork(SSV_NETWORK_ADDRESS).registerValidator(publicKey, operatorIds, sharesData, amount, cluster); + validatorsStates[keccak256(publicKey)] = VALIDATOR_STATE.REGISTERED; + emit SSVValidatorRegistered(publicKey, operatorIds); + } + + /// @dev Exit a validator from the Beacon chain. + /// The staked ETH will be sent to the EigenPod. + function exitSsvValidator( + bytes calldata publicKey, + uint64[] calldata operatorIds + ) + external + onlyRegistrator + whenNotPaused + { + VALIDATOR_STATE currentState = validatorsStates[keccak256(publicKey)]; + if (currentState != VALIDATOR_STATE.STAKED) { + revert ValidatorInUnexpectedState(publicKey, currentState); + } + + ISSVNetwork(SSV_NETWORK_ADDRESS).exitValidator(publicKey, operatorIds); + emit SSVValidatorExitInitiated(publicKey, operatorIds); + + validatorsStates[keccak256(publicKey)] = VALIDATOR_STATE.EXITING; + } + + /// @dev Remove a validator from the SSV Cluster. + /// Make sure `exitSsvValidator` is called before and the validate has exited the Beacon chain. + /// If removed before the validator has exited the beacon chain will result in the validator being slashed. + function removeSsvValidator( + bytes calldata publicKey, + uint64[] calldata operatorIds, + Cluster calldata cluster + ) + external + onlyRegistrator + whenNotPaused + { + VALIDATOR_STATE currentState = validatorsStates[keccak256(publicKey)]; + if (currentState != VALIDATOR_STATE.EXITING) { + revert ValidatorInUnexpectedState(publicKey, currentState); + } + + ISSVNetwork(SSV_NETWORK_ADDRESS).removeValidator(publicKey, operatorIds, cluster); + emit SSVValidatorExitCompleted(publicKey, operatorIds); + + validatorsStates[keccak256(publicKey)] = VALIDATOR_STATE.EXIT_COMPLETE; + } } diff --git a/contracts/deploy/000_mock.js b/contracts/deploy/000_mock.js index eda17e4a71..ab09ffcc46 100644 --- a/contracts/deploy/000_mock.js +++ b/contracts/deploy/000_mock.js @@ -419,6 +419,10 @@ const deployMocks = async ({ getNamedAccounts, deployments }) => { from: deployerAddr, }); + await deploy("BeaconChainDepositContractMock", { + from: deployerAddr, + }); + console.log("000_mock deploy done."); return true; diff --git a/contracts/deploy/001_core.js b/contracts/deploy/001_core.js index 6a634cc642..ed14d833ec 100644 --- a/contracts/deploy/001_core.js +++ b/contracts/deploy/001_core.js @@ -764,6 +764,7 @@ const deployNativeStakingSSVStrategy = async () => { assetAddresses.SSV, // ssvToken assetAddresses.SSVNetwork, // ssvNetwork dFeeAccumulatorProxy.address, // feeAccumulator + assetAddresses.beaconChainDepositContract // depositContractMock ] ); const cStrategyImpl = await ethers.getContractAt( diff --git a/contracts/deploy/091_native_ssv_staking.js b/contracts/deploy/091_native_ssv_staking.js index 60aecc157a..82f14f4bf7 100644 --- a/contracts/deploy/091_native_ssv_staking.js +++ b/contracts/deploy/091_native_ssv_staking.js @@ -11,7 +11,7 @@ module.exports = deploymentWithGovernanceProposal( // "", }, async ({ deployWithConfirmation, ethers, getTxOpts, withConfirmation }) => { - const { deployerAddr } = await getNamedAccounts(); + const { deployerAddr, strategistAddr } = await getNamedAccounts(); const sDeployer = await ethers.provider.getSigner(deployerAddr); // Current contracts @@ -57,6 +57,7 @@ module.exports = deploymentWithGovernanceProposal( addresses.mainnet.SSV, // ssvToken addresses.mainnet.SSVNetwork, // ssvNetwork dFeeAccumulatorProxy.address, // feeAccumulator + addresses.mainnet.beaconChainDepositContract, // beacon chain deposit contract ] ); const cStrategyImpl = await ethers.getContractAt( @@ -147,23 +148,23 @@ module.exports = deploymentWithGovernanceProposal( // 4. configure the fuse interval { contract: cStrategy, - signature: "setFuseInterval(uint256, uint256)", + signature: "setFuseInterval(uint256,uint256)", args: [ ethers.utils.parseEther("21.6"), ethers.utils.parseEther("25.6"), ], }, - // 5. configure the fuse interval + // 5. configure the accounting governor { contract: cStrategy, signature: "setAccountingGovernor(address)", args: [deployerAddr], // TODO: change this to the defender action }, - // 6. configure the fuse interval + // 6. configure strategist address { contract: cStrategy, signature: "setStrategist(address)", - args: [deployerAddr], + args: [strategistAddr], }, ], }; diff --git a/contracts/test/_hot-deploy.js b/contracts/test/_hot-deploy.js index dfcdde466d..1e395d04a6 100644 --- a/contracts/test/_hot-deploy.js +++ b/contracts/test/_hot-deploy.js @@ -89,12 +89,11 @@ async function constructNewContract( ].FEE_ACCUMULATOR_ADDRESS(); return [ [addresses.zero, addresses.mainnet.OETHVaultProxy], - [ - addresses.mainnet.WETH, - addresses.mainnet.SSV, - addresses.mainnet.SSVNetwork, - feeAccumulatorAddress, - ], + addresses.mainnet.WETH, + addresses.mainnet.SSV, + addresses.mainnet.SSVNetwork, + feeAccumulatorAddress, + addresses.mainnet.beaconChainDepositContract, ]; } }; @@ -167,7 +166,7 @@ async function hotDeployOption( } else if (fixtureName === "nativeStakingSSVStrategyFixture") { await hotDeployFixture( fixture, // fixture - "nativeStakingStrategy", // fixtureStrategyVarName + "nativeStakingSSVStrategy", // fixtureStrategyVarName "NativeStakingSSVStrategy" // implContractName ); } diff --git a/contracts/test/helpers.js b/contracts/test/helpers.js index 5bd9aeb785..62c72dfbd3 100644 --- a/contracts/test/helpers.js +++ b/contracts/test/helpers.js @@ -427,6 +427,8 @@ const getAssetAddresses = async (deployments) => { BAL: addresses.mainnet.BAL, SSV: addresses.mainnet.SSV, SSVNetwork: addresses.mainnet.SSVNetwork, + beaconChainDepositContract: addresses.mainnet.beaconChainDepositContract, + }; } else { const addressMap = { @@ -474,6 +476,7 @@ const getAssetAddresses = async (deployments) => { BAL: (await deployments.get("MockBAL")).address, SSV: (await deployments.get("MockSSV")).address, SSVNetwork: (await deployments.get("MockSSVNetwork")).address, + beaconChainDepositContract: (await deployments.get("BeaconChainDepositContractMock")).address, }; try { diff --git a/contracts/test/strategies/nativeSSVStaking.js b/contracts/test/strategies/nativeSSVStaking.js index 22eac6e183..037ff17c8f 100644 --- a/contracts/test/strategies/nativeSSVStaking.js +++ b/contracts/test/strategies/nativeSSVStaking.js @@ -17,7 +17,7 @@ const { const loadFixture = createFixtureLoader(nativeStakingSSVStrategyFixture); -describe("ForkTest: Native SSV Staking Strategy", function () { +describe("Unit test: Native SSV Staking Strategy", function () { this.timeout(0); // Retry up to 3 times on CI @@ -697,7 +697,5 @@ describe("ForkTest: Native SSV Staking Strategy", function () { } it("Should be able to collect the SSV reward token", async () => {}); - - it("Check balance should report correct values", async () => {}); }); }); diff --git a/contracts/utils/addresses.js b/contracts/utils/addresses.js index 23a3bb4be5..adc918518c 100644 --- a/contracts/utils/addresses.js +++ b/contracts/utils/addresses.js @@ -243,6 +243,7 @@ addresses.mainnet.CurveCVXPool = "0xB576491F1E6e5E62f1d8F26062Ee822B40B0E0d4"; // SSV network addresses.mainnet.SSV = "0x9D65fF81a3c488d585bBfb0Bfe3c7707c7917f54"; addresses.mainnet.SSVNetwork = "0xDD9BC35aE942eF0cFa76930954a156B3fF30a4E1"; +addresses.mainnet.beaconChainDepositContract = "0x00000000219ab540356cbb839cbe05303d7705fa"; // Arbitrum One addresses.arbitrumOne = {}; From 121c7f790db3eef50323ed2b30dbf7a75bfebd7c Mon Sep 17 00:00:00 2001 From: Nick Addison Date: Tue, 23 Apr 2024 01:35:01 +1000 Subject: [PATCH 015/273] Native staking updates (#2023) * Update Natspec * Generated docs for native eth strategy * Prettier and linter Fixed spelling of ValidatorAccountant events Implemented depositSSV * Updated Natspec Moved MAX_STAKE on ValidatorAccountant to a constant * Removed strategist from strategy as its already maintained in the Vault * Fix compilation error * Fix unit tests * fix linter --- .../contracts/interfaces/IDepositContract.sol | 2 +- .../mocks/BeaconChainDepositContractMock.sol | 28 ++- .../NativeStaking/FeeAccumulator.sol | 27 +-- .../NativeStakingSSVStrategy.sol | 45 +++-- .../strategies/NativeStaking/README.md | 21 +++ .../NativeStaking/ValidatorAccountant.sol | 65 ++++--- .../NativeStaking/ValidatorRegistrator.sol | 103 ++++++---- contracts/deploy/001_core.js | 2 +- contracts/docs/FeeAccumulatorSquashed.svg | 52 +++++ .../NativeStakingSSVStrategyHierarchy.svg | 142 ++++++++++++++ .../docs/NativeStakingSSVStrategySquashed.svg | 154 +++++++++++++++ .../docs/NativeStakingSSVStrategyStorage.svg | 177 ++++++++++++++++++ contracts/docs/generate.sh | 5 + contracts/test/_fixture.js | 6 +- contracts/test/helpers.js | 5 +- contracts/test/strategies/nativeSSVStaking.js | 52 ++--- .../strategies/nativeSsvStaking.fork-test.js | 8 +- contracts/utils/addresses.js | 3 +- 18 files changed, 741 insertions(+), 156 deletions(-) create mode 100644 contracts/contracts/strategies/NativeStaking/README.md create mode 100644 contracts/docs/FeeAccumulatorSquashed.svg create mode 100644 contracts/docs/NativeStakingSSVStrategyHierarchy.svg create mode 100644 contracts/docs/NativeStakingSSVStrategySquashed.svg create mode 100644 contracts/docs/NativeStakingSSVStrategyStorage.svg diff --git a/contracts/contracts/interfaces/IDepositContract.sol b/contracts/contracts/interfaces/IDepositContract.sol index 9d62b5d776..07f654443b 100644 --- a/contracts/contracts/interfaces/IDepositContract.sol +++ b/contracts/contracts/interfaces/IDepositContract.sol @@ -31,4 +31,4 @@ interface IDepositContract { /// @notice Query the current deposit count. /// @return The deposit count encoded as a little endian 64-bit number. function get_deposit_count() external view returns (bytes memory); -} \ No newline at end of file +} diff --git a/contracts/contracts/mocks/BeaconChainDepositContractMock.sol b/contracts/contracts/mocks/BeaconChainDepositContractMock.sol index d2e148cf46..3d8b995efe 100644 --- a/contracts/contracts/mocks/BeaconChainDepositContractMock.sol +++ b/contracts/contracts/mocks/BeaconChainDepositContractMock.sol @@ -25,13 +25,29 @@ contract BeaconChainDepositContractMock { ) external payable { // Extended ABI length checks since dynamic types are used. require(pubkey.length == 48, "DepositContract: invalid pubkey length"); - require(withdrawal_credentials.length == 32, "DepositContract: invalid withdrawal_credentials length"); - require(signature.length == 96, "DepositContract: invalid signature length"); + require( + withdrawal_credentials.length == 32, + "DepositContract: invalid withdrawal_credentials length" + ); + require( + signature.length == 96, + "DepositContract: invalid signature length" + ); // Check deposit amount require(msg.value >= 1 ether, "DepositContract: deposit value too low"); - require(msg.value % 1 gwei == 0, "DepositContract: deposit value not multiple of gwei"); - uint deposit_amount = msg.value / 1 gwei; - require(deposit_amount <= type(uint64).max, "DepositContract: deposit value too high"); + require( + msg.value % 1 gwei == 0, + "DepositContract: deposit value not multiple of gwei" + ); + uint256 deposit_amount = msg.value / 1 gwei; + require( + deposit_amount <= type(uint64).max, + "DepositContract: deposit value too high" + ); + require( + deposit_data_root != 0, + "DepositContract: invalid deposit_data_root" + ); } -} \ No newline at end of file +} diff --git a/contracts/contracts/strategies/NativeStaking/FeeAccumulator.sol b/contracts/contracts/strategies/NativeStaking/FeeAccumulator.sol index 6a9abd7046..baa5e2bf52 100644 --- a/contracts/contracts/strategies/NativeStaking/FeeAccumulator.sol +++ b/contracts/contracts/strategies/NativeStaking/FeeAccumulator.sol @@ -7,13 +7,14 @@ import { IWETH9 } from "../../interfaces/IWETH9.sol"; /** * @title Fee Accumulator for Native Staking SSV Strategy * @notice This contract is setup to receive fees from processing transactions on the beacon chain - * which includes priority fees and any MEV rewards + * which includes priority fees and any MEV rewards. + * It does NOT include swept ETH from consensus rewards or withdrawals. * @author Origin Protocol Inc */ contract FeeAccumulator is Governable { - /// @dev ETH is sent to the collector address + /// @notice The address the WETH is sent to on `collect` which is the Native Staking Strategy address public immutable COLLECTOR; - /// @notice WETH token address + /// @notice The address of the Wrapped ETH (WETH) token contract address public immutable WETH_TOKEN_ADDRESS; error CallerNotCollector(address caller, address expectedCaller); @@ -23,14 +24,15 @@ contract FeeAccumulator is Governable { /** * @param _collector Address of the contract that collects the fees + * @param _weth Address of the Wrapped ETH (WETH) token contract */ constructor(address _collector, address _weth) { COLLECTOR = _collector; WETH_TOKEN_ADDRESS = _weth; } - /* - * @notice Asserts that the caller is the collector + /** + * @dev Asserts that the caller is the collector */ function _assertIsCollector() internal view { if (msg.sender != COLLECTOR) { @@ -38,15 +40,16 @@ contract FeeAccumulator is Governable { } } - /* - * @notice Send all the ETH to the collector + /** + * @notice Converts ETH to WETH and sends the WETH to the collector + * @return weth The amount of WETH sent to the collector */ - function collect() external returns (uint256 wethReturned) { + function collect() external returns (uint256 weth) { _assertIsCollector(); - wethReturned = address(this).balance; - if (wethReturned > 0) { - IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: wethReturned }(); - IWETH9(WETH_TOKEN_ADDRESS).transfer(COLLECTOR, wethReturned); + weth = address(this).balance; + if (weth > 0) { + IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: weth }(); + IWETH9(WETH_TOKEN_ADDRESS).transfer(COLLECTOR, weth); } } } diff --git a/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol b/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol index 7d06295e35..7bbd0345bd 100644 --- a/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol +++ b/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol @@ -5,6 +5,7 @@ import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import { InitializableAbstractStrategy } from "../../utils/InitializableAbstractStrategy.sol"; +import { ISSVNetwork, Cluster } from "../../interfaces/ISSVNetwork.sol"; import { IWETH9 } from "../../interfaces/IWETH9.sol"; import { FeeAccumulator } from "./FeeAccumulator.sol"; import { ValidatorAccountant } from "./ValidatorAccountant.sol"; @@ -39,7 +40,7 @@ contract NativeStakingSSVStrategy is error EmptyRecipient(); error NotWeth(); - error InsuffiscientWethBalance( + error InsufficientWethBalance( uint256 requiredBalance, uint256 availableBalance ); @@ -60,7 +61,12 @@ contract NativeStakingSSVStrategy is address _beaconChainDepositContract ) InitializableAbstractStrategy(_baseConfig) - ValidatorAccountant(_wethAddress, _baseConfig.vaultAddress, _beaconChainDepositContract, _ssvNetwork) + ValidatorAccountant( + _wethAddress, + _baseConfig.vaultAddress, + _beaconChainDepositContract, + _ssvNetwork + ) { SSV_TOKEN_ADDRESS = _ssvToken; FEE_ACCUMULATOR_ADDRESS = _feeAccumulator; @@ -98,7 +104,8 @@ contract NativeStakingSSVStrategy is beaconChainRewardWETH; } - /// @notice Collect accumulated WETH & SSV tokens and send to the Harvester. + /// @notice Convert accumulated ETH to WETH and send to the Harvester. + /// Only callable by the Harvester. function collectRewardTokens() external virtual @@ -129,7 +136,7 @@ contract NativeStakingSSVStrategy is if (balance > 0) { if (address(rewardToken) == WETH_TOKEN_ADDRESS) { if (beaconChainRewardWETH > balance) { - revert InsuffiscientWethBalance( + revert InsufficientWethBalance( beaconChainRewardWETH, balance ); @@ -232,9 +239,9 @@ contract NativeStakingSSVStrategy is function _abstractSetPToken(address _asset, address) internal override {} /// @notice Returns the total value of (W)ETH that is staked to the validators - /// and also present on the native staking and fee accumulator contracts + /// and also present on the native staking and fee accumulator contracts. /// @param _asset Address of weth asset - /// @return balance Total value of (W)ETH + /// @return balance Total value of (W)ETH function checkBalance(address _asset) external view @@ -254,14 +261,13 @@ contract NativeStakingSSVStrategy is _pause(); } - /// @dev Retuns bool indicating whether asset is supported by strategy - /// @param _asset Address of the asset + /// @notice Returns bool indicating whether asset is supported by strategy. + /// @param _asset The address of the asset token. function supportsAsset(address _asset) public view override returns (bool) { return _asset == WETH_TOKEN_ADDRESS; } - /// @notice Approve the spending of all assets - /// @dev Approves the SSV Network contract to transfer SSV tokens for deposits + /// @notice Approves the SSV Network contract to transfer SSV tokens for deposits function safeApproveAllTokens() external override { /// @dev Approves the SSV Network contract to transfer SSV tokens for deposits IERC20(SSV_TOKEN_ADDRESS).approve( @@ -271,17 +277,20 @@ contract NativeStakingSSVStrategy is } /// @notice Deposits more SSV Tokens to the SSV Network contract which is used to pay the SSV Operators. - /// @dev A SSV cluster is defined by the SSVOwnerAddress and the set of operatorIds - /// uses "onlyStrategist" modifier so continuous fron-running can't DOS our maintenance service - /// that tries to top us SSV tokens. + /// @dev A SSV cluster is defined by the SSVOwnerAddress and the set of operatorIds. + /// uses "onlyStrategist" modifier so continuous front-running can't DOS our maintenance service + /// that tries to top up SSV tokens. + /// @param cluster The SSV cluster details that must be derived from emitted events from the SSVNetwork contract. function depositSSV( uint64[] memory operatorIds, uint256 amount, Cluster memory cluster - ) - onlyStrategist - external { - // address SSV_NETWORK_ADDRESS = lrtConfig.getContract(LRTConstants.SSV_NETWORK); - // ISSVNetwork(SSV_NETWORK_ADDRESS).deposit(address(this), operatorIds, amount, cluster); + ) external onlyStrategist { + ISSVNetwork(SSV_NETWORK_ADDRESS).deposit( + address(this), + operatorIds, + amount, + cluster + ); } } diff --git a/contracts/contracts/strategies/NativeStaking/README.md b/contracts/contracts/strategies/NativeStaking/README.md new file mode 100644 index 0000000000..13e280eb9b --- /dev/null +++ b/contracts/contracts/strategies/NativeStaking/README.md @@ -0,0 +1,21 @@ +# Diagrams + +## Native Staking SSV Strategy + +### Hierarchy + +![Native Staking SSV Strategy Hierarchy](../../../docs/NativeStakingSSVStrategyHierarchy.svg) + +### Squashed + +![Native Staking SSV Strategy Squashed](../../../docs/NativeStakingSSVStrategySquashed.svg) + +### Storage + +![Native Staking SSV Strategy Storage](../../../docs/NativeStakingSSVStrategyStorage.svg) + +## Fee Accumulator + +### Squashed + +![Fee Accumulator Squashed](../../../docs/FeeAccumulatorSquashed.svg) diff --git a/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol b/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol index e85b808129..8570e96f16 100644 --- a/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol +++ b/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol @@ -3,6 +3,7 @@ pragma solidity ^0.8.0; import { Pausable } from "@openzeppelin/contracts/security/Pausable.sol"; import { ValidatorRegistrator } from "./ValidatorRegistrator.sol"; +import { IVault } from "../../interfaces/IVault.sol"; import { IWETH9 } from "../../interfaces/IWETH9.sol"; /// @title Accountant of the rewards Beacon Chain ETH @@ -10,6 +11,10 @@ import { IWETH9 } from "../../interfaces/IWETH9.sol"; /// or partial withdrawals /// @author Origin Protocol Inc abstract contract ValidatorAccountant is ValidatorRegistrator { + /// @notice The maximum amount of ETH that can be staked by a validator + /// @dev this can change in the future with EIP-7251, Increase the MAX_EFFECTIVE_BALANCE + uint256 public constant MAX_STAKE = 32 ether; + /// @notice Address of the OETH Vault proxy contract address public immutable VAULT_ADDRESS; /// @dev The WETH present on this contract will come from 2 sources: @@ -23,14 +28,12 @@ abstract contract ValidatorAccountant is ValidatorRegistrator { /// present as a result of a deposit. uint256 public beaconChainRewardWETH = 0; - /// @dev start of fuse interval + /// @notice start of fuse interval uint256 public fuseIntervalStart = 0; - /// @dev end of fuse interval + /// @notice end of fuse interval uint256 public fuseIntervalEnd = 0; - /// @dev Governor that can manually correct the accounting + /// @notice Governor that can manually correct the accounting address public accountingGovernor; - /// @dev Strategist that can pause the accounting - address public strategist; uint256[50] private __gap; @@ -40,12 +43,12 @@ abstract contract ValidatorAccountant is ValidatorRegistrator { uint256 start, uint256 end ); - event AccuntingFullyWithdrawnValidator( + event AccountingFullyWithdrawnValidator( uint256 noOfValidators, uint256 remainingValidators, uint256 wethSentToVault ); - event AccuntingValidatorSlashed( + event AccountingValidatorSlashed( uint256 remainingValidators, uint256 wethSentToVault ); @@ -54,10 +57,6 @@ abstract contract ValidatorAccountant is ValidatorRegistrator { address newAddress ); event AccountingBeaconChainRewards(uint256 amount); - event StrategistAddressChanged( - address oldStrategist, - address newStrategist - ); event AccountingManuallyFixed( uint256 oldActiveDepositedValidators, @@ -85,7 +84,10 @@ abstract contract ValidatorAccountant is ValidatorRegistrator { /// @dev Throws if called by any account other than the Strategist modifier onlyStrategist() { - require(msg.sender == strategist, "Caller is not the Strategist"); + require( + msg.sender == IVault(VAULT_ADDRESS).strategistAddr(), + "Caller is not the Strategist" + ); _; } @@ -93,8 +95,18 @@ abstract contract ValidatorAccountant is ValidatorRegistrator { /// @param _vaultAddress Address of the Vault /// @param _beaconChainDepositContract Address of the beacon chain deposit contract /// @param _ssvNetwork Address of the SSV Network contract - constructor(address _wethAddress, address _vaultAddress, address _beaconChainDepositContract, address _ssvNetwork) - ValidatorRegistrator(_wethAddress, _beaconChainDepositContract, _ssvNetwork) { + constructor( + address _wethAddress, + address _vaultAddress, + address _beaconChainDepositContract, + address _ssvNetwork + ) + ValidatorRegistrator( + _wethAddress, + _beaconChainDepositContract, + _ssvNetwork + ) + { VAULT_ADDRESS = _vaultAddress; } @@ -103,11 +115,6 @@ abstract contract ValidatorAccountant is ValidatorRegistrator { accountingGovernor = _address; } - function setStrategist(address _address) external onlyGovernor { - emit StrategistAddressChanged(strategist, _address); - strategist = _address; - } - /// @notice set fuse interval values function setFuseInterval( uint256 _fuseIntervalStart, @@ -133,19 +140,24 @@ abstract contract ValidatorAccountant is ValidatorRegistrator { fuseIntervalEnd = _fuseIntervalEnd; } + /* solhint-disable max-line-length */ /// This notion page offers a good explanation of how the accounting functions /// https://www.notion.so/originprotocol/Limited-simplified-native-staking-accounting-67a217c8420d40678eb943b9da0ee77d - /// In short after dividing by 32 if the ETH remaining on the contract falls between 0 and fuseIntervalStart the accounting + /// In short, after dividing by 32 if the ETH remaining on the contract falls between 0 and fuseIntervalStart the accounting /// function will treat that ETH as a Beacon Chain Reward ETH. /// On the contrary if after dividing by 32 the ETH remaining on the contract falls between fuseIntervalEnd and 32 the /// accounting function will treat that as a validator slashing. /// @notice Perform the accounting attributing beacon chain ETH to either full or partial withdrawals. Returns true when - /// accounting is valid and fuse isn't "blown". Returns false when fuse is blown + /// accounting is valid and fuse isn't "blown". Returns false when fuse is blown. /// @dev This function could in theory be permission-less but lets allow only the Registrator (Defender Action) to call it - /// for now - function doAccounting() external onlyRegistrator returns (bool accountingValid) { + /// for now. + /* solhint-enable max-line-length */ + function doAccounting() + external + onlyRegistrator + returns (bool accountingValid) + { uint256 ethBalance = address(this).balance; - uint256 MAX_STAKE = 32 ether; accountingValid = true; // send the WETH that is from fully withdrawn validators to the Vault @@ -157,7 +169,7 @@ abstract contract ValidatorAccountant is ValidatorRegistrator { IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: wethToVault }(); IWETH9(WETH_TOKEN_ADDRESS).transfer(VAULT_ADDRESS, wethToVault); - emit AccuntingFullyWithdrawnValidator( + emit AccountingFullyWithdrawnValidator( fullyWithdrawnValidators, activeDepositedValidators, wethToVault @@ -173,6 +185,7 @@ abstract contract ValidatorAccountant is ValidatorRegistrator { // Beacon chain rewards swept (partial validator withdrawals) if (ethRemaining <= fuseIntervalStart) { IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: ethRemaining }(); + // solhint-disable-next-line reentrancy beaconChainRewardWETH += ethRemaining; emit AccountingBeaconChainRewards(ethRemaining); } @@ -182,7 +195,7 @@ abstract contract ValidatorAccountant is ValidatorRegistrator { IWETH9(WETH_TOKEN_ADDRESS).transfer(VAULT_ADDRESS, ethRemaining); activeDepositedValidators -= 1; - emit AccuntingValidatorSlashed( + emit AccountingValidatorSlashed( activeDepositedValidators, ethRemaining ); diff --git a/contracts/contracts/strategies/NativeStaking/ValidatorRegistrator.sol b/contracts/contracts/strategies/NativeStaking/ValidatorRegistrator.sol index 2ee2a87fa1..1674b47730 100644 --- a/contracts/contracts/strategies/NativeStaking/ValidatorRegistrator.sol +++ b/contracts/contracts/strategies/NativeStaking/ValidatorRegistrator.sol @@ -15,16 +15,16 @@ struct ValidatorStakeData { /** * @title Registrator of the validators - * @notice This contract implements all the required functionality to register validators + * @notice This contract implements all the required functionality to register, exit and remove validators. * @author Origin Protocol Inc */ abstract contract ValidatorRegistrator is Governable, Pausable { - /// @notice The Wrapped ETH (WETH) contract address + /// @notice The address of the Wrapped ETH (WETH) token contract address public immutable WETH_TOKEN_ADDRESS; - /// @notice Address of the beacon chain deposit contract + /// @notice The address of the beacon chain deposit contract address public immutable BEACON_CHAIN_DEPOSIT_CONTRACT; - /// @notice SSV Network contract used to interface with - address public immutable SSV_NETWORK_ADDRESS; + /// @notice The address of the SSV Network contract used to interface with + address public immutable SSV_NETWORK_ADDRESS; /// @notice Address of the registrator - allowed to register, exit and remove validators address public validatorRegistrator; @@ -66,7 +66,11 @@ abstract contract ValidatorRegistrator is Governable, Pausable { /// @param _wethAddress Address of the Erc20 WETH Token contract /// @param _beaconChainDepositContract Address of the beacon chain deposit contract /// @param _ssvNetwork Address of the SSV Network contract - constructor(address _wethAddress, address _beaconChainDepositContract, address _ssvNetwork) { + constructor( + address _wethAddress, + address _beaconChainDepositContract, + address _ssvNetwork + ) { WETH_TOKEN_ADDRESS = _wethAddress; BEACON_CHAIN_DEPOSIT_CONTRACT = _beaconChainDepositContract; SSV_NETWORK_ADDRESS = _ssvNetwork; @@ -88,12 +92,13 @@ abstract contract ValidatorRegistrator is Governable, Pausable { /// @notice Stakes WETH to the node validators /// @param validators A list of validator data needed to stake. - /// The ValidatorStakeData struct contains the pubkey, signature and depositDataRoot. - /// @dev Only accounts with the Operator role can call this function. - function stakeEth(ValidatorStakeData[] calldata validators) + /// The `ValidatorStakeData` struct contains the pubkey, signature and depositDataRoot. + /// Only the registrator can call this function. + function stakeEth(ValidatorStakeData[] calldata validators) + external onlyRegistrator whenNotPaused - external { + { uint256 requiredWETH = validators.length * 32 ether; uint256 wethBalance = getWETHBalanceEligibleForStaking(); if (wethBalance < requiredWETH) { @@ -104,15 +109,22 @@ abstract contract ValidatorRegistrator is Governable, Pausable { IWETH9(WETH_TOKEN_ADDRESS).withdraw(wethBalance); // For each validator - for (uint256 i = 0; i < validators.length;) { + for (uint256 i = 0; i < validators.length; ) { bytes32 pubkeyHash = keccak256(validators[i].pubkey); VALIDATOR_STATE currentState = validatorsStates[pubkeyHash]; if (currentState != VALIDATOR_STATE.REGISTERED) { - revert ValidatorInUnexpectedState(validators[i].pubkey, currentState); + revert ValidatorInUnexpectedState( + validators[i].pubkey, + currentState + ); } - _stakeEth(validators[i].pubkey, validators[i].signature, validators[i].depositDataRoot); + _stakeEth( + validators[i].pubkey, + validators[i].signature, + validators[i].depositDataRoot + ); validatorsStates[pubkeyHash] = VALIDATOR_STATE.STAKED; unchecked { @@ -121,51 +133,61 @@ abstract contract ValidatorRegistrator is Governable, Pausable { } } - /// @dev Deposit WETH to the beacon chain deposit contract - /// @dev The public functions that call this internal function are responsible for access control. - function _stakeEth(bytes calldata pubkey, bytes calldata signature, bytes32 depositDataRoot) internal { + /// @dev Deposit WETH to the beacon chain deposit contract. + /// The public functions that call this internal function are responsible for access control. + function _stakeEth( + bytes calldata pubkey, + bytes calldata signature, + bytes32 depositDataRoot + ) internal { /* 0x01 to indicate that withdrawal credentials will contain an EOA address that the sweeping function * can sweep funds to. * bytes11(0) to fill up the required zeros * remaining bytes20 are for the address */ - bytes memory withdrawal_credentials = abi.encodePacked(bytes1(0x01), bytes11(0), address(this)); + bytes memory withdrawal_credentials = abi.encodePacked( + bytes1(0x01), + bytes11(0), + address(this) + ); IDepositContract(BEACON_CHAIN_DEPOSIT_CONTRACT).deposit( - pubkey, withdrawal_credentials, signature, depositDataRoot + pubkey, + withdrawal_credentials, + signature, + depositDataRoot ); activeDepositedValidators += 1; emit ETHStaked(pubkey, 32 ether, withdrawal_credentials); - } - /// @dev Registers a new validator in the SSV Cluster + /// @notice Registers a new validator in the SSV Cluster. + /// Only the registrator can call this function. function registerSsvValidator( bytes calldata publicKey, uint64[] calldata operatorIds, bytes calldata sharesData, uint256 amount, Cluster calldata cluster - ) - external - onlyRegistrator - whenNotPaused - { - ISSVNetwork(SSV_NETWORK_ADDRESS).registerValidator(publicKey, operatorIds, sharesData, amount, cluster); + ) external onlyRegistrator whenNotPaused { + ISSVNetwork(SSV_NETWORK_ADDRESS).registerValidator( + publicKey, + operatorIds, + sharesData, + amount, + cluster + ); validatorsStates[keccak256(publicKey)] = VALIDATOR_STATE.REGISTERED; emit SSVValidatorRegistered(publicKey, operatorIds); } - /// @dev Exit a validator from the Beacon chain. - /// The staked ETH will be sent to the EigenPod. + /// @notice Exit a validator from the Beacon chain. + /// The staked ETH will eventually swept to this native staking strategy. + /// Only the registrator can call this function. function exitSsvValidator( bytes calldata publicKey, uint64[] calldata operatorIds - ) - external - onlyRegistrator - whenNotPaused - { + ) external onlyRegistrator whenNotPaused { VALIDATOR_STATE currentState = validatorsStates[keccak256(publicKey)]; if (currentState != VALIDATOR_STATE.STAKED) { revert ValidatorInUnexpectedState(publicKey, currentState); @@ -177,24 +199,25 @@ abstract contract ValidatorRegistrator is Governable, Pausable { validatorsStates[keccak256(publicKey)] = VALIDATOR_STATE.EXITING; } - /// @dev Remove a validator from the SSV Cluster. + /// @notice Remove a validator from the SSV Cluster. /// Make sure `exitSsvValidator` is called before and the validate has exited the Beacon chain. /// If removed before the validator has exited the beacon chain will result in the validator being slashed. + /// Only the registrator can call this function. function removeSsvValidator( bytes calldata publicKey, uint64[] calldata operatorIds, Cluster calldata cluster - ) - external - onlyRegistrator - whenNotPaused - { + ) external onlyRegistrator whenNotPaused { VALIDATOR_STATE currentState = validatorsStates[keccak256(publicKey)]; if (currentState != VALIDATOR_STATE.EXITING) { revert ValidatorInUnexpectedState(publicKey, currentState); } - ISSVNetwork(SSV_NETWORK_ADDRESS).removeValidator(publicKey, operatorIds, cluster); + ISSVNetwork(SSV_NETWORK_ADDRESS).removeValidator( + publicKey, + operatorIds, + cluster + ); emit SSVValidatorExitCompleted(publicKey, operatorIds); validatorsStates[keccak256(publicKey)] = VALIDATOR_STATE.EXIT_COMPLETE; diff --git a/contracts/deploy/001_core.js b/contracts/deploy/001_core.js index ed14d833ec..b3cb95cea2 100644 --- a/contracts/deploy/001_core.js +++ b/contracts/deploy/001_core.js @@ -764,7 +764,7 @@ const deployNativeStakingSSVStrategy = async () => { assetAddresses.SSV, // ssvToken assetAddresses.SSVNetwork, // ssvNetwork dFeeAccumulatorProxy.address, // feeAccumulator - assetAddresses.beaconChainDepositContract // depositContractMock + assetAddresses.beaconChainDepositContract, // depositContractMock ] ); const cStrategyImpl = await ethers.getContractAt( diff --git a/contracts/docs/FeeAccumulatorSquashed.svg b/contracts/docs/FeeAccumulatorSquashed.svg new file mode 100644 index 0000000000..3c2c1558ab --- /dev/null +++ b/contracts/docs/FeeAccumulatorSquashed.svg @@ -0,0 +1,52 @@ + + + + + + +UmlClassDiagram + + + +278 + +FeeAccumulator +../contracts/strategies/NativeStaking/FeeAccumulator.sol + +Private: +   governorPosition: bytes32 <<Governable>> +   pendingGovernorPosition: bytes32 <<Governable>> +   reentryStatusPosition: bytes32 <<Governable>> +   __gap: uint256[50] <<FeeAccumulator>> +Public: +   _NOT_ENTERED: uint256 <<Governable>> +   _ENTERED: uint256 <<Governable>> +   COLLECTOR: address <<FeeAccumulator>> +   WETH_TOKEN_ADDRESS: address <<FeeAccumulator>> + +Internal: +    _governor(): (governorOut: address) <<Governable>> +    _pendingGovernor(): (pendingGovernor: address) <<Governable>> +    _setGovernor(newGovernor: address) <<Governable>> +    _setPendingGovernor(newGovernor: address) <<Governable>> +    _changeGovernor(_newGovernor: address) <<Governable>> +    _assertIsCollector() <<FeeAccumulator>> +External: +    transferGovernance(_newGovernor: address) <<onlyGovernor>> <<Governable>> +    claimGovernance() <<Governable>> +    collect(): (weth: uint256) <<FeeAccumulator>> +Public: +    <<event>> PendingGovernorshipTransfer(previousGovernor: address, newGovernor: address) <<Governable>> +    <<event>> GovernorshipTransferred(previousGovernor: address, newGovernor: address) <<Governable>> +    <<modifier>> onlyGovernor() <<Governable>> +    <<modifier>> nonReentrant() <<Governable>> +    constructor() <<Governable>> +    governor(): address <<Governable>> +    isGovernor(): bool <<Governable>> +    constructor(_collector: address, _weth: address) <<FeeAccumulator>> + + + diff --git a/contracts/docs/NativeStakingSSVStrategyHierarchy.svg b/contracts/docs/NativeStakingSSVStrategyHierarchy.svg new file mode 100644 index 0000000000..3007a5a443 --- /dev/null +++ b/contracts/docs/NativeStakingSSVStrategyHierarchy.svg @@ -0,0 +1,142 @@ + + + + + + +UmlClassDiagram + + + +20 + +Governable +../contracts/governance/Governable.sol + + + +278 + +FeeAccumulator +../contracts/strategies/NativeStaking/FeeAccumulator.sol + + + +278->20 + + + + + +280 + +NativeStakingSSVStrategy +../contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol + + + +280->278 + + + + + +281 + +<<Abstract>> +ValidatorAccountant +../contracts/strategies/NativeStaking/ValidatorAccountant.sol + + + +280->281 + + + + + +210 + +<<Abstract>> +InitializableAbstractStrategy +../contracts/utils/InitializableAbstractStrategy.sol + + + +280->210 + + + + + +283 + +<<Abstract>> +ValidatorRegistrator +../contracts/strategies/NativeStaking/ValidatorRegistrator.sol + + + +281->283 + + + + + +283->20 + + + + + +336 + +<<Abstract>> +Pausable +../node_modules/@openzeppelin/contracts/security/Pausable.sol + + + +283->336 + + + + + +209 + +<<Abstract>> +Initializable +../contracts/utils/Initializable.sol + + + +210->20 + + + + + +210->209 + + + + + +341 + +<<Abstract>> +Context +../node_modules/@openzeppelin/contracts/utils/Context.sol + + + +336->341 + + + + + diff --git a/contracts/docs/NativeStakingSSVStrategySquashed.svg b/contracts/docs/NativeStakingSSVStrategySquashed.svg new file mode 100644 index 0000000000..838bee6efe --- /dev/null +++ b/contracts/docs/NativeStakingSSVStrategySquashed.svg @@ -0,0 +1,154 @@ + + + + + + +UmlClassDiagram + + + +280 + +NativeStakingSSVStrategy +../contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol + +Private: +   governorPosition: bytes32 <<Governable>> +   pendingGovernorPosition: bytes32 <<Governable>> +   reentryStatusPosition: bytes32 <<Governable>> +   _paused: bool <<Pausable>> +   __gap: uint256[50] <<ValidatorRegistrator>> +   __gap: uint256[50] <<ValidatorAccountant>> +   initialized: bool <<Initializable>> +   initializing: bool <<Initializable>> +   ______gap: uint256[50] <<Initializable>> +   _deprecated_platformAddress: address <<InitializableAbstractStrategy>> +   _deprecated_vaultAddress: address <<InitializableAbstractStrategy>> +   _deprecated_rewardTokenAddress: address <<InitializableAbstractStrategy>> +   _deprecated_rewardLiquidationThreshold: uint256 <<InitializableAbstractStrategy>> +   _reserved: int256[98] <<InitializableAbstractStrategy>> +   __gap: uint256[50] <<NativeStakingSSVStrategy>> +Internal: +   assetsMapped: address[] <<InitializableAbstractStrategy>> +Public: +   _NOT_ENTERED: uint256 <<Governable>> +   _ENTERED: uint256 <<Governable>> +   WETH_TOKEN_ADDRESS: address <<ValidatorRegistrator>> +   BEACON_CHAIN_DEPOSIT_CONTRACT: address <<ValidatorRegistrator>> +   SSV_NETWORK_ADDRESS: address <<ValidatorRegistrator>> +   validatorRegistrator: address <<ValidatorRegistrator>> +   activeDepositedValidators: uint256 <<ValidatorRegistrator>> +   validatorsStates: mapping(bytes32=>VALIDATOR_STATE) <<ValidatorRegistrator>> +   VAULT_ADDRESS: address <<ValidatorAccountant>> +   beaconChainRewardWETH: uint256 <<ValidatorAccountant>> +   fuseIntervalStart: uint256 <<ValidatorAccountant>> +   fuseIntervalEnd: uint256 <<ValidatorAccountant>> +   accountingGovernor: address <<ValidatorAccountant>> +   strategist: address <<ValidatorAccountant>> +   platformAddress: address <<InitializableAbstractStrategy>> +   vaultAddress: address <<InitializableAbstractStrategy>> +   assetToPToken: mapping(address=>address) <<InitializableAbstractStrategy>> +   harvesterAddress: address <<InitializableAbstractStrategy>> +   rewardTokenAddresses: address[] <<InitializableAbstractStrategy>> +   SSV_TOKEN_ADDRESS: address <<NativeStakingSSVStrategy>> +   FEE_ACCUMULATOR_ADDRESS: address <<NativeStakingSSVStrategy>> + +Internal: +    _governor(): (governorOut: address) <<Governable>> +    _pendingGovernor(): (pendingGovernor: address) <<Governable>> +    _setGovernor(newGovernor: address) <<Governable>> +    _setPendingGovernor(newGovernor: address) <<Governable>> +    _changeGovernor(_newGovernor: address) <<Governable>> +    _msgSender(): address <<Context>> +    _msgData(): bytes <<Context>> +    _pause() <<whenNotPaused>> <<Pausable>> +    _unpause() <<whenPaused>> <<Pausable>> +    _stakeEth(pubkey: bytes, signature: bytes, depositDataRoot: bytes32) <<ValidatorRegistrator>> +    _initialize(_rewardTokenAddresses: address[], _assets: address[], _pTokens: address[]) <<InitializableAbstractStrategy>> +    _collectRewardTokens() <<NativeStakingSSVStrategy>> +    _setPTokenAddress(_asset: address, _pToken: address) <<InitializableAbstractStrategy>> +    _abstractSetPToken(_asset: address, address) <<NativeStakingSSVStrategy>> +    _deposit(_asset: address, _amount: uint256) <<NativeStakingSSVStrategy>> +    _withdraw(_recipient: address, _asset: address, _amount: uint256) <<NativeStakingSSVStrategy>> +External: +    transferGovernance(_newGovernor: address) <<onlyGovernor>> <<Governable>> +    claimGovernance() <<Governable>> +    setRegistratorAddress(_address: address) <<onlyGovernor>> <<ValidatorRegistrator>> +    stakeEth(validators: ValidatorStakeData[]) <<onlyRegistrator, whenNotPaused>> <<ValidatorRegistrator>> +    registerSsvValidator(publicKey: bytes, operatorIds: uint64[], sharesData: bytes, amount: uint256, cluster: Cluster) <<onlyRegistrator, whenNotPaused>> <<ValidatorRegistrator>> +    exitSsvValidator(publicKey: bytes, operatorIds: uint64[]) <<onlyRegistrator, whenNotPaused>> <<ValidatorRegistrator>> +    removeSsvValidator(publicKey: bytes, operatorIds: uint64[], cluster: Cluster) <<onlyRegistrator, whenNotPaused>> <<ValidatorRegistrator>> +    setAccountingGovernor(_address: address) <<onlyGovernor>> <<ValidatorAccountant>> +    setStrategist(_address: address) <<onlyGovernor>> <<ValidatorAccountant>> +    setFuseInterval(_fuseIntervalStart: uint256, _fuseIntervalEnd: uint256) <<onlyGovernor>> <<ValidatorAccountant>> +    doAccounting(): (accountingValid: bool) <<onlyRegistrator>> <<ValidatorAccountant>> +    manuallyFixAccounting(_activeDepositedValidators: uint256, _ethToWeth: uint256, _wethToBeSentToVault: uint256, _beaconChainRewardWETH: uint256, _ethThresholdCheck: uint256, _wethThresholdCheck: uint256) <<onlyAccountingGovernor>> <<ValidatorAccountant>> +    collectRewardTokens() <<onlyHarvester, nonReentrant>> <<NativeStakingSSVStrategy>> +    setRewardTokenAddresses(_rewardTokenAddresses: address[]) <<onlyGovernor>> <<InitializableAbstractStrategy>> +    getRewardTokenAddresses(): address[] <<InitializableAbstractStrategy>> +    setPTokenAddress(_asset: address, _pToken: address) <<onlyGovernor>> <<InitializableAbstractStrategy>> +    removePToken(_assetIndex: uint256) <<onlyGovernor>> <<InitializableAbstractStrategy>> +    setHarvesterAddress(_harvesterAddress: address) <<onlyGovernor>> <<InitializableAbstractStrategy>> +    safeApproveAllTokens() <<NativeStakingSSVStrategy>> +    deposit(_asset: address, _amount: uint256) <<onlyVault, nonReentrant>> <<NativeStakingSSVStrategy>> +    depositAll() <<onlyVault, nonReentrant>> <<NativeStakingSSVStrategy>> +    withdraw(_recipient: address, _asset: address, _amount: uint256) <<onlyVault, nonReentrant>> <<NativeStakingSSVStrategy>> +    withdrawAll() <<onlyVaultOrGovernor, nonReentrant>> <<NativeStakingSSVStrategy>> +    checkBalance(_asset: address): (balance: uint256) <<NativeStakingSSVStrategy>> +    initialize(_rewardTokenAddresses: address[], _assets: address[], _pTokens: address[]) <<onlyGovernor, initializer>> <<NativeStakingSSVStrategy>> +    pause() <<onlyStrategist>> <<NativeStakingSSVStrategy>> +    depositSSV(operatorIds: uint64[], amount: uint256, cluster: Cluster) <<onlyStrategist>> <<NativeStakingSSVStrategy>> +Public: +    <<event>> PendingGovernorshipTransfer(previousGovernor: address, newGovernor: address) <<Governable>> +    <<event>> GovernorshipTransferred(previousGovernor: address, newGovernor: address) <<Governable>> +    <<event>> Paused(account: address) <<Pausable>> +    <<event>> Unpaused(account: address) <<Pausable>> +    <<event>> RegistratorAddressChanged(oldAddress: address, newAddress: address) <<ValidatorRegistrator>> +    <<event>> ETHStaked(pubkey: bytes, amount: uint256, withdrawal_credentials: bytes) <<ValidatorRegistrator>> +    <<event>> SSVValidatorRegistered(pubkey: bytes, operatorIds: uint64[]) <<ValidatorRegistrator>> +    <<event>> SSVValidatorExitInitiated(pubkey: bytes, operatorIds: uint64[]) <<ValidatorRegistrator>> +    <<event>> SSVValidatorExitCompleted(pubkey: bytes, operatorIds: uint64[]) <<ValidatorRegistrator>> +    <<event>> FuseIntervalUpdated(oldStart: uint256, oldEnd: uint256, start: uint256, end: uint256) <<ValidatorAccountant>> +    <<event>> AccuntingFullyWithdrawnValidator(noOfValidators: uint256, remainingValidators: uint256, wethSentToVault: uint256) <<ValidatorAccountant>> +    <<event>> AccuntingValidatorSlashed(remainingValidators: uint256, wethSentToVault: uint256) <<ValidatorAccountant>> +    <<event>> AccountingGovernorAddressChanged(oldAddress: address, newAddress: address) <<ValidatorAccountant>> +    <<event>> AccountingBeaconChainRewards(amount: uint256) <<ValidatorAccountant>> +    <<event>> StrategistAddressChanged(oldStrategist: address, newStrategist: address) <<ValidatorAccountant>> +    <<event>> AccountingManuallyFixed(oldActiveDepositedValidators: uint256, activeDepositedValidators: uint256, oldBeaconChainRewardWETH: uint256, beaconChainRewardWETH: uint256, ethToWeth: uint256, wethToBeSentToVault: uint256) <<ValidatorAccountant>> +    <<event>> PTokenAdded(_asset: address, _pToken: address) <<InitializableAbstractStrategy>> +    <<event>> PTokenRemoved(_asset: address, _pToken: address) <<InitializableAbstractStrategy>> +    <<event>> Deposit(_asset: address, _pToken: address, _amount: uint256) <<InitializableAbstractStrategy>> +    <<event>> Withdrawal(_asset: address, _pToken: address, _amount: uint256) <<InitializableAbstractStrategy>> +    <<event>> RewardTokenCollected(recipient: address, rewardToken: address, amount: uint256) <<InitializableAbstractStrategy>> +    <<event>> RewardTokenAddressesUpdated(_oldAddresses: address[], _newAddresses: address[]) <<InitializableAbstractStrategy>> +    <<event>> HarvesterAddressesUpdated(_oldHarvesterAddress: address, _newHarvesterAddress: address) <<InitializableAbstractStrategy>> +    <<modifier>> onlyGovernor() <<Governable>> +    <<modifier>> nonReentrant() <<Governable>> +    <<modifier>> whenNotPaused() <<Pausable>> +    <<modifier>> whenPaused() <<Pausable>> +    <<modifier>> onlyRegistrator() <<ValidatorRegistrator>> +    <<modifier>> onlyAccountingGovernor() <<ValidatorAccountant>> +    <<modifier>> onlyStrategist() <<ValidatorAccountant>> +    <<modifier>> initializer() <<Initializable>> +    <<modifier>> onlyVault() <<InitializableAbstractStrategy>> +    <<modifier>> onlyHarvester() <<InitializableAbstractStrategy>> +    <<modifier>> onlyVaultOrGovernor() <<InitializableAbstractStrategy>> +    <<modifier>> onlyVaultOrGovernorOrStrategist() <<InitializableAbstractStrategy>> +    constructor() <<Pausable>> +    governor(): address <<Governable>> +    isGovernor(): bool <<Governable>> +    paused(): bool <<Pausable>> +    constructor(_wethAddress: address, _beaconChainDepositContract: address, _ssvNetwork: address) <<ValidatorRegistrator>> +    getWETHBalanceEligibleForStaking(): (_amount: uint256) <<NativeStakingSSVStrategy>> +    constructor(_wethAddress: address, _vaultAddress: address, _beaconChainDepositContract: address, _ssvNetwork: address) <<ValidatorAccountant>> +    constructor(_config: BaseStrategyConfig) <<InitializableAbstractStrategy>> +    transferToken(_asset: address, _amount: uint256) <<onlyGovernor>> <<InitializableAbstractStrategy>> +    supportsAsset(_asset: address): bool <<NativeStakingSSVStrategy>> +    constructor(_baseConfig: BaseStrategyConfig, _wethAddress: address, _ssvToken: address, _ssvNetwork: address, _feeAccumulator: address, _beaconChainDepositContract: address) <<NativeStakingSSVStrategy>> + + + diff --git a/contracts/docs/NativeStakingSSVStrategyStorage.svg b/contracts/docs/NativeStakingSSVStrategyStorage.svg new file mode 100644 index 0000000000..41964933b0 --- /dev/null +++ b/contracts/docs/NativeStakingSSVStrategyStorage.svg @@ -0,0 +1,177 @@ + + + + + + +StorageDiagram + + + +3 + +NativeStakingSSVStrategy <<Contract>> + +slot + +0 + +1 + +2 + +3-52 + +53 + +54 + +55 + +56 + +57 + +58-107 + +108 + +109-158 + +159 + +160 + +161 + +162 + +163 + +164 + +165 + +166 + +167-264 + +265-314 + +type: <inherited contract>.variable (bytes) + +unallocated (11) + +address: ValidatorRegistrator.validatorRegistrator (20) + +bool: Pausable._paused (1) + +uint256: ValidatorRegistrator.activeDepositedValidators (32) + +mapping(bytes32=>VALIDATOR_STATE): ValidatorRegistrator.validatorsStates (32) + +uint256[50]: ValidatorRegistrator.__gap (1600) + +uint256: ValidatorAccountant.beaconChainRewardWETH (32) + +uint256: ValidatorAccountant.fuseIntervalStart (32) + +uint256: ValidatorAccountant.fuseIntervalEnd (32) + +unallocated (12) + +address: ValidatorAccountant.accountingGovernor (20) + +unallocated (12) + +address: ValidatorAccountant.strategist (20) + +uint256[50]: ValidatorAccountant.__gap (1600) + +unallocated (30) + +bool: Initializable.initializing (1) + +bool: Initializable.initialized (1) + +uint256[50]: Initializable.______gap (1600) + +unallocated (12) + +address: InitializableAbstractStrategy._deprecated_platformAddress (20) + +unallocated (12) + +address: InitializableAbstractStrategy._deprecated_vaultAddress (20) + +mapping(address=>address): InitializableAbstractStrategy.assetToPToken (32) + +address[]: InitializableAbstractStrategy.assetsMapped (32) + +unallocated (12) + +address: InitializableAbstractStrategy._deprecated_rewardTokenAddress (20) + +uint256: InitializableAbstractStrategy._deprecated_rewardLiquidationThreshold (32) + +unallocated (12) + +address: InitializableAbstractStrategy.harvesterAddress (20) + +address[]: InitializableAbstractStrategy.rewardTokenAddresses (32) + +int256[98]: InitializableAbstractStrategy._reserved (3136) + +uint256[50]: __gap (1600) + + + +1 + +address[]: assetsMapped <<Array>> +0xaaf4f58de99300cfadc4585755f376d5fa747d5bc561d5bd9d710de1f91bf42d + +offset + +0 + +type: variable (bytes) + +unallocated (12) + +address (20) + + + +3:19->1 + + + + + +2 + +address[]: rewardTokenAddresses <<Array>> +0x2da56674729343acc9933752c8c469a244252915242eb6d4c02d11ddd69164a1 + +offset + +0 + +type: variable (bytes) + +unallocated (12) + +address (20) + + + +3:24->2 + + + + + diff --git a/contracts/docs/generate.sh b/contracts/docs/generate.sh index 1299504db7..69ab22c21c 100644 --- a/contracts/docs/generate.sh +++ b/contracts/docs/generate.sh @@ -82,6 +82,11 @@ sol2uml .. -v -hv -hf -he -hs -hl -hi -b Generalized4626Strategy -o Generalized4 sol2uml .. -s -d 0 -b Generalized4626Strategy -o Generalized4626StrategySquashed.svg sol2uml storage .. -c Generalized4626Strategy -o Generalized4626StrategyStorage.svg --hideExpand ______gap,_reserved,__gap +sol2uml .. -v -hv -hf -he -hs -hl -hi -b NativeStakingSSVStrategy -o NativeStakingSSVStrategyHierarchy.svg +sol2uml .. -s -d 0 -b NativeStakingSSVStrategy -o NativeStakingSSVStrategySquashed.svg +sol2uml .. -s -d 0 -b FeeAccumulator -o FeeAccumulatorSquashed.svg +sol2uml storage .. -c NativeStakingSSVStrategy -o NativeStakingSSVStrategyStorage.svg --hideExpand __gap,______gap,_reserved + sol2uml .. -v -hv -hf -he -hs -hl -hi -b MorphoAaveStrategy -o MorphoAaveStrategyHierarchy.svg sol2uml .. -s -d 0 -b MorphoAaveStrategy -o MorphoAaveStrategySquashed.svg sol2uml storage .. -c MorphoAaveStrategy -o MorphoAaveStrategyStorage.svg --hideExpand ______gap,_reserved diff --git a/contracts/test/_fixture.js b/contracts/test/_fixture.js index a3c4b13836..f969368877 100644 --- a/contracts/test/_fixture.js +++ b/contracts/test/_fixture.js @@ -1422,7 +1422,7 @@ async function nativeStakingSSVStrategyFixture() { .setAssetDefaultStrategy(weth.address, nativeStakingSSVStrategy.address); } else { const { governorAddr } = await getNamedAccounts(); - const { oethVault, weth, nativeStakingSSVStrategy, strategist } = fixture; + const { oethVault, weth, nativeStakingSSVStrategy } = fixture; const sGovernor = await ethers.provider.getSigner(governorAddr); // Approve Strategy @@ -1454,10 +1454,6 @@ async function nativeStakingSSVStrategyFixture() { await nativeStakingSSVStrategy .connect(sGovernor) .setAccountingGovernor(governorAddr); - - await nativeStakingSSVStrategy - .connect(sGovernor) - .setStrategist(strategist.address); } return fixture; diff --git a/contracts/test/helpers.js b/contracts/test/helpers.js index 62c72dfbd3..ae8f1a05d5 100644 --- a/contracts/test/helpers.js +++ b/contracts/test/helpers.js @@ -428,7 +428,6 @@ const getAssetAddresses = async (deployments) => { SSV: addresses.mainnet.SSV, SSVNetwork: addresses.mainnet.SSVNetwork, beaconChainDepositContract: addresses.mainnet.beaconChainDepositContract, - }; } else { const addressMap = { @@ -476,7 +475,9 @@ const getAssetAddresses = async (deployments) => { BAL: (await deployments.get("MockBAL")).address, SSV: (await deployments.get("MockSSV")).address, SSVNetwork: (await deployments.get("MockSSVNetwork")).address, - beaconChainDepositContract: (await deployments.get("BeaconChainDepositContractMock")).address, + beaconChainDepositContract: ( + await deployments.get("BeaconChainDepositContractMock") + ).address, }; try { diff --git a/contracts/test/strategies/nativeSSVStaking.js b/contracts/test/strategies/nativeSSVStaking.js index 037ff17c8f..910a5d8ba0 100644 --- a/contracts/test/strategies/nativeSSVStaking.js +++ b/contracts/test/strategies/nativeSSVStaking.js @@ -186,16 +186,6 @@ describe("Unit test: Native SSV Staking Strategy", function () { ).to.be.revertedWith("Caller is not the Governor"); }); - it("Only governor can change the strategist", async () => { - const { nativeStakingSSVStrategy, strategist } = fixture; - - await expect( - nativeStakingSSVStrategy - .connect(strategist) - .setStrategist(strategist.address) - ).to.be.revertedWith("Caller is not the Governor"); - }); - it("Change the accounting governor", async () => { const { nativeStakingSSVStrategy, governor, strategist } = fixture; @@ -217,26 +207,6 @@ describe("Unit test: Native SSV Staking Strategy", function () { strategist.address ); }); - - it("Change the strategist", async () => { - const { nativeStakingSSVStrategy, governor, strategist } = fixture; - - const tx = await nativeStakingSSVStrategy - .connect(governor) - .setStrategist(governor.address); - - const events = (await tx.wait()).events || []; - const strategistAddressChanged = events.find( - (e) => e.event === "StrategistAddressChanged" - ); - - expect(strategistAddressChanged).to.not.be.undefined; - expect(strategistAddressChanged.event).to.equal( - "StrategistAddressChanged" - ); - expect(strategistAddressChanged.args[0]).to.equal(strategist.address); - expect(strategistAddressChanged.args[1]).to.equal(governor.address); - }); }); describe("Accounting", function () { @@ -345,7 +315,7 @@ describe("Unit test: Native SSV Staking Strategy", function () { } const WithdrawnEvent = events.find( - (e) => e.event === "AccuntingFullyWithdrawnValidator" + (e) => e.event === "AccountingFullyWithdrawnValidator" ); if (expectedValidatorsFullWithdrawals > 0) { expect(WithdrawnEvent).to.not.be.undefined; @@ -374,7 +344,7 @@ describe("Unit test: Native SSV Staking Strategy", function () { } const SlashEvent = events.find( - (e) => e.event === "AccuntingValidatorSlashed" + (e) => e.event === "AccountingValidatorSlashed" ); if (slashDetected) { expect(SlashEvent).to.not.be.undefined; @@ -567,7 +537,7 @@ describe("Unit test: Native SSV Staking Strategy", function () { const { nativeStakingSSVStrategy, governor, - strategist, + // strategist, oethHarvester, weth, josh, @@ -642,7 +612,7 @@ describe("Unit test: Native SSV Staking Strategy", function () { nativeStakingSSVStrategy, governor, strategist, - oethHarvester, + // oethHarvester, weth, josh, } = fixture; @@ -651,11 +621,11 @@ describe("Unit test: Native SSV Staking Strategy", function () { beaconChainRewardEth, wethFromDeposits, expectedEthSentToHarvester, - nrOfActiveDepositedValidators + nrOfActiveDepositedValidators, } = testCase; const feeAccumulatorAddress = await nativeStakingSSVStrategy.FEE_ACCUMULATOR_ADDRESS(); - const sHarvester = await impersonateAndFund(oethHarvester.address); + // const sHarvester = await impersonateAndFund(oethHarvester.address); // setup state if (beaconChainRewardEth.gt(BigNumber.from("0"))) { @@ -690,8 +660,14 @@ describe("Unit test: Native SSV Staking Strategy", function () { // run the accounting await nativeStakingSSVStrategy.connect(governor).doAccounting(); - expect(await nativeStakingSSVStrategy.checkBalance(weth.address)).to.equal( - expectedEthSentToHarvester.add(BigNumber.from(`${nrOfActiveDepositedValidators}`).mul(utils.parseEther("32"))) + expect( + await nativeStakingSSVStrategy.checkBalance(weth.address) + ).to.equal( + expectedEthSentToHarvester.add( + BigNumber.from(`${nrOfActiveDepositedValidators}`).mul( + utils.parseEther("32") + ) + ) ); }); } diff --git a/contracts/test/strategies/nativeSsvStaking.fork-test.js b/contracts/test/strategies/nativeSsvStaking.fork-test.js index f5d6b1512d..3fbd13a3c5 100644 --- a/contracts/test/strategies/nativeSsvStaking.fork-test.js +++ b/contracts/test/strategies/nativeSsvStaking.fork-test.js @@ -1,15 +1,11 @@ -const hre = require("hardhat"); const { expect } = require("chai"); -const { units, oethUnits, isCI } = require("../helpers"); const addresses = require("../../utils/addresses"); const { createFixtureLoader, nativeStakingSSVStrategyFixture, } = require("./../_fixture"); -const { impersonateAndFund } = require("../../utils/signers"); -const { setERC20TokenBalance } = require("../_fund"); const loadFixture = createFixtureLoader(nativeStakingSSVStrategyFixture); @@ -17,7 +13,7 @@ describe("ForkTest: Native SSV Staking Strategy", function () { this.timeout(0); // Retry up to 3 times on CI - this.retries(isCI ? 3 : 0); + // this.retries(isCI ? 3 : 0); let fixture; beforeEach(async () => { @@ -26,7 +22,7 @@ describe("ForkTest: Native SSV Staking Strategy", function () { describe("Initial setup", function () { it("Should verify the initial state", async () => { - const { weth, nativeStakingSSVStrategy } = fixture; + const { nativeStakingSSVStrategy } = fixture; await expect( await nativeStakingSSVStrategy.WETH_TOKEN_ADDRESS() ).to.equal(addresses.mainnet.WETH, "Incorrect WETH address set"); diff --git a/contracts/utils/addresses.js b/contracts/utils/addresses.js index adc918518c..36c557e3b1 100644 --- a/contracts/utils/addresses.js +++ b/contracts/utils/addresses.js @@ -243,7 +243,8 @@ addresses.mainnet.CurveCVXPool = "0xB576491F1E6e5E62f1d8F26062Ee822B40B0E0d4"; // SSV network addresses.mainnet.SSV = "0x9D65fF81a3c488d585bBfb0Bfe3c7707c7917f54"; addresses.mainnet.SSVNetwork = "0xDD9BC35aE942eF0cFa76930954a156B3fF30a4E1"; -addresses.mainnet.beaconChainDepositContract = "0x00000000219ab540356cbb839cbe05303d7705fa"; +addresses.mainnet.beaconChainDepositContract = + "0x00000000219ab540356cbb839cbe05303d7705fa"; // Arbitrum One addresses.arbitrumOne = {}; From 8a64dc8a8cf5d7dd9088ec9fdc99dd5e8501bf8e Mon Sep 17 00:00:00 2001 From: Nick Addison Date: Tue, 23 Apr 2024 23:02:03 +1000 Subject: [PATCH 016/273] Native staking changes (#2024) * Added OETH process diagram with functions calls for native staking * Native Staking Strategy now hold consensus rewards at ETH FeeAccumulator now holds execution rewards as ETH Removed WETH immutable from FeeAccumulator Converted custom errors back to require with string collect rewards now converts ETH to WETH at harvest checkBalance is now validators * 32 plus WETH balance from deposits Renamed beaconChainRewardsWETH to consensusRewards Fixed bug in stakeETH that was converting all WETH to ETH --- .../NativeStaking/FeeAccumulator.sol | 51 +- .../NativeStakingSSVStrategy.sol | 128 ++--- .../NativeStaking/ValidatorAccountant.sol | 91 ++-- .../NativeStaking/ValidatorRegistrator.sol | 97 ++-- contracts/deploy/001_core.js | 1 - contracts/deploy/091_native_ssv_staking.js | 1 - contracts/docs/FeeAccumulatorSquashed.svg | 53 +- .../docs/NativeStakingSSVStrategySquashed.svg | 269 +++++----- .../docs/NativeStakingSSVStrategyStorage.svg | 160 +++--- contracts/docs/plantuml/oethProcesses.png | Bin 0 -> 434884 bytes contracts/docs/plantuml/oethProcesses.puml | 279 +++++++++++ contracts/test/strategies/nativeSSVStaking.js | 464 +++++++++--------- 12 files changed, 887 insertions(+), 707 deletions(-) create mode 100644 contracts/docs/plantuml/oethProcesses.png create mode 100644 contracts/docs/plantuml/oethProcesses.puml diff --git a/contracts/contracts/strategies/NativeStaking/FeeAccumulator.sol b/contracts/contracts/strategies/NativeStaking/FeeAccumulator.sol index baa5e2bf52..00ee3e8bee 100644 --- a/contracts/contracts/strategies/NativeStaking/FeeAccumulator.sol +++ b/contracts/contracts/strategies/NativeStaking/FeeAccumulator.sol @@ -1,55 +1,40 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; +import { Address } from "@openzeppelin/contracts/utils/Address.sol"; + import { Governable } from "../../governance/Governable.sol"; import { IWETH9 } from "../../interfaces/IWETH9.sol"; /** * @title Fee Accumulator for Native Staking SSV Strategy - * @notice This contract is setup to receive fees from processing transactions on the beacon chain - * which includes priority fees and any MEV rewards. - * It does NOT include swept ETH from consensus rewards or withdrawals. + * @notice Receives execution rewards which includes tx fees and + * MEV rewards like tx priority and tx ordering. + * It does NOT include swept ETH from beacon chain consensus rewards or full validator withdrawals. * @author Origin Protocol Inc */ contract FeeAccumulator is Governable { - /// @notice The address the WETH is sent to on `collect` which is the Native Staking Strategy - address public immutable COLLECTOR; - /// @notice The address of the Wrapped ETH (WETH) token contract - address public immutable WETH_TOKEN_ADDRESS; - - error CallerNotCollector(address caller, address expectedCaller); - - // For future use - uint256[50] private __gap; + /// @notice The address of the Native Staking Strategy + address public immutable STRATEGY; /** - * @param _collector Address of the contract that collects the fees - * @param _weth Address of the Wrapped ETH (WETH) token contract + * @param _strategy Address of the Native Staking Strategy */ - constructor(address _collector, address _weth) { - COLLECTOR = _collector; - WETH_TOKEN_ADDRESS = _weth; + constructor(address _strategy) { + STRATEGY = _strategy; } /** - * @dev Asserts that the caller is the collector + * @notice sends all ETH in this FeeAccumulator contract to the Native Staking Strategy. + * @return eth The amount of execution rewards that were sent to the Native Staking Strategy */ - function _assertIsCollector() internal view { - if (msg.sender != COLLECTOR) { - revert CallerNotCollector(msg.sender, COLLECTOR); - } - } + function collect() external returns (uint256 eth) { + require(msg.sender == STRATEGY, "Caller is not the Strategy"); - /** - * @notice Converts ETH to WETH and sends the WETH to the collector - * @return weth The amount of WETH sent to the collector - */ - function collect() external returns (uint256 weth) { - _assertIsCollector(); - weth = address(this).balance; - if (weth > 0) { - IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: weth }(); - IWETH9(WETH_TOKEN_ADDRESS).transfer(COLLECTOR, weth); + eth = address(this).balance; + if (eth > 0) { + // Send the ETH to the Native Staking Strategy + Address.sendValue(payable(STRATEGY), eth); } } } diff --git a/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol b/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol index 7bbd0345bd..1c4f44f02d 100644 --- a/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol +++ b/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol @@ -38,13 +38,6 @@ contract NativeStakingSSVStrategy is // For future use uint256[50] private __gap; - error EmptyRecipient(); - error NotWeth(); - error InsufficientWethBalance( - uint256 requiredBalance, - uint256 availableBalance - ); - /// @param _baseConfig Base strategy config with platformAddress (ERC-4626 Vault contract), eg sfrxETH or sDAI, /// and vaultAddress (OToken Vault contract), eg VaultProxy or OETHVaultProxy /// @param _wethAddress Address of the Erc20 WETH Token contract @@ -88,73 +81,36 @@ contract NativeStakingSSVStrategy is ); } - /// @notice return the WETH balance on the contract that can be used to for beacon chain - /// staking - staking on the validators. Because WETH on this contract can be present as - /// a result of deposits and beacon chain rewards this function needs to return only WETH - /// that is present due to deposits. - function getWETHBalanceEligibleForStaking() - public - view - override - returns (uint256 _amount) - { - // if below amount results in a negative number there is a bug with accounting - _amount = - IWETH9(WETH_TOKEN_ADDRESS).balanceOf(address(this)) - - beaconChainRewardWETH; - } - - /// @notice Convert accumulated ETH to WETH and send to the Harvester. - /// Only callable by the Harvester. - function collectRewardTokens() - external - virtual - override - onlyHarvester - nonReentrant - { - // collect WETH from fee collector and wrap it into WETH - uint256 wethCollected = FeeAccumulator(FEE_ACCUMULATOR_ADDRESS) + /// @dev Convert accumulated ETH to WETH and send to the Harvester. + function _collectRewardTokens() internal override { + // collect ETH from execution rewards from the fee accumulator + uint256 executionRewards = FeeAccumulator(FEE_ACCUMULATOR_ADDRESS) .collect(); - /* add up the WETH collected from the fee accumulator to beaconChainRewardWETH - * so it can be sent to the harvester in one swoop in the "_collectRewardTokens" - * step. - */ - beaconChainRewardWETH += wethCollected; - _collectRewardTokens(); - } + // total ETH rewards to be harvested = execution rewards + consensus rewards + uint256 ethRewards = executionRewards + consensusRewards; - /// @dev Need to override this function since the strategy doesn't allow for all the WETH - /// to be collected. Some might be there as a result of deposit and is waiting for the Registrar - /// to be deposited to the validators. - function _collectRewardTokens() internal override { - uint256 rewardTokenCount = rewardTokenAddresses.length; - for (uint256 i = 0; i < rewardTokenCount; ++i) { - IERC20 rewardToken = IERC20(rewardTokenAddresses[i]); - uint256 balance = rewardToken.balanceOf(address(this)); - if (balance > 0) { - if (address(rewardToken) == WETH_TOKEN_ADDRESS) { - if (beaconChainRewardWETH > balance) { - revert InsufficientWethBalance( - beaconChainRewardWETH, - balance - ); - } + require( + address(this).balance >= ethRewards, + "insufficient eth balance" + ); + + if (ethRewards > 0) { + // reset the counter keeping track of beacon chain consensus rewards + consensusRewards = 0; - // only allow for the WETH that is part of beacon chain rewards to be harvested - balance = beaconChainRewardWETH; - // reset the counter keeping track of beacon chain WETH rewards - beaconChainRewardWETH = 0; - } + // Convert ETH rewards to WETH + IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: ethRewards }(); - emit RewardTokenCollected( - harvesterAddress, - address(rewardToken), - balance - ); - rewardToken.safeTransfer(harvesterAddress, balance); - } + emit RewardTokenCollected( + harvesterAddress, + WETH_TOKEN_ADDRESS, + ethRewards + ); + IERC20(WETH_TOKEN_ADDRESS).safeTransfer( + harvesterAddress, + ethRewards + ); } } @@ -218,9 +174,7 @@ contract NativeStakingSSVStrategy is uint256 _amount ) internal { require(_amount > 0, "Must withdraw something"); - if (_recipient == address(0)) { - revert EmptyRecipient(); - } + require(_recipient != address(0), "Must specify recipient"); emit Withdrawal(_asset, address(0), _amount); IERC20(_asset).safeTransfer(_recipient, _amount); @@ -239,7 +193,10 @@ contract NativeStakingSSVStrategy is function _abstractSetPToken(address _asset, address) internal override {} /// @notice Returns the total value of (W)ETH that is staked to the validators - /// and also present on the native staking and fee accumulator contracts. + /// and WETH deposits that are still to be staked. + /// This does not include ETH from consensus rewards sitting in this strategy + /// or ETH from MEV rewards in the FeeAccumulator. These rewards are harvested + /// and sent to the Dripper so will eventually be sent to the Vault as WETH. /// @param _asset Address of weth asset /// @return balance Total value of (W)ETH function checkBalance(address _asset) @@ -248,13 +205,14 @@ contract NativeStakingSSVStrategy is override returns (uint256 balance) { - if (_asset != WETH_TOKEN_ADDRESS) { - revert NotWeth(); - } + require(_asset == WETH_TOKEN_ADDRESS, "Unsupported asset"); - balance = activeDepositedValidators * 32 ether; - balance += beaconChainRewardWETH; - balance += FEE_ACCUMULATOR_ADDRESS.balance; + balance = + // add the ETH that has been staked in validators + activeDepositedValidators * + 32 ether + + // add the WETH in the strategy from deposits that are still to be staked + IERC20(WETH_TOKEN_ADDRESS).balanceOf(address(this)); } function pause() external onlyStrategist { @@ -293,4 +251,16 @@ contract NativeStakingSSVStrategy is cluster ); } + + /** + * @notice Only accept ETH from the FeeAccumulator + * @dev don't want to receive donations from anyone else as this will + * mess with the accounting of the consensus rewards and validator full withdrawals + */ + receive() external payable { + require( + msg.sender == FEE_ACCUMULATOR_ADDRESS, + "eth not sent from Fee Accumulator" + ); + } } diff --git a/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol b/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol index 8570e96f16..f6d919b4b7 100644 --- a/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol +++ b/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol @@ -6,9 +6,10 @@ import { ValidatorRegistrator } from "./ValidatorRegistrator.sol"; import { IVault } from "../../interfaces/IVault.sol"; import { IWETH9 } from "../../interfaces/IWETH9.sol"; -/// @title Accountant of the rewards Beacon Chain ETH -/// @notice This contract contains the logic to attribute the Beacon Chain swept ETH either to full -/// or partial withdrawals +/// @title Validator Accountant +/// @notice Attributes the ETH swept from beacon chain validators to this strategy contract +/// as either full or partial withdrawals. Partial withdrawals being consensus rewards. +/// Full withdrawals are from exited validators. /// @author Origin Protocol Inc abstract contract ValidatorAccountant is ValidatorRegistrator { /// @notice The maximum amount of ETH that can be staked by a validator @@ -17,16 +18,8 @@ abstract contract ValidatorAccountant is ValidatorRegistrator { /// @notice Address of the OETH Vault proxy contract address public immutable VAULT_ADDRESS; - /// @dev The WETH present on this contract will come from 2 sources: - /// - as a result of deposits from the VaultAdmin - /// - accounting function converting beaconChain rewards from ETH to WETH - /// - /// We need to be able to keep a separate accounting of the WETH so we understand how much we can pass oh to - /// the harvester as a consequence of rewards harvesting and how much registrator can pick up as a result of WETH - /// deposit into the strategy contract. - /// To achieve this the beacon chain rewards are accounted for using below variable, all other WETH is assumed to be - /// present as a result of a deposit. - uint256 public beaconChainRewardWETH = 0; + /// @notice Keeps track of the total consensus rewards swept from the beacon chain + uint256 public consensusRewards = 0; /// @notice start of fuse interval uint256 public fuseIntervalStart = 0; @@ -61,18 +54,12 @@ abstract contract ValidatorAccountant is ValidatorRegistrator { event AccountingManuallyFixed( uint256 oldActiveDepositedValidators, uint256 activeDepositedValidators, - uint256 oldBeaconChainRewardWETH, - uint256 beaconChainRewardWETH, + uint256 oldBeaconChainRewards, + uint256 beaconChainRewards, uint256 ethToWeth, uint256 wethToBeSentToVault ); - error UnexpectedEthAccountingInterval(uint256 errorneousEthAmount); - error ManualFixAccountingThresholdReached(); - error FuseIntervalValuesIncorrect(); - error NotPaused(); - error InsuffiscientETHbalance(); - /// @dev Throws if called by any account other than the Accounting Governor modifier onlyAccountingGovernor() { require( @@ -120,14 +107,13 @@ abstract contract ValidatorAccountant is ValidatorRegistrator { uint256 _fuseIntervalStart, uint256 _fuseIntervalEnd ) external onlyGovernor { - if ( - _fuseIntervalStart > _fuseIntervalEnd || - _fuseIntervalStart >= 32 ether || - _fuseIntervalEnd >= 32 ether || - _fuseIntervalEnd - _fuseIntervalStart < 4 ether - ) { - revert FuseIntervalValuesIncorrect(); - } + require( + _fuseIntervalStart < _fuseIntervalEnd && + _fuseIntervalStart < 32 ether && + _fuseIntervalEnd < 32 ether && + _fuseIntervalEnd - _fuseIntervalStart >= 4 ether, + "incorrect fuse interval" + ); emit FuseIntervalUpdated( fuseIntervalStart, @@ -157,12 +143,13 @@ abstract contract ValidatorAccountant is ValidatorRegistrator { onlyRegistrator returns (bool accountingValid) { - uint256 ethBalance = address(this).balance; + // Calculate all the new ETH that has been swept to the contract since the last accounting + uint256 newSweptETH = address(this).balance - consensusRewards; accountingValid = true; - // send the WETH that is from fully withdrawn validators to the Vault - if (ethBalance >= MAX_STAKE) { - uint256 fullyWithdrawnValidators = ethBalance / MAX_STAKE; + // send the ETH that is from fully withdrawn validators to the Vault + if (newSweptETH >= MAX_STAKE) { + uint256 fullyWithdrawnValidators = newSweptETH / MAX_STAKE; activeDepositedValidators -= fullyWithdrawnValidators; uint256 wethToVault = MAX_STAKE * fullyWithdrawnValidators; @@ -177,16 +164,13 @@ abstract contract ValidatorAccountant is ValidatorRegistrator { } uint256 ethRemaining = address(this).balance; - // should never happen - if (ethRemaining > 32 ether) { - revert UnexpectedEthAccountingInterval(ethRemaining); - } + // should be less than a whole validator stake + require(ethRemaining < 32 ether, "unexpected accounting"); // Beacon chain rewards swept (partial validator withdrawals) if (ethRemaining <= fuseIntervalStart) { - IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: ethRemaining }(); // solhint-disable-next-line reentrancy - beaconChainRewardWETH += ethRemaining; + consensusRewards += ethRemaining; emit AccountingBeaconChainRewards(ethRemaining); } // Beacon chain rewards swept but also a slashed validator fully exited @@ -213,7 +197,7 @@ abstract contract ValidatorAccountant is ValidatorRegistrator { /// @param _activeDepositedValidators the override value of activeDepositedValidators /// @param _ethToWeth the amount of ETH to be converted to WETH /// @param _wethToBeSentToVault the amount of WETH to be sent to the Vault - /// @param _beaconChainRewardWETH the override value for beaconChainRewardWETH + /// @param _consensusRewards the override value for consensusRewards /// @param _ethThresholdCheck maximum allowed ETH balance on the contract for the function to run /// @param _wethThresholdCheck maximum allowed WETH balance on the contract for the function to run /// the above 2 checks are done so transaction doesn't get front run and cause @@ -222,40 +206,37 @@ abstract contract ValidatorAccountant is ValidatorRegistrator { uint256 _activeDepositedValidators, uint256 _ethToWeth, uint256 _wethToBeSentToVault, - uint256 _beaconChainRewardWETH, + uint256 _consensusRewards, uint256 _ethThresholdCheck, uint256 _wethThresholdCheck ) external onlyAccountingGovernor { - if (!paused()) { - revert NotPaused(); - } + require(paused(), "not paused"); uint256 ethBalance = address(this).balance; uint256 wethBalance = IWETH9(WETH_TOKEN_ADDRESS).balanceOf( address(this) ); - if ( - ethBalance > _ethThresholdCheck || wethBalance > _wethThresholdCheck - ) { - revert ManualFixAccountingThresholdReached(); - } + require( + ethBalance <= _ethThresholdCheck && + wethBalance <= _wethThresholdCheck, + "over accounting threshold" + ); emit AccountingManuallyFixed( activeDepositedValidators, _activeDepositedValidators, - beaconChainRewardWETH, - _beaconChainRewardWETH, + consensusRewards, + _consensusRewards, _ethToWeth, _wethToBeSentToVault ); activeDepositedValidators = _activeDepositedValidators; - beaconChainRewardWETH = _beaconChainRewardWETH; + consensusRewards = _consensusRewards; if (_ethToWeth > 0) { - if (ethBalance < _ethToWeth) { - revert InsuffiscientETHbalance(); - } + require(_ethToWeth <= ethBalance, "insufficient ETH"); + IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: _ethToWeth }(); } if (_wethToBeSentToVault > 0) { diff --git a/contracts/contracts/strategies/NativeStaking/ValidatorRegistrator.sol b/contracts/contracts/strategies/NativeStaking/ValidatorRegistrator.sol index 1674b47730..27aaaf247c 100644 --- a/contracts/contracts/strategies/NativeStaking/ValidatorRegistrator.sol +++ b/contracts/contracts/strategies/NativeStaking/ValidatorRegistrator.sol @@ -51,9 +51,6 @@ abstract contract ValidatorRegistrator is Governable, Pausable { event SSVValidatorExitInitiated(bytes pubkey, uint64[] operatorIds); event SSVValidatorExitCompleted(bytes pubkey, uint64[] operatorIds); - error InsufficientWETH(uint256 wethBalance, uint256 requiredWethBalance); - error ValidatorInUnexpectedState(bytes pubkey, VALIDATOR_STATE state); - /// @dev Throws if called by any account other than the Registrator modifier onlyRegistrator() { require( @@ -82,14 +79,6 @@ abstract contract ValidatorRegistrator is Governable, Pausable { validatorRegistrator = _address; } - /// @notice return the WETH balance on the contract that can be used to for beacon chain - /// staking - staking on the validators - function getWETHBalanceEligibleForStaking() - public - view - virtual - returns (uint256 _amount); - /// @notice Stakes WETH to the node validators /// @param validators A list of validator data needed to stake. /// The `ValidatorStakeData` struct contains the pubkey, signature and depositDataRoot. @@ -99,32 +88,51 @@ abstract contract ValidatorRegistrator is Governable, Pausable { onlyRegistrator whenNotPaused { - uint256 requiredWETH = validators.length * 32 ether; - uint256 wethBalance = getWETHBalanceEligibleForStaking(); - if (wethBalance < requiredWETH) { - revert InsufficientWETH(wethBalance, requiredWETH); - } + uint256 requiredETH = validators.length * 32 ether; + + // Check there is enough WETH from the deposits sitting in this strategy contract + require( + requiredETH <= IWETH9(WETH_TOKEN_ADDRESS).balanceOf(address(this)), + "insufficient WETH" + ); - // Convert WETH asset to native ETH - IWETH9(WETH_TOKEN_ADDRESS).withdraw(wethBalance); + // Convert required ETH from WETH + IWETH9(WETH_TOKEN_ADDRESS).withdraw(requiredETH); // For each validator for (uint256 i = 0; i < validators.length; ) { bytes32 pubkeyHash = keccak256(validators[i].pubkey); VALIDATOR_STATE currentState = validatorsStates[pubkeyHash]; - if (currentState != VALIDATOR_STATE.REGISTERED) { - revert ValidatorInUnexpectedState( - validators[i].pubkey, - currentState - ); - } + require( + currentState == VALIDATOR_STATE.REGISTERED, + "Validator not registered" + ); - _stakeEth( + /* 0x01 to indicate that withdrawal credentials will contain an EOA address that the sweeping function + * can sweep funds to. + * bytes11(0) to fill up the required zeros + * remaining bytes20 are for the address + */ + bytes memory withdrawal_credentials = abi.encodePacked( + bytes1(0x01), + bytes11(0), + address(this) + ); + IDepositContract(BEACON_CHAIN_DEPOSIT_CONTRACT).deposit( validators[i].pubkey, + withdrawal_credentials, validators[i].signature, validators[i].depositDataRoot ); + + activeDepositedValidators += 1; + emit ETHStaked( + validators[i].pubkey, + 32 ether, + withdrawal_credentials + ); + validatorsStates[pubkeyHash] = VALIDATOR_STATE.STAKED; unchecked { @@ -133,34 +141,6 @@ abstract contract ValidatorRegistrator is Governable, Pausable { } } - /// @dev Deposit WETH to the beacon chain deposit contract. - /// The public functions that call this internal function are responsible for access control. - function _stakeEth( - bytes calldata pubkey, - bytes calldata signature, - bytes32 depositDataRoot - ) internal { - /* 0x01 to indicate that withdrawal credentials will contain an EOA address that the sweeping function - * can sweep funds to. - * bytes11(0) to fill up the required zeros - * remaining bytes20 are for the address - */ - bytes memory withdrawal_credentials = abi.encodePacked( - bytes1(0x01), - bytes11(0), - address(this) - ); - IDepositContract(BEACON_CHAIN_DEPOSIT_CONTRACT).deposit( - pubkey, - withdrawal_credentials, - signature, - depositDataRoot - ); - - activeDepositedValidators += 1; - emit ETHStaked(pubkey, 32 ether, withdrawal_credentials); - } - /// @notice Registers a new validator in the SSV Cluster. /// Only the registrator can call this function. function registerSsvValidator( @@ -189,9 +169,7 @@ abstract contract ValidatorRegistrator is Governable, Pausable { uint64[] calldata operatorIds ) external onlyRegistrator whenNotPaused { VALIDATOR_STATE currentState = validatorsStates[keccak256(publicKey)]; - if (currentState != VALIDATOR_STATE.STAKED) { - revert ValidatorInUnexpectedState(publicKey, currentState); - } + require(currentState == VALIDATOR_STATE.STAKED, "Validator not staked"); ISSVNetwork(SSV_NETWORK_ADDRESS).exitValidator(publicKey, operatorIds); emit SSVValidatorExitInitiated(publicKey, operatorIds); @@ -209,9 +187,10 @@ abstract contract ValidatorRegistrator is Governable, Pausable { Cluster calldata cluster ) external onlyRegistrator whenNotPaused { VALIDATOR_STATE currentState = validatorsStates[keccak256(publicKey)]; - if (currentState != VALIDATOR_STATE.EXITING) { - revert ValidatorInUnexpectedState(publicKey, currentState); - } + require( + currentState == VALIDATOR_STATE.EXITING, + "Validator not exiting" + ); ISSVNetwork(SSV_NETWORK_ADDRESS).removeValidator( publicKey, diff --git a/contracts/deploy/001_core.js b/contracts/deploy/001_core.js index b3cb95cea2..6dcf9545d8 100644 --- a/contracts/deploy/001_core.js +++ b/contracts/deploy/001_core.js @@ -807,7 +807,6 @@ const deployNativeStakingSSVStrategy = async () => { log("Deploy fee accumulator implementation"); const dFeeAccumulator = await deployWithConfirmation("FeeAccumulator", [ cNativeStakingSSVStrategyProxy.address, // _collector - assetAddresses.WETH, // _weth ]); const cFeeAccumulator = await ethers.getContractAt( "FeeAccumulator", diff --git a/contracts/deploy/091_native_ssv_staking.js b/contracts/deploy/091_native_ssv_staking.js index 82f14f4bf7..36e0c3393a 100644 --- a/contracts/deploy/091_native_ssv_staking.js +++ b/contracts/deploy/091_native_ssv_staking.js @@ -96,7 +96,6 @@ module.exports = deploymentWithGovernanceProposal( // 5. Deploy the new fee accumulator implementation const dFeeAccumulator = await deployWithConfirmation("FeeAccumulator", [ cStrategyProxy.address, // _collector - addresses.mainnet.WETH, // _weth ]); const cFeeAccumulator = await ethers.getContractAt( "FeeAccumulator", diff --git a/contracts/docs/FeeAccumulatorSquashed.svg b/contracts/docs/FeeAccumulatorSquashed.svg index 3c2c1558ab..c41be6097f 100644 --- a/contracts/docs/FeeAccumulatorSquashed.svg +++ b/contracts/docs/FeeAccumulatorSquashed.svg @@ -4,40 +4,37 @@ - - + + UmlClassDiagram - + 278 - -FeeAccumulator -../contracts/strategies/NativeStaking/FeeAccumulator.sol - -Private: -   governorPosition: bytes32 <<Governable>> -   pendingGovernorPosition: bytes32 <<Governable>> -   reentryStatusPosition: bytes32 <<Governable>> -   __gap: uint256[50] <<FeeAccumulator>> -Public: -   _NOT_ENTERED: uint256 <<Governable>> -   _ENTERED: uint256 <<Governable>> -   COLLECTOR: address <<FeeAccumulator>> -   WETH_TOKEN_ADDRESS: address <<FeeAccumulator>> - -Internal: -    _governor(): (governorOut: address) <<Governable>> -    _pendingGovernor(): (pendingGovernor: address) <<Governable>> -    _setGovernor(newGovernor: address) <<Governable>> -    _setPendingGovernor(newGovernor: address) <<Governable>> -    _changeGovernor(_newGovernor: address) <<Governable>> -    _assertIsCollector() <<FeeAccumulator>> + +FeeAccumulator +../contracts/strategies/NativeStaking/FeeAccumulator.sol + +Private: +   governorPosition: bytes32 <<Governable>> +   pendingGovernorPosition: bytes32 <<Governable>> +   reentryStatusPosition: bytes32 <<Governable>> +Public: +   _NOT_ENTERED: uint256 <<Governable>> +   _ENTERED: uint256 <<Governable>> +   STRATEGY: address <<FeeAccumulator>> + +Internal: +    _governor(): (governorOut: address) <<Governable>> +    _pendingGovernor(): (pendingGovernor: address) <<Governable>> +    _setGovernor(newGovernor: address) <<Governable>> +    _setPendingGovernor(newGovernor: address) <<Governable>> +    _changeGovernor(_newGovernor: address) <<Governable>> External:    transferGovernance(_newGovernor: address) <<onlyGovernor>> <<Governable>>    claimGovernance() <<Governable>> -    collect(): (weth: uint256) <<FeeAccumulator>> +    collect(): (eth: uint256) <<FeeAccumulator>> Public:    <<event>> PendingGovernorshipTransfer(previousGovernor: address, newGovernor: address) <<Governable>>    <<event>> GovernorshipTransferred(previousGovernor: address, newGovernor: address) <<Governable>> @@ -46,7 +43,7 @@    constructor() <<Governable>>    governor(): address <<Governable>>    isGovernor(): bool <<Governable>> -    constructor(_collector: address, _weth: address) <<FeeAccumulator>> +    constructor(_strategy: address) <<FeeAccumulator>> diff --git a/contracts/docs/NativeStakingSSVStrategySquashed.svg b/contracts/docs/NativeStakingSSVStrategySquashed.svg index 838bee6efe..a12c2db559 100644 --- a/contracts/docs/NativeStakingSSVStrategySquashed.svg +++ b/contracts/docs/NativeStakingSSVStrategySquashed.svg @@ -4,146 +4,143 @@ - - + + UmlClassDiagram - + 280 - -NativeStakingSSVStrategy -../contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol - -Private: -   governorPosition: bytes32 <<Governable>> -   pendingGovernorPosition: bytes32 <<Governable>> -   reentryStatusPosition: bytes32 <<Governable>> -   _paused: bool <<Pausable>> -   __gap: uint256[50] <<ValidatorRegistrator>> -   __gap: uint256[50] <<ValidatorAccountant>> -   initialized: bool <<Initializable>> -   initializing: bool <<Initializable>> -   ______gap: uint256[50] <<Initializable>> -   _deprecated_platformAddress: address <<InitializableAbstractStrategy>> -   _deprecated_vaultAddress: address <<InitializableAbstractStrategy>> -   _deprecated_rewardTokenAddress: address <<InitializableAbstractStrategy>> -   _deprecated_rewardLiquidationThreshold: uint256 <<InitializableAbstractStrategy>> -   _reserved: int256[98] <<InitializableAbstractStrategy>> -   __gap: uint256[50] <<NativeStakingSSVStrategy>> -Internal: -   assetsMapped: address[] <<InitializableAbstractStrategy>> -Public: -   _NOT_ENTERED: uint256 <<Governable>> -   _ENTERED: uint256 <<Governable>> -   WETH_TOKEN_ADDRESS: address <<ValidatorRegistrator>> -   BEACON_CHAIN_DEPOSIT_CONTRACT: address <<ValidatorRegistrator>> -   SSV_NETWORK_ADDRESS: address <<ValidatorRegistrator>> -   validatorRegistrator: address <<ValidatorRegistrator>> -   activeDepositedValidators: uint256 <<ValidatorRegistrator>> -   validatorsStates: mapping(bytes32=>VALIDATOR_STATE) <<ValidatorRegistrator>> -   VAULT_ADDRESS: address <<ValidatorAccountant>> -   beaconChainRewardWETH: uint256 <<ValidatorAccountant>> -   fuseIntervalStart: uint256 <<ValidatorAccountant>> -   fuseIntervalEnd: uint256 <<ValidatorAccountant>> -   accountingGovernor: address <<ValidatorAccountant>> -   strategist: address <<ValidatorAccountant>> -   platformAddress: address <<InitializableAbstractStrategy>> -   vaultAddress: address <<InitializableAbstractStrategy>> -   assetToPToken: mapping(address=>address) <<InitializableAbstractStrategy>> -   harvesterAddress: address <<InitializableAbstractStrategy>> -   rewardTokenAddresses: address[] <<InitializableAbstractStrategy>> -   SSV_TOKEN_ADDRESS: address <<NativeStakingSSVStrategy>> -   FEE_ACCUMULATOR_ADDRESS: address <<NativeStakingSSVStrategy>> - -Internal: -    _governor(): (governorOut: address) <<Governable>> -    _pendingGovernor(): (pendingGovernor: address) <<Governable>> -    _setGovernor(newGovernor: address) <<Governable>> -    _setPendingGovernor(newGovernor: address) <<Governable>> -    _changeGovernor(_newGovernor: address) <<Governable>> -    _msgSender(): address <<Context>> -    _msgData(): bytes <<Context>> -    _pause() <<whenNotPaused>> <<Pausable>> -    _unpause() <<whenPaused>> <<Pausable>> -    _stakeEth(pubkey: bytes, signature: bytes, depositDataRoot: bytes32) <<ValidatorRegistrator>> -    _initialize(_rewardTokenAddresses: address[], _assets: address[], _pTokens: address[]) <<InitializableAbstractStrategy>> -    _collectRewardTokens() <<NativeStakingSSVStrategy>> -    _setPTokenAddress(_asset: address, _pToken: address) <<InitializableAbstractStrategy>> -    _abstractSetPToken(_asset: address, address) <<NativeStakingSSVStrategy>> -    _deposit(_asset: address, _amount: uint256) <<NativeStakingSSVStrategy>> -    _withdraw(_recipient: address, _asset: address, _amount: uint256) <<NativeStakingSSVStrategy>> -External: -    transferGovernance(_newGovernor: address) <<onlyGovernor>> <<Governable>> -    claimGovernance() <<Governable>> -    setRegistratorAddress(_address: address) <<onlyGovernor>> <<ValidatorRegistrator>> -    stakeEth(validators: ValidatorStakeData[]) <<onlyRegistrator, whenNotPaused>> <<ValidatorRegistrator>> -    registerSsvValidator(publicKey: bytes, operatorIds: uint64[], sharesData: bytes, amount: uint256, cluster: Cluster) <<onlyRegistrator, whenNotPaused>> <<ValidatorRegistrator>> -    exitSsvValidator(publicKey: bytes, operatorIds: uint64[]) <<onlyRegistrator, whenNotPaused>> <<ValidatorRegistrator>> -    removeSsvValidator(publicKey: bytes, operatorIds: uint64[], cluster: Cluster) <<onlyRegistrator, whenNotPaused>> <<ValidatorRegistrator>> -    setAccountingGovernor(_address: address) <<onlyGovernor>> <<ValidatorAccountant>> -    setStrategist(_address: address) <<onlyGovernor>> <<ValidatorAccountant>> -    setFuseInterval(_fuseIntervalStart: uint256, _fuseIntervalEnd: uint256) <<onlyGovernor>> <<ValidatorAccountant>> -    doAccounting(): (accountingValid: bool) <<onlyRegistrator>> <<ValidatorAccountant>> -    manuallyFixAccounting(_activeDepositedValidators: uint256, _ethToWeth: uint256, _wethToBeSentToVault: uint256, _beaconChainRewardWETH: uint256, _ethThresholdCheck: uint256, _wethThresholdCheck: uint256) <<onlyAccountingGovernor>> <<ValidatorAccountant>> -    collectRewardTokens() <<onlyHarvester, nonReentrant>> <<NativeStakingSSVStrategy>> -    setRewardTokenAddresses(_rewardTokenAddresses: address[]) <<onlyGovernor>> <<InitializableAbstractStrategy>> -    getRewardTokenAddresses(): address[] <<InitializableAbstractStrategy>> -    setPTokenAddress(_asset: address, _pToken: address) <<onlyGovernor>> <<InitializableAbstractStrategy>> -    removePToken(_assetIndex: uint256) <<onlyGovernor>> <<InitializableAbstractStrategy>> -    setHarvesterAddress(_harvesterAddress: address) <<onlyGovernor>> <<InitializableAbstractStrategy>> -    safeApproveAllTokens() <<NativeStakingSSVStrategy>> -    deposit(_asset: address, _amount: uint256) <<onlyVault, nonReentrant>> <<NativeStakingSSVStrategy>> -    depositAll() <<onlyVault, nonReentrant>> <<NativeStakingSSVStrategy>> -    withdraw(_recipient: address, _asset: address, _amount: uint256) <<onlyVault, nonReentrant>> <<NativeStakingSSVStrategy>> -    withdrawAll() <<onlyVaultOrGovernor, nonReentrant>> <<NativeStakingSSVStrategy>> -    checkBalance(_asset: address): (balance: uint256) <<NativeStakingSSVStrategy>> -    initialize(_rewardTokenAddresses: address[], _assets: address[], _pTokens: address[]) <<onlyGovernor, initializer>> <<NativeStakingSSVStrategy>> -    pause() <<onlyStrategist>> <<NativeStakingSSVStrategy>> -    depositSSV(operatorIds: uint64[], amount: uint256, cluster: Cluster) <<onlyStrategist>> <<NativeStakingSSVStrategy>> -Public: -    <<event>> PendingGovernorshipTransfer(previousGovernor: address, newGovernor: address) <<Governable>> -    <<event>> GovernorshipTransferred(previousGovernor: address, newGovernor: address) <<Governable>> -    <<event>> Paused(account: address) <<Pausable>> -    <<event>> Unpaused(account: address) <<Pausable>> -    <<event>> RegistratorAddressChanged(oldAddress: address, newAddress: address) <<ValidatorRegistrator>> -    <<event>> ETHStaked(pubkey: bytes, amount: uint256, withdrawal_credentials: bytes) <<ValidatorRegistrator>> -    <<event>> SSVValidatorRegistered(pubkey: bytes, operatorIds: uint64[]) <<ValidatorRegistrator>> -    <<event>> SSVValidatorExitInitiated(pubkey: bytes, operatorIds: uint64[]) <<ValidatorRegistrator>> -    <<event>> SSVValidatorExitCompleted(pubkey: bytes, operatorIds: uint64[]) <<ValidatorRegistrator>> -    <<event>> FuseIntervalUpdated(oldStart: uint256, oldEnd: uint256, start: uint256, end: uint256) <<ValidatorAccountant>> -    <<event>> AccuntingFullyWithdrawnValidator(noOfValidators: uint256, remainingValidators: uint256, wethSentToVault: uint256) <<ValidatorAccountant>> -    <<event>> AccuntingValidatorSlashed(remainingValidators: uint256, wethSentToVault: uint256) <<ValidatorAccountant>> -    <<event>> AccountingGovernorAddressChanged(oldAddress: address, newAddress: address) <<ValidatorAccountant>> -    <<event>> AccountingBeaconChainRewards(amount: uint256) <<ValidatorAccountant>> -    <<event>> StrategistAddressChanged(oldStrategist: address, newStrategist: address) <<ValidatorAccountant>> -    <<event>> AccountingManuallyFixed(oldActiveDepositedValidators: uint256, activeDepositedValidators: uint256, oldBeaconChainRewardWETH: uint256, beaconChainRewardWETH: uint256, ethToWeth: uint256, wethToBeSentToVault: uint256) <<ValidatorAccountant>> -    <<event>> PTokenAdded(_asset: address, _pToken: address) <<InitializableAbstractStrategy>> -    <<event>> PTokenRemoved(_asset: address, _pToken: address) <<InitializableAbstractStrategy>> -    <<event>> Deposit(_asset: address, _pToken: address, _amount: uint256) <<InitializableAbstractStrategy>> -    <<event>> Withdrawal(_asset: address, _pToken: address, _amount: uint256) <<InitializableAbstractStrategy>> -    <<event>> RewardTokenCollected(recipient: address, rewardToken: address, amount: uint256) <<InitializableAbstractStrategy>> -    <<event>> RewardTokenAddressesUpdated(_oldAddresses: address[], _newAddresses: address[]) <<InitializableAbstractStrategy>> -    <<event>> HarvesterAddressesUpdated(_oldHarvesterAddress: address, _newHarvesterAddress: address) <<InitializableAbstractStrategy>> -    <<modifier>> onlyGovernor() <<Governable>> -    <<modifier>> nonReentrant() <<Governable>> -    <<modifier>> whenNotPaused() <<Pausable>> -    <<modifier>> whenPaused() <<Pausable>> -    <<modifier>> onlyRegistrator() <<ValidatorRegistrator>> -    <<modifier>> onlyAccountingGovernor() <<ValidatorAccountant>> -    <<modifier>> onlyStrategist() <<ValidatorAccountant>> -    <<modifier>> initializer() <<Initializable>> -    <<modifier>> onlyVault() <<InitializableAbstractStrategy>> -    <<modifier>> onlyHarvester() <<InitializableAbstractStrategy>> -    <<modifier>> onlyVaultOrGovernor() <<InitializableAbstractStrategy>> -    <<modifier>> onlyVaultOrGovernorOrStrategist() <<InitializableAbstractStrategy>> -    constructor() <<Pausable>> -    governor(): address <<Governable>> -    isGovernor(): bool <<Governable>> -    paused(): bool <<Pausable>> -    constructor(_wethAddress: address, _beaconChainDepositContract: address, _ssvNetwork: address) <<ValidatorRegistrator>> -    getWETHBalanceEligibleForStaking(): (_amount: uint256) <<NativeStakingSSVStrategy>> + +NativeStakingSSVStrategy +../contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol + +Private: +   governorPosition: bytes32 <<Governable>> +   pendingGovernorPosition: bytes32 <<Governable>> +   reentryStatusPosition: bytes32 <<Governable>> +   _paused: bool <<Pausable>> +   __gap: uint256[50] <<ValidatorRegistrator>> +   __gap: uint256[50] <<ValidatorAccountant>> +   initialized: bool <<Initializable>> +   initializing: bool <<Initializable>> +   ______gap: uint256[50] <<Initializable>> +   _deprecated_platformAddress: address <<InitializableAbstractStrategy>> +   _deprecated_vaultAddress: address <<InitializableAbstractStrategy>> +   _deprecated_rewardTokenAddress: address <<InitializableAbstractStrategy>> +   _deprecated_rewardLiquidationThreshold: uint256 <<InitializableAbstractStrategy>> +   _reserved: int256[98] <<InitializableAbstractStrategy>> +   __gap: uint256[50] <<NativeStakingSSVStrategy>> +Internal: +   assetsMapped: address[] <<InitializableAbstractStrategy>> +Public: +   _NOT_ENTERED: uint256 <<Governable>> +   _ENTERED: uint256 <<Governable>> +   WETH_TOKEN_ADDRESS: address <<ValidatorRegistrator>> +   BEACON_CHAIN_DEPOSIT_CONTRACT: address <<ValidatorRegistrator>> +   SSV_NETWORK_ADDRESS: address <<ValidatorRegistrator>> +   validatorRegistrator: address <<ValidatorRegistrator>> +   activeDepositedValidators: uint256 <<ValidatorRegistrator>> +   validatorsStates: mapping(bytes32=>VALIDATOR_STATE) <<ValidatorRegistrator>> +   MAX_STAKE: uint256 <<ValidatorAccountant>> +   VAULT_ADDRESS: address <<ValidatorAccountant>> +   consensusRewards: uint256 <<ValidatorAccountant>> +   fuseIntervalStart: uint256 <<ValidatorAccountant>> +   fuseIntervalEnd: uint256 <<ValidatorAccountant>> +   accountingGovernor: address <<ValidatorAccountant>> +   platformAddress: address <<InitializableAbstractStrategy>> +   vaultAddress: address <<InitializableAbstractStrategy>> +   assetToPToken: mapping(address=>address) <<InitializableAbstractStrategy>> +   harvesterAddress: address <<InitializableAbstractStrategy>> +   rewardTokenAddresses: address[] <<InitializableAbstractStrategy>> +   SSV_TOKEN_ADDRESS: address <<NativeStakingSSVStrategy>> +   FEE_ACCUMULATOR_ADDRESS: address <<NativeStakingSSVStrategy>> + +Internal: +    _governor(): (governorOut: address) <<Governable>> +    _pendingGovernor(): (pendingGovernor: address) <<Governable>> +    _setGovernor(newGovernor: address) <<Governable>> +    _setPendingGovernor(newGovernor: address) <<Governable>> +    _changeGovernor(_newGovernor: address) <<Governable>> +    _msgSender(): address <<Context>> +    _msgData(): bytes <<Context>> +    _pause() <<whenNotPaused>> <<Pausable>> +    _unpause() <<whenPaused>> <<Pausable>> +    _initialize(_rewardTokenAddresses: address[], _assets: address[], _pTokens: address[]) <<InitializableAbstractStrategy>> +    _collectRewardTokens() <<NativeStakingSSVStrategy>> +    _setPTokenAddress(_asset: address, _pToken: address) <<InitializableAbstractStrategy>> +    _abstractSetPToken(_asset: address, address) <<NativeStakingSSVStrategy>> +    _deposit(_asset: address, _amount: uint256) <<NativeStakingSSVStrategy>> +    _withdraw(_recipient: address, _asset: address, _amount: uint256) <<NativeStakingSSVStrategy>> +External: +    <<payable>> null() <<NativeStakingSSVStrategy>> +    transferGovernance(_newGovernor: address) <<onlyGovernor>> <<Governable>> +    claimGovernance() <<Governable>> +    setRegistratorAddress(_address: address) <<onlyGovernor>> <<ValidatorRegistrator>> +    stakeEth(validators: ValidatorStakeData[]) <<onlyRegistrator, whenNotPaused>> <<ValidatorRegistrator>> +    registerSsvValidator(publicKey: bytes, operatorIds: uint64[], sharesData: bytes, amount: uint256, cluster: Cluster) <<onlyRegistrator, whenNotPaused>> <<ValidatorRegistrator>> +    exitSsvValidator(publicKey: bytes, operatorIds: uint64[]) <<onlyRegistrator, whenNotPaused>> <<ValidatorRegistrator>> +    removeSsvValidator(publicKey: bytes, operatorIds: uint64[], cluster: Cluster) <<onlyRegistrator, whenNotPaused>> <<ValidatorRegistrator>> +    setAccountingGovernor(_address: address) <<onlyGovernor>> <<ValidatorAccountant>> +    setFuseInterval(_fuseIntervalStart: uint256, _fuseIntervalEnd: uint256) <<onlyGovernor>> <<ValidatorAccountant>> +    doAccounting(): (accountingValid: bool) <<onlyRegistrator>> <<ValidatorAccountant>> +    manuallyFixAccounting(_activeDepositedValidators: uint256, _ethToWeth: uint256, _wethToBeSentToVault: uint256, _consensusRewards: uint256, _ethThresholdCheck: uint256, _wethThresholdCheck: uint256) <<onlyAccountingGovernor>> <<ValidatorAccountant>> +    collectRewardTokens() <<onlyHarvester, nonReentrant>> <<InitializableAbstractStrategy>> +    setRewardTokenAddresses(_rewardTokenAddresses: address[]) <<onlyGovernor>> <<InitializableAbstractStrategy>> +    getRewardTokenAddresses(): address[] <<InitializableAbstractStrategy>> +    setPTokenAddress(_asset: address, _pToken: address) <<onlyGovernor>> <<InitializableAbstractStrategy>> +    removePToken(_assetIndex: uint256) <<onlyGovernor>> <<InitializableAbstractStrategy>> +    setHarvesterAddress(_harvesterAddress: address) <<onlyGovernor>> <<InitializableAbstractStrategy>> +    safeApproveAllTokens() <<NativeStakingSSVStrategy>> +    deposit(_asset: address, _amount: uint256) <<onlyVault, nonReentrant>> <<NativeStakingSSVStrategy>> +    depositAll() <<onlyVault, nonReentrant>> <<NativeStakingSSVStrategy>> +    withdraw(_recipient: address, _asset: address, _amount: uint256) <<onlyVault, nonReentrant>> <<NativeStakingSSVStrategy>> +    withdrawAll() <<onlyVaultOrGovernor, nonReentrant>> <<NativeStakingSSVStrategy>> +    checkBalance(_asset: address): (balance: uint256) <<NativeStakingSSVStrategy>> +    initialize(_rewardTokenAddresses: address[], _assets: address[], _pTokens: address[]) <<onlyGovernor, initializer>> <<NativeStakingSSVStrategy>> +    pause() <<onlyStrategist>> <<NativeStakingSSVStrategy>> +    depositSSV(operatorIds: uint64[], amount: uint256, cluster: Cluster) <<onlyStrategist>> <<NativeStakingSSVStrategy>> +Public: +    <<event>> PendingGovernorshipTransfer(previousGovernor: address, newGovernor: address) <<Governable>> +    <<event>> GovernorshipTransferred(previousGovernor: address, newGovernor: address) <<Governable>> +    <<event>> Paused(account: address) <<Pausable>> +    <<event>> Unpaused(account: address) <<Pausable>> +    <<event>> RegistratorAddressChanged(oldAddress: address, newAddress: address) <<ValidatorRegistrator>> +    <<event>> ETHStaked(pubkey: bytes, amount: uint256, withdrawal_credentials: bytes) <<ValidatorRegistrator>> +    <<event>> SSVValidatorRegistered(pubkey: bytes, operatorIds: uint64[]) <<ValidatorRegistrator>> +    <<event>> SSVValidatorExitInitiated(pubkey: bytes, operatorIds: uint64[]) <<ValidatorRegistrator>> +    <<event>> SSVValidatorExitCompleted(pubkey: bytes, operatorIds: uint64[]) <<ValidatorRegistrator>> +    <<event>> FuseIntervalUpdated(oldStart: uint256, oldEnd: uint256, start: uint256, end: uint256) <<ValidatorAccountant>> +    <<event>> AccountingFullyWithdrawnValidator(noOfValidators: uint256, remainingValidators: uint256, wethSentToVault: uint256) <<ValidatorAccountant>> +    <<event>> AccountingValidatorSlashed(remainingValidators: uint256, wethSentToVault: uint256) <<ValidatorAccountant>> +    <<event>> AccountingGovernorAddressChanged(oldAddress: address, newAddress: address) <<ValidatorAccountant>> +    <<event>> AccountingBeaconChainRewards(amount: uint256) <<ValidatorAccountant>> +    <<event>> AccountingManuallyFixed(oldActiveDepositedValidators: uint256, activeDepositedValidators: uint256, oldBeaconChainRewards: uint256, beaconChainRewards: uint256, ethToWeth: uint256, wethToBeSentToVault: uint256) <<ValidatorAccountant>> +    <<event>> PTokenAdded(_asset: address, _pToken: address) <<InitializableAbstractStrategy>> +    <<event>> PTokenRemoved(_asset: address, _pToken: address) <<InitializableAbstractStrategy>> +    <<event>> Deposit(_asset: address, _pToken: address, _amount: uint256) <<InitializableAbstractStrategy>> +    <<event>> Withdrawal(_asset: address, _pToken: address, _amount: uint256) <<InitializableAbstractStrategy>> +    <<event>> RewardTokenCollected(recipient: address, rewardToken: address, amount: uint256) <<InitializableAbstractStrategy>> +    <<event>> RewardTokenAddressesUpdated(_oldAddresses: address[], _newAddresses: address[]) <<InitializableAbstractStrategy>> +    <<event>> HarvesterAddressesUpdated(_oldHarvesterAddress: address, _newHarvesterAddress: address) <<InitializableAbstractStrategy>> +    <<modifier>> onlyGovernor() <<Governable>> +    <<modifier>> nonReentrant() <<Governable>> +    <<modifier>> whenNotPaused() <<Pausable>> +    <<modifier>> whenPaused() <<Pausable>> +    <<modifier>> onlyRegistrator() <<ValidatorRegistrator>> +    <<modifier>> onlyAccountingGovernor() <<ValidatorAccountant>> +    <<modifier>> onlyStrategist() <<ValidatorAccountant>> +    <<modifier>> initializer() <<Initializable>> +    <<modifier>> onlyVault() <<InitializableAbstractStrategy>> +    <<modifier>> onlyHarvester() <<InitializableAbstractStrategy>> +    <<modifier>> onlyVaultOrGovernor() <<InitializableAbstractStrategy>> +    <<modifier>> onlyVaultOrGovernorOrStrategist() <<InitializableAbstractStrategy>> +    constructor() <<Pausable>> +    governor(): address <<Governable>> +    isGovernor(): bool <<Governable>> +    paused(): bool <<Pausable>> +    constructor(_wethAddress: address, _beaconChainDepositContract: address, _ssvNetwork: address) <<ValidatorRegistrator>>    constructor(_wethAddress: address, _vaultAddress: address, _beaconChainDepositContract: address, _ssvNetwork: address) <<ValidatorAccountant>>    constructor(_config: BaseStrategyConfig) <<InitializableAbstractStrategy>>    transferToken(_asset: address, _amount: uint256) <<onlyGovernor>> <<InitializableAbstractStrategy>> diff --git a/contracts/docs/NativeStakingSSVStrategyStorage.svg b/contracts/docs/NativeStakingSSVStrategyStorage.svg index 41964933b0..058cea8538 100644 --- a/contracts/docs/NativeStakingSSVStrategyStorage.svg +++ b/contracts/docs/NativeStakingSSVStrategyStorage.svg @@ -4,90 +4,84 @@ - - + + StorageDiagram - + 3 - -NativeStakingSSVStrategy <<Contract>> - -slot - -0 + +NativeStakingSSVStrategy <<Contract>> + +slot -1 +0 -2 +1 -3-52 +2 -53 +3-52 -54 +53 -55 +54 -56 +55 -57 +56 -58-107 +57-106 -108 +107 -109-158 +108-157 -159 +158 -160 +159 -161 +160 -162 +161 -163 +162 -164 +163 -165 +164 -166 +165 -167-264 +166-263 -265-314 - -type: <inherited contract>.variable (bytes) - -unallocated (11) - -address: ValidatorRegistrator.validatorRegistrator (20) - -bool: Pausable._paused (1) +264-313 + +type: <inherited contract>.variable (bytes) -uint256: ValidatorRegistrator.activeDepositedValidators (32) +unallocated (11) + +address: ValidatorRegistrator.validatorRegistrator (20) + +bool: Pausable._paused (1) -mapping(bytes32=>VALIDATOR_STATE): ValidatorRegistrator.validatorsStates (32) +uint256: ValidatorRegistrator.activeDepositedValidators (32) -uint256[50]: ValidatorRegistrator.__gap (1600) +mapping(bytes32=>VALIDATOR_STATE): ValidatorRegistrator.validatorsStates (32) -uint256: ValidatorAccountant.beaconChainRewardWETH (32) +uint256[50]: ValidatorRegistrator.__gap (1600) -uint256: ValidatorAccountant.fuseIntervalStart (32) +uint256: ValidatorAccountant.consensusRewards (32) -uint256: ValidatorAccountant.fuseIntervalEnd (32) +uint256: ValidatorAccountant.fuseIntervalStart (32) -unallocated (12) - -address: ValidatorAccountant.accountingGovernor (20) +uint256: ValidatorAccountant.fuseIntervalEnd (32) -unallocated (12) - -address: ValidatorAccountant.strategist (20) +unallocated (12) + +address: ValidatorAccountant.accountingGovernor (20) uint256[50]: ValidatorAccountant.__gap (1600) @@ -130,48 +124,48 @@ 1 - -address[]: assetsMapped <<Array>> -0xaaf4f58de99300cfadc4585755f376d5fa747d5bc561d5bd9d710de1f91bf42d - -offset - -0 - -type: variable (bytes) - -unallocated (12) - -address (20) + +address[]: assetsMapped <<Array>> +0xaadc37b8ba5645e62f4546802db221593a94729ccbfc5a97d01365a88f649878 + +offset + +0 + +type: variable (bytes) + +unallocated (12) + +address (20) -3:19->1 - - +3:18->1 + + 2 - -address[]: rewardTokenAddresses <<Array>> -0x2da56674729343acc9933752c8c469a244252915242eb6d4c02d11ddd69164a1 - -offset - -0 - -type: variable (bytes) - -unallocated (12) - -address (20) + +address[]: rewardTokenAddresses <<Array>> +0xb29a2b3b6f2ff1b765777a231725941da5072cc4fcc30ac4a2ce09706e8ddeff + +offset + +0 + +type: variable (bytes) + +unallocated (12) + +address (20) -3:24->2 - - +3:23->2 + + diff --git a/contracts/docs/plantuml/oethProcesses.png b/contracts/docs/plantuml/oethProcesses.png new file mode 100644 index 0000000000000000000000000000000000000000..ded50a16e0421f48385dc5531959c3cbedfe682c GIT binary patch literal 434884 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̢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�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 NP&uufbkz9H{{i-1*$4mt literal 0 HcmV?d00001 diff --git a/contracts/docs/plantuml/oethProcesses.puml b/contracts/docs/plantuml/oethProcesses.puml new file mode 100644 index 0000000000..b97837a856 --- /dev/null +++ b/contracts/docs/plantuml/oethProcesses.puml @@ -0,0 +1,279 @@ +@startuml + +skinparam tabSize 2 +hide footbox + +title "Origin ETH processes" + +actor "Anyone" as sender +actor "Registrator" as reg <> +actor "Governor" as gov <> +actor "Treasury" as treasury <> +participant "API" as api <> +actor "Operators" as ssvOp <> + +box "Execution Chain" +participant "Harvester" as harv <> +participant "Native\nStaking SSV\nStrategy" as nativeStrat <> +participant "Fee\nAccumulator" as feeAccum <> +participant "SSV Network" as ssvNet <> +participant "Token" as ssv <> +participant "WETH" as weth <> +participant "Deposit" as dep <> +end box + +box "Beacon chain" +participant "Validator" as val <> +end box + +group Governor initializes the Native Staking Strategy + +gov -> nativeStrat : initialize() +activate nativeStrat +nativeStrat -> ssv : approve(\nSSV Network,\namount) +activate ssv +note right : Native Staking Strategy approves\nSSV Network to spend\nSSV tokens +return +' nativeStrat -> ssvNet : setFeeRecipientAddress(\nrecipient) +' activate ssvNet +' note right : NodeDelegator set as the fee recipient +' return +return + +gov -> ssv : transfer(\nfrom\nto\namount) +activate ssv +note right : transfer SSV tokens\nfrom Governor\nto Native Staking Strategy +return + +end group + +group Registrator creates a new SSV validator + +reg -> api: POST\neth/staking/ssv/request/create\nuuid,\nvalidatorsCount,\ntype,\nwithdrawalAddress,\nfeeRecipientAddress,\nssvOwnerAddress,\noperationPeriodInDays +activate api +note right +withdrawalAddress is Native Staking Strategy +feeRecipientAddress is FeeAccumulator contract +ssvOwnerAddress is Native Staking Strategy +type is without-encrypt-key +end note +api -> api: private key +note right : generate a validator private key +api -> api: split(key) +note right : splits validator key into multiple KeyShares +return + +reg -> api: status(uuid) +activate api +return status,\nvalidatorRegistration,\nshareData +note right : validatorRegistration contains the pubkey, operatorIds and cluster details + +reg -> nativeStrat : registerSsvValidator(\npublicKey,\noperatorIds,\nsharesData,\namount,\ncluster,\nwithdrawal_credentials,\nsignature,\ndepositDataRoot) +activate nativeStrat +note right +cluster data: +The number of validators in the cluster +The index of network fees related to this cluster +The last index calculated for the cluster +Flag indicating whether the cluster is active +The SSV balance of the cluster +end note +nativeStrat -> ssvNet : registerValidator(\npublicKey,\noperatorIds,\nsharesData,\namount,\ncluster) +activate ssvNet +ssvNet -> ssv : transferFrom(\nfrom\nto\namount) +activate ssv +note right: transfer SSV tokens\nfrom NodeDelegator\nto SSV Network +return +return + +nativeStrat -> weth : withdraw(\namount) +activate weth +note right : WETH burned for ETH +return ETH + +nativeStrat -> dep : stake(\npubkey,\nwithdrawal_credentials,\nsignature,\ndepositDataRoot) +activate dep +note left : 32 ETH from Native Staking Strategy\nis sent to Beacon Deposit +return +return + +note over val : Pending Deposit + +... 1024 execution blocks (~4 hours) ... +... 32 consensus epochs (~3.5 hours) ... + +dep -> val : 32 ETH + +note over val : Pending Activation + +... four validators are activated each epoch from the Validator Queue (~1.5 days) ... + +note over val : Active + +end group + + +group Registrator deposits more SSV to SSV cluster + +treasury -> ssv : transfer(\nto\namount) +activate ssv +note right : transfer SSV tokens\nfrom Treasury\nto Native Staking Strategy +return + +group SSV ClusterScanner +reg -> ssvNet : getPastEvents(filter) +activate ssvNet +note right : get all events where the ownerAddress\nis the Native Staking Strategy +return events + +reg -> reg : getCluster(events):\n cluster +note right +cluster data: + validatorCount + networkFeeIndex + index + active + balance +end note +end group + +reg -> nativeStrat : depositSSV(\noperatorIds,\namount,\ncluster) +activate nativeStrat +nativeStrat -> ssvNet : deposit(\nclusterOwner,\noperatorIds,\namount,\ncluster) +activate ssvNet +note right +clusterOwner is Native Staking Strategy +operatorIds are the SSV Operators +amount of SSV tokens +end note +ssvNet -> ssv : transferFrom(\nfrom\nto\namount) +activate ssv +note right: transfer SSV tokens\nfrom Native Staking Strategy\nto SSV Network +return +return +return +end group + +group Consensus Rewards + +note over val +attesting to blocks +proposing blocks +participating in sync committees +end note +val -> val : ETH + +... swept every 8-10 days ... + +note over val : partial withdraw of excess ETH\nfrom validator to the Native Staking Strategy +val -> nativeStrat : ETH + +note over nativeStrat : Native Staking Strategy's\nWETH balance does not change + +end group + +group Registrator full withdraw from validator + +reg -> nativeStrat : exitSsvValidator(\npublicKey\noperatorIds) +activate nativeStrat +nativeStrat -> ssvNet : exitValidator(\npublicKey\noperatorIds) +activate ssvNet +return +return + +ssvOp -> ssvOp : sign(\npk,\nexit message) +note right : voluntary exit message signed by the validator private key +ssvOp -> val : signed voluntary exit message +activate val +return + +... wait until validator has exited.\nmin four epochs (~25 min), currently 1.5 hours but can take a number of days depending on the number of validators in the exit queue ... + +reg -> nativeStrat : removeSsvValidator(\npublicKey,\noperatorIds,\ncluster) +activate nativeStrat +nativeStrat -> ssvNet : removeValidator(\npublicKey\noperatorIds,\ncluster) +activate ssvNet +note right : stop paying SSV to Operators\n and reduce required SSV collateral +return +return + +... wait for the validator to be swept on the Beacon chain\ncurrent time is every 8.5 days ... + +val -> nativeStrat : ETH +note left : transfer staked ETH and rewards\nfrom Beacon Deposit\nto Native Staking Strategy + +note over nativeStrat : Native Staking Strategy's\nWETH balance does not change + +end group + +group Registrator does accounting of consensus rewards and validator withdrawals + +reg -> nativeStrat : doAccounting() +activate nativeStrat + +note over nativeStrat +ETH received since last accounting = current ETH balance - previous consensus rewards +validator withdrawals = ETH received / 32 ETH +end note + +nativeStrat -> weth : deposit(\nwithdrawn ETH) +activate weth +note left : convert ETH from full withdrawals to WETH +return + +nativeStrat -> weth : transfer(\nvault,\nwithdrawn ETH) +activate weth +note left : transfer withdrawn WETH\nfrom Native Staking Strategy\nto OETH Vault +return + +note over nativeStrat +Add remaining ETH to consensus rewards. +ETH from consensus rewards stays in the Native Staking Strategy. +end note + +return accounting valid flag + +end group + +group Execution Rewards + +sender -> feeAccum : ETH +note right : tx fees and MEV rewards + +note over nativeStrat : Native Staking Strategy's\nWETH balance does not change + +end group + +group Harvester collects ETH rewards + +sender -> harv : harvestAndSwap(\nstrtaegy) +activate harv +harv -> nativeStrat : collectRewardTokens() +activate nativeStrat + +nativeStrat -> feeAccum : collect() +activate feeAccum +feeAccum -> nativeStrat : ETH +note right : send all execution rewards in the FeeAccumulator\nto the Native Staking Stragegy +return execution rewards + +note over nativeStrat : total rewards = execution rewards + consensus rewards + +note over nativeStrat : reset consensus rewards to zero + +nativeStrat -> weth : deposit(\ntotal rewards) +activate weth +note left : convert ETH rewards to WETH +return + +nativeStrat -> weth : transfer(\nHarvester,\ntotal ETH rewards) +activate weth +note left : transfer rewards as WETH\nfrom Native Staking Strategy\nto Harvester +return + +return +return + +end group + +@enduml \ No newline at end of file diff --git a/contracts/test/strategies/nativeSSVStaking.js b/contracts/test/strategies/nativeSSVStaking.js index 910a5d8ba0..dafaed2aff 100644 --- a/contracts/test/strategies/nativeSSVStaking.js +++ b/contracts/test/strategies/nativeSSVStaking.js @@ -1,6 +1,6 @@ const { expect } = require("chai"); -const ethers = require("ethers"); -const { utils, BigNumber } = ethers; +const { BigNumber } = require("ethers"); +const { formatUnits, parseEther } = require("ethers").utils; const { setBalance } = require("@nomicfoundation/hardhat-network-helpers"); const { isCI } = require("../helpers"); @@ -57,11 +57,11 @@ describe("Unit test: Native SSV Staking Strategy", function () { ); const tx = { to: nativeStakingSSVStrategy.address, - value: ethers.utils.parseEther("2", "ether"), + value: parseEther("2", "ether"), }; await expect(signer.sendTransaction(tx)).to.be.revertedWith( - "function selector was not recognized and there's no fallback nor receive function" + "eth not sent from Fee Accumulator" ); }); @@ -115,7 +115,7 @@ describe("Unit test: Native SSV Staking Strategy", function () { await expect( nativeStakingSSVStrategy .connect(strategist) - .setFuseInterval(utils.parseEther("21.6"), utils.parseEther("25.6")) + .setFuseInterval(parseEther("21.6"), parseEther("25.6")) ).to.be.revertedWith("Caller is not the Governor"); }); @@ -125,8 +125,8 @@ describe("Unit test: Native SSV Staking Strategy", function () { await expect( nativeStakingSSVStrategy .connect(governor) - .setFuseInterval(utils.parseEther("25.6"), utils.parseEther("21.6")) - ).to.be.revertedWith("FuseIntervalValuesIncorrect"); + .setFuseInterval(parseEther("25.6"), parseEther("21.6")) + ).to.be.revertedWith("incorrect fuse interval"); }); it("There should be at least 4 ETH between interval start and interval end", async () => { @@ -135,8 +135,8 @@ describe("Unit test: Native SSV Staking Strategy", function () { await expect( nativeStakingSSVStrategy .connect(governor) - .setFuseInterval(utils.parseEther("21.6"), utils.parseEther("25.5")) - ).to.be.revertedWith("FuseIntervalValuesIncorrect"); + .setFuseInterval(parseEther("21.6"), parseEther("25.5")) + ).to.be.revertedWith("incorrect fuse interval"); }); it("Revert when fuse intervals are larger than 32 ether", async () => { @@ -145,17 +145,17 @@ describe("Unit test: Native SSV Staking Strategy", function () { await expect( nativeStakingSSVStrategy .connect(governor) - .setFuseInterval(utils.parseEther("32.1"), utils.parseEther("32.1")) - ).to.be.revertedWith("FuseIntervalValuesIncorrect"); + .setFuseInterval(parseEther("32.1"), parseEther("32.1")) + ).to.be.revertedWith("incorrect fuse interval"); }); it("Governor should be able to change fuse interval", async () => { const { nativeStakingSSVStrategy, governor } = fixture; - const oldFuseStartBn = utils.parseEther("21.6"); - const oldFuseEndBn = utils.parseEther("25.6"); - const fuseStartBn = utils.parseEther("22.6"); - const fuseEndBn = utils.parseEther("26.6"); + const oldFuseStartBn = parseEther("21.6"); + const oldFuseEndBn = parseEther("25.6"); + const fuseStartBn = parseEther("22.6"); + const fuseEndBn = parseEther("26.6"); const tx = await nativeStakingSSVStrategy .connect(governor) @@ -213,56 +213,56 @@ describe("Unit test: Native SSV Staking Strategy", function () { const testCases = [ // normal beacon chain rewards { - ethBalance: utils.parseEther("14"), - expectedRewards: utils.parseEther("14"), + ethBalance: parseEther("14"), + expectedRewards: parseEther("14"), expectedValidatorsFullWithdrawals: 0, slashDetected: false, fuseBlown: false, }, // normal beacon chain rewards + 1 withdrawn validator { - ethBalance: utils.parseEther("34"), - expectedRewards: utils.parseEther("2"), + ethBalance: parseEther("34"), + expectedRewards: parseEther("2"), expectedValidatorsFullWithdrawals: 1, slashDetected: false, fuseBlown: false, }, // 8 withdrawn validators + beacon chain rewards { - ethBalance: utils.parseEther("276"), - expectedRewards: utils.parseEther("20"), + ethBalance: parseEther("276"), + expectedRewards: parseEther("20"), expectedValidatorsFullWithdrawals: 8, slashDetected: false, fuseBlown: false, }, // fuse blown { - ethBalance: utils.parseEther("22"), - expectedRewards: utils.parseEther("0"), + ethBalance: parseEther("22"), + expectedRewards: parseEther("0"), expectedValidatorsFullWithdrawals: 0, slashDetected: false, fuseBlown: true, }, // fuse blown + 1 full withdrawal { - ethBalance: utils.parseEther("54"), - expectedRewards: utils.parseEther("0"), + ethBalance: parseEther("54"), + expectedRewards: parseEther("0"), expectedValidatorsFullWithdrawals: 1, slashDetected: false, fuseBlown: true, }, // 1 validator slashed { - ethBalance: utils.parseEther("26.6"), - expectedRewards: utils.parseEther("0"), + ethBalance: parseEther("26.6"), + expectedRewards: parseEther("0"), expectedValidatorsFullWithdrawals: 0, slashDetected: true, fuseBlown: false, }, // 1 validator fully withdrawn + 1 slashed { - ethBalance: utils.parseEther("58.6"), // 26.6 + 32 - expectedRewards: utils.parseEther("0"), + ethBalance: parseEther("58.6"), // 26.6 + 32 + expectedRewards: parseEther("0"), expectedValidatorsFullWithdrawals: 1, slashDetected: true, fuseBlown: false, @@ -277,9 +277,9 @@ describe("Unit test: Native SSV Staking Strategy", function () { slashDetected, fuseBlown, } = testCase; - it(`Expect that ${utils.formatUnits( + it(`Expect that ${formatUnits( ethBalance - )} ETH will result in ${utils.formatUnits( + )} ETH will result in ${formatUnits( expectedRewards )} ETH rewards and ${expectedValidatorsFullWithdrawals} validators withdrawn.`, async () => { const { nativeStakingSSVStrategy, governor, strategist } = fixture; @@ -290,11 +290,11 @@ describe("Unit test: Native SSV Staking Strategy", function () { await nativeStakingSSVStrategy.connect(strategist).pause(); await nativeStakingSSVStrategy.connect(governor).manuallyFixAccounting( 30, // activeDepositedValidators - ethers.utils.parseEther("0", "ether"), //_ethToWeth - ethers.utils.parseEther("0", "ether"), //_wethToBeSentToVault - ethers.utils.parseEther("0", "ether"), //_beaconChainRewardWETH - ethers.utils.parseEther("3000", "ether"), //_ethThresholdCheck - ethers.utils.parseEther("3000", "ether") //_wethThresholdCheck + parseEther("0", "ether"), //_ethToWeth + parseEther("0", "ether"), //_wethToBeSentToVault + parseEther("0", "ether"), //_beaconChainRewardWETH + parseEther("3000", "ether"), //_ethThresholdCheck + parseEther("3000", "ether") //_wethThresholdCheck ); // check accounting values @@ -328,9 +328,9 @@ describe("Unit test: Native SSV Staking Strategy", function () { ); // weth sent to vault expect(WithdrawnEvent.args[2]).to.equal( - utils - .parseEther("32") - .mul(BigNumber.from(`${expectedValidatorsFullWithdrawals}`)) + parseEther("32").mul( + BigNumber.from(`${expectedValidatorsFullWithdrawals}`) + ) ); } else { expect(WithdrawnEvent).to.be.undefined; @@ -365,11 +365,11 @@ describe("Unit test: Native SSV Staking Strategy", function () { await expect( nativeStakingSSVStrategy.connect(strategist).manuallyFixAccounting( 10, //_activeDepositedValidators - ethers.utils.parseEther("2", "ether"), //_ethToWeth - ethers.utils.parseEther("2", "ether"), //_wethToBeSentToVault - ethers.utils.parseEther("2", "ether"), //_beaconChainRewardWETH - ethers.utils.parseEther("0", "ether"), //_ethThresholdCheck - ethers.utils.parseEther("0", "ether") //_wethThresholdCheck + parseEther("2", "ether"), //_ethToWeth + parseEther("2", "ether"), //_wethToBeSentToVault + parseEther("2", "ether"), //_beaconChainRewardWETH + parseEther("0", "ether"), //_ethThresholdCheck + parseEther("0", "ether") //_wethThresholdCheck ) ).to.be.revertedWith("Caller is not the Accounting Governor"); }); @@ -381,13 +381,13 @@ describe("Unit test: Native SSV Staking Strategy", function () { await expect( nativeStakingSSVStrategy.connect(governor).manuallyFixAccounting( 10, //_activeDepositedValidators - ethers.utils.parseEther("2", "ether"), //_ethToWeth - ethers.utils.parseEther("2", "ether"), //_wethToBeSentToVault - ethers.utils.parseEther("2", "ether"), //_beaconChainRewardWETH - ethers.utils.parseEther("1", "ether"), //_ethThresholdCheck - ethers.utils.parseEther("0", "ether") //_wethThresholdCheck + parseEther("2", "ether"), //_ethToWeth + parseEther("2", "ether"), //_wethToBeSentToVault + parseEther("2", "ether"), //_beaconChainRewardWETH + parseEther("1", "ether"), //_ethThresholdCheck + parseEther("0", "ether") //_wethThresholdCheck ) - ).to.be.revertedWith("NotPaused"); + ).to.be.revertedWith("not paused"); }); it("Should not execute manual recovery if eth threshold reached", async () => { @@ -396,26 +396,23 @@ describe("Unit test: Native SSV Staking Strategy", function () { await setBalance( nativeStakingSSVStrategy.address, - ethers.utils.parseEther("6", "ether") + parseEther("6", "ether") ); await weth .connect(josh) - .transfer( - nativeStakingSSVStrategy.address, - ethers.utils.parseEther("5", "ether") - ); + .transfer(nativeStakingSSVStrategy.address, parseEther("5", "ether")); await nativeStakingSSVStrategy.connect(strategist).pause(); await expect( nativeStakingSSVStrategy.connect(governor).manuallyFixAccounting( 10, //_activeDepositedValidators - ethers.utils.parseEther("2", "ether"), //_ethToWeth - ethers.utils.parseEther("2", "ether"), //_wethToBeSentToVault - ethers.utils.parseEther("2", "ether"), //_beaconChainRewardWETH - ethers.utils.parseEther("5", "ether"), //_ethThresholdCheck - ethers.utils.parseEther("5", "ether") //_wethThresholdCheck + parseEther("2", "ether"), //_ethToWeth + parseEther("2", "ether"), //_wethToBeSentToVault + parseEther("2", "ether"), //_beaconChainRewardWETH + parseEther("5", "ether"), //_ethThresholdCheck + parseEther("5", "ether") //_wethThresholdCheck ) - ).to.be.revertedWith("ManualFixAccountingThresholdReached"); + ).to.be.revertedWith("over accounting threshold"); }); it("Should not execute manual recovery if weth threshold reached", async () => { @@ -424,26 +421,23 @@ describe("Unit test: Native SSV Staking Strategy", function () { await setBalance( nativeStakingSSVStrategy.address, - ethers.utils.parseEther("5", "ether") + parseEther("5", "ether") ); await weth .connect(josh) - .transfer( - nativeStakingSSVStrategy.address, - ethers.utils.parseEther("6", "ether") - ); + .transfer(nativeStakingSSVStrategy.address, parseEther("6", "ether")); await nativeStakingSSVStrategy.connect(strategist).pause(); await expect( nativeStakingSSVStrategy.connect(governor).manuallyFixAccounting( 10, //_activeDepositedValidators - ethers.utils.parseEther("2", "ether"), //_ethToWeth - ethers.utils.parseEther("2", "ether"), //_wethToBeSentToVault - ethers.utils.parseEther("2", "ether"), //_beaconChainRewardWETH - ethers.utils.parseEther("5", "ether"), //_ethThresholdCheck - ethers.utils.parseEther("5", "ether") //_wethThresholdCheck + parseEther("2", "ether"), //_ethToWeth + parseEther("2", "ether"), //_wethToBeSentToVault + parseEther("2", "ether"), //_beaconChainRewardWETH + parseEther("5", "ether"), //_ethThresholdCheck + parseEther("5", "ether") //_wethThresholdCheck ) - ).to.be.revertedWith("ManualFixAccountingThresholdReached"); + ).to.be.revertedWith("over accounting threshold"); }); it("Should allow 5/8 governor to recover paused contract and correct the accounting state", async () => { @@ -452,14 +446,11 @@ describe("Unit test: Native SSV Staking Strategy", function () { await setBalance( nativeStakingSSVStrategy.address, - ethers.utils.parseEther("5", "ether") + parseEther("5", "ether") ); await weth .connect(josh) - .transfer( - nativeStakingSSVStrategy.address, - ethers.utils.parseEther("5", "ether") - ); + .transfer(nativeStakingSSVStrategy.address, parseEther("5", "ether")); await nativeStakingSSVStrategy.connect(strategist).pause(); // unit test fixture sets OUSD governor as accounting governor @@ -467,11 +458,11 @@ describe("Unit test: Native SSV Staking Strategy", function () { .connect(governor) .manuallyFixAccounting( 3, //_activeDepositedValidators - ethers.utils.parseEther("2.1", "ether"), //_ethToWeth - ethers.utils.parseEther("2.2", "ether"), //_wethToBeSentToVault - ethers.utils.parseEther("2.3", "ether"), //_beaconChainRewardWETH - ethers.utils.parseEther("5", "ether"), //_ethThresholdCheck - ethers.utils.parseEther("5", "ether") //_wethThresholdCheck + parseEther("2.1", "ether"), //_ethToWeth + parseEther("2.2", "ether"), //_wethToBeSentToVault + parseEther("2.3", "ether"), //_beaconChainRewardWETH + parseEther("5", "ether"), //_ethThresholdCheck + parseEther("5", "ether") //_wethThresholdCheck ); const events = (await tx.wait()).events || []; @@ -486,16 +477,16 @@ describe("Unit test: Native SSV Staking Strategy", function () { expect(AccountingManuallyFixedEvent.args[0]).to.equal(0); // oldActiveDepositedValidators expect(AccountingManuallyFixedEvent.args[1]).to.equal(3); // activeDepositedValidators expect(AccountingManuallyFixedEvent.args[2]).to.equal( - ethers.utils.parseEther("0", "ether") + parseEther("0", "ether") ); // oldBeaconChainRewardWETH expect(AccountingManuallyFixedEvent.args[3]).to.equal( - ethers.utils.parseEther("2.3", "ether") + parseEther("2.3", "ether") ); // beaconChainRewardWETH expect(AccountingManuallyFixedEvent.args[4]).to.equal( - ethers.utils.parseEther("2.1", "ether") + parseEther("2.1", "ether") ); // ethToWeth expect(AccountingManuallyFixedEvent.args[5]).to.equal( - ethers.utils.parseEther("2.2", "ether") + parseEther("2.2", "ether") ); // wethToBeSentToVault }); }); @@ -503,174 +494,183 @@ describe("Unit test: Native SSV Staking Strategy", function () { describe("General functionality", function () { const rewardTestCases = [ { - feeAccumulatorEth: utils.parseEther("2.2"), - beaconChainRewardEth: utils.parseEther("16.3"), - wethFromDeposits: utils.parseEther("100"), + feeAccumulatorEth: 2.2, + consensusRewards: 16.3, + deposits: 100, nrOfActiveDepositedValidators: 7, - expectedEthSentToHarvester: utils.parseEther("18.5"), + expectedHarvester: 18.5, + expectedBalance: 100 + 7 * 32, }, { - feeAccumulatorEth: utils.parseEther("10.2"), - beaconChainRewardEth: utils.parseEther("21.6"), - wethFromDeposits: utils.parseEther("0"), + feeAccumulatorEth: 10.2, + consensusRewards: 21.6, + deposits: 0, nrOfActiveDepositedValidators: 5, - expectedEthSentToHarvester: utils.parseEther("31.8"), + expectedHarvester: 31.8, + expectedBalance: 0 + 5 * 32, }, { - feeAccumulatorEth: utils.parseEther("10.2"), - beaconChainRewardEth: utils.parseEther("21.6"), - wethFromDeposits: utils.parseEther("1"), + feeAccumulatorEth: 10.2, + consensusRewards: 21.6, + deposits: 1, nrOfActiveDepositedValidators: 0, - expectedEthSentToHarvester: utils.parseEther("31.8"), + expectedHarvester: 31.8, + expectedBalance: 1 + 0 * 32, }, { - feeAccumulatorEth: utils.parseEther("0"), - beaconChainRewardEth: utils.parseEther("0"), - wethFromDeposits: utils.parseEther("0"), + feeAccumulatorEth: 0, + consensusRewards: 0, + deposits: 0, nrOfActiveDepositedValidators: 0, - expectedEthSentToHarvester: utils.parseEther("0"), + expectedHarvester: 0, + expectedBalance: 0 + 0 * 32, }, ]; - for (const testCase of rewardTestCases) { - it("Collecting rewards and should correctly account for WETH", async () => { - const { - nativeStakingSSVStrategy, - governor, - // strategist, - oethHarvester, - weth, - josh, - } = fixture; - const { - feeAccumulatorEth, - beaconChainRewardEth, - wethFromDeposits, - expectedEthSentToHarvester, - } = testCase; - const feeAccumulatorAddress = - await nativeStakingSSVStrategy.FEE_ACCUMULATOR_ADDRESS(); - const sHarvester = await impersonateAndFund(oethHarvester.address); - - // setup state - if (beaconChainRewardEth.gt(BigNumber.from("0"))) { - // set the reward eth on the strategy - await setBalance( - nativeStakingSSVStrategy.address, - beaconChainRewardEth - ); - } - if (feeAccumulatorEth.gt(BigNumber.from("0"))) { - // set execution layer rewards on the fee accumulator - await setBalance(feeAccumulatorAddress, feeAccumulatorEth); - } - if (wethFromDeposits.gt(BigNumber.from("0"))) { - // send eth to the strategy as if Vault would send it via a Deposit function - await weth - .connect(josh) - .transfer(nativeStakingSSVStrategy.address, wethFromDeposits); - } - - // run the accounting - await nativeStakingSSVStrategy.connect(governor).doAccounting(); - - const harvesterWethBalance = await weth.balanceOf( - oethHarvester.address + describe("Collecting rewards and should correctly account for WETH", async () => { + for (const testCase of rewardTestCases) { + const feeAccumulatorEth = parseEther( + testCase.feeAccumulatorEth.toString() ); - const tx = await nativeStakingSSVStrategy - .connect(sHarvester) - .collectRewardTokens(); - const events = (await tx.wait()).events || []; - - const harvesterBalanceDiff = ( - await weth.balanceOf(oethHarvester.address) - ).sub(harvesterWethBalance); - expect(harvesterBalanceDiff).to.equal(expectedEthSentToHarvester); - - const rewardTokenCollectedEvent = events.find( - (e) => e.event === "RewardTokenCollected" + const consensusRewards = parseEther( + testCase.consensusRewards.toString() + ); + const deposits = parseEther(testCase.deposits.toString()); + const expectedHarvester = parseEther( + testCase.expectedHarvester.toString() ); - if (expectedEthSentToHarvester.gt(BigNumber.from("0"))) { - expect(rewardTokenCollectedEvent).to.not.be.undefined; - expect(rewardTokenCollectedEvent.event).to.equal( - "RewardTokenCollected" + it(`with ${testCase.feeAccumulatorEth} execution rewards, ${testCase.consensusRewards} consensus rewards and ${testCase.deposits} deposits. expect harvest ${testCase.expectedHarvester}`, async () => { + const { + nativeStakingSSVStrategy, + governor, + oethHarvester, + weth, + josh, + } = fixture; + const feeAccumulatorAddress = + await nativeStakingSSVStrategy.FEE_ACCUMULATOR_ADDRESS(); + const sHarvester = await impersonateAndFund(oethHarvester.address); + + // setup state + if (consensusRewards.gt(BigNumber.from("0"))) { + // set the reward eth on the strategy + await setBalance( + nativeStakingSSVStrategy.address, + consensusRewards + ); + } + if (feeAccumulatorEth.gt(BigNumber.from("0"))) { + // set execution layer rewards on the fee accumulator + await setBalance(feeAccumulatorAddress, feeAccumulatorEth); + } + if (deposits.gt(BigNumber.from("0"))) { + // send eth to the strategy as if Vault would send it via a Deposit function + await weth + .connect(josh) + .transfer(nativeStakingSSVStrategy.address, deposits); + } + + // run the accounting + await nativeStakingSSVStrategy.connect(governor).doAccounting(); + + const harvesterWethBalance = await weth.balanceOf( + oethHarvester.address ); - expect(rewardTokenCollectedEvent.args[1]).to.equal(weth.address); - expect(rewardTokenCollectedEvent.args[2]).to.equal( - expectedEthSentToHarvester + const tx = await nativeStakingSSVStrategy + .connect(sHarvester) + .collectRewardTokens(); + const events = (await tx.wait()).events || []; + + const harvesterBalanceDiff = ( + await weth.balanceOf(oethHarvester.address) + ).sub(harvesterWethBalance); + expect(harvesterBalanceDiff).to.equal(expectedHarvester); + + const rewardTokenCollectedEvent = events.find( + (e) => e.event === "RewardTokenCollected" ); - } else { - expect(rewardTokenCollectedEvent).to.be.undefined; - } - }); - } - for (const testCase of rewardTestCases) { - it("Checking balance should return the correct values", async () => { - const { - nativeStakingSSVStrategy, - governor, - strategist, - // oethHarvester, - weth, - josh, - } = fixture; - const { - feeAccumulatorEth, - beaconChainRewardEth, - wethFromDeposits, - expectedEthSentToHarvester, - nrOfActiveDepositedValidators, - } = testCase; - const feeAccumulatorAddress = - await nativeStakingSSVStrategy.FEE_ACCUMULATOR_ADDRESS(); - // const sHarvester = await impersonateAndFund(oethHarvester.address); - - // setup state - if (beaconChainRewardEth.gt(BigNumber.from("0"))) { - // set the reward eth on the strategy - await setBalance( - nativeStakingSSVStrategy.address, - beaconChainRewardEth - ); - } - if (feeAccumulatorEth.gt(BigNumber.from("0"))) { - // set execution layer rewards on the fee accumulator - await setBalance(feeAccumulatorAddress, feeAccumulatorEth); - } - if (wethFromDeposits.gt(BigNumber.from("0"))) { - // send eth to the strategy as if Vault would send it via a Deposit function - await weth - .connect(josh) - .transfer(nativeStakingSSVStrategy.address, wethFromDeposits); - } + if (expectedHarvester.gt(BigNumber.from("0"))) { + expect(rewardTokenCollectedEvent).to.not.be.undefined; + expect(rewardTokenCollectedEvent.event).to.equal( + "RewardTokenCollected" + ); + expect(rewardTokenCollectedEvent.args[1]).to.equal(weth.address); + expect(rewardTokenCollectedEvent.args[2]).to.equal( + expectedHarvester + ); + } else { + expect(rewardTokenCollectedEvent).to.be.undefined; + } + }); + } + }); - // set the correct amount of staked validators - await nativeStakingSSVStrategy.connect(strategist).pause(); - await nativeStakingSSVStrategy.connect(governor).manuallyFixAccounting( - nrOfActiveDepositedValidators, // activeDepositedValidators - ethers.utils.parseEther("0", "ether"), //_ethToWeth - ethers.utils.parseEther("0", "ether"), //_wethToBeSentToVault - ethers.utils.parseEther("0", "ether"), //_beaconChainRewardWETH - ethers.utils.parseEther("3000", "ether"), //_ethThresholdCheck - ethers.utils.parseEther("3000", "ether") //_wethThresholdCheck + describe("Checking balance should return the correct values", async () => { + for (const testCase of rewardTestCases) { + const feeAccumulatorEth = parseEther( + testCase.feeAccumulatorEth.toString() ); - - // run the accounting - await nativeStakingSSVStrategy.connect(governor).doAccounting(); - - expect( - await nativeStakingSSVStrategy.checkBalance(weth.address) - ).to.equal( - expectedEthSentToHarvester.add( - BigNumber.from(`${nrOfActiveDepositedValidators}`).mul( - utils.parseEther("32") - ) - ) + const consensusRewards = parseEther( + testCase.consensusRewards.toString() ); - }); - } + const deposits = parseEther(testCase.deposits.toString()); + const expectedBalance = parseEther(testCase.expectedBalance.toString()); + const { nrOfActiveDepositedValidators } = testCase; + it(`with ${testCase.feeAccumulatorEth} execution rewards, ${testCase.consensusRewards} consensus rewards, ${testCase.deposits} deposits and ${nrOfActiveDepositedValidators} validators. expected balance ${testCase.expectedBalance}`, async () => { + const { + nativeStakingSSVStrategy, + governor, + strategist, + // oethHarvester, + weth, + josh, + } = fixture; + const feeAccumulatorAddress = + await nativeStakingSSVStrategy.FEE_ACCUMULATOR_ADDRESS(); + + // setup state + if (consensusRewards.gt(BigNumber.from("0"))) { + // set the reward eth on the strategy + await setBalance( + nativeStakingSSVStrategy.address, + consensusRewards + ); + } + if (feeAccumulatorEth.gt(BigNumber.from("0"))) { + // set execution layer rewards on the fee accumulator + await setBalance(feeAccumulatorAddress, feeAccumulatorEth); + } + if (deposits.gt(BigNumber.from("0"))) { + // send eth to the strategy as if Vault would send it via a Deposit function + await weth + .connect(josh) + .transfer(nativeStakingSSVStrategy.address, deposits); + } + + // set the correct amount of staked validators + await nativeStakingSSVStrategy.connect(strategist).pause(); + await nativeStakingSSVStrategy + .connect(governor) + .manuallyFixAccounting( + nrOfActiveDepositedValidators, // activeDepositedValidators + parseEther("0", "ether"), //_ethToWeth + parseEther("0", "ether"), //_wethToBeSentToVault + parseEther("0", "ether"), //_beaconChainRewardWETH + parseEther("3000", "ether"), //_ethThresholdCheck + parseEther("3000", "ether") //_wethThresholdCheck + ); + + // run the accounting + await nativeStakingSSVStrategy.connect(governor).doAccounting(); + + expect( + await nativeStakingSSVStrategy.checkBalance(weth.address) + ).to.equal(expectedBalance); + }); + } + }); it("Should be able to collect the SSV reward token", async () => {}); }); From 8419fc7776a8747c12aa2623d67aadf77c846ffe Mon Sep 17 00:00:00 2001 From: Nick Addison Date: Thu, 25 Apr 2024 19:38:01 +1000 Subject: [PATCH 017/273] Native staking changes and unit tests (#2029) * Fixed native staking deployment since the strategist is got from the vault * Refactor of some Native Staking events Refactor of Native Staking unit tests * Renamed AccountingBeaconChainRewards to AccountingConsensusRewards Accounting updated to handle zero ETH from the beacon chain * fixed bug not accounting for previous consensus rewards Blow fuse if ETH balance < previous consensus rewards * Pause collectRewardTokens and doAccounting on accounting failure. Validated asset on deposit to Native Staking Strategy. Moved depositSSV from NativeStakingSSVStrategy to ValidatorRegistrator moved onlyStrategist modified and VAULT_ADDRESS immutable from ValidatorAccountant to ValidatorRegistrator manuallyFixAccounting changed to use whenPaused modifier made fuseIntervalEnd inclusive Natspec updates refactoring of native staking unit tests --- .../NativeStakingSSVStrategy.sol | 48 +- .../NativeStaking/ValidatorAccountant.sol | 76 +- .../NativeStaking/ValidatorRegistrator.sol | 41 +- contracts/deploy/091_native_ssv_staking.js | 8 +- .../docs/NativeStakingSSVStrategySquashed.svg | 265 +++--- contracts/test/_fixture.js | 7 +- contracts/test/strategies/nativeSSVStaking.js | 804 +++++++++++------- 7 files changed, 703 insertions(+), 546 deletions(-) diff --git a/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol b/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol index 1c4f44f02d..75a6f6cc4e 100644 --- a/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol +++ b/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol @@ -82,7 +82,8 @@ contract NativeStakingSSVStrategy is } /// @dev Convert accumulated ETH to WETH and send to the Harvester. - function _collectRewardTokens() internal override { + /// Will revert if the strategy is paused for accounting. + function _collectRewardTokens() internal override whenNotPaused { // collect ETH from execution rewards from the fee accumulator uint256 executionRewards = FeeAccumulator(FEE_ACCUMULATOR_ADDRESS) .collect(); @@ -114,19 +115,23 @@ contract NativeStakingSSVStrategy is } } - /// @notice Deposit asset into the underlying platform - /// @param _asset Address of asset to deposit - /// @param _amount Amount of assets to deposit + /// @notice Unlike other strategies, this does not deposit assets into the underlying platform. + /// It just checks the asset is WETH and emits the Deposit event. + /// To deposit WETH into validators `registerSsvValidator` and `stakeEth` must be used. + /// Will NOT revert if the strategy is paused from an accounting failure. + /// @param _asset Address of asset to deposit. Has to be WETH. + /// @param _amount Amount of assets that were transferred to the strategy by the vault. function deposit(address _asset, uint256 _amount) external override onlyVault nonReentrant { + require(_asset == WETH_TOKEN_ADDRESS, "Unsupported asset"); _deposit(_asset, _amount); } - /// @dev Deposit WETH to this contract to enable automated action to stake it + /// @dev Deposit WETH to this strategy so it can later be staked into a validator. /// @param _asset Address of WETH /// @param _amount Amount of WETH to deposit function _deposit(address _asset, uint256 _amount) internal { @@ -143,7 +148,10 @@ contract NativeStakingSSVStrategy is emit Deposit(_asset, address(0), _amount); } - /// @notice Deposit the entire balance of WETH asset in the strategy into the underlying platform + /// @notice Unlike other strategies, this does not deposit assets into the underlying platform. + /// It just emits the Deposit event. + /// To deposit WETH into validators `registerSsvValidator` and `stakeEth` must be used. + /// Will NOT revert if the strategy is paused from an accounting failure. function depositAll() external override onlyVault nonReentrant { uint256 wethBalance = IERC20(WETH_TOKEN_ADDRESS).balanceOf( address(this) @@ -157,6 +165,7 @@ contract NativeStakingSSVStrategy is /// can happen when: /// - the deposit was not a multiple of 32 WETH /// - someone sent WETH directly to this contract + /// Will NOT revert if the strategy is paused from an accounting failure. /// @param _recipient Address to receive withdrawn assets /// @param _asset WETH to withdraw /// @param _amount Amount of WETH to withdraw @@ -180,7 +189,14 @@ contract NativeStakingSSVStrategy is IERC20(_asset).safeTransfer(_recipient, _amount); } - /// @notice Remove all supported assets from the underlying platform and send them to Vault contract. + /// @notice transfer all WETH deposits back to the vault. + /// This does not withdraw from the validators. That has to be done separately with the + /// `exitSsvValidator` and `removeSsvValidator` operations. + /// This does not withdraw any execution rewards from the FeeAccumulator or + /// consensus rewards in this strategy. + /// Any ETH in this strategy that was swept from a full validator withdrawal will not be withdrawn. + /// ETH from full validator withdrawals is sent to the Vault using `doAccounting`. + /// Will NOT revert if the strategy is paused from an accounting failure. function withdrawAll() external override onlyVaultOrGovernor nonReentrant { uint256 wethBalance = IERC20(WETH_TOKEN_ADDRESS).balanceOf( address(this) @@ -234,24 +250,6 @@ contract NativeStakingSSVStrategy is ); } - /// @notice Deposits more SSV Tokens to the SSV Network contract which is used to pay the SSV Operators. - /// @dev A SSV cluster is defined by the SSVOwnerAddress and the set of operatorIds. - /// uses "onlyStrategist" modifier so continuous front-running can't DOS our maintenance service - /// that tries to top up SSV tokens. - /// @param cluster The SSV cluster details that must be derived from emitted events from the SSVNetwork contract. - function depositSSV( - uint64[] memory operatorIds, - uint256 amount, - Cluster memory cluster - ) external onlyStrategist { - ISSVNetwork(SSV_NETWORK_ADDRESS).deposit( - address(this), - operatorIds, - amount, - cluster - ); - } - /** * @notice Only accept ETH from the FeeAccumulator * @dev don't want to receive donations from anyone else as this will diff --git a/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol b/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol index f6d919b4b7..2f1843ee56 100644 --- a/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol +++ b/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol @@ -3,7 +3,6 @@ pragma solidity ^0.8.0; import { Pausable } from "@openzeppelin/contracts/security/Pausable.sol"; import { ValidatorRegistrator } from "./ValidatorRegistrator.sol"; -import { IVault } from "../../interfaces/IVault.sol"; import { IWETH9 } from "../../interfaces/IWETH9.sol"; /// @title Validator Accountant @@ -15,8 +14,6 @@ abstract contract ValidatorAccountant is ValidatorRegistrator { /// @notice The maximum amount of ETH that can be staked by a validator /// @dev this can change in the future with EIP-7251, Increase the MAX_EFFECTIVE_BALANCE uint256 public constant MAX_STAKE = 32 ether; - /// @notice Address of the OETH Vault proxy contract - address public immutable VAULT_ADDRESS; /// @notice Keeps track of the total consensus rewards swept from the beacon chain uint256 public consensusRewards = 0; @@ -30,12 +27,7 @@ abstract contract ValidatorAccountant is ValidatorRegistrator { uint256[50] private __gap; - event FuseIntervalUpdated( - uint256 oldStart, - uint256 oldEnd, - uint256 start, - uint256 end - ); + event FuseIntervalUpdated(uint256 start, uint256 end); event AccountingFullyWithdrawnValidator( uint256 noOfValidators, uint256 remainingValidators, @@ -45,11 +37,8 @@ abstract contract ValidatorAccountant is ValidatorRegistrator { uint256 remainingValidators, uint256 wethSentToVault ); - event AccountingGovernorAddressChanged( - address oldAddress, - address newAddress - ); - event AccountingBeaconChainRewards(uint256 amount); + event AccountingGovernorChanged(address newAddress); + event AccountingConsensusRewards(uint256 amount); event AccountingManuallyFixed( uint256 oldActiveDepositedValidators, @@ -69,15 +58,6 @@ abstract contract ValidatorAccountant is ValidatorRegistrator { _; } - /// @dev Throws if called by any account other than the Strategist - modifier onlyStrategist() { - require( - msg.sender == IVault(VAULT_ADDRESS).strategistAddr(), - "Caller is not the Strategist" - ); - _; - } - /// @param _wethAddress Address of the Erc20 WETH Token contract /// @param _vaultAddress Address of the Vault /// @param _beaconChainDepositContract Address of the beacon chain deposit contract @@ -90,15 +70,14 @@ abstract contract ValidatorAccountant is ValidatorRegistrator { ) ValidatorRegistrator( _wethAddress, + _vaultAddress, _beaconChainDepositContract, _ssvNetwork ) - { - VAULT_ADDRESS = _vaultAddress; - } + {} function setAccountingGovernor(address _address) external onlyGovernor { - emit AccountingGovernorAddressChanged(accountingGovernor, _address); + emit AccountingGovernorChanged(_address); accountingGovernor = _address; } @@ -115,12 +94,7 @@ abstract contract ValidatorAccountant is ValidatorRegistrator { "incorrect fuse interval" ); - emit FuseIntervalUpdated( - fuseIntervalStart, - fuseIntervalEnd, - _fuseIntervalStart, - _fuseIntervalEnd - ); + emit FuseIntervalUpdated(_fuseIntervalStart, _fuseIntervalEnd); fuseIntervalStart = _fuseIntervalStart; fuseIntervalEnd = _fuseIntervalEnd; @@ -129,10 +103,10 @@ abstract contract ValidatorAccountant is ValidatorRegistrator { /* solhint-disable max-line-length */ /// This notion page offers a good explanation of how the accounting functions /// https://www.notion.so/originprotocol/Limited-simplified-native-staking-accounting-67a217c8420d40678eb943b9da0ee77d - /// In short, after dividing by 32 if the ETH remaining on the contract falls between 0 and fuseIntervalStart the accounting - /// function will treat that ETH as a Beacon Chain Reward ETH. - /// On the contrary if after dividing by 32 the ETH remaining on the contract falls between fuseIntervalEnd and 32 the - /// accounting function will treat that as a validator slashing. + /// In short, after dividing by 32, if the ETH remaining on the contract falls between 0 and fuseIntervalStart, + /// the accounting function will treat that ETH as Beacon chain consensus rewards. + /// On the contrary, if after dividing by 32, the ETH remaining on the contract falls between fuseIntervalEnd and 32, + /// the accounting function will treat that as a validator slashing. /// @notice Perform the accounting attributing beacon chain ETH to either full or partial withdrawals. Returns true when /// accounting is valid and fuse isn't "blown". Returns false when fuse is blown. /// @dev This function could in theory be permission-less but lets allow only the Registrator (Defender Action) to call it @@ -141,8 +115,15 @@ abstract contract ValidatorAccountant is ValidatorRegistrator { function doAccounting() external onlyRegistrator + whenNotPaused returns (bool accountingValid) { + if (address(this).balance < consensusRewards) { + // pause and fail the accounting + _pause(); + return false; + } + // Calculate all the new ETH that has been swept to the contract since the last accounting uint256 newSweptETH = address(this).balance - consensusRewards; accountingValid = true; @@ -163,18 +144,23 @@ abstract contract ValidatorAccountant is ValidatorRegistrator { ); } - uint256 ethRemaining = address(this).balance; + uint256 ethRemaining = address(this).balance - consensusRewards; // should be less than a whole validator stake require(ethRemaining < 32 ether, "unexpected accounting"); - // Beacon chain rewards swept (partial validator withdrawals) - if (ethRemaining <= fuseIntervalStart) { + // If no Beacon chain consensus rewards swept + if (ethRemaining == 0) { + // do nothing + return accountingValid; + } + // Beacon chain consensus rewards swept (partial validator withdrawals) + else if (ethRemaining < fuseIntervalStart) { // solhint-disable-next-line reentrancy consensusRewards += ethRemaining; - emit AccountingBeaconChainRewards(ethRemaining); + emit AccountingConsensusRewards(ethRemaining); } - // Beacon chain rewards swept but also a slashed validator fully exited - else if (ethRemaining >= fuseIntervalEnd) { + // Beacon chain consensus rewards swept but also a slashed validator fully exited + else if (ethRemaining > fuseIntervalEnd) { IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: ethRemaining }(); IWETH9(WETH_TOKEN_ADDRESS).transfer(VAULT_ADDRESS, ethRemaining); activeDepositedValidators -= 1; @@ -209,9 +195,7 @@ abstract contract ValidatorAccountant is ValidatorRegistrator { uint256 _consensusRewards, uint256 _ethThresholdCheck, uint256 _wethThresholdCheck - ) external onlyAccountingGovernor { - require(paused(), "not paused"); - + ) external onlyAccountingGovernor whenPaused { uint256 ethBalance = address(this).balance; uint256 wethBalance = IWETH9(WETH_TOKEN_ADDRESS).balanceOf( address(this) diff --git a/contracts/contracts/strategies/NativeStaking/ValidatorRegistrator.sol b/contracts/contracts/strategies/NativeStaking/ValidatorRegistrator.sol index 27aaaf247c..d609efe6d6 100644 --- a/contracts/contracts/strategies/NativeStaking/ValidatorRegistrator.sol +++ b/contracts/contracts/strategies/NativeStaking/ValidatorRegistrator.sol @@ -4,6 +4,7 @@ pragma solidity ^0.8.0; import { Pausable } from "@openzeppelin/contracts/security/Pausable.sol"; import { Governable } from "../../governance/Governable.sol"; import { IDepositContract } from "../../interfaces/IDepositContract.sol"; +import { IVault } from "../../interfaces/IVault.sol"; import { IWETH9 } from "../../interfaces/IWETH9.sol"; import { ISSVNetwork, Cluster } from "../../interfaces/ISSVNetwork.sol"; @@ -25,6 +26,8 @@ abstract contract ValidatorRegistrator is Governable, Pausable { address public immutable BEACON_CHAIN_DEPOSIT_CONTRACT; /// @notice The address of the SSV Network contract used to interface with address public immutable SSV_NETWORK_ADDRESS; + /// @notice Address of the OETH Vault proxy contract + address public immutable VAULT_ADDRESS; /// @notice Address of the registrator - allowed to register, exit and remove validators address public validatorRegistrator; @@ -45,7 +48,7 @@ abstract contract ValidatorRegistrator is Governable, Pausable { EXIT_COMPLETE // validator has funds withdrawn to the EigenPod and is removed from the SSV } - event RegistratorAddressChanged(address oldAddress, address newAddress); + event RegistratorChanged(address newAddress); event ETHStaked(bytes pubkey, uint256 amount, bytes withdrawal_credentials); event SSVValidatorRegistered(bytes pubkey, uint64[] operatorIds); event SSVValidatorExitInitiated(bytes pubkey, uint64[] operatorIds); @@ -60,22 +63,34 @@ abstract contract ValidatorRegistrator is Governable, Pausable { _; } + /// @dev Throws if called by any account other than the Strategist + modifier onlyStrategist() { + require( + msg.sender == IVault(VAULT_ADDRESS).strategistAddr(), + "Caller is not the Strategist" + ); + _; + } + /// @param _wethAddress Address of the Erc20 WETH Token contract + /// @param _vaultAddress Address of the Vault /// @param _beaconChainDepositContract Address of the beacon chain deposit contract /// @param _ssvNetwork Address of the SSV Network contract constructor( address _wethAddress, + address _vaultAddress, address _beaconChainDepositContract, address _ssvNetwork ) { WETH_TOKEN_ADDRESS = _wethAddress; BEACON_CHAIN_DEPOSIT_CONTRACT = _beaconChainDepositContract; SSV_NETWORK_ADDRESS = _ssvNetwork; + VAULT_ADDRESS = _vaultAddress; } - /// @notice Set the address of the registrator - function setRegistratorAddress(address _address) external onlyGovernor { - emit RegistratorAddressChanged(validatorRegistrator, _address); + /// @notice Set the address of the registrator which can register, exit and remove validators + function setRegistrator(address _address) external onlyGovernor { + emit RegistratorChanged(_address); validatorRegistrator = _address; } @@ -201,4 +216,22 @@ abstract contract ValidatorRegistrator is Governable, Pausable { validatorsStates[keccak256(publicKey)] = VALIDATOR_STATE.EXIT_COMPLETE; } + + /// @notice Deposits more SSV Tokens to the SSV Network contract which is used to pay the SSV Operators. + /// @dev A SSV cluster is defined by the SSVOwnerAddress and the set of operatorIds. + /// uses "onlyStrategist" modifier so continuous front-running can't DOS our maintenance service + /// that tries to top up SSV tokens. + /// @param cluster The SSV cluster details that must be derived from emitted events from the SSVNetwork contract. + function depositSSV( + uint64[] memory operatorIds, + uint256 amount, + Cluster memory cluster + ) external onlyStrategist { + ISSVNetwork(SSV_NETWORK_ADDRESS).deposit( + address(this), + operatorIds, + amount, + cluster + ); + } } diff --git a/contracts/deploy/091_native_ssv_staking.js b/contracts/deploy/091_native_ssv_staking.js index 36e0c3393a..9b4748ad3b 100644 --- a/contracts/deploy/091_native_ssv_staking.js +++ b/contracts/deploy/091_native_ssv_staking.js @@ -11,7 +11,7 @@ module.exports = deploymentWithGovernanceProposal( // "", }, async ({ deployWithConfirmation, ethers, getTxOpts, withConfirmation }) => { - const { deployerAddr, strategistAddr } = await getNamedAccounts(); + const { deployerAddr } = await getNamedAccounts(); const sDeployer = await ethers.provider.getSigner(deployerAddr); // Current contracts @@ -159,12 +159,6 @@ module.exports = deploymentWithGovernanceProposal( signature: "setAccountingGovernor(address)", args: [deployerAddr], // TODO: change this to the defender action }, - // 6. configure strategist address - { - contract: cStrategy, - signature: "setStrategist(address)", - args: [strategistAddr], - }, ], }; } diff --git a/contracts/docs/NativeStakingSSVStrategySquashed.svg b/contracts/docs/NativeStakingSSVStrategySquashed.svg index a12c2db559..392788f64f 100644 --- a/contracts/docs/NativeStakingSSVStrategySquashed.svg +++ b/contracts/docs/NativeStakingSSVStrategySquashed.svg @@ -4,143 +4,142 @@ - - + + UmlClassDiagram - + 280 - -NativeStakingSSVStrategy -../contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol - -Private: -   governorPosition: bytes32 <<Governable>> -   pendingGovernorPosition: bytes32 <<Governable>> -   reentryStatusPosition: bytes32 <<Governable>> -   _paused: bool <<Pausable>> -   __gap: uint256[50] <<ValidatorRegistrator>> -   __gap: uint256[50] <<ValidatorAccountant>> -   initialized: bool <<Initializable>> -   initializing: bool <<Initializable>> -   ______gap: uint256[50] <<Initializable>> -   _deprecated_platformAddress: address <<InitializableAbstractStrategy>> -   _deprecated_vaultAddress: address <<InitializableAbstractStrategy>> -   _deprecated_rewardTokenAddress: address <<InitializableAbstractStrategy>> -   _deprecated_rewardLiquidationThreshold: uint256 <<InitializableAbstractStrategy>> -   _reserved: int256[98] <<InitializableAbstractStrategy>> -   __gap: uint256[50] <<NativeStakingSSVStrategy>> -Internal: -   assetsMapped: address[] <<InitializableAbstractStrategy>> -Public: -   _NOT_ENTERED: uint256 <<Governable>> -   _ENTERED: uint256 <<Governable>> -   WETH_TOKEN_ADDRESS: address <<ValidatorRegistrator>> -   BEACON_CHAIN_DEPOSIT_CONTRACT: address <<ValidatorRegistrator>> -   SSV_NETWORK_ADDRESS: address <<ValidatorRegistrator>> -   validatorRegistrator: address <<ValidatorRegistrator>> -   activeDepositedValidators: uint256 <<ValidatorRegistrator>> -   validatorsStates: mapping(bytes32=>VALIDATOR_STATE) <<ValidatorRegistrator>> -   MAX_STAKE: uint256 <<ValidatorAccountant>> -   VAULT_ADDRESS: address <<ValidatorAccountant>> -   consensusRewards: uint256 <<ValidatorAccountant>> -   fuseIntervalStart: uint256 <<ValidatorAccountant>> -   fuseIntervalEnd: uint256 <<ValidatorAccountant>> -   accountingGovernor: address <<ValidatorAccountant>> -   platformAddress: address <<InitializableAbstractStrategy>> -   vaultAddress: address <<InitializableAbstractStrategy>> -   assetToPToken: mapping(address=>address) <<InitializableAbstractStrategy>> -   harvesterAddress: address <<InitializableAbstractStrategy>> -   rewardTokenAddresses: address[] <<InitializableAbstractStrategy>> -   SSV_TOKEN_ADDRESS: address <<NativeStakingSSVStrategy>> -   FEE_ACCUMULATOR_ADDRESS: address <<NativeStakingSSVStrategy>> - -Internal: -    _governor(): (governorOut: address) <<Governable>> -    _pendingGovernor(): (pendingGovernor: address) <<Governable>> -    _setGovernor(newGovernor: address) <<Governable>> -    _setPendingGovernor(newGovernor: address) <<Governable>> -    _changeGovernor(_newGovernor: address) <<Governable>> -    _msgSender(): address <<Context>> -    _msgData(): bytes <<Context>> -    _pause() <<whenNotPaused>> <<Pausable>> -    _unpause() <<whenPaused>> <<Pausable>> -    _initialize(_rewardTokenAddresses: address[], _assets: address[], _pTokens: address[]) <<InitializableAbstractStrategy>> -    _collectRewardTokens() <<NativeStakingSSVStrategy>> -    _setPTokenAddress(_asset: address, _pToken: address) <<InitializableAbstractStrategy>> -    _abstractSetPToken(_asset: address, address) <<NativeStakingSSVStrategy>> -    _deposit(_asset: address, _amount: uint256) <<NativeStakingSSVStrategy>> -    _withdraw(_recipient: address, _asset: address, _amount: uint256) <<NativeStakingSSVStrategy>> -External: -    <<payable>> null() <<NativeStakingSSVStrategy>> -    transferGovernance(_newGovernor: address) <<onlyGovernor>> <<Governable>> -    claimGovernance() <<Governable>> -    setRegistratorAddress(_address: address) <<onlyGovernor>> <<ValidatorRegistrator>> -    stakeEth(validators: ValidatorStakeData[]) <<onlyRegistrator, whenNotPaused>> <<ValidatorRegistrator>> -    registerSsvValidator(publicKey: bytes, operatorIds: uint64[], sharesData: bytes, amount: uint256, cluster: Cluster) <<onlyRegistrator, whenNotPaused>> <<ValidatorRegistrator>> -    exitSsvValidator(publicKey: bytes, operatorIds: uint64[]) <<onlyRegistrator, whenNotPaused>> <<ValidatorRegistrator>> -    removeSsvValidator(publicKey: bytes, operatorIds: uint64[], cluster: Cluster) <<onlyRegistrator, whenNotPaused>> <<ValidatorRegistrator>> -    setAccountingGovernor(_address: address) <<onlyGovernor>> <<ValidatorAccountant>> -    setFuseInterval(_fuseIntervalStart: uint256, _fuseIntervalEnd: uint256) <<onlyGovernor>> <<ValidatorAccountant>> -    doAccounting(): (accountingValid: bool) <<onlyRegistrator>> <<ValidatorAccountant>> -    manuallyFixAccounting(_activeDepositedValidators: uint256, _ethToWeth: uint256, _wethToBeSentToVault: uint256, _consensusRewards: uint256, _ethThresholdCheck: uint256, _wethThresholdCheck: uint256) <<onlyAccountingGovernor>> <<ValidatorAccountant>> -    collectRewardTokens() <<onlyHarvester, nonReentrant>> <<InitializableAbstractStrategy>> -    setRewardTokenAddresses(_rewardTokenAddresses: address[]) <<onlyGovernor>> <<InitializableAbstractStrategy>> -    getRewardTokenAddresses(): address[] <<InitializableAbstractStrategy>> -    setPTokenAddress(_asset: address, _pToken: address) <<onlyGovernor>> <<InitializableAbstractStrategy>> -    removePToken(_assetIndex: uint256) <<onlyGovernor>> <<InitializableAbstractStrategy>> -    setHarvesterAddress(_harvesterAddress: address) <<onlyGovernor>> <<InitializableAbstractStrategy>> -    safeApproveAllTokens() <<NativeStakingSSVStrategy>> -    deposit(_asset: address, _amount: uint256) <<onlyVault, nonReentrant>> <<NativeStakingSSVStrategy>> -    depositAll() <<onlyVault, nonReentrant>> <<NativeStakingSSVStrategy>> -    withdraw(_recipient: address, _asset: address, _amount: uint256) <<onlyVault, nonReentrant>> <<NativeStakingSSVStrategy>> -    withdrawAll() <<onlyVaultOrGovernor, nonReentrant>> <<NativeStakingSSVStrategy>> -    checkBalance(_asset: address): (balance: uint256) <<NativeStakingSSVStrategy>> -    initialize(_rewardTokenAddresses: address[], _assets: address[], _pTokens: address[]) <<onlyGovernor, initializer>> <<NativeStakingSSVStrategy>> -    pause() <<onlyStrategist>> <<NativeStakingSSVStrategy>> -    depositSSV(operatorIds: uint64[], amount: uint256, cluster: Cluster) <<onlyStrategist>> <<NativeStakingSSVStrategy>> -Public: -    <<event>> PendingGovernorshipTransfer(previousGovernor: address, newGovernor: address) <<Governable>> -    <<event>> GovernorshipTransferred(previousGovernor: address, newGovernor: address) <<Governable>> -    <<event>> Paused(account: address) <<Pausable>> -    <<event>> Unpaused(account: address) <<Pausable>> -    <<event>> RegistratorAddressChanged(oldAddress: address, newAddress: address) <<ValidatorRegistrator>> -    <<event>> ETHStaked(pubkey: bytes, amount: uint256, withdrawal_credentials: bytes) <<ValidatorRegistrator>> -    <<event>> SSVValidatorRegistered(pubkey: bytes, operatorIds: uint64[]) <<ValidatorRegistrator>> -    <<event>> SSVValidatorExitInitiated(pubkey: bytes, operatorIds: uint64[]) <<ValidatorRegistrator>> -    <<event>> SSVValidatorExitCompleted(pubkey: bytes, operatorIds: uint64[]) <<ValidatorRegistrator>> -    <<event>> FuseIntervalUpdated(oldStart: uint256, oldEnd: uint256, start: uint256, end: uint256) <<ValidatorAccountant>> -    <<event>> AccountingFullyWithdrawnValidator(noOfValidators: uint256, remainingValidators: uint256, wethSentToVault: uint256) <<ValidatorAccountant>> -    <<event>> AccountingValidatorSlashed(remainingValidators: uint256, wethSentToVault: uint256) <<ValidatorAccountant>> -    <<event>> AccountingGovernorAddressChanged(oldAddress: address, newAddress: address) <<ValidatorAccountant>> -    <<event>> AccountingBeaconChainRewards(amount: uint256) <<ValidatorAccountant>> -    <<event>> AccountingManuallyFixed(oldActiveDepositedValidators: uint256, activeDepositedValidators: uint256, oldBeaconChainRewards: uint256, beaconChainRewards: uint256, ethToWeth: uint256, wethToBeSentToVault: uint256) <<ValidatorAccountant>> -    <<event>> PTokenAdded(_asset: address, _pToken: address) <<InitializableAbstractStrategy>> -    <<event>> PTokenRemoved(_asset: address, _pToken: address) <<InitializableAbstractStrategy>> -    <<event>> Deposit(_asset: address, _pToken: address, _amount: uint256) <<InitializableAbstractStrategy>> -    <<event>> Withdrawal(_asset: address, _pToken: address, _amount: uint256) <<InitializableAbstractStrategy>> -    <<event>> RewardTokenCollected(recipient: address, rewardToken: address, amount: uint256) <<InitializableAbstractStrategy>> -    <<event>> RewardTokenAddressesUpdated(_oldAddresses: address[], _newAddresses: address[]) <<InitializableAbstractStrategy>> -    <<event>> HarvesterAddressesUpdated(_oldHarvesterAddress: address, _newHarvesterAddress: address) <<InitializableAbstractStrategy>> -    <<modifier>> onlyGovernor() <<Governable>> -    <<modifier>> nonReentrant() <<Governable>> -    <<modifier>> whenNotPaused() <<Pausable>> -    <<modifier>> whenPaused() <<Pausable>> -    <<modifier>> onlyRegistrator() <<ValidatorRegistrator>> -    <<modifier>> onlyAccountingGovernor() <<ValidatorAccountant>> -    <<modifier>> onlyStrategist() <<ValidatorAccountant>> -    <<modifier>> initializer() <<Initializable>> -    <<modifier>> onlyVault() <<InitializableAbstractStrategy>> -    <<modifier>> onlyHarvester() <<InitializableAbstractStrategy>> -    <<modifier>> onlyVaultOrGovernor() <<InitializableAbstractStrategy>> -    <<modifier>> onlyVaultOrGovernorOrStrategist() <<InitializableAbstractStrategy>> -    constructor() <<Pausable>> -    governor(): address <<Governable>> -    isGovernor(): bool <<Governable>> -    paused(): bool <<Pausable>> -    constructor(_wethAddress: address, _beaconChainDepositContract: address, _ssvNetwork: address) <<ValidatorRegistrator>> + +NativeStakingSSVStrategy +../contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol + +Private: +   governorPosition: bytes32 <<Governable>> +   pendingGovernorPosition: bytes32 <<Governable>> +   reentryStatusPosition: bytes32 <<Governable>> +   _paused: bool <<Pausable>> +   __gap: uint256[50] <<ValidatorRegistrator>> +   __gap: uint256[50] <<ValidatorAccountant>> +   initialized: bool <<Initializable>> +   initializing: bool <<Initializable>> +   ______gap: uint256[50] <<Initializable>> +   _deprecated_platformAddress: address <<InitializableAbstractStrategy>> +   _deprecated_vaultAddress: address <<InitializableAbstractStrategy>> +   _deprecated_rewardTokenAddress: address <<InitializableAbstractStrategy>> +   _deprecated_rewardLiquidationThreshold: uint256 <<InitializableAbstractStrategy>> +   _reserved: int256[98] <<InitializableAbstractStrategy>> +   __gap: uint256[50] <<NativeStakingSSVStrategy>> +Internal: +   assetsMapped: address[] <<InitializableAbstractStrategy>> +Public: +   _NOT_ENTERED: uint256 <<Governable>> +   _ENTERED: uint256 <<Governable>> +   WETH_TOKEN_ADDRESS: address <<ValidatorRegistrator>> +   BEACON_CHAIN_DEPOSIT_CONTRACT: address <<ValidatorRegistrator>> +   SSV_NETWORK_ADDRESS: address <<ValidatorRegistrator>> +   VAULT_ADDRESS: address <<ValidatorRegistrator>> +   validatorRegistrator: address <<ValidatorRegistrator>> +   activeDepositedValidators: uint256 <<ValidatorRegistrator>> +   validatorsStates: mapping(bytes32=>VALIDATOR_STATE) <<ValidatorRegistrator>> +   MAX_STAKE: uint256 <<ValidatorAccountant>> +   consensusRewards: uint256 <<ValidatorAccountant>> +   fuseIntervalStart: uint256 <<ValidatorAccountant>> +   fuseIntervalEnd: uint256 <<ValidatorAccountant>> +   accountingGovernor: address <<ValidatorAccountant>> +   platformAddress: address <<InitializableAbstractStrategy>> +   vaultAddress: address <<InitializableAbstractStrategy>> +   assetToPToken: mapping(address=>address) <<InitializableAbstractStrategy>> +   harvesterAddress: address <<InitializableAbstractStrategy>> +   rewardTokenAddresses: address[] <<InitializableAbstractStrategy>> +   SSV_TOKEN_ADDRESS: address <<NativeStakingSSVStrategy>> +   FEE_ACCUMULATOR_ADDRESS: address <<NativeStakingSSVStrategy>> + +Internal: +    _governor(): (governorOut: address) <<Governable>> +    _pendingGovernor(): (pendingGovernor: address) <<Governable>> +    _setGovernor(newGovernor: address) <<Governable>> +    _setPendingGovernor(newGovernor: address) <<Governable>> +    _changeGovernor(_newGovernor: address) <<Governable>> +    _msgSender(): address <<Context>> +    _msgData(): bytes <<Context>> +    _pause() <<whenNotPaused>> <<Pausable>> +    _unpause() <<whenPaused>> <<Pausable>> +    _initialize(_rewardTokenAddresses: address[], _assets: address[], _pTokens: address[]) <<InitializableAbstractStrategy>> +    _collectRewardTokens() <<whenNotPaused>> <<NativeStakingSSVStrategy>> +    _setPTokenAddress(_asset: address, _pToken: address) <<InitializableAbstractStrategy>> +    _abstractSetPToken(_asset: address, address) <<NativeStakingSSVStrategy>> +    _deposit(_asset: address, _amount: uint256) <<NativeStakingSSVStrategy>> +    _withdraw(_recipient: address, _asset: address, _amount: uint256) <<NativeStakingSSVStrategy>> +External: +    <<payable>> null() <<NativeStakingSSVStrategy>> +    transferGovernance(_newGovernor: address) <<onlyGovernor>> <<Governable>> +    claimGovernance() <<Governable>> +    setRegistrator(_address: address) <<onlyGovernor>> <<ValidatorRegistrator>> +    stakeEth(validators: ValidatorStakeData[]) <<onlyRegistrator, whenNotPaused>> <<ValidatorRegistrator>> +    registerSsvValidator(publicKey: bytes, operatorIds: uint64[], sharesData: bytes, amount: uint256, cluster: Cluster) <<onlyRegistrator, whenNotPaused>> <<ValidatorRegistrator>> +    exitSsvValidator(publicKey: bytes, operatorIds: uint64[]) <<onlyRegistrator, whenNotPaused>> <<ValidatorRegistrator>> +    removeSsvValidator(publicKey: bytes, operatorIds: uint64[], cluster: Cluster) <<onlyRegistrator, whenNotPaused>> <<ValidatorRegistrator>> +    depositSSV(operatorIds: uint64[], amount: uint256, cluster: Cluster) <<onlyStrategist>> <<ValidatorRegistrator>> +    setAccountingGovernor(_address: address) <<onlyGovernor>> <<ValidatorAccountant>> +    setFuseInterval(_fuseIntervalStart: uint256, _fuseIntervalEnd: uint256) <<onlyGovernor>> <<ValidatorAccountant>> +    doAccounting(): (accountingValid: bool) <<onlyRegistrator, whenNotPaused>> <<ValidatorAccountant>> +    manuallyFixAccounting(_activeDepositedValidators: uint256, _ethToWeth: uint256, _wethToBeSentToVault: uint256, _consensusRewards: uint256, _ethThresholdCheck: uint256, _wethThresholdCheck: uint256) <<onlyAccountingGovernor, whenPaused>> <<ValidatorAccountant>> +    collectRewardTokens() <<onlyHarvester, nonReentrant>> <<InitializableAbstractStrategy>> +    setRewardTokenAddresses(_rewardTokenAddresses: address[]) <<onlyGovernor>> <<InitializableAbstractStrategy>> +    getRewardTokenAddresses(): address[] <<InitializableAbstractStrategy>> +    setPTokenAddress(_asset: address, _pToken: address) <<onlyGovernor>> <<InitializableAbstractStrategy>> +    removePToken(_assetIndex: uint256) <<onlyGovernor>> <<InitializableAbstractStrategy>> +    setHarvesterAddress(_harvesterAddress: address) <<onlyGovernor>> <<InitializableAbstractStrategy>> +    safeApproveAllTokens() <<NativeStakingSSVStrategy>> +    deposit(_asset: address, _amount: uint256) <<onlyVault, nonReentrant>> <<NativeStakingSSVStrategy>> +    depositAll() <<onlyVault, nonReentrant>> <<NativeStakingSSVStrategy>> +    withdraw(_recipient: address, _asset: address, _amount: uint256) <<onlyVault, nonReentrant>> <<NativeStakingSSVStrategy>> +    withdrawAll() <<onlyVaultOrGovernor, nonReentrant>> <<NativeStakingSSVStrategy>> +    checkBalance(_asset: address): (balance: uint256) <<NativeStakingSSVStrategy>> +    initialize(_rewardTokenAddresses: address[], _assets: address[], _pTokens: address[]) <<onlyGovernor, initializer>> <<NativeStakingSSVStrategy>> +    pause() <<onlyStrategist>> <<NativeStakingSSVStrategy>> +Public: +    <<event>> PendingGovernorshipTransfer(previousGovernor: address, newGovernor: address) <<Governable>> +    <<event>> GovernorshipTransferred(previousGovernor: address, newGovernor: address) <<Governable>> +    <<event>> Paused(account: address) <<Pausable>> +    <<event>> Unpaused(account: address) <<Pausable>> +    <<event>> RegistratorChanged(newAddress: address) <<ValidatorRegistrator>> +    <<event>> ETHStaked(pubkey: bytes, amount: uint256, withdrawal_credentials: bytes) <<ValidatorRegistrator>> +    <<event>> SSVValidatorRegistered(pubkey: bytes, operatorIds: uint64[]) <<ValidatorRegistrator>> +    <<event>> SSVValidatorExitInitiated(pubkey: bytes, operatorIds: uint64[]) <<ValidatorRegistrator>> +    <<event>> SSVValidatorExitCompleted(pubkey: bytes, operatorIds: uint64[]) <<ValidatorRegistrator>> +    <<event>> FuseIntervalUpdated(start: uint256, end: uint256) <<ValidatorAccountant>> +    <<event>> AccountingFullyWithdrawnValidator(noOfValidators: uint256, remainingValidators: uint256, wethSentToVault: uint256) <<ValidatorAccountant>> +    <<event>> AccountingValidatorSlashed(remainingValidators: uint256, wethSentToVault: uint256) <<ValidatorAccountant>> +    <<event>> AccountingGovernorChanged(newAddress: address) <<ValidatorAccountant>> +    <<event>> AccountingConsensusRewards(amount: uint256) <<ValidatorAccountant>> +    <<event>> AccountingManuallyFixed(oldActiveDepositedValidators: uint256, activeDepositedValidators: uint256, oldBeaconChainRewards: uint256, beaconChainRewards: uint256, ethToWeth: uint256, wethToBeSentToVault: uint256) <<ValidatorAccountant>> +    <<event>> PTokenAdded(_asset: address, _pToken: address) <<InitializableAbstractStrategy>> +    <<event>> PTokenRemoved(_asset: address, _pToken: address) <<InitializableAbstractStrategy>> +    <<event>> Deposit(_asset: address, _pToken: address, _amount: uint256) <<InitializableAbstractStrategy>> +    <<event>> Withdrawal(_asset: address, _pToken: address, _amount: uint256) <<InitializableAbstractStrategy>> +    <<event>> RewardTokenCollected(recipient: address, rewardToken: address, amount: uint256) <<InitializableAbstractStrategy>> +    <<event>> RewardTokenAddressesUpdated(_oldAddresses: address[], _newAddresses: address[]) <<InitializableAbstractStrategy>> +    <<event>> HarvesterAddressesUpdated(_oldHarvesterAddress: address, _newHarvesterAddress: address) <<InitializableAbstractStrategy>> +    <<modifier>> onlyGovernor() <<Governable>> +    <<modifier>> nonReentrant() <<Governable>> +    <<modifier>> whenNotPaused() <<Pausable>> +    <<modifier>> whenPaused() <<Pausable>> +    <<modifier>> onlyRegistrator() <<ValidatorRegistrator>> +    <<modifier>> onlyStrategist() <<ValidatorRegistrator>> +    <<modifier>> onlyAccountingGovernor() <<ValidatorAccountant>> +    <<modifier>> initializer() <<Initializable>> +    <<modifier>> onlyVault() <<InitializableAbstractStrategy>> +    <<modifier>> onlyHarvester() <<InitializableAbstractStrategy>> +    <<modifier>> onlyVaultOrGovernor() <<InitializableAbstractStrategy>> +    <<modifier>> onlyVaultOrGovernorOrStrategist() <<InitializableAbstractStrategy>> +    constructor() <<Pausable>> +    governor(): address <<Governable>> +    isGovernor(): bool <<Governable>> +    paused(): bool <<Pausable>>    constructor(_wethAddress: address, _vaultAddress: address, _beaconChainDepositContract: address, _ssvNetwork: address) <<ValidatorAccountant>>    constructor(_config: BaseStrategyConfig) <<InitializableAbstractStrategy>>    transferToken(_asset: address, _amount: uint256) <<onlyGovernor>> <<InitializableAbstractStrategy>> diff --git a/contracts/test/_fixture.js b/contracts/test/_fixture.js index f969368877..91714bc6f2 100644 --- a/contracts/test/_fixture.js +++ b/contracts/test/_fixture.js @@ -1430,10 +1430,7 @@ async function nativeStakingSSVStrategyFixture() { .connect(sGovernor) .approveStrategy(nativeStakingSSVStrategy.address); - console.log( - "nativeStakingSSVStrategy.address", - nativeStakingSSVStrategy.address - ); + log("nativeStakingSSVStrategy.address", nativeStakingSSVStrategy.address); const fuseStartBn = ethers.utils.parseEther("21.6"); const fuseEndBn = ethers.utils.parseEther("25.6"); @@ -1449,7 +1446,7 @@ async function nativeStakingSSVStrategyFixture() { await nativeStakingSSVStrategy .connect(sGovernor) - .setRegistratorAddress(governorAddr); + .setRegistrator(governorAddr); await nativeStakingSSVStrategy .connect(sGovernor) diff --git a/contracts/test/strategies/nativeSSVStaking.js b/contracts/test/strategies/nativeSSVStaking.js index dafaed2aff..c176d3fea3 100644 --- a/contracts/test/strategies/nativeSSVStaking.js +++ b/contracts/test/strategies/nativeSSVStaking.js @@ -1,6 +1,6 @@ const { expect } = require("chai"); const { BigNumber } = require("ethers"); -const { formatUnits, parseEther } = require("ethers").utils; +const { parseEther } = require("ethers").utils; const { setBalance } = require("@nomicfoundation/hardhat-network-helpers"); const { isCI } = require("../helpers"); @@ -49,7 +49,7 @@ describe("Unit test: Native SSV Staking Strategy", function () { })); describe("Initial setup", function () { - it("Should not allow sending of ETH to the strategy via a transaction", async () => { + it("Should not allow ETH to be sent to the strategy if not Fee Accumulator", async () => { const { nativeStakingSSVStrategy, strategist } = fixture; const signer = nativeStakingSSVStrategy.provider.getSigner( @@ -82,21 +82,11 @@ describe("Unit test: Native SSV Staking Strategy", function () { const tx = await nativeStakingSSVStrategy .connect(governor) - .setRegistratorAddress(strategist.address); + .setRegistrator(strategist.address); - const events = (await tx.wait()).events || []; - const RegistratorAddressChangedEvent = events.find( - (e) => e.event === "RegistratorAddressChanged" - ); - - expect(RegistratorAddressChangedEvent).to.not.be.undefined; - expect(RegistratorAddressChangedEvent.event).to.equal( - "RegistratorAddressChanged" - ); - expect(RegistratorAddressChangedEvent.args[0]).to.equal(governor.address); - expect(RegistratorAddressChangedEvent.args[1]).to.equal( - strategist.address - ); + await expect(tx) + .to.emit(nativeStakingSSVStrategy, "RegistratorChanged") + .withArgs(strategist.address); }); it("Non governor should not be able to change the registrator address", async () => { @@ -105,7 +95,7 @@ describe("Unit test: Native SSV Staking Strategy", function () { await expect( nativeStakingSSVStrategy .connect(strategist) - .setRegistratorAddress(strategist.address) + .setRegistrator(strategist.address) ).to.be.revertedWith("Caller is not the Governor"); }); @@ -152,8 +142,6 @@ describe("Unit test: Native SSV Staking Strategy", function () { it("Governor should be able to change fuse interval", async () => { const { nativeStakingSSVStrategy, governor } = fixture; - const oldFuseStartBn = parseEther("21.6"); - const oldFuseEndBn = parseEther("25.6"); const fuseStartBn = parseEther("22.6"); const fuseEndBn = parseEther("26.6"); @@ -161,17 +149,9 @@ describe("Unit test: Native SSV Staking Strategy", function () { .connect(governor) .setFuseInterval(fuseStartBn, fuseEndBn); - const events = (await tx.wait()).events || []; - const FuseIntervalUpdated = events.find( - (e) => e.event === "FuseIntervalUpdated" - ); - - expect(FuseIntervalUpdated).to.not.be.undefined; - expect(FuseIntervalUpdated.event).to.equal("FuseIntervalUpdated"); - expect(FuseIntervalUpdated.args[0]).to.equal(oldFuseStartBn); // prev fuse start - expect(FuseIntervalUpdated.args[1]).to.equal(oldFuseEndBn); // prev fuse end - expect(FuseIntervalUpdated.args[2]).to.equal(fuseStartBn); // fuse start - expect(FuseIntervalUpdated.args[3]).to.equal(fuseEndBn); // fuse end + await expect(tx) + .to.emit(nativeStakingSSVStrategy, "FuseIntervalUpdated") + .withArgs(fuseStartBn, fuseEndBn); }); it("Only accounting governor can call accounting", async () => {}); @@ -193,169 +173,373 @@ describe("Unit test: Native SSV Staking Strategy", function () { .connect(governor) .setAccountingGovernor(strategist.address); - const events = (await tx.wait()).events || []; - const AccountingGovernorChangedEvent = events.find( - (e) => e.event === "AccountingGovernorAddressChanged" - ); - - expect(AccountingGovernorChangedEvent).to.not.be.undefined; - expect(AccountingGovernorChangedEvent.event).to.equal( - "AccountingGovernorAddressChanged" - ); - expect(AccountingGovernorChangedEvent.args[0]).to.equal(governor.address); - expect(AccountingGovernorChangedEvent.args[1]).to.equal( - strategist.address - ); + await expect(tx) + .to.emit(nativeStakingSSVStrategy, "AccountingGovernorChanged") + .withArgs(strategist.address); }); }); describe("Accounting", function () { - const testCases = [ - // normal beacon chain rewards - { - ethBalance: parseEther("14"), - expectedRewards: parseEther("14"), - expectedValidatorsFullWithdrawals: 0, - slashDetected: false, - fuseBlown: false, - }, - // normal beacon chain rewards + 1 withdrawn validator - { - ethBalance: parseEther("34"), - expectedRewards: parseEther("2"), - expectedValidatorsFullWithdrawals: 1, - slashDetected: false, - fuseBlown: false, - }, - // 8 withdrawn validators + beacon chain rewards - { - ethBalance: parseEther("276"), - expectedRewards: parseEther("20"), - expectedValidatorsFullWithdrawals: 8, - slashDetected: false, - fuseBlown: false, - }, - // fuse blown - { - ethBalance: parseEther("22"), - expectedRewards: parseEther("0"), - expectedValidatorsFullWithdrawals: 0, - slashDetected: false, - fuseBlown: true, - }, - // fuse blown + 1 full withdrawal - { - ethBalance: parseEther("54"), - expectedRewards: parseEther("0"), - expectedValidatorsFullWithdrawals: 1, - slashDetected: false, - fuseBlown: true, - }, - // 1 validator slashed - { - ethBalance: parseEther("26.6"), - expectedRewards: parseEther("0"), - expectedValidatorsFullWithdrawals: 0, - slashDetected: true, - fuseBlown: false, - }, - // 1 validator fully withdrawn + 1 slashed - { - ethBalance: parseEther("58.6"), // 26.6 + 32 - expectedRewards: parseEther("0"), - expectedValidatorsFullWithdrawals: 1, - slashDetected: true, - fuseBlown: false, - }, - ]; - - for (const testCase of testCases) { - const { - ethBalance, - expectedRewards, - expectedValidatorsFullWithdrawals, - slashDetected, - fuseBlown, - } = testCase; - it(`Expect that ${formatUnits( - ethBalance - )} ETH will result in ${formatUnits( - expectedRewards - )} ETH rewards and ${expectedValidatorsFullWithdrawals} validators withdrawn.`, async () => { - const { nativeStakingSSVStrategy, governor, strategist } = fixture; - - // setup state - await setBalance(nativeStakingSSVStrategy.address, ethBalance); - // pause, so manuallyFixAccounting can be called - await nativeStakingSSVStrategy.connect(strategist).pause(); - await nativeStakingSSVStrategy.connect(governor).manuallyFixAccounting( - 30, // activeDepositedValidators - parseEther("0", "ether"), //_ethToWeth - parseEther("0", "ether"), //_wethToBeSentToVault - parseEther("0", "ether"), //_beaconChainRewardWETH - parseEther("3000", "ether"), //_ethThresholdCheck - parseEther("3000", "ether") //_wethThresholdCheck + describe("Should account for beacon chain ETH", function () { + // fuseStart 21.6 + // fuseEnd 25.6 + + const testCases = [ + // no new rewards + { + ethBalance: 0, + previousConsensusRewards: 0, + expectedConsensusRewards: 0, + expectedValidatorsFullWithdrawals: 0, + slashDetected: false, + fuseBlown: false, + }, + // no new rewards on previous rewards + { + ethBalance: 0.001, + previousConsensusRewards: 0.001, + expectedConsensusRewards: 0, + expectedValidatorsFullWithdrawals: 0, + slashDetected: false, + fuseBlown: false, + }, + // invalid eth balance + { + ethBalance: 1.9, + previousConsensusRewards: 2, + expectedConsensusRewards: 0, + expectedValidatorsFullWithdrawals: 0, + slashDetected: false, + fuseBlown: true, + }, + // tiny consensus rewards + { + ethBalance: 0.001, + previousConsensusRewards: 0, + expectedConsensusRewards: 0.001, + expectedValidatorsFullWithdrawals: 0, + slashDetected: false, + fuseBlown: false, + }, + // tiny consensus rewards on small previous rewards + { + ethBalance: 0.03, + previousConsensusRewards: 0.02, + expectedConsensusRewards: 0.01, + expectedValidatorsFullWithdrawals: 0, + slashDetected: false, + fuseBlown: false, + }, + // tiny consensus rewards on large previous rewards + { + ethBalance: 5.04, + previousConsensusRewards: 5, + expectedConsensusRewards: 0.04, + expectedValidatorsFullWithdrawals: 0, + slashDetected: false, + fuseBlown: false, + }, + // large consensus rewards + { + ethBalance: 14, + previousConsensusRewards: 0, + expectedConsensusRewards: 14, + expectedValidatorsFullWithdrawals: 0, + slashDetected: false, + fuseBlown: false, + }, + // just under fuse start + { + ethBalance: 21.5, + previousConsensusRewards: 0, + expectedConsensusRewards: 21.5, + expectedValidatorsFullWithdrawals: 0, + slashDetected: false, + fuseBlown: false, + }, + // exactly fuse start + { + ethBalance: 21.6, + previousConsensusRewards: 0, + expectedConsensusRewards: 0, + expectedValidatorsFullWithdrawals: 0, + slashDetected: false, + fuseBlown: true, + }, + // fuse blown + { + ethBalance: 22, + previousConsensusRewards: 0, + expectedConsensusRewards: 0, + expectedValidatorsFullWithdrawals: 0, + slashDetected: false, + fuseBlown: true, + }, + // just under fuse end + { + ethBalance: 25.5, + previousConsensusRewards: 0, + expectedConsensusRewards: 0, + expectedValidatorsFullWithdrawals: 0, + slashDetected: false, + fuseBlown: true, + }, + // exactly fuse end + { + ethBalance: 25.6, + previousConsensusRewards: 0, + expectedConsensusRewards: 0, + expectedValidatorsFullWithdrawals: 0, + slashDetected: false, + fuseBlown: true, + }, + // just over fuse end + { + ethBalance: 25.7, + previousConsensusRewards: 0, + expectedConsensusRewards: 0, + expectedValidatorsFullWithdrawals: 0, + slashDetected: true, + fuseBlown: false, + }, + // 1 validator slashed + { + ethBalance: 26.6, + previousConsensusRewards: 0, + expectedConsensusRewards: 0, + expectedValidatorsFullWithdrawals: 0, + slashDetected: true, + fuseBlown: false, + }, + // no consensus rewards, 1 slashed validator + { + ethBalance: 31.9, + previousConsensusRewards: 0, + expectedConsensusRewards: 0, + expectedValidatorsFullWithdrawals: 0, + slashDetected: true, + fuseBlown: false, + }, + // no consensus rewards, 1 validator fully withdrawn + { + ethBalance: 32, + previousConsensusRewards: 0, + expectedConsensusRewards: 0, + expectedValidatorsFullWithdrawals: 1, + slashDetected: false, + fuseBlown: false, + }, + // tiny consensus rewards + 1 withdrawn validator + { + ethBalance: 32.01, + previousConsensusRewards: 0, + expectedConsensusRewards: 0.01, + expectedValidatorsFullWithdrawals: 1, + slashDetected: false, + fuseBlown: false, + }, + // consensus rewards on previous rewards > 32 + { + ethBalance: 33, + previousConsensusRewards: 32.3, + expectedConsensusRewards: 0.7, + expectedValidatorsFullWithdrawals: 0, + slashDetected: false, + fuseBlown: false, + }, + // large consensus rewards + 1 withdrawn validator + { + ethBalance: 34, + previousConsensusRewards: 0, + expectedConsensusRewards: 2, + expectedValidatorsFullWithdrawals: 1, + slashDetected: false, + fuseBlown: false, + }, + // large consensus rewards on large previous rewards + { + ethBalance: 44, + previousConsensusRewards: 24, + expectedConsensusRewards: 20, + expectedValidatorsFullWithdrawals: 0, + slashDetected: false, + fuseBlown: false, + }, + // fuse blown + 1 withdrawn validator + { + ethBalance: 54, + previousConsensusRewards: 0, + expectedConsensusRewards: 0, + expectedValidatorsFullWithdrawals: 1, + slashDetected: false, + fuseBlown: true, + }, + // fuse blown + 1 withdrawn validator with previous rewards + { + ethBalance: 55, + previousConsensusRewards: 1, + expectedConsensusRewards: 0, + expectedValidatorsFullWithdrawals: 1, + slashDetected: false, + fuseBlown: true, + }, + // 1 validator fully withdrawn + 1 slashed + { + ethBalance: 58.6, // 26.6 + 32 + previousConsensusRewards: 0, + expectedConsensusRewards: 0, + expectedValidatorsFullWithdrawals: 1, + slashDetected: true, + fuseBlown: false, + }, + // 2 full withdraws + { + ethBalance: 64, + previousConsensusRewards: 0, + expectedConsensusRewards: 0, + expectedValidatorsFullWithdrawals: 2, + slashDetected: false, + fuseBlown: false, + }, + // tiny consensus rewards + 2 withdrawn validators + { + ethBalance: 64.1, + previousConsensusRewards: 0, + expectedConsensusRewards: 0.1, + expectedValidatorsFullWithdrawals: 2, + slashDetected: false, + fuseBlown: false, + }, + // 2 full withdraws on previous rewards + { + ethBalance: 66, + previousConsensusRewards: 2, + expectedConsensusRewards: 0, + expectedValidatorsFullWithdrawals: 2, + slashDetected: false, + fuseBlown: false, + }, + // consensus rewards on large previous rewards + { + ethBalance: 66, + previousConsensusRewards: 65, + expectedConsensusRewards: 1, + expectedValidatorsFullWithdrawals: 0, + slashDetected: false, + fuseBlown: false, + }, + // consensus rewards on large previous rewards with withdraw + { + ethBalance: 100, + previousConsensusRewards: 65, + expectedConsensusRewards: 3, + expectedValidatorsFullWithdrawals: 1, + slashDetected: false, + fuseBlown: false, + }, + // 8 withdrawn validators + consensus rewards + { + ethBalance: 276, + previousConsensusRewards: 0, + expectedConsensusRewards: 20, + expectedValidatorsFullWithdrawals: 8, + slashDetected: false, + fuseBlown: false, + }, + ]; + + for (const testCase of testCases) { + const { expectedValidatorsFullWithdrawals, slashDetected, fuseBlown } = + testCase; + const ethBalance = parseEther(testCase.ethBalance.toString()); + const previousConsensusRewards = parseEther( + testCase.previousConsensusRewards.toString() + ); + const expectedConsensusRewards = parseEther( + testCase.expectedConsensusRewards.toString() ); - // check accounting values - const tx = await nativeStakingSSVStrategy - .connect(governor) - .doAccounting(); + it(`given ${testCase.ethBalance} ETH balance and ${ + testCase.previousConsensusRewards + } previous consensus rewards, then ${ + testCase.expectedConsensusRewards + } consensus rewards, ${expectedValidatorsFullWithdrawals} withdraws${ + fuseBlown ? ", fuse blown" : "" + }${slashDetected ? ", slash detected" : ""}.`, async () => { + const { nativeStakingSSVStrategy, governor, strategist } = fixture; - const events = (await tx.wait()).events || []; + // setup state + if (ethBalance.gt(0)) { + await setBalance(nativeStakingSSVStrategy.address, ethBalance); + } + // pause, so manuallyFixAccounting can be called + await nativeStakingSSVStrategy.connect(strategist).pause(); + await nativeStakingSSVStrategy + .connect(governor) + .manuallyFixAccounting( + 30, // activeDepositedValidators + 0, //_ethToWeth + 0, //_wethToBeSentToVault + previousConsensusRewards, //_consensusRewards + parseEther("3000"), //_ethThresholdCheck + parseEther("3000") //_wethThresholdCheck + ); - const BeaconRewardsEvent = events.find( - (e) => e.event === "AccountingBeaconChainRewards" - ); - if (expectedRewards.gt(BigNumber.from("0"))) { - expect(BeaconRewardsEvent).to.not.be.undefined; - expect(BeaconRewardsEvent.args[0]).to.equal(expectedRewards); - } else { - expect(BeaconRewardsEvent).to.be.undefined; - } - - const WithdrawnEvent = events.find( - (e) => e.event === "AccountingFullyWithdrawnValidator" - ); - if (expectedValidatorsFullWithdrawals > 0) { - expect(WithdrawnEvent).to.not.be.undefined; - expect(WithdrawnEvent.args[0]).to.equal( - BigNumber.from(`${expectedValidatorsFullWithdrawals}`) - ); - // still active validators - expect(WithdrawnEvent.args[1]).to.equal( - BigNumber.from(`${30 - expectedValidatorsFullWithdrawals}`) - ); - // weth sent to vault - expect(WithdrawnEvent.args[2]).to.equal( - parseEther("32").mul( - BigNumber.from(`${expectedValidatorsFullWithdrawals}`) - ) - ); - } else { - expect(WithdrawnEvent).to.be.undefined; - } - - const PausedEvent = events.find((e) => e.event === "Paused"); - if (fuseBlown) { - expect(PausedEvent).to.not.be.undefined; - } else { - expect(PausedEvent).to.be.undefined; - } - - const SlashEvent = events.find( - (e) => e.event === "AccountingValidatorSlashed" - ); - if (slashDetected) { - expect(SlashEvent).to.not.be.undefined; - expect(SlashEvent.args[0]).to.equal( - BigNumber.from(`${30 - expectedValidatorsFullWithdrawals - 1}`) - ); - } else { - expect(SlashEvent).to.be.undefined; - } - }); - } + // check accounting values + const tx = await nativeStakingSSVStrategy + .connect(governor) + .doAccounting(); + + if (expectedConsensusRewards.gt(BigNumber.from("0"))) { + await expect(tx) + .to.emit(nativeStakingSSVStrategy, "AccountingConsensusRewards") + .withArgs(expectedConsensusRewards); + } else { + await expect(tx).to.not.emit( + nativeStakingSSVStrategy, + "AccountingConsensusRewards" + ); + } + + if (expectedValidatorsFullWithdrawals > 0) { + await expect(tx) + .to.emit( + nativeStakingSSVStrategy, + "AccountingFullyWithdrawnValidator" + ) + .withArgs( + expectedValidatorsFullWithdrawals, + 30 - expectedValidatorsFullWithdrawals, + parseEther("32").mul(expectedValidatorsFullWithdrawals) + ); + } else { + await expect(tx).to.not.emit( + nativeStakingSSVStrategy, + "AccountingFullyWithdrawnValidator" + ); + } + + if (fuseBlown) { + await expect(tx).to.emit(nativeStakingSSVStrategy, "Paused"); + } else { + await expect(tx).to.not.emit(nativeStakingSSVStrategy, "Paused"); + } + + if (slashDetected) { + await expect(tx) + .to.emit(nativeStakingSSVStrategy, "AccountingValidatorSlashed") + .withNamedArgs({ + remainingValidators: 30 - expectedValidatorsFullWithdrawals - 1, + }); + } else { + await expect(tx).to.not.emit( + nativeStakingSSVStrategy, + "AccountingValidatorSlashed" + ); + } + }); + } + }); it("Only accounting governor is allowed to manually fix accounting", async () => { const { nativeStakingSSVStrategy, strategist } = fixture; @@ -367,7 +551,7 @@ describe("Unit test: Native SSV Staking Strategy", function () { 10, //_activeDepositedValidators parseEther("2", "ether"), //_ethToWeth parseEther("2", "ether"), //_wethToBeSentToVault - parseEther("2", "ether"), //_beaconChainRewardWETH + parseEther("2", "ether"), //_consensusRewards parseEther("0", "ether"), //_ethThresholdCheck parseEther("0", "ether") //_wethThresholdCheck ) @@ -387,7 +571,7 @@ describe("Unit test: Native SSV Staking Strategy", function () { parseEther("1", "ether"), //_ethThresholdCheck parseEther("0", "ether") //_wethThresholdCheck ) - ).to.be.revertedWith("not paused"); + ).to.be.revertedWith("Pausable: not paused"); }); it("Should not execute manual recovery if eth threshold reached", async () => { @@ -465,34 +649,62 @@ describe("Unit test: Native SSV Staking Strategy", function () { parseEther("5", "ether") //_wethThresholdCheck ); - const events = (await tx.wait()).events || []; - const AccountingManuallyFixedEvent = events.find( - (e) => e.event === "AccountingManuallyFixed" - ); - - expect(AccountingManuallyFixedEvent).to.not.be.undefined; - expect(AccountingManuallyFixedEvent.event).to.equal( - "AccountingManuallyFixed" - ); - expect(AccountingManuallyFixedEvent.args[0]).to.equal(0); // oldActiveDepositedValidators - expect(AccountingManuallyFixedEvent.args[1]).to.equal(3); // activeDepositedValidators - expect(AccountingManuallyFixedEvent.args[2]).to.equal( - parseEther("0", "ether") - ); // oldBeaconChainRewardWETH - expect(AccountingManuallyFixedEvent.args[3]).to.equal( - parseEther("2.3", "ether") - ); // beaconChainRewardWETH - expect(AccountingManuallyFixedEvent.args[4]).to.equal( - parseEther("2.1", "ether") - ); // ethToWeth - expect(AccountingManuallyFixedEvent.args[5]).to.equal( - parseEther("2.2", "ether") - ); // wethToBeSentToVault + expect(tx) + .to.emit(nativeStakingSSVStrategy, "AccountingManuallyFixed") + .withArgs( + 0, // oldActiveDepositedValidators + 3, // activeDepositedValidators + 0, // oldBeaconChainRewardWETH + parseEther("2.3"), // beaconChainRewardWETH + parseEther("2.1"), // ethToWeth + parseEther("2.2") // wethToBeSentToVault + ); }); }); - describe("General functionality", function () { + describe("Harvest and strategy balance", function () { + // fuseStart 21.6 + // fuseEnd 25.6 + // expectedHarvester = feeAccumulatorEth + consensusRewards + // expectedBalance = deposits + nrOfActiveDepositedValidators * 32 const rewardTestCases = [ + // no rewards to harvest + { + feeAccumulatorEth: 0, + consensusRewards: 0, + deposits: 0, + nrOfActiveDepositedValidators: 0, + expectedHarvester: 0, + expectedBalance: 0, + }, + // a little execution rewards + { + feeAccumulatorEth: 0.1, + consensusRewards: 0, + deposits: 0, + nrOfActiveDepositedValidators: 0, + expectedHarvester: 0.1, + expectedBalance: 0, + }, + // a little consensus rewards + { + feeAccumulatorEth: 0, + consensusRewards: 0.2, + deposits: 0, + nrOfActiveDepositedValidators: 0, + expectedHarvester: 0.2, + expectedBalance: 0, + }, + // a little consensus and execution rewards + { + feeAccumulatorEth: 0.1, + consensusRewards: 0.2, + deposits: 0, + nrOfActiveDepositedValidators: 0, + expectedHarvester: 0.3, + expectedBalance: 0, + }, + // a lot of consensus rewards { feeAccumulatorEth: 2.2, consensusRewards: 16.3, @@ -501,56 +713,44 @@ describe("Unit test: Native SSV Staking Strategy", function () { expectedHarvester: 18.5, expectedBalance: 100 + 7 * 32, }, + // consensus rewards just below fuse start { feeAccumulatorEth: 10.2, - consensusRewards: 21.6, + consensusRewards: 21.5, deposits: 0, nrOfActiveDepositedValidators: 5, - expectedHarvester: 31.8, + expectedHarvester: 31.7, expectedBalance: 0 + 5 * 32, }, + // consensus rewards just below fuse start { feeAccumulatorEth: 10.2, - consensusRewards: 21.6, + consensusRewards: 21.5, deposits: 1, nrOfActiveDepositedValidators: 0, - expectedHarvester: 31.8, + expectedHarvester: 31.7, expectedBalance: 1 + 0 * 32, }, - { - feeAccumulatorEth: 0, - consensusRewards: 0, - deposits: 0, - nrOfActiveDepositedValidators: 0, - expectedHarvester: 0, - expectedBalance: 0 + 0 * 32, - }, ]; - describe("Collecting rewards and should correctly account for WETH", async () => { - for (const testCase of rewardTestCases) { - const feeAccumulatorEth = parseEther( - testCase.feeAccumulatorEth.toString() - ); - const consensusRewards = parseEther( - testCase.consensusRewards.toString() - ); - const deposits = parseEther(testCase.deposits.toString()); - const expectedHarvester = parseEther( - testCase.expectedHarvester.toString() - ); + for (const testCase of rewardTestCases) { + const feeAccumulatorEth = parseEther( + testCase.feeAccumulatorEth.toString() + ); + const consensusRewards = parseEther(testCase.consensusRewards.toString()); + const deposits = parseEther(testCase.deposits.toString()); + const expectedHarvester = parseEther( + testCase.expectedHarvester.toString() + ); + const expectedBalance = parseEther(testCase.expectedBalance.toString()); + const { nrOfActiveDepositedValidators } = testCase; - it(`with ${testCase.feeAccumulatorEth} execution rewards, ${testCase.consensusRewards} consensus rewards and ${testCase.deposits} deposits. expect harvest ${testCase.expectedHarvester}`, async () => { - const { - nativeStakingSSVStrategy, - governor, - oethHarvester, - weth, - josh, - } = fixture; + describe(`given ${testCase.feeAccumulatorEth} execution rewards, ${testCase.consensusRewards} consensus rewards, ${testCase.deposits} deposits and ${nrOfActiveDepositedValidators} validators`, () => { + beforeEach(async () => { + const { nativeStakingSSVStrategy, governor, strategist, weth, josh } = + fixture; const feeAccumulatorAddress = await nativeStakingSSVStrategy.FEE_ACCUMULATOR_ADDRESS(); - const sHarvester = await impersonateAndFund(oethHarvester.address); // setup state if (consensusRewards.gt(BigNumber.from("0"))) { @@ -571,107 +771,59 @@ describe("Unit test: Native SSV Staking Strategy", function () { .transfer(nativeStakingSSVStrategy.address, deposits); } + // set the correct amount of staked validators + await nativeStakingSSVStrategy.connect(strategist).pause(); + await nativeStakingSSVStrategy + .connect(governor) + .manuallyFixAccounting( + nrOfActiveDepositedValidators, // activeDepositedValidators + parseEther("0"), //_ethToWeth + parseEther("0"), //_wethToBeSentToVault + consensusRewards, //_consensusRewards + parseEther("3000"), //_ethThresholdCheck + parseEther("3000") //_wethThresholdCheck + ); + // run the accounting await nativeStakingSSVStrategy.connect(governor).doAccounting(); + }); + + it(`then should harvest ${testCase.expectedHarvester} WETH`, async () => { + const { nativeStakingSSVStrategy, oethHarvester, weth } = fixture; + const sHarvester = await impersonateAndFund(oethHarvester.address); - const harvesterWethBalance = await weth.balanceOf( + const harvesterWethBalanceBefore = await weth.balanceOf( oethHarvester.address ); const tx = await nativeStakingSSVStrategy .connect(sHarvester) .collectRewardTokens(); - const events = (await tx.wait()).events || []; - - const harvesterBalanceDiff = ( - await weth.balanceOf(oethHarvester.address) - ).sub(harvesterWethBalance); - expect(harvesterBalanceDiff).to.equal(expectedHarvester); - - const rewardTokenCollectedEvent = events.find( - (e) => e.event === "RewardTokenCollected" - ); if (expectedHarvester.gt(BigNumber.from("0"))) { - expect(rewardTokenCollectedEvent).to.not.be.undefined; - expect(rewardTokenCollectedEvent.event).to.equal( - "RewardTokenCollected" - ); - expect(rewardTokenCollectedEvent.args[1]).to.equal(weth.address); - expect(rewardTokenCollectedEvent.args[2]).to.equal( - expectedHarvester - ); + await expect(tx) + .to.emit(nativeStakingSSVStrategy, "RewardTokenCollected") + .withArgs(oethHarvester.address, weth.address, expectedHarvester); } else { - expect(rewardTokenCollectedEvent).to.be.undefined; - } - }); - } - }); - - describe("Checking balance should return the correct values", async () => { - for (const testCase of rewardTestCases) { - const feeAccumulatorEth = parseEther( - testCase.feeAccumulatorEth.toString() - ); - const consensusRewards = parseEther( - testCase.consensusRewards.toString() - ); - const deposits = parseEther(testCase.deposits.toString()); - const expectedBalance = parseEther(testCase.expectedBalance.toString()); - const { nrOfActiveDepositedValidators } = testCase; - it(`with ${testCase.feeAccumulatorEth} execution rewards, ${testCase.consensusRewards} consensus rewards, ${testCase.deposits} deposits and ${nrOfActiveDepositedValidators} validators. expected balance ${testCase.expectedBalance}`, async () => { - const { - nativeStakingSSVStrategy, - governor, - strategist, - // oethHarvester, - weth, - josh, - } = fixture; - const feeAccumulatorAddress = - await nativeStakingSSVStrategy.FEE_ACCUMULATOR_ADDRESS(); - - // setup state - if (consensusRewards.gt(BigNumber.from("0"))) { - // set the reward eth on the strategy - await setBalance( - nativeStakingSSVStrategy.address, - consensusRewards + await expect(tx).to.not.emit( + nativeStakingSSVStrategy, + "RewardTokenCollected" ); } - if (feeAccumulatorEth.gt(BigNumber.from("0"))) { - // set execution layer rewards on the fee accumulator - await setBalance(feeAccumulatorAddress, feeAccumulatorEth); - } - if (deposits.gt(BigNumber.from("0"))) { - // send eth to the strategy as if Vault would send it via a Deposit function - await weth - .connect(josh) - .transfer(nativeStakingSSVStrategy.address, deposits); - } - // set the correct amount of staked validators - await nativeStakingSSVStrategy.connect(strategist).pause(); - await nativeStakingSSVStrategy - .connect(governor) - .manuallyFixAccounting( - nrOfActiveDepositedValidators, // activeDepositedValidators - parseEther("0", "ether"), //_ethToWeth - parseEther("0", "ether"), //_wethToBeSentToVault - parseEther("0", "ether"), //_beaconChainRewardWETH - parseEther("3000", "ether"), //_ethThresholdCheck - parseEther("3000", "ether") //_wethThresholdCheck - ); + const harvesterBalanceDiff = ( + await weth.balanceOf(oethHarvester.address) + ).sub(harvesterWethBalanceBefore); + expect(harvesterBalanceDiff).to.equal(expectedHarvester); + }); - // run the accounting - await nativeStakingSSVStrategy.connect(governor).doAccounting(); + it(`then the strategy should have a ${testCase.expectedBalance} balance`, async () => { + const { nativeStakingSSVStrategy, weth } = fixture; expect( await nativeStakingSSVStrategy.checkBalance(weth.address) ).to.equal(expectedBalance); }); - } - }); - - it("Should be able to collect the SSV reward token", async () => {}); + }); + } }); }); From 87c525471a36affc58a8e9082957a3d1ac5ed923 Mon Sep 17 00:00:00 2001 From: Domen Grabec Date: Sat, 27 Apr 2024 00:28:29 +0200 Subject: [PATCH 018/273] allow for WETH to send ETH to the contract --- .../strategies/NativeStaking/NativeStakingSSVStrategy.sol | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol b/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol index 75a6f6cc4e..f3a86e6b47 100644 --- a/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol +++ b/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol @@ -251,14 +251,15 @@ contract NativeStakingSSVStrategy is } /** - * @notice Only accept ETH from the FeeAccumulator + * @notice Only accept ETH from the FeeAccumulator and the WETH contract - required when + * unwrapping WETH just before staking it to the validator * @dev don't want to receive donations from anyone else as this will * mess with the accounting of the consensus rewards and validator full withdrawals */ receive() external payable { require( - msg.sender == FEE_ACCUMULATOR_ADDRESS, - "eth not sent from Fee Accumulator" + msg.sender == FEE_ACCUMULATOR_ADDRESS || msg.sender == WETH_TOKEN_ADDRESS, + "eth not sent from Fee Accumulator or WETH contract" ); } } From 1d665080cf08e7dcaa9efd3088890b22974a585c Mon Sep 17 00:00:00 2001 From: Domen Grabec Date: Sat, 27 Apr 2024 00:47:46 +0200 Subject: [PATCH 019/273] shorten error message --- .../strategies/NativeStaking/NativeStakingSSVStrategy.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol b/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol index f3a86e6b47..970251e776 100644 --- a/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol +++ b/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol @@ -259,7 +259,7 @@ contract NativeStakingSSVStrategy is receive() external payable { require( msg.sender == FEE_ACCUMULATOR_ADDRESS || msg.sender == WETH_TOKEN_ADDRESS, - "eth not sent from Fee Accumulator or WETH contract" + "eth not from allowed contracts" ); } } From 00ec8784ee2dca20c2b6cc4a97c8dedaaa5cb201 Mon Sep 17 00:00:00 2001 From: Domen Grabec Date: Sat, 27 Apr 2024 18:00:24 +0200 Subject: [PATCH 020/273] fix depositing bug --- .../contracts/strategies/NativeStaking/ValidatorRegistrator.sol | 2 +- contracts/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/contracts/strategies/NativeStaking/ValidatorRegistrator.sol b/contracts/contracts/strategies/NativeStaking/ValidatorRegistrator.sol index d609efe6d6..45336f0362 100644 --- a/contracts/contracts/strategies/NativeStaking/ValidatorRegistrator.sol +++ b/contracts/contracts/strategies/NativeStaking/ValidatorRegistrator.sol @@ -134,7 +134,7 @@ abstract contract ValidatorRegistrator is Governable, Pausable { bytes11(0), address(this) ); - IDepositContract(BEACON_CHAIN_DEPOSIT_CONTRACT).deposit( + IDepositContract(BEACON_CHAIN_DEPOSIT_CONTRACT).deposit{ value: 32 ether }( validators[i].pubkey, withdrawal_credentials, validators[i].signature, diff --git a/contracts/package.json b/contracts/package.json index 5f728f7549..74100a2bb0 100644 --- a/contracts/package.json +++ b/contracts/package.json @@ -19,7 +19,7 @@ "prettier:check": "prettier -c \"*.js\" \"deploy/**/*.js\" \"scripts/**/*.js\" \"smoke/**/*.js\" \"scripts/**/*.js\" \"tasks/**/*.js\" \"test/**/*.js\" \"utils/**/*.js\"", "prettier:js": "prettier --write \"*.js\" \"deploy/**/*.js\" \"scripts/**/*.js\" \"smoke/**/*.js\" \"scripts/**/*.js\" \"tasks/**/*.js\" \"test/**/*.js\" \"utils/**/*.js\"", "prettier:sol": "prettier --write \"contracts/**/*.sol\"", - "test": "IS_TEST=true npx hardhat test", + "test": "rm -rf deployments/hardhat && IS_TEST=true npx hardhat test", "test:fork": "./fork-test.sh", "test:arb-fork": "FORK_NETWORK_NAME=arbitrumOne ./fork-test.sh", "test:fork:w_trace": "TRACE=true ./fork-test.sh", From ec4933b1feb282d4c2211a44666dee2314c004e8 Mon Sep 17 00:00:00 2001 From: Domen Grabec Date: Mon, 29 Apr 2024 15:52:39 +0200 Subject: [PATCH 021/273] Holesky deploy (#2026) * add basic steps to deploy OETH to holesky * prettier * minor change * holesky deployment ifles holesky deployment files * add holesky deployment files * minor fix * minor fixes * make the fork tests run on Holesky * add some more tests * testing SSV staking on Holesky * refactor where deployment files are located * more progress on deployment * add deposit to validator deployment files * remove log * prettier * lint * move file * SSV cluster info (#2036) * add ability to fetch SSV cluster information * prettier --- .../contracts/oracle/OETHFixedOracle.sol | 30 + .../NativeStaking/FeeAccumulator.sol | 1 - .../NativeStakingSSVStrategy.sol | 5 +- .../NativeStaking/ValidatorRegistrator.sol | 4 +- .../deploy/{001_core.js => deployActions.js} | 421 ++-- contracts/deploy/holesky/001_core.js | 75 + .../deploy/holesky/002_upgrade_strategy.js | 18 + .../holesky/003_deposit_to_native_strategy.js | 67 + contracts/deploy/{ => mainnet}/000_mock.js | 10 +- contracts/deploy/mainnet/001_core.js | 68 + .../deploy/{ => mainnet}/002_upgrade_vault.js | 8 +- .../deploy/{ => mainnet}/003_governor.js | 4 +- .../{ => mainnet}/004_single_asset_staking.js | 8 +- .../{ => mainnet}/005_compensation_claims.js | 8 +- .../{ => mainnet}/006_liquidity_reward.js | 6 +- .../007_upgrade_single_asset_staking.js | 8 +- .../deploy/{ => mainnet}/008_ousd_reset.js | 10 +- .../deploy/{ => mainnet}/009_ousd_fix.js | 8 +- .../010_upgrade_single_asset_staking.js | 8 +- .../deploy/{ => mainnet}/011_ousd_fix.js | 8 +- .../deploy/{ => mainnet}/012_upgrades.js | 8 +- contracts/deploy/{ => mainnet}/013_trustee.js | 8 +- .../{ => mainnet}/014_3pool_strategy.js | 8 +- contracts/deploy/{ => mainnet}/015_flipper.js | 8 +- .../016_chainlink_and_buyback.js | 8 +- .../017_3pool_strategy_update.js | 8 +- .../{ => mainnet}/018_upgrade_governor.js | 8 +- .../019_resolution_and_savings.js | 2 +- .../deploy/{ => mainnet}/020_new_governor.js | 2 +- .../{ => mainnet}/021_solidity_upgrade.js | 4 +- .../023_set_dai_default_strategy.js | 2 +- .../024_resolution_upgrade_start.js | 2 +- .../025_resolution_upgrade_end.js | 2 +- .../deploy/{ => mainnet}/026_comp_rescue_a.js | 2 +- .../deploy/{ => mainnet}/027_comp_rescue_b.js | 2 +- .../{ => mainnet}/028_dai_default_aave.js | 2 +- contracts/deploy/{ => mainnet}/029_convex.js | 2 +- .../030_staking_to_new_governor.js | 2 +- .../{ => mainnet}/031_staking_add_rescue.js | 2 +- .../{ => mainnet}/032_convex_rewards.js | 2 +- .../{ => mainnet}/034_vault_value_checker.js | 2 +- .../{ => mainnet}/035_reduce_collect_gas.js | 2 +- .../036_multiple_rewards_strategies.js | 4 +- contracts/deploy/{ => mainnet}/037_dripper.js | 2 +- .../deploy/{ => mainnet}/038_staking_patch.js | 2 +- .../deploy/{ => mainnet}/039_wrapped_ousd.js | 5 +- .../{ => mainnet}/040_vault_peg_check.js | 2 +- .../{ => mainnet}/041_stop_buyback_swaps.js | 4 +- .../deploy/{ => mainnet}/042_ogv_buyback.js | 2 +- .../{ => mainnet}/043_convexOUSDMeta.js | 4 +- .../{ => mainnet}/044_morpho_strategy.js | 2 +- .../045_convex_lusd_meta_strategy.js | 4 +- .../{ => mainnet}/046_value_value_checker.js | 2 +- .../{ => mainnet}/047_morpho_aave_strategy.js | 2 +- .../048_deposit_withdraw_tooling.js | 4 +- .../deploy/{ => mainnet}/049_oeth_proxy.js | 4 +- .../deploy/{ => mainnet}/050_woeth_proxy.js | 4 +- .../{ => mainnet}/051_upgrade_buyback.js | 4 +- .../052_upgrade_ousd_vault_harvester.js | 6 +- contracts/deploy/{ => mainnet}/053_oeth.js | 6 +- contracts/deploy/{ => mainnet}/054_woeth.js | 2 +- .../deploy/{ => mainnet}/055_curve_amo.js | 10 +- .../{ => mainnet}/056_oeth_zapper_again.js | 2 +- .../deploy/{ => mainnet}/057_drip_all.js | 2 +- .../058_oeth_vault_value_checker.js | 2 +- .../{ => mainnet}/059_harvest_crv_limit.js | 2 +- .../{ => mainnet}/060_harvest_crv_limit_2.js | 2 +- .../{ => mainnet}/061_oeth_timelock_part_1.js | 4 +- .../{ => mainnet}/062_oeth_timelock_part_2.js | 2 +- .../063_oeth_harvest_crv_limit.js | 2 +- .../{ => mainnet}/064_oeth_mopho_aave_v2.js | 4 +- .../deploy/{ => mainnet}/065_oeth_swapper.js | 2 +- .../065_upgrade_fraxeth_strategy.js | 4 +- .../{ => mainnet}/066_oeth_vault_swaps.js | 2 +- .../067_ousd_vault_value_checker.js | 2 +- .../068_oeth_to_ogv_governance_p1.js | 4 +- .../069_oeth_to_ogv_governance_p2.js | 2 +- .../deploy/{ => mainnet}/070_flux_strategy.js | 6 +- .../{ => mainnet}/071_balancer_rETH_WETH.js | 6 +- .../{ => mainnet}/072_ousd_maker_dsr.js | 4 +- .../073_ousd_disable_stratgies.js | 2 +- .../074_upgrade_oeth_oracle_router.js | 4 +- .../{ => mainnet}/075_oeth_amo_upgrade.js | 6 +- .../076_upgrade_fraxeth_strategy.js | 4 +- .../{ => mainnet}/077_balancer_rETH_WETH.js | 6 +- .../{ => mainnet}/080_upgrade_buyback.js | 4 +- .../{ => mainnet}/081_upgrade_harvester.js | 6 +- .../deploy/{ => mainnet}/082_upgrade_oeth.js | 2 +- .../{ => mainnet}/083_dripper_seven_day.js | 2 +- .../{ => mainnet}/084_delpoy_woeth_on_arb.js | 9 +- .../{ => mainnet}/085_upgrade_oeth_vault.js | 4 +- .../{ => mainnet}/086_frxeth_redeem_strat.js | 4 +- .../{ => mainnet}/087_reduce_redeem_fee.js | 2 +- .../{ => mainnet}/088_upgrade_woeth_on_arb.js | 8 +- .../deploy/{ => mainnet}/089_1inch_buyback.js | 4 +- .../089_simplified_oeth_vault.js | 4 +- .../{ => mainnet}/090_disable_compound.js | 4 +- .../{ => mainnet}/091_native_ssv_staking.js | 7 +- .../{ => mainnet}/999_fork_test_setup.js | 18 +- contracts/deployments/holesky/.chainId | 1 + .../deployments/holesky/.migrations.json | 5 + .../deployments/holesky/FeeAccumulator.json | 218 ++ .../NativeStakingFeeAccumulatorProxy.json | 289 +++ .../holesky/NativeStakingSSVStrategy.json | 1901 +++++++++++++++++ .../NativeStakingSSVStrategyProxy.json | 289 +++ contracts/deployments/holesky/OETH.json | 1126 ++++++++++ .../deployments/holesky/OETHDripper.json | 350 +++ .../deployments/holesky/OETHDripperProxy.json | 289 +++ .../deployments/holesky/OETHHarvester.json | 1044 +++++++++ .../holesky/OETHHarvesterProxy.json | 304 +++ .../deployments/holesky/OETHOracleRouter.json | 157 ++ contracts/deployments/holesky/OETHProxy.json | 289 +++ contracts/deployments/holesky/OETHVault.json | 1876 ++++++++++++++++ .../deployments/holesky/OETHVaultAdmin.json | 1858 ++++++++++++++++ .../deployments/holesky/OETHVaultCore.json | 1696 +++++++++++++++ .../deployments/holesky/OETHVaultProxy.json | 289 +++ .../0213c8dc30149ba5fb281c6d46803d0b.json | 104 + .../46be8b80ad6bb26f70e58a31071e073e.json | 104 + .../da4c2bc4af0be4b969e54f8b43895033.json | 671 ++++++ .../e8f6f73d56d3c5372e8e110ffa009f0b.json | 62 + .../ea04f995873c65a558ae1a10ef794843.json | 122 ++ contracts/dev.env | 4 + contracts/fork-test.sh | 20 +- contracts/hardhat.config.js | 163 +- contracts/node.sh | 4 +- contracts/package.json | 7 +- .../deploy/verifySimpleOETHDeployment.sh | 47 + .../scripts/test/signAndBroadcastHolesky.js | 60 + contracts/tasks/ssv.js | 83 + contracts/tasks/tasks.js | 37 +- contracts/test/_fixture.js | 141 ++ contracts/test/helpers.js | 15 + .../strategies/nativeSsvStaking.fork-test.js | 46 - .../nativeSsvStaking.holesky.fork-test.js | 147 ++ contracts/utils/addresses.js | 10 + contracts/utils/deploy.js | 8 +- contracts/utils/hardhat-helpers.js | 134 ++ contracts/yarn.lock | 1545 +++++++++++++- 138 files changed, 16113 insertions(+), 494 deletions(-) create mode 100644 contracts/contracts/oracle/OETHFixedOracle.sol rename contracts/deploy/{001_core.js => deployActions.js} (86%) create mode 100644 contracts/deploy/holesky/001_core.js create mode 100644 contracts/deploy/holesky/002_upgrade_strategy.js create mode 100644 contracts/deploy/holesky/003_deposit_to_native_strategy.js rename contracts/deploy/{ => mainnet}/000_mock.js (97%) create mode 100644 contracts/deploy/mainnet/001_core.js rename contracts/deploy/{ => mainnet}/002_upgrade_vault.js (93%) rename contracts/deploy/{ => mainnet}/003_governor.js (85%) rename contracts/deploy/{ => mainnet}/004_single_asset_staking.js (96%) rename contracts/deploy/{ => mainnet}/005_compensation_claims.js (92%) rename contracts/deploy/{ => mainnet}/006_liquidity_reward.js (97%) rename contracts/deploy/{ => mainnet}/007_upgrade_single_asset_staking.js (91%) rename contracts/deploy/{ => mainnet}/008_ousd_reset.js (98%) rename contracts/deploy/{ => mainnet}/009_ousd_fix.js (93%) rename contracts/deploy/{ => mainnet}/010_upgrade_single_asset_staking.js (90%) rename contracts/deploy/{ => mainnet}/011_ousd_fix.js (89%) rename contracts/deploy/{ => mainnet}/012_upgrades.js (93%) rename contracts/deploy/{ => mainnet}/013_trustee.js (92%) rename contracts/deploy/{ => mainnet}/014_3pool_strategy.js (96%) rename contracts/deploy/{ => mainnet}/015_flipper.js (89%) rename contracts/deploy/{ => mainnet}/016_chainlink_and_buyback.js (94%) rename contracts/deploy/{ => mainnet}/017_3pool_strategy_update.js (90%) rename contracts/deploy/{ => mainnet}/018_upgrade_governor.js (95%) rename contracts/deploy/{ => mainnet}/019_resolution_and_savings.js (92%) rename contracts/deploy/{ => mainnet}/020_new_governor.js (95%) rename contracts/deploy/{ => mainnet}/021_solidity_upgrade.js (98%) rename contracts/deploy/{ => mainnet}/023_set_dai_default_strategy.js (95%) rename contracts/deploy/{ => mainnet}/024_resolution_upgrade_start.js (93%) rename contracts/deploy/{ => mainnet}/025_resolution_upgrade_end.js (90%) rename contracts/deploy/{ => mainnet}/026_comp_rescue_a.js (91%) rename contracts/deploy/{ => mainnet}/027_comp_rescue_b.js (92%) rename contracts/deploy/{ => mainnet}/028_dai_default_aave.js (94%) rename contracts/deploy/{ => mainnet}/029_convex.js (97%) rename contracts/deploy/{ => mainnet}/030_staking_to_new_governor.js (90%) rename contracts/deploy/{ => mainnet}/031_staking_add_rescue.js (94%) rename contracts/deploy/{ => mainnet}/032_convex_rewards.js (95%) rename contracts/deploy/{ => mainnet}/034_vault_value_checker.js (92%) rename contracts/deploy/{ => mainnet}/035_reduce_collect_gas.js (91%) rename contracts/deploy/{ => mainnet}/036_multiple_rewards_strategies.js (98%) rename contracts/deploy/{ => mainnet}/037_dripper.js (98%) rename contracts/deploy/{ => mainnet}/038_staking_patch.js (92%) rename contracts/deploy/{ => mainnet}/039_wrapped_ousd.js (95%) rename contracts/deploy/{ => mainnet}/040_vault_peg_check.js (94%) rename contracts/deploy/{ => mainnet}/041_stop_buyback_swaps.js (81%) rename contracts/deploy/{ => mainnet}/042_ogv_buyback.js (97%) rename contracts/deploy/{ => mainnet}/043_convexOUSDMeta.js (97%) rename contracts/deploy/{ => mainnet}/044_morpho_strategy.js (98%) rename contracts/deploy/{ => mainnet}/045_convex_lusd_meta_strategy.js (84%) rename contracts/deploy/{ => mainnet}/046_value_value_checker.js (93%) rename contracts/deploy/{ => mainnet}/047_morpho_aave_strategy.js (98%) rename contracts/deploy/{ => mainnet}/048_deposit_withdraw_tooling.js (90%) rename contracts/deploy/{ => mainnet}/049_oeth_proxy.js (91%) rename contracts/deploy/{ => mainnet}/050_woeth_proxy.js (91%) rename contracts/deploy/{ => mainnet}/051_upgrade_buyback.js (97%) rename contracts/deploy/{ => mainnet}/052_upgrade_ousd_vault_harvester.js (97%) rename contracts/deploy/{ => mainnet}/053_oeth.js (97%) rename contracts/deploy/{ => mainnet}/054_woeth.js (93%) rename contracts/deploy/{ => mainnet}/055_curve_amo.js (99%) rename contracts/deploy/{ => mainnet}/056_oeth_zapper_again.js (89%) rename contracts/deploy/{ => mainnet}/057_drip_all.js (96%) rename contracts/deploy/{ => mainnet}/058_oeth_vault_value_checker.js (91%) rename contracts/deploy/{ => mainnet}/059_harvest_crv_limit.js (96%) rename contracts/deploy/{ => mainnet}/060_harvest_crv_limit_2.js (96%) rename contracts/deploy/{ => mainnet}/061_oeth_timelock_part_1.js (93%) rename contracts/deploy/{ => mainnet}/062_oeth_timelock_part_2.js (96%) rename contracts/deploy/{ => mainnet}/063_oeth_harvest_crv_limit.js (95%) rename contracts/deploy/{ => mainnet}/064_oeth_mopho_aave_v2.js (95%) rename contracts/deploy/{ => mainnet}/065_oeth_swapper.js (91%) rename contracts/deploy/{ => mainnet}/065_upgrade_fraxeth_strategy.js (90%) rename contracts/deploy/{ => mainnet}/066_oeth_vault_swaps.js (98%) rename contracts/deploy/{ => mainnet}/067_ousd_vault_value_checker.js (91%) rename contracts/deploy/{ => mainnet}/068_oeth_to_ogv_governance_p1.js (95%) rename contracts/deploy/{ => mainnet}/069_oeth_to_ogv_governance_p2.js (96%) rename contracts/deploy/{ => mainnet}/070_flux_strategy.js (95%) rename contracts/deploy/{ => mainnet}/071_balancer_rETH_WETH.js (95%) rename contracts/deploy/{ => mainnet}/072_ousd_maker_dsr.js (96%) rename contracts/deploy/{ => mainnet}/073_ousd_disable_stratgies.js (95%) rename contracts/deploy/{ => mainnet}/074_upgrade_oeth_oracle_router.js (95%) rename contracts/deploy/{ => mainnet}/075_oeth_amo_upgrade.js (88%) rename contracts/deploy/{ => mainnet}/076_upgrade_fraxeth_strategy.js (91%) rename contracts/deploy/{ => mainnet}/077_balancer_rETH_WETH.js (91%) rename contracts/deploy/{ => mainnet}/080_upgrade_buyback.js (98%) rename contracts/deploy/{ => mainnet}/081_upgrade_harvester.js (98%) rename contracts/deploy/{ => mainnet}/082_upgrade_oeth.js (95%) rename contracts/deploy/{ => mainnet}/083_dripper_seven_day.js (95%) rename contracts/deploy/{ => mainnet}/084_delpoy_woeth_on_arb.js (87%) rename contracts/deploy/{ => mainnet}/085_upgrade_oeth_vault.js (93%) rename contracts/deploy/{ => mainnet}/086_frxeth_redeem_strat.js (95%) rename contracts/deploy/{ => mainnet}/087_reduce_redeem_fee.js (92%) rename contracts/deploy/{ => mainnet}/088_upgrade_woeth_on_arb.js (74%) rename contracts/deploy/{ => mainnet}/089_1inch_buyback.js (97%) rename contracts/deploy/{ => mainnet}/089_simplified_oeth_vault.js (93%) rename contracts/deploy/{ => mainnet}/090_disable_compound.js (87%) rename contracts/deploy/{ => mainnet}/091_native_ssv_staking.js (96%) rename contracts/deploy/{ => mainnet}/999_fork_test_setup.js (85%) create mode 100644 contracts/deployments/holesky/.chainId create mode 100644 contracts/deployments/holesky/.migrations.json create mode 100644 contracts/deployments/holesky/FeeAccumulator.json create mode 100644 contracts/deployments/holesky/NativeStakingFeeAccumulatorProxy.json create mode 100644 contracts/deployments/holesky/NativeStakingSSVStrategy.json create mode 100644 contracts/deployments/holesky/NativeStakingSSVStrategyProxy.json create mode 100644 contracts/deployments/holesky/OETH.json create mode 100644 contracts/deployments/holesky/OETHDripper.json create mode 100644 contracts/deployments/holesky/OETHDripperProxy.json create mode 100644 contracts/deployments/holesky/OETHHarvester.json create mode 100644 contracts/deployments/holesky/OETHHarvesterProxy.json create mode 100644 contracts/deployments/holesky/OETHOracleRouter.json create mode 100644 contracts/deployments/holesky/OETHProxy.json create mode 100644 contracts/deployments/holesky/OETHVault.json create mode 100644 contracts/deployments/holesky/OETHVaultAdmin.json create mode 100644 contracts/deployments/holesky/OETHVaultCore.json create mode 100644 contracts/deployments/holesky/OETHVaultProxy.json create mode 100644 contracts/deployments/holesky/solcInputs/0213c8dc30149ba5fb281c6d46803d0b.json create mode 100644 contracts/deployments/holesky/solcInputs/46be8b80ad6bb26f70e58a31071e073e.json create mode 100644 contracts/deployments/holesky/solcInputs/da4c2bc4af0be4b969e54f8b43895033.json create mode 100644 contracts/deployments/holesky/solcInputs/e8f6f73d56d3c5372e8e110ffa009f0b.json create mode 100644 contracts/deployments/holesky/solcInputs/ea04f995873c65a558ae1a10ef794843.json create mode 100644 contracts/scripts/deploy/verifySimpleOETHDeployment.sh create mode 100644 contracts/scripts/test/signAndBroadcastHolesky.js create mode 100644 contracts/tasks/ssv.js delete mode 100644 contracts/test/strategies/nativeSsvStaking.fork-test.js create mode 100644 contracts/test/strategies/nativeSsvStaking.holesky.fork-test.js create mode 100644 contracts/utils/hardhat-helpers.js diff --git a/contracts/contracts/oracle/OETHFixedOracle.sol b/contracts/contracts/oracle/OETHFixedOracle.sol new file mode 100644 index 0000000000..1713c1e236 --- /dev/null +++ b/contracts/contracts/oracle/OETHFixedOracle.sol @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import { OETHOracleRouter } from "./OETHOracleRouter.sol"; + +// @notice Oracle Router that returns 1e18 for all prices +// used solely for deployment to testnets +contract OETHFixedOracle is OETHOracleRouter { + constructor(address _auraPriceFeed) OETHOracleRouter(_auraPriceFeed) {} + + /** + * @dev The price feed contract to use for a particular asset along with + * maximum data staleness + * @param asset address of the asset + * @return feedAddress address of the price feed for the asset + * @return maxStaleness maximum acceptable data staleness duration + */ + // solhint-disable-next-line no-unused-vars + function feedMetadata(address asset) + internal + view + virtual + override + returns (address feedAddress, uint256 maxStaleness) + { + // fixes price for all of the assets + feedAddress = FIXED_PRICE; + maxStaleness = 0; + } +} diff --git a/contracts/contracts/strategies/NativeStaking/FeeAccumulator.sol b/contracts/contracts/strategies/NativeStaking/FeeAccumulator.sol index 00ee3e8bee..175c2e5edc 100644 --- a/contracts/contracts/strategies/NativeStaking/FeeAccumulator.sol +++ b/contracts/contracts/strategies/NativeStaking/FeeAccumulator.sol @@ -4,7 +4,6 @@ pragma solidity ^0.8.0; import { Address } from "@openzeppelin/contracts/utils/Address.sol"; import { Governable } from "../../governance/Governable.sol"; -import { IWETH9 } from "../../interfaces/IWETH9.sol"; /** * @title Fee Accumulator for Native Staking SSV Strategy diff --git a/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol b/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol index 970251e776..79629473cd 100644 --- a/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol +++ b/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol @@ -251,14 +251,15 @@ contract NativeStakingSSVStrategy is } /** - * @notice Only accept ETH from the FeeAccumulator and the WETH contract - required when + * @notice Only accept ETH from the FeeAccumulator and the WETH contract - required when * unwrapping WETH just before staking it to the validator * @dev don't want to receive donations from anyone else as this will * mess with the accounting of the consensus rewards and validator full withdrawals */ receive() external payable { require( - msg.sender == FEE_ACCUMULATOR_ADDRESS || msg.sender == WETH_TOKEN_ADDRESS, + msg.sender == FEE_ACCUMULATOR_ADDRESS || + msg.sender == WETH_TOKEN_ADDRESS, "eth not from allowed contracts" ); } diff --git a/contracts/contracts/strategies/NativeStaking/ValidatorRegistrator.sol b/contracts/contracts/strategies/NativeStaking/ValidatorRegistrator.sol index 45336f0362..30270331f4 100644 --- a/contracts/contracts/strategies/NativeStaking/ValidatorRegistrator.sol +++ b/contracts/contracts/strategies/NativeStaking/ValidatorRegistrator.sol @@ -134,7 +134,9 @@ abstract contract ValidatorRegistrator is Governable, Pausable { bytes11(0), address(this) ); - IDepositContract(BEACON_CHAIN_DEPOSIT_CONTRACT).deposit{ value: 32 ether }( + IDepositContract(BEACON_CHAIN_DEPOSIT_CONTRACT).deposit{ + value: 32 ether + }( validators[i].pubkey, withdrawal_credentials, validators[i].signature, diff --git a/contracts/deploy/001_core.js b/contracts/deploy/deployActions.js similarity index 86% rename from contracts/deploy/001_core.js rename to contracts/deploy/deployActions.js index 6dcf9545d8..88dab9238c 100644 --- a/contracts/deploy/001_core.js +++ b/contracts/deploy/deployActions.js @@ -5,8 +5,8 @@ const { getAssetAddresses, getOracleAddresses, isMainnet, - isFork, isMainnetOrFork, + isHolesky, } = require("../test/helpers.js"); const { deployWithConfirmation, withConfirmation } = require("../utils/deploy"); const { @@ -14,7 +14,7 @@ const { lusdMetapoolLPCRVPid, } = require("../utils/constants"); -const log = require("../utils/logger")("deploy:001_core"); +const log = require("../utils/logger")("deploy:core"); /** * Deploy AAVE Strategy which only supports DAI. @@ -449,7 +449,7 @@ const configureVault = async () => { /** * Configure OETH Vault by adding supported assets and Strategies. */ -const configureOETHVault = async () => { +const configureOETHVault = async (isSimpleOETH) => { const assetAddresses = await getAssetAddresses(deployments); const { governorAddr, strategistAddr } = await getNamedAccounts(); // Signers @@ -463,7 +463,8 @@ const configureOETHVault = async () => { ); // Set up supported assets for Vault const { WETH, RETH, stETH, frxETH } = assetAddresses; - for (const asset of [WETH, RETH, stETH, frxETH]) { + const assets = isSimpleOETH ? [WETH] : [WETH, RETH, stETH, frxETH]; + for (const asset of assets) { await withConfirmation(cVault.connect(sGovernor).supportAsset(asset, 0)); } log("Added assets to OETH Vault"); @@ -497,45 +498,29 @@ const configureOETHVault = async () => { ); }; -/** - * Deploy Harvester - */ -const deployHarvesters = async () => { +const deployOUSDHarvester = async (ousdDripper) => { const assetAddresses = await getAssetAddresses(deployments); const { governorAddr } = await getNamedAccounts(); const sGovernor = await ethers.provider.getSigner(governorAddr); const cVaultProxy = await ethers.getContract("VaultProxy"); - const cOETHVaultProxy = await ethers.getContract("OETHVaultProxy"); const dHarvesterProxy = await deployWithConfirmation( "HarvesterProxy", [], "InitializeGovernedUpgradeabilityProxy" ); - const dOETHHarvesterProxy = await deployWithConfirmation( - "OETHHarvesterProxy", - [], - "InitializeGovernedUpgradeabilityProxy" - ); const cHarvesterProxy = await ethers.getContract("HarvesterProxy"); - const cOETHHarvesterProxy = await ethers.getContract("OETHHarvesterProxy"); + const dHarvester = await deployWithConfirmation("Harvester", [ cVaultProxy.address, assetAddresses.USDT, ]); - const dOETHHarvester = await deployWithConfirmation("OETHHarvester", [ - cOETHVaultProxy.address, - assetAddresses.WETH, - ]); + const cHarvester = await ethers.getContractAt( "Harvester", dHarvesterProxy.address ); - const cOETHHarvester = await ethers.getContractAt( - "OETHHarvester", - dOETHHarvesterProxy.address - ); await withConfirmation( cHarvesterProxy["initialize(address,address,bytes)"]( @@ -544,6 +529,44 @@ const deployHarvesters = async () => { [] ) ); + + log("Initialized HarvesterProxy"); + + await withConfirmation( + cHarvester + .connect(sGovernor) + .setRewardProceedsAddress( + isMainnet || isHolesky ? ousdDripper.address : cVaultProxy.address + ) + ); + + return dHarvesterProxy; +}; + +const deployOETHHarvester = async (oethDripper) => { + const assetAddresses = await getAssetAddresses(deployments); + const { governorAddr } = await getNamedAccounts(); + const sGovernor = await ethers.provider.getSigner(governorAddr); + const cVaultProxy = await ethers.getContract("VaultProxy"); + const cOETHVaultProxy = await ethers.getContract("OETHVaultProxy"); + + const dOETHHarvesterProxy = await deployWithConfirmation( + "OETHHarvesterProxy", + [], + "InitializeGovernedUpgradeabilityProxy" + ); + const cOETHHarvesterProxy = await ethers.getContract("OETHHarvesterProxy"); + + const dOETHHarvester = await deployWithConfirmation("OETHHarvester", [ + cOETHVaultProxy.address, + assetAddresses.WETH, + ]); + + const cOETHHarvester = await ethers.getContractAt( + "OETHHarvester", + dOETHHarvesterProxy.address + ); + await withConfirmation( cOETHHarvesterProxy["initialize(address,address,bytes)"]( dOETHHarvester.address, @@ -551,21 +574,26 @@ const deployHarvesters = async () => { [] ) ); + log("Initialized OETHHarvesterProxy"); - if (!isMainnet) { - await withConfirmation( - cHarvester - .connect(sGovernor) - .setRewardProceedsAddress(cVaultProxy.address) - ); + await withConfirmation( + cOETHHarvester + .connect(sGovernor) + .setRewardProceedsAddress( + isMainnet || isHolesky ? oethDripper.address : cVaultProxy.address + ) + ); - await withConfirmation( - cOETHHarvester - .connect(sGovernor) - .setRewardProceedsAddress(cOETHVaultProxy.address) - ); - } + return dOETHHarvesterProxy; +}; + +/** + * Deploy Harvester + */ +const deployHarvesters = async (ousdDripper, oethDripper) => { + const dHarvesterProxy = await deployOUSDHarvester(ousdDripper); + const dOETHHarvesterProxy = await deployOETHHarvester(oethDripper); return [dHarvesterProxy, dOETHHarvesterProxy]; }; @@ -662,7 +690,7 @@ const configureStrategies = async (harvesterProxy, oethHarvesterProxy) => { ); }; -const deployDripper = async () => { +const deployOUSDDripper = async () => { const { governorAddr } = await getNamedAccounts(); const assetAddresses = await getAssetAddresses(deployments); @@ -683,6 +711,41 @@ const deployDripper = async () => { [] ) ); + + return cDripperProxy; +}; + +const deployOETHDripper = async () => { + const { governorAddr } = await getNamedAccounts(); + + const assetAddresses = await getAssetAddresses(deployments); + const cVaultProxy = await ethers.getContract("OETHVaultProxy"); + + // Deploy Dripper Impl + const dDripper = await deployWithConfirmation("OETHDripper", [ + cVaultProxy.address, + assetAddresses.WETH, + ]); + + await deployWithConfirmation("OETHDripperProxy"); + // Deploy Dripper Proxy + const cDripperProxy = await ethers.getContract("OETHDripperProxy"); + await withConfirmation( + cDripperProxy["initialize(address,address,bytes)"]( + dDripper.address, + governorAddr, + [] + ) + ); + + return cDripperProxy; +}; + +const deployDrippers = async () => { + const ousdDripper = await deployOUSDDripper(); + const oethDripper = await deployOETHDripper(); + + return [ousdDripper, oethDripper]; }; /** @@ -727,6 +790,39 @@ const deployFraxEthStrategy = async () => { return cFraxETHStrategy; }; +/** + * Upgrade NativeStakingSSVStrategy + */ +const upgradeNativeStakingSSVStrategy = async () => { + const assetAddresses = await getAssetAddresses(deployments); + const { deployerAddr } = await getNamedAccounts(); + const cOETHVaultProxy = await ethers.getContract("OETHVaultProxy"); + const strategyProxy = await ethers.getContract( + "NativeStakingSSVStrategyProxy" + ); + const sDeployer = await ethers.provider.getSigner(deployerAddr); + + const cFeeAccumulatorProxy = await ethers.getContract( + "NativeStakingFeeAccumulatorProxy" + ); + + const dStrategyImpl = await deployWithConfirmation( + "NativeStakingSSVStrategy", + [ + [addresses.zero, cOETHVaultProxy.address], //_baseConfig + assetAddresses.WETH, // wethAddress + assetAddresses.SSV, // ssvToken + assetAddresses.SSVNetwork, // ssvNetwork + cFeeAccumulatorProxy.address, // feeAccumulator + assetAddresses.beaconChainDepositContract, // depositContractMock + ] + ); + + await withConfirmation( + strategyProxy.connect(sDeployer).upgradeTo(dStrategyImpl.address) + ); +}; + /** * Deploy NativeStakingSSVStrategy * Deploys a proxy, the actual strategy, initializes the proxy and initializes @@ -771,16 +867,12 @@ const deployNativeStakingSSVStrategy = async () => { "NativeStakingSSVStrategy", dStrategyImpl.address ); - const cStrategy = await ethers.getContractAt( - "NativeStakingSSVStrategy", - dNativeStakingSSVStrategyProxy.address - ); log("Deploy encode initialize function of the strategy contract"); const initData = cStrategyImpl.interface.encodeFunctionData( "initialize(address[],address[],address[])", [ - [assetAddresses.WETH, assetAddresses.SSV], // reward token addresses + [assetAddresses.WETH], // reward token addresses /* no need to specify WETH as an asset, since we have that overriden in the "supportsAsset" * function on the strategy */ @@ -801,12 +893,17 @@ const deployNativeStakingSSVStrategy = async () => { ) ); + const cStrategy = await ethers.getContractAt( + "NativeStakingSSVStrategy", + dNativeStakingSSVStrategyProxy.address + ); + log("Approve spending of the SSV token"); - await cStrategy.connect(sDeployer).safeApproveAllTokens(); + await withConfirmation(cStrategy.connect(sDeployer).safeApproveAllTokens()); log("Deploy fee accumulator implementation"); const dFeeAccumulator = await deployWithConfirmation("FeeAccumulator", [ - cNativeStakingSSVStrategyProxy.address, // _collector + cNativeStakingSSVStrategyProxy.address, // STRATEGY ]); const cFeeAccumulator = await ethers.getContractAt( "FeeAccumulator", @@ -824,7 +921,6 @@ const deployNativeStakingSSVStrategy = async () => { "0x" // do not call any initialize functions ) ); - return cStrategy; }; @@ -836,12 +932,28 @@ const deployOracles = async () => { // Signers const sDeployer = await ethers.provider.getSigner(deployerAddr); - // TODO: Change this to intelligently decide which router contract to deploy? - const oracleContract = isMainnet ? "OracleRouter" : "MockOracleRouter"; - await deployWithConfirmation("OracleRouter", [], oracleContract); + let oracleContract = "MockOracleRouter"; + let contractName = "OracleRouter"; + let args = []; + if (isMainnet) { + oracleContract = "OracleRouter"; + } else if (isHolesky) { + oracleContract = "OETHFixedOracle"; + contractName = "OETHOracleRouter"; + args = [addresses.zero]; + } + + await deployWithConfirmation(contractName, args, oracleContract); const oracleRouter = await ethers.getContract("OracleRouter"); log("Deployed OracleRouter"); + if (isHolesky) { + // no need to configure any feeds since they are hardcoded to a fixed feed + // TODO: further deployments will require more intelligent separation of different + // chains / environment oracle deployments + return; + } + const assetAddresses = await getAssetAddresses(deployments); await deployWithConfirmation("AuraWETHPriceFeed", [ assetAddresses.auraWeightedOraclePool, @@ -890,12 +1002,8 @@ const deployOracles = async () => { log("Initialized AuraWETHPriceFeed"); }; -/** - * Deploy the core contracts (Vault and OUSD). - */ -const deployCore = async () => { +const deployOETHCore = async () => { const { governorAddr } = await hre.getNamedAccounts(); - const assetAddresses = await getAssetAddresses(deployments); log(`Using asset addresses: ${JSON.stringify(assetAddresses, null, 2)}`); @@ -903,35 +1011,23 @@ const deployCore = async () => { const sGovernor = await ethers.provider.getSigner(governorAddr); // Proxies - await deployWithConfirmation("OUSDProxy"); - await deployWithConfirmation("VaultProxy"); await deployWithConfirmation("OETHProxy"); await deployWithConfirmation("OETHVaultProxy"); // Main contracts - const dOUSD = await deployWithConfirmation("OUSD"); - const dVault = await deployWithConfirmation("Vault"); - const dVaultCore = await deployWithConfirmation("VaultCore"); - const dVaultAdmin = await deployWithConfirmation("VaultAdmin"); - const dOETH = await deployWithConfirmation("OETH"); const dOETHVault = await deployWithConfirmation("OETHVault"); const dOETHVaultCore = await deployWithConfirmation("OETHVaultCore", [ - addresses.mainnet.WETH, + assetAddresses.WETH, ]); - - await deployWithConfirmation("Governor", [governorAddr, 60]); + const dOETHVaultAdmin = await deployWithConfirmation("OETHVaultAdmin"); // Get contract instances - const cOUSDProxy = await ethers.getContract("OUSDProxy"); - const cVaultProxy = await ethers.getContract("VaultProxy"); - const cOUSD = await ethers.getContractAt("OUSD", cOUSDProxy.address); - const cOracleRouter = await ethers.getContract("OracleRouter"); - const cVault = await ethers.getContractAt("IVault", cVaultProxy.address); - const cOETHProxy = await ethers.getContract("OETHProxy"); const cOETHVaultProxy = await ethers.getContract("OETHVaultProxy"); const cOETH = await ethers.getContractAt("OETH", cOETHProxy.address); + const cOracleRouter = await ethers.getContract("OracleRouter"); + const cOETHOracleRouter = isMainnet ? await ethers.getContract("OETHOracleRouter") : cOracleRouter; @@ -941,41 +1037,110 @@ const deployCore = async () => { ); await withConfirmation( - cOUSDProxy["initialize(address,address,bytes)"]( - dOUSD.address, + cOETHProxy["initialize(address,address,bytes)"]( + dOETH.address, governorAddr, [] ) ); - log("Initialized OUSDProxy"); + log("Initialized OETHProxy"); await withConfirmation( - cOETHProxy["initialize(address,address,bytes)"]( - dOETH.address, + cOETHVaultProxy["initialize(address,address,bytes)"]( + dOETHVault.address, governorAddr, [] ) ); - log("Initialized OETHProxy"); + log("Initialized OETHVaultProxy"); - // Need to call the initializer on the Vault then upgraded it to the actual - // VaultCore implementation await withConfirmation( - cVaultProxy["initialize(address,address,bytes)"]( - dVault.address, + cOETHVault + .connect(sGovernor) + .initialize(cOETHOracleRouter.address, cOETHProxy.address) + ); + log("Initialized OETHVault"); + + await withConfirmation( + cOETHVaultProxy.connect(sGovernor).upgradeTo(dOETHVaultCore.address) + ); + log("Upgraded VaultCore implementation"); + + await withConfirmation( + cOETHVault.connect(sGovernor).setAdminImpl(dOETHVaultAdmin.address) + ); + + log("Initialized VaultAdmin implementation"); + // Initialize OETH + /* Set the original resolution to 27 decimals. We used to have it set to 18 + * decimals at launch and then migrated to 27. Having it set to 27 it will + * make unit tests run at that resolution that more closely mimics mainnet + * behaviour. + * + * Another reason: + * Testing Vault value checker with small changes in Vault value and supply + * was behaving incorrectly because the rounding error that is present with + * 18 decimal point resolution, which was interfering with unit test correctness. + * Possible solutions were: + * - scale up unit test values so rounding error isn't a problem + * - have unit test run in 27 decimal point rebasingCreditsPerToken resolution + * + * Latter seems more fitting - due to mimicking production better as already mentioned. + */ + const resolution = ethers.utils.parseUnits("1", 27); + await withConfirmation( + cOETH + .connect(sGovernor) + .initialize("Origin Ether", "OETH", cOETHVaultProxy.address, resolution) + ); + log("Initialized OETH"); +}; + +const deployOUSDCore = async () => { + const { governorAddr } = await hre.getNamedAccounts(); + const assetAddresses = await getAssetAddresses(deployments); + log(`Using asset addresses: ${JSON.stringify(assetAddresses, null, 2)}`); + + // Signers + const sGovernor = await ethers.provider.getSigner(governorAddr); + + // Proxies + await deployWithConfirmation("OUSDProxy"); + await deployWithConfirmation("VaultProxy"); + + // Main contracts + const dOUSD = await deployWithConfirmation("OUSD"); + const dVault = await deployWithConfirmation("Vault"); + const dVaultCore = await deployWithConfirmation("VaultCore"); + const dVaultAdmin = await deployWithConfirmation("VaultAdmin"); + + await deployWithConfirmation("Governor", [governorAddr, 60]); + + // Get contract instances + const cOUSDProxy = await ethers.getContract("OUSDProxy"); + const cVaultProxy = await ethers.getContract("VaultProxy"); + const cOUSD = await ethers.getContractAt("OUSD", cOUSDProxy.address); + const cOracleRouter = await ethers.getContract("OracleRouter"); + const cVault = await ethers.getContractAt("IVault", cVaultProxy.address); + + await withConfirmation( + cOUSDProxy["initialize(address,address,bytes)"]( + dOUSD.address, governorAddr, [] ) ); - log("Initialized OETHVaultProxy"); + log("Initialized OUSDProxy"); + + // Need to call the initializer on the Vault then upgraded it to the actual + // VaultCore implementation await withConfirmation( - cOETHVaultProxy["initialize(address,address,bytes)"]( - dOETHVault.address, + cVaultProxy["initialize(address,address,bytes)"]( + dVault.address, governorAddr, [] ) ); - log("Initialized OETHVaultProxy"); await withConfirmation( cVault @@ -983,27 +1148,15 @@ const deployCore = async () => { .initialize(cOracleRouter.address, cOUSDProxy.address) ); log("Initialized Vault"); - await withConfirmation( - cOETHVault - .connect(sGovernor) - .initialize(cOETHOracleRouter.address, cOETHProxy.address) - ); - log("Initialized OETHVault"); await withConfirmation( cVaultProxy.connect(sGovernor).upgradeTo(dVaultCore.address) ); - await withConfirmation( - cOETHVaultProxy.connect(sGovernor).upgradeTo(dOETHVaultCore.address) - ); log("Upgraded VaultCore implementation"); await withConfirmation( cVault.connect(sGovernor).setAdminImpl(dVaultAdmin.address) ); - await withConfirmation( - cOETHVault.connect(sGovernor).setAdminImpl(dVaultAdmin.address) - ); log("Initialized VaultAdmin implementation"); // Initialize OUSD @@ -1029,13 +1182,14 @@ const deployCore = async () => { .initialize("Origin Dollar", "OUSD", cVaultProxy.address, resolution) ); log("Initialized OUSD"); +}; - await withConfirmation( - cOETH - .connect(sGovernor) - .initialize("Origin Ether", "OETH", cOETHVaultProxy.address, resolution) - ); - log("Initialized OETH"); +/** + * Deploy the core contracts (Vault and OUSD). + */ +const deployCore = async () => { + await deployOUSDCore(); + await deployOETHCore(); }; // deploy curve metapool mocks @@ -1334,39 +1488,36 @@ const deployOUSDSwapper = async () => { await vault.connect(sGovernor).setOracleSlippage(assetAddresses.USDT, 50); }; -const main = async () => { - console.log("Running 001_core deployment..."); - await deployOracles(); - await deployCore(); - await deployCurveMetapoolMocks(); - await deployCurveLUSDMetapoolMocks(); - await deployCompoundStrategy(); - await deployAaveStrategy(); - await deployThreePoolStrategy(); - await deployConvexStrategy(); - await deployConvexOUSDMetaStrategy(); - await deployConvexLUSDMetaStrategy(); - await deployNativeStakingSSVStrategy(); - await deployFraxEthStrategy(); - const [harvesterProxy, oethHarvesterProxy] = await deployHarvesters(); - await configureVault(); - await configureOETHVault(); - await configureStrategies(harvesterProxy, oethHarvesterProxy); - await deployDripper(); - await deployFlipper(); - await deployBuyback(); - await deployUniswapV3Pool(); - await deployVaultValueChecker(); - await deployWOusd(); - await deployOETHSwapper(); - await deployOUSDSwapper(); - console.log("001_core deploy done."); - return true; +module.exports = { + deployOracles, + deployCore, + deployOETHCore, + deployOUSDCore, + deployCurveMetapoolMocks, + deployCurveLUSDMetapoolMocks, + deployCompoundStrategy, + deployAaveStrategy, + deployThreePoolStrategy, + deployConvexStrategy, + deployConvexOUSDMetaStrategy, + deployConvexLUSDMetaStrategy, + deployNativeStakingSSVStrategy, + deployFraxEthStrategy, + deployDrippers, + deployOETHDripper, + deployOUSDDripper, + deployHarvesters, + deployOETHHarvester, + deployOUSDHarvester, + configureVault, + configureOETHVault, + configureStrategies, + deployFlipper, + deployBuyback, + deployUniswapV3Pool, + deployVaultValueChecker, + deployWOusd, + deployOETHSwapper, + deployOUSDSwapper, + upgradeNativeStakingSSVStrategy, }; - -main.id = "001_core"; -main.dependencies = ["mocks"]; -main.tags = ["unit_tests", "arb_unit_tests"]; -main.skip = () => isFork; - -module.exports = main; diff --git a/contracts/deploy/holesky/001_core.js b/contracts/deploy/holesky/001_core.js new file mode 100644 index 0000000000..308c1f8838 --- /dev/null +++ b/contracts/deploy/holesky/001_core.js @@ -0,0 +1,75 @@ +const { + deployOracles, + deployOETHCore, + deployNativeStakingSSVStrategy, + deployOETHDripper, + deployOETHHarvester, + configureOETHVault, +} = require("../deployActions"); + +const { withConfirmation } = require("../../utils/deploy"); + +const mainExport = async () => { + console.log("Running 001_core deployment on Holesky..."); + const { governorAddr } = await getNamedAccounts(); + const sGovernor = await ethers.provider.getSigner(governorAddr); + + console.log("Deploying Oracles"); + await deployOracles(); + console.log("Deploying Core"); + await deployOETHCore(); + console.log("Deploying Native Staking"); + await deployNativeStakingSSVStrategy(); + + const cOETHDripper = await deployOETHDripper(); + const cOETHHarvester = await deployOETHHarvester(cOETHDripper); + await configureOETHVault(true); + + const cVault = await ethers.getContractAt( + "IVault", + ( + await ethers.getContract("OETHVaultProxy") + ).address + ); + + const nativeStakingSSVStrategyProxy = await ethers.getContract( + "NativeStakingSSVStrategyProxy" + ); + + const nativeStakingSSVStrategy = await ethers.getContractAt( + "NativeStakingSSVStrategy", + nativeStakingSSVStrategyProxy.address + ); + + await withConfirmation( + nativeStakingSSVStrategy + .connect(sGovernor) + .setHarvesterAddress(cOETHHarvester.address) + ); + + await withConfirmation( + cVault + .connect(sGovernor) + .approveStrategy(nativeStakingSSVStrategyProxy.address) + ); + + await withConfirmation( + nativeStakingSSVStrategy.connect(sGovernor).setRegistrator(governorAddr) + ); + + await withConfirmation( + nativeStakingSSVStrategy + .connect(sGovernor) + .setAccountingGovernor(governorAddr) + ); + + console.log("001_core deploy done."); + return true; +}; + +mainExport.id = "001_core"; +mainExport.tags = []; +mainExport.dependencies = []; +mainExport.skip = () => false; + +module.exports = mainExport; diff --git a/contracts/deploy/holesky/002_upgrade_strategy.js b/contracts/deploy/holesky/002_upgrade_strategy.js new file mode 100644 index 0000000000..c1ba7006d9 --- /dev/null +++ b/contracts/deploy/holesky/002_upgrade_strategy.js @@ -0,0 +1,18 @@ +const { upgradeNativeStakingSSVStrategy } = require("../deployActions"); + +const mainExport = async () => { + console.log("Running 002 deployment on Holesky..."); + + console.log("Upgrading native staking strategy"); + await upgradeNativeStakingSSVStrategy(); + + console.log("Running 002 deployment done"); + return true; +}; + +mainExport.id = "002_upgrade_strategy"; +mainExport.tags = []; +mainExport.dependencies = []; +mainExport.skip = () => false; + +module.exports = mainExport; diff --git a/contracts/deploy/holesky/003_deposit_to_native_strategy.js b/contracts/deploy/holesky/003_deposit_to_native_strategy.js new file mode 100644 index 0000000000..4e743ee5b5 --- /dev/null +++ b/contracts/deploy/holesky/003_deposit_to_native_strategy.js @@ -0,0 +1,67 @@ +const { utils, BigNumber } = require("ethers"); +const { withConfirmation } = require("../../utils/deploy"); + +const mainExport = async () => { + console.log("Running 003 deployment on Holesky..."); + const { governorAddr } = await getNamedAccounts(); + const sGovernor = await ethers.provider.getSigner(governorAddr); + const { getAssetAddresses } = require("../../test/helpers.js"); + + const strategyProxy = await ethers.getContract( + "NativeStakingSSVStrategyProxy" + ); + const strategy = await ethers.getContractAt( + "NativeStakingSSVStrategy", + strategyProxy.address + ); + const cOETHVaultProxy = await ethers.getContract("OETHVaultProxy"); + const cOETHVault = await ethers.getContractAt( + "OETHVault", + cOETHVaultProxy.address + ); + const assetAddresses = await getAssetAddresses(); + + await withConfirmation( + cOETHVault.connect(sGovernor).depositToStrategy( + strategyProxy.address, // strategy address + [assetAddresses.WETH], // assets + [utils.parseEther("32")] // amounts + ) + ); + + await withConfirmation( + strategy.registerSsvValidator( + "0xa023587296851ae359280e2bff7ac8ec840b9192dddc9a8b817fd55d23b0034b4a4856d897d3aec58d99c6f6a9ba6032", //pubkey + [119, 139, 230, 252], // operatorIds + // sharesData + "0x8a19414d6eaaadb19f3e5362de068bac9bf1cd1561a0c592772d3dcbf29a3dd515e1ab1cbddca45262d5c8bc89cac22307a561f00246e251c40bcfc7152cb6b848d1d4399bdf22005214aba83c8ac507a1003922d84f110d75565fb498802b568c3c4f626206855906e32335d22cddec651fe14fb9db68470ce2ed90b7272b75aef523cd2e0ee350f5f2ebbc737edd45a9afe797cd1a3836ea968f1b428868b238aa6d0784d9042b7065f401986131ac66d574c16a359438e9b9fb8230422f98a3cfd2b89ac20cda7f7b324b26829f27304c5f03e3dd36028a804e8d2241406e6f8d8b3de92749d2b30bf99bb3f26cad97f655d0aac104c0b412f18357350393b9bbeb5f14bbf57464207e38c7e9721823ec459b0a6584a5eabe110a9bdeacff1fafd25981f0b1443e8327323ff34b78f4d04eb4158c3ffe2efe289a83cf23388af467aa782dd5b81994935b2925c1c61a9bd3b3dd4781c03a4473b035f019d72eaa28feceef3b564d5d3659c78f54edf8274d997f5f505f32ec17a72a6b53903f5cbd0e17824cfd94c7fb957fbd19f448e20c4fc81e6708ebb49f666c844199253de6d8d4776b0d9645a95b4ea1bd12a80be5b14532749c5c4d9d6c8cdbbef05fdab373ddff1ed59642152661c4d3e47af55ed7bec280d8a3782ad94682b47d7135cf56681716380aa3d95e8915f692db482caddf70ccb48273681e0516d54ac0d85cd19e9db98a89b94683181fcfea87df3b30377b5f37acb3c386de9db2b571675036d420259ea0496acd2821541b72c8d1636b86c79acfaa46fe3021414e8291916778f6a37c86f02b43ccd4b8a5e9a02dea5552413629b2e835320d7c84fad8be64971f3ee24ea94ae95cbde50706e9b5149473fdfe2fc425d553a4219810cda5eb10263fe42bf2cc83060e26e9bf56b1da4b6d70e471a9705cf77f91f98282b10697e3a028d42fca9d4b494b36481443c247dece2a3bda8e5bbaef6524a9527b3f51f26cbf46e5310fc03d29d6cf6cd6685ec3367ca210f1f39d9c050fb7581f1de234959817383566d528afe44c3ff45f43c115679f2b4d93687a8c7a653b1478126b5eb933fa52a52b37bee47ee88d378fe553899f7e7ea7dd4af67b188d43934ab004709b9715753301bcb9c20c1a3d933d793dc73ba6736c164d9c8fbba393763145bd3250256acf17b0706aade1356084ef18a91807449fb56a3a11f85a804d8e20e6d3486e5e30da4a8f83fb15d3651ddcd58d7c7a0569ccaab38c978f5357d44529bfb88bf778dcc9222c3c6b6f03f72727eec267420264edefd8d68451424e5e077eb8cc5718365911f9b23ed7f87bbc84b4b38037eec25615b0bddbaa2047f6a84ccea6dad0b3c222d4e618603c02f0d63733b76113d97c682f16147da0de37f9021b9a55163eeca2668ec1332146b7adf58639505bd186d8876c4b6a95658bbc3a65b61aa9671c9c9bc75c3bc9b809680f51864dd4eeb43ab99564719f782c3d595c03b64af22b62b115efe1eb93e09cf67c0b4162429ab074cee64e072581d6b9d6120d9b01ad0bcfe5f6d9fed8a79fdc03d33104049202e8cc11bef16e4825352988496522e92ca870121c5b02b6148e40477ef48a80e5edd257e6264a5c7b849d060d06a5be079fb7a546859d1cc90c8688d8e7d5b4b1b5fa742870745abf908962ce81dda9ba97060d1925117143f64aec125c0fef93ad33af0be63e4c0617d1afe4f148e218a4b312aa33c193e92931bac3ad55e967bd847a2a23eea22d1e8ca25c86385b079dd18a7984ede1e24c435fd066fe5f890027fc37006348b570ece5eb67dcb6b3656c64f9dfa8d36ab5c17ce5ea00e459", + BigNumber.from("1801362952000000000"), + [0, 0, 0, true, 0] // cluster + ) + ); + + console.log("Validator registered"); + + await withConfirmation( + strategy.stakeEth([ + [ + "0xa023587296851ae359280e2bff7ac8ec840b9192dddc9a8b817fd55d23b0034b4a4856d897d3aec58d99c6f6a9ba6032", //pubkey + // signature + "0xb59d5d21392a1d03d6bd40558ab3eb9fad1e8ced748b4e9fcf379c304317d9e2189c0b8f321ecc3a927c8cfef9f92046017f92456ae0a16e564d6db15541e468ab696cb0409d4e5b30cefaf835a739533f4810c677837e9d9ecbfb5bbb534944", + // deposit data root + "0xfc3f49c04eaf3437df6f6af7e66eb777858c60eddafec63b3a530e32d33724be", + ], + ]) + ); + console.log("Validator registered"); + + console.log("Running 003 deployment done"); + return true; +}; + +mainExport.id = "003_deposit_to_native_strategy"; +mainExport.tags = []; +mainExport.dependencies = []; +mainExport.skip = () => false; + +module.exports = mainExport; diff --git a/contracts/deploy/000_mock.js b/contracts/deploy/mainnet/000_mock.js similarity index 97% rename from contracts/deploy/000_mock.js rename to contracts/deploy/mainnet/000_mock.js index ab09ffcc46..bc77bd2839 100644 --- a/contracts/deploy/000_mock.js +++ b/contracts/deploy/mainnet/000_mock.js @@ -1,9 +1,9 @@ const { parseUnits } = require("ethers").utils; -const { isMainnetOrFork } = require("../test/helpers"); -const addresses = require("../utils/addresses"); -const { threeCRVPid } = require("../utils/constants"); -const { replaceContractAt } = require("../utils/hardhat"); -const { hardhatSetBalance } = require("../test/_fund"); +const { isMainnetOrFork } = require("../../test/helpers"); +const addresses = require("../../utils/addresses"); +const { threeCRVPid } = require("../../utils/constants"); +const { replaceContractAt } = require("../../utils/hardhat"); +const { hardhatSetBalance } = require("../../test/_fund"); const { abi: FACTORY_ABI, diff --git a/contracts/deploy/mainnet/001_core.js b/contracts/deploy/mainnet/001_core.js new file mode 100644 index 0000000000..61b7451e4d --- /dev/null +++ b/contracts/deploy/mainnet/001_core.js @@ -0,0 +1,68 @@ +const { isFork } = require("../../test/helpers.js"); + +const { + deployOracles, + deployCore, + deployCurveMetapoolMocks, + deployCurveLUSDMetapoolMocks, + deployCompoundStrategy, + deployAaveStrategy, + deployThreePoolStrategy, + deployConvexStrategy, + deployConvexOUSDMetaStrategy, + deployConvexLUSDMetaStrategy, + deployNativeStakingSSVStrategy, + deployFraxEthStrategy, + deployDrippers, + deployHarvesters, + configureVault, + configureOETHVault, + configureStrategies, + deployFlipper, + deployBuyback, + deployUniswapV3Pool, + deployVaultValueChecker, + deployWOusd, + deployOETHSwapper, + deployOUSDSwapper, +} = require("../deployActions"); + +const main = async () => { + console.log("Running 001_core deployment..."); + await deployOracles(); + await deployCore(); + await deployCurveMetapoolMocks(); + await deployCurveLUSDMetapoolMocks(); + await deployCompoundStrategy(); + await deployAaveStrategy(); + await deployThreePoolStrategy(); + await deployConvexStrategy(); + await deployConvexOUSDMetaStrategy(); + await deployConvexLUSDMetaStrategy(); + await deployNativeStakingSSVStrategy(); + await deployFraxEthStrategy(); + const [ousdDripper, oethDripper] = await deployDrippers(); + const [harvesterProxy, oethHarvesterProxy] = await deployHarvesters( + ousdDripper, + oethDripper + ); + await configureVault(); + await configureOETHVault(false); + await configureStrategies(harvesterProxy, oethHarvesterProxy); + await deployFlipper(); + await deployBuyback(); + await deployUniswapV3Pool(); + await deployVaultValueChecker(); + await deployWOusd(); + await deployOETHSwapper(); + await deployOUSDSwapper(); + console.log("001_core deploy done."); + return true; +}; + +main.id = "001_core"; +main.dependencies = ["mocks"]; +main.tags = ["unit_tests", "arb_unit_tests"]; +main.skip = () => isFork; + +module.exports = main; diff --git a/contracts/deploy/002_upgrade_vault.js b/contracts/deploy/mainnet/002_upgrade_vault.js similarity index 93% rename from contracts/deploy/002_upgrade_vault.js rename to contracts/deploy/mainnet/002_upgrade_vault.js index ead6ebbd44..2c928cb303 100644 --- a/contracts/deploy/002_upgrade_vault.js +++ b/contracts/deploy/mainnet/002_upgrade_vault.js @@ -1,12 +1,12 @@ -const { isMainnet, isFork } = require("../test/helpers.js"); -const { proposeArgs } = require("../utils/governor"); +const { isMainnet, isFork } = require("../../test/helpers.js"); +const { proposeArgs } = require("../../utils/governor"); const { deployWithConfirmation, withConfirmation, sleep, -} = require("../utils/deploy"); +} = require("../../utils/deploy"); -const { impersonateAndFund } = require("../utils/signers.js"); +const { impersonateAndFund } = require("../../utils/signers.js"); const upgradeVaultCoreAndAdmin = async ({ getNamedAccounts }) => { console.log("Running 002_vault_upgrade deployment..."); diff --git a/contracts/deploy/003_governor.js b/contracts/deploy/mainnet/003_governor.js similarity index 85% rename from contracts/deploy/003_governor.js rename to contracts/deploy/mainnet/003_governor.js index 8838c7174c..f67f0ad74a 100644 --- a/contracts/deploy/003_governor.js +++ b/contracts/deploy/mainnet/003_governor.js @@ -2,8 +2,8 @@ // Deploys a new governor contract on Mainnet // -const { isMainnet, isFork } = require("../test/helpers.js"); -const { deployWithConfirmation } = require("../utils/deploy"); +const { isMainnet, isFork } = require("../../test/helpers.js"); +const { deployWithConfirmation } = require("../../utils/deploy"); const deployName = "003_governor"; diff --git a/contracts/deploy/004_single_asset_staking.js b/contracts/deploy/mainnet/004_single_asset_staking.js similarity index 96% rename from contracts/deploy/004_single_asset_staking.js rename to contracts/deploy/mainnet/004_single_asset_staking.js index 4fe79afda2..8ef883a0e3 100644 --- a/contracts/deploy/004_single_asset_staking.js +++ b/contracts/deploy/mainnet/004_single_asset_staking.js @@ -7,15 +7,15 @@ const { isFork, isTest, isMainnetOrFork, -} = require("../test/helpers.js"); +} = require("../../test/helpers.js"); const { utils } = require("ethers"); const { log, deployWithConfirmation, withConfirmation, executeProposal, -} = require("../utils/deploy"); -const { proposeArgs } = require("../utils/governor"); +} = require("../../utils/deploy"); +const { proposeArgs } = require("../../utils/governor"); const deployName = "004_single_asset_staking"; @@ -114,7 +114,7 @@ const singleAssetStaking = async ({ getNamedAccounts, deployments }) => { dropProofDepth = process.env.DROP_PROOF_DEPTH; } else { // use testing generated scripts - const { computeRootHash } = require("../utils/stake"); + const { computeRootHash } = require("../../utils/stake"); const testPayouts = require("../scripts/staking/rawAccountsToBeCompensated.json"); const root = await computeRootHash(cOGNStaking.address, testPayouts); dropRootHash = root.hash; diff --git a/contracts/deploy/005_compensation_claims.js b/contracts/deploy/mainnet/005_compensation_claims.js similarity index 92% rename from contracts/deploy/005_compensation_claims.js rename to contracts/deploy/mainnet/005_compensation_claims.js index 169f3317c5..19ab6cc88b 100644 --- a/contracts/deploy/005_compensation_claims.js +++ b/contracts/deploy/mainnet/005_compensation_claims.js @@ -1,4 +1,4 @@ -const { isMainnet, isFork } = require("../test/helpers.js"); +const { isMainnet, isFork } = require("../../test/helpers.js"); const { log, @@ -6,9 +6,9 @@ const { withConfirmation, executeProposal, sendProposal, -} = require("../utils/deploy"); -const { getTxOpts } = require("../utils/tx"); -const { proposeArgs } = require("../utils/governor"); +} = require("../../utils/deploy"); +const { getTxOpts } = require("../../utils/tx"); +const { proposeArgs } = require("../../utils/governor"); const deployName = "005_compensation_claims"; diff --git a/contracts/deploy/006_liquidity_reward.js b/contracts/deploy/mainnet/006_liquidity_reward.js similarity index 97% rename from contracts/deploy/006_liquidity_reward.js rename to contracts/deploy/mainnet/006_liquidity_reward.js index 19ff7d35fa..0d752541dd 100644 --- a/contracts/deploy/006_liquidity_reward.js +++ b/contracts/deploy/mainnet/006_liquidity_reward.js @@ -6,14 +6,14 @@ const { isMainnet, isFork, isMainnetOrFork, -} = require("../test/helpers.js"); -const addresses = require("../utils/addresses.js"); +} = require("../../test/helpers.js"); +const addresses = require("../../utils/addresses.js"); const { utils } = require("ethers"); const { log, deployWithConfirmation, withConfirmation, -} = require("../utils/deploy"); +} = require("../../utils/deploy"); const deployName = "006_liquidity_reward"; diff --git a/contracts/deploy/007_upgrade_single_asset_staking.js b/contracts/deploy/mainnet/007_upgrade_single_asset_staking.js similarity index 91% rename from contracts/deploy/007_upgrade_single_asset_staking.js rename to contracts/deploy/mainnet/007_upgrade_single_asset_staking.js index 2cd3a6b6c7..02f423d384 100644 --- a/contracts/deploy/007_upgrade_single_asset_staking.js +++ b/contracts/deploy/mainnet/007_upgrade_single_asset_staking.js @@ -1,14 +1,14 @@ // // Script to upgrade the Single Asset Staking contract. // -const { isMainnet, isFork } = require("../test/helpers.js"); +const { isMainnet, isFork } = require("../../test/helpers.js"); const { log, deployWithConfirmation, executeProposal, -} = require("../utils/deploy"); -const { proposeArgs } = require("../utils/governor"); -const { getTxOpts } = require("../utils/tx"); +} = require("../../utils/deploy"); +const { proposeArgs } = require("../../utils/governor"); +const { getTxOpts } = require("../../utils/tx"); const deployName = "007_upgrade_single_asset_staking"; diff --git a/contracts/deploy/008_ousd_reset.js b/contracts/deploy/mainnet/008_ousd_reset.js similarity index 98% rename from contracts/deploy/008_ousd_reset.js rename to contracts/deploy/mainnet/008_ousd_reset.js index 9b73df6eab..b37bc755e7 100644 --- a/contracts/deploy/008_ousd_reset.js +++ b/contracts/deploy/mainnet/008_ousd_reset.js @@ -1,22 +1,22 @@ const hre = require("hardhat"); const { utils } = require("ethers"); -const addresses = require("../utils/addresses"); +const addresses = require("../../utils/addresses"); const { getAssetAddresses, getOracleAddresses, isMainnet, isFork, isMainnetOrFork, -} = require("../test/helpers.js"); +} = require("../../test/helpers.js"); const { log, deployWithConfirmation, withConfirmation, executeProposal, -} = require("../utils/deploy"); -const { proposeArgs } = require("../utils/governor"); -const { getTxOpts } = require("../utils/tx"); +} = require("../../utils/deploy"); +const { proposeArgs } = require("../../utils/governor"); +const { getTxOpts } = require("../../utils/tx"); const deployName = "008_ousd_reset"; diff --git a/contracts/deploy/009_ousd_fix.js b/contracts/deploy/mainnet/009_ousd_fix.js similarity index 93% rename from contracts/deploy/009_ousd_fix.js rename to contracts/deploy/mainnet/009_ousd_fix.js index 5faa55cf74..ac77861116 100644 --- a/contracts/deploy/009_ousd_fix.js +++ b/contracts/deploy/mainnet/009_ousd_fix.js @@ -1,15 +1,15 @@ const hre = require("hardhat"); -const { isMainnet, isFork } = require("../test/helpers.js"); +const { isMainnet, isFork } = require("../../test/helpers.js"); const { log, deployWithConfirmation, withConfirmation, executeProposal, sendProposal, -} = require("../utils/deploy"); -const { proposeArgs } = require("../utils/governor"); -const { getTxOpts } = require("../utils/tx"); +} = require("../../utils/deploy"); +const { proposeArgs } = require("../../utils/governor"); +const { getTxOpts } = require("../../utils/tx"); const deployName = "009_ousd_fix"; diff --git a/contracts/deploy/010_upgrade_single_asset_staking.js b/contracts/deploy/mainnet/010_upgrade_single_asset_staking.js similarity index 90% rename from contracts/deploy/010_upgrade_single_asset_staking.js rename to contracts/deploy/mainnet/010_upgrade_single_asset_staking.js index da6b3ffb46..b390fe5c06 100644 --- a/contracts/deploy/010_upgrade_single_asset_staking.js +++ b/contracts/deploy/mainnet/010_upgrade_single_asset_staking.js @@ -1,15 +1,15 @@ // // Script to upgrade the Single Asset Staking contract. // -const { isMainnet, isFork } = require("../test/helpers.js"); +const { isMainnet, isFork } = require("../../test/helpers.js"); const { log, deployWithConfirmation, executeProposal, sendProposal, -} = require("../utils/deploy"); -const { proposeArgs } = require("../utils/governor"); -const { getTxOpts } = require("../utils/tx"); +} = require("../../utils/deploy"); +const { proposeArgs } = require("../../utils/governor"); +const { getTxOpts } = require("../../utils/tx"); const deployName = "010_upgrade_single_asset_staking"; diff --git a/contracts/deploy/011_ousd_fix.js b/contracts/deploy/mainnet/011_ousd_fix.js similarity index 89% rename from contracts/deploy/011_ousd_fix.js rename to contracts/deploy/mainnet/011_ousd_fix.js index 92a65cc1ff..790f204a3f 100644 --- a/contracts/deploy/011_ousd_fix.js +++ b/contracts/deploy/mainnet/011_ousd_fix.js @@ -1,13 +1,13 @@ -const { isMainnet, isFork } = require("../test/helpers.js"); +const { isMainnet, isFork } = require("../../test/helpers.js"); const { log, deployWithConfirmation, withConfirmation, executeProposal, sendProposal, -} = require("../utils/deploy"); -const { proposeArgs } = require("../utils/governor"); -const { getTxOpts } = require("../utils/tx"); +} = require("../../utils/deploy"); +const { proposeArgs } = require("../../utils/governor"); +const { getTxOpts } = require("../../utils/tx"); const deployName = "011_ousd_fix"; diff --git a/contracts/deploy/012_upgrades.js b/contracts/deploy/mainnet/012_upgrades.js similarity index 93% rename from contracts/deploy/012_upgrades.js rename to contracts/deploy/mainnet/012_upgrades.js index ffe55a9452..3224d8d663 100644 --- a/contracts/deploy/012_upgrades.js +++ b/contracts/deploy/mainnet/012_upgrades.js @@ -1,13 +1,13 @@ -const { isMainnet, isFork, isSmokeTest } = require("../test/helpers.js"); +const { isMainnet, isFork, isSmokeTest } = require("../../test/helpers.js"); const { log, deployWithConfirmation, withConfirmation, executeProposal, sendProposal, -} = require("../utils/deploy"); -const { proposeArgs } = require("../utils/governor"); -const { getTxOpts } = require("../utils/tx"); +} = require("../../utils/deploy"); +const { proposeArgs } = require("../../utils/governor"); +const { getTxOpts } = require("../../utils/tx"); const deployName = "012_upgrades"; diff --git a/contracts/deploy/013_trustee.js b/contracts/deploy/mainnet/013_trustee.js similarity index 92% rename from contracts/deploy/013_trustee.js rename to contracts/deploy/mainnet/013_trustee.js index 82a2478544..fd261aa8b3 100644 --- a/contracts/deploy/013_trustee.js +++ b/contracts/deploy/mainnet/013_trustee.js @@ -1,13 +1,13 @@ -const { isMainnet, isFork, isSmokeTest } = require("../test/helpers.js"); +const { isMainnet, isFork, isSmokeTest } = require("../../test/helpers.js"); const { log, deployWithConfirmation, withConfirmation, executeProposal, sendProposal, -} = require("../utils/deploy"); -const { proposeArgs } = require("../utils/governor"); -const { getTxOpts } = require("../utils/tx"); +} = require("../../utils/deploy"); +const { proposeArgs } = require("../../utils/governor"); +const { getTxOpts } = require("../../utils/tx"); const deployName = "013_trustee"; diff --git a/contracts/deploy/014_3pool_strategy.js b/contracts/deploy/mainnet/014_3pool_strategy.js similarity index 96% rename from contracts/deploy/014_3pool_strategy.js rename to contracts/deploy/mainnet/014_3pool_strategy.js index 164fb4c1a4..bcbe1aed02 100644 --- a/contracts/deploy/014_3pool_strategy.js +++ b/contracts/deploy/mainnet/014_3pool_strategy.js @@ -3,16 +3,16 @@ const { isMainnet, isFork, isSmokeTest, -} = require("../test/helpers.js"); +} = require("../../test/helpers.js"); const { log, deployWithConfirmation, withConfirmation, executeProposal, sendProposal, -} = require("../utils/deploy"); -const { proposeArgs } = require("../utils/governor"); -const { getTxOpts } = require("../utils/tx"); +} = require("../../utils/deploy"); +const { proposeArgs } = require("../../utils/governor"); +const { getTxOpts } = require("../../utils/tx"); const deployName = "014_3pool_strategy"; diff --git a/contracts/deploy/015_flipper.js b/contracts/deploy/mainnet/015_flipper.js similarity index 89% rename from contracts/deploy/015_flipper.js rename to contracts/deploy/mainnet/015_flipper.js index 282a6d8284..8c79cd648c 100644 --- a/contracts/deploy/015_flipper.js +++ b/contracts/deploy/mainnet/015_flipper.js @@ -1,11 +1,11 @@ -const { isMainnet, isFork, isSmokeTest } = require("../test/helpers.js"); +const { isMainnet, isFork, isSmokeTest } = require("../../test/helpers.js"); const { log, deployWithConfirmation, withConfirmation, -} = require("../utils/deploy"); -const { getTxOpts } = require("../utils/tx"); -const { impersonateAndFund } = require("../utils/signers.js"); +} = require("../../utils/deploy"); +const { getTxOpts } = require("../../utils/tx"); +const { impersonateAndFund } = require("../../utils/signers.js"); const deployName = "015_flipper"; diff --git a/contracts/deploy/016_chainlink_and_buyback.js b/contracts/deploy/mainnet/016_chainlink_and_buyback.js similarity index 94% rename from contracts/deploy/016_chainlink_and_buyback.js rename to contracts/deploy/mainnet/016_chainlink_and_buyback.js index e3e0c79ca6..5e4332c00d 100644 --- a/contracts/deploy/016_chainlink_and_buyback.js +++ b/contracts/deploy/mainnet/016_chainlink_and_buyback.js @@ -1,13 +1,13 @@ -const { isMainnet, isFork, isSmokeTest } = require("../test/helpers.js"); +const { isMainnet, isFork, isSmokeTest } = require("../../test/helpers.js"); const { log, deployWithConfirmation, withConfirmation, executeProposal, sendProposal, -} = require("../utils/deploy"); -const { proposeArgs } = require("../utils/governor"); -const { getTxOpts } = require("../utils/tx"); +} = require("../../utils/deploy"); +const { proposeArgs } = require("../../utils/governor"); +const { getTxOpts } = require("../../utils/tx"); const deployName = "016_chainlink_and_buyback"; diff --git a/contracts/deploy/017_3pool_strategy_update.js b/contracts/deploy/mainnet/017_3pool_strategy_update.js similarity index 90% rename from contracts/deploy/017_3pool_strategy_update.js rename to contracts/deploy/mainnet/017_3pool_strategy_update.js index 2bb0fcca0c..08b4421ffe 100644 --- a/contracts/deploy/017_3pool_strategy_update.js +++ b/contracts/deploy/mainnet/017_3pool_strategy_update.js @@ -1,13 +1,13 @@ -const { isMainnet, isFork, isSmokeTest } = require("../test/helpers.js"); +const { isMainnet, isFork, isSmokeTest } = require("../../test/helpers.js"); const { log, deployWithConfirmation, withConfirmation, executeProposal, sendProposal, -} = require("../utils/deploy"); -const { proposeArgs } = require("../utils/governor"); -const { getTxOpts } = require("../utils/tx"); +} = require("../../utils/deploy"); +const { proposeArgs } = require("../../utils/governor"); +const { getTxOpts } = require("../../utils/tx"); const deployName = "017_3pool_strategy_update"; diff --git a/contracts/deploy/018_upgrade_governor.js b/contracts/deploy/mainnet/018_upgrade_governor.js similarity index 95% rename from contracts/deploy/018_upgrade_governor.js rename to contracts/deploy/mainnet/018_upgrade_governor.js index 8cf912dd05..008fb80591 100644 --- a/contracts/deploy/018_upgrade_governor.js +++ b/contracts/deploy/mainnet/018_upgrade_governor.js @@ -2,15 +2,15 @@ // 2. Submit a proposal on the old governor to call transferGovernance() on all governable contracts. // 3. Submit a proposal on the new governor to call claimGovernance() on all governable contracts. -const { isMainnet, isFork, isSmokeTest } = require("../test/helpers.js"); +const { isMainnet, isFork, isSmokeTest } = require("../../test/helpers.js"); const { log, deployWithConfirmation, executeProposal, sendProposal, -} = require("../utils/deploy"); -const { proposeArgs } = require("../utils/governor"); -const addresses = require("../utils/addresses"); +} = require("../../utils/deploy"); +const { proposeArgs } = require("../../utils/governor"); +const addresses = require("../../utils/addresses"); const deployName = "018_upgrade_governor"; diff --git a/contracts/deploy/019_resolution_and_savings.js b/contracts/deploy/mainnet/019_resolution_and_savings.js similarity index 92% rename from contracts/deploy/019_resolution_and_savings.js rename to contracts/deploy/mainnet/019_resolution_and_savings.js index 53b90fbc25..ab008cef50 100644 --- a/contracts/deploy/019_resolution_and_savings.js +++ b/contracts/deploy/mainnet/019_resolution_and_savings.js @@ -1,4 +1,4 @@ -const { deploymentWithProposal } = require("../utils/deploy"); +const { deploymentWithProposal } = require("../../utils/deploy"); module.exports = deploymentWithProposal( { deployName: "019_resolution_and_savings" }, diff --git a/contracts/deploy/020_new_governor.js b/contracts/deploy/mainnet/020_new_governor.js similarity index 95% rename from contracts/deploy/020_new_governor.js rename to contracts/deploy/mainnet/020_new_governor.js index 603f2db8ca..54e114a4be 100644 --- a/contracts/deploy/020_new_governor.js +++ b/contracts/deploy/mainnet/020_new_governor.js @@ -1,6 +1,6 @@ const hre = require("hardhat"); -const { log, deploymentWithProposal } = require("../utils/deploy"); +const { log, deploymentWithProposal } = require("../../utils/deploy"); module.exports = deploymentWithProposal( { deployName: "020_new_governor" }, diff --git a/contracts/deploy/021_solidity_upgrade.js b/contracts/deploy/mainnet/021_solidity_upgrade.js similarity index 98% rename from contracts/deploy/021_solidity_upgrade.js rename to contracts/deploy/mainnet/021_solidity_upgrade.js index 9e1f0f660f..035ededcee 100644 --- a/contracts/deploy/021_solidity_upgrade.js +++ b/contracts/deploy/mainnet/021_solidity_upgrade.js @@ -1,7 +1,7 @@ const hre = require("hardhat"); -const addresses = require("../utils/addresses"); -const { log, deploymentWithProposal } = require("../utils/deploy"); +const addresses = require("../../utils/addresses"); +const { log, deploymentWithProposal } = require("../../utils/deploy"); module.exports = deploymentWithProposal( { deployName: "021_solidity_upgrade" }, diff --git a/contracts/deploy/023_set_dai_default_strategy.js b/contracts/deploy/mainnet/023_set_dai_default_strategy.js similarity index 95% rename from contracts/deploy/023_set_dai_default_strategy.js rename to contracts/deploy/mainnet/023_set_dai_default_strategy.js index c0c542acb3..5e8a1dc8de 100644 --- a/contracts/deploy/023_set_dai_default_strategy.js +++ b/contracts/deploy/mainnet/023_set_dai_default_strategy.js @@ -1,4 +1,4 @@ -const { deploymentWithProposal } = require("../utils/deploy"); +const { deploymentWithProposal } = require("../../utils/deploy"); module.exports = deploymentWithProposal( { deployName: "023_set_dai_default_strategy" }, diff --git a/contracts/deploy/024_resolution_upgrade_start.js b/contracts/deploy/mainnet/024_resolution_upgrade_start.js similarity index 93% rename from contracts/deploy/024_resolution_upgrade_start.js rename to contracts/deploy/mainnet/024_resolution_upgrade_start.js index abea4e6f08..3d2b676827 100644 --- a/contracts/deploy/024_resolution_upgrade_start.js +++ b/contracts/deploy/mainnet/024_resolution_upgrade_start.js @@ -1,4 +1,4 @@ -const { deploymentWithProposal } = require("../utils/deploy"); +const { deploymentWithProposal } = require("../../utils/deploy"); module.exports = deploymentWithProposal( { deployName: "024_resolution_upgrade_start", forceDeploy: false }, diff --git a/contracts/deploy/025_resolution_upgrade_end.js b/contracts/deploy/mainnet/025_resolution_upgrade_end.js similarity index 90% rename from contracts/deploy/025_resolution_upgrade_end.js rename to contracts/deploy/mainnet/025_resolution_upgrade_end.js index 1b83ccb7ff..6277bc78cb 100644 --- a/contracts/deploy/025_resolution_upgrade_end.js +++ b/contracts/deploy/mainnet/025_resolution_upgrade_end.js @@ -1,4 +1,4 @@ -const { deploymentWithProposal } = require("../utils/deploy"); +const { deploymentWithProposal } = require("../../utils/deploy"); module.exports = deploymentWithProposal( { deployName: "025_resolution_upgrade_start", forceDeploy: false }, diff --git a/contracts/deploy/026_comp_rescue_a.js b/contracts/deploy/mainnet/026_comp_rescue_a.js similarity index 91% rename from contracts/deploy/026_comp_rescue_a.js rename to contracts/deploy/mainnet/026_comp_rescue_a.js index 96e0daf2ae..6f582622da 100644 --- a/contracts/deploy/026_comp_rescue_a.js +++ b/contracts/deploy/mainnet/026_comp_rescue_a.js @@ -1,4 +1,4 @@ -const { deploymentWithProposal } = require("../utils/deploy"); +const { deploymentWithProposal } = require("../../utils/deploy"); const OLD_GOVERNOR = "0x830622BDd79CC677eE6594E20bBda5B26568b781"; const OLD_COMP_STRAT = "0xD5433168Ed0B1F7714819646606DB509D9d8EC1f"; diff --git a/contracts/deploy/027_comp_rescue_b.js b/contracts/deploy/mainnet/027_comp_rescue_b.js similarity index 92% rename from contracts/deploy/027_comp_rescue_b.js rename to contracts/deploy/mainnet/027_comp_rescue_b.js index 1523cae696..0df3a5078c 100644 --- a/contracts/deploy/027_comp_rescue_b.js +++ b/contracts/deploy/mainnet/027_comp_rescue_b.js @@ -1,4 +1,4 @@ -const { deploymentWithProposal } = require("../utils/deploy"); +const { deploymentWithProposal } = require("../../utils/deploy"); const OLD_COMP_STRAT = "0xD5433168Ed0B1F7714819646606DB509D9d8EC1f"; diff --git a/contracts/deploy/028_dai_default_aave.js b/contracts/deploy/mainnet/028_dai_default_aave.js similarity index 94% rename from contracts/deploy/028_dai_default_aave.js rename to contracts/deploy/mainnet/028_dai_default_aave.js index dacde4adab..f491dea96a 100644 --- a/contracts/deploy/028_dai_default_aave.js +++ b/contracts/deploy/mainnet/028_dai_default_aave.js @@ -1,4 +1,4 @@ -const { deploymentWithProposal } = require("../utils/deploy"); +const { deploymentWithProposal } = require("../../utils/deploy"); module.exports = deploymentWithProposal( { deployName: "028_dai_default_aave", forceDeploy: false }, diff --git a/contracts/deploy/029_convex.js b/contracts/deploy/mainnet/029_convex.js similarity index 97% rename from contracts/deploy/029_convex.js rename to contracts/deploy/mainnet/029_convex.js index bda0504eb3..f75d8c4823 100644 --- a/contracts/deploy/029_convex.js +++ b/contracts/deploy/mainnet/029_convex.js @@ -1,4 +1,4 @@ -const { deploymentWithProposal } = require("../utils/deploy"); +const { deploymentWithProposal } = require("../../utils/deploy"); module.exports = deploymentWithProposal( { deployName: "029_convex" }, diff --git a/contracts/deploy/030_staking_to_new_governor.js b/contracts/deploy/mainnet/030_staking_to_new_governor.js similarity index 90% rename from contracts/deploy/030_staking_to_new_governor.js rename to contracts/deploy/mainnet/030_staking_to_new_governor.js index 5cfdba99df..ec11f133f4 100644 --- a/contracts/deploy/030_staking_to_new_governor.js +++ b/contracts/deploy/mainnet/030_staking_to_new_governor.js @@ -1,4 +1,4 @@ -const { deploymentWithProposal } = require("../utils/deploy"); +const { deploymentWithProposal } = require("../../utils/deploy"); const OLD_GOVERNOR = "0x830622BDd79CC677eE6594E20bBda5B26568b781"; const NEW_GOVERNOR = "0x72426BA137DEC62657306b12B1E869d43FeC6eC7"; diff --git a/contracts/deploy/031_staking_add_rescue.js b/contracts/deploy/mainnet/031_staking_add_rescue.js similarity index 94% rename from contracts/deploy/031_staking_add_rescue.js rename to contracts/deploy/mainnet/031_staking_add_rescue.js index 540dbcbe37..e950bc3f3c 100644 --- a/contracts/deploy/031_staking_add_rescue.js +++ b/contracts/deploy/mainnet/031_staking_add_rescue.js @@ -1,4 +1,4 @@ -const { deploymentWithProposal } = require("../utils/deploy"); +const { deploymentWithProposal } = require("../../utils/deploy"); const TRANSFER_AGENT = "0x449E0B5564e0d141b3bc3829E74fFA0Ea8C08ad5"; diff --git a/contracts/deploy/032_convex_rewards.js b/contracts/deploy/mainnet/032_convex_rewards.js similarity index 95% rename from contracts/deploy/032_convex_rewards.js rename to contracts/deploy/mainnet/032_convex_rewards.js index 05a89aa48d..87f1db7075 100644 --- a/contracts/deploy/032_convex_rewards.js +++ b/contracts/deploy/mainnet/032_convex_rewards.js @@ -1,4 +1,4 @@ -const { deploymentWithProposal } = require("../utils/deploy"); +const { deploymentWithProposal } = require("../../utils/deploy"); module.exports = deploymentWithProposal( { deployName: "032_convex_rewards", forceDeploy: false }, diff --git a/contracts/deploy/034_vault_value_checker.js b/contracts/deploy/mainnet/034_vault_value_checker.js similarity index 92% rename from contracts/deploy/034_vault_value_checker.js rename to contracts/deploy/mainnet/034_vault_value_checker.js index 62ecdfbd18..0d9b1f25d1 100644 --- a/contracts/deploy/034_vault_value_checker.js +++ b/contracts/deploy/mainnet/034_vault_value_checker.js @@ -1,4 +1,4 @@ -const { deploymentWithProposal } = require("../utils/deploy"); +const { deploymentWithProposal } = require("../../utils/deploy"); module.exports = deploymentWithProposal( { deployName: "034_vault_value_checker", forceDeploy: false }, diff --git a/contracts/deploy/035_reduce_collect_gas.js b/contracts/deploy/mainnet/035_reduce_collect_gas.js similarity index 91% rename from contracts/deploy/035_reduce_collect_gas.js rename to contracts/deploy/mainnet/035_reduce_collect_gas.js index a81a2fe2e8..7818b2f61c 100644 --- a/contracts/deploy/035_reduce_collect_gas.js +++ b/contracts/deploy/mainnet/035_reduce_collect_gas.js @@ -1,4 +1,4 @@ -const { deploymentWithProposal } = require("../utils/deploy"); +const { deploymentWithProposal } = require("../../utils/deploy"); module.exports = deploymentWithProposal( { deployName: "035_reduce_collect_gas", forceDeploy: false }, diff --git a/contracts/deploy/036_multiple_rewards_strategies.js b/contracts/deploy/mainnet/036_multiple_rewards_strategies.js similarity index 98% rename from contracts/deploy/036_multiple_rewards_strategies.js rename to contracts/deploy/mainnet/036_multiple_rewards_strategies.js index 50dff2211f..cdf0ac8ea6 100644 --- a/contracts/deploy/036_multiple_rewards_strategies.js +++ b/contracts/deploy/mainnet/036_multiple_rewards_strategies.js @@ -1,5 +1,5 @@ -const { deploymentWithProposal, log } = require("../utils/deploy"); -const { MAX_UINT256 } = require("../utils/constants"); +const { deploymentWithProposal, log } = require("../../utils/deploy"); +const { MAX_UINT256 } = require("../../utils/constants"); module.exports = deploymentWithProposal( { deployName: "036_multiple_rewards_public_harvest", forceDeploy: false }, diff --git a/contracts/deploy/037_dripper.js b/contracts/deploy/mainnet/037_dripper.js similarity index 98% rename from contracts/deploy/037_dripper.js rename to contracts/deploy/mainnet/037_dripper.js index 35f9b44a03..523aef34e9 100644 --- a/contracts/deploy/037_dripper.js +++ b/contracts/deploy/mainnet/037_dripper.js @@ -1,4 +1,4 @@ -const { deploymentWithProposal } = require("../utils/deploy"); +const { deploymentWithProposal } = require("../../utils/deploy"); module.exports = deploymentWithProposal( { deployName: "037_dripper", forceDeploy: false }, diff --git a/contracts/deploy/038_staking_patch.js b/contracts/deploy/mainnet/038_staking_patch.js similarity index 92% rename from contracts/deploy/038_staking_patch.js rename to contracts/deploy/mainnet/038_staking_patch.js index bab4957279..71cc38e4c4 100644 --- a/contracts/deploy/038_staking_patch.js +++ b/contracts/deploy/mainnet/038_staking_patch.js @@ -1,4 +1,4 @@ -const { deploymentWithProposal } = require("../utils/deploy"); +const { deploymentWithProposal } = require("../../utils/deploy"); // Deploy new staking implimentation contract with fix // Upgrade to using it diff --git a/contracts/deploy/039_wrapped_ousd.js b/contracts/deploy/mainnet/039_wrapped_ousd.js similarity index 95% rename from contracts/deploy/039_wrapped_ousd.js rename to contracts/deploy/mainnet/039_wrapped_ousd.js index 9b443f31aa..e62c424c60 100644 --- a/contracts/deploy/039_wrapped_ousd.js +++ b/contracts/deploy/mainnet/039_wrapped_ousd.js @@ -1,4 +1,7 @@ -const { deploymentWithProposal, withConfirmation } = require("../utils/deploy"); +const { + deploymentWithProposal, + withConfirmation, +} = require("../../utils/deploy"); module.exports = deploymentWithProposal( { deployName: "039_wrapped_ousd", forceDeploy: false }, diff --git a/contracts/deploy/040_vault_peg_check.js b/contracts/deploy/mainnet/040_vault_peg_check.js similarity index 94% rename from contracts/deploy/040_vault_peg_check.js rename to contracts/deploy/mainnet/040_vault_peg_check.js index e102360b1f..2679add545 100644 --- a/contracts/deploy/040_vault_peg_check.js +++ b/contracts/deploy/mainnet/040_vault_peg_check.js @@ -1,4 +1,4 @@ -const { deploymentWithProposal } = require("../utils/deploy"); +const { deploymentWithProposal } = require("../../utils/deploy"); module.exports = deploymentWithProposal( { deployName: "040_vault_peg_check", forceDeploy: false }, diff --git a/contracts/deploy/041_stop_buyback_swaps.js b/contracts/deploy/mainnet/041_stop_buyback_swaps.js similarity index 81% rename from contracts/deploy/041_stop_buyback_swaps.js rename to contracts/deploy/mainnet/041_stop_buyback_swaps.js index 71d1df1d3b..aae548aabd 100644 --- a/contracts/deploy/041_stop_buyback_swaps.js +++ b/contracts/deploy/mainnet/041_stop_buyback_swaps.js @@ -1,5 +1,5 @@ -const addresses = require("../utils/addresses"); -const { deploymentWithProposal } = require("../utils/deploy"); +const addresses = require("../../utils/addresses"); +const { deploymentWithProposal } = require("../../utils/deploy"); module.exports = deploymentWithProposal( { deployName: "041_stop_buyback_swaps", forceDeploy: false }, async () => { diff --git a/contracts/deploy/042_ogv_buyback.js b/contracts/deploy/mainnet/042_ogv_buyback.js similarity index 97% rename from contracts/deploy/042_ogv_buyback.js rename to contracts/deploy/mainnet/042_ogv_buyback.js index 626e8e1d42..1f82ac9317 100644 --- a/contracts/deploy/042_ogv_buyback.js +++ b/contracts/deploy/mainnet/042_ogv_buyback.js @@ -1,4 +1,4 @@ -const { deploymentWithProposal } = require("../utils/deploy"); +const { deploymentWithProposal } = require("../../utils/deploy"); module.exports = deploymentWithProposal( { deployName: "042_ogv_buyback", forceDeploy: false }, diff --git a/contracts/deploy/043_convexOUSDMeta.js b/contracts/deploy/mainnet/043_convexOUSDMeta.js similarity index 97% rename from contracts/deploy/043_convexOUSDMeta.js rename to contracts/deploy/mainnet/043_convexOUSDMeta.js index 340010f4c5..ea4ca938f6 100644 --- a/contracts/deploy/043_convexOUSDMeta.js +++ b/contracts/deploy/mainnet/043_convexOUSDMeta.js @@ -1,5 +1,5 @@ -const { deploymentWithProposal } = require("../utils/deploy"); -const addresses = require("../utils/addresses"); +const { deploymentWithProposal } = require("../../utils/deploy"); +const addresses = require("../../utils/addresses"); const { BigNumber } = require("ethers"); module.exports = deploymentWithProposal( diff --git a/contracts/deploy/044_morpho_strategy.js b/contracts/deploy/mainnet/044_morpho_strategy.js similarity index 98% rename from contracts/deploy/044_morpho_strategy.js rename to contracts/deploy/mainnet/044_morpho_strategy.js index d2c177ae19..5b2d33a549 100644 --- a/contracts/deploy/044_morpho_strategy.js +++ b/contracts/deploy/mainnet/044_morpho_strategy.js @@ -1,4 +1,4 @@ -const { deploymentWithProposal } = require("../utils/deploy"); +const { deploymentWithProposal } = require("../../utils/deploy"); module.exports = deploymentWithProposal( { deployName: "044_morpho_strategy", forceDeploy: false, proposalId: 39 }, diff --git a/contracts/deploy/045_convex_lusd_meta_strategy.js b/contracts/deploy/mainnet/045_convex_lusd_meta_strategy.js similarity index 84% rename from contracts/deploy/045_convex_lusd_meta_strategy.js rename to contracts/deploy/mainnet/045_convex_lusd_meta_strategy.js index bf59b333e7..4922ee97e2 100644 --- a/contracts/deploy/045_convex_lusd_meta_strategy.js +++ b/contracts/deploy/mainnet/045_convex_lusd_meta_strategy.js @@ -1,5 +1,5 @@ -const generalizedConvexStratDeployment = require("../utils/generalizedConvexStratDeployment"); -const { lusdMetapoolLPCRVPid } = require("../utils/constants"); +const generalizedConvexStratDeployment = require("../../utils/generalizedConvexStratDeployment"); +const { lusdMetapoolLPCRVPid } = require("../../utils/constants"); module.exports = generalizedConvexStratDeployment({ deployName: "045_convex_lusd_meta_strategy", diff --git a/contracts/deploy/046_value_value_checker.js b/contracts/deploy/mainnet/046_value_value_checker.js similarity index 93% rename from contracts/deploy/046_value_value_checker.js rename to contracts/deploy/mainnet/046_value_value_checker.js index b434c4652a..db3eb41656 100644 --- a/contracts/deploy/046_value_value_checker.js +++ b/contracts/deploy/mainnet/046_value_value_checker.js @@ -1,4 +1,4 @@ -const { deploymentWithProposal } = require("../utils/deploy"); +const { deploymentWithProposal } = require("../../utils/deploy"); module.exports = deploymentWithProposal( { deployName: "046_vault_value_checker", forceDeploy: false }, diff --git a/contracts/deploy/047_morpho_aave_strategy.js b/contracts/deploy/mainnet/047_morpho_aave_strategy.js similarity index 98% rename from contracts/deploy/047_morpho_aave_strategy.js rename to contracts/deploy/mainnet/047_morpho_aave_strategy.js index 4cd2a17649..5e5cdc127a 100644 --- a/contracts/deploy/047_morpho_aave_strategy.js +++ b/contracts/deploy/mainnet/047_morpho_aave_strategy.js @@ -1,4 +1,4 @@ -const { deploymentWithProposal } = require("../utils/deploy"); +const { deploymentWithProposal } = require("../../utils/deploy"); module.exports = deploymentWithProposal( { diff --git a/contracts/deploy/048_deposit_withdraw_tooling.js b/contracts/deploy/mainnet/048_deposit_withdraw_tooling.js similarity index 90% rename from contracts/deploy/048_deposit_withdraw_tooling.js rename to contracts/deploy/mainnet/048_deposit_withdraw_tooling.js index 8a9a616641..6ab1795751 100644 --- a/contracts/deploy/048_deposit_withdraw_tooling.js +++ b/contracts/deploy/mainnet/048_deposit_withdraw_tooling.js @@ -1,5 +1,5 @@ -const { deploymentWithGovernanceProposal } = require("../utils/deploy"); -const { isMainnet } = require("../test/helpers.js"); +const { deploymentWithGovernanceProposal } = require("../../utils/deploy"); +const { isMainnet } = require("../../test/helpers.js"); module.exports = deploymentWithGovernanceProposal( { diff --git a/contracts/deploy/049_oeth_proxy.js b/contracts/deploy/mainnet/049_oeth_proxy.js similarity index 91% rename from contracts/deploy/049_oeth_proxy.js rename to contracts/deploy/mainnet/049_oeth_proxy.js index e8130ea8d9..f384e5efce 100644 --- a/contracts/deploy/049_oeth_proxy.js +++ b/contracts/deploy/mainnet/049_oeth_proxy.js @@ -1,5 +1,5 @@ -const { deploymentWithProposal } = require("../utils/deploy"); -const addresses = require("../utils/addresses"); +const { deploymentWithProposal } = require("../../utils/deploy"); +const addresses = require("../../utils/addresses"); module.exports = deploymentWithProposal( { deployName: "049_oeth_proxy", forceDeploy: false, forceSkip: true }, diff --git a/contracts/deploy/050_woeth_proxy.js b/contracts/deploy/mainnet/050_woeth_proxy.js similarity index 91% rename from contracts/deploy/050_woeth_proxy.js rename to contracts/deploy/mainnet/050_woeth_proxy.js index 6d2d7f215b..90a5f8fd6b 100644 --- a/contracts/deploy/050_woeth_proxy.js +++ b/contracts/deploy/mainnet/050_woeth_proxy.js @@ -1,5 +1,5 @@ -const { deploymentWithProposal } = require("../utils/deploy"); -const addresses = require("../utils/addresses"); +const { deploymentWithProposal } = require("../../utils/deploy"); +const addresses = require("../../utils/addresses"); module.exports = deploymentWithProposal( { deployName: "050_woeth_proxy", forceDeploy: false, forceSkip: true }, diff --git a/contracts/deploy/051_upgrade_buyback.js b/contracts/deploy/mainnet/051_upgrade_buyback.js similarity index 97% rename from contracts/deploy/051_upgrade_buyback.js rename to contracts/deploy/mainnet/051_upgrade_buyback.js index 6d70377ccf..e4b5daef40 100644 --- a/contracts/deploy/051_upgrade_buyback.js +++ b/contracts/deploy/mainnet/051_upgrade_buyback.js @@ -1,5 +1,5 @@ -const { deploymentWithGovernanceProposal } = require("../utils/deploy"); -const { getTxOpts } = require("../utils/tx"); +const { deploymentWithGovernanceProposal } = require("../../utils/deploy"); +const { getTxOpts } = require("../../utils/tx"); module.exports = deploymentWithGovernanceProposal( { diff --git a/contracts/deploy/052_upgrade_ousd_vault_harvester.js b/contracts/deploy/mainnet/052_upgrade_ousd_vault_harvester.js similarity index 97% rename from contracts/deploy/052_upgrade_ousd_vault_harvester.js rename to contracts/deploy/mainnet/052_upgrade_ousd_vault_harvester.js index cce6bc8dc2..507c457faf 100644 --- a/contracts/deploy/052_upgrade_ousd_vault_harvester.js +++ b/contracts/deploy/mainnet/052_upgrade_ousd_vault_harvester.js @@ -1,9 +1,9 @@ const { deploymentWithGovernanceProposal, withConfirmation, -} = require("../utils/deploy"); -const addresses = require("../utils/addresses"); -const { isMainnet } = require("../test/helpers.js"); +} = require("../../utils/deploy"); +const addresses = require("../../utils/addresses"); +const { isMainnet } = require("../../test/helpers.js"); module.exports = deploymentWithGovernanceProposal( { diff --git a/contracts/deploy/053_oeth.js b/contracts/deploy/mainnet/053_oeth.js similarity index 97% rename from contracts/deploy/053_oeth.js rename to contracts/deploy/mainnet/053_oeth.js index b35a108d48..e564600ebf 100644 --- a/contracts/deploy/053_oeth.js +++ b/contracts/deploy/mainnet/053_oeth.js @@ -1,8 +1,8 @@ -const { deploymentWithGuardianGovernor } = require("../utils/deploy"); -const addresses = require("../utils/addresses"); +const { deploymentWithGuardianGovernor } = require("../../utils/deploy"); +const addresses = require("../../utils/addresses"); const hre = require("hardhat"); const { BigNumber, utils } = require("ethers"); -const { getAssetAddresses } = require("../test/helpers.js"); +const { getAssetAddresses } = require("../../test/helpers.js"); // 5/8 multisig const guardianAddr = addresses.mainnet.Guardian; diff --git a/contracts/deploy/054_woeth.js b/contracts/deploy/mainnet/054_woeth.js similarity index 93% rename from contracts/deploy/054_woeth.js rename to contracts/deploy/mainnet/054_woeth.js index 960a348cbb..3cf56e9e11 100644 --- a/contracts/deploy/054_woeth.js +++ b/contracts/deploy/mainnet/054_woeth.js @@ -1,4 +1,4 @@ -const { deploymentWithGuardianGovernor } = require("../utils/deploy"); +const { deploymentWithGuardianGovernor } = require("../../utils/deploy"); module.exports = deploymentWithGuardianGovernor( { deployName: "054_woeth" }, diff --git a/contracts/deploy/055_curve_amo.js b/contracts/deploy/mainnet/055_curve_amo.js similarity index 99% rename from contracts/deploy/055_curve_amo.js rename to contracts/deploy/mainnet/055_curve_amo.js index 0da9ebef45..c38f1e411e 100644 --- a/contracts/deploy/055_curve_amo.js +++ b/contracts/deploy/mainnet/055_curve_amo.js @@ -1,10 +1,10 @@ -const { deploymentWithGuardianGovernor } = require("../utils/deploy"); -const addresses = require("../utils/addresses"); +const { deploymentWithGuardianGovernor } = require("../../utils/deploy"); +const addresses = require("../../utils/addresses"); const hre = require("hardhat"); const { utils, Contract } = require("ethers"); -const { getAssetAddresses, isMainnet } = require("../test/helpers.js"); -const { MAX_UINT256, oethPoolLpPID } = require("../utils/constants"); -const { impersonateAndFund } = require("../utils/signers"); +const { getAssetAddresses, isMainnet } = require("../../test/helpers.js"); +const { MAX_UINT256, oethPoolLpPID } = require("../../utils/constants"); +const { impersonateAndFund } = require("../../utils/signers"); const crvRewards = "0x24b65DC1cf053A8D96872c323d29e86ec43eB33A"; const poolAddress = "0x94b17476a93b3262d87b9a326965d1e91f9c13e7"; const tokenAddress = "0x94b17476a93b3262d87b9a326965d1e91f9c13e7"; diff --git a/contracts/deploy/056_oeth_zapper_again.js b/contracts/deploy/mainnet/056_oeth_zapper_again.js similarity index 89% rename from contracts/deploy/056_oeth_zapper_again.js rename to contracts/deploy/mainnet/056_oeth_zapper_again.js index 82e1de4066..081df5601e 100644 --- a/contracts/deploy/056_oeth_zapper_again.js +++ b/contracts/deploy/mainnet/056_oeth_zapper_again.js @@ -1,4 +1,4 @@ -const { deploymentWithProposal } = require("../utils/deploy"); +const { deploymentWithProposal } = require("../../utils/deploy"); module.exports = deploymentWithProposal( { deployName: "056_oeth_zapper_again", forceDeploy: false }, diff --git a/contracts/deploy/057_drip_all.js b/contracts/deploy/mainnet/057_drip_all.js similarity index 96% rename from contracts/deploy/057_drip_all.js rename to contracts/deploy/mainnet/057_drip_all.js index 49bb08d278..3ba28ce257 100644 --- a/contracts/deploy/057_drip_all.js +++ b/contracts/deploy/mainnet/057_drip_all.js @@ -1,4 +1,4 @@ -const { deploymentWithGovernanceProposal } = require("../utils/deploy"); +const { deploymentWithGovernanceProposal } = require("../../utils/deploy"); module.exports = deploymentWithGovernanceProposal( { diff --git a/contracts/deploy/058_oeth_vault_value_checker.js b/contracts/deploy/mainnet/058_oeth_vault_value_checker.js similarity index 91% rename from contracts/deploy/058_oeth_vault_value_checker.js rename to contracts/deploy/mainnet/058_oeth_vault_value_checker.js index 0cd242ae45..f76673eed6 100644 --- a/contracts/deploy/058_oeth_vault_value_checker.js +++ b/contracts/deploy/mainnet/058_oeth_vault_value_checker.js @@ -1,4 +1,4 @@ -const { deploymentWithProposal } = require("../utils/deploy"); +const { deploymentWithProposal } = require("../../utils/deploy"); module.exports = deploymentWithProposal( { deployName: "058_oeth_vault_value_checker" }, diff --git a/contracts/deploy/059_harvest_crv_limit.js b/contracts/deploy/mainnet/059_harvest_crv_limit.js similarity index 96% rename from contracts/deploy/059_harvest_crv_limit.js rename to contracts/deploy/mainnet/059_harvest_crv_limit.js index db2ba53085..ebf7d89c25 100644 --- a/contracts/deploy/059_harvest_crv_limit.js +++ b/contracts/deploy/mainnet/059_harvest_crv_limit.js @@ -1,5 +1,5 @@ const { parseUnits, formatUnits } = require("ethers").utils; -const { deploymentWithGovernanceProposal, log } = require("../utils/deploy"); +const { deploymentWithGovernanceProposal, log } = require("../../utils/deploy"); module.exports = deploymentWithGovernanceProposal( { diff --git a/contracts/deploy/060_harvest_crv_limit_2.js b/contracts/deploy/mainnet/060_harvest_crv_limit_2.js similarity index 96% rename from contracts/deploy/060_harvest_crv_limit_2.js rename to contracts/deploy/mainnet/060_harvest_crv_limit_2.js index 4e15861dc5..98e3e6cf6d 100644 --- a/contracts/deploy/060_harvest_crv_limit_2.js +++ b/contracts/deploy/mainnet/060_harvest_crv_limit_2.js @@ -1,5 +1,5 @@ const { parseUnits, formatUnits } = require("ethers").utils; -const { deploymentWithGovernanceProposal, log } = require("../utils/deploy"); +const { deploymentWithGovernanceProposal, log } = require("../../utils/deploy"); /* The 059 harvest change proposal has timed out. This just re-submits it. */ diff --git a/contracts/deploy/061_oeth_timelock_part_1.js b/contracts/deploy/mainnet/061_oeth_timelock_part_1.js similarity index 93% rename from contracts/deploy/061_oeth_timelock_part_1.js rename to contracts/deploy/mainnet/061_oeth_timelock_part_1.js index 6f3c7badd2..4f5d9cabee 100644 --- a/contracts/deploy/061_oeth_timelock_part_1.js +++ b/contracts/deploy/mainnet/061_oeth_timelock_part_1.js @@ -1,5 +1,5 @@ -const { deploymentWithGuardianGovernor } = require("../utils/deploy"); -const addresses = require("../utils/addresses"); +const { deploymentWithGuardianGovernor } = require("../../utils/deploy"); +const addresses = require("../../utils/addresses"); module.exports = deploymentWithGuardianGovernor( { deployName: "061_oeth_timelock_part_1" }, diff --git a/contracts/deploy/062_oeth_timelock_part_2.js b/contracts/deploy/mainnet/062_oeth_timelock_part_2.js similarity index 96% rename from contracts/deploy/062_oeth_timelock_part_2.js rename to contracts/deploy/mainnet/062_oeth_timelock_part_2.js index bc6dbfa3c2..f715c689f4 100644 --- a/contracts/deploy/062_oeth_timelock_part_2.js +++ b/contracts/deploy/mainnet/062_oeth_timelock_part_2.js @@ -1,4 +1,4 @@ -const { deploymentWithProposal } = require("../utils/deploy"); +const { deploymentWithProposal } = require("../../utils/deploy"); module.exports = deploymentWithProposal( { deployName: "062_oeth_timelock_part_2" }, diff --git a/contracts/deploy/063_oeth_harvest_crv_limit.js b/contracts/deploy/mainnet/063_oeth_harvest_crv_limit.js similarity index 95% rename from contracts/deploy/063_oeth_harvest_crv_limit.js rename to contracts/deploy/mainnet/063_oeth_harvest_crv_limit.js index 1607af1f86..efd99dac4d 100644 --- a/contracts/deploy/063_oeth_harvest_crv_limit.js +++ b/contracts/deploy/mainnet/063_oeth_harvest_crv_limit.js @@ -1,5 +1,5 @@ const { parseUnits, formatUnits } = require("ethers").utils; -const { deploymentWithProposal, log } = require("../utils/deploy"); +const { deploymentWithProposal, log } = require("../../utils/deploy"); /* The 059 harvest change proposal has timed out. This just re-submits it. */ diff --git a/contracts/deploy/064_oeth_mopho_aave_v2.js b/contracts/deploy/mainnet/064_oeth_mopho_aave_v2.js similarity index 95% rename from contracts/deploy/064_oeth_mopho_aave_v2.js rename to contracts/deploy/mainnet/064_oeth_mopho_aave_v2.js index ecf85cbafb..6f55310856 100644 --- a/contracts/deploy/064_oeth_mopho_aave_v2.js +++ b/contracts/deploy/mainnet/064_oeth_mopho_aave_v2.js @@ -1,5 +1,5 @@ -const { deploymentWithProposal } = require("../utils/deploy"); -const addresses = require("../utils/addresses"); +const { deploymentWithProposal } = require("../../utils/deploy"); +const addresses = require("../../utils/addresses"); module.exports = deploymentWithProposal( { diff --git a/contracts/deploy/065_oeth_swapper.js b/contracts/deploy/mainnet/065_oeth_swapper.js similarity index 91% rename from contracts/deploy/065_oeth_swapper.js rename to contracts/deploy/mainnet/065_oeth_swapper.js index a2defe479e..865f4f1c57 100644 --- a/contracts/deploy/065_oeth_swapper.js +++ b/contracts/deploy/mainnet/065_oeth_swapper.js @@ -1,4 +1,4 @@ -const { deploymentWithProposal } = require("../utils/deploy"); +const { deploymentWithProposal } = require("../../utils/deploy"); module.exports = deploymentWithProposal( { deployName: "065_oeth_swapper", forceDeploy: false, reduceQueueTime: true }, diff --git a/contracts/deploy/065_upgrade_fraxeth_strategy.js b/contracts/deploy/mainnet/065_upgrade_fraxeth_strategy.js similarity index 90% rename from contracts/deploy/065_upgrade_fraxeth_strategy.js rename to contracts/deploy/mainnet/065_upgrade_fraxeth_strategy.js index 08981ba261..a3e47672ae 100644 --- a/contracts/deploy/065_upgrade_fraxeth_strategy.js +++ b/contracts/deploy/mainnet/065_upgrade_fraxeth_strategy.js @@ -1,5 +1,5 @@ -const { deploymentWithProposal } = require("../utils/deploy"); -const addresses = require("../utils/addresses"); +const { deploymentWithProposal } = require("../../utils/deploy"); +const addresses = require("../../utils/addresses"); module.exports = deploymentWithProposal( { diff --git a/contracts/deploy/066_oeth_vault_swaps.js b/contracts/deploy/mainnet/066_oeth_vault_swaps.js similarity index 98% rename from contracts/deploy/066_oeth_vault_swaps.js rename to contracts/deploy/mainnet/066_oeth_vault_swaps.js index f8ce4f7a79..582558335f 100644 --- a/contracts/deploy/066_oeth_vault_swaps.js +++ b/contracts/deploy/mainnet/066_oeth_vault_swaps.js @@ -1,4 +1,4 @@ -const { deploymentWithProposal } = require("../utils/deploy"); +const { deploymentWithProposal } = require("../../utils/deploy"); module.exports = deploymentWithProposal( { diff --git a/contracts/deploy/067_ousd_vault_value_checker.js b/contracts/deploy/mainnet/067_ousd_vault_value_checker.js similarity index 91% rename from contracts/deploy/067_ousd_vault_value_checker.js rename to contracts/deploy/mainnet/067_ousd_vault_value_checker.js index b567d06547..75523268b4 100644 --- a/contracts/deploy/067_ousd_vault_value_checker.js +++ b/contracts/deploy/mainnet/067_ousd_vault_value_checker.js @@ -1,4 +1,4 @@ -const { deploymentWithProposal } = require("../utils/deploy"); +const { deploymentWithProposal } = require("../../utils/deploy"); module.exports = deploymentWithProposal( { deployName: "067_ousd_vault_value_checker" }, diff --git a/contracts/deploy/068_oeth_to_ogv_governance_p1.js b/contracts/deploy/mainnet/068_oeth_to_ogv_governance_p1.js similarity index 95% rename from contracts/deploy/068_oeth_to_ogv_governance_p1.js rename to contracts/deploy/mainnet/068_oeth_to_ogv_governance_p1.js index 46b7a5a21a..1ca0078214 100644 --- a/contracts/deploy/068_oeth_to_ogv_governance_p1.js +++ b/contracts/deploy/mainnet/068_oeth_to_ogv_governance_p1.js @@ -1,5 +1,5 @@ -const { deploymentWithProposal } = require("../utils/deploy"); -const addresses = require("../utils/addresses"); +const { deploymentWithProposal } = require("../../utils/deploy"); +const addresses = require("../../utils/addresses"); module.exports = deploymentWithProposal( { diff --git a/contracts/deploy/069_oeth_to_ogv_governance_p2.js b/contracts/deploy/mainnet/069_oeth_to_ogv_governance_p2.js similarity index 96% rename from contracts/deploy/069_oeth_to_ogv_governance_p2.js rename to contracts/deploy/mainnet/069_oeth_to_ogv_governance_p2.js index 87768cbc3c..8902d1fe6d 100644 --- a/contracts/deploy/069_oeth_to_ogv_governance_p2.js +++ b/contracts/deploy/mainnet/069_oeth_to_ogv_governance_p2.js @@ -1,4 +1,4 @@ -const { deploymentWithGovernanceProposal } = require("../utils/deploy"); +const { deploymentWithGovernanceProposal } = require("../../utils/deploy"); module.exports = deploymentWithGovernanceProposal( { diff --git a/contracts/deploy/070_flux_strategy.js b/contracts/deploy/mainnet/070_flux_strategy.js similarity index 95% rename from contracts/deploy/070_flux_strategy.js rename to contracts/deploy/mainnet/070_flux_strategy.js index 5b3bbfa7b6..1915370268 100644 --- a/contracts/deploy/070_flux_strategy.js +++ b/contracts/deploy/mainnet/070_flux_strategy.js @@ -2,9 +2,9 @@ const { deploymentWithGovernanceProposal, deployWithConfirmation, withConfirmation, -} = require("../utils/deploy"); -const addresses = require("../utils/addresses"); -const { getTxOpts } = require("../utils/tx"); +} = require("../../utils/deploy"); +const addresses = require("../../utils/addresses"); +const { getTxOpts } = require("../../utils/tx"); module.exports = deploymentWithGovernanceProposal( { diff --git a/contracts/deploy/071_balancer_rETH_WETH.js b/contracts/deploy/mainnet/071_balancer_rETH_WETH.js similarity index 95% rename from contracts/deploy/071_balancer_rETH_WETH.js rename to contracts/deploy/mainnet/071_balancer_rETH_WETH.js index 46f20f0594..1e6760be89 100644 --- a/contracts/deploy/071_balancer_rETH_WETH.js +++ b/contracts/deploy/mainnet/071_balancer_rETH_WETH.js @@ -1,6 +1,6 @@ -const { deploymentWithGovernanceProposal } = require("../utils/deploy"); -const addresses = require("../utils/addresses"); -const { balancer_rETH_WETH_PID } = require("../utils/constants"); +const { deploymentWithGovernanceProposal } = require("../../utils/deploy"); +const addresses = require("../../utils/addresses"); +const { balancer_rETH_WETH_PID } = require("../../utils/constants"); const platformAddress = addresses.mainnet.rETH_WETH_BPT; diff --git a/contracts/deploy/072_ousd_maker_dsr.js b/contracts/deploy/mainnet/072_ousd_maker_dsr.js similarity index 96% rename from contracts/deploy/072_ousd_maker_dsr.js rename to contracts/deploy/mainnet/072_ousd_maker_dsr.js index cb15cc0d64..c1c7596504 100644 --- a/contracts/deploy/072_ousd_maker_dsr.js +++ b/contracts/deploy/mainnet/072_ousd_maker_dsr.js @@ -1,5 +1,5 @@ -const addresses = require("../utils/addresses"); -const { deploymentWithGovernanceProposal } = require("../utils/deploy"); +const addresses = require("../../utils/addresses"); +const { deploymentWithGovernanceProposal } = require("../../utils/deploy"); module.exports = deploymentWithGovernanceProposal( { diff --git a/contracts/deploy/073_ousd_disable_stratgies.js b/contracts/deploy/mainnet/073_ousd_disable_stratgies.js similarity index 95% rename from contracts/deploy/073_ousd_disable_stratgies.js rename to contracts/deploy/mainnet/073_ousd_disable_stratgies.js index 92c9d1de43..5e813ca908 100644 --- a/contracts/deploy/073_ousd_disable_stratgies.js +++ b/contracts/deploy/mainnet/073_ousd_disable_stratgies.js @@ -1,4 +1,4 @@ -const { deploymentWithGovernanceProposal } = require("../utils/deploy"); +const { deploymentWithGovernanceProposal } = require("../../utils/deploy"); module.exports = deploymentWithGovernanceProposal( { diff --git a/contracts/deploy/074_upgrade_oeth_oracle_router.js b/contracts/deploy/mainnet/074_upgrade_oeth_oracle_router.js similarity index 95% rename from contracts/deploy/074_upgrade_oeth_oracle_router.js rename to contracts/deploy/mainnet/074_upgrade_oeth_oracle_router.js index d4d0e8b8c6..7174c73c07 100644 --- a/contracts/deploy/074_upgrade_oeth_oracle_router.js +++ b/contracts/deploy/mainnet/074_upgrade_oeth_oracle_router.js @@ -1,9 +1,9 @@ -const addresses = require("../utils/addresses"); +const addresses = require("../../utils/addresses"); const { deploymentWithGovernanceProposal, deployWithConfirmation, withConfirmation, -} = require("../utils/deploy"); +} = require("../../utils/deploy"); module.exports = deploymentWithGovernanceProposal( { diff --git a/contracts/deploy/075_oeth_amo_upgrade.js b/contracts/deploy/mainnet/075_oeth_amo_upgrade.js similarity index 88% rename from contracts/deploy/075_oeth_amo_upgrade.js rename to contracts/deploy/mainnet/075_oeth_amo_upgrade.js index da5c690045..2c395397b0 100644 --- a/contracts/deploy/075_oeth_amo_upgrade.js +++ b/contracts/deploy/mainnet/075_oeth_amo_upgrade.js @@ -1,6 +1,6 @@ -const addresses = require("../utils/addresses"); -const { oethPoolLpPID } = require("../utils/constants"); -const { deploymentWithGovernanceProposal } = require("../utils/deploy"); +const addresses = require("../../utils/addresses"); +const { oethPoolLpPID } = require("../../utils/constants"); +const { deploymentWithGovernanceProposal } = require("../../utils/deploy"); module.exports = deploymentWithGovernanceProposal( { diff --git a/contracts/deploy/076_upgrade_fraxeth_strategy.js b/contracts/deploy/mainnet/076_upgrade_fraxeth_strategy.js similarity index 91% rename from contracts/deploy/076_upgrade_fraxeth_strategy.js rename to contracts/deploy/mainnet/076_upgrade_fraxeth_strategy.js index 5c70c656ac..42db175b69 100644 --- a/contracts/deploy/076_upgrade_fraxeth_strategy.js +++ b/contracts/deploy/mainnet/076_upgrade_fraxeth_strategy.js @@ -1,5 +1,5 @@ -const { deploymentWithGovernanceProposal } = require("../utils/deploy"); -const addresses = require("../utils/addresses"); +const { deploymentWithGovernanceProposal } = require("../../utils/deploy"); +const addresses = require("../../utils/addresses"); module.exports = deploymentWithGovernanceProposal( { diff --git a/contracts/deploy/077_balancer_rETH_WETH.js b/contracts/deploy/mainnet/077_balancer_rETH_WETH.js similarity index 91% rename from contracts/deploy/077_balancer_rETH_WETH.js rename to contracts/deploy/mainnet/077_balancer_rETH_WETH.js index 2872114a4c..4c6fabe66a 100644 --- a/contracts/deploy/077_balancer_rETH_WETH.js +++ b/contracts/deploy/mainnet/077_balancer_rETH_WETH.js @@ -1,6 +1,6 @@ -const { deploymentWithGovernanceProposal } = require("../utils/deploy"); -const addresses = require("../utils/addresses"); -const { balancer_rETH_WETH_PID } = require("../utils/constants"); +const { deploymentWithGovernanceProposal } = require("../../utils/deploy"); +const addresses = require("../../utils/addresses"); +const { balancer_rETH_WETH_PID } = require("../../utils/constants"); const platformAddress = addresses.mainnet.rETH_WETH_BPT; diff --git a/contracts/deploy/080_upgrade_buyback.js b/contracts/deploy/mainnet/080_upgrade_buyback.js similarity index 98% rename from contracts/deploy/080_upgrade_buyback.js rename to contracts/deploy/mainnet/080_upgrade_buyback.js index 410aa360e7..6e16521f41 100644 --- a/contracts/deploy/080_upgrade_buyback.js +++ b/contracts/deploy/mainnet/080_upgrade_buyback.js @@ -1,8 +1,8 @@ const { deploymentWithGovernanceProposal, withConfirmation, -} = require("../utils/deploy"); -const addresses = require("../utils/addresses"); +} = require("../../utils/deploy"); +const addresses = require("../../utils/addresses"); module.exports = deploymentWithGovernanceProposal( { diff --git a/contracts/deploy/081_upgrade_harvester.js b/contracts/deploy/mainnet/081_upgrade_harvester.js similarity index 98% rename from contracts/deploy/081_upgrade_harvester.js rename to contracts/deploy/mainnet/081_upgrade_harvester.js index 0ae5466b17..4299652d76 100644 --- a/contracts/deploy/081_upgrade_harvester.js +++ b/contracts/deploy/mainnet/081_upgrade_harvester.js @@ -1,9 +1,9 @@ const { deploymentWithGovernanceProposal, withConfirmation, -} = require("../utils/deploy"); -const addresses = require("../utils/addresses"); -const { oethUnits } = require("../test/helpers"); +} = require("../../utils/deploy"); +const addresses = require("../../utils/addresses"); +const { oethUnits } = require("../../test/helpers"); const { utils } = require("ethers"); module.exports = deploymentWithGovernanceProposal( diff --git a/contracts/deploy/082_upgrade_oeth.js b/contracts/deploy/mainnet/082_upgrade_oeth.js similarity index 95% rename from contracts/deploy/082_upgrade_oeth.js rename to contracts/deploy/mainnet/082_upgrade_oeth.js index 7e8402801f..c865d8bd74 100644 --- a/contracts/deploy/082_upgrade_oeth.js +++ b/contracts/deploy/mainnet/082_upgrade_oeth.js @@ -1,4 +1,4 @@ -const { deploymentWithGovernanceProposal } = require("../utils/deploy"); +const { deploymentWithGovernanceProposal } = require("../../utils/deploy"); module.exports = deploymentWithGovernanceProposal( { diff --git a/contracts/deploy/083_dripper_seven_day.js b/contracts/deploy/mainnet/083_dripper_seven_day.js similarity index 95% rename from contracts/deploy/083_dripper_seven_day.js rename to contracts/deploy/mainnet/083_dripper_seven_day.js index c8df6102db..ad1c383a90 100644 --- a/contracts/deploy/083_dripper_seven_day.js +++ b/contracts/deploy/mainnet/083_dripper_seven_day.js @@ -1,4 +1,4 @@ -const { deploymentWithGovernanceProposal } = require("../utils/deploy"); +const { deploymentWithGovernanceProposal } = require("../../utils/deploy"); module.exports = deploymentWithGovernanceProposal( { diff --git a/contracts/deploy/084_delpoy_woeth_on_arb.js b/contracts/deploy/mainnet/084_delpoy_woeth_on_arb.js similarity index 87% rename from contracts/deploy/084_delpoy_woeth_on_arb.js rename to contracts/deploy/mainnet/084_delpoy_woeth_on_arb.js index b186b14d5e..3ee28446f5 100644 --- a/contracts/deploy/084_delpoy_woeth_on_arb.js +++ b/contracts/deploy/mainnet/084_delpoy_woeth_on_arb.js @@ -1,6 +1,9 @@ -const { deployOnArb } = require("../utils/delpoy-l2"); -const { deployWithConfirmation, withConfirmation } = require("../utils/deploy"); -const { getTxOpts } = require("../utils/tx"); +const { deployOnArb } = require("../../utils/delpoy-l2"); +const { + deployWithConfirmation, + withConfirmation, +} = require("../../utils/deploy"); +const { getTxOpts } = require("../../utils/tx"); module.exports = deployOnArb( { diff --git a/contracts/deploy/085_upgrade_oeth_vault.js b/contracts/deploy/mainnet/085_upgrade_oeth_vault.js similarity index 93% rename from contracts/deploy/085_upgrade_oeth_vault.js rename to contracts/deploy/mainnet/085_upgrade_oeth_vault.js index 1c137a9eb8..f94c2f1880 100644 --- a/contracts/deploy/085_upgrade_oeth_vault.js +++ b/contracts/deploy/mainnet/085_upgrade_oeth_vault.js @@ -1,8 +1,8 @@ -const addresses = require("../utils/addresses"); +const addresses = require("../../utils/addresses"); const { deploymentWithGovernanceProposal, deployWithConfirmation, -} = require("../utils/deploy"); +} = require("../../utils/deploy"); module.exports = deploymentWithGovernanceProposal( { diff --git a/contracts/deploy/086_frxeth_redeem_strat.js b/contracts/deploy/mainnet/086_frxeth_redeem_strat.js similarity index 95% rename from contracts/deploy/086_frxeth_redeem_strat.js rename to contracts/deploy/mainnet/086_frxeth_redeem_strat.js index 4f11e82b1a..e15c142400 100644 --- a/contracts/deploy/086_frxeth_redeem_strat.js +++ b/contracts/deploy/mainnet/086_frxeth_redeem_strat.js @@ -1,5 +1,5 @@ -const { deploymentWithGovernanceProposal } = require("../utils/deploy"); -const addresses = require("../utils/addresses"); +const { deploymentWithGovernanceProposal } = require("../../utils/deploy"); +const addresses = require("../../utils/addresses"); module.exports = deploymentWithGovernanceProposal( { diff --git a/contracts/deploy/087_reduce_redeem_fee.js b/contracts/deploy/mainnet/087_reduce_redeem_fee.js similarity index 92% rename from contracts/deploy/087_reduce_redeem_fee.js rename to contracts/deploy/mainnet/087_reduce_redeem_fee.js index de4eb46faa..ba19afce5a 100644 --- a/contracts/deploy/087_reduce_redeem_fee.js +++ b/contracts/deploy/mainnet/087_reduce_redeem_fee.js @@ -1,4 +1,4 @@ -const { deploymentWithGovernanceProposal } = require("../utils/deploy"); +const { deploymentWithGovernanceProposal } = require("../../utils/deploy"); module.exports = deploymentWithGovernanceProposal( { diff --git a/contracts/deploy/088_upgrade_woeth_on_arb.js b/contracts/deploy/mainnet/088_upgrade_woeth_on_arb.js similarity index 74% rename from contracts/deploy/088_upgrade_woeth_on_arb.js rename to contracts/deploy/mainnet/088_upgrade_woeth_on_arb.js index 8478268f04..72954cc794 100644 --- a/contracts/deploy/088_upgrade_woeth_on_arb.js +++ b/contracts/deploy/mainnet/088_upgrade_woeth_on_arb.js @@ -1,7 +1,7 @@ -const { isFork } = require("../test/helpers"); -const { deployOnArb } = require("../utils/delpoy-l2"); -const { deployWithConfirmation } = require("../utils/deploy"); -const { impersonateAndFund } = require("../utils/signers"); +const { isFork } = require("../../test/helpers"); +const { deployOnArb } = require("../../utils/delpoy-l2"); +const { deployWithConfirmation } = require("../../utils/deploy"); +const { impersonateAndFund } = require("../../utils/signers"); module.exports = deployOnArb( { diff --git a/contracts/deploy/089_1inch_buyback.js b/contracts/deploy/mainnet/089_1inch_buyback.js similarity index 97% rename from contracts/deploy/089_1inch_buyback.js rename to contracts/deploy/mainnet/089_1inch_buyback.js index 571dd012f5..d1578f5c61 100644 --- a/contracts/deploy/089_1inch_buyback.js +++ b/contracts/deploy/mainnet/089_1inch_buyback.js @@ -1,8 +1,8 @@ -const addresses = require("../utils/addresses"); +const addresses = require("../../utils/addresses"); const { deploymentWithGovernanceProposal, deployWithConfirmation, -} = require("../utils/deploy"); +} = require("../../utils/deploy"); module.exports = deploymentWithGovernanceProposal( { diff --git a/contracts/deploy/089_simplified_oeth_vault.js b/contracts/deploy/mainnet/089_simplified_oeth_vault.js similarity index 93% rename from contracts/deploy/089_simplified_oeth_vault.js rename to contracts/deploy/mainnet/089_simplified_oeth_vault.js index 59a28ba3bf..ff28c40493 100644 --- a/contracts/deploy/089_simplified_oeth_vault.js +++ b/contracts/deploy/mainnet/089_simplified_oeth_vault.js @@ -1,8 +1,8 @@ -const addresses = require("../utils/addresses"); +const addresses = require("../../utils/addresses"); const { deploymentWithGovernanceProposal, deployWithConfirmation, -} = require("../utils/deploy"); +} = require("../../utils/deploy"); module.exports = deploymentWithGovernanceProposal( { diff --git a/contracts/deploy/090_disable_compound.js b/contracts/deploy/mainnet/090_disable_compound.js similarity index 87% rename from contracts/deploy/090_disable_compound.js rename to contracts/deploy/mainnet/090_disable_compound.js index 2f2fbc880d..1309da792d 100644 --- a/contracts/deploy/090_disable_compound.js +++ b/contracts/deploy/mainnet/090_disable_compound.js @@ -1,5 +1,5 @@ -const addresses = require("../utils/addresses"); -const { deploymentWithGovernanceProposal } = require("../utils/deploy"); +const addresses = require("../../utils/addresses"); +const { deploymentWithGovernanceProposal } = require("../../utils/deploy"); module.exports = deploymentWithGovernanceProposal( { diff --git a/contracts/deploy/091_native_ssv_staking.js b/contracts/deploy/mainnet/091_native_ssv_staking.js similarity index 96% rename from contracts/deploy/091_native_ssv_staking.js rename to contracts/deploy/mainnet/091_native_ssv_staking.js index 9b4748ad3b..77cb1135e8 100644 --- a/contracts/deploy/091_native_ssv_staking.js +++ b/contracts/deploy/mainnet/091_native_ssv_staking.js @@ -1,5 +1,5 @@ -const { deploymentWithGovernanceProposal } = require("../utils/deploy"); -const addresses = require("../utils/addresses"); +const { deploymentWithGovernanceProposal } = require("../../utils/deploy"); +const addresses = require("../../utils/addresses"); module.exports = deploymentWithGovernanceProposal( { @@ -8,7 +8,6 @@ module.exports = deploymentWithGovernanceProposal( //forceSkip: true, deployerIsProposer: false, // proposalId: - // "", }, async ({ deployWithConfirmation, ethers, getTxOpts, withConfirmation }) => { const { deployerAddr } = await getNamedAccounts(); @@ -73,7 +72,7 @@ module.exports = deploymentWithGovernanceProposal( const initData = cStrategyImpl.interface.encodeFunctionData( "initialize(address[],address[],address[])", [ - [addresses.mainnet.WETH, addresses.mainnet.SSV], // reward token addresses + [addresses.mainnet.WETH], // reward token addresses /* no need to specify WETH as an asset, since we have that overriden in the "supportsAsset" * function on the strategy */ diff --git a/contracts/deploy/999_fork_test_setup.js b/contracts/deploy/mainnet/999_fork_test_setup.js similarity index 85% rename from contracts/deploy/999_fork_test_setup.js rename to contracts/deploy/mainnet/999_fork_test_setup.js index 4b752ab62e..1bade75cde 100644 --- a/contracts/deploy/999_fork_test_setup.js +++ b/contracts/deploy/mainnet/999_fork_test_setup.js @@ -1,14 +1,14 @@ -const { isFork, isForkWithLocalNode } = require("../test/helpers"); -const { deployWithConfirmation } = require("../utils/deploy"); -const { fundAccounts } = require("../utils/funding"); -const addresses = require("../utils/addresses"); -const { replaceContractAt } = require("../utils/hardhat"); -const { impersonateAndFund } = require("../utils/signers"); -const { hardhatSetBalance } = require("../test/_fund"); +const { isFork, isForkWithLocalNode } = require("../../test/helpers"); +const { deployWithConfirmation } = require("../../utils/deploy"); +const { fundAccounts } = require("../../utils/funding"); +const addresses = require("../../utils/addresses"); +const { replaceContractAt } = require("../../utils/hardhat"); +const { impersonateAndFund } = require("../../utils/signers"); +const { hardhatSetBalance } = require("../../test/_fund"); -const daiAbi = require("../test/abi/dai.json").abi; +const daiAbi = require("../../test/abi/dai.json").abi; -const log = require("../utils/logger")("deploy:999_fork_test_setup"); +const log = require("../../utils/logger")("deploy:999_fork_test_setup"); const main = async (hre) => { log(`Running 999_fork_test_setup deployment...`); diff --git a/contracts/deployments/holesky/.chainId b/contracts/deployments/holesky/.chainId new file mode 100644 index 0000000000..029d1a32ff --- /dev/null +++ b/contracts/deployments/holesky/.chainId @@ -0,0 +1 @@ +17000 \ No newline at end of file diff --git a/contracts/deployments/holesky/.migrations.json b/contracts/deployments/holesky/.migrations.json new file mode 100644 index 0000000000..d45ad24364 --- /dev/null +++ b/contracts/deployments/holesky/.migrations.json @@ -0,0 +1,5 @@ +{ + "001_core": 1714168010, + "002_upgrade_strategy": 1714233842, + "003_deposit_to_native_strategy": 1714307581 +} \ No newline at end of file diff --git a/contracts/deployments/holesky/FeeAccumulator.json b/contracts/deployments/holesky/FeeAccumulator.json new file mode 100644 index 0000000000..863cc1ba96 --- /dev/null +++ b/contracts/deployments/holesky/FeeAccumulator.json @@ -0,0 +1,218 @@ +{ + "address": "0x79681d3f14a0068479420eE5fDdF59B62301f810", + "abi": [ + { + "inputs": [ + { + "internalType": "address", + "name": "_strategy", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "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": true, + "internalType": "address", + "name": "previousGovernor", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newGovernor", + "type": "address" + } + ], + "name": "PendingGovernorshipTransfer", + "type": "event" + }, + { + "inputs": [], + "name": "STRATEGY", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "claimGovernance", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "collect", + "outputs": [ + { + "internalType": "uint256", + "name": "eth", + "type": "uint256" + } + ], + "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": [ + { + "internalType": "address", + "name": "_newGovernor", + "type": "address" + } + ], + "name": "transferGovernance", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "transactionHash": "0x19762cf6f04f946ee9af7a2b33ef576781afc364bf031afe6319b03d0c531a6d", + "receipt": { + "to": null, + "from": "0x1b94CA50D3Ad9f8368851F8526132272d1a5028C", + "contractAddress": "0x79681d3f14a0068479420eE5fDdF59B62301f810", + "transactionIndex": 63, + "gasUsed": "405585", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000008000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000000004000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000010000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000080000000000000000", + "blockHash": "0xc40d7f3894c751ce39361b41360973e012fccc0bcc8770bcbb6a926d9474a899", + "transactionHash": "0x19762cf6f04f946ee9af7a2b33ef576781afc364bf031afe6319b03d0c531a6d", + "logs": [ + { + "transactionIndex": 63, + "blockNumber": 1405126, + "transactionHash": "0x19762cf6f04f946ee9af7a2b33ef576781afc364bf031afe6319b03d0c531a6d", + "address": "0x79681d3f14a0068479420eE5fDdF59B62301f810", + "topics": [ + "0xc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000001b94ca50d3ad9f8368851f8526132272d1a5028c" + ], + "data": "0x", + "logIndex": 69, + "blockHash": "0xc40d7f3894c751ce39361b41360973e012fccc0bcc8770bcbb6a926d9474a899" + } + ], + "blockNumber": 1405126, + "cumulativeGasUsed": "7055269", + "status": 1, + "byzantium": true + }, + "args": [ + "0x4Eac8847c7AE50e3A3551B1Aa4FF7Cc162151410" + ], + "numDeployments": 1, + "solcInputHash": "0213c8dc30149ba5fb281c6d46803d0b", + "metadata": "{\"compiler\":{\"version\":\"0.8.7+commit.e28d00a7\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_strategy\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"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\":true,\"internalType\":\"address\",\"name\":\"previousGovernor\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newGovernor\",\"type\":\"address\"}],\"name\":\"PendingGovernorshipTransfer\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"STRATEGY\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"claimGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"collect\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"eth\",\"type\":\"uint256\"}],\"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\":[{\"internalType\":\"address\",\"name\":\"_newGovernor\",\"type\":\"address\"}],\"name\":\"transferGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"author\":\"Origin Protocol Inc\",\"kind\":\"dev\",\"methods\":{\"collect()\":{\"returns\":{\"eth\":\"The amount of execution rewards that were sent to the Native Staking Strategy\"}},\"constructor\":{\"params\":{\"_strategy\":\"Address of the Native Staking Strategy\"}},\"transferGovernance(address)\":{\"params\":{\"_newGovernor\":\"Address of the new Governor\"}}},\"title\":\"Fee Accumulator for Native Staking SSV Strategy\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"STRATEGY()\":{\"notice\":\"The address of the Native Staking Strategy\"},\"claimGovernance()\":{\"notice\":\"Claim Governance of the contract to a new account (`newGovernor`). Can only be called by the new Governor.\"},\"collect()\":{\"notice\":\"sends all ETH in this FeeAccumulator contract to the Native Staking Strategy.\"},\"governor()\":{\"notice\":\"Returns the address of the current Governor.\"},\"isGovernor()\":{\"notice\":\"Returns true if the caller is the current Governor.\"},\"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\"}},\"notice\":\"Receives execution rewards which includes tx fees and MEV rewards like tx priority and tx ordering. It does NOT include swept ETH from beacon chain consensus rewards or full validator withdrawals.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/strategies/NativeStaking/FeeAccumulator.sol\":\"FeeAccumulator\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@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\"},\"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/strategies/NativeStaking/FeeAccumulator.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport { Address } from \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\n\\nimport { Governable } from \\\"../../governance/Governable.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 is Governable {\\n /// @notice The address of the Native Staking Strategy\\n address public immutable STRATEGY;\\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 }\\n}\\n\",\"keccak256\":\"0xf47bcc46ce70f649f061bec3d2303f376a15700ba18fe471fba823f60bdfed8b\",\"license\":\"MIT\"}},\"version\":1}", + "bytecode": "0x60a060405234801561001057600080fd5b506040516106fe3803806106fe83398101604081905261002f916100a1565b610045336000805160206106de83398151915255565b6000805160206106de833981519152546040516001600160a01b03909116906000907fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a908290a360601b6001600160601b0319166080526100d1565b6000602082840312156100b357600080fd5b81516001600160a01b03811681146100ca57600080fd5b9392505050565b60805160601c6105e26100fc600039600081816091015281816102d8015261035201526105e26000f3fe608060405234801561001057600080fd5b50600436106100625760003560e01c80630c340a2414610067578063185025ef1461008c5780635d36b190146100b3578063c7af3352146100bd578063d38bfff4146100d5578063e5225381146100e8575b600080fd5b61006f6100fe565b6040516001600160a01b0390911681526020015b60405180910390f35b61006f7f000000000000000000000000000000000000000000000000000000000000000081565b6100bb61011b565b005b6100c56101c6565b6040519015158152602001610083565b6100bb6100e336600461055c565b6101f7565b6100f06102cb565b604051908152602001610083565b600061011660008051602061058d8339815191525490565b905090565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b0316146101bb5760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b60648201526084015b60405180910390fd5b6101c43361037a565b565b60006101de60008051602061058d8339815191525490565b6001600160a01b0316336001600160a01b031614905090565b6101ff6101c6565b61024b5760405162461bcd60e51b815260206004820152601a60248201527f43616c6c6572206973206e6f742074686520476f7665726e6f7200000000000060448201526064016101b2565b610273817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b031661029360008051602061058d8339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b6000336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146103455760405162461bcd60e51b815260206004820152601a60248201527f43616c6c6572206973206e6f742074686520537472617465677900000000000060448201526064016101b2565b50478015610377576103777f00000000000000000000000000000000000000000000000000000000000000008261043e565b90565b6001600160a01b0381166103d05760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f72206973206164647265737328302900000000000060448201526064016101b2565b806001600160a01b03166103f060008051602061058d8339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a361043b8160008051602061058d83398151915255565b50565b8047101561048e5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e636500000060448201526064016101b2565b6000826001600160a01b03168260405160006040518083038185875af1925050503d80600081146104db576040519150601f19603f3d011682016040523d82523d6000602084013e6104e0565b606091505b50509050806105575760405162461bcd60e51b815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d6179206861766520726576657274656400000000000060648201526084016101b2565b505050565b60006020828403121561056e57600080fd5b81356001600160a01b038116811461058557600080fd5b939250505056fe7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa26469706673582212200be77de36795d09032129c2625dac1fb5df5aa816a58c269aa5090717764a41664736f6c634300080700337bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a", + "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106100625760003560e01c80630c340a2414610067578063185025ef1461008c5780635d36b190146100b3578063c7af3352146100bd578063d38bfff4146100d5578063e5225381146100e8575b600080fd5b61006f6100fe565b6040516001600160a01b0390911681526020015b60405180910390f35b61006f7f000000000000000000000000000000000000000000000000000000000000000081565b6100bb61011b565b005b6100c56101c6565b6040519015158152602001610083565b6100bb6100e336600461055c565b6101f7565b6100f06102cb565b604051908152602001610083565b600061011660008051602061058d8339815191525490565b905090565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b0316146101bb5760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b60648201526084015b60405180910390fd5b6101c43361037a565b565b60006101de60008051602061058d8339815191525490565b6001600160a01b0316336001600160a01b031614905090565b6101ff6101c6565b61024b5760405162461bcd60e51b815260206004820152601a60248201527f43616c6c6572206973206e6f742074686520476f7665726e6f7200000000000060448201526064016101b2565b610273817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b031661029360008051602061058d8339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b6000336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146103455760405162461bcd60e51b815260206004820152601a60248201527f43616c6c6572206973206e6f742074686520537472617465677900000000000060448201526064016101b2565b50478015610377576103777f00000000000000000000000000000000000000000000000000000000000000008261043e565b90565b6001600160a01b0381166103d05760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f72206973206164647265737328302900000000000060448201526064016101b2565b806001600160a01b03166103f060008051602061058d8339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a361043b8160008051602061058d83398151915255565b50565b8047101561048e5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e636500000060448201526064016101b2565b6000826001600160a01b03168260405160006040518083038185875af1925050503d80600081146104db576040519150601f19603f3d011682016040523d82523d6000602084013e6104e0565b606091505b50509050806105575760405162461bcd60e51b815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d6179206861766520726576657274656400000000000060648201526084016101b2565b505050565b60006020828403121561056e57600080fd5b81356001600160a01b038116811461058557600080fd5b939250505056fe7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa26469706673582212200be77de36795d09032129c2625dac1fb5df5aa816a58c269aa5090717764a41664736f6c63430008070033", + "libraries": {}, + "devdoc": { + "author": "Origin Protocol Inc", + "kind": "dev", + "methods": { + "collect()": { + "returns": { + "eth": "The amount of execution rewards that were sent to the Native Staking Strategy" + } + }, + "constructor": { + "params": { + "_strategy": "Address of the Native Staking Strategy" + } + }, + "transferGovernance(address)": { + "params": { + "_newGovernor": "Address of the new Governor" + } + } + }, + "title": "Fee Accumulator for Native Staking SSV Strategy", + "version": 1 + }, + "userdoc": { + "kind": "user", + "methods": { + "STRATEGY()": { + "notice": "The address of the Native Staking Strategy" + }, + "claimGovernance()": { + "notice": "Claim Governance of the contract to a new account (`newGovernor`). Can only be called by the new Governor." + }, + "collect()": { + "notice": "sends all ETH in this FeeAccumulator contract to the Native Staking Strategy." + }, + "governor()": { + "notice": "Returns the address of the current Governor." + }, + "isGovernor()": { + "notice": "Returns true if the caller is the current Governor." + }, + "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" + } + }, + "notice": "Receives execution rewards which includes tx fees and MEV rewards like tx priority and tx ordering. It does NOT include swept ETH from beacon chain consensus rewards or full validator withdrawals.", + "version": 1 + }, + "storageLayout": { + "storage": [], + "types": null + } +} \ No newline at end of file diff --git a/contracts/deployments/holesky/NativeStakingFeeAccumulatorProxy.json b/contracts/deployments/holesky/NativeStakingFeeAccumulatorProxy.json new file mode 100644 index 0000000000..613ebfdf20 --- /dev/null +++ b/contracts/deployments/holesky/NativeStakingFeeAccumulatorProxy.json @@ -0,0 +1,289 @@ +{ + "address": "0x590B781b511e953dbFC49e7E7864A6E787aFBDCc", + "abi": [ + { + "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": true, + "internalType": "address", + "name": "previousGovernor", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newGovernor", + "type": "address" + } + ], + "name": "PendingGovernorshipTransfer", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "implementation", + "type": "address" + } + ], + "name": "Upgraded", + "type": "event" + }, + { + "stateMutability": "payable", + "type": "fallback" + }, + { + "inputs": [], + "name": "admin", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "claimGovernance", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "governor", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "implementation", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_logic", + "type": "address" + }, + { + "internalType": "address", + "name": "_initGovernor", + "type": "address" + }, + { + "internalType": "bytes", + "name": "_data", + "type": "bytes" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [], + "name": "isGovernor", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_newGovernor", + "type": "address" + } + ], + "name": "transferGovernance", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newImplementation", + "type": "address" + } + ], + "name": "upgradeTo", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newImplementation", + "type": "address" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "upgradeToAndCall", + "outputs": [], + "stateMutability": "payable", + "type": "function" + } + ], + "transactionHash": "0xe18ea4add8d4b624520b0d846ca2cd46ce529dbfe4b1cd3d0021af17f101976c", + "receipt": { + "to": null, + "from": "0x1b94CA50D3Ad9f8368851F8526132272d1a5028C", + "contractAddress": "0x590B781b511e953dbFC49e7E7864A6E787aFBDCc", + "transactionIndex": 27, + "gasUsed": "580428", + "logsBloom": "0x00000000000000000000000000000000000000004000000000000000000000000000000000000100000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000000004000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000010000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000400000000", + "blockHash": "0x5b923d8e846ac85cdb6738b81eb0c4497e0bae72d3df76486bafd0c5370abe94", + "transactionHash": "0xe18ea4add8d4b624520b0d846ca2cd46ce529dbfe4b1cd3d0021af17f101976c", + "logs": [ + { + "transactionIndex": 27, + "blockNumber": 1405107, + "transactionHash": "0xe18ea4add8d4b624520b0d846ca2cd46ce529dbfe4b1cd3d0021af17f101976c", + "address": "0x590B781b511e953dbFC49e7E7864A6E787aFBDCc", + "topics": [ + "0xc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000001b94ca50d3ad9f8368851f8526132272d1a5028c" + ], + "data": "0x", + "logIndex": 35, + "blockHash": "0x5b923d8e846ac85cdb6738b81eb0c4497e0bae72d3df76486bafd0c5370abe94" + } + ], + "blockNumber": 1405107, + "cumulativeGasUsed": "3056739", + "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\":true,\"internalType\":\"address\",\"name\":\"previousGovernor\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newGovernor\",\"type\":\"address\"}],\"name\":\"GovernorshipTransferred\",\"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\":true,\"internalType\":\"address\",\"name\":\"implementation\",\"type\":\"address\"}],\"name\":\"Upgraded\",\"type\":\"event\"},{\"stateMutability\":\"payable\",\"type\":\"fallback\"},{\"inputs\":[],\"name\":\"admin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"claimGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"governor\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"implementation\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_logic\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_initGovernor\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isGovernor\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_newGovernor\",\"type\":\"address\"}],\"name\":\"transferGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newImplementation\",\"type\":\"address\"}],\"name\":\"upgradeTo\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newImplementation\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"upgradeToAndCall\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"admin()\":{\"returns\":{\"_0\":\"The address of the proxy admin/it's also the governor.\"}},\"implementation()\":{\"returns\":{\"_0\":\"The address of the implementation.\"}},\"initialize(address,address,bytes)\":{\"details\":\"Contract initializer with Governor enforcement\",\"params\":{\"_data\":\"Data to send as msg.data to the implementation to initialize the proxied contract. It should include the signature and the parameters of the function to be called, as described in https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding. This parameter is optional, if no data is given the initialization call to proxied contract will be skipped.\",\"_initGovernor\":\"Address of the initial Governor.\",\"_logic\":\"Address of the initial implementation.\"}},\"transferGovernance(address)\":{\"params\":{\"_newGovernor\":\"Address of the new Governor\"}},\"upgradeTo(address)\":{\"details\":\"Upgrade the backing implementation of the proxy. Only the admin can call this function.\",\"params\":{\"newImplementation\":\"Address of the new implementation.\"}},\"upgradeToAndCall(address,bytes)\":{\"details\":\"Upgrade the backing implementation of the proxy and call a function on the new implementation. This is useful to initialize the proxied contract.\",\"params\":{\"data\":\"Data to send as msg.data in the low level call. It should include the signature and the parameters of the function to be called, as described in https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.\",\"newImplementation\":\"Address of the new implementation.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"claimGovernance()\":{\"notice\":\"Claim Governance of the contract to a new account (`newGovernor`). Can only be called by the new Governor.\"},\"governor()\":{\"notice\":\"Returns the address of the current Governor.\"},\"isGovernor()\":{\"notice\":\"Returns true if the caller is the current Governor.\"},\"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\"}},\"notice\":\"NativeStakingFeeAccumulatorProxy delegates calls to NativeStakingFeeCollector implementation\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/proxies/Proxies.sol\":\"NativeStakingFeeAccumulatorProxy\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@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\"},\"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/proxies/InitializeGovernedUpgradeabilityProxy.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport { Address } from \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\n\\nimport { Governable } from \\\"../governance/Governable.sol\\\";\\n\\n/**\\n * @title BaseGovernedUpgradeabilityProxy\\n * @dev This contract combines an upgradeability proxy with our governor system.\\n * It is based on an older version of OpenZeppelins BaseUpgradeabilityProxy\\n * with Solidity ^0.8.0.\\n * @author Origin Protocol Inc\\n */\\ncontract InitializeGovernedUpgradeabilityProxy is Governable {\\n /**\\n * @dev Emitted when the implementation is upgraded.\\n * @param implementation Address of the new implementation.\\n */\\n event Upgraded(address indexed implementation);\\n\\n /**\\n * @dev Contract initializer with Governor enforcement\\n * @param _logic Address of the initial implementation.\\n * @param _initGovernor Address of the initial Governor.\\n * @param _data Data to send as msg.data to the implementation to initialize\\n * the proxied contract.\\n * It should include the signature and the parameters of the function to be\\n * called, as described in\\n * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.\\n * This parameter is optional, if no data is given the initialization call\\n * to proxied contract will be skipped.\\n */\\n function initialize(\\n address _logic,\\n address _initGovernor,\\n bytes calldata _data\\n ) public payable onlyGovernor {\\n require(_implementation() == address(0));\\n assert(\\n IMPLEMENTATION_SLOT ==\\n bytes32(uint256(keccak256(\\\"eip1967.proxy.implementation\\\")) - 1)\\n );\\n _setImplementation(_logic);\\n if (_data.length > 0) {\\n (bool success, ) = _logic.delegatecall(_data);\\n require(success);\\n }\\n _changeGovernor(_initGovernor);\\n }\\n\\n /**\\n * @return The address of the proxy admin/it's also the governor.\\n */\\n function admin() external view returns (address) {\\n return _governor();\\n }\\n\\n /**\\n * @return The address of the implementation.\\n */\\n function implementation() external view returns (address) {\\n return _implementation();\\n }\\n\\n /**\\n * @dev Upgrade the backing implementation of the proxy.\\n * Only the admin can call this function.\\n * @param newImplementation Address of the new implementation.\\n */\\n function upgradeTo(address newImplementation) external onlyGovernor {\\n _upgradeTo(newImplementation);\\n }\\n\\n /**\\n * @dev Upgrade the backing implementation of the proxy and call a function\\n * on the new implementation.\\n * This is useful to initialize the proxied contract.\\n * @param newImplementation Address of the new implementation.\\n * @param data Data to send as msg.data in the low level call.\\n * It should include the signature and the parameters of the function to be called, as described in\\n * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.\\n */\\n function upgradeToAndCall(address newImplementation, bytes calldata data)\\n external\\n payable\\n onlyGovernor\\n {\\n _upgradeTo(newImplementation);\\n (bool success, ) = newImplementation.delegatecall(data);\\n require(success);\\n }\\n\\n /**\\n * @dev Fallback function.\\n * Implemented entirely in `_fallback`.\\n */\\n fallback() external payable {\\n _fallback();\\n }\\n\\n /**\\n * @dev Delegates execution to an implementation contract.\\n * This is a low level function that doesn't return to its internal call site.\\n * It will return to the external caller whatever the implementation returns.\\n * @param _impl Address to delegate.\\n */\\n function _delegate(address _impl) internal {\\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(gas(), _impl, 0, calldatasize(), 0, 0)\\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 /**\\n * @dev Function that is run as the first thing in the fallback function.\\n * Can be redefined in derived contracts to add functionality.\\n * Redefinitions must call super._willFallback().\\n */\\n function _willFallback() internal {}\\n\\n /**\\n * @dev fallback implementation.\\n * Extracted to enable manual triggering.\\n */\\n function _fallback() internal {\\n _willFallback();\\n _delegate(_implementation());\\n }\\n\\n /**\\n * @dev Storage slot with the address of the current implementation.\\n * This is the keccak-256 hash of \\\"eip1967.proxy.implementation\\\" subtracted by 1, and is\\n * validated in the constructor.\\n */\\n bytes32 internal constant IMPLEMENTATION_SLOT =\\n 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\\n\\n /**\\n * @dev Returns the current implementation.\\n * @return impl Address of the current implementation\\n */\\n function _implementation() internal view returns (address impl) {\\n bytes32 slot = IMPLEMENTATION_SLOT;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n impl := sload(slot)\\n }\\n }\\n\\n /**\\n * @dev Upgrades the proxy to a new implementation.\\n * @param newImplementation Address of the new implementation.\\n */\\n function _upgradeTo(address newImplementation) internal {\\n _setImplementation(newImplementation);\\n emit Upgraded(newImplementation);\\n }\\n\\n /**\\n * @dev Sets the implementation address of the proxy.\\n * @param newImplementation Address of the new implementation.\\n */\\n function _setImplementation(address newImplementation) internal {\\n require(\\n Address.isContract(newImplementation),\\n \\\"Cannot set a proxy implementation to a non-contract address\\\"\\n );\\n\\n bytes32 slot = IMPLEMENTATION_SLOT;\\n\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n sstore(slot, newImplementation)\\n }\\n }\\n}\\n\",\"keccak256\":\"0xcf9bc33957fa41a745726edb6461a4bddca875a038c848286a059f0f22b7f184\",\"license\":\"MIT\"},\"contracts/proxies/Proxies.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport { InitializeGovernedUpgradeabilityProxy } from \\\"./InitializeGovernedUpgradeabilityProxy.sol\\\";\\n\\n/**\\n * @notice OUSDProxy delegates calls to an OUSD implementation\\n */\\ncontract OUSDProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice WrappedOUSDProxy delegates calls to a WrappedOUSD implementation\\n */\\ncontract WrappedOUSDProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice VaultProxy delegates calls to a Vault implementation\\n */\\ncontract VaultProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice CompoundStrategyProxy delegates calls to a CompoundStrategy implementation\\n */\\ncontract CompoundStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice AaveStrategyProxy delegates calls to a AaveStrategy implementation\\n */\\ncontract AaveStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice ThreePoolStrategyProxy delegates calls to a ThreePoolStrategy implementation\\n */\\ncontract ThreePoolStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice ConvexStrategyProxy delegates calls to a ConvexStrategy implementation\\n */\\ncontract ConvexStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice HarvesterProxy delegates calls to a Harvester implementation\\n */\\ncontract HarvesterProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice DripperProxy delegates calls to a Dripper implementation\\n */\\ncontract DripperProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice MorphoCompoundStrategyProxy delegates calls to a MorphoCompoundStrategy implementation\\n */\\ncontract MorphoCompoundStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice ConvexOUSDMetaStrategyProxy delegates calls to a ConvexOUSDMetaStrategy implementation\\n */\\ncontract ConvexOUSDMetaStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice ConvexLUSDMetaStrategyProxy delegates calls to a ConvexalGeneralizedMetaStrategy implementation\\n */\\ncontract ConvexLUSDMetaStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice MorphoAaveStrategyProxy delegates calls to a MorphoCompoundStrategy implementation\\n */\\ncontract MorphoAaveStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice OETHProxy delegates calls to nowhere for now\\n */\\ncontract OETHProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice WOETHProxy delegates calls to nowhere for now\\n */\\ncontract WOETHProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice OETHVaultProxy delegates calls to a Vault implementation\\n */\\ncontract OETHVaultProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice OETHDripperProxy delegates calls to a OETHDripper implementation\\n */\\ncontract OETHDripperProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice OETHHarvesterProxy delegates calls to a Harvester implementation\\n */\\ncontract OETHHarvesterProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice FraxETHStrategyProxy delegates calls to a FraxETHStrategy implementation\\n */\\ncontract FraxETHStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice CurveEthStrategyProxy delegates calls to a CurveEthStrategy implementation\\n */\\ncontract ConvexEthMetaStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice BuybackProxy delegates calls to Buyback implementation\\n */\\ncontract BuybackProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice OETHMorphoAaveStrategyProxy delegates calls to a MorphoAaveStrategy implementation\\n */\\ncontract OETHMorphoAaveStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice OETHBalancerMetaPoolrEthStrategyProxy delegates calls to a BalancerMetaPoolStrategy implementation\\n */\\ncontract OETHBalancerMetaPoolrEthStrategyProxy is\\n InitializeGovernedUpgradeabilityProxy\\n{\\n\\n}\\n\\n/**\\n * @notice OETHBalancerMetaPoolwstEthStrategyProxy delegates calls to a BalancerMetaPoolStrategy implementation\\n */\\ncontract OETHBalancerMetaPoolwstEthStrategyProxy is\\n InitializeGovernedUpgradeabilityProxy\\n{\\n\\n}\\n\\n/**\\n * @notice FluxStrategyProxy delegates calls to a CompoundStrategy implementation\\n */\\ncontract FluxStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice MakerDsrStrategyProxy delegates calls to a Generalized4626Strategy implementation\\n */\\ncontract MakerDsrStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice FrxEthRedeemStrategyProxy delegates calls to a FrxEthRedeemStrategy implementation\\n */\\ncontract FrxEthRedeemStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice OETHBuybackProxy delegates calls to Buyback implementation\\n */\\ncontract OETHBuybackProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice BridgedWOETHProxy delegates calls to BridgedWOETH implementation\\n */\\ncontract BridgedWOETHProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice NativeStakingSSVStrategyProxy delegates calls to NativeStakingSSVStrategy implementation\\n */\\ncontract NativeStakingSSVStrategyProxy is\\n InitializeGovernedUpgradeabilityProxy\\n{\\n\\n}\\n\\n/**\\n * @notice NativeStakingFeeAccumulatorProxy delegates calls to NativeStakingFeeCollector implementation\\n */\\ncontract NativeStakingFeeAccumulatorProxy is\\n InitializeGovernedUpgradeabilityProxy\\n{\\n\\n}\\n\",\"keccak256\":\"0x2e294507edd91494e1020a2a1c43502d2f5cba01266c228406562ecde7a2d872\",\"license\":\"MIT\"}},\"version\":1}", + "bytecode": "0x608060405234801561001057600080fd5b506100273360008051602061099083398151915255565b600080516020610990833981519152546040516001600160a01b03909116906000907fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a908290a36109138061007d6000396000f3fe6080604052600436106100865760003560e01c80635d36b190116100595780635d36b1901461010a578063c7af33521461011f578063cf7a1d7714610144578063d38bfff414610157578063f851a4401461009057610086565b80630c340a24146100905780633659cfe6146100c25780634f1ef286146100e25780635c60da1b146100f5575b61008e610177565b005b34801561009c57600080fd5b506100a5610197565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156100ce57600080fd5b5061008e6100dd366004610745565b6101b4565b61008e6100f03660046107c8565b6101ed565b34801561010157600080fd5b506100a561028a565b34801561011657600080fd5b5061008e6102a2565b34801561012b57600080fd5b50610134610346565b60405190151581526020016100b9565b61008e610152366004610767565b610377565b34801561016357600080fd5b5061008e610172366004610745565b610491565b61019561019060008051602061089e8339815191525490565b610535565b565b60006101af6000805160206108be8339815191525490565b905090565b6101bc610346565b6101e15760405162461bcd60e51b81526004016101d89061082b565b60405180910390fd5b6101ea81610559565b50565b6101f5610346565b6102115760405162461bcd60e51b81526004016101d89061082b565b61021a83610559565b6000836001600160a01b0316838360405161023692919061081b565b600060405180830381855af49150503d8060008114610271576040519150601f19603f3d011682016040523d82523d6000602084013e610276565b606091505b505090508061028457600080fd5b50505050565b60006101af60008051602061089e8339815191525490565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b03161461033d5760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b60648201526084016101d8565b61019533610599565b600061035e6000805160206108be8339815191525490565b6001600160a01b0316336001600160a01b031614905090565b61037f610346565b61039b5760405162461bcd60e51b81526004016101d89061082b565b60006103b360008051602061089e8339815191525490565b6001600160a01b0316146103c657600080fd5b6103f160017f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbd610862565b60008051602061089e8339815191521461040d5761040d610887565b6104168461065a565b8015610488576000846001600160a01b0316838360405161043892919061081b565b600060405180830381855af49150503d8060008114610473576040519150601f19603f3d011682016040523d82523d6000602084013e610478565b606091505b505090508061048657600080fd5b505b61028483610599565b610499610346565b6104b55760405162461bcd60e51b81526004016101d89061082b565b6104dd817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b03166104fd6000805160206108be8339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b3660008037600080366000845af43d6000803e808015610554573d6000f35b3d6000fd5b6105628161065a565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b6001600160a01b0381166105ef5760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f72206973206164647265737328302900000000000060448201526064016101d8565b806001600160a01b031661060f6000805160206108be8339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a36101ea816000805160206108be83398151915255565b803b6106ce5760405162461bcd60e51b815260206004820152603b60248201527f43616e6e6f742073657420612070726f787920696d706c656d656e746174696f60448201527f6e20746f2061206e6f6e2d636f6e74726163742061646472657373000000000060648201526084016101d8565b60008051602061089e83398151915255565b80356001600160a01b03811681146106f757600080fd5b919050565b60008083601f84011261070e57600080fd5b50813567ffffffffffffffff81111561072657600080fd5b60208301915083602082850101111561073e57600080fd5b9250929050565b60006020828403121561075757600080fd5b610760826106e0565b9392505050565b6000806000806060858703121561077d57600080fd5b610786856106e0565b9350610794602086016106e0565b9250604085013567ffffffffffffffff8111156107b057600080fd5b6107bc878288016106fc565b95989497509550505050565b6000806000604084860312156107dd57600080fd5b6107e6846106e0565b9250602084013567ffffffffffffffff81111561080257600080fd5b61080e868287016106fc565b9497909650939450505050565b8183823760009101908152919050565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b60008282101561088257634e487b7160e01b600052601160045260246000fd5b500390565b634e487b7160e01b600052600160045260246000fdfe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa26469706673582212205970f4615c7f37182e1f488c42ecbeb496eeeae3e15b9d0b344a6c7530953ff364736f6c634300080700337bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a", + "deployedBytecode": "0x6080604052600436106100865760003560e01c80635d36b190116100595780635d36b1901461010a578063c7af33521461011f578063cf7a1d7714610144578063d38bfff414610157578063f851a4401461009057610086565b80630c340a24146100905780633659cfe6146100c25780634f1ef286146100e25780635c60da1b146100f5575b61008e610177565b005b34801561009c57600080fd5b506100a5610197565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156100ce57600080fd5b5061008e6100dd366004610745565b6101b4565b61008e6100f03660046107c8565b6101ed565b34801561010157600080fd5b506100a561028a565b34801561011657600080fd5b5061008e6102a2565b34801561012b57600080fd5b50610134610346565b60405190151581526020016100b9565b61008e610152366004610767565b610377565b34801561016357600080fd5b5061008e610172366004610745565b610491565b61019561019060008051602061089e8339815191525490565b610535565b565b60006101af6000805160206108be8339815191525490565b905090565b6101bc610346565b6101e15760405162461bcd60e51b81526004016101d89061082b565b60405180910390fd5b6101ea81610559565b50565b6101f5610346565b6102115760405162461bcd60e51b81526004016101d89061082b565b61021a83610559565b6000836001600160a01b0316838360405161023692919061081b565b600060405180830381855af49150503d8060008114610271576040519150601f19603f3d011682016040523d82523d6000602084013e610276565b606091505b505090508061028457600080fd5b50505050565b60006101af60008051602061089e8339815191525490565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b03161461033d5760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b60648201526084016101d8565b61019533610599565b600061035e6000805160206108be8339815191525490565b6001600160a01b0316336001600160a01b031614905090565b61037f610346565b61039b5760405162461bcd60e51b81526004016101d89061082b565b60006103b360008051602061089e8339815191525490565b6001600160a01b0316146103c657600080fd5b6103f160017f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbd610862565b60008051602061089e8339815191521461040d5761040d610887565b6104168461065a565b8015610488576000846001600160a01b0316838360405161043892919061081b565b600060405180830381855af49150503d8060008114610473576040519150601f19603f3d011682016040523d82523d6000602084013e610478565b606091505b505090508061048657600080fd5b505b61028483610599565b610499610346565b6104b55760405162461bcd60e51b81526004016101d89061082b565b6104dd817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b03166104fd6000805160206108be8339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b3660008037600080366000845af43d6000803e808015610554573d6000f35b3d6000fd5b6105628161065a565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b6001600160a01b0381166105ef5760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f72206973206164647265737328302900000000000060448201526064016101d8565b806001600160a01b031661060f6000805160206108be8339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a36101ea816000805160206108be83398151915255565b803b6106ce5760405162461bcd60e51b815260206004820152603b60248201527f43616e6e6f742073657420612070726f787920696d706c656d656e746174696f60448201527f6e20746f2061206e6f6e2d636f6e74726163742061646472657373000000000060648201526084016101d8565b60008051602061089e83398151915255565b80356001600160a01b03811681146106f757600080fd5b919050565b60008083601f84011261070e57600080fd5b50813567ffffffffffffffff81111561072657600080fd5b60208301915083602082850101111561073e57600080fd5b9250929050565b60006020828403121561075757600080fd5b610760826106e0565b9392505050565b6000806000806060858703121561077d57600080fd5b610786856106e0565b9350610794602086016106e0565b9250604085013567ffffffffffffffff8111156107b057600080fd5b6107bc878288016106fc565b95989497509550505050565b6000806000604084860312156107dd57600080fd5b6107e6846106e0565b9250602084013567ffffffffffffffff81111561080257600080fd5b61080e868287016106fc565b9497909650939450505050565b8183823760009101908152919050565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b60008282101561088257634e487b7160e01b600052601160045260246000fd5b500390565b634e487b7160e01b600052600160045260246000fdfe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa26469706673582212205970f4615c7f37182e1f488c42ecbeb496eeeae3e15b9d0b344a6c7530953ff364736f6c63430008070033", + "libraries": {}, + "devdoc": { + "kind": "dev", + "methods": { + "admin()": { + "returns": { + "_0": "The address of the proxy admin/it's also the governor." + } + }, + "implementation()": { + "returns": { + "_0": "The address of the implementation." + } + }, + "initialize(address,address,bytes)": { + "details": "Contract initializer with Governor enforcement", + "params": { + "_data": "Data to send as msg.data to the implementation to initialize the proxied contract. It should include the signature and the parameters of the function to be called, as described in https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding. This parameter is optional, if no data is given the initialization call to proxied contract will be skipped.", + "_initGovernor": "Address of the initial Governor.", + "_logic": "Address of the initial implementation." + } + }, + "transferGovernance(address)": { + "params": { + "_newGovernor": "Address of the new Governor" + } + }, + "upgradeTo(address)": { + "details": "Upgrade the backing implementation of the proxy. Only the admin can call this function.", + "params": { + "newImplementation": "Address of the new implementation." + } + }, + "upgradeToAndCall(address,bytes)": { + "details": "Upgrade the backing implementation of the proxy and call a function on the new implementation. This is useful to initialize the proxied contract.", + "params": { + "data": "Data to send as msg.data in the low level call. It should include the signature and the parameters of the function to be called, as described in https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.", + "newImplementation": "Address of the new implementation." + } + } + }, + "version": 1 + }, + "userdoc": { + "kind": "user", + "methods": { + "claimGovernance()": { + "notice": "Claim Governance of the contract to a new account (`newGovernor`). Can only be called by the new Governor." + }, + "governor()": { + "notice": "Returns the address of the current Governor." + }, + "isGovernor()": { + "notice": "Returns true if the caller is the current Governor." + }, + "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" + } + }, + "notice": "NativeStakingFeeAccumulatorProxy delegates calls to NativeStakingFeeCollector implementation", + "version": 1 + }, + "storageLayout": { + "storage": [], + "types": null + } +} \ No newline at end of file diff --git a/contracts/deployments/holesky/NativeStakingSSVStrategy.json b/contracts/deployments/holesky/NativeStakingSSVStrategy.json new file mode 100644 index 0000000000..260cfb1a33 --- /dev/null +++ b/contracts/deployments/holesky/NativeStakingSSVStrategy.json @@ -0,0 +1,1901 @@ +{ + "address": "0x4aEAcdb5D84eDf02Dd85f3DFC1645b89D7579d62", + "abi": [ + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "platformAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "vaultAddress", + "type": "address" + } + ], + "internalType": "struct InitializableAbstractStrategy.BaseStrategyConfig", + "name": "_baseConfig", + "type": "tuple" + }, + { + "internalType": "address", + "name": "_wethAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_ssvToken", + "type": "address" + }, + { + "internalType": "address", + "name": "_ssvNetwork", + "type": "address" + }, + { + "internalType": "address", + "name": "_feeAccumulator", + "type": "address" + }, + { + "internalType": "address", + "name": "_beaconChainDepositContract", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "AccountingConsensusRewards", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "noOfValidators", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "remainingValidators", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "wethSentToVault", + "type": "uint256" + } + ], + "name": "AccountingFullyWithdrawnValidator", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "newAddress", + "type": "address" + } + ], + "name": "AccountingGovernorChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldActiveDepositedValidators", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "activeDepositedValidators", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "oldBeaconChainRewards", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "beaconChainRewards", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "ethToWeth", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "wethToBeSentToVault", + "type": "uint256" + } + ], + "name": "AccountingManuallyFixed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "remainingValidators", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "wethSentToVault", + "type": "uint256" + } + ], + "name": "AccountingValidatorSlashed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_asset", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "_pToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + } + ], + "name": "Deposit", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "pubkey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "withdrawal_credentials", + "type": "bytes" + } + ], + "name": "ETHStaked", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "start", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "end", + "type": "uint256" + } + ], + "name": "FuseIntervalUpdated", + "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": "address", + "name": "_oldHarvesterAddress", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "_newHarvesterAddress", + "type": "address" + } + ], + "name": "HarvesterAddressesUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_asset", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "_pToken", + "type": "address" + } + ], + "name": "PTokenAdded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_asset", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "_pToken", + "type": "address" + } + ], + "name": "PTokenRemoved", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Paused", + "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": "newAddress", + "type": "address" + } + ], + "name": "RegistratorChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address[]", + "name": "_oldAddresses", + "type": "address[]" + }, + { + "indexed": false, + "internalType": "address[]", + "name": "_newAddresses", + "type": "address[]" + } + ], + "name": "RewardTokenAddressesUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "rewardToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "RewardTokenCollected", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "pubkey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint64[]", + "name": "operatorIds", + "type": "uint64[]" + } + ], + "name": "SSVValidatorExitCompleted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "pubkey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint64[]", + "name": "operatorIds", + "type": "uint64[]" + } + ], + "name": "SSVValidatorExitInitiated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "pubkey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint64[]", + "name": "operatorIds", + "type": "uint64[]" + } + ], + "name": "SSVValidatorRegistered", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Unpaused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_asset", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "_pToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + } + ], + "name": "Withdrawal", + "type": "event" + }, + { + "inputs": [], + "name": "BEACON_CHAIN_DEPOSIT_CONTRACT", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "FEE_ACCUMULATOR_ADDRESS", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "MAX_STAKE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "SSV_NETWORK_ADDRESS", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "SSV_TOKEN_ADDRESS", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "VAULT_ADDRESS", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "WETH_TOKEN_ADDRESS", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "accountingGovernor", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "assetToPToken", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_asset", + "type": "address" + } + ], + "name": "checkBalance", + "outputs": [ + { + "internalType": "uint256", + "name": "balance", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "claimGovernance", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "collectRewardTokens", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "consensusRewards", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_asset", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + } + ], + "name": "deposit", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "depositAll", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint64[]", + "name": "operatorIds", + "type": "uint64[]" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "uint32", + "name": "validatorCount", + "type": "uint32" + }, + { + "internalType": "uint64", + "name": "networkFeeIndex", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "index", + "type": "uint64" + }, + { + "internalType": "bool", + "name": "active", + "type": "bool" + }, + { + "internalType": "uint256", + "name": "balance", + "type": "uint256" + } + ], + "internalType": "struct Cluster", + "name": "cluster", + "type": "tuple" + } + ], + "name": "depositSSV", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "doAccounting", + "outputs": [ + { + "internalType": "bool", + "name": "accountingValid", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + }, + { + "internalType": "uint64[]", + "name": "operatorIds", + "type": "uint64[]" + } + ], + "name": "exitSsvValidator", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "fuseIntervalEnd", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "fuseIntervalStart", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getRewardTokenAddresses", + "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": "harvesterAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "_rewardTokenAddresses", + "type": "address[]" + }, + { + "internalType": "address[]", + "name": "_assets", + "type": "address[]" + }, + { + "internalType": "address[]", + "name": "_pTokens", + "type": "address[]" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "isGovernor", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_activeDepositedValidators", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_ethToWeth", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_wethToBeSentToVault", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_consensusRewards", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_ethThresholdCheck", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_wethThresholdCheck", + "type": "uint256" + } + ], + "name": "manuallyFixAccounting", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "pause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "paused", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "platformAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + }, + { + "internalType": "uint64[]", + "name": "operatorIds", + "type": "uint64[]" + }, + { + "internalType": "bytes", + "name": "sharesData", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "uint32", + "name": "validatorCount", + "type": "uint32" + }, + { + "internalType": "uint64", + "name": "networkFeeIndex", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "index", + "type": "uint64" + }, + { + "internalType": "bool", + "name": "active", + "type": "bool" + }, + { + "internalType": "uint256", + "name": "balance", + "type": "uint256" + } + ], + "internalType": "struct Cluster", + "name": "cluster", + "type": "tuple" + } + ], + "name": "registerSsvValidator", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_assetIndex", + "type": "uint256" + } + ], + "name": "removePToken", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + }, + { + "internalType": "uint64[]", + "name": "operatorIds", + "type": "uint64[]" + }, + { + "components": [ + { + "internalType": "uint32", + "name": "validatorCount", + "type": "uint32" + }, + { + "internalType": "uint64", + "name": "networkFeeIndex", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "index", + "type": "uint64" + }, + { + "internalType": "bool", + "name": "active", + "type": "bool" + }, + { + "internalType": "uint256", + "name": "balance", + "type": "uint256" + } + ], + "internalType": "struct Cluster", + "name": "cluster", + "type": "tuple" + } + ], + "name": "removeSsvValidator", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "rewardTokenAddresses", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "safeApproveAllTokens", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_address", + "type": "address" + } + ], + "name": "setAccountingGovernor", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_fuseIntervalStart", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_fuseIntervalEnd", + "type": "uint256" + } + ], + "name": "setFuseInterval", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_harvesterAddress", + "type": "address" + } + ], + "name": "setHarvesterAddress", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_asset", + "type": "address" + }, + { + "internalType": "address", + "name": "_pToken", + "type": "address" + } + ], + "name": "setPTokenAddress", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_address", + "type": "address" + } + ], + "name": "setRegistrator", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "_rewardTokenAddresses", + "type": "address[]" + } + ], + "name": "setRewardTokenAddresses", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "bytes", + "name": "pubkey", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + }, + { + "internalType": "bytes32", + "name": "depositDataRoot", + "type": "bytes32" + } + ], + "internalType": "struct ValidatorStakeData[]", + "name": "validators", + "type": "tuple[]" + } + ], + "name": "stakeEth", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_asset", + "type": "address" + } + ], + "name": "supportsAsset", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "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": "validatorRegistrator", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "name": "validatorsStates", + "outputs": [ + { + "internalType": "enum ValidatorRegistrator.VALIDATOR_STATE", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "vaultAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_recipient", + "type": "address" + }, + { + "internalType": "address", + "name": "_asset", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + } + ], + "name": "withdraw", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "withdrawAll", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" + } + ], + "transactionHash": "0x32a95bad479c439018f11c6c93e19fc7fd7edc0fdbcdc15009a32231d7967c5c", + "receipt": { + "to": null, + "from": "0x1b94CA50D3Ad9f8368851F8526132272d1a5028C", + "contractAddress": "0x4aEAcdb5D84eDf02Dd85f3DFC1645b89D7579d62", + "transactionIndex": 26, + "gasUsed": "4123386", + "logsBloom": "0x00000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000000004000000000000002000000000000000000040000001000000000000000000000000000000000000000000000000000000000000000000000000000000000200000010000000000010000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x7accf851e0f53d2da70bb20741170ae10a24b9724ad337e6e7ec6f032a75da32", + "transactionHash": "0x32a95bad479c439018f11c6c93e19fc7fd7edc0fdbcdc15009a32231d7967c5c", + "logs": [ + { + "transactionIndex": 26, + "blockNumber": 1429889, + "transactionHash": "0x32a95bad479c439018f11c6c93e19fc7fd7edc0fdbcdc15009a32231d7967c5c", + "address": "0x4aEAcdb5D84eDf02Dd85f3DFC1645b89D7579d62", + "topics": [ + "0xc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000001b94ca50d3ad9f8368851f8526132272d1a5028c" + ], + "data": "0x", + "logIndex": 38, + "blockHash": "0x7accf851e0f53d2da70bb20741170ae10a24b9724ad337e6e7ec6f032a75da32" + } + ], + "blockNumber": 1429889, + "cumulativeGasUsed": "6291081", + "status": 1, + "byzantium": true + }, + "args": [ + [ + "0x0000000000000000000000000000000000000000", + "0x19d2bAaBA949eFfa163bFB9efB53ed8701aA5dD9" + ], + "0x94373a4919B3240D86eA41593D5eBa789FEF3848", + "0xad45A78180961079BFaeEe349704F411dfF947C6", + "0x38A4794cCEd47d3baf7370CcC43B560D3a1beEFA", + "0x590B781b511e953dbFC49e7E7864A6E787aFBDCc", + "0x4242424242424242424242424242424242424242" + ], + "numDeployments": 2, + "solcInputHash": "46be8b80ad6bb26f70e58a31071e073e", + "metadata": "{\"compiler\":{\"version\":\"0.8.7+commit.e28d00a7\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"platformAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"vaultAddress\",\"type\":\"address\"}],\"internalType\":\"struct InitializableAbstractStrategy.BaseStrategyConfig\",\"name\":\"_baseConfig\",\"type\":\"tuple\"},{\"internalType\":\"address\",\"name\":\"_wethAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_ssvToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_ssvNetwork\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_feeAccumulator\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_beaconChainDepositContract\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"AccountingConsensusRewards\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"noOfValidators\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"remainingValidators\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"wethSentToVault\",\"type\":\"uint256\"}],\"name\":\"AccountingFullyWithdrawnValidator\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newAddress\",\"type\":\"address\"}],\"name\":\"AccountingGovernorChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldActiveDepositedValidators\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"activeDepositedValidators\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldBeaconChainRewards\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"beaconChainRewards\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"ethToWeth\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"wethToBeSentToVault\",\"type\":\"uint256\"}],\"name\":\"AccountingManuallyFixed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"remainingValidators\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"wethSentToVault\",\"type\":\"uint256\"}],\"name\":\"AccountingValidatorSlashed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"Deposit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"pubkey\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"withdrawal_credentials\",\"type\":\"bytes\"}],\"name\":\"ETHStaked\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"start\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"end\",\"type\":\"uint256\"}],\"name\":\"FuseIntervalUpdated\",\"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\":\"address\",\"name\":\"_oldHarvesterAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_newHarvesterAddress\",\"type\":\"address\"}],\"name\":\"HarvesterAddressesUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"}],\"name\":\"PTokenAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"}],\"name\":\"PTokenRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Paused\",\"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\":\"newAddress\",\"type\":\"address\"}],\"name\":\"RegistratorChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"_oldAddresses\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"_newAddresses\",\"type\":\"address[]\"}],\"name\":\"RewardTokenAddressesUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"rewardToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"RewardTokenCollected\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"pubkey\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"}],\"name\":\"SSVValidatorExitCompleted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"pubkey\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"}],\"name\":\"SSVValidatorExitInitiated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"pubkey\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"}],\"name\":\"SSVValidatorRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Unpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"Withdrawal\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"BEACON_CHAIN_DEPOSIT_CONTRACT\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_ACCUMULATOR_ADDRESS\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MAX_STAKE\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"SSV_NETWORK_ADDRESS\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"SSV_TOKEN_ADDRESS\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"VAULT_ADDRESS\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"WETH_TOKEN_ADDRESS\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"accountingGovernor\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"assetToPToken\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"}],\"name\":\"checkBalance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"claimGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"collectRewardTokens\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"consensusRewards\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"depositAll\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"validatorCount\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"networkFeeIndex\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"index\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"active\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"internalType\":\"struct Cluster\",\"name\":\"cluster\",\"type\":\"tuple\"}],\"name\":\"depositSSV\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"doAccounting\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"accountingValid\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"publicKey\",\"type\":\"bytes\"},{\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"}],\"name\":\"exitSsvValidator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fuseIntervalEnd\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fuseIntervalStart\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRewardTokenAddresses\",\"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\":\"harvesterAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"_rewardTokenAddresses\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"_assets\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"_pTokens\",\"type\":\"address[]\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isGovernor\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_activeDepositedValidators\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_ethToWeth\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_wethToBeSentToVault\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_consensusRewards\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_ethThresholdCheck\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_wethThresholdCheck\",\"type\":\"uint256\"}],\"name\":\"manuallyFixAccounting\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"paused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"platformAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"publicKey\",\"type\":\"bytes\"},{\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"},{\"internalType\":\"bytes\",\"name\":\"sharesData\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"validatorCount\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"networkFeeIndex\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"index\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"active\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"internalType\":\"struct Cluster\",\"name\":\"cluster\",\"type\":\"tuple\"}],\"name\":\"registerSsvValidator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_assetIndex\",\"type\":\"uint256\"}],\"name\":\"removePToken\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"publicKey\",\"type\":\"bytes\"},{\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"validatorCount\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"networkFeeIndex\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"index\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"active\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"internalType\":\"struct Cluster\",\"name\":\"cluster\",\"type\":\"tuple\"}],\"name\":\"removeSsvValidator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"rewardTokenAddresses\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"safeApproveAllTokens\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"setAccountingGovernor\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_fuseIntervalStart\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_fuseIntervalEnd\",\"type\":\"uint256\"}],\"name\":\"setFuseInterval\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_harvesterAddress\",\"type\":\"address\"}],\"name\":\"setHarvesterAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"}],\"name\":\"setPTokenAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"setRegistrator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"_rewardTokenAddresses\",\"type\":\"address[]\"}],\"name\":\"setRewardTokenAddresses\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"pubkey\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"depositDataRoot\",\"type\":\"bytes32\"}],\"internalType\":\"struct ValidatorStakeData[]\",\"name\":\"validators\",\"type\":\"tuple[]\"}],\"name\":\"stakeEth\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"}],\"name\":\"supportsAsset\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"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\":\"validatorRegistrator\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"validatorsStates\",\"outputs\":[{\"internalType\":\"enum ValidatorRegistrator.VALIDATOR_STATE\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"vaultAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"withdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdrawAll\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"author\":\"Origin Protocol Inc\",\"kind\":\"dev\",\"methods\":{\"checkBalance(address)\":{\"params\":{\"_asset\":\"Address of weth asset\"},\"returns\":{\"balance\":\" Total value of (W)ETH\"}},\"constructor\":{\"params\":{\"_baseConfig\":\"Base strategy config with platformAddress (ERC-4626 Vault contract), eg sfrxETH or sDAI, and vaultAddress (OToken Vault contract), eg VaultProxy or OETHVaultProxy\",\"_beaconChainDepositContract\":\"Address of the beacon chain deposit contract\",\"_feeAccumulator\":\"Address of the fee accumulator receiving execution layer validator rewards\",\"_ssvNetwork\":\"Address of the SSV Network contract\",\"_ssvToken\":\"Address of the Erc20 SSV Token contract\",\"_wethAddress\":\"Address of the Erc20 WETH Token contract\"}},\"deposit(address,uint256)\":{\"params\":{\"_amount\":\"Amount of assets that were transferred to the strategy by the vault.\",\"_asset\":\"Address of asset to deposit. Has to be WETH.\"}},\"depositSSV(uint64[],uint256,(uint32,uint64,uint64,bool,uint256))\":{\"details\":\"A SSV cluster is defined by the SSVOwnerAddress and the set of operatorIds. uses \\\"onlyStrategist\\\" modifier so continuous front-running can't DOS our maintenance service that tries to top up SSV tokens.\",\"params\":{\"cluster\":\"The SSV cluster details that must be derived from emitted events from the SSVNetwork contract.\"}},\"doAccounting()\":{\"details\":\"This function could in theory be permission-less but lets allow only the Registrator (Defender Action) to call it for now.\"},\"getRewardTokenAddresses()\":{\"returns\":{\"_0\":\"address[] the reward token addresses.\"}},\"initialize(address[],address[],address[])\":{\"params\":{\"_assets\":\"Addresses of initial supported assets\",\"_pTokens\":\"Platform Token corresponding addresses\",\"_rewardTokenAddresses\":\"Address of reward token for platform\"}},\"manuallyFixAccounting(uint256,uint256,uint256,uint256,uint256,uint256)\":{\"details\":\"allow the accounting governor to fix the accounting of this strategy and unpause\",\"params\":{\"_activeDepositedValidators\":\"the override value of activeDepositedValidators\",\"_consensusRewards\":\"the override value for consensusRewards\",\"_ethThresholdCheck\":\"maximum allowed ETH balance on the contract for the function to run\",\"_ethToWeth\":\"the amount of ETH to be converted to WETH\",\"_wethThresholdCheck\":\"maximum allowed WETH balance on the contract for the function to run the above 2 checks are done so transaction doesn't get front run and cause unexpected behaviour\",\"_wethToBeSentToVault\":\"the amount of WETH to be sent to the Vault\"}},\"paused()\":{\"details\":\"Returns true if the contract is paused, and false otherwise.\"},\"removePToken(uint256)\":{\"params\":{\"_assetIndex\":\"Index of the asset to be removed\"}},\"setHarvesterAddress(address)\":{\"params\":{\"_harvesterAddress\":\"Address of the harvester contract.\"}},\"setPTokenAddress(address,address)\":{\"params\":{\"_asset\":\"Address for the asset\",\"_pToken\":\"Address for the corresponding platform token\"}},\"setRewardTokenAddresses(address[])\":{\"params\":{\"_rewardTokenAddresses\":\"Array of reward token addresses\"}},\"stakeEth((bytes,bytes,bytes32)[])\":{\"params\":{\"validators\":\"A list of validator data needed to stake. The `ValidatorStakeData` struct contains the pubkey, signature and depositDataRoot. Only the registrator can call this function.\"}},\"supportsAsset(address)\":{\"params\":{\"_asset\":\"The address of the asset token.\"}},\"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\"}},\"withdraw(address,address,uint256)\":{\"params\":{\"_amount\":\"Amount of WETH to withdraw\",\"_asset\":\"WETH to withdraw\",\"_recipient\":\"Address to receive withdrawn assets\"}}},\"stateVariables\":{\"FEE_ACCUMULATOR_ADDRESS\":{\"details\":\"this address will receive Execution layer rewards - These are rewards earned for executing transactions on the Ethereum network as part of block proposals. They include priority fees (fees paid by users for their transactions to be included) and MEV rewards (rewards for arranging transactions in a way that benefits the validator).\"}},\"title\":\"Native Staking SSV Strategy\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"BEACON_CHAIN_DEPOSIT_CONTRACT()\":{\"notice\":\"The address of the beacon chain deposit contract\"},\"FEE_ACCUMULATOR_ADDRESS()\":{\"notice\":\"Fee collector address\"},\"MAX_STAKE()\":{\"notice\":\"The maximum amount of ETH that can be staked by a validator\"},\"SSV_NETWORK_ADDRESS()\":{\"notice\":\"The address of the SSV Network contract used to interface with\"},\"SSV_TOKEN_ADDRESS()\":{\"notice\":\"SSV ERC20 token that serves as a payment for operating SSV validators\"},\"VAULT_ADDRESS()\":{\"notice\":\"Address of the OETH Vault proxy contract\"},\"WETH_TOKEN_ADDRESS()\":{\"notice\":\"The address of the Wrapped ETH (WETH) token contract\"},\"accountingGovernor()\":{\"notice\":\"Governor that can manually correct the accounting\"},\"assetToPToken(address)\":{\"notice\":\"asset => pToken (Platform Specific Token Address)\"},\"checkBalance(address)\":{\"notice\":\"Returns the total value of (W)ETH that is staked to the validators and WETH deposits that are still to be staked. This does not include ETH from consensus rewards sitting in this strategy or ETH from MEV rewards in the FeeAccumulator. These rewards are harvested and sent to the Dripper so will eventually be sent to the Vault as WETH.\"},\"claimGovernance()\":{\"notice\":\"Claim Governance of the contract to a new account (`newGovernor`). Can only be called by the new Governor.\"},\"collectRewardTokens()\":{\"notice\":\"Collect accumulated reward token and send to Vault.\"},\"consensusRewards()\":{\"notice\":\"Keeps track of the total consensus rewards swept from the beacon chain\"},\"deposit(address,uint256)\":{\"notice\":\"Unlike other strategies, this does not deposit assets into the underlying platform. It just checks the asset is WETH and emits the Deposit event. To deposit WETH into validators `registerSsvValidator` and `stakeEth` must be used. Will NOT revert if the strategy is paused from an accounting failure.\"},\"depositAll()\":{\"notice\":\"Unlike other strategies, this does not deposit assets into the underlying platform. It just emits the Deposit event. To deposit WETH into validators `registerSsvValidator` and `stakeEth` must be used. Will NOT revert if the strategy is paused from an accounting failure.\"},\"depositSSV(uint64[],uint256,(uint32,uint64,uint64,bool,uint256))\":{\"notice\":\"Deposits more SSV Tokens to the SSV Network contract which is used to pay the SSV Operators.\"},\"doAccounting()\":{\"notice\":\"This notion page offers a good explanation of how the accounting functions https://www.notion.so/originprotocol/Limited-simplified-native-staking-accounting-67a217c8420d40678eb943b9da0ee77d In short, after dividing by 32, if the ETH remaining on the contract falls between 0 and fuseIntervalStart, the accounting function will treat that ETH as Beacon chain consensus rewards. On the contrary, if after dividing by 32, the ETH remaining on the contract falls between fuseIntervalEnd and 32, the accounting function will treat that as a validator slashing.Perform the accounting attributing beacon chain ETH to either full or partial withdrawals. Returns true when accounting is valid and fuse isn't \\\"blown\\\". Returns false when fuse is blown.\"},\"exitSsvValidator(bytes,uint64[])\":{\"notice\":\"Exit a validator from the Beacon chain. The staked ETH will eventually swept to this native staking strategy. Only the registrator can call this function.\"},\"fuseIntervalEnd()\":{\"notice\":\"end of fuse interval\"},\"fuseIntervalStart()\":{\"notice\":\"start of fuse interval\"},\"getRewardTokenAddresses()\":{\"notice\":\"Get the reward token addresses.\"},\"governor()\":{\"notice\":\"Returns the address of the current Governor.\"},\"harvesterAddress()\":{\"notice\":\"Address of the Harvester contract allowed to collect reward tokens\"},\"initialize(address[],address[],address[])\":{\"notice\":\"initialize function, to set up initial internal state\"},\"isGovernor()\":{\"notice\":\"Returns true if the caller is the current Governor.\"},\"platformAddress()\":{\"notice\":\"Address of the underlying platform\"},\"registerSsvValidator(bytes,uint64[],bytes,uint256,(uint32,uint64,uint64,bool,uint256))\":{\"notice\":\"Registers a new validator in the SSV Cluster. Only the registrator can call this function.\"},\"removePToken(uint256)\":{\"notice\":\"Remove a supported asset by passing its index. This method can only be called by the system Governor\"},\"removeSsvValidator(bytes,uint64[],(uint32,uint64,uint64,bool,uint256))\":{\"notice\":\"Remove a validator from the SSV Cluster. Make sure `exitSsvValidator` is called before and the validate has exited the Beacon chain. If removed before the validator has exited the beacon chain will result in the validator being slashed. Only the registrator can call this function.\"},\"rewardTokenAddresses(uint256)\":{\"notice\":\"Address of the reward tokens. eg CRV, BAL, CVX, AURA\"},\"safeApproveAllTokens()\":{\"notice\":\"Approves the SSV Network contract to transfer SSV tokens for deposits\"},\"setFuseInterval(uint256,uint256)\":{\"notice\":\"set fuse interval values\"},\"setHarvesterAddress(address)\":{\"notice\":\"Set the Harvester contract that can collect rewards.\"},\"setPTokenAddress(address,address)\":{\"notice\":\"Provide support for asset by passing its pToken address. This method can only be called by the system Governor\"},\"setRegistrator(address)\":{\"notice\":\"Set the address of the registrator which can register, exit and remove validators\"},\"setRewardTokenAddresses(address[])\":{\"notice\":\"Set the reward token addresses. Any old addresses will be overwritten.\"},\"stakeEth((bytes,bytes,bytes32)[])\":{\"notice\":\"Stakes WETH to the node validators\"},\"supportsAsset(address)\":{\"notice\":\"Returns bool indicating whether asset is supported by strategy.\"},\"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 strategy contracts, i.e. mistaken sends.\"},\"validatorRegistrator()\":{\"notice\":\"Address of the registrator - allowed to register, exit and remove validators\"},\"validatorsStates(bytes32)\":{\"notice\":\"State of the validators keccak256(pubKey) => state\"},\"vaultAddress()\":{\"notice\":\"Address of the OToken vault\"},\"withdraw(address,address,uint256)\":{\"notice\":\"Withdraw WETH from this contract. Used only if some WETH for is lingering on the contract. That can happen when: - the deposit was not a multiple of 32 WETH - someone sent WETH directly to this contract Will NOT revert if the strategy is paused from an accounting failure.\"},\"withdrawAll()\":{\"notice\":\"transfer all WETH deposits back to the vault. This does not withdraw from the validators. That has to be done separately with the `exitSsvValidator` and `removeSsvValidator` operations. This does not withdraw any execution rewards from the FeeAccumulator or consensus rewards in this strategy. Any ETH in this strategy that was swept from a full validator withdrawal will not be withdrawn. ETH from full validator withdrawals is sent to the Vault using `doAccounting`. Will NOT revert if the strategy is paused from an accounting failure.\"}},\"notice\":\"Strategy to deploy funds into DVT validators powered by the SSV Network\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol\":\"NativeStakingSSVStrategy\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"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\",\"keccak256\":\"0xe68ed7fb8766ed1e888291f881e36b616037f852b37d96877045319ad298ba87\",\"license\":\"MIT\"},\"@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/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\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"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/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\",\"keccak256\":\"0x598f90bdbc854250bbd5991426bfb43367207e64e33109c41aa8b54323fd8d8e\",\"license\":\"MIT\"},\"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 error ApprovalNotWithinTimeframe();\\n error CallerNotOwner();\\n error CallerNotWhitelisted();\\n error ClusterAlreadyEnabled();\\n error ClusterDoesNotExists();\\n error ClusterIsLiquidated();\\n error ClusterNotLiquidatable();\\n error ExceedValidatorLimit();\\n error FeeExceedsIncreaseLimit();\\n error FeeIncreaseNotAllowed();\\n error FeeTooHigh();\\n error FeeTooLow();\\n error IncorrectClusterState();\\n error IncorrectValidatorState();\\n error InsufficientBalance();\\n error InvalidOperatorIdsLength();\\n error InvalidPublicKeyLength();\\n error MaxValueExceeded();\\n error NewBlockPeriodIsBelowMinimum();\\n error NoFeeDeclared();\\n error NotAuthorized();\\n error OperatorAlreadyExists();\\n error OperatorDoesNotExist();\\n error OperatorsListNotUnique();\\n error SameFeeChangeNotAllowed();\\n error TargetModuleDoesNotExist();\\n error TokenTransferFailed();\\n error UnsortedOperatorsList();\\n error ValidatorAlreadyExists();\\n error ValidatorDoesNotExist();\\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 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 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 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\",\"keccak256\":\"0x76e2c5148727b72752939b06fee7abc1f732c18970b8c7db7fe7cdfe74629d36\",\"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/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/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\",\"keccak256\":\"0x05b7dce6c24d3cd4e48b5c6346d86e5e40ecc3291bcdf3f3ef091c98fc826519\",\"license\":\"MIT\"},\"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\\nimport { Governable } from \\\"../../governance/Governable.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 is Governable {\\n /// @notice The address of the Native Staking Strategy\\n address public immutable STRATEGY;\\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 }\\n}\\n\",\"keccak256\":\"0xf47bcc46ce70f649f061bec3d2303f376a15700ba18fe471fba823f60bdfed8b\",\"license\":\"MIT\"},\"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\\\";\\n\\nimport { InitializableAbstractStrategy } from \\\"../../utils/InitializableAbstractStrategy.sol\\\";\\nimport { ISSVNetwork, Cluster } from \\\"../../interfaces/ISSVNetwork.sol\\\";\\nimport { IWETH9 } from \\\"../../interfaces/IWETH9.sol\\\";\\nimport { FeeAccumulator } from \\\"./FeeAccumulator.sol\\\";\\nimport { ValidatorAccountant } from \\\"./ValidatorAccountant.sol\\\";\\nimport { Cluster } from \\\"../../interfaces/ISSVNetwork.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\\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_ADDRESS;\\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 public immutable FEE_ACCUMULATOR_ADDRESS;\\n\\n // For future use\\n uint256[50] 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 _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 address _feeAccumulator,\\n address _beaconChainDepositContract\\n )\\n InitializableAbstractStrategy(_baseConfig)\\n ValidatorAccountant(\\n _wethAddress,\\n _baseConfig.vaultAddress,\\n _beaconChainDepositContract,\\n _ssvNetwork\\n )\\n {\\n SSV_TOKEN_ADDRESS = _ssvToken;\\n FEE_ACCUMULATOR_ADDRESS = _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 /// @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_TOKEN_ADDRESS).deposit{ value: ethRewards }();\\n\\n emit RewardTokenCollected(\\n harvesterAddress,\\n WETH_TOKEN_ADDRESS,\\n ethRewards\\n );\\n IERC20(WETH_TOKEN_ADDRESS).safeTransfer(\\n harvesterAddress,\\n ethRewards\\n );\\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_TOKEN_ADDRESS, \\\"Unsupported asset\\\");\\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_TOKEN_ADDRESS).balanceOf(\\n address(this)\\n );\\n if (wethBalance > 0) {\\n _deposit(WETH_TOKEN_ADDRESS, wethBalance);\\n }\\n }\\n\\n /// @notice Withdraw WETH from this contract. Used only if some WETH for is lingering on the contract. That\\n /// can happen when:\\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 _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 emit Withdrawal(_asset, address(0), _amount);\\n IERC20(_asset).safeTransfer(_recipient, _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_TOKEN_ADDRESS).balanceOf(\\n address(this)\\n );\\n if (wethBalance > 0) {\\n _withdraw(vaultAddress, WETH_TOKEN_ADDRESS, wethBalance);\\n }\\n }\\n\\n function _abstractSetPToken(address _asset, address) internal override {}\\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_TOKEN_ADDRESS, \\\"Unsupported asset\\\");\\n\\n balance =\\n // add the ETH that has been staked in validators\\n activeDepositedValidators *\\n 32 ether +\\n // add the WETH in the strategy from deposits that are still to be staked\\n IERC20(WETH_TOKEN_ADDRESS).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_TOKEN_ADDRESS;\\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_ADDRESS).approve(\\n SSV_NETWORK_ADDRESS,\\n type(uint256).max\\n );\\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_TOKEN_ADDRESS,\\n \\\"eth not from allowed contracts\\\"\\n );\\n }\\n}\\n\",\"keccak256\":\"0xf591c47516bc68b9b0a220b7d7c6b96f87315b03ea8636b47ca5c6540e59fb85\",\"license\":\"MIT\"},\"contracts/strategies/NativeStaking/ValidatorAccountant.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport { Pausable } from \\\"@openzeppelin/contracts/security/Pausable.sol\\\";\\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 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 MAX_STAKE = 32 ether;\\n\\n /// @notice Keeps track of the total consensus rewards swept from the beacon chain\\n uint256 public consensusRewards = 0;\\n\\n /// @notice start of fuse interval\\n uint256 public fuseIntervalStart = 0;\\n /// @notice end of fuse interval\\n uint256 public fuseIntervalEnd = 0;\\n /// @notice Governor that can manually correct the accounting\\n address public accountingGovernor;\\n\\n uint256[50] 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 AccountingGovernorChanged(address newAddress);\\n event AccountingConsensusRewards(uint256 amount);\\n\\n event AccountingManuallyFixed(\\n uint256 oldActiveDepositedValidators,\\n uint256 activeDepositedValidators,\\n uint256 oldBeaconChainRewards,\\n uint256 beaconChainRewards,\\n uint256 ethToWeth,\\n uint256 wethToBeSentToVault\\n );\\n\\n /// @dev Throws if called by any account other than the Accounting Governor\\n modifier onlyAccountingGovernor() {\\n require(\\n msg.sender == accountingGovernor,\\n \\\"Caller is not the Accounting Governor\\\"\\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 constructor(\\n address _wethAddress,\\n address _vaultAddress,\\n address _beaconChainDepositContract,\\n address _ssvNetwork\\n )\\n ValidatorRegistrator(\\n _wethAddress,\\n _vaultAddress,\\n _beaconChainDepositContract,\\n _ssvNetwork\\n )\\n {}\\n\\n function setAccountingGovernor(address _address) external onlyGovernor {\\n emit AccountingGovernorChanged(_address);\\n accountingGovernor = _address;\\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 _fuseIntervalStart < 32 ether &&\\n _fuseIntervalEnd < 32 ether &&\\n _fuseIntervalEnd - _fuseIntervalStart >= 4 ether,\\n \\\"incorrect fuse interval\\\"\\n );\\n\\n emit FuseIntervalUpdated(_fuseIntervalStart, _fuseIntervalEnd);\\n\\n fuseIntervalStart = _fuseIntervalStart;\\n fuseIntervalEnd = _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 /* solhint-enable max-line-length */\\n function doAccounting()\\n external\\n onlyRegistrator\\n whenNotPaused\\n returns (bool accountingValid)\\n {\\n if (address(this).balance < consensusRewards) {\\n // pause and fail the accounting\\n _pause();\\n return false;\\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 >= MAX_STAKE) {\\n uint256 fullyWithdrawnValidators = newSweptETH / MAX_STAKE;\\n activeDepositedValidators -= fullyWithdrawnValidators;\\n\\n uint256 wethToVault = MAX_STAKE * fullyWithdrawnValidators;\\n IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: wethToVault }();\\n IWETH9(WETH_TOKEN_ADDRESS).transfer(VAULT_ADDRESS, 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 < 32 ether, \\\"unexpected accounting\\\");\\n\\n // If no Beacon chain consensus rewards swept\\n if (ethRemaining == 0) {\\n // do nothing\\n return accountingValid;\\n }\\n // Beacon chain consensus rewards swept (partial validator withdrawals)\\n else if (ethRemaining < fuseIntervalStart) {\\n // solhint-disable-next-line reentrancy\\n consensusRewards += ethRemaining;\\n emit AccountingConsensusRewards(ethRemaining);\\n }\\n // Beacon chain consensus rewards swept but also a slashed validator fully exited\\n else if (ethRemaining > fuseIntervalEnd) {\\n IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: ethRemaining }();\\n IWETH9(WETH_TOKEN_ADDRESS).transfer(VAULT_ADDRESS, ethRemaining);\\n activeDepositedValidators -= 1;\\n\\n emit AccountingValidatorSlashed(\\n activeDepositedValidators,\\n ethRemaining\\n );\\n }\\n // Oh no... Fuse is blown. The governor (Multisig not OGV Governor) needs to set the\\n // record straight by manually set the accounting values.\\n else {\\n // will emit a paused event\\n _pause();\\n accountingValid = false;\\n }\\n }\\n\\n /// @dev allow the accounting governor to fix the accounting of this strategy and unpause\\n /// @param _activeDepositedValidators the override value of activeDepositedValidators\\n /// @param _ethToWeth the amount of ETH to be converted to WETH\\n /// @param _wethToBeSentToVault the amount of WETH to be sent to the Vault\\n /// @param _consensusRewards the override value for consensusRewards\\n /// @param _ethThresholdCheck maximum allowed ETH balance on the contract for the function to run\\n /// @param _wethThresholdCheck maximum allowed WETH balance on the contract for the function to run\\n /// the above 2 checks are done so transaction doesn't get front run and cause\\n /// unexpected behaviour\\n function manuallyFixAccounting(\\n uint256 _activeDepositedValidators,\\n uint256 _ethToWeth,\\n uint256 _wethToBeSentToVault,\\n uint256 _consensusRewards,\\n uint256 _ethThresholdCheck,\\n uint256 _wethThresholdCheck\\n ) external onlyAccountingGovernor whenPaused {\\n uint256 ethBalance = address(this).balance;\\n uint256 wethBalance = IWETH9(WETH_TOKEN_ADDRESS).balanceOf(\\n address(this)\\n );\\n\\n require(\\n ethBalance <= _ethThresholdCheck &&\\n wethBalance <= _wethThresholdCheck,\\n \\\"over accounting threshold\\\"\\n );\\n\\n emit AccountingManuallyFixed(\\n activeDepositedValidators,\\n _activeDepositedValidators,\\n consensusRewards,\\n _consensusRewards,\\n _ethToWeth,\\n _wethToBeSentToVault\\n );\\n\\n activeDepositedValidators = _activeDepositedValidators;\\n consensusRewards = _consensusRewards;\\n if (_ethToWeth > 0) {\\n require(_ethToWeth <= ethBalance, \\\"insufficient ETH\\\");\\n\\n IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: _ethToWeth }();\\n }\\n if (_wethToBeSentToVault > 0) {\\n IWETH9(WETH_TOKEN_ADDRESS).transfer(\\n VAULT_ADDRESS,\\n _wethToBeSentToVault\\n );\\n }\\n\\n _unpause();\\n }\\n}\\n\",\"keccak256\":\"0x44a1fc3a3e324b3ae63b39d2c5ae0a3e8a1b71b8dbf7e604b70d81ef5b170754\",\"license\":\"MIT\"},\"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 address of the Wrapped ETH (WETH) token contract\\n address public immutable WETH_TOKEN_ADDRESS;\\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_ADDRESS;\\n /// @notice Address of the OETH Vault proxy contract\\n address public immutable VAULT_ADDRESS;\\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 activeDepositedValidators;\\n /// @notice State of the validators keccak256(pubKey) => state\\n mapping(bytes32 => VALIDATOR_STATE) public validatorsStates;\\n\\n // For future use\\n uint256[50] private __gap;\\n\\n enum VALIDATOR_STATE {\\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 newAddress);\\n event ETHStaked(bytes pubkey, uint256 amount, bytes withdrawal_credentials);\\n event SSVValidatorRegistered(bytes pubkey, uint64[] operatorIds);\\n event SSVValidatorExitInitiated(bytes pubkey, uint64[] operatorIds);\\n event SSVValidatorExitCompleted(bytes pubkey, uint64[] operatorIds);\\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 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 constructor(\\n address _wethAddress,\\n address _vaultAddress,\\n address _beaconChainDepositContract,\\n address _ssvNetwork\\n ) {\\n WETH_TOKEN_ADDRESS = _wethAddress;\\n BEACON_CHAIN_DEPOSIT_CONTRACT = _beaconChainDepositContract;\\n SSV_NETWORK_ADDRESS = _ssvNetwork;\\n VAULT_ADDRESS = _vaultAddress;\\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 emit RegistratorChanged(_address);\\n validatorRegistrator = _address;\\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 function stakeEth(ValidatorStakeData[] calldata validators)\\n external\\n onlyRegistrator\\n whenNotPaused\\n {\\n uint256 requiredETH = validators.length * 32 ether;\\n\\n // Check there is enough WETH from the deposits sitting in this strategy contract\\n require(\\n requiredETH <= IWETH9(WETH_TOKEN_ADDRESS).balanceOf(address(this)),\\n \\\"insufficient WETH\\\"\\n );\\n\\n // Convert required ETH from WETH\\n IWETH9(WETH_TOKEN_ADDRESS).withdraw(requiredETH);\\n\\n // For each validator\\n for (uint256 i = 0; i < validators.length; ) {\\n bytes32 pubkeyHash = keccak256(validators[i].pubkey);\\n VALIDATOR_STATE currentState = validatorsStates[pubkeyHash];\\n\\n require(\\n currentState == VALIDATOR_STATE.REGISTERED,\\n \\\"Validator not registered\\\"\\n );\\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 withdrawal_credentials = abi.encodePacked(\\n bytes1(0x01),\\n bytes11(0),\\n address(this)\\n );\\n IDepositContract(BEACON_CHAIN_DEPOSIT_CONTRACT).deposit(\\n validators[i].pubkey,\\n withdrawal_credentials,\\n validators[i].signature,\\n validators[i].depositDataRoot\\n );\\n\\n activeDepositedValidators += 1;\\n emit ETHStaked(\\n validators[i].pubkey,\\n 32 ether,\\n withdrawal_credentials\\n );\\n\\n validatorsStates[pubkeyHash] = VALIDATOR_STATE.STAKED;\\n\\n unchecked {\\n ++i;\\n }\\n }\\n }\\n\\n /// @notice Registers a new validator in the SSV Cluster.\\n /// Only the registrator can call this function.\\n function registerSsvValidator(\\n bytes calldata publicKey,\\n uint64[] calldata operatorIds,\\n bytes calldata sharesData,\\n uint256 amount,\\n Cluster calldata cluster\\n ) external onlyRegistrator whenNotPaused {\\n ISSVNetwork(SSV_NETWORK_ADDRESS).registerValidator(\\n publicKey,\\n operatorIds,\\n sharesData,\\n amount,\\n cluster\\n );\\n validatorsStates[keccak256(publicKey)] = VALIDATOR_STATE.REGISTERED;\\n emit SSVValidatorRegistered(publicKey, operatorIds);\\n }\\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 function exitSsvValidator(\\n bytes calldata publicKey,\\n uint64[] calldata operatorIds\\n ) external onlyRegistrator whenNotPaused {\\n VALIDATOR_STATE currentState = validatorsStates[keccak256(publicKey)];\\n require(currentState == VALIDATOR_STATE.STAKED, \\\"Validator not staked\\\");\\n\\n ISSVNetwork(SSV_NETWORK_ADDRESS).exitValidator(publicKey, operatorIds);\\n emit SSVValidatorExitInitiated(publicKey, operatorIds);\\n\\n validatorsStates[keccak256(publicKey)] = VALIDATOR_STATE.EXITING;\\n }\\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 function removeSsvValidator(\\n bytes calldata publicKey,\\n uint64[] calldata operatorIds,\\n Cluster calldata cluster\\n ) external onlyRegistrator whenNotPaused {\\n VALIDATOR_STATE currentState = validatorsStates[keccak256(publicKey)];\\n require(\\n currentState == VALIDATOR_STATE.EXITING,\\n \\\"Validator not exiting\\\"\\n );\\n\\n ISSVNetwork(SSV_NETWORK_ADDRESS).removeValidator(\\n publicKey,\\n operatorIds,\\n cluster\\n );\\n emit SSVValidatorExitCompleted(publicKey, operatorIds);\\n\\n validatorsStates[keccak256(publicKey)] = VALIDATOR_STATE.EXIT_COMPLETE;\\n }\\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 cluster The SSV cluster details that must be derived from emitted events from the SSVNetwork contract.\\n function depositSSV(\\n uint64[] memory operatorIds,\\n uint256 amount,\\n Cluster memory cluster\\n ) external onlyStrategist {\\n ISSVNetwork(SSV_NETWORK_ADDRESS).deposit(\\n address(this),\\n operatorIds,\\n amount,\\n cluster\\n );\\n }\\n}\\n\",\"keccak256\":\"0x3caea29d952f616674ae0c9c80a161cc5d07b956b2dd219f8674119e41141c53\",\"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/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\",\"keccak256\":\"0x5e17bb3db9f9e1014b7c5c836547f8fa81e02af7568c0bb8f2a2e0e7c2192db4\",\"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/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": "0x610180604052600060685560006069556000606a553480156200002157600080fd5b5060405162004ce338038062004ce3833981016040819052620000449162000147565b8585876020015183868383838362000062336200011760201b60201c565b60008051602062004cc3833981519152546040516001600160a01b03909116906000907fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a908290a36033805460ff191690556001600160601b0319606094851b811660805291841b821660a052831b811660c05290821b811660e0528651821b811661010052602090960151811b86166101205298891b851661014052505050509190931b1661016052506200022292505050565b60008051602062004cc383398151915255565b80516001600160a01b03811681146200014257600080fd5b919050565b60008060008060008086880360e08112156200016257600080fd5b60408112156200017157600080fd5b50604080519081016001600160401b0381118282101715620001a357634e487b7160e01b600052604160045260246000fd5b604052620001b1886200012a565b8152620001c1602089016200012a565b60208201529550620001d6604088016200012a565b9450620001e6606088016200012a565b9350620001f6608088016200012a565b92506200020660a088016200012a565b91506200021660c088016200012a565b90509295509295509295565b60805160601c60a05160601c60c05160601c60e05160601c6101005160601c6101205160601c6101405160601c6101605160601c614904620003bf600039600081816102c2015281816109b301526132ee01526000818161059801526127ba01526000818161046c01528181610db601528181611d0301528181611e7c01528181612b9b0152612e230152600061097f0152600081816106f101528181610b4e01528181611b4001528181611c010152818161231601526125650152600081816109fc01528181610c540152818161172b0152818161278a015281816128a20152612d190152600081816108cb015261147c0152600081816102f4015281816104f6015281816107c201528181610ab501528181610e2b01528181610ffa01528181611082015281816112310152818161130c0152818161192201528181611ab001528181611b6f01528181611ded01528181611e9d0152818161229001528181612345015281816124df0152818161259401528181612eae01528181612f3d015281816133f30152818161347801526134ec01526149046000f3fe6080604052600436106102b25760003560e01c8063853828b611610175578063c2e1e3f4116100dc578063d9caed1211610095578063dd505df61161006f578063dd505df6146109a1578063de5f6268146109d5578063f1188e40146109ea578063f6ca71b014610a1e57600080fd5b8063d9caed121461092d578063d9f00ec71461094d578063dbe55e561461096d57600080fd5b8063c2e1e3f414610867578063c7af335214610887578063c98517c51461089c578063cceab750146108b9578063d38bfff4146108ed578063d5c360f61461090d57600080fd5b8063a4f98af41161012e578063a4f98af414610790578063aa388af6146107a5578063ab12edf5146107f2578063ad1728cb14610812578063af37dcbe14610827578063bb1b918d1461084757600080fd5b8063853828b6146106a557806387bae867146106ba5780639092c31c146106df5780639136616a1461071357806396d538bb146107335780639da0e4621461075357600080fd5b80635c975abb116102195780636ef38795116101d25780636ef38795146105fa57806371a735f31461061a5780637b2d9b2c1461063a5780637e20fffa1461065a578063842f5c461461067a5780638456cb591461069057600080fd5b80635c975abb1461052d5780635d36b190146105515780635f515226146105665780636093d3801461058657806367c7066c146105ba5780636e811d38146105da57600080fd5b8063430bf08a1161026b578063430bf08a1461045a578063435356d11461048e57806347e7ef24146104ae578063484be812146104ce578063579a7e1a146104e45780635a063f631461051857600080fd5b80630c340a241461036e5780630ed57b3a146103a05780630fc3b4c4146103c05780631072cbea146103f657806322495dc8146104165780633c8649591461043657600080fd5b3661036957336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614806103165750336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016145b6103675760405162461bcd60e51b815260206004820152601e60248201527f657468206e6f742066726f6d20616c6c6f77656420636f6e747261637473000060448201526064015b60405180910390fd5b005b600080fd5b34801561037a57600080fd5b50610383610a40565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156103ac57600080fd5b506103676103bb366004613ce6565b610a5d565b3480156103cc57600080fd5b506103836103db366004613cac565b60a0602052600090815260409020546001600160a01b031681565b34801561040257600080fd5b50610367610411366004613d60565b610a8f565b34801561042257600080fd5b50610367610431366004613e54565b610b4c565b34801561044257600080fd5b5061044c60695481565b604051908152602001610397565b34801561046657600080fd5b506103837f000000000000000000000000000000000000000000000000000000000000000081565b34801561049a57600080fd5b506103676104a9366004613dcd565b610cc6565b3480156104ba57600080fd5b506103676104c9366004613d60565b610dab565b3480156104da57600080fd5b5061044c606a5481565b3480156104f057600080fd5b506103837f000000000000000000000000000000000000000000000000000000000000000081565b34801561052457600080fd5b50610367610eb1565b34801561053957600080fd5b5060335460ff165b6040519015158152602001610397565b34801561055d57600080fd5b50610367610f50565b34801561057257600080fd5b5061044c610581366004613cac565b610ff6565b34801561059257600080fd5b506103837f000000000000000000000000000000000000000000000000000000000000000081565b3480156105c657600080fd5b5060a454610383906001600160a01b031681565b3480156105e657600080fd5b506103676105f5366004613cac565b61112a565b34801561060657600080fd5b50610367610615366004613d8c565b6111b2565b34801561062657600080fd5b50610367610635366004614062565b611634565b34801561064657600080fd5b50610383610655366004613f2a565b61182d565b34801561066657600080fd5b5061036761067536600461411e565b611857565b34801561068657600080fd5b5061044c60685481565b34801561069c57600080fd5b50610367611bff565b3480156106b157600080fd5b50610367611cf8565b3480156106c657600080fd5b506033546103839061010090046001600160a01b031681565b3480156106eb57600080fd5b506103837f000000000000000000000000000000000000000000000000000000000000000081565b34801561071f57600080fd5b5061036761072e366004613f2a565b611eca565b34801561073f57600080fd5b5061036761074e366004613d8c565b612095565b34801561075f57600080fd5b5061078361076e366004613f2a565b60356020526000908152604090205460ff1681565b6040516103979190614565565b34801561079c57600080fd5b506105416121b5565b3480156107b157600080fd5b506105416107c0366004613cac565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0390811691161490565b3480156107fe57600080fd5b5061036761080d3660046140fc565b612677565b34801561081e57600080fd5b50610367612773565b34801561083357600080fd5b50606b54610383906001600160a01b031681565b34801561085357600080fd5b50610367610862366004613fae565b612839565b34801561087357600080fd5b50610367610882366004613cac565b6129ac565b34801561089357600080fd5b50610541612a39565b3480156108a857600080fd5b5061044c6801bc16d674ec80000081565b3480156108c557600080fd5b506103837f000000000000000000000000000000000000000000000000000000000000000081565b3480156108f957600080fd5b50610367610908366004613cac565b612a6a565b34801561091957600080fd5b50610367610928366004613cac565b612b0e565b34801561093957600080fd5b50610367610948366004613d1f565b612b90565b34801561095957600080fd5b50610367610968366004613f43565b612c23565b34801561097957600080fd5b506103837f000000000000000000000000000000000000000000000000000000000000000081565b3480156109ad57600080fd5b506103837f000000000000000000000000000000000000000000000000000000000000000081565b3480156109e157600080fd5b50610367612e18565b3480156109f657600080fd5b506103837f000000000000000000000000000000000000000000000000000000000000000081565b348015610a2a57600080fd5b50610a33612f62565b604051610397919061433b565b6000610a586000805160206148af8339815191525490565b905090565b610a65612a39565b610a815760405162461bcd60e51b815260040161035e906145d7565b610a8b8282612fc4565b5050565b610a97612a39565b610ab35760405162461bcd60e51b815260040161035e906145d7565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b039081169083161415610b305760405162461bcd60e51b815260206004820152601f60248201527f43616e6e6f74207472616e7366657220737570706f7274656420617373657400604482015260640161035e565b610a8b610b3b610a40565b6001600160a01b0384169083613123565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b158015610ba557600080fd5b505afa158015610bb9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bdd9190613cc9565b6001600160a01b0316336001600160a01b031614610c3d5760405162461bcd60e51b815260206004820152601c60248201527f43616c6c6572206973206e6f7420746865205374726174656769737400000000604482015260640161035e565b60405163bc26e7e560e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063bc26e7e590610c8f90309087908790879060040161428b565b600060405180830381600087803b158015610ca957600080fd5b505af1158015610cbd573d6000803e3d6000fd5b50505050505050565b610cce612a39565b610cea5760405162461bcd60e51b815260040161035e906145d7565b600054610100900460ff1680610d03575060005460ff16155b610d665760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840161035e565b600054610100900460ff16158015610d88576000805461ffff19166101011790555b610d9384848461317a565b8015610da5576000805461ff00191690555b50505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610df35760405162461bcd60e51b815260040161035e906145a0565b60008051602061488f83398151915280546002811415610e255760405162461bcd60e51b815260040161035e9061466f565b600282557f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316846001600160a01b031614610e9e5760405162461bcd60e51b8152602060048201526011602482015270155b9cdd5c1c1bdc9d195908185cdcd95d607a1b604482015260640161035e565b610ea88484613235565b50600190555050565b60a4546001600160a01b03163314610f0b5760405162461bcd60e51b815260206004820152601b60248201527f43616c6c6572206973206e6f7420746865204861727665737465720000000000604482015260640161035e565b60008051602061488f83398151915280546002811415610f3d5760405162461bcd60e51b815260040161035e9061466f565b60028255610f496132c7565b5060019055565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b031614610feb5760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b606482015260840161035e565b610ff433613515565b565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b03161461106d5760405162461bcd60e51b8152602060048201526011602482015270155b9cdd5c1c1bdc9d195908185cdcd95d607a1b604482015260640161035e565b6040516370a0823160e01b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b1580156110cc57600080fd5b505afa1580156110e0573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061110491906140e3565b60345461111a906801bc16d674ec800000614780565b6111249190614746565b92915050565b611132612a39565b61114e5760405162461bcd60e51b815260040161035e906145d7565b6040516001600160a01b03821681527f83f29c79feb71f8fba9d0fbc4ba5f0982a28b6b1e868b3fc50e6400d100bca0f9060200160405180910390a1603380546001600160a01b0390921661010002610100600160a81b0319909216919091179055565b60335461010090046001600160a01b031633146111e15760405162461bcd60e51b815260040161035e90614638565b60335460ff16156112045760405162461bcd60e51b815260040161035e9061460e565b6000611219826801bc16d674ec800000614780565b6040516370a0823160e01b81523060048201529091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b15801561127b57600080fd5b505afa15801561128f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112b391906140e3565b8111156112f65760405162461bcd60e51b81526020600482015260116024820152700d2dce6eaccccd2c6d2cadce840ae8aa89607b1b604482015260640161035e565b604051632e1a7d4d60e01b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561135857600080fd5b505af115801561136c573d6000803e3d6000fd5b5050505060005b82811015610da557600084848381811061138f5761138f61483f565b90506020028101906113a191906146dd565b6113ab9080614697565b6040516113b992919061425f565b6040805191829003909120600081815260356020529182205490925060ff16908160038111156113eb576113eb614813565b146114385760405162461bcd60e51b815260206004820152601860248201527f56616c696461746f72206e6f7420726567697374657265640000000000000000604482015260640161035e565b60408051600160f81b60208201526000602182018190526bffffffffffffffffffffffff193060601b16602c830152910160405160208183030381529060405290507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663228951188888878181106114bb576114bb61483f565b90506020028101906114cd91906146dd565b6114d79080614697565b848b8b8a8181106114ea576114ea61483f565b90506020028101906114fc91906146dd565b61150a906020810190614697565b8d8d8c81811061151c5761151c61483f565b905060200281019061152e91906146dd565b604001356040518763ffffffff1660e01b8152600401611553969594939291906144ea565b600060405180830381600087803b15801561156d57600080fd5b505af1158015611581573d6000803e3d6000fd5b505050506001603460008282546115989190614746565b909155507ffeb31a79d38edb1b090d516e4df3e273651179c6f2c2ec53a9a22ae015b70ba990508787868181106115d1576115d161483f565b90506020028101906115e391906146dd565b6115ed9080614697565b6801bc16d674ec800000846040516116089493929190614539565b60405180910390a150506000908152603560205260409020805460ff1916600190811790915501611373565b60335461010090046001600160a01b031633146116635760405162461bcd60e51b815260040161035e90614638565b60335460ff16156116865760405162461bcd60e51b815260040161035e9061460e565b600060356000878760405161169c92919061425f565b604080519182900390912082526020820192909252016000205460ff16905060028160038111156116cf576116cf614813565b146117145760405162461bcd60e51b815260206004820152601560248201527456616c696461746f72206e6f742065786974696e6760581b604482015260640161035e565b6040516312b3fc1960e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906312b3fc199061176890899089908990899089906004016144a9565b600060405180830381600087803b15801561178257600080fd5b505af1158015611796573d6000803e3d6000fd5b505050507ff72821b8777f002ccdf6326f1242d9e0f762eb077668b67bebe640535378066d868686866040516117cf9493929190614420565b60405180910390a160036035600088886040516117ed92919061425f565b60408051918290039091208252602082019290925201600020805460ff1916600183600381111561182057611820614813565b0217905550505050505050565b60a5818154811061183d57600080fd5b6000918252602090912001546001600160a01b0316905081565b606b546001600160a01b031633146118bf5760405162461bcd60e51b815260206004820152602560248201527f43616c6c6572206973206e6f7420746865204163636f756e74696e6720476f7660448201526432b93737b960d91b606482015260840161035e565b60335460ff166119085760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b604482015260640161035e565b6040516370a0823160e01b815230600482015247906000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b15801561196c57600080fd5b505afa158015611980573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119a491906140e3565b90508382111580156119b65750828111155b611a025760405162461bcd60e51b815260206004820152601960248201527f6f766572206163636f756e74696e67207468726573686f6c6400000000000000604482015260640161035e565b60345460685460408051928352602083018b9052820152606081018690526080810188905260a081018790527fb2c41d2aedabd456081f30f3b116ce88de1c795a7d4ca787fef373a393f3c5db9060c00160405180910390a1603488905560688590558615611b235781871115611aae5760405162461bcd60e51b815260206004820152601060248201526f0d2dce6eaccccd2c6d2cadce8408aa8960831b604482015260640161035e565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0886040518263ffffffff1660e01b81526004016000604051808303818588803b158015611b0957600080fd5b505af1158015611b1d573d6000803e3d6000fd5b50505050505b8515611bed5760405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018890527f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb90604401602060405180830381600087803b158015611bb357600080fd5b505af1158015611bc7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611beb9190613f0d565b505b611bf56135d6565b5050505050505050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b158015611c5857600080fd5b505afa158015611c6c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c909190613cc9565b6001600160a01b0316336001600160a01b031614611cf05760405162461bcd60e51b815260206004820152601c60248201527f43616c6c6572206973206e6f7420746865205374726174656769737400000000604482015260640161035e565b610ff4613669565b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161480611d475750611d32610a40565b6001600160a01b0316336001600160a01b0316145b611d9f5760405162461bcd60e51b815260206004820152602360248201527f43616c6c6572206973206e6f7420746865205661756c74206f7220476f7665726044820152623737b960e91b606482015260840161035e565b60008051602061488f83398151915280546002811415611dd15760405162461bcd60e51b815260040161035e9061466f565b600282556040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b158015611e3757600080fd5b505afa158015611e4b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e6f91906140e3565b90508015611ec257611ec27f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000836136c1565b505060019055565b611ed2612a39565b611eee5760405162461bcd60e51b815260040161035e906145d7565b60a1548110611f2f5760405162461bcd60e51b815260206004820152600d60248201526c092dcecc2d8d2c840d2dcc8caf609b1b604482015260640161035e565b600060a18281548110611f4457611f4461483f565b60009182526020808320909101546001600160a01b0390811680845260a090925260409092205460a15491935090911690611f819060019061479f565b8310156120035760a18054611f989060019061479f565b81548110611fa857611fa861483f565b60009182526020909120015460a180546001600160a01b039092169185908110611fd457611fd461483f565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505b60a180548061201457612014614829565b60008281526020808220600019908401810180546001600160a01b031990811690915593019093556001600160a01b0385811680835260a0855260409283902080549094169093559051908416815290917f16b7600acff27e39a8a96056b3d533045298de927507f5c1d97e4accde60488c910160405180910390a2505050565b61209d612a39565b6120b95760405162461bcd60e51b815260040161035e906145d7565b8060005b8181101561216c5760008484838181106120d9576120d961483f565b90506020020160208101906120ee9190613cac565b6001600160a01b0316141561215c5760405162461bcd60e51b815260206004820152602e60248201527f43616e206e6f742073657420616e20656d70747920616464726573732061732060448201526d30903932bbb0b932103a37b5b2b760911b606482015260840161035e565b612165816147e2565b90506120bd565b507f04c0b9649497d316554306e53678d5f5f5dbc3a06f97dec13ff4cfe98b986bbc60a584846040516121a193929190614388565b60405180910390a1610da560a58484613a05565b60335460009061010090046001600160a01b031633146121e75760405162461bcd60e51b815260040161035e90614638565b60335460ff161561220a5760405162461bcd60e51b815260040161035e9061460e565b6068544710156122225761221c613669565b50600090565b600060685447612232919061479f565b9050600191506801bc16d674ec800000811061240d57600061225d6801bc16d674ec8000008361475e565b90508060346000828254612271919061479f565b909155506000905061228c826801bc16d674ec800000614780565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b1580156122e957600080fd5b505af11580156122fd573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb92506044019050602060405180830381600087803b15801561238d57600080fd5b505af11580156123a1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123c59190613f0d565b5060345460408051848152602081019290925281018290527fbe7040030ff7b347853214bf49820c6d455fedf58f3815f85c7bc5216993682b9060600160405180910390a150505b60006068544761241d919061479f565b90506801bc16d674ec800000811061246f5760405162461bcd60e51b8152602060048201526015602482015274756e6578706563746564206163636f756e74696e6760581b604482015260640161035e565b8061247957505090565b6069548110156124d35780606860008282546124959190614746565b90915550506040518181527f7a745a2c63a535068f52ceca27debd5297bbad5f7f37ec53d044a59d0362445d906020015b60405180910390a1505090565b606a54811115612666577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b15801561253857600080fd5b505af115801561254c573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb92506044019050602060405180830381600087803b1580156125dc57600080fd5b505af11580156125f0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126149190613f0d565b50600160346000828254612628919061479f565b909155505060345460408051918252602082018390527f6aa7e30787b26429ced603a7aba8b19c4b5d5bcf29a3257da953c8d53bcaa3a691016124c6565b61266e613669565b60009250505090565b61267f612a39565b61269b5760405162461bcd60e51b815260040161035e906145d7565b80821080156126b257506801bc16d674ec80000082105b80156126c657506801bc16d674ec80000081105b80156126e35750673782dace9d9000006126e0838361479f565b10155b61272f5760405162461bcd60e51b815260206004820152601760248201527f696e636f7272656374206675736520696e74657276616c000000000000000000604482015260640161035e565b60408051838152602081018390527fcb8d24e46eb3c402bf344ee60a6576cba9ef2f59ea1af3b311520704924e901a910160405180910390a1606991909155606a55565b60405163095ea7b360e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015260001960248301527f0000000000000000000000000000000000000000000000000000000000000000169063095ea7b390604401602060405180830381600087803b1580156127fe57600080fd5b505af1158015612812573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128369190613f0d565b50565b60335461010090046001600160a01b031633146128685760405162461bcd60e51b815260040161035e90614638565b60335460ff161561288b5760405162461bcd60e51b815260040161035e9061460e565b6040516301ba3ee760e21b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906306e8fb9c906128e5908b908b908b908b908b908b908b908b90600401614447565b600060405180830381600087803b1580156128ff57600080fd5b505af1158015612913573d6000803e3d6000fd5b505050506000603560008a8a60405161292d92919061425f565b60408051918290039091208252602082019290925201600020805460ff1916600183600381111561296057612960614813565b02179055507f75c4a66b2c6c28cf46db7131182a812e4fbbb2f0591377aa83a737909a9b68c38888888860405161299a9493929190614420565b60405180910390a15050505050505050565b6129b4612a39565b6129d05760405162461bcd60e51b815260040161035e906145d7565b60a454604080516001600160a01b03928316815291831660208301527fe48386b84419f4d36e0f96c10cc3510b6fb1a33795620c5098b22472bbe90796910160405180910390a160a480546001600160a01b0319166001600160a01b0392909216919091179055565b6000612a516000805160206148af8339815191525490565b6001600160a01b0316336001600160a01b031614905090565b612a72612a39565b612a8e5760405162461bcd60e51b815260040161035e906145d7565b612ab6817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b0316612ad66000805160206148af8339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b612b16612a39565b612b325760405162461bcd60e51b815260040161035e906145d7565b6040516001600160a01b03821681527ff3dd2b598e2a94dd3f46b414f7c960f8e10a0b0efd00df97d27cdd0fee5c87539060200160405180910390a1606b80546001600160a01b0319166001600160a01b0392909216919091179055565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614612bd85760405162461bcd60e51b815260040161035e906145a0565b60008051602061488f83398151915280546002811415612c0a5760405162461bcd60e51b815260040161035e9061466f565b60028255612c198585856136c1565b5060019055505050565b60335461010090046001600160a01b03163314612c525760405162461bcd60e51b815260040161035e90614638565b60335460ff1615612c755760405162461bcd60e51b815260040161035e9061460e565b6000603560008686604051612c8b92919061425f565b604080519182900390912082526020820192909252016000205460ff1690506001816003811115612cbe57612cbe614813565b14612d025760405162461bcd60e51b815260206004820152601460248201527315985b1a59185d1bdc881b9bdd081cdd185ad95960621b604482015260640161035e565b604051633877322b60e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690633877322b90612d54908890889088908890600401614420565b600060405180830381600087803b158015612d6e57600080fd5b505af1158015612d82573d6000803e3d6000fd5b505050507ff8821da16f5ed966b41e0343c3eff9903af782d74f99f1689dd9d4562b6545b385858585604051612dbb9493929190614420565b60405180910390a16002603560008787604051612dd992919061425f565b60408051918290039091208252602082019290925201600020805460ff19166001836003811115612e0c57612e0c614813565b02179055505050505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614612e605760405162461bcd60e51b815260040161035e906145a0565b60008051602061488f83398151915280546002811415612e925760405162461bcd60e51b815260040161035e9061466f565b600282556040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b158015612ef857600080fd5b505afa158015612f0c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f3091906140e3565b90508015611ec257611ec27f000000000000000000000000000000000000000000000000000000000000000082613235565b606060a5805480602002602001604051908101604052809291908181526020018280548015612fba57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612f9c575b5050505050905090565b6001600160a01b03828116600090815260a0602052604090205416156130215760405162461bcd60e51b81526020600482015260126024820152711c151bdad95b88185b1c9958591e481cd95d60721b604482015260640161035e565b6001600160a01b0382161580159061304157506001600160a01b03811615155b6130815760405162461bcd60e51b8152602060048201526011602482015270496e76616c69642061646472657373657360781b604482015260640161035e565b6001600160a01b03828116600081815260a06020908152604080832080549587166001600160a01b0319968716811790915560a1805460018101825594527faadc37b8ba5645e62f4546802db221593a94729ccbfc5a97d01365a88f64987890930180549095168417909455925190815290917fef6485b84315f9b1483beffa32aae9a0596890395e3d7521f1c5fbb51790e765910160405180910390a25050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b1790526131759084906137b9565b505050565b825161318d9060a5906020860190613a68565b508151815181146131d75760405162461bcd60e51b8152602060048201526014602482015273496e76616c696420696e7075742061727261797360601b604482015260640161035e565b60005b8181101561322e5761321e8482815181106131f7576131f761483f565b60200260200101518483815181106132115761321161483f565b6020026020010151612fc4565b613227816147e2565b90506131da565b5050505050565b6000811161327e5760405162461bcd60e51b81526020600482015260166024820152754d757374206465706f73697420736f6d657468696e6760501b604482015260640161035e565b6040805160008152602081018390526001600160a01b038416917f5548c837ab068cf56a2c2479df0882a4922fd203edb7517321831d95078c5f62910160405180910390a25050565b60335460ff16156132ea5760405162461bcd60e51b815260040161035e9061460e565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663e52253816040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561334757600080fd5b505af115801561335b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061337f91906140e3565b90506000606854826133919190614746565b9050804710156133e35760405162461bcd60e51b815260206004820152601860248201527f696e73756666696369656e74206574682062616c616e63650000000000000000604482015260640161035e565b8015610a8b5760006068819055507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b15801561344c57600080fd5b505af1158015613460573d6000803e3d6000fd5b505060a454604080516001600160a01b0392831681527f0000000000000000000000000000000000000000000000000000000000000000909216602083015281018590527ff6c07a063ed4e63808eb8da7112d46dbcd38de2b40a73dbcc9353c5a94c72353935060600191506134d39050565b60405180910390a160a454610a8b906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116911683613123565b6001600160a01b03811661356b5760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f722069732061646472657373283029000000000000604482015260640161035e565b806001600160a01b031661358b6000805160206148af8339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a3612836816000805160206148af83398151915255565b60335460ff1661361f5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b604482015260640161035e565b6033805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b60335460ff161561368c5760405162461bcd60e51b815260040161035e9061460e565b6033805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25861364c3390565b600081116137115760405162461bcd60e51b815260206004820152601760248201527f4d75737420776974686472617720736f6d657468696e67000000000000000000604482015260640161035e565b6001600160a01b0383166137605760405162461bcd60e51b8152602060048201526016602482015275135d5cdd081cdc1958da599e481c9958da5c1a595b9d60521b604482015260640161035e565b6040805160008152602081018390526001600160a01b038416917f2717ead6b9200dd235aad468c9809ea400fe33ac69b5bfaa6d3e90fc922b6398910160405180910390a26131756001600160a01b0383168483613123565b600061380e826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661388b9092919063ffffffff16565b805190915015613175578080602001905181019061382c9190613f0d565b6131755760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840161035e565b606061389a84846000856138a4565b90505b9392505050565b6060824710156139055760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840161035e565b843b6139535760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161035e565b600080866001600160a01b0316858760405161396f919061426f565b60006040518083038185875af1925050503d80600081146139ac576040519150601f19603f3d011682016040523d82523d6000602084013e6139b1565b606091505b50915091506139c18282866139cc565b979650505050505050565b606083156139db57508161389d565b8251156139eb5782518084602001fd5b8160405162461bcd60e51b815260040161035e919061458d565b828054828255906000526020600020908101928215613a58579160200282015b82811115613a585781546001600160a01b0319166001600160a01b03843516178255602090920191600190910190613a25565b50613a64929150613abd565b5090565b828054828255906000526020600020908101928215613a58579160200282015b82811115613a5857825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190613a88565b5b80821115613a645760008155600101613abe565b60008083601f840112613ae457600080fd5b5081356001600160401b03811115613afb57600080fd5b6020830191508360208260051b8501011115613b1657600080fd5b9250929050565b600082601f830112613b2e57600080fd5b81356020613b43613b3e83614723565b6146f3565b80838252828201915082860187848660051b8901011115613b6357600080fd5b60005b85811015613b8b578135613b798161486b565b84529284019290840190600101613b66565b5090979650505050505050565b60008083601f840112613baa57600080fd5b5081356001600160401b03811115613bc157600080fd5b602083019150836020828501011115613b1657600080fd5b600060a08284031215613beb57600080fd5b50919050565b600060a08284031215613c0357600080fd5b60405160a081018181106001600160401b0382111715613c2557613c25614855565b604052905080613c3483613c7c565b8152613c4260208401613c95565b6020820152613c5360408401613c95565b60408201526060830135613c6681614880565b6060820152608092830135920191909152919050565b803563ffffffff81168114613c9057600080fd5b919050565b80356001600160401b0381168114613c9057600080fd5b600060208284031215613cbe57600080fd5b813561389d8161486b565b600060208284031215613cdb57600080fd5b815161389d8161486b565b60008060408385031215613cf957600080fd5b8235613d048161486b565b91506020830135613d148161486b565b809150509250929050565b600080600060608486031215613d3457600080fd5b8335613d3f8161486b565b92506020840135613d4f8161486b565b929592945050506040919091013590565b60008060408385031215613d7357600080fd5b8235613d7e8161486b565b946020939093013593505050565b60008060208385031215613d9f57600080fd5b82356001600160401b03811115613db557600080fd5b613dc185828601613ad2565b90969095509350505050565b600080600060608486031215613de257600080fd5b83356001600160401b0380821115613df957600080fd5b613e0587838801613b1d565b94506020860135915080821115613e1b57600080fd5b613e2787838801613b1d565b93506040860135915080821115613e3d57600080fd5b50613e4a86828701613b1d565b9150509250925092565b600080600060e08486031215613e6957600080fd5b83356001600160401b03811115613e7f57600080fd5b8401601f81018613613e9057600080fd5b80356020613ea0613b3e83614723565b8083825282820191508285018a848660051b8801011115613ec057600080fd5b600095505b84861015613eea57613ed681613c95565b835260019590950194918301918301613ec5565b509650508601359350613f04915086905060408601613bf1565b90509250925092565b600060208284031215613f1f57600080fd5b815161389d81614880565b600060208284031215613f3c57600080fd5b5035919050565b60008060008060408587031215613f5957600080fd5b84356001600160401b0380821115613f7057600080fd5b613f7c88838901613b98565b90965094506020870135915080821115613f9557600080fd5b50613fa287828801613ad2565b95989497509550505050565b600080600080600080600080610120898b031215613fcb57600080fd5b88356001600160401b0380821115613fe257600080fd5b613fee8c838d01613b98565b909a50985060208b013591508082111561400757600080fd5b6140138c838d01613ad2565b909850965060408b013591508082111561402c57600080fd5b506140398b828c01613b98565b909550935050606089013591506140538a60808b01613bd9565b90509295985092959890939650565b600080600080600060e0868803121561407a57600080fd5b85356001600160401b038082111561409157600080fd5b61409d89838a01613b98565b909750955060208801359150808211156140b657600080fd5b506140c388828901613ad2565b90945092506140d790508760408801613bd9565b90509295509295909350565b6000602082840312156140f557600080fd5b5051919050565b6000806040838503121561410f57600080fd5b50508035926020909101359150565b60008060008060008060c0878903121561413757600080fd5b505084359660208601359650604086013595606081013595506080810135945060a0013592509050565b8183526000602080850194508260005b8581101561419d576001600160401b0361418a83613c95565b1687529582019590820190600101614171565b509495945050505050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b600081518084526141e98160208601602086016147b6565b601f01601f19169290920160200192915050565b63ffffffff61420b82613c7c565b16825261421a60208201613c95565b6001600160401b0380821660208501528061423760408501613c95565b1660408501525050606081013561424d81614880565b15156060830152608090810135910152565b8183823760009101908152919050565b600082516142818184602087016147b6565b9190910192915050565b6001600160a01b03851681526101006020808301829052855191830182905260009161012084019187810191845b818110156142de5783516001600160401b0316855293820193928201926001016142b9565b505082935086604086015263ffffffff865116606086015280860151925050506001600160401b0380821660808501528060408601511660a085015250506060830151151560c0830152608083015160e083015295945050505050565b6020808252825182820181905260009190848201906040850190845b8181101561437c5783516001600160a01b031683529284019291840191600101614357565b50909695505050505050565b6000604082016040835280865480835260608501915087600052602092508260002060005b828110156143d25781546001600160a01b0316845292840192600191820191016143ad565b505050838103828501528481528590820160005b868110156144145782356143f98161486b565b6001600160a01b0316825291830191908301906001016143e6565b50979650505050505050565b6040815260006144346040830186886141a8565b82810360208401526139c1818587614161565b600061012080835261445c8184018b8d6141a8565b9050828103602084015261447181898b614161565b905082810360408401526144868187896141a8565b91505083606083015261449c60808301846141fd565b9998505050505050505050565b60e0815260006144bd60e0830187896141a8565b82810360208401526144d0818688614161565b9150506144e060408301846141fd565b9695505050505050565b6080815260006144fe60808301888a6141a8565b828103602084015261451081886141d1565b905082810360408401526145258186886141a8565b915050826060830152979650505050505050565b60608152600061454d6060830186886141a8565b84602084015282810360408401526139c181856141d1565b602081016004831061458757634e487b7160e01b600052602160045260246000fd5b91905290565b60208152600061389d60208301846141d1565b60208082526017908201527f43616c6c6572206973206e6f7420746865205661756c74000000000000000000604082015260600190565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b60208082526010908201526f14185d5cd8589b194e881c185d5cd95960821b604082015260600190565b6020808252601d908201527f43616c6c6572206973206e6f7420746865205265676973747261746f72000000604082015260600190565b6020808252600e908201526d1499595b9d1c985b9d0818d85b1b60921b604082015260600190565b6000808335601e198436030181126146ae57600080fd5b8301803591506001600160401b038211156146c857600080fd5b602001915036819003821315613b1657600080fd5b60008235605e1983360301811261428157600080fd5b604051601f8201601f191681016001600160401b038111828210171561471b5761471b614855565b604052919050565b60006001600160401b0382111561473c5761473c614855565b5060051b60200190565b60008219821115614759576147596147fd565b500190565b60008261477b57634e487b7160e01b600052601260045260246000fd5b500490565b600081600019048311821515161561479a5761479a6147fd565b500290565b6000828210156147b1576147b16147fd565b500390565b60005b838110156147d15781810151838201526020016147b9565b83811115610da55750506000910152565b60006000198214156147f6576147f66147fd565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b038116811461283657600080fd5b801515811461283657600080fdfe53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac45357bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa26469706673582212204292636866460b0a0ebdd872cc7401407e5a3bdd212181fd3cea747a97b6379e64736f6c634300080700337bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a", + "deployedBytecode": "0x6080604052600436106102b25760003560e01c8063853828b611610175578063c2e1e3f4116100dc578063d9caed1211610095578063dd505df61161006f578063dd505df6146109a1578063de5f6268146109d5578063f1188e40146109ea578063f6ca71b014610a1e57600080fd5b8063d9caed121461092d578063d9f00ec71461094d578063dbe55e561461096d57600080fd5b8063c2e1e3f414610867578063c7af335214610887578063c98517c51461089c578063cceab750146108b9578063d38bfff4146108ed578063d5c360f61461090d57600080fd5b8063a4f98af41161012e578063a4f98af414610790578063aa388af6146107a5578063ab12edf5146107f2578063ad1728cb14610812578063af37dcbe14610827578063bb1b918d1461084757600080fd5b8063853828b6146106a557806387bae867146106ba5780639092c31c146106df5780639136616a1461071357806396d538bb146107335780639da0e4621461075357600080fd5b80635c975abb116102195780636ef38795116101d25780636ef38795146105fa57806371a735f31461061a5780637b2d9b2c1461063a5780637e20fffa1461065a578063842f5c461461067a5780638456cb591461069057600080fd5b80635c975abb1461052d5780635d36b190146105515780635f515226146105665780636093d3801461058657806367c7066c146105ba5780636e811d38146105da57600080fd5b8063430bf08a1161026b578063430bf08a1461045a578063435356d11461048e57806347e7ef24146104ae578063484be812146104ce578063579a7e1a146104e45780635a063f631461051857600080fd5b80630c340a241461036e5780630ed57b3a146103a05780630fc3b4c4146103c05780631072cbea146103f657806322495dc8146104165780633c8649591461043657600080fd5b3661036957336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614806103165750336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016145b6103675760405162461bcd60e51b815260206004820152601e60248201527f657468206e6f742066726f6d20616c6c6f77656420636f6e747261637473000060448201526064015b60405180910390fd5b005b600080fd5b34801561037a57600080fd5b50610383610a40565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156103ac57600080fd5b506103676103bb366004613ce6565b610a5d565b3480156103cc57600080fd5b506103836103db366004613cac565b60a0602052600090815260409020546001600160a01b031681565b34801561040257600080fd5b50610367610411366004613d60565b610a8f565b34801561042257600080fd5b50610367610431366004613e54565b610b4c565b34801561044257600080fd5b5061044c60695481565b604051908152602001610397565b34801561046657600080fd5b506103837f000000000000000000000000000000000000000000000000000000000000000081565b34801561049a57600080fd5b506103676104a9366004613dcd565b610cc6565b3480156104ba57600080fd5b506103676104c9366004613d60565b610dab565b3480156104da57600080fd5b5061044c606a5481565b3480156104f057600080fd5b506103837f000000000000000000000000000000000000000000000000000000000000000081565b34801561052457600080fd5b50610367610eb1565b34801561053957600080fd5b5060335460ff165b6040519015158152602001610397565b34801561055d57600080fd5b50610367610f50565b34801561057257600080fd5b5061044c610581366004613cac565b610ff6565b34801561059257600080fd5b506103837f000000000000000000000000000000000000000000000000000000000000000081565b3480156105c657600080fd5b5060a454610383906001600160a01b031681565b3480156105e657600080fd5b506103676105f5366004613cac565b61112a565b34801561060657600080fd5b50610367610615366004613d8c565b6111b2565b34801561062657600080fd5b50610367610635366004614062565b611634565b34801561064657600080fd5b50610383610655366004613f2a565b61182d565b34801561066657600080fd5b5061036761067536600461411e565b611857565b34801561068657600080fd5b5061044c60685481565b34801561069c57600080fd5b50610367611bff565b3480156106b157600080fd5b50610367611cf8565b3480156106c657600080fd5b506033546103839061010090046001600160a01b031681565b3480156106eb57600080fd5b506103837f000000000000000000000000000000000000000000000000000000000000000081565b34801561071f57600080fd5b5061036761072e366004613f2a565b611eca565b34801561073f57600080fd5b5061036761074e366004613d8c565b612095565b34801561075f57600080fd5b5061078361076e366004613f2a565b60356020526000908152604090205460ff1681565b6040516103979190614565565b34801561079c57600080fd5b506105416121b5565b3480156107b157600080fd5b506105416107c0366004613cac565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0390811691161490565b3480156107fe57600080fd5b5061036761080d3660046140fc565b612677565b34801561081e57600080fd5b50610367612773565b34801561083357600080fd5b50606b54610383906001600160a01b031681565b34801561085357600080fd5b50610367610862366004613fae565b612839565b34801561087357600080fd5b50610367610882366004613cac565b6129ac565b34801561089357600080fd5b50610541612a39565b3480156108a857600080fd5b5061044c6801bc16d674ec80000081565b3480156108c557600080fd5b506103837f000000000000000000000000000000000000000000000000000000000000000081565b3480156108f957600080fd5b50610367610908366004613cac565b612a6a565b34801561091957600080fd5b50610367610928366004613cac565b612b0e565b34801561093957600080fd5b50610367610948366004613d1f565b612b90565b34801561095957600080fd5b50610367610968366004613f43565b612c23565b34801561097957600080fd5b506103837f000000000000000000000000000000000000000000000000000000000000000081565b3480156109ad57600080fd5b506103837f000000000000000000000000000000000000000000000000000000000000000081565b3480156109e157600080fd5b50610367612e18565b3480156109f657600080fd5b506103837f000000000000000000000000000000000000000000000000000000000000000081565b348015610a2a57600080fd5b50610a33612f62565b604051610397919061433b565b6000610a586000805160206148af8339815191525490565b905090565b610a65612a39565b610a815760405162461bcd60e51b815260040161035e906145d7565b610a8b8282612fc4565b5050565b610a97612a39565b610ab35760405162461bcd60e51b815260040161035e906145d7565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b039081169083161415610b305760405162461bcd60e51b815260206004820152601f60248201527f43616e6e6f74207472616e7366657220737570706f7274656420617373657400604482015260640161035e565b610a8b610b3b610a40565b6001600160a01b0384169083613123565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b158015610ba557600080fd5b505afa158015610bb9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bdd9190613cc9565b6001600160a01b0316336001600160a01b031614610c3d5760405162461bcd60e51b815260206004820152601c60248201527f43616c6c6572206973206e6f7420746865205374726174656769737400000000604482015260640161035e565b60405163bc26e7e560e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063bc26e7e590610c8f90309087908790879060040161428b565b600060405180830381600087803b158015610ca957600080fd5b505af1158015610cbd573d6000803e3d6000fd5b50505050505050565b610cce612a39565b610cea5760405162461bcd60e51b815260040161035e906145d7565b600054610100900460ff1680610d03575060005460ff16155b610d665760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840161035e565b600054610100900460ff16158015610d88576000805461ffff19166101011790555b610d9384848461317a565b8015610da5576000805461ff00191690555b50505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610df35760405162461bcd60e51b815260040161035e906145a0565b60008051602061488f83398151915280546002811415610e255760405162461bcd60e51b815260040161035e9061466f565b600282557f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316846001600160a01b031614610e9e5760405162461bcd60e51b8152602060048201526011602482015270155b9cdd5c1c1bdc9d195908185cdcd95d607a1b604482015260640161035e565b610ea88484613235565b50600190555050565b60a4546001600160a01b03163314610f0b5760405162461bcd60e51b815260206004820152601b60248201527f43616c6c6572206973206e6f7420746865204861727665737465720000000000604482015260640161035e565b60008051602061488f83398151915280546002811415610f3d5760405162461bcd60e51b815260040161035e9061466f565b60028255610f496132c7565b5060019055565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b031614610feb5760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b606482015260840161035e565b610ff433613515565b565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b03161461106d5760405162461bcd60e51b8152602060048201526011602482015270155b9cdd5c1c1bdc9d195908185cdcd95d607a1b604482015260640161035e565b6040516370a0823160e01b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b1580156110cc57600080fd5b505afa1580156110e0573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061110491906140e3565b60345461111a906801bc16d674ec800000614780565b6111249190614746565b92915050565b611132612a39565b61114e5760405162461bcd60e51b815260040161035e906145d7565b6040516001600160a01b03821681527f83f29c79feb71f8fba9d0fbc4ba5f0982a28b6b1e868b3fc50e6400d100bca0f9060200160405180910390a1603380546001600160a01b0390921661010002610100600160a81b0319909216919091179055565b60335461010090046001600160a01b031633146111e15760405162461bcd60e51b815260040161035e90614638565b60335460ff16156112045760405162461bcd60e51b815260040161035e9061460e565b6000611219826801bc16d674ec800000614780565b6040516370a0823160e01b81523060048201529091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b15801561127b57600080fd5b505afa15801561128f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112b391906140e3565b8111156112f65760405162461bcd60e51b81526020600482015260116024820152700d2dce6eaccccd2c6d2cadce840ae8aa89607b1b604482015260640161035e565b604051632e1a7d4d60e01b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561135857600080fd5b505af115801561136c573d6000803e3d6000fd5b5050505060005b82811015610da557600084848381811061138f5761138f61483f565b90506020028101906113a191906146dd565b6113ab9080614697565b6040516113b992919061425f565b6040805191829003909120600081815260356020529182205490925060ff16908160038111156113eb576113eb614813565b146114385760405162461bcd60e51b815260206004820152601860248201527f56616c696461746f72206e6f7420726567697374657265640000000000000000604482015260640161035e565b60408051600160f81b60208201526000602182018190526bffffffffffffffffffffffff193060601b16602c830152910160405160208183030381529060405290507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663228951188888878181106114bb576114bb61483f565b90506020028101906114cd91906146dd565b6114d79080614697565b848b8b8a8181106114ea576114ea61483f565b90506020028101906114fc91906146dd565b61150a906020810190614697565b8d8d8c81811061151c5761151c61483f565b905060200281019061152e91906146dd565b604001356040518763ffffffff1660e01b8152600401611553969594939291906144ea565b600060405180830381600087803b15801561156d57600080fd5b505af1158015611581573d6000803e3d6000fd5b505050506001603460008282546115989190614746565b909155507ffeb31a79d38edb1b090d516e4df3e273651179c6f2c2ec53a9a22ae015b70ba990508787868181106115d1576115d161483f565b90506020028101906115e391906146dd565b6115ed9080614697565b6801bc16d674ec800000846040516116089493929190614539565b60405180910390a150506000908152603560205260409020805460ff1916600190811790915501611373565b60335461010090046001600160a01b031633146116635760405162461bcd60e51b815260040161035e90614638565b60335460ff16156116865760405162461bcd60e51b815260040161035e9061460e565b600060356000878760405161169c92919061425f565b604080519182900390912082526020820192909252016000205460ff16905060028160038111156116cf576116cf614813565b146117145760405162461bcd60e51b815260206004820152601560248201527456616c696461746f72206e6f742065786974696e6760581b604482015260640161035e565b6040516312b3fc1960e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906312b3fc199061176890899089908990899089906004016144a9565b600060405180830381600087803b15801561178257600080fd5b505af1158015611796573d6000803e3d6000fd5b505050507ff72821b8777f002ccdf6326f1242d9e0f762eb077668b67bebe640535378066d868686866040516117cf9493929190614420565b60405180910390a160036035600088886040516117ed92919061425f565b60408051918290039091208252602082019290925201600020805460ff1916600183600381111561182057611820614813565b0217905550505050505050565b60a5818154811061183d57600080fd5b6000918252602090912001546001600160a01b0316905081565b606b546001600160a01b031633146118bf5760405162461bcd60e51b815260206004820152602560248201527f43616c6c6572206973206e6f7420746865204163636f756e74696e6720476f7660448201526432b93737b960d91b606482015260840161035e565b60335460ff166119085760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b604482015260640161035e565b6040516370a0823160e01b815230600482015247906000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b15801561196c57600080fd5b505afa158015611980573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119a491906140e3565b90508382111580156119b65750828111155b611a025760405162461bcd60e51b815260206004820152601960248201527f6f766572206163636f756e74696e67207468726573686f6c6400000000000000604482015260640161035e565b60345460685460408051928352602083018b9052820152606081018690526080810188905260a081018790527fb2c41d2aedabd456081f30f3b116ce88de1c795a7d4ca787fef373a393f3c5db9060c00160405180910390a1603488905560688590558615611b235781871115611aae5760405162461bcd60e51b815260206004820152601060248201526f0d2dce6eaccccd2c6d2cadce8408aa8960831b604482015260640161035e565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0886040518263ffffffff1660e01b81526004016000604051808303818588803b158015611b0957600080fd5b505af1158015611b1d573d6000803e3d6000fd5b50505050505b8515611bed5760405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018890527f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb90604401602060405180830381600087803b158015611bb357600080fd5b505af1158015611bc7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611beb9190613f0d565b505b611bf56135d6565b5050505050505050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b158015611c5857600080fd5b505afa158015611c6c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c909190613cc9565b6001600160a01b0316336001600160a01b031614611cf05760405162461bcd60e51b815260206004820152601c60248201527f43616c6c6572206973206e6f7420746865205374726174656769737400000000604482015260640161035e565b610ff4613669565b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161480611d475750611d32610a40565b6001600160a01b0316336001600160a01b0316145b611d9f5760405162461bcd60e51b815260206004820152602360248201527f43616c6c6572206973206e6f7420746865205661756c74206f7220476f7665726044820152623737b960e91b606482015260840161035e565b60008051602061488f83398151915280546002811415611dd15760405162461bcd60e51b815260040161035e9061466f565b600282556040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b158015611e3757600080fd5b505afa158015611e4b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e6f91906140e3565b90508015611ec257611ec27f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000836136c1565b505060019055565b611ed2612a39565b611eee5760405162461bcd60e51b815260040161035e906145d7565b60a1548110611f2f5760405162461bcd60e51b815260206004820152600d60248201526c092dcecc2d8d2c840d2dcc8caf609b1b604482015260640161035e565b600060a18281548110611f4457611f4461483f565b60009182526020808320909101546001600160a01b0390811680845260a090925260409092205460a15491935090911690611f819060019061479f565b8310156120035760a18054611f989060019061479f565b81548110611fa857611fa861483f565b60009182526020909120015460a180546001600160a01b039092169185908110611fd457611fd461483f565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505b60a180548061201457612014614829565b60008281526020808220600019908401810180546001600160a01b031990811690915593019093556001600160a01b0385811680835260a0855260409283902080549094169093559051908416815290917f16b7600acff27e39a8a96056b3d533045298de927507f5c1d97e4accde60488c910160405180910390a2505050565b61209d612a39565b6120b95760405162461bcd60e51b815260040161035e906145d7565b8060005b8181101561216c5760008484838181106120d9576120d961483f565b90506020020160208101906120ee9190613cac565b6001600160a01b0316141561215c5760405162461bcd60e51b815260206004820152602e60248201527f43616e206e6f742073657420616e20656d70747920616464726573732061732060448201526d30903932bbb0b932103a37b5b2b760911b606482015260840161035e565b612165816147e2565b90506120bd565b507f04c0b9649497d316554306e53678d5f5f5dbc3a06f97dec13ff4cfe98b986bbc60a584846040516121a193929190614388565b60405180910390a1610da560a58484613a05565b60335460009061010090046001600160a01b031633146121e75760405162461bcd60e51b815260040161035e90614638565b60335460ff161561220a5760405162461bcd60e51b815260040161035e9061460e565b6068544710156122225761221c613669565b50600090565b600060685447612232919061479f565b9050600191506801bc16d674ec800000811061240d57600061225d6801bc16d674ec8000008361475e565b90508060346000828254612271919061479f565b909155506000905061228c826801bc16d674ec800000614780565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b1580156122e957600080fd5b505af11580156122fd573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb92506044019050602060405180830381600087803b15801561238d57600080fd5b505af11580156123a1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123c59190613f0d565b5060345460408051848152602081019290925281018290527fbe7040030ff7b347853214bf49820c6d455fedf58f3815f85c7bc5216993682b9060600160405180910390a150505b60006068544761241d919061479f565b90506801bc16d674ec800000811061246f5760405162461bcd60e51b8152602060048201526015602482015274756e6578706563746564206163636f756e74696e6760581b604482015260640161035e565b8061247957505090565b6069548110156124d35780606860008282546124959190614746565b90915550506040518181527f7a745a2c63a535068f52ceca27debd5297bbad5f7f37ec53d044a59d0362445d906020015b60405180910390a1505090565b606a54811115612666577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b15801561253857600080fd5b505af115801561254c573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb92506044019050602060405180830381600087803b1580156125dc57600080fd5b505af11580156125f0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126149190613f0d565b50600160346000828254612628919061479f565b909155505060345460408051918252602082018390527f6aa7e30787b26429ced603a7aba8b19c4b5d5bcf29a3257da953c8d53bcaa3a691016124c6565b61266e613669565b60009250505090565b61267f612a39565b61269b5760405162461bcd60e51b815260040161035e906145d7565b80821080156126b257506801bc16d674ec80000082105b80156126c657506801bc16d674ec80000081105b80156126e35750673782dace9d9000006126e0838361479f565b10155b61272f5760405162461bcd60e51b815260206004820152601760248201527f696e636f7272656374206675736520696e74657276616c000000000000000000604482015260640161035e565b60408051838152602081018390527fcb8d24e46eb3c402bf344ee60a6576cba9ef2f59ea1af3b311520704924e901a910160405180910390a1606991909155606a55565b60405163095ea7b360e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015260001960248301527f0000000000000000000000000000000000000000000000000000000000000000169063095ea7b390604401602060405180830381600087803b1580156127fe57600080fd5b505af1158015612812573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128369190613f0d565b50565b60335461010090046001600160a01b031633146128685760405162461bcd60e51b815260040161035e90614638565b60335460ff161561288b5760405162461bcd60e51b815260040161035e9061460e565b6040516301ba3ee760e21b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906306e8fb9c906128e5908b908b908b908b908b908b908b908b90600401614447565b600060405180830381600087803b1580156128ff57600080fd5b505af1158015612913573d6000803e3d6000fd5b505050506000603560008a8a60405161292d92919061425f565b60408051918290039091208252602082019290925201600020805460ff1916600183600381111561296057612960614813565b02179055507f75c4a66b2c6c28cf46db7131182a812e4fbbb2f0591377aa83a737909a9b68c38888888860405161299a9493929190614420565b60405180910390a15050505050505050565b6129b4612a39565b6129d05760405162461bcd60e51b815260040161035e906145d7565b60a454604080516001600160a01b03928316815291831660208301527fe48386b84419f4d36e0f96c10cc3510b6fb1a33795620c5098b22472bbe90796910160405180910390a160a480546001600160a01b0319166001600160a01b0392909216919091179055565b6000612a516000805160206148af8339815191525490565b6001600160a01b0316336001600160a01b031614905090565b612a72612a39565b612a8e5760405162461bcd60e51b815260040161035e906145d7565b612ab6817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b0316612ad66000805160206148af8339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b612b16612a39565b612b325760405162461bcd60e51b815260040161035e906145d7565b6040516001600160a01b03821681527ff3dd2b598e2a94dd3f46b414f7c960f8e10a0b0efd00df97d27cdd0fee5c87539060200160405180910390a1606b80546001600160a01b0319166001600160a01b0392909216919091179055565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614612bd85760405162461bcd60e51b815260040161035e906145a0565b60008051602061488f83398151915280546002811415612c0a5760405162461bcd60e51b815260040161035e9061466f565b60028255612c198585856136c1565b5060019055505050565b60335461010090046001600160a01b03163314612c525760405162461bcd60e51b815260040161035e90614638565b60335460ff1615612c755760405162461bcd60e51b815260040161035e9061460e565b6000603560008686604051612c8b92919061425f565b604080519182900390912082526020820192909252016000205460ff1690506001816003811115612cbe57612cbe614813565b14612d025760405162461bcd60e51b815260206004820152601460248201527315985b1a59185d1bdc881b9bdd081cdd185ad95960621b604482015260640161035e565b604051633877322b60e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690633877322b90612d54908890889088908890600401614420565b600060405180830381600087803b158015612d6e57600080fd5b505af1158015612d82573d6000803e3d6000fd5b505050507ff8821da16f5ed966b41e0343c3eff9903af782d74f99f1689dd9d4562b6545b385858585604051612dbb9493929190614420565b60405180910390a16002603560008787604051612dd992919061425f565b60408051918290039091208252602082019290925201600020805460ff19166001836003811115612e0c57612e0c614813565b02179055505050505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614612e605760405162461bcd60e51b815260040161035e906145a0565b60008051602061488f83398151915280546002811415612e925760405162461bcd60e51b815260040161035e9061466f565b600282556040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b158015612ef857600080fd5b505afa158015612f0c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f3091906140e3565b90508015611ec257611ec27f000000000000000000000000000000000000000000000000000000000000000082613235565b606060a5805480602002602001604051908101604052809291908181526020018280548015612fba57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612f9c575b5050505050905090565b6001600160a01b03828116600090815260a0602052604090205416156130215760405162461bcd60e51b81526020600482015260126024820152711c151bdad95b88185b1c9958591e481cd95d60721b604482015260640161035e565b6001600160a01b0382161580159061304157506001600160a01b03811615155b6130815760405162461bcd60e51b8152602060048201526011602482015270496e76616c69642061646472657373657360781b604482015260640161035e565b6001600160a01b03828116600081815260a06020908152604080832080549587166001600160a01b0319968716811790915560a1805460018101825594527faadc37b8ba5645e62f4546802db221593a94729ccbfc5a97d01365a88f64987890930180549095168417909455925190815290917fef6485b84315f9b1483beffa32aae9a0596890395e3d7521f1c5fbb51790e765910160405180910390a25050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b1790526131759084906137b9565b505050565b825161318d9060a5906020860190613a68565b508151815181146131d75760405162461bcd60e51b8152602060048201526014602482015273496e76616c696420696e7075742061727261797360601b604482015260640161035e565b60005b8181101561322e5761321e8482815181106131f7576131f761483f565b60200260200101518483815181106132115761321161483f565b6020026020010151612fc4565b613227816147e2565b90506131da565b5050505050565b6000811161327e5760405162461bcd60e51b81526020600482015260166024820152754d757374206465706f73697420736f6d657468696e6760501b604482015260640161035e565b6040805160008152602081018390526001600160a01b038416917f5548c837ab068cf56a2c2479df0882a4922fd203edb7517321831d95078c5f62910160405180910390a25050565b60335460ff16156132ea5760405162461bcd60e51b815260040161035e9061460e565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663e52253816040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561334757600080fd5b505af115801561335b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061337f91906140e3565b90506000606854826133919190614746565b9050804710156133e35760405162461bcd60e51b815260206004820152601860248201527f696e73756666696369656e74206574682062616c616e63650000000000000000604482015260640161035e565b8015610a8b5760006068819055507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b15801561344c57600080fd5b505af1158015613460573d6000803e3d6000fd5b505060a454604080516001600160a01b0392831681527f0000000000000000000000000000000000000000000000000000000000000000909216602083015281018590527ff6c07a063ed4e63808eb8da7112d46dbcd38de2b40a73dbcc9353c5a94c72353935060600191506134d39050565b60405180910390a160a454610a8b906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116911683613123565b6001600160a01b03811661356b5760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f722069732061646472657373283029000000000000604482015260640161035e565b806001600160a01b031661358b6000805160206148af8339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a3612836816000805160206148af83398151915255565b60335460ff1661361f5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b604482015260640161035e565b6033805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b60335460ff161561368c5760405162461bcd60e51b815260040161035e9061460e565b6033805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25861364c3390565b600081116137115760405162461bcd60e51b815260206004820152601760248201527f4d75737420776974686472617720736f6d657468696e67000000000000000000604482015260640161035e565b6001600160a01b0383166137605760405162461bcd60e51b8152602060048201526016602482015275135d5cdd081cdc1958da599e481c9958da5c1a595b9d60521b604482015260640161035e565b6040805160008152602081018390526001600160a01b038416917f2717ead6b9200dd235aad468c9809ea400fe33ac69b5bfaa6d3e90fc922b6398910160405180910390a26131756001600160a01b0383168483613123565b600061380e826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661388b9092919063ffffffff16565b805190915015613175578080602001905181019061382c9190613f0d565b6131755760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840161035e565b606061389a84846000856138a4565b90505b9392505050565b6060824710156139055760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840161035e565b843b6139535760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161035e565b600080866001600160a01b0316858760405161396f919061426f565b60006040518083038185875af1925050503d80600081146139ac576040519150601f19603f3d011682016040523d82523d6000602084013e6139b1565b606091505b50915091506139c18282866139cc565b979650505050505050565b606083156139db57508161389d565b8251156139eb5782518084602001fd5b8160405162461bcd60e51b815260040161035e919061458d565b828054828255906000526020600020908101928215613a58579160200282015b82811115613a585781546001600160a01b0319166001600160a01b03843516178255602090920191600190910190613a25565b50613a64929150613abd565b5090565b828054828255906000526020600020908101928215613a58579160200282015b82811115613a5857825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190613a88565b5b80821115613a645760008155600101613abe565b60008083601f840112613ae457600080fd5b5081356001600160401b03811115613afb57600080fd5b6020830191508360208260051b8501011115613b1657600080fd5b9250929050565b600082601f830112613b2e57600080fd5b81356020613b43613b3e83614723565b6146f3565b80838252828201915082860187848660051b8901011115613b6357600080fd5b60005b85811015613b8b578135613b798161486b565b84529284019290840190600101613b66565b5090979650505050505050565b60008083601f840112613baa57600080fd5b5081356001600160401b03811115613bc157600080fd5b602083019150836020828501011115613b1657600080fd5b600060a08284031215613beb57600080fd5b50919050565b600060a08284031215613c0357600080fd5b60405160a081018181106001600160401b0382111715613c2557613c25614855565b604052905080613c3483613c7c565b8152613c4260208401613c95565b6020820152613c5360408401613c95565b60408201526060830135613c6681614880565b6060820152608092830135920191909152919050565b803563ffffffff81168114613c9057600080fd5b919050565b80356001600160401b0381168114613c9057600080fd5b600060208284031215613cbe57600080fd5b813561389d8161486b565b600060208284031215613cdb57600080fd5b815161389d8161486b565b60008060408385031215613cf957600080fd5b8235613d048161486b565b91506020830135613d148161486b565b809150509250929050565b600080600060608486031215613d3457600080fd5b8335613d3f8161486b565b92506020840135613d4f8161486b565b929592945050506040919091013590565b60008060408385031215613d7357600080fd5b8235613d7e8161486b565b946020939093013593505050565b60008060208385031215613d9f57600080fd5b82356001600160401b03811115613db557600080fd5b613dc185828601613ad2565b90969095509350505050565b600080600060608486031215613de257600080fd5b83356001600160401b0380821115613df957600080fd5b613e0587838801613b1d565b94506020860135915080821115613e1b57600080fd5b613e2787838801613b1d565b93506040860135915080821115613e3d57600080fd5b50613e4a86828701613b1d565b9150509250925092565b600080600060e08486031215613e6957600080fd5b83356001600160401b03811115613e7f57600080fd5b8401601f81018613613e9057600080fd5b80356020613ea0613b3e83614723565b8083825282820191508285018a848660051b8801011115613ec057600080fd5b600095505b84861015613eea57613ed681613c95565b835260019590950194918301918301613ec5565b509650508601359350613f04915086905060408601613bf1565b90509250925092565b600060208284031215613f1f57600080fd5b815161389d81614880565b600060208284031215613f3c57600080fd5b5035919050565b60008060008060408587031215613f5957600080fd5b84356001600160401b0380821115613f7057600080fd5b613f7c88838901613b98565b90965094506020870135915080821115613f9557600080fd5b50613fa287828801613ad2565b95989497509550505050565b600080600080600080600080610120898b031215613fcb57600080fd5b88356001600160401b0380821115613fe257600080fd5b613fee8c838d01613b98565b909a50985060208b013591508082111561400757600080fd5b6140138c838d01613ad2565b909850965060408b013591508082111561402c57600080fd5b506140398b828c01613b98565b909550935050606089013591506140538a60808b01613bd9565b90509295985092959890939650565b600080600080600060e0868803121561407a57600080fd5b85356001600160401b038082111561409157600080fd5b61409d89838a01613b98565b909750955060208801359150808211156140b657600080fd5b506140c388828901613ad2565b90945092506140d790508760408801613bd9565b90509295509295909350565b6000602082840312156140f557600080fd5b5051919050565b6000806040838503121561410f57600080fd5b50508035926020909101359150565b60008060008060008060c0878903121561413757600080fd5b505084359660208601359650604086013595606081013595506080810135945060a0013592509050565b8183526000602080850194508260005b8581101561419d576001600160401b0361418a83613c95565b1687529582019590820190600101614171565b509495945050505050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b600081518084526141e98160208601602086016147b6565b601f01601f19169290920160200192915050565b63ffffffff61420b82613c7c565b16825261421a60208201613c95565b6001600160401b0380821660208501528061423760408501613c95565b1660408501525050606081013561424d81614880565b15156060830152608090810135910152565b8183823760009101908152919050565b600082516142818184602087016147b6565b9190910192915050565b6001600160a01b03851681526101006020808301829052855191830182905260009161012084019187810191845b818110156142de5783516001600160401b0316855293820193928201926001016142b9565b505082935086604086015263ffffffff865116606086015280860151925050506001600160401b0380821660808501528060408601511660a085015250506060830151151560c0830152608083015160e083015295945050505050565b6020808252825182820181905260009190848201906040850190845b8181101561437c5783516001600160a01b031683529284019291840191600101614357565b50909695505050505050565b6000604082016040835280865480835260608501915087600052602092508260002060005b828110156143d25781546001600160a01b0316845292840192600191820191016143ad565b505050838103828501528481528590820160005b868110156144145782356143f98161486b565b6001600160a01b0316825291830191908301906001016143e6565b50979650505050505050565b6040815260006144346040830186886141a8565b82810360208401526139c1818587614161565b600061012080835261445c8184018b8d6141a8565b9050828103602084015261447181898b614161565b905082810360408401526144868187896141a8565b91505083606083015261449c60808301846141fd565b9998505050505050505050565b60e0815260006144bd60e0830187896141a8565b82810360208401526144d0818688614161565b9150506144e060408301846141fd565b9695505050505050565b6080815260006144fe60808301888a6141a8565b828103602084015261451081886141d1565b905082810360408401526145258186886141a8565b915050826060830152979650505050505050565b60608152600061454d6060830186886141a8565b84602084015282810360408401526139c181856141d1565b602081016004831061458757634e487b7160e01b600052602160045260246000fd5b91905290565b60208152600061389d60208301846141d1565b60208082526017908201527f43616c6c6572206973206e6f7420746865205661756c74000000000000000000604082015260600190565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b60208082526010908201526f14185d5cd8589b194e881c185d5cd95960821b604082015260600190565b6020808252601d908201527f43616c6c6572206973206e6f7420746865205265676973747261746f72000000604082015260600190565b6020808252600e908201526d1499595b9d1c985b9d0818d85b1b60921b604082015260600190565b6000808335601e198436030181126146ae57600080fd5b8301803591506001600160401b038211156146c857600080fd5b602001915036819003821315613b1657600080fd5b60008235605e1983360301811261428157600080fd5b604051601f8201601f191681016001600160401b038111828210171561471b5761471b614855565b604052919050565b60006001600160401b0382111561473c5761473c614855565b5060051b60200190565b60008219821115614759576147596147fd565b500190565b60008261477b57634e487b7160e01b600052601260045260246000fd5b500490565b600081600019048311821515161561479a5761479a6147fd565b500290565b6000828210156147b1576147b16147fd565b500390565b60005b838110156147d15781810151838201526020016147b9565b83811115610da55750506000910152565b60006000198214156147f6576147f66147fd565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b038116811461283657600080fd5b801515811461283657600080fdfe53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac45357bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa26469706673582212204292636866460b0a0ebdd872cc7401407e5a3bdd212181fd3cea747a97b6379e64736f6c63430008070033", + "libraries": {}, + "devdoc": { + "author": "Origin Protocol Inc", + "kind": "dev", + "methods": { + "checkBalance(address)": { + "params": { + "_asset": "Address of weth asset" + }, + "returns": { + "balance": " Total value of (W)ETH" + } + }, + "constructor": { + "params": { + "_baseConfig": "Base strategy config with platformAddress (ERC-4626 Vault contract), eg sfrxETH or sDAI, and vaultAddress (OToken Vault contract), eg VaultProxy or OETHVaultProxy", + "_beaconChainDepositContract": "Address of the beacon chain deposit contract", + "_feeAccumulator": "Address of the fee accumulator receiving execution layer validator rewards", + "_ssvNetwork": "Address of the SSV Network contract", + "_ssvToken": "Address of the Erc20 SSV Token contract", + "_wethAddress": "Address of the Erc20 WETH Token contract" + } + }, + "deposit(address,uint256)": { + "params": { + "_amount": "Amount of assets that were transferred to the strategy by the vault.", + "_asset": "Address of asset to deposit. Has to be WETH." + } + }, + "depositSSV(uint64[],uint256,(uint32,uint64,uint64,bool,uint256))": { + "details": "A SSV cluster is defined by the SSVOwnerAddress and the set of operatorIds. uses \"onlyStrategist\" modifier so continuous front-running can't DOS our maintenance service that tries to top up SSV tokens.", + "params": { + "cluster": "The SSV cluster details that must be derived from emitted events from the SSVNetwork contract." + } + }, + "doAccounting()": { + "details": "This function could in theory be permission-less but lets allow only the Registrator (Defender Action) to call it for now." + }, + "getRewardTokenAddresses()": { + "returns": { + "_0": "address[] the reward token addresses." + } + }, + "initialize(address[],address[],address[])": { + "params": { + "_assets": "Addresses of initial supported assets", + "_pTokens": "Platform Token corresponding addresses", + "_rewardTokenAddresses": "Address of reward token for platform" + } + }, + "manuallyFixAccounting(uint256,uint256,uint256,uint256,uint256,uint256)": { + "details": "allow the accounting governor to fix the accounting of this strategy and unpause", + "params": { + "_activeDepositedValidators": "the override value of activeDepositedValidators", + "_consensusRewards": "the override value for consensusRewards", + "_ethThresholdCheck": "maximum allowed ETH balance on the contract for the function to run", + "_ethToWeth": "the amount of ETH to be converted to WETH", + "_wethThresholdCheck": "maximum allowed WETH balance on the contract for the function to run the above 2 checks are done so transaction doesn't get front run and cause unexpected behaviour", + "_wethToBeSentToVault": "the amount of WETH to be sent to the Vault" + } + }, + "paused()": { + "details": "Returns true if the contract is paused, and false otherwise." + }, + "removePToken(uint256)": { + "params": { + "_assetIndex": "Index of the asset to be removed" + } + }, + "setHarvesterAddress(address)": { + "params": { + "_harvesterAddress": "Address of the harvester contract." + } + }, + "setPTokenAddress(address,address)": { + "params": { + "_asset": "Address for the asset", + "_pToken": "Address for the corresponding platform token" + } + }, + "setRewardTokenAddresses(address[])": { + "params": { + "_rewardTokenAddresses": "Array of reward token addresses" + } + }, + "stakeEth((bytes,bytes,bytes32)[])": { + "params": { + "validators": "A list of validator data needed to stake. The `ValidatorStakeData` struct contains the pubkey, signature and depositDataRoot. Only the registrator can call this function." + } + }, + "supportsAsset(address)": { + "params": { + "_asset": "The address of the asset token." + } + }, + "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" + } + }, + "withdraw(address,address,uint256)": { + "params": { + "_amount": "Amount of WETH to withdraw", + "_asset": "WETH to withdraw", + "_recipient": "Address to receive withdrawn assets" + } + } + }, + "stateVariables": { + "FEE_ACCUMULATOR_ADDRESS": { + "details": "this address will receive Execution layer rewards - These are rewards earned for executing transactions on the Ethereum network as part of block proposals. They include priority fees (fees paid by users for their transactions to be included) and MEV rewards (rewards for arranging transactions in a way that benefits the validator)." + } + }, + "title": "Native Staking SSV Strategy", + "version": 1 + }, + "userdoc": { + "kind": "user", + "methods": { + "BEACON_CHAIN_DEPOSIT_CONTRACT()": { + "notice": "The address of the beacon chain deposit contract" + }, + "FEE_ACCUMULATOR_ADDRESS()": { + "notice": "Fee collector address" + }, + "MAX_STAKE()": { + "notice": "The maximum amount of ETH that can be staked by a validator" + }, + "SSV_NETWORK_ADDRESS()": { + "notice": "The address of the SSV Network contract used to interface with" + }, + "SSV_TOKEN_ADDRESS()": { + "notice": "SSV ERC20 token that serves as a payment for operating SSV validators" + }, + "VAULT_ADDRESS()": { + "notice": "Address of the OETH Vault proxy contract" + }, + "WETH_TOKEN_ADDRESS()": { + "notice": "The address of the Wrapped ETH (WETH) token contract" + }, + "accountingGovernor()": { + "notice": "Governor that can manually correct the accounting" + }, + "assetToPToken(address)": { + "notice": "asset => pToken (Platform Specific Token Address)" + }, + "checkBalance(address)": { + "notice": "Returns the total value of (W)ETH that is staked to the validators and WETH deposits that are still to be staked. This does not include ETH from consensus rewards sitting in this strategy or ETH from MEV rewards in the FeeAccumulator. These rewards are harvested and sent to the Dripper so will eventually be sent to the Vault as WETH." + }, + "claimGovernance()": { + "notice": "Claim Governance of the contract to a new account (`newGovernor`). Can only be called by the new Governor." + }, + "collectRewardTokens()": { + "notice": "Collect accumulated reward token and send to Vault." + }, + "consensusRewards()": { + "notice": "Keeps track of the total consensus rewards swept from the beacon chain" + }, + "deposit(address,uint256)": { + "notice": "Unlike other strategies, this does not deposit assets into the underlying platform. It just checks the asset is WETH and emits the Deposit event. To deposit WETH into validators `registerSsvValidator` and `stakeEth` must be used. Will NOT revert if the strategy is paused from an accounting failure." + }, + "depositAll()": { + "notice": "Unlike other strategies, this does not deposit assets into the underlying platform. It just emits the Deposit event. To deposit WETH into validators `registerSsvValidator` and `stakeEth` must be used. Will NOT revert if the strategy is paused from an accounting failure." + }, + "depositSSV(uint64[],uint256,(uint32,uint64,uint64,bool,uint256))": { + "notice": "Deposits more SSV Tokens to the SSV Network contract which is used to pay the SSV Operators." + }, + "doAccounting()": { + "notice": "This notion page offers a good explanation of how the accounting functions https://www.notion.so/originprotocol/Limited-simplified-native-staking-accounting-67a217c8420d40678eb943b9da0ee77d In short, after dividing by 32, if the ETH remaining on the contract falls between 0 and fuseIntervalStart, the accounting function will treat that ETH as Beacon chain consensus rewards. On the contrary, if after dividing by 32, the ETH remaining on the contract falls between fuseIntervalEnd and 32, the accounting function will treat that as a validator slashing.Perform the accounting attributing beacon chain ETH to either full or partial withdrawals. Returns true when accounting is valid and fuse isn't \"blown\". Returns false when fuse is blown." + }, + "exitSsvValidator(bytes,uint64[])": { + "notice": "Exit a validator from the Beacon chain. The staked ETH will eventually swept to this native staking strategy. Only the registrator can call this function." + }, + "fuseIntervalEnd()": { + "notice": "end of fuse interval" + }, + "fuseIntervalStart()": { + "notice": "start of fuse interval" + }, + "getRewardTokenAddresses()": { + "notice": "Get the reward token addresses." + }, + "governor()": { + "notice": "Returns the address of the current Governor." + }, + "harvesterAddress()": { + "notice": "Address of the Harvester contract allowed to collect reward tokens" + }, + "initialize(address[],address[],address[])": { + "notice": "initialize function, to set up initial internal state" + }, + "isGovernor()": { + "notice": "Returns true if the caller is the current Governor." + }, + "platformAddress()": { + "notice": "Address of the underlying platform" + }, + "registerSsvValidator(bytes,uint64[],bytes,uint256,(uint32,uint64,uint64,bool,uint256))": { + "notice": "Registers a new validator in the SSV Cluster. Only the registrator can call this function." + }, + "removePToken(uint256)": { + "notice": "Remove a supported asset by passing its index. This method can only be called by the system Governor" + }, + "removeSsvValidator(bytes,uint64[],(uint32,uint64,uint64,bool,uint256))": { + "notice": "Remove a validator from the SSV Cluster. Make sure `exitSsvValidator` is called before and the validate has exited the Beacon chain. If removed before the validator has exited the beacon chain will result in the validator being slashed. Only the registrator can call this function." + }, + "rewardTokenAddresses(uint256)": { + "notice": "Address of the reward tokens. eg CRV, BAL, CVX, AURA" + }, + "safeApproveAllTokens()": { + "notice": "Approves the SSV Network contract to transfer SSV tokens for deposits" + }, + "setFuseInterval(uint256,uint256)": { + "notice": "set fuse interval values" + }, + "setHarvesterAddress(address)": { + "notice": "Set the Harvester contract that can collect rewards." + }, + "setPTokenAddress(address,address)": { + "notice": "Provide support for asset by passing its pToken address. This method can only be called by the system Governor" + }, + "setRegistrator(address)": { + "notice": "Set the address of the registrator which can register, exit and remove validators" + }, + "setRewardTokenAddresses(address[])": { + "notice": "Set the reward token addresses. Any old addresses will be overwritten." + }, + "stakeEth((bytes,bytes,bytes32)[])": { + "notice": "Stakes WETH to the node validators" + }, + "supportsAsset(address)": { + "notice": "Returns bool indicating whether asset is supported by strategy." + }, + "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 strategy contracts, i.e. mistaken sends." + }, + "validatorRegistrator()": { + "notice": "Address of the registrator - allowed to register, exit and remove validators" + }, + "validatorsStates(bytes32)": { + "notice": "State of the validators keccak256(pubKey) => state" + }, + "vaultAddress()": { + "notice": "Address of the OToken vault" + }, + "withdraw(address,address,uint256)": { + "notice": "Withdraw WETH from this contract. Used only if some WETH for is lingering on the contract. That can happen when: - the deposit was not a multiple of 32 WETH - someone sent WETH directly to this contract Will NOT revert if the strategy is paused from an accounting failure." + }, + "withdrawAll()": { + "notice": "transfer all WETH deposits back to the vault. This does not withdraw from the validators. That has to be done separately with the `exitSsvValidator` and `removeSsvValidator` operations. This does not withdraw any execution rewards from the FeeAccumulator or consensus rewards in this strategy. Any ETH in this strategy that was swept from a full validator withdrawal will not be withdrawn. ETH from full validator withdrawals is sent to the Vault using `doAccounting`. Will NOT revert if the strategy is paused from an accounting failure." + } + }, + "notice": "Strategy to deploy funds into DVT validators powered by the SSV Network", + "version": 1 + }, + "storageLayout": { + "storage": [ + { + "astId": 5232, + "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", + "label": "initialized", + "offset": 0, + "slot": "0", + "type": "t_bool" + }, + { + "astId": 5235, + "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", + "label": "initializing", + "offset": 1, + "slot": "0", + "type": "t_bool" + }, + { + "astId": 5275, + "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", + "label": "______gap", + "offset": 0, + "slot": "1", + "type": "t_array(t_uint256)50_storage" + }, + { + "astId": 17, + "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", + "label": "_paused", + "offset": 0, + "slot": "51", + "type": "t_bool" + }, + { + "astId": 3497, + "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", + "label": "validatorRegistrator", + "offset": 1, + "slot": "51", + "type": "t_address" + }, + { + "astId": 3500, + "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", + "label": "activeDepositedValidators", + "offset": 0, + "slot": "52", + "type": "t_uint256" + }, + { + "astId": 3506, + "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", + "label": "validatorsStates", + "offset": 0, + "slot": "53", + "type": "t_mapping(t_bytes32,t_enum(VALIDATOR_STATE)3515)" + }, + { + "astId": 3510, + "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", + "label": "__gap", + "offset": 0, + "slot": "54", + "type": "t_array(t_uint256)50_storage" + }, + { + "astId": 3042, + "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", + "label": "consensusRewards", + "offset": 0, + "slot": "104", + "type": "t_uint256" + }, + { + "astId": 3046, + "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", + "label": "fuseIntervalStart", + "offset": 0, + "slot": "105", + "type": "t_uint256" + }, + { + "astId": 3050, + "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", + "label": "fuseIntervalEnd", + "offset": 0, + "slot": "106", + "type": "t_uint256" + }, + { + "astId": 3053, + "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", + "label": "accountingGovernor", + "offset": 0, + "slot": "107", + "type": "t_address" + }, + { + "astId": 3057, + "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", + "label": "__gap", + "offset": 0, + "slot": "108", + "type": "t_array(t_uint256)50_storage" + }, + { + "astId": 5355, + "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", + "label": "_deprecated_platformAddress", + "offset": 0, + "slot": "158", + "type": "t_address" + }, + { + "astId": 5358, + "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", + "label": "_deprecated_vaultAddress", + "offset": 0, + "slot": "159", + "type": "t_address" + }, + { + "astId": 5363, + "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", + "label": "assetToPToken", + "offset": 0, + "slot": "160", + "type": "t_mapping(t_address,t_address)" + }, + { + "astId": 5367, + "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", + "label": "assetsMapped", + "offset": 0, + "slot": "161", + "type": "t_array(t_address)dyn_storage" + }, + { + "astId": 5369, + "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", + "label": "_deprecated_rewardTokenAddress", + "offset": 0, + "slot": "162", + "type": "t_address" + }, + { + "astId": 5371, + "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", + "label": "_deprecated_rewardLiquidationThreshold", + "offset": 0, + "slot": "163", + "type": "t_uint256" + }, + { + "astId": 5374, + "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", + "label": "harvesterAddress", + "offset": 0, + "slot": "164", + "type": "t_address" + }, + { + "astId": 5378, + "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", + "label": "rewardTokenAddresses", + "offset": 0, + "slot": "165", + "type": "t_array(t_address)dyn_storage" + }, + { + "astId": 5382, + "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", + "label": "_reserved", + "offset": 0, + "slot": "166", + "type": "t_array(t_int256)98_storage" + }, + { + "astId": 2613, + "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", + "label": "__gap", + "offset": 0, + "slot": "264", + "type": "t_array(t_uint256)50_storage" + } + ], + "types": { + "t_address": { + "encoding": "inplace", + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_address)dyn_storage": { + "base": "t_address", + "encoding": "dynamic_array", + "label": "address[]", + "numberOfBytes": "32" + }, + "t_array(t_int256)98_storage": { + "base": "t_int256", + "encoding": "inplace", + "label": "int256[98]", + "numberOfBytes": "3136" + }, + "t_array(t_uint256)50_storage": { + "base": "t_uint256", + "encoding": "inplace", + "label": "uint256[50]", + "numberOfBytes": "1600" + }, + "t_bool": { + "encoding": "inplace", + "label": "bool", + "numberOfBytes": "1" + }, + "t_bytes32": { + "encoding": "inplace", + "label": "bytes32", + "numberOfBytes": "32" + }, + "t_enum(VALIDATOR_STATE)3515": { + "encoding": "inplace", + "label": "enum ValidatorRegistrator.VALIDATOR_STATE", + "numberOfBytes": "1" + }, + "t_int256": { + "encoding": "inplace", + "label": "int256", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_address)": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => address)", + "numberOfBytes": "32", + "value": "t_address" + }, + "t_mapping(t_bytes32,t_enum(VALIDATOR_STATE)3515)": { + "encoding": "mapping", + "key": "t_bytes32", + "label": "mapping(bytes32 => enum ValidatorRegistrator.VALIDATOR_STATE)", + "numberOfBytes": "32", + "value": "t_enum(VALIDATOR_STATE)3515" + }, + "t_uint256": { + "encoding": "inplace", + "label": "uint256", + "numberOfBytes": "32" + } + } + } +} \ No newline at end of file diff --git a/contracts/deployments/holesky/NativeStakingSSVStrategyProxy.json b/contracts/deployments/holesky/NativeStakingSSVStrategyProxy.json new file mode 100644 index 0000000000..e6e3625aba --- /dev/null +++ b/contracts/deployments/holesky/NativeStakingSSVStrategyProxy.json @@ -0,0 +1,289 @@ +{ + "address": "0x4Eac8847c7AE50e3A3551B1Aa4FF7Cc162151410", + "abi": [ + { + "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": true, + "internalType": "address", + "name": "previousGovernor", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newGovernor", + "type": "address" + } + ], + "name": "PendingGovernorshipTransfer", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "implementation", + "type": "address" + } + ], + "name": "Upgraded", + "type": "event" + }, + { + "stateMutability": "payable", + "type": "fallback" + }, + { + "inputs": [], + "name": "admin", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "claimGovernance", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "governor", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "implementation", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_logic", + "type": "address" + }, + { + "internalType": "address", + "name": "_initGovernor", + "type": "address" + }, + { + "internalType": "bytes", + "name": "_data", + "type": "bytes" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [], + "name": "isGovernor", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_newGovernor", + "type": "address" + } + ], + "name": "transferGovernance", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newImplementation", + "type": "address" + } + ], + "name": "upgradeTo", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newImplementation", + "type": "address" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "upgradeToAndCall", + "outputs": [], + "stateMutability": "payable", + "type": "function" + } + ], + "transactionHash": "0x8f9577961a6ba3cd743d72c27db2c8f2472a6c26a58fc73150fc25a4cd371ad5", + "receipt": { + "to": null, + "from": "0x1b94CA50D3Ad9f8368851F8526132272d1a5028C", + "contractAddress": "0x4Eac8847c7AE50e3A3551B1Aa4FF7Cc162151410", + "transactionIndex": 46, + "gasUsed": "580428", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000020000000004000000000800000000000000000000000000080000000004000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000010000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0xc04b8dec47c654e4489a465ba27058787f5aeb4496c2d3026f3ca88b9f690e3e", + "transactionHash": "0x8f9577961a6ba3cd743d72c27db2c8f2472a6c26a58fc73150fc25a4cd371ad5", + "logs": [ + { + "transactionIndex": 46, + "blockNumber": 1405102, + "transactionHash": "0x8f9577961a6ba3cd743d72c27db2c8f2472a6c26a58fc73150fc25a4cd371ad5", + "address": "0x4Eac8847c7AE50e3A3551B1Aa4FF7Cc162151410", + "topics": [ + "0xc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000001b94ca50d3ad9f8368851f8526132272d1a5028c" + ], + "data": "0x", + "logIndex": 56, + "blockHash": "0xc04b8dec47c654e4489a465ba27058787f5aeb4496c2d3026f3ca88b9f690e3e" + } + ], + "blockNumber": 1405102, + "cumulativeGasUsed": "6315195", + "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\":true,\"internalType\":\"address\",\"name\":\"previousGovernor\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newGovernor\",\"type\":\"address\"}],\"name\":\"GovernorshipTransferred\",\"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\":true,\"internalType\":\"address\",\"name\":\"implementation\",\"type\":\"address\"}],\"name\":\"Upgraded\",\"type\":\"event\"},{\"stateMutability\":\"payable\",\"type\":\"fallback\"},{\"inputs\":[],\"name\":\"admin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"claimGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"governor\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"implementation\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_logic\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_initGovernor\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isGovernor\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_newGovernor\",\"type\":\"address\"}],\"name\":\"transferGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newImplementation\",\"type\":\"address\"}],\"name\":\"upgradeTo\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newImplementation\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"upgradeToAndCall\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"admin()\":{\"returns\":{\"_0\":\"The address of the proxy admin/it's also the governor.\"}},\"implementation()\":{\"returns\":{\"_0\":\"The address of the implementation.\"}},\"initialize(address,address,bytes)\":{\"details\":\"Contract initializer with Governor enforcement\",\"params\":{\"_data\":\"Data to send as msg.data to the implementation to initialize the proxied contract. It should include the signature and the parameters of the function to be called, as described in https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding. This parameter is optional, if no data is given the initialization call to proxied contract will be skipped.\",\"_initGovernor\":\"Address of the initial Governor.\",\"_logic\":\"Address of the initial implementation.\"}},\"transferGovernance(address)\":{\"params\":{\"_newGovernor\":\"Address of the new Governor\"}},\"upgradeTo(address)\":{\"details\":\"Upgrade the backing implementation of the proxy. Only the admin can call this function.\",\"params\":{\"newImplementation\":\"Address of the new implementation.\"}},\"upgradeToAndCall(address,bytes)\":{\"details\":\"Upgrade the backing implementation of the proxy and call a function on the new implementation. This is useful to initialize the proxied contract.\",\"params\":{\"data\":\"Data to send as msg.data in the low level call. It should include the signature and the parameters of the function to be called, as described in https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.\",\"newImplementation\":\"Address of the new implementation.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"claimGovernance()\":{\"notice\":\"Claim Governance of the contract to a new account (`newGovernor`). Can only be called by the new Governor.\"},\"governor()\":{\"notice\":\"Returns the address of the current Governor.\"},\"isGovernor()\":{\"notice\":\"Returns true if the caller is the current Governor.\"},\"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\"}},\"notice\":\"NativeStakingSSVStrategyProxy delegates calls to NativeStakingSSVStrategy implementation\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/proxies/Proxies.sol\":\"NativeStakingSSVStrategyProxy\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@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\"},\"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/proxies/InitializeGovernedUpgradeabilityProxy.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport { Address } from \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\n\\nimport { Governable } from \\\"../governance/Governable.sol\\\";\\n\\n/**\\n * @title BaseGovernedUpgradeabilityProxy\\n * @dev This contract combines an upgradeability proxy with our governor system.\\n * It is based on an older version of OpenZeppelins BaseUpgradeabilityProxy\\n * with Solidity ^0.8.0.\\n * @author Origin Protocol Inc\\n */\\ncontract InitializeGovernedUpgradeabilityProxy is Governable {\\n /**\\n * @dev Emitted when the implementation is upgraded.\\n * @param implementation Address of the new implementation.\\n */\\n event Upgraded(address indexed implementation);\\n\\n /**\\n * @dev Contract initializer with Governor enforcement\\n * @param _logic Address of the initial implementation.\\n * @param _initGovernor Address of the initial Governor.\\n * @param _data Data to send as msg.data to the implementation to initialize\\n * the proxied contract.\\n * It should include the signature and the parameters of the function to be\\n * called, as described in\\n * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.\\n * This parameter is optional, if no data is given the initialization call\\n * to proxied contract will be skipped.\\n */\\n function initialize(\\n address _logic,\\n address _initGovernor,\\n bytes calldata _data\\n ) public payable onlyGovernor {\\n require(_implementation() == address(0));\\n assert(\\n IMPLEMENTATION_SLOT ==\\n bytes32(uint256(keccak256(\\\"eip1967.proxy.implementation\\\")) - 1)\\n );\\n _setImplementation(_logic);\\n if (_data.length > 0) {\\n (bool success, ) = _logic.delegatecall(_data);\\n require(success);\\n }\\n _changeGovernor(_initGovernor);\\n }\\n\\n /**\\n * @return The address of the proxy admin/it's also the governor.\\n */\\n function admin() external view returns (address) {\\n return _governor();\\n }\\n\\n /**\\n * @return The address of the implementation.\\n */\\n function implementation() external view returns (address) {\\n return _implementation();\\n }\\n\\n /**\\n * @dev Upgrade the backing implementation of the proxy.\\n * Only the admin can call this function.\\n * @param newImplementation Address of the new implementation.\\n */\\n function upgradeTo(address newImplementation) external onlyGovernor {\\n _upgradeTo(newImplementation);\\n }\\n\\n /**\\n * @dev Upgrade the backing implementation of the proxy and call a function\\n * on the new implementation.\\n * This is useful to initialize the proxied contract.\\n * @param newImplementation Address of the new implementation.\\n * @param data Data to send as msg.data in the low level call.\\n * It should include the signature and the parameters of the function to be called, as described in\\n * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.\\n */\\n function upgradeToAndCall(address newImplementation, bytes calldata data)\\n external\\n payable\\n onlyGovernor\\n {\\n _upgradeTo(newImplementation);\\n (bool success, ) = newImplementation.delegatecall(data);\\n require(success);\\n }\\n\\n /**\\n * @dev Fallback function.\\n * Implemented entirely in `_fallback`.\\n */\\n fallback() external payable {\\n _fallback();\\n }\\n\\n /**\\n * @dev Delegates execution to an implementation contract.\\n * This is a low level function that doesn't return to its internal call site.\\n * It will return to the external caller whatever the implementation returns.\\n * @param _impl Address to delegate.\\n */\\n function _delegate(address _impl) internal {\\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(gas(), _impl, 0, calldatasize(), 0, 0)\\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 /**\\n * @dev Function that is run as the first thing in the fallback function.\\n * Can be redefined in derived contracts to add functionality.\\n * Redefinitions must call super._willFallback().\\n */\\n function _willFallback() internal {}\\n\\n /**\\n * @dev fallback implementation.\\n * Extracted to enable manual triggering.\\n */\\n function _fallback() internal {\\n _willFallback();\\n _delegate(_implementation());\\n }\\n\\n /**\\n * @dev Storage slot with the address of the current implementation.\\n * This is the keccak-256 hash of \\\"eip1967.proxy.implementation\\\" subtracted by 1, and is\\n * validated in the constructor.\\n */\\n bytes32 internal constant IMPLEMENTATION_SLOT =\\n 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\\n\\n /**\\n * @dev Returns the current implementation.\\n * @return impl Address of the current implementation\\n */\\n function _implementation() internal view returns (address impl) {\\n bytes32 slot = IMPLEMENTATION_SLOT;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n impl := sload(slot)\\n }\\n }\\n\\n /**\\n * @dev Upgrades the proxy to a new implementation.\\n * @param newImplementation Address of the new implementation.\\n */\\n function _upgradeTo(address newImplementation) internal {\\n _setImplementation(newImplementation);\\n emit Upgraded(newImplementation);\\n }\\n\\n /**\\n * @dev Sets the implementation address of the proxy.\\n * @param newImplementation Address of the new implementation.\\n */\\n function _setImplementation(address newImplementation) internal {\\n require(\\n Address.isContract(newImplementation),\\n \\\"Cannot set a proxy implementation to a non-contract address\\\"\\n );\\n\\n bytes32 slot = IMPLEMENTATION_SLOT;\\n\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n sstore(slot, newImplementation)\\n }\\n }\\n}\\n\",\"keccak256\":\"0xcf9bc33957fa41a745726edb6461a4bddca875a038c848286a059f0f22b7f184\",\"license\":\"MIT\"},\"contracts/proxies/Proxies.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport { InitializeGovernedUpgradeabilityProxy } from \\\"./InitializeGovernedUpgradeabilityProxy.sol\\\";\\n\\n/**\\n * @notice OUSDProxy delegates calls to an OUSD implementation\\n */\\ncontract OUSDProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice WrappedOUSDProxy delegates calls to a WrappedOUSD implementation\\n */\\ncontract WrappedOUSDProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice VaultProxy delegates calls to a Vault implementation\\n */\\ncontract VaultProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice CompoundStrategyProxy delegates calls to a CompoundStrategy implementation\\n */\\ncontract CompoundStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice AaveStrategyProxy delegates calls to a AaveStrategy implementation\\n */\\ncontract AaveStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice ThreePoolStrategyProxy delegates calls to a ThreePoolStrategy implementation\\n */\\ncontract ThreePoolStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice ConvexStrategyProxy delegates calls to a ConvexStrategy implementation\\n */\\ncontract ConvexStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice HarvesterProxy delegates calls to a Harvester implementation\\n */\\ncontract HarvesterProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice DripperProxy delegates calls to a Dripper implementation\\n */\\ncontract DripperProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice MorphoCompoundStrategyProxy delegates calls to a MorphoCompoundStrategy implementation\\n */\\ncontract MorphoCompoundStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice ConvexOUSDMetaStrategyProxy delegates calls to a ConvexOUSDMetaStrategy implementation\\n */\\ncontract ConvexOUSDMetaStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice ConvexLUSDMetaStrategyProxy delegates calls to a ConvexalGeneralizedMetaStrategy implementation\\n */\\ncontract ConvexLUSDMetaStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice MorphoAaveStrategyProxy delegates calls to a MorphoCompoundStrategy implementation\\n */\\ncontract MorphoAaveStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice OETHProxy delegates calls to nowhere for now\\n */\\ncontract OETHProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice WOETHProxy delegates calls to nowhere for now\\n */\\ncontract WOETHProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice OETHVaultProxy delegates calls to a Vault implementation\\n */\\ncontract OETHVaultProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice OETHDripperProxy delegates calls to a OETHDripper implementation\\n */\\ncontract OETHDripperProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice OETHHarvesterProxy delegates calls to a Harvester implementation\\n */\\ncontract OETHHarvesterProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice FraxETHStrategyProxy delegates calls to a FraxETHStrategy implementation\\n */\\ncontract FraxETHStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice CurveEthStrategyProxy delegates calls to a CurveEthStrategy implementation\\n */\\ncontract ConvexEthMetaStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice BuybackProxy delegates calls to Buyback implementation\\n */\\ncontract BuybackProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice OETHMorphoAaveStrategyProxy delegates calls to a MorphoAaveStrategy implementation\\n */\\ncontract OETHMorphoAaveStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice OETHBalancerMetaPoolrEthStrategyProxy delegates calls to a BalancerMetaPoolStrategy implementation\\n */\\ncontract OETHBalancerMetaPoolrEthStrategyProxy is\\n InitializeGovernedUpgradeabilityProxy\\n{\\n\\n}\\n\\n/**\\n * @notice OETHBalancerMetaPoolwstEthStrategyProxy delegates calls to a BalancerMetaPoolStrategy implementation\\n */\\ncontract OETHBalancerMetaPoolwstEthStrategyProxy is\\n InitializeGovernedUpgradeabilityProxy\\n{\\n\\n}\\n\\n/**\\n * @notice FluxStrategyProxy delegates calls to a CompoundStrategy implementation\\n */\\ncontract FluxStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice MakerDsrStrategyProxy delegates calls to a Generalized4626Strategy implementation\\n */\\ncontract MakerDsrStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice FrxEthRedeemStrategyProxy delegates calls to a FrxEthRedeemStrategy implementation\\n */\\ncontract FrxEthRedeemStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice OETHBuybackProxy delegates calls to Buyback implementation\\n */\\ncontract OETHBuybackProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice BridgedWOETHProxy delegates calls to BridgedWOETH implementation\\n */\\ncontract BridgedWOETHProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice NativeStakingSSVStrategyProxy delegates calls to NativeStakingSSVStrategy implementation\\n */\\ncontract NativeStakingSSVStrategyProxy is\\n InitializeGovernedUpgradeabilityProxy\\n{\\n\\n}\\n\\n/**\\n * @notice NativeStakingFeeAccumulatorProxy delegates calls to NativeStakingFeeCollector implementation\\n */\\ncontract NativeStakingFeeAccumulatorProxy is\\n InitializeGovernedUpgradeabilityProxy\\n{\\n\\n}\\n\",\"keccak256\":\"0x2e294507edd91494e1020a2a1c43502d2f5cba01266c228406562ecde7a2d872\",\"license\":\"MIT\"}},\"version\":1}", + "bytecode": "0x608060405234801561001057600080fd5b506100273360008051602061099083398151915255565b600080516020610990833981519152546040516001600160a01b03909116906000907fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a908290a36109138061007d6000396000f3fe6080604052600436106100865760003560e01c80635d36b190116100595780635d36b1901461010a578063c7af33521461011f578063cf7a1d7714610144578063d38bfff414610157578063f851a4401461009057610086565b80630c340a24146100905780633659cfe6146100c25780634f1ef286146100e25780635c60da1b146100f5575b61008e610177565b005b34801561009c57600080fd5b506100a5610197565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156100ce57600080fd5b5061008e6100dd366004610745565b6101b4565b61008e6100f03660046107c8565b6101ed565b34801561010157600080fd5b506100a561028a565b34801561011657600080fd5b5061008e6102a2565b34801561012b57600080fd5b50610134610346565b60405190151581526020016100b9565b61008e610152366004610767565b610377565b34801561016357600080fd5b5061008e610172366004610745565b610491565b61019561019060008051602061089e8339815191525490565b610535565b565b60006101af6000805160206108be8339815191525490565b905090565b6101bc610346565b6101e15760405162461bcd60e51b81526004016101d89061082b565b60405180910390fd5b6101ea81610559565b50565b6101f5610346565b6102115760405162461bcd60e51b81526004016101d89061082b565b61021a83610559565b6000836001600160a01b0316838360405161023692919061081b565b600060405180830381855af49150503d8060008114610271576040519150601f19603f3d011682016040523d82523d6000602084013e610276565b606091505b505090508061028457600080fd5b50505050565b60006101af60008051602061089e8339815191525490565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b03161461033d5760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b60648201526084016101d8565b61019533610599565b600061035e6000805160206108be8339815191525490565b6001600160a01b0316336001600160a01b031614905090565b61037f610346565b61039b5760405162461bcd60e51b81526004016101d89061082b565b60006103b360008051602061089e8339815191525490565b6001600160a01b0316146103c657600080fd5b6103f160017f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbd610862565b60008051602061089e8339815191521461040d5761040d610887565b6104168461065a565b8015610488576000846001600160a01b0316838360405161043892919061081b565b600060405180830381855af49150503d8060008114610473576040519150601f19603f3d011682016040523d82523d6000602084013e610478565b606091505b505090508061048657600080fd5b505b61028483610599565b610499610346565b6104b55760405162461bcd60e51b81526004016101d89061082b565b6104dd817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b03166104fd6000805160206108be8339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b3660008037600080366000845af43d6000803e808015610554573d6000f35b3d6000fd5b6105628161065a565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b6001600160a01b0381166105ef5760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f72206973206164647265737328302900000000000060448201526064016101d8565b806001600160a01b031661060f6000805160206108be8339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a36101ea816000805160206108be83398151915255565b803b6106ce5760405162461bcd60e51b815260206004820152603b60248201527f43616e6e6f742073657420612070726f787920696d706c656d656e746174696f60448201527f6e20746f2061206e6f6e2d636f6e74726163742061646472657373000000000060648201526084016101d8565b60008051602061089e83398151915255565b80356001600160a01b03811681146106f757600080fd5b919050565b60008083601f84011261070e57600080fd5b50813567ffffffffffffffff81111561072657600080fd5b60208301915083602082850101111561073e57600080fd5b9250929050565b60006020828403121561075757600080fd5b610760826106e0565b9392505050565b6000806000806060858703121561077d57600080fd5b610786856106e0565b9350610794602086016106e0565b9250604085013567ffffffffffffffff8111156107b057600080fd5b6107bc878288016106fc565b95989497509550505050565b6000806000604084860312156107dd57600080fd5b6107e6846106e0565b9250602084013567ffffffffffffffff81111561080257600080fd5b61080e868287016106fc565b9497909650939450505050565b8183823760009101908152919050565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b60008282101561088257634e487b7160e01b600052601160045260246000fd5b500390565b634e487b7160e01b600052600160045260246000fdfe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa26469706673582212203019a79a43f7d4ec89620197adcc99852be5f4965adfb8a6bbb0ad3954812e2c64736f6c634300080700337bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a", + "deployedBytecode": "0x6080604052600436106100865760003560e01c80635d36b190116100595780635d36b1901461010a578063c7af33521461011f578063cf7a1d7714610144578063d38bfff414610157578063f851a4401461009057610086565b80630c340a24146100905780633659cfe6146100c25780634f1ef286146100e25780635c60da1b146100f5575b61008e610177565b005b34801561009c57600080fd5b506100a5610197565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156100ce57600080fd5b5061008e6100dd366004610745565b6101b4565b61008e6100f03660046107c8565b6101ed565b34801561010157600080fd5b506100a561028a565b34801561011657600080fd5b5061008e6102a2565b34801561012b57600080fd5b50610134610346565b60405190151581526020016100b9565b61008e610152366004610767565b610377565b34801561016357600080fd5b5061008e610172366004610745565b610491565b61019561019060008051602061089e8339815191525490565b610535565b565b60006101af6000805160206108be8339815191525490565b905090565b6101bc610346565b6101e15760405162461bcd60e51b81526004016101d89061082b565b60405180910390fd5b6101ea81610559565b50565b6101f5610346565b6102115760405162461bcd60e51b81526004016101d89061082b565b61021a83610559565b6000836001600160a01b0316838360405161023692919061081b565b600060405180830381855af49150503d8060008114610271576040519150601f19603f3d011682016040523d82523d6000602084013e610276565b606091505b505090508061028457600080fd5b50505050565b60006101af60008051602061089e8339815191525490565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b03161461033d5760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b60648201526084016101d8565b61019533610599565b600061035e6000805160206108be8339815191525490565b6001600160a01b0316336001600160a01b031614905090565b61037f610346565b61039b5760405162461bcd60e51b81526004016101d89061082b565b60006103b360008051602061089e8339815191525490565b6001600160a01b0316146103c657600080fd5b6103f160017f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbd610862565b60008051602061089e8339815191521461040d5761040d610887565b6104168461065a565b8015610488576000846001600160a01b0316838360405161043892919061081b565b600060405180830381855af49150503d8060008114610473576040519150601f19603f3d011682016040523d82523d6000602084013e610478565b606091505b505090508061048657600080fd5b505b61028483610599565b610499610346565b6104b55760405162461bcd60e51b81526004016101d89061082b565b6104dd817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b03166104fd6000805160206108be8339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b3660008037600080366000845af43d6000803e808015610554573d6000f35b3d6000fd5b6105628161065a565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b6001600160a01b0381166105ef5760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f72206973206164647265737328302900000000000060448201526064016101d8565b806001600160a01b031661060f6000805160206108be8339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a36101ea816000805160206108be83398151915255565b803b6106ce5760405162461bcd60e51b815260206004820152603b60248201527f43616e6e6f742073657420612070726f787920696d706c656d656e746174696f60448201527f6e20746f2061206e6f6e2d636f6e74726163742061646472657373000000000060648201526084016101d8565b60008051602061089e83398151915255565b80356001600160a01b03811681146106f757600080fd5b919050565b60008083601f84011261070e57600080fd5b50813567ffffffffffffffff81111561072657600080fd5b60208301915083602082850101111561073e57600080fd5b9250929050565b60006020828403121561075757600080fd5b610760826106e0565b9392505050565b6000806000806060858703121561077d57600080fd5b610786856106e0565b9350610794602086016106e0565b9250604085013567ffffffffffffffff8111156107b057600080fd5b6107bc878288016106fc565b95989497509550505050565b6000806000604084860312156107dd57600080fd5b6107e6846106e0565b9250602084013567ffffffffffffffff81111561080257600080fd5b61080e868287016106fc565b9497909650939450505050565b8183823760009101908152919050565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b60008282101561088257634e487b7160e01b600052601160045260246000fd5b500390565b634e487b7160e01b600052600160045260246000fdfe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa26469706673582212203019a79a43f7d4ec89620197adcc99852be5f4965adfb8a6bbb0ad3954812e2c64736f6c63430008070033", + "libraries": {}, + "devdoc": { + "kind": "dev", + "methods": { + "admin()": { + "returns": { + "_0": "The address of the proxy admin/it's also the governor." + } + }, + "implementation()": { + "returns": { + "_0": "The address of the implementation." + } + }, + "initialize(address,address,bytes)": { + "details": "Contract initializer with Governor enforcement", + "params": { + "_data": "Data to send as msg.data to the implementation to initialize the proxied contract. It should include the signature and the parameters of the function to be called, as described in https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding. This parameter is optional, if no data is given the initialization call to proxied contract will be skipped.", + "_initGovernor": "Address of the initial Governor.", + "_logic": "Address of the initial implementation." + } + }, + "transferGovernance(address)": { + "params": { + "_newGovernor": "Address of the new Governor" + } + }, + "upgradeTo(address)": { + "details": "Upgrade the backing implementation of the proxy. Only the admin can call this function.", + "params": { + "newImplementation": "Address of the new implementation." + } + }, + "upgradeToAndCall(address,bytes)": { + "details": "Upgrade the backing implementation of the proxy and call a function on the new implementation. This is useful to initialize the proxied contract.", + "params": { + "data": "Data to send as msg.data in the low level call. It should include the signature and the parameters of the function to be called, as described in https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.", + "newImplementation": "Address of the new implementation." + } + } + }, + "version": 1 + }, + "userdoc": { + "kind": "user", + "methods": { + "claimGovernance()": { + "notice": "Claim Governance of the contract to a new account (`newGovernor`). Can only be called by the new Governor." + }, + "governor()": { + "notice": "Returns the address of the current Governor." + }, + "isGovernor()": { + "notice": "Returns true if the caller is the current Governor." + }, + "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" + } + }, + "notice": "NativeStakingSSVStrategyProxy delegates calls to NativeStakingSSVStrategy implementation", + "version": 1 + }, + "storageLayout": { + "storage": [], + "types": null + } +} \ No newline at end of file diff --git a/contracts/deployments/holesky/OETH.json b/contracts/deployments/holesky/OETH.json new file mode 100644 index 0000000000..c1eaf1b2ac --- /dev/null +++ b/contracts/deployments/holesky/OETH.json @@ -0,0 +1,1126 @@ +{ + "address": "0x7909c19E355E95043e277e76Dd6680fE899F61D6", + "abi": [ + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "AccountRebasingDisabled", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "AccountRebasingEnabled", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousGovernor", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newGovernor", + "type": "address" + } + ], + "name": "GovernorshipTransferred", + "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": "uint256", + "name": "totalSupply", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "rebasingCredits", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "rebasingCreditsPerToken", + "type": "uint256" + } + ], + "name": "TotalSupplyUpdatedHighres", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "inputs": [], + "name": "_totalSupply", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_owner", + "type": "address" + }, + { + "internalType": "address", + "name": "_spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_value", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_account", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "burn", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newTotalSupply", + "type": "uint256" + } + ], + "name": "changeSupply", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "claimGovernance", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_account", + "type": "address" + } + ], + "name": "creditsBalanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_account", + "type": "address" + } + ], + "name": "creditsBalanceOfHighres", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "decimals", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_subtractedValue", + "type": "uint256" + } + ], + "name": "decreaseAllowance", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_account", + "type": "address" + } + ], + "name": "governanceRebaseOptIn", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "governor", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_addedValue", + "type": "uint256" + } + ], + "name": "increaseAllowance", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "_nameArg", + "type": "string" + }, + { + "internalType": "string", + "name": "_symbolArg", + "type": "string" + }, + { + "internalType": "address", + "name": "_vaultAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_initialCreditsPerToken", + "type": "uint256" + } + ], + "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": "isUpgraded", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_account", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + } + ], + "name": "mint", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "name", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "nonRebasingCreditsPerToken", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "nonRebasingSupply", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "rebaseOptIn", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "rebaseOptOut", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "rebaseState", + "outputs": [ + { + "internalType": "enum OUSD.RebaseOptions", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "rebasingCredits", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "rebasingCreditsHighres", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "rebasingCreditsPerToken", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "rebasingCreditsPerTokenHighres", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "symbol", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_value", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_from", + "type": "address" + }, + { + "internalType": "address", + "name": "_to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_value", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_newGovernor", + "type": "address" + } + ], + "name": "transferGovernance", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "vaultAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + } + ], + "transactionHash": "0xc35a695f1258f6afd032e34f6a9301423a898c65cde8c4ccfef13075ad256792", + "receipt": { + "to": null, + "from": "0x1b94CA50D3Ad9f8368851F8526132272d1a5028C", + "contractAddress": "0x7909c19E355E95043e277e76Dd6680fE899F61D6", + "transactionIndex": 45, + "gasUsed": "1888482", + "logsBloom": "0x00000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000000004000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000010000000000000008000000000000000000000000020000000000000000000000000000000000000000000000000080000000000000000", + "blockHash": "0xbf8d64ab1675835a7af31ef9fbbd105a6b18b0f5fa6990776f77781ed98bd364", + "transactionHash": "0xc35a695f1258f6afd032e34f6a9301423a898c65cde8c4ccfef13075ad256792", + "logs": [ + { + "transactionIndex": 45, + "blockNumber": 1405053, + "transactionHash": "0xc35a695f1258f6afd032e34f6a9301423a898c65cde8c4ccfef13075ad256792", + "address": "0x7909c19E355E95043e277e76Dd6680fE899F61D6", + "topics": [ + "0xc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000001b94ca50d3ad9f8368851f8526132272d1a5028c" + ], + "data": "0x", + "logIndex": 45, + "blockHash": "0xbf8d64ab1675835a7af31ef9fbbd105a6b18b0f5fa6990776f77781ed98bd364" + } + ], + "blockNumber": 1405053, + "cumulativeGasUsed": "7260791", + "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\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AccountRebasingDisabled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AccountRebasingEnabled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousGovernor\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newGovernor\",\"type\":\"address\"}],\"name\":\"GovernorshipTransferred\",\"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\":\"uint256\",\"name\":\"totalSupply\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"rebasingCredits\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"rebasingCreditsPerToken\",\"type\":\"uint256\"}],\"name\":\"TotalSupplyUpdatedHighres\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"_totalSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_spender\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_account\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"burn\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_newTotalSupply\",\"type\":\"uint256\"}],\"name\":\"changeSupply\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"claimGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_account\",\"type\":\"address\"}],\"name\":\"creditsBalanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_account\",\"type\":\"address\"}],\"name\":\"creditsBalanceOfHighres\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"decimals\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_subtractedValue\",\"type\":\"uint256\"}],\"name\":\"decreaseAllowance\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_account\",\"type\":\"address\"}],\"name\":\"governanceRebaseOptIn\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"governor\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_addedValue\",\"type\":\"uint256\"}],\"name\":\"increaseAllowance\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"_nameArg\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"_symbolArg\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"_vaultAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_initialCreditsPerToken\",\"type\":\"uint256\"}],\"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\":\"isUpgraded\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_account\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"mint\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"nonRebasingCreditsPerToken\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"nonRebasingSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rebaseOptIn\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rebaseOptOut\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"rebaseState\",\"outputs\":[{\"internalType\":\"enum OUSD.RebaseOptions\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rebasingCredits\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rebasingCreditsHighres\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rebasingCreditsPerToken\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rebasingCreditsPerTokenHighres\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_newGovernor\",\"type\":\"address\"}],\"name\":\"transferGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"vaultAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"author\":\"Origin Protocol Inc\",\"kind\":\"dev\",\"methods\":{\"allowance(address,address)\":{\"details\":\"Function to check the amount of tokens that _owner has allowed to `_spender`.\",\"params\":{\"_owner\":\"The address which owns the funds.\",\"_spender\":\"The address which will spend the funds.\"},\"returns\":{\"_0\":\"The number of tokens still available for the _spender.\"}},\"approve(address,uint256)\":{\"details\":\"Approve the passed address to spend the specified amount of tokens on behalf of msg.sender. This method is included for ERC20 compatibility. `increaseAllowance` and `decreaseAllowance` should be used instead. Changing an allowance with this method brings the risk that someone may transfer both the old and the new allowance - if they are both greater than zero - if a transfer transaction is mined before the later approve() call is mined.\",\"params\":{\"_spender\":\"The address which will spend the funds.\",\"_value\":\"The amount of tokens to be spent.\"}},\"balanceOf(address)\":{\"details\":\"Gets the balance of the specified address.\",\"params\":{\"_account\":\"Address to query the balance of.\"},\"returns\":{\"_0\":\"A uint256 representing the amount of base units owned by the specified address.\"}},\"burn(address,uint256)\":{\"details\":\"Burns tokens, decreasing totalSupply.\"},\"changeSupply(uint256)\":{\"details\":\"Modify the supply without minting new tokens. This uses a change in the exchange rate between \\\"credits\\\" and OUSD tokens to change balances.\",\"params\":{\"_newTotalSupply\":\"New total supply of OUSD.\"}},\"creditsBalanceOf(address)\":{\"details\":\"Gets the credits balance of the specified address.Backwards compatible with old low res credits per token.\",\"params\":{\"_account\":\"The address to query the balance of.\"},\"returns\":{\"_0\":\"(uint256, uint256) Credit balance and credits per token of the address\"}},\"creditsBalanceOfHighres(address)\":{\"details\":\"Gets the credits balance of the specified address.\",\"params\":{\"_account\":\"The address to query the balance of.\"},\"returns\":{\"_0\":\"(uint256, uint256, bool) Credit balance, credits per token of the address, and isUpgraded\"}},\"decreaseAllowance(address,uint256)\":{\"details\":\"Decrease the amount of tokens that an owner has allowed to `_spender`.\",\"params\":{\"_spender\":\"The address which will spend the funds.\",\"_subtractedValue\":\"The amount of tokens to decrease the allowance by.\"}},\"governanceRebaseOptIn(address)\":{\"details\":\"Add a contract address to the non-rebasing exception list. The address's balance will be part of rebases and the account will be exposed to upside and downside.\",\"params\":{\"_account\":\"Address of the account.\"}},\"increaseAllowance(address,uint256)\":{\"details\":\"Increase the amount of tokens that an owner has allowed to `_spender`. This method should be used instead of approve() to avoid the double approval vulnerability described above.\",\"params\":{\"_addedValue\":\"The amount of tokens to increase the allowance by.\",\"_spender\":\"The address which will spend the funds.\"}},\"mint(address,uint256)\":{\"details\":\"Mints new tokens, increasing totalSupply.\"},\"rebaseOptIn()\":{\"details\":\"Add a contract address to the non-rebasing exception list. The address's balance will be part of rebases and the account will be exposed to upside and downside.\"},\"rebaseOptOut()\":{\"details\":\"Explicitly mark that an address is non-rebasing.\"},\"rebasingCredits()\":{\"returns\":{\"_0\":\"Low resolution total number of rebasing credits\"}},\"rebasingCreditsHighres()\":{\"returns\":{\"_0\":\"High resolution total number of rebasing credits\"}},\"rebasingCreditsPerToken()\":{\"returns\":{\"_0\":\"Low resolution rebasingCreditsPerToken\"}},\"rebasingCreditsPerTokenHighres()\":{\"returns\":{\"_0\":\"High resolution rebasingCreditsPerToken\"}},\"totalSupply()\":{\"returns\":{\"_0\":\"The total supply of OUSD.\"}},\"transfer(address,uint256)\":{\"details\":\"Transfer tokens to a specified address.\",\"params\":{\"_to\":\"the address to transfer to.\",\"_value\":\"the amount to be transferred.\"},\"returns\":{\"_0\":\"true on success.\"}},\"transferFrom(address,address,uint256)\":{\"details\":\"Transfer tokens from one address to another.\",\"params\":{\"_from\":\"The address you want to send tokens from.\",\"_to\":\"The address you want to transfer to.\",\"_value\":\"The amount of tokens to be transferred.\"}},\"transferGovernance(address)\":{\"params\":{\"_newGovernor\":\"Address of the new Governor\"}}},\"title\":\"OETH Token Contract\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"claimGovernance()\":{\"notice\":\"Claim Governance of the contract to a new account (`newGovernor`). Can only be called by the new Governor.\"},\"decimals()\":{\"notice\":\"Returns the number of decimals used to get its user representation. For example, if `decimals` equals `2`, a balance of `505` tokens should be displayed to a user as `5,05` (`505 / 10 ** 2`). Tokens usually opt for a value of 18, imitating the relationship between Ether and Wei. NOTE: This information is only used for _display_ purposes: it in no way affects any of the arithmetic of the contract, including {IERC20-balanceOf} and {IERC20-transfer}.\"},\"governanceRebaseOptIn(address)\":{\"notice\":\"Enable rebasing for an account.\"},\"governor()\":{\"notice\":\"Returns the address of the current Governor.\"},\"isGovernor()\":{\"notice\":\"Returns true if the caller is the current Governor.\"},\"name()\":{\"notice\":\"Returns the name of the token.\"},\"symbol()\":{\"notice\":\"Returns the symbol of the token, usually a shorter version of the name.\"},\"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\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/token/OETH.sol\":\"OETH\"},\"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/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/token/OETH.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport { OUSD } from \\\"./OUSD.sol\\\";\\n\\n/**\\n * @title OETH Token Contract\\n * @author Origin Protocol Inc\\n */\\ncontract OETH is OUSD {\\n\\n}\\n\",\"keccak256\":\"0x1046a590097f1cddcc1523b4d646fbe2db7c646e40fc504a6947202e44dada4a\",\"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/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\"}},\"version\":1}", + "bytecode": "0x6080604052609c80546001600160a01b031916905534801561002057600080fd5b506100373360008051602061213d83398151915255565b60008051602061213d833981519152546040516001600160a01b03909116906000907fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a908290a36120b08061008d6000396000f3fe608060405234801561001057600080fd5b50600436106102065760003560e01c80637a46a9c51161011a578063c2376dff116100ad578063e5c4fffe1161007c578063e5c4fffe1461045c578063e696393a1461048c578063f51b0fd414610495578063f542033f1461049d578063f9854bfc146104b057600080fd5b8063c2376dff14610400578063c7af335214610408578063d38bfff414610410578063dd62ed3e1461042357600080fd5b80639dc29fac116100e95780639dc29fac146103b4578063a457c2d7146103c7578063a9059cbb146103da578063baa9c9db146103ed57600080fd5b80637a46a9c51461037c5780637d0d66ff1461038457806395d89b411461038c57806395ef84b91461039457600080fd5b806339a7919f1161019d578063456ee2861161016c578063456ee286146103095780635d36b19014610339578063609350cd146103415780636691cb3d1461036157806370a082311461036957600080fd5b806339a7919f146102c55780633eaaf86b146102da57806340c10f19146102e3578063430bf08a146102f657600080fd5b806318160ddd116101d957806318160ddd1461028257806323b872dd1461028a578063313ce5671461029d57806339509351146102b257600080fd5b806306fdde031461020b578063077f22b714610229578063095ea7b31461023f5780630c340a2414610262575b600080fd5b6102136104d8565b6040516102209190611e58565b60405180910390f35b61023161056a565b604051908152602001610220565b61025261024d366004611d64565b610583565b6040519015158152602001610220565b61026a6105ef565b6040516001600160a01b039091168152602001610220565b609a54610231565b610252610298366004611d28565b610607565b60995460405160ff9091168152602001610220565b6102526102c0366004611d64565b610759565b6102d86102d3366004611e17565b6107de565b005b610231609a5481565b6102d86102f1366004611d64565b6109e7565b609c5461026a906001600160a01b031681565b61032c610317366004611cda565b60a26020526000908152604090205460ff1681565b6040516102209190611e30565b6102d8610a1f565b61023161034f366004611cda565b60a16020526000908152604090205481565b610231610ac5565b610231610377366004611cda565b610ad9565b609f54610231565b609e54610231565b610213610b2f565b6102316103a2366004611cda565b60a36020526000908152604090205481565b6102d86103c2366004611d64565b610b3e565b6102526103d5366004611d64565b610b72565b6102526103e8366004611d64565b610c59565b6102d86103fb366004611cda565b610d3a565b6102d8610d9d565b610252610ec4565b6102d861041e366004611cda565b610ef5565b610231610431366004611cf5565b6001600160a01b039182166000908152609b6020908152604080832093909416825291909152205490565b61046f61046a366004611cda565b610f99565b604080519384526020840192909252151590820152606001610220565b61023160a05481565b6102d8610fe8565b6102d86104ab366004611d8e565b61102e565b6104c36104be366004611cda565b6111a1565b60408051928352602083019190915201610220565b6060609780546104e790611fb3565b80601f016020809104026020016040519081016040528092919081815260200182805461051390611fb3565b80156105605780601f1061053557610100808354040283529160200191610560565b820191906000526020600020905b81548152906001019060200180831161054357829003601f168201915b5050505050905090565b6000633b9aca00609e5461057e9190611f5b565b905090565b336000818152609b602090815260408083206001600160a01b038716808552925280832085905551919290917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925906105de9086815260200190565b60405180910390a350600192915050565b600061057e60008051602061205b8339815191525490565b60006001600160a01b03831661065f5760405162461bcd60e51b81526020600482015260186024820152775472616e7366657220746f207a65726f206164647265737360401b60448201526064015b60405180910390fd5b61066884610ad9565b8211156106b75760405162461bcd60e51b815260206004820152601d60248201527f5472616e736665722067726561746572207468616e2062616c616e63650000006044820152606401610656565b6001600160a01b0384166000908152609b602090815260408083203384529091529020546106e59083611225565b6001600160a01b0385166000908152609b60209081526040808320338452909152902055610714848484611238565b826001600160a01b0316846001600160a01b031660008051602061203b8339815191528460405161074791815260200190565b60405180910390a35060019392505050565b336000908152609b602090815260408083206001600160a01b038616845290915281205461078790836113a5565b336000818152609b602090815260408083206001600160a01b038916808552908352928190208590555193845290927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591016105de565b609c546001600160a01b031633146108085760405162461bcd60e51b815260040161065690611ead565b60008051602061201b8339815191528054600281141561083a5760405162461bcd60e51b815260040161065690611f1b565b600282556000609a54116108905760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420696e637265617365203020737570706c7900000000000000006044820152606401610656565b82609a5414156108e657609a54609e54609f5460408051938452602084019290925282820152517f41645eb819d3011b13f97696a8109d14bfcddfaca7d063ec0564d62a3e2572359181900360600190a16109df565b6001600160801b0383116108fa5782610903565b6001600160801b035b609a81905560a0546109219161091891611225565b609e54906113b1565b609f8190556109725760405162461bcd60e51b815260206004820152601860248201527f496e76616c6964206368616e676520696e20737570706c7900000000000000006044820152606401610656565b61099560a05461098f609f54609e546113b190919063ffffffff16565b906113a5565b609a819055609e54609f5460408051938452602084019290925282820152517f41645eb819d3011b13f97696a8109d14bfcddfaca7d063ec0564d62a3e2572359181900360600190a15b506001905550565b609c546001600160a01b03163314610a115760405162461bcd60e51b815260040161065690611ead565b610a1b82826113da565b5050565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b031614610aba5760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b6064820152608401610656565b610ac33361157b565b565b6000633b9aca00609f5461057e9190611f5b565b6001600160a01b0381166000908152609d6020526040812054610afe57506000919050565b610b29610b0a8361163f565b6001600160a01b0384166000908152609d6020526040902054906113b1565b92915050565b6060609880546104e790611fb3565b609c546001600160a01b03163314610b685760405162461bcd60e51b815260040161065690611ead565b610a1b8282611686565b336000908152609b602090815260408083206001600160a01b0386168452909152812054808310610bc657336000908152609b602090815260408083206001600160a01b0388168452909152812055610bf5565b610bd08184611225565b336000908152609b602090815260408083206001600160a01b03891684529091529020555b336000818152609b602090815260408083206001600160a01b038916808552908352928190205490519081529192917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a35060019392505050565b60006001600160a01b038316610cac5760405162461bcd60e51b81526020600482015260186024820152775472616e7366657220746f207a65726f206164647265737360401b6044820152606401610656565b610cb533610ad9565b821115610d045760405162461bcd60e51b815260206004820152601d60248201527f5472616e736665722067726561746572207468616e2062616c616e63650000006044820152606401610656565b610d0f338484611238565b6040518281526001600160a01b03841690339060008051602061203b833981519152906020016105de565b60008051602061201b83398151915280546002811415610d6c5760405162461bcd60e51b815260040161065690611f1b565b60028255610d78610ec4565b610d945760405162461bcd60e51b815260040161065690611ee4565b6109df8361188f565b60008051602061201b83398151915280546002811415610dcf5760405162461bcd60e51b815260040161065690611f1b565b60028255610ddc336119c7565b15610e295760405162461bcd60e51b815260206004820152601860248201527f4163636f756e7420686173206e6f74206f7074656420696e00000000000000006044820152606401610656565b610e3e610e3533610ad9565b60a054906113a5565b60a055609f5433600090815260a16020908152604080832093909355609d90522054609e54610e6c91611225565b609e5533600081815260a26020908152604091829020805460ff1916600117905590519182527f201ace89ad3f5ab7428b91989f6a50d1998791c7b94a0fa812fd64a57687165e910160405180910390a15060019055565b6000610edc60008051602061205b8339815191525490565b6001600160a01b0316336001600160a01b031614905090565b610efd610ec4565b610f195760405162461bcd60e51b815260040161065690611ee4565b610f41817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b0316610f6160008051602061205b8339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b6001600160a01b0381166000908152609d602052604081205481908190610fbf8561163f565b6001600160a01b0395909516600090815260a36020526040902054909560019091149350915050565b60008051602061201b8339815191528054600281141561101a5760405162461bcd60e51b815260040161065690611f1b565b600282556110273361188f565b5060019055565b611036610ec4565b6110525760405162461bcd60e51b815260040161065690611ee4565b600054610100900460ff168061106b575060005460ff16155b6110ce5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610656565b600054610100900460ff161580156110f0576000805461ffff19166101011790555b61116687878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f8b01819004810282018101909252898152925089915088908190840183828082843760009201919091525060129250611a32915050565b609f829055609c80546001600160a01b0319166001600160a01b0385161790558015611198576000805461ff00191690555b50505050505050565b60008060006111af8461163f565b9050806b033b2e3c9fd0803ce800000014156111e5576001600160a01b039093166000908152609d602052604090205493915050565b6001600160a01b0384166000908152609d602052604090205461120d90633b9aca0090611f5b565b61121b633b9aca0083611f5b565b9250925050915091565b60006112318284611f9c565b9392505050565b6000611243836119c7565b90506000611250856119c7565b905060006112676112608661163f565b8590611a72565b9050600061127e6112778861163f565b8690611a72565b90506112ef816040518060400160405280601f81526020017f5472616e7366657220616d6f756e7420657863656564732062616c616e636500815250609d60008b6001600160a01b03166001600160a01b0316815260200190815260200160002054611a879092919063ffffffff16565b6001600160a01b038089166000908152609d6020526040808220939093559088168152205461131e90836113a5565b6001600160a01b0387166000908152609d6020526040902055838015611342575082155b1561136c5760a05461135490866113a5565b60a055609e546113649082611225565b609e55611198565b831580156113775750825b156111985760a0546113899086611225565b60a055609e5461139990836113a5565b609e5550505050505050565b60006112318284611f43565b6000806113c684670de0b6b3a7640000611ab3565b90506113d28184611abf565b949350505050565b60008051602061201b8339815191528054600281141561140c5760405162461bcd60e51b815260040161065690611f1b565b600282556001600160a01b0384166114665760405162461bcd60e51b815260206004820152601860248201527f4d696e7420746f20746865207a65726f206164647265737300000000000000006044820152606401610656565b6000611471856119c7565b905060006114816112778761163f565b6001600160a01b0387166000908152609d60205260409020549091506114a790826113a5565b6001600160a01b0387166000908152609d602052604090205581156114db5760a0546114d390866113a5565b60a0556114ec565b609e546114e890826113a5565b609e555b609a546114f990866113a5565b609a8190556001600160801b03116115405760405162461bcd60e51b815260206004820152600a6024820152694d617820737570706c7960b01b6044820152606401610656565b6040518581526001600160a01b0387169060009060008051602061203b8339815191529060200160405180910390a350506001825550505050565b6001600160a01b0381166115d15760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f7220697320616464726573732830290000000000006044820152606401610656565b806001600160a01b03166115f160008051602061205b8339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a361163c8160008051602061205b83398151915255565b50565b6001600160a01b038116600090815260a160205260408120541561167957506001600160a01b0316600090815260a1602052604090205490565b5050609f5490565b919050565b60008051602061201b833981519152805460028114156116b85760405162461bcd60e51b815260040161065690611f1b565b600282556001600160a01b0384166117125760405162461bcd60e51b815260206004820152601a60248201527f4275726e2066726f6d20746865207a65726f20616464726573730000000000006044820152606401610656565b8261171c57611886565b6000611727856119c7565b905060006117376112778761163f565b6001600160a01b0387166000908152609d60205260409020549091508082148061176a575081611768600183611f9c565b145b1561178d576001600160a01b0387166000908152609d6020526040812055611817565b818111156117d6576001600160a01b0387166000908152609d60205260409020546117b89083611225565b6001600160a01b0388166000908152609d6020526040902055611817565b60405162461bcd60e51b815260206004820152601660248201527552656d6f766520657863656564732062616c616e636560501b6044820152606401610656565b82156118325760a05461182a9087611225565b60a055611843565b609e5461183f9083611225565b609e555b609a546118509087611225565b609a556040518681526000906001600160a01b0389169060008051602061203b8339815191529060200160405180910390a35050505b50600190555050565b611898816119c7565b6118e45760405162461bcd60e51b815260206004820152601960248201527f4163636f756e7420686173206e6f74206f70746564206f7574000000000000006044820152606401610656565b600061191d6118f28361163f565b609f546001600160a01b0385166000908152609d602052604090205461191791611ab3565b90611abf565b905061193461192b83610ad9565b60a05490611225565b60a0556001600160a01b0382166000908152609d60205260409020819055609e5461195f90826113a5565b609e556001600160a01b038216600081815260a260209081526040808320805460ff1916600217905560a182528083209290925590519182527f19a249fa2050bac8314ac10e3ad420bd9825574bf750f58810c3c7adfc7b1c6f910160405180910390a15050565b6000813b158015908190611a0557506001600160a01b038316600090815260a2602052604081205460ff166002811115611a0357611a03612004565b145b15611a1357611a1383611acb565b50506001600160a01b0316600090815260a16020526040902054151590565b8251611a45906097906020860190611be1565b508151611a59906098906020850190611be1565b506099805460ff191660ff929092169190911790555050565b60006112318383670de0b6b3a7640000611bbf565b60008184841115611aab5760405162461bcd60e51b81526004016106569190611e58565b505050900390565b60006112318284611f7d565b60006112318284611f5b565b6001600160a01b038116600090815260a1602052604090205461163c576040516001600160a01b03821681527f201ace89ad3f5ab7428b91989f6a50d1998791c7b94a0fa812fd64a57687165e9060200160405180910390a16001600160a01b0381166000908152609d6020526040902054611b69576001600160a01b0316600090815260a1602052604090206b033b2e3c9fd0803ce80000009055565b609f546001600160a01b038216600090815260a16020526040902055611b91610e3582610ad9565b60a0556001600160a01b0381166000908152609d6020526040902054609e54611bb991611225565b609e5550565b600080611bcc8585611ab3565b9050611bd88184611abf565b95945050505050565b828054611bed90611fb3565b90600052602060002090601f016020900481019282611c0f5760008555611c55565b82601f10611c2857805160ff1916838001178555611c55565b82800160010185558215611c55579182015b82811115611c55578251825591602001919060010190611c3a565b50611c61929150611c65565b5090565b5b80821115611c615760008155600101611c66565b80356001600160a01b038116811461168157600080fd5b60008083601f840112611ca357600080fd5b50813567ffffffffffffffff811115611cbb57600080fd5b602083019150836020828501011115611cd357600080fd5b9250929050565b600060208284031215611cec57600080fd5b61123182611c7a565b60008060408385031215611d0857600080fd5b611d1183611c7a565b9150611d1f60208401611c7a565b90509250929050565b600080600060608486031215611d3d57600080fd5b611d4684611c7a565b9250611d5460208501611c7a565b9150604084013590509250925092565b60008060408385031215611d7757600080fd5b611d8083611c7a565b946020939093013593505050565b60008060008060008060808789031215611da757600080fd5b863567ffffffffffffffff80821115611dbf57600080fd5b611dcb8a838b01611c91565b90985096506020890135915080821115611de457600080fd5b50611df189828a01611c91565b9095509350611e04905060408801611c7a565b9150606087013590509295509295509295565b600060208284031215611e2957600080fd5b5035919050565b6020810160038310611e5257634e487b7160e01b600052602160045260246000fd5b91905290565b600060208083528351808285015260005b81811015611e8557858101830151858201604001528201611e69565b81811115611e97576000604083870101525b50601f01601f1916929092016040019392505050565b60208082526017908201527f43616c6c6572206973206e6f7420746865205661756c74000000000000000000604082015260600190565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b6020808252600e908201526d1499595b9d1c985b9d0818d85b1b60921b604082015260600190565b60008219821115611f5657611f56611fee565b500190565b600082611f7857634e487b7160e01b600052601260045260246000fd5b500490565b6000816000190483118215151615611f9757611f97611fee565b500290565b600082821015611fae57611fae611fee565b500390565b600181811c90821680611fc757607f821691505b60208210811415611fe857634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fdfe53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac4535ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa2646970667358221220e6ce96a4adc2aa5ece684be58c49f0afc45c508d1faee763208eca986ee5334c64736f6c634300080700337bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a", + "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106102065760003560e01c80637a46a9c51161011a578063c2376dff116100ad578063e5c4fffe1161007c578063e5c4fffe1461045c578063e696393a1461048c578063f51b0fd414610495578063f542033f1461049d578063f9854bfc146104b057600080fd5b8063c2376dff14610400578063c7af335214610408578063d38bfff414610410578063dd62ed3e1461042357600080fd5b80639dc29fac116100e95780639dc29fac146103b4578063a457c2d7146103c7578063a9059cbb146103da578063baa9c9db146103ed57600080fd5b80637a46a9c51461037c5780637d0d66ff1461038457806395d89b411461038c57806395ef84b91461039457600080fd5b806339a7919f1161019d578063456ee2861161016c578063456ee286146103095780635d36b19014610339578063609350cd146103415780636691cb3d1461036157806370a082311461036957600080fd5b806339a7919f146102c55780633eaaf86b146102da57806340c10f19146102e3578063430bf08a146102f657600080fd5b806318160ddd116101d957806318160ddd1461028257806323b872dd1461028a578063313ce5671461029d57806339509351146102b257600080fd5b806306fdde031461020b578063077f22b714610229578063095ea7b31461023f5780630c340a2414610262575b600080fd5b6102136104d8565b6040516102209190611e58565b60405180910390f35b61023161056a565b604051908152602001610220565b61025261024d366004611d64565b610583565b6040519015158152602001610220565b61026a6105ef565b6040516001600160a01b039091168152602001610220565b609a54610231565b610252610298366004611d28565b610607565b60995460405160ff9091168152602001610220565b6102526102c0366004611d64565b610759565b6102d86102d3366004611e17565b6107de565b005b610231609a5481565b6102d86102f1366004611d64565b6109e7565b609c5461026a906001600160a01b031681565b61032c610317366004611cda565b60a26020526000908152604090205460ff1681565b6040516102209190611e30565b6102d8610a1f565b61023161034f366004611cda565b60a16020526000908152604090205481565b610231610ac5565b610231610377366004611cda565b610ad9565b609f54610231565b609e54610231565b610213610b2f565b6102316103a2366004611cda565b60a36020526000908152604090205481565b6102d86103c2366004611d64565b610b3e565b6102526103d5366004611d64565b610b72565b6102526103e8366004611d64565b610c59565b6102d86103fb366004611cda565b610d3a565b6102d8610d9d565b610252610ec4565b6102d861041e366004611cda565b610ef5565b610231610431366004611cf5565b6001600160a01b039182166000908152609b6020908152604080832093909416825291909152205490565b61046f61046a366004611cda565b610f99565b604080519384526020840192909252151590820152606001610220565b61023160a05481565b6102d8610fe8565b6102d86104ab366004611d8e565b61102e565b6104c36104be366004611cda565b6111a1565b60408051928352602083019190915201610220565b6060609780546104e790611fb3565b80601f016020809104026020016040519081016040528092919081815260200182805461051390611fb3565b80156105605780601f1061053557610100808354040283529160200191610560565b820191906000526020600020905b81548152906001019060200180831161054357829003601f168201915b5050505050905090565b6000633b9aca00609e5461057e9190611f5b565b905090565b336000818152609b602090815260408083206001600160a01b038716808552925280832085905551919290917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925906105de9086815260200190565b60405180910390a350600192915050565b600061057e60008051602061205b8339815191525490565b60006001600160a01b03831661065f5760405162461bcd60e51b81526020600482015260186024820152775472616e7366657220746f207a65726f206164647265737360401b60448201526064015b60405180910390fd5b61066884610ad9565b8211156106b75760405162461bcd60e51b815260206004820152601d60248201527f5472616e736665722067726561746572207468616e2062616c616e63650000006044820152606401610656565b6001600160a01b0384166000908152609b602090815260408083203384529091529020546106e59083611225565b6001600160a01b0385166000908152609b60209081526040808320338452909152902055610714848484611238565b826001600160a01b0316846001600160a01b031660008051602061203b8339815191528460405161074791815260200190565b60405180910390a35060019392505050565b336000908152609b602090815260408083206001600160a01b038616845290915281205461078790836113a5565b336000818152609b602090815260408083206001600160a01b038916808552908352928190208590555193845290927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591016105de565b609c546001600160a01b031633146108085760405162461bcd60e51b815260040161065690611ead565b60008051602061201b8339815191528054600281141561083a5760405162461bcd60e51b815260040161065690611f1b565b600282556000609a54116108905760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420696e637265617365203020737570706c7900000000000000006044820152606401610656565b82609a5414156108e657609a54609e54609f5460408051938452602084019290925282820152517f41645eb819d3011b13f97696a8109d14bfcddfaca7d063ec0564d62a3e2572359181900360600190a16109df565b6001600160801b0383116108fa5782610903565b6001600160801b035b609a81905560a0546109219161091891611225565b609e54906113b1565b609f8190556109725760405162461bcd60e51b815260206004820152601860248201527f496e76616c6964206368616e676520696e20737570706c7900000000000000006044820152606401610656565b61099560a05461098f609f54609e546113b190919063ffffffff16565b906113a5565b609a819055609e54609f5460408051938452602084019290925282820152517f41645eb819d3011b13f97696a8109d14bfcddfaca7d063ec0564d62a3e2572359181900360600190a15b506001905550565b609c546001600160a01b03163314610a115760405162461bcd60e51b815260040161065690611ead565b610a1b82826113da565b5050565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b031614610aba5760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b6064820152608401610656565b610ac33361157b565b565b6000633b9aca00609f5461057e9190611f5b565b6001600160a01b0381166000908152609d6020526040812054610afe57506000919050565b610b29610b0a8361163f565b6001600160a01b0384166000908152609d6020526040902054906113b1565b92915050565b6060609880546104e790611fb3565b609c546001600160a01b03163314610b685760405162461bcd60e51b815260040161065690611ead565b610a1b8282611686565b336000908152609b602090815260408083206001600160a01b0386168452909152812054808310610bc657336000908152609b602090815260408083206001600160a01b0388168452909152812055610bf5565b610bd08184611225565b336000908152609b602090815260408083206001600160a01b03891684529091529020555b336000818152609b602090815260408083206001600160a01b038916808552908352928190205490519081529192917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a35060019392505050565b60006001600160a01b038316610cac5760405162461bcd60e51b81526020600482015260186024820152775472616e7366657220746f207a65726f206164647265737360401b6044820152606401610656565b610cb533610ad9565b821115610d045760405162461bcd60e51b815260206004820152601d60248201527f5472616e736665722067726561746572207468616e2062616c616e63650000006044820152606401610656565b610d0f338484611238565b6040518281526001600160a01b03841690339060008051602061203b833981519152906020016105de565b60008051602061201b83398151915280546002811415610d6c5760405162461bcd60e51b815260040161065690611f1b565b60028255610d78610ec4565b610d945760405162461bcd60e51b815260040161065690611ee4565b6109df8361188f565b60008051602061201b83398151915280546002811415610dcf5760405162461bcd60e51b815260040161065690611f1b565b60028255610ddc336119c7565b15610e295760405162461bcd60e51b815260206004820152601860248201527f4163636f756e7420686173206e6f74206f7074656420696e00000000000000006044820152606401610656565b610e3e610e3533610ad9565b60a054906113a5565b60a055609f5433600090815260a16020908152604080832093909355609d90522054609e54610e6c91611225565b609e5533600081815260a26020908152604091829020805460ff1916600117905590519182527f201ace89ad3f5ab7428b91989f6a50d1998791c7b94a0fa812fd64a57687165e910160405180910390a15060019055565b6000610edc60008051602061205b8339815191525490565b6001600160a01b0316336001600160a01b031614905090565b610efd610ec4565b610f195760405162461bcd60e51b815260040161065690611ee4565b610f41817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b0316610f6160008051602061205b8339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b6001600160a01b0381166000908152609d602052604081205481908190610fbf8561163f565b6001600160a01b0395909516600090815260a36020526040902054909560019091149350915050565b60008051602061201b8339815191528054600281141561101a5760405162461bcd60e51b815260040161065690611f1b565b600282556110273361188f565b5060019055565b611036610ec4565b6110525760405162461bcd60e51b815260040161065690611ee4565b600054610100900460ff168061106b575060005460ff16155b6110ce5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610656565b600054610100900460ff161580156110f0576000805461ffff19166101011790555b61116687878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f8b01819004810282018101909252898152925089915088908190840183828082843760009201919091525060129250611a32915050565b609f829055609c80546001600160a01b0319166001600160a01b0385161790558015611198576000805461ff00191690555b50505050505050565b60008060006111af8461163f565b9050806b033b2e3c9fd0803ce800000014156111e5576001600160a01b039093166000908152609d602052604090205493915050565b6001600160a01b0384166000908152609d602052604090205461120d90633b9aca0090611f5b565b61121b633b9aca0083611f5b565b9250925050915091565b60006112318284611f9c565b9392505050565b6000611243836119c7565b90506000611250856119c7565b905060006112676112608661163f565b8590611a72565b9050600061127e6112778861163f565b8690611a72565b90506112ef816040518060400160405280601f81526020017f5472616e7366657220616d6f756e7420657863656564732062616c616e636500815250609d60008b6001600160a01b03166001600160a01b0316815260200190815260200160002054611a879092919063ffffffff16565b6001600160a01b038089166000908152609d6020526040808220939093559088168152205461131e90836113a5565b6001600160a01b0387166000908152609d6020526040902055838015611342575082155b1561136c5760a05461135490866113a5565b60a055609e546113649082611225565b609e55611198565b831580156113775750825b156111985760a0546113899086611225565b60a055609e5461139990836113a5565b609e5550505050505050565b60006112318284611f43565b6000806113c684670de0b6b3a7640000611ab3565b90506113d28184611abf565b949350505050565b60008051602061201b8339815191528054600281141561140c5760405162461bcd60e51b815260040161065690611f1b565b600282556001600160a01b0384166114665760405162461bcd60e51b815260206004820152601860248201527f4d696e7420746f20746865207a65726f206164647265737300000000000000006044820152606401610656565b6000611471856119c7565b905060006114816112778761163f565b6001600160a01b0387166000908152609d60205260409020549091506114a790826113a5565b6001600160a01b0387166000908152609d602052604090205581156114db5760a0546114d390866113a5565b60a0556114ec565b609e546114e890826113a5565b609e555b609a546114f990866113a5565b609a8190556001600160801b03116115405760405162461bcd60e51b815260206004820152600a6024820152694d617820737570706c7960b01b6044820152606401610656565b6040518581526001600160a01b0387169060009060008051602061203b8339815191529060200160405180910390a350506001825550505050565b6001600160a01b0381166115d15760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f7220697320616464726573732830290000000000006044820152606401610656565b806001600160a01b03166115f160008051602061205b8339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a361163c8160008051602061205b83398151915255565b50565b6001600160a01b038116600090815260a160205260408120541561167957506001600160a01b0316600090815260a1602052604090205490565b5050609f5490565b919050565b60008051602061201b833981519152805460028114156116b85760405162461bcd60e51b815260040161065690611f1b565b600282556001600160a01b0384166117125760405162461bcd60e51b815260206004820152601a60248201527f4275726e2066726f6d20746865207a65726f20616464726573730000000000006044820152606401610656565b8261171c57611886565b6000611727856119c7565b905060006117376112778761163f565b6001600160a01b0387166000908152609d60205260409020549091508082148061176a575081611768600183611f9c565b145b1561178d576001600160a01b0387166000908152609d6020526040812055611817565b818111156117d6576001600160a01b0387166000908152609d60205260409020546117b89083611225565b6001600160a01b0388166000908152609d6020526040902055611817565b60405162461bcd60e51b815260206004820152601660248201527552656d6f766520657863656564732062616c616e636560501b6044820152606401610656565b82156118325760a05461182a9087611225565b60a055611843565b609e5461183f9083611225565b609e555b609a546118509087611225565b609a556040518681526000906001600160a01b0389169060008051602061203b8339815191529060200160405180910390a35050505b50600190555050565b611898816119c7565b6118e45760405162461bcd60e51b815260206004820152601960248201527f4163636f756e7420686173206e6f74206f70746564206f7574000000000000006044820152606401610656565b600061191d6118f28361163f565b609f546001600160a01b0385166000908152609d602052604090205461191791611ab3565b90611abf565b905061193461192b83610ad9565b60a05490611225565b60a0556001600160a01b0382166000908152609d60205260409020819055609e5461195f90826113a5565b609e556001600160a01b038216600081815260a260209081526040808320805460ff1916600217905560a182528083209290925590519182527f19a249fa2050bac8314ac10e3ad420bd9825574bf750f58810c3c7adfc7b1c6f910160405180910390a15050565b6000813b158015908190611a0557506001600160a01b038316600090815260a2602052604081205460ff166002811115611a0357611a03612004565b145b15611a1357611a1383611acb565b50506001600160a01b0316600090815260a16020526040902054151590565b8251611a45906097906020860190611be1565b508151611a59906098906020850190611be1565b506099805460ff191660ff929092169190911790555050565b60006112318383670de0b6b3a7640000611bbf565b60008184841115611aab5760405162461bcd60e51b81526004016106569190611e58565b505050900390565b60006112318284611f7d565b60006112318284611f5b565b6001600160a01b038116600090815260a1602052604090205461163c576040516001600160a01b03821681527f201ace89ad3f5ab7428b91989f6a50d1998791c7b94a0fa812fd64a57687165e9060200160405180910390a16001600160a01b0381166000908152609d6020526040902054611b69576001600160a01b0316600090815260a1602052604090206b033b2e3c9fd0803ce80000009055565b609f546001600160a01b038216600090815260a16020526040902055611b91610e3582610ad9565b60a0556001600160a01b0381166000908152609d6020526040902054609e54611bb991611225565b609e5550565b600080611bcc8585611ab3565b9050611bd88184611abf565b95945050505050565b828054611bed90611fb3565b90600052602060002090601f016020900481019282611c0f5760008555611c55565b82601f10611c2857805160ff1916838001178555611c55565b82800160010185558215611c55579182015b82811115611c55578251825591602001919060010190611c3a565b50611c61929150611c65565b5090565b5b80821115611c615760008155600101611c66565b80356001600160a01b038116811461168157600080fd5b60008083601f840112611ca357600080fd5b50813567ffffffffffffffff811115611cbb57600080fd5b602083019150836020828501011115611cd357600080fd5b9250929050565b600060208284031215611cec57600080fd5b61123182611c7a565b60008060408385031215611d0857600080fd5b611d1183611c7a565b9150611d1f60208401611c7a565b90509250929050565b600080600060608486031215611d3d57600080fd5b611d4684611c7a565b9250611d5460208501611c7a565b9150604084013590509250925092565b60008060408385031215611d7757600080fd5b611d8083611c7a565b946020939093013593505050565b60008060008060008060808789031215611da757600080fd5b863567ffffffffffffffff80821115611dbf57600080fd5b611dcb8a838b01611c91565b90985096506020890135915080821115611de457600080fd5b50611df189828a01611c91565b9095509350611e04905060408801611c7a565b9150606087013590509295509295509295565b600060208284031215611e2957600080fd5b5035919050565b6020810160038310611e5257634e487b7160e01b600052602160045260246000fd5b91905290565b600060208083528351808285015260005b81811015611e8557858101830151858201604001528201611e69565b81811115611e97576000604083870101525b50601f01601f1916929092016040019392505050565b60208082526017908201527f43616c6c6572206973206e6f7420746865205661756c74000000000000000000604082015260600190565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b6020808252600e908201526d1499595b9d1c985b9d0818d85b1b60921b604082015260600190565b60008219821115611f5657611f56611fee565b500190565b600082611f7857634e487b7160e01b600052601260045260246000fd5b500490565b6000816000190483118215151615611f9757611f97611fee565b500290565b600082821015611fae57611fae611fee565b500390565b600181811c90821680611fc757607f821691505b60208210811415611fe857634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fdfe53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac4535ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa2646970667358221220e6ce96a4adc2aa5ece684be58c49f0afc45c508d1faee763208eca986ee5334c64736f6c63430008070033", + "libraries": {}, + "devdoc": { + "author": "Origin Protocol Inc", + "kind": "dev", + "methods": { + "allowance(address,address)": { + "details": "Function to check the amount of tokens that _owner has allowed to `_spender`.", + "params": { + "_owner": "The address which owns the funds.", + "_spender": "The address which will spend the funds." + }, + "returns": { + "_0": "The number of tokens still available for the _spender." + } + }, + "approve(address,uint256)": { + "details": "Approve the passed address to spend the specified amount of tokens on behalf of msg.sender. This method is included for ERC20 compatibility. `increaseAllowance` and `decreaseAllowance` should be used instead. Changing an allowance with this method brings the risk that someone may transfer both the old and the new allowance - if they are both greater than zero - if a transfer transaction is mined before the later approve() call is mined.", + "params": { + "_spender": "The address which will spend the funds.", + "_value": "The amount of tokens to be spent." + } + }, + "balanceOf(address)": { + "details": "Gets the balance of the specified address.", + "params": { + "_account": "Address to query the balance of." + }, + "returns": { + "_0": "A uint256 representing the amount of base units owned by the specified address." + } + }, + "burn(address,uint256)": { + "details": "Burns tokens, decreasing totalSupply." + }, + "changeSupply(uint256)": { + "details": "Modify the supply without minting new tokens. This uses a change in the exchange rate between \"credits\" and OUSD tokens to change balances.", + "params": { + "_newTotalSupply": "New total supply of OUSD." + } + }, + "creditsBalanceOf(address)": { + "details": "Gets the credits balance of the specified address.Backwards compatible with old low res credits per token.", + "params": { + "_account": "The address to query the balance of." + }, + "returns": { + "_0": "(uint256, uint256) Credit balance and credits per token of the address" + } + }, + "creditsBalanceOfHighres(address)": { + "details": "Gets the credits balance of the specified address.", + "params": { + "_account": "The address to query the balance of." + }, + "returns": { + "_0": "(uint256, uint256, bool) Credit balance, credits per token of the address, and isUpgraded" + } + }, + "decreaseAllowance(address,uint256)": { + "details": "Decrease the amount of tokens that an owner has allowed to `_spender`.", + "params": { + "_spender": "The address which will spend the funds.", + "_subtractedValue": "The amount of tokens to decrease the allowance by." + } + }, + "governanceRebaseOptIn(address)": { + "details": "Add a contract address to the non-rebasing exception list. The address's balance will be part of rebases and the account will be exposed to upside and downside.", + "params": { + "_account": "Address of the account." + } + }, + "increaseAllowance(address,uint256)": { + "details": "Increase the amount of tokens that an owner has allowed to `_spender`. This method should be used instead of approve() to avoid the double approval vulnerability described above.", + "params": { + "_addedValue": "The amount of tokens to increase the allowance by.", + "_spender": "The address which will spend the funds." + } + }, + "mint(address,uint256)": { + "details": "Mints new tokens, increasing totalSupply." + }, + "rebaseOptIn()": { + "details": "Add a contract address to the non-rebasing exception list. The address's balance will be part of rebases and the account will be exposed to upside and downside." + }, + "rebaseOptOut()": { + "details": "Explicitly mark that an address is non-rebasing." + }, + "rebasingCredits()": { + "returns": { + "_0": "Low resolution total number of rebasing credits" + } + }, + "rebasingCreditsHighres()": { + "returns": { + "_0": "High resolution total number of rebasing credits" + } + }, + "rebasingCreditsPerToken()": { + "returns": { + "_0": "Low resolution rebasingCreditsPerToken" + } + }, + "rebasingCreditsPerTokenHighres()": { + "returns": { + "_0": "High resolution rebasingCreditsPerToken" + } + }, + "totalSupply()": { + "returns": { + "_0": "The total supply of OUSD." + } + }, + "transfer(address,uint256)": { + "details": "Transfer tokens to a specified address.", + "params": { + "_to": "the address to transfer to.", + "_value": "the amount to be transferred." + }, + "returns": { + "_0": "true on success." + } + }, + "transferFrom(address,address,uint256)": { + "details": "Transfer tokens from one address to another.", + "params": { + "_from": "The address you want to send tokens from.", + "_to": "The address you want to transfer to.", + "_value": "The amount of tokens to be transferred." + } + }, + "transferGovernance(address)": { + "params": { + "_newGovernor": "Address of the new Governor" + } + } + }, + "title": "OETH Token Contract", + "version": 1 + }, + "userdoc": { + "kind": "user", + "methods": { + "claimGovernance()": { + "notice": "Claim Governance of the contract to a new account (`newGovernor`). Can only be called by the new Governor." + }, + "decimals()": { + "notice": "Returns the number of decimals used to get its user representation. For example, if `decimals` equals `2`, a balance of `505` tokens should be displayed to a user as `5,05` (`505 / 10 ** 2`). Tokens usually opt for a value of 18, imitating the relationship between Ether and Wei. NOTE: This information is only used for _display_ purposes: it in no way affects any of the arithmetic of the contract, including {IERC20-balanceOf} and {IERC20-transfer}." + }, + "governanceRebaseOptIn(address)": { + "notice": "Enable rebasing for an account." + }, + "governor()": { + "notice": "Returns the address of the current Governor." + }, + "isGovernor()": { + "notice": "Returns true if the caller is the current Governor." + }, + "name()": { + "notice": "Returns the name of the token." + }, + "symbol()": { + "notice": "Returns the symbol of the token, usually a shorter version of the name." + }, + "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" + } + }, + "version": 1 + }, + "storageLayout": { + "storage": [ + { + "astId": 41419, + "contract": "contracts/token/OETH.sol:OETH", + "label": "initialized", + "offset": 0, + "slot": "0", + "type": "t_bool" + }, + { + "astId": 41422, + "contract": "contracts/token/OETH.sol:OETH", + "label": "initializing", + "offset": 1, + "slot": "0", + "type": "t_bool" + }, + { + "astId": 41462, + "contract": "contracts/token/OETH.sol:OETH", + "label": "______gap", + "offset": 0, + "slot": "1", + "type": "t_array(t_uint256)50_storage" + }, + { + "astId": 42102, + "contract": "contracts/token/OETH.sol:OETH", + "label": "_____gap", + "offset": 0, + "slot": "51", + "type": "t_array(t_uint256)100_storage" + }, + { + "astId": 42104, + "contract": "contracts/token/OETH.sol:OETH", + "label": "_name", + "offset": 0, + "slot": "151", + "type": "t_string_storage" + }, + { + "astId": 42106, + "contract": "contracts/token/OETH.sol:OETH", + "label": "_symbol", + "offset": 0, + "slot": "152", + "type": "t_string_storage" + }, + { + "astId": 42108, + "contract": "contracts/token/OETH.sol:OETH", + "label": "_decimals", + "offset": 0, + "slot": "153", + "type": "t_uint8" + }, + { + "astId": 39075, + "contract": "contracts/token/OETH.sol:OETH", + "label": "_totalSupply", + "offset": 0, + "slot": "154", + "type": "t_uint256" + }, + { + "astId": 39081, + "contract": "contracts/token/OETH.sol:OETH", + "label": "_allowances", + "offset": 0, + "slot": "155", + "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))" + }, + { + "astId": 39087, + "contract": "contracts/token/OETH.sol:OETH", + "label": "vaultAddress", + "offset": 0, + "slot": "156", + "type": "t_address" + }, + { + "astId": 39091, + "contract": "contracts/token/OETH.sol:OETH", + "label": "_creditBalances", + "offset": 0, + "slot": "157", + "type": "t_mapping(t_address,t_uint256)" + }, + { + "astId": 39093, + "contract": "contracts/token/OETH.sol:OETH", + "label": "_rebasingCredits", + "offset": 0, + "slot": "158", + "type": "t_uint256" + }, + { + "astId": 39095, + "contract": "contracts/token/OETH.sol:OETH", + "label": "_rebasingCreditsPerToken", + "offset": 0, + "slot": "159", + "type": "t_uint256" + }, + { + "astId": 39097, + "contract": "contracts/token/OETH.sol:OETH", + "label": "nonRebasingSupply", + "offset": 0, + "slot": "160", + "type": "t_uint256" + }, + { + "astId": 39101, + "contract": "contracts/token/OETH.sol:OETH", + "label": "nonRebasingCreditsPerToken", + "offset": 0, + "slot": "161", + "type": "t_mapping(t_address,t_uint256)" + }, + { + "astId": 39106, + "contract": "contracts/token/OETH.sol:OETH", + "label": "rebaseState", + "offset": 0, + "slot": "162", + "type": "t_mapping(t_address,t_enum(RebaseOptions)39066)" + }, + { + "astId": 39110, + "contract": "contracts/token/OETH.sol:OETH", + "label": "isUpgraded", + "offset": 0, + "slot": "163", + "type": "t_mapping(t_address,t_uint256)" + } + ], + "types": { + "t_address": { + "encoding": "inplace", + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_uint256)100_storage": { + "base": "t_uint256", + "encoding": "inplace", + "label": "uint256[100]", + "numberOfBytes": "3200" + }, + "t_array(t_uint256)50_storage": { + "base": "t_uint256", + "encoding": "inplace", + "label": "uint256[50]", + "numberOfBytes": "1600" + }, + "t_bool": { + "encoding": "inplace", + "label": "bool", + "numberOfBytes": "1" + }, + "t_enum(RebaseOptions)39066": { + "encoding": "inplace", + "label": "enum OUSD.RebaseOptions", + "numberOfBytes": "1" + }, + "t_mapping(t_address,t_enum(RebaseOptions)39066)": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => enum OUSD.RebaseOptions)", + "numberOfBytes": "32", + "value": "t_enum(RebaseOptions)39066" + }, + "t_mapping(t_address,t_mapping(t_address,t_uint256))": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => mapping(address => uint256))", + "numberOfBytes": "32", + "value": "t_mapping(t_address,t_uint256)" + }, + "t_mapping(t_address,t_uint256)": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => uint256)", + "numberOfBytes": "32", + "value": "t_uint256" + }, + "t_string_storage": { + "encoding": "bytes", + "label": "string", + "numberOfBytes": "32" + }, + "t_uint256": { + "encoding": "inplace", + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint8": { + "encoding": "inplace", + "label": "uint8", + "numberOfBytes": "1" + } + } + } +} \ No newline at end of file diff --git a/contracts/deployments/holesky/OETHDripper.json b/contracts/deployments/holesky/OETHDripper.json new file mode 100644 index 0000000000..eefb72dd0c --- /dev/null +++ b/contracts/deployments/holesky/OETHDripper.json @@ -0,0 +1,350 @@ +{ + "address": "0x3833C32826A7f2a93C48D50ae44D45F45Ab17B7F", + "abi": [ + { + "inputs": [ + { + "internalType": "address", + "name": "_vault", + "type": "address" + }, + { + "internalType": "address", + "name": "_token", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "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": true, + "internalType": "address", + "name": "previousGovernor", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newGovernor", + "type": "address" + } + ], + "name": "PendingGovernorshipTransfer", + "type": "event" + }, + { + "inputs": [], + "name": "availableFunds", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "claimGovernance", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "collect", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "collectAndRebase", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "drip", + "outputs": [ + { + "internalType": "uint64", + "name": "lastCollect", + "type": "uint64" + }, + { + "internalType": "uint192", + "name": "perBlock", + "type": "uint192" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "dripDuration", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "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": "uint256", + "name": "_durationSeconds", + "type": "uint256" + } + ], + "name": "setDripDuration", + "outputs": [], + "stateMutability": "nonpayable", + "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" + } + ], + "transactionHash": "0x3df341dc5ee2f71853b1632bdc6b4cccacebc4073c9f019eac50130a74bdd097", + "receipt": { + "to": null, + "from": "0x1b94CA50D3Ad9f8368851F8526132272d1a5028C", + "contractAddress": "0x3833C32826A7f2a93C48D50ae44D45F45Ab17B7F", + "transactionIndex": 79, + "gasUsed": "794986", + "logsBloom": "0x00000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000000004000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000010000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000200000", + "blockHash": "0x9a8a2b95d892413f5f742bfc744f96bb331b1014d83c28dd7072809d6eff2313", + "transactionHash": "0x3df341dc5ee2f71853b1632bdc6b4cccacebc4073c9f019eac50130a74bdd097", + "logs": [ + { + "transactionIndex": 79, + "blockNumber": 1405136, + "transactionHash": "0x3df341dc5ee2f71853b1632bdc6b4cccacebc4073c9f019eac50130a74bdd097", + "address": "0x3833C32826A7f2a93C48D50ae44D45F45Ab17B7F", + "topics": [ + "0xc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000001b94ca50d3ad9f8368851f8526132272d1a5028c" + ], + "data": "0x", + "logIndex": 117, + "blockHash": "0x9a8a2b95d892413f5f742bfc744f96bb331b1014d83c28dd7072809d6eff2313" + } + ], + "blockNumber": 1405136, + "cumulativeGasUsed": "15824006", + "status": 1, + "byzantium": true + }, + "args": [ + "0x19d2bAaBA949eFfa163bFB9efB53ed8701aA5dD9", + "0x94373a4919b3240d86ea41593d5eba789fef3848" + ], + "numDeployments": 1, + "solcInputHash": "da4c2bc4af0be4b969e54f8b43895033", + "metadata": "{\"compiler\":{\"version\":\"0.8.7+commit.e28d00a7\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_vault\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"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\":true,\"internalType\":\"address\",\"name\":\"previousGovernor\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newGovernor\",\"type\":\"address\"}],\"name\":\"PendingGovernorshipTransfer\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"availableFunds\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"claimGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"collect\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"collectAndRebase\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"drip\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"lastCollect\",\"type\":\"uint64\"},{\"internalType\":\"uint192\",\"name\":\"perBlock\",\"type\":\"uint192\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"dripDuration\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"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\":\"uint256\",\"name\":\"_durationSeconds\",\"type\":\"uint256\"}],\"name\":\"setDripDuration\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"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\"}],\"devdoc\":{\"author\":\"Origin Protocol Inc\",\"kind\":\"dev\",\"methods\":{\"availableFunds()\":{\"returns\":{\"_0\":\"The amount that would be sent if a collect was called\"}},\"setDripDuration(uint256)\":{\"details\":\"Change the drip duration. Governor only.\",\"params\":{\"_durationSeconds\":\"the number of seconds to drip out the entire balance over if no collects were called during that time.\"}},\"transferGovernance(address)\":{\"params\":{\"_newGovernor\":\"Address of the new Governor\"}},\"transferToken(address,uint256)\":{\"details\":\"Transfer out ERC20 tokens held by the contract. Governor only.\",\"params\":{\"_amount\":\"amount to transfer\",\"_asset\":\"ERC20 token address\"}}},\"title\":\"OETH Dripper Contract\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"claimGovernance()\":{\"notice\":\"Claim Governance of the contract to a new account (`newGovernor`). Can only be called by the new Governor.\"},\"collect()\":{\"notice\":\"Collect all dripped funds and send to vault. Recalculate new drip rate.\"},\"collectAndRebase()\":{\"notice\":\"Collect all dripped funds, send to vault, recalculate new drip rate, and rebase OUSD.\"},\"governor()\":{\"notice\":\"Returns the address of the current Governor.\"},\"isGovernor()\":{\"notice\":\"Returns true if the caller is the current Governor.\"},\"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\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/harvest/OETHDripper.sol\":\"OETHDripper\"},\"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/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\",\"keccak256\":\"0x8c069829d144d083c274c855a26b692d1142b82cbe0f27ef0598e15544084f5c\",\"license\":\"MIT\"},\"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\",\"keccak256\":\"0x793bb189f2419450b11a386f7a0e42cc0fdbf272624c8f93441046d9df6b8c83\",\"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/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/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/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": "0x60c060405234801561001057600080fd5b50604051610e47380380610e4783398101604081905261002f916100cb565b818161004733600080516020610e2783398151915255565b600080516020610e27833981519152546040516001600160a01b03909116906000907fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a908290a36001600160601b0319606092831b8116608052911b1660a052506100fe9050565b80516001600160a01b03811681146100c657600080fd5b919050565b600080604083850312156100de57600080fd5b6100e7836100af565b91506100f5602084016100af565b90509250929050565b60805160601c60a05160601c610ce961013e600039600081816102bb0152818161058c01526106c101526000818161042801526106e30152610ce96000f3fe608060405234801561001057600080fd5b50600436106100a95760003560e01c8063737962971161007157806373796297146101195780639f678cca14610121578063bb7a632e1461016f578063c7af335214610178578063d38bfff414610190578063e5225381146101a357600080fd5b80630493a0fa146100ae5780630c340a24146100c35780631072cbea146100e857806346fcff4c146100fb5780635d36b19014610111575b600080fd5b6100c16100bc366004610b41565b6101ab565b005b6100cb610238565b6040516001600160a01b0390911681526020015b60405180910390f35b6100c16100f6366004610af5565b610255565b610103610299565b6040519081526020016100df565b6100c1610378565b6100c161041e565b6001546101479067ffffffffffffffff811690600160401b90046001600160c01b031682565b6040805167ffffffffffffffff90931683526001600160c01b039091166020830152016100df565b61010360005481565b61018061049b565b60405190151581526020016100df565b6100c161019e366004610ada565b6104cc565b6100c1610570565b6101b361049b565b6101d85760405162461bcd60e51b81526004016101cf90610bc2565b60405180910390fd5b600081116102285760405162461bcd60e51b815260206004820152601960248201527f6475726174696f6e206d757374206265206e6f6e2d7a65726f0000000000000060448201526064016101cf565b6000819055610235610574565b50565b6000610250600080516020610c948339815191525490565b905090565b61025d61049b565b6102795760405162461bcd60e51b81526004016101cf90610bc2565b610295610284610238565b6001600160a01b038416908361070d565b5050565b6040516370a0823160e01b815230600482015260009081906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a082319060240160206040518083038186803b1580156102fd57600080fd5b505afa158015610311573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103359190610b5a565b6040805180820190915260015467ffffffffffffffff81168252600160401b90046001600160c01b0316602082015290915061037290829061075f565b91505090565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b0316146104135760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b60648201526084016101cf565b61041c336107b1565b565b610426610574565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663af14052c6040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561048157600080fd5b505af1158015610495573d6000803e3d6000fd5b50505050565b60006104b3600080516020610c948339815191525490565b6001600160a01b0316336001600160a01b031614905090565b6104d461049b565b6104f05760405162461bcd60e51b81526004016101cf90610bc2565b610518817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b0316610538600080516020610c948339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b61041c5b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b1580156105d657600080fd5b505afa1580156105ea573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061060e9190610b5a565b6040805180820190915260015467ffffffffffffffff81168252600160401b90046001600160c01b0316602082015290915060009061064e90839061075f565b9050600061065c8284610c3a565b905060405180604001604052804267ffffffffffffffff168152602001600054836106879190610bf9565b6001600160c01b03908116909152815160209092015116600160401b0267ffffffffffffffff909116176001556107086001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000167f00000000000000000000000000000000000000000000000000000000000000008461070d565b505050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052610708908490610872565b8051600090819061077a9067ffffffffffffffff1642610c3a565b9050600083602001516001600160c01b0316826107979190610c1b565b90508481116107a657806107a8565b845b95945050505050565b6001600160a01b0381166108075760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f72206973206164647265737328302900000000000060448201526064016101cf565b806001600160a01b0316610827600080516020610c948339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a361023581600080516020610c9483398151915255565b60006108c7826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166109449092919063ffffffff16565b80519091501561070857808060200190518101906108e59190610b1f565b6107085760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016101cf565b6060610953848460008561095d565b90505b9392505050565b6060824710156109be5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016101cf565b843b610a0c5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016101cf565b600080866001600160a01b03168587604051610a289190610b73565b60006040518083038185875af1925050503d8060008114610a65576040519150601f19603f3d011682016040523d82523d6000602084013e610a6a565b606091505b5091509150610a7a828286610a85565b979650505050505050565b60608315610a94575081610956565b825115610aa45782518084602001fd5b8160405162461bcd60e51b81526004016101cf9190610b8f565b80356001600160a01b0381168114610ad557600080fd5b919050565b600060208284031215610aec57600080fd5b61095682610abe565b60008060408385031215610b0857600080fd5b610b1183610abe565b946020939093013593505050565b600060208284031215610b3157600080fd5b8151801515811461095657600080fd5b600060208284031215610b5357600080fd5b5035919050565b600060208284031215610b6c57600080fd5b5051919050565b60008251610b85818460208701610c51565b9190910192915050565b6020815260008251806020840152610bae816040850160208701610c51565b601f01601f19169190910160400192915050565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b600082610c1657634e487b7160e01b600052601260045260246000fd5b500490565b6000816000190483118215151615610c3557610c35610c7d565b500290565b600082821015610c4c57610c4c610c7d565b500390565b60005b83811015610c6c578181015183820152602001610c54565b838111156104955750506000910152565b634e487b7160e01b600052601160045260246000fdfe7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa2646970667358221220318ea734077dc528725556f5f46b7961f2c528788339893927ca309b94193b5f64736f6c634300080700337bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a", + "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106100a95760003560e01c8063737962971161007157806373796297146101195780639f678cca14610121578063bb7a632e1461016f578063c7af335214610178578063d38bfff414610190578063e5225381146101a357600080fd5b80630493a0fa146100ae5780630c340a24146100c35780631072cbea146100e857806346fcff4c146100fb5780635d36b19014610111575b600080fd5b6100c16100bc366004610b41565b6101ab565b005b6100cb610238565b6040516001600160a01b0390911681526020015b60405180910390f35b6100c16100f6366004610af5565b610255565b610103610299565b6040519081526020016100df565b6100c1610378565b6100c161041e565b6001546101479067ffffffffffffffff811690600160401b90046001600160c01b031682565b6040805167ffffffffffffffff90931683526001600160c01b039091166020830152016100df565b61010360005481565b61018061049b565b60405190151581526020016100df565b6100c161019e366004610ada565b6104cc565b6100c1610570565b6101b361049b565b6101d85760405162461bcd60e51b81526004016101cf90610bc2565b60405180910390fd5b600081116102285760405162461bcd60e51b815260206004820152601960248201527f6475726174696f6e206d757374206265206e6f6e2d7a65726f0000000000000060448201526064016101cf565b6000819055610235610574565b50565b6000610250600080516020610c948339815191525490565b905090565b61025d61049b565b6102795760405162461bcd60e51b81526004016101cf90610bc2565b610295610284610238565b6001600160a01b038416908361070d565b5050565b6040516370a0823160e01b815230600482015260009081906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a082319060240160206040518083038186803b1580156102fd57600080fd5b505afa158015610311573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103359190610b5a565b6040805180820190915260015467ffffffffffffffff81168252600160401b90046001600160c01b0316602082015290915061037290829061075f565b91505090565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b0316146104135760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b60648201526084016101cf565b61041c336107b1565b565b610426610574565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663af14052c6040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561048157600080fd5b505af1158015610495573d6000803e3d6000fd5b50505050565b60006104b3600080516020610c948339815191525490565b6001600160a01b0316336001600160a01b031614905090565b6104d461049b565b6104f05760405162461bcd60e51b81526004016101cf90610bc2565b610518817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b0316610538600080516020610c948339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b61041c5b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b1580156105d657600080fd5b505afa1580156105ea573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061060e9190610b5a565b6040805180820190915260015467ffffffffffffffff81168252600160401b90046001600160c01b0316602082015290915060009061064e90839061075f565b9050600061065c8284610c3a565b905060405180604001604052804267ffffffffffffffff168152602001600054836106879190610bf9565b6001600160c01b03908116909152815160209092015116600160401b0267ffffffffffffffff909116176001556107086001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000167f00000000000000000000000000000000000000000000000000000000000000008461070d565b505050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052610708908490610872565b8051600090819061077a9067ffffffffffffffff1642610c3a565b9050600083602001516001600160c01b0316826107979190610c1b565b90508481116107a657806107a8565b845b95945050505050565b6001600160a01b0381166108075760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f72206973206164647265737328302900000000000060448201526064016101cf565b806001600160a01b0316610827600080516020610c948339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a361023581600080516020610c9483398151915255565b60006108c7826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166109449092919063ffffffff16565b80519091501561070857808060200190518101906108e59190610b1f565b6107085760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016101cf565b6060610953848460008561095d565b90505b9392505050565b6060824710156109be5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016101cf565b843b610a0c5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016101cf565b600080866001600160a01b03168587604051610a289190610b73565b60006040518083038185875af1925050503d8060008114610a65576040519150601f19603f3d011682016040523d82523d6000602084013e610a6a565b606091505b5091509150610a7a828286610a85565b979650505050505050565b60608315610a94575081610956565b825115610aa45782518084602001fd5b8160405162461bcd60e51b81526004016101cf9190610b8f565b80356001600160a01b0381168114610ad557600080fd5b919050565b600060208284031215610aec57600080fd5b61095682610abe565b60008060408385031215610b0857600080fd5b610b1183610abe565b946020939093013593505050565b600060208284031215610b3157600080fd5b8151801515811461095657600080fd5b600060208284031215610b5357600080fd5b5035919050565b600060208284031215610b6c57600080fd5b5051919050565b60008251610b85818460208701610c51565b9190910192915050565b6020815260008251806020840152610bae816040850160208701610c51565b601f01601f19169190910160400192915050565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b600082610c1657634e487b7160e01b600052601260045260246000fd5b500490565b6000816000190483118215151615610c3557610c35610c7d565b500290565b600082821015610c4c57610c4c610c7d565b500390565b60005b83811015610c6c578181015183820152602001610c54565b838111156104955750506000910152565b634e487b7160e01b600052601160045260246000fdfe7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa2646970667358221220318ea734077dc528725556f5f46b7961f2c528788339893927ca309b94193b5f64736f6c63430008070033", + "libraries": {}, + "devdoc": { + "author": "Origin Protocol Inc", + "kind": "dev", + "methods": { + "availableFunds()": { + "returns": { + "_0": "The amount that would be sent if a collect was called" + } + }, + "setDripDuration(uint256)": { + "details": "Change the drip duration. Governor only.", + "params": { + "_durationSeconds": "the number of seconds to drip out the entire balance over if no collects were called during that time." + } + }, + "transferGovernance(address)": { + "params": { + "_newGovernor": "Address of the new Governor" + } + }, + "transferToken(address,uint256)": { + "details": "Transfer out ERC20 tokens held by the contract. Governor only.", + "params": { + "_amount": "amount to transfer", + "_asset": "ERC20 token address" + } + } + }, + "title": "OETH Dripper Contract", + "version": 1 + }, + "userdoc": { + "kind": "user", + "methods": { + "claimGovernance()": { + "notice": "Claim Governance of the contract to a new account (`newGovernor`). Can only be called by the new Governor." + }, + "collect()": { + "notice": "Collect all dripped funds and send to vault. Recalculate new drip rate." + }, + "collectAndRebase()": { + "notice": "Collect all dripped funds, send to vault, recalculate new drip rate, and rebase OUSD." + }, + "governor()": { + "notice": "Returns the address of the current Governor." + }, + "isGovernor()": { + "notice": "Returns true if the caller is the current Governor." + }, + "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" + } + }, + "version": 1 + }, + "storageLayout": { + "storage": [ + { + "astId": 10483, + "contract": "contracts/harvest/OETHDripper.sol:OETHDripper", + "label": "dripDuration", + "offset": 0, + "slot": "0", + "type": "t_uint256" + }, + { + "astId": 10486, + "contract": "contracts/harvest/OETHDripper.sol:OETHDripper", + "label": "drip", + "offset": 0, + "slot": "1", + "type": "t_struct(Drip)10477_storage" + } + ], + "types": { + "t_struct(Drip)10477_storage": { + "encoding": "inplace", + "label": "struct Dripper.Drip", + "members": [ + { + "astId": 10474, + "contract": "contracts/harvest/OETHDripper.sol:OETHDripper", + "label": "lastCollect", + "offset": 0, + "slot": "0", + "type": "t_uint64" + }, + { + "astId": 10476, + "contract": "contracts/harvest/OETHDripper.sol:OETHDripper", + "label": "perBlock", + "offset": 8, + "slot": "0", + "type": "t_uint192" + } + ], + "numberOfBytes": "32" + }, + "t_uint192": { + "encoding": "inplace", + "label": "uint192", + "numberOfBytes": "24" + }, + "t_uint256": { + "encoding": "inplace", + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint64": { + "encoding": "inplace", + "label": "uint64", + "numberOfBytes": "8" + } + } + } +} \ No newline at end of file diff --git a/contracts/deployments/holesky/OETHDripperProxy.json b/contracts/deployments/holesky/OETHDripperProxy.json new file mode 100644 index 0000000000..755a1342be --- /dev/null +++ b/contracts/deployments/holesky/OETHDripperProxy.json @@ -0,0 +1,289 @@ +{ + "address": "0xaFF1E6263F4004C95Ae611DEb2ADaC049B5aD121", + "abi": [ + { + "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": true, + "internalType": "address", + "name": "previousGovernor", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newGovernor", + "type": "address" + } + ], + "name": "PendingGovernorshipTransfer", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "implementation", + "type": "address" + } + ], + "name": "Upgraded", + "type": "event" + }, + { + "stateMutability": "payable", + "type": "fallback" + }, + { + "inputs": [], + "name": "admin", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "claimGovernance", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "governor", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "implementation", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_logic", + "type": "address" + }, + { + "internalType": "address", + "name": "_initGovernor", + "type": "address" + }, + { + "internalType": "bytes", + "name": "_data", + "type": "bytes" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [], + "name": "isGovernor", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_newGovernor", + "type": "address" + } + ], + "name": "transferGovernance", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newImplementation", + "type": "address" + } + ], + "name": "upgradeTo", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newImplementation", + "type": "address" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "upgradeToAndCall", + "outputs": [], + "stateMutability": "payable", + "type": "function" + } + ], + "transactionHash": "0x95226f8bb7f8e21d228772290f0abec23b1a53b2558de51a24484a539f3a01a5", + "receipt": { + "to": null, + "from": "0x1b94CA50D3Ad9f8368851F8526132272d1a5028C", + "contractAddress": "0xaFF1E6263F4004C95Ae611DEb2ADaC049B5aD121", + "transactionIndex": 58, + "gasUsed": "580428", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000008000000000000000000000000000000000000000000000000000000000100000000000000000000000020000000000000000000800000000000000000000000000000000000004000100000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000010000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x1432d24281a746b15785bcc94305d8935ae0f5fe9512cecb7d16e69680939018", + "transactionHash": "0x95226f8bb7f8e21d228772290f0abec23b1a53b2558de51a24484a539f3a01a5", + "logs": [ + { + "transactionIndex": 58, + "blockNumber": 1405140, + "transactionHash": "0x95226f8bb7f8e21d228772290f0abec23b1a53b2558de51a24484a539f3a01a5", + "address": "0xaFF1E6263F4004C95Ae611DEb2ADaC049B5aD121", + "topics": [ + "0xc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000001b94ca50d3ad9f8368851f8526132272d1a5028c" + ], + "data": "0x", + "logIndex": 102, + "blockHash": "0x1432d24281a746b15785bcc94305d8935ae0f5fe9512cecb7d16e69680939018" + } + ], + "blockNumber": 1405140, + "cumulativeGasUsed": "10971939", + "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\":true,\"internalType\":\"address\",\"name\":\"previousGovernor\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newGovernor\",\"type\":\"address\"}],\"name\":\"GovernorshipTransferred\",\"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\":true,\"internalType\":\"address\",\"name\":\"implementation\",\"type\":\"address\"}],\"name\":\"Upgraded\",\"type\":\"event\"},{\"stateMutability\":\"payable\",\"type\":\"fallback\"},{\"inputs\":[],\"name\":\"admin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"claimGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"governor\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"implementation\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_logic\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_initGovernor\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isGovernor\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_newGovernor\",\"type\":\"address\"}],\"name\":\"transferGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newImplementation\",\"type\":\"address\"}],\"name\":\"upgradeTo\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newImplementation\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"upgradeToAndCall\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"admin()\":{\"returns\":{\"_0\":\"The address of the proxy admin/it's also the governor.\"}},\"implementation()\":{\"returns\":{\"_0\":\"The address of the implementation.\"}},\"initialize(address,address,bytes)\":{\"details\":\"Contract initializer with Governor enforcement\",\"params\":{\"_data\":\"Data to send as msg.data to the implementation to initialize the proxied contract. It should include the signature and the parameters of the function to be called, as described in https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding. This parameter is optional, if no data is given the initialization call to proxied contract will be skipped.\",\"_initGovernor\":\"Address of the initial Governor.\",\"_logic\":\"Address of the initial implementation.\"}},\"transferGovernance(address)\":{\"params\":{\"_newGovernor\":\"Address of the new Governor\"}},\"upgradeTo(address)\":{\"details\":\"Upgrade the backing implementation of the proxy. Only the admin can call this function.\",\"params\":{\"newImplementation\":\"Address of the new implementation.\"}},\"upgradeToAndCall(address,bytes)\":{\"details\":\"Upgrade the backing implementation of the proxy and call a function on the new implementation. This is useful to initialize the proxied contract.\",\"params\":{\"data\":\"Data to send as msg.data in the low level call. It should include the signature and the parameters of the function to be called, as described in https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.\",\"newImplementation\":\"Address of the new implementation.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"claimGovernance()\":{\"notice\":\"Claim Governance of the contract to a new account (`newGovernor`). Can only be called by the new Governor.\"},\"governor()\":{\"notice\":\"Returns the address of the current Governor.\"},\"isGovernor()\":{\"notice\":\"Returns true if the caller is the current Governor.\"},\"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\"}},\"notice\":\"OETHDripperProxy delegates calls to a OETHDripper implementation\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/proxies/Proxies.sol\":\"OETHDripperProxy\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@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\"},\"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/proxies/InitializeGovernedUpgradeabilityProxy.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport { Address } from \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\n\\nimport { Governable } from \\\"../governance/Governable.sol\\\";\\n\\n/**\\n * @title BaseGovernedUpgradeabilityProxy\\n * @dev This contract combines an upgradeability proxy with our governor system.\\n * It is based on an older version of OpenZeppelins BaseUpgradeabilityProxy\\n * with Solidity ^0.8.0.\\n * @author Origin Protocol Inc\\n */\\ncontract InitializeGovernedUpgradeabilityProxy is Governable {\\n /**\\n * @dev Emitted when the implementation is upgraded.\\n * @param implementation Address of the new implementation.\\n */\\n event Upgraded(address indexed implementation);\\n\\n /**\\n * @dev Contract initializer with Governor enforcement\\n * @param _logic Address of the initial implementation.\\n * @param _initGovernor Address of the initial Governor.\\n * @param _data Data to send as msg.data to the implementation to initialize\\n * the proxied contract.\\n * It should include the signature and the parameters of the function to be\\n * called, as described in\\n * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.\\n * This parameter is optional, if no data is given the initialization call\\n * to proxied contract will be skipped.\\n */\\n function initialize(\\n address _logic,\\n address _initGovernor,\\n bytes calldata _data\\n ) public payable onlyGovernor {\\n require(_implementation() == address(0));\\n assert(\\n IMPLEMENTATION_SLOT ==\\n bytes32(uint256(keccak256(\\\"eip1967.proxy.implementation\\\")) - 1)\\n );\\n _setImplementation(_logic);\\n if (_data.length > 0) {\\n (bool success, ) = _logic.delegatecall(_data);\\n require(success);\\n }\\n _changeGovernor(_initGovernor);\\n }\\n\\n /**\\n * @return The address of the proxy admin/it's also the governor.\\n */\\n function admin() external view returns (address) {\\n return _governor();\\n }\\n\\n /**\\n * @return The address of the implementation.\\n */\\n function implementation() external view returns (address) {\\n return _implementation();\\n }\\n\\n /**\\n * @dev Upgrade the backing implementation of the proxy.\\n * Only the admin can call this function.\\n * @param newImplementation Address of the new implementation.\\n */\\n function upgradeTo(address newImplementation) external onlyGovernor {\\n _upgradeTo(newImplementation);\\n }\\n\\n /**\\n * @dev Upgrade the backing implementation of the proxy and call a function\\n * on the new implementation.\\n * This is useful to initialize the proxied contract.\\n * @param newImplementation Address of the new implementation.\\n * @param data Data to send as msg.data in the low level call.\\n * It should include the signature and the parameters of the function to be called, as described in\\n * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.\\n */\\n function upgradeToAndCall(address newImplementation, bytes calldata data)\\n external\\n payable\\n onlyGovernor\\n {\\n _upgradeTo(newImplementation);\\n (bool success, ) = newImplementation.delegatecall(data);\\n require(success);\\n }\\n\\n /**\\n * @dev Fallback function.\\n * Implemented entirely in `_fallback`.\\n */\\n fallback() external payable {\\n _fallback();\\n }\\n\\n /**\\n * @dev Delegates execution to an implementation contract.\\n * This is a low level function that doesn't return to its internal call site.\\n * It will return to the external caller whatever the implementation returns.\\n * @param _impl Address to delegate.\\n */\\n function _delegate(address _impl) internal {\\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(gas(), _impl, 0, calldatasize(), 0, 0)\\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 /**\\n * @dev Function that is run as the first thing in the fallback function.\\n * Can be redefined in derived contracts to add functionality.\\n * Redefinitions must call super._willFallback().\\n */\\n function _willFallback() internal {}\\n\\n /**\\n * @dev fallback implementation.\\n * Extracted to enable manual triggering.\\n */\\n function _fallback() internal {\\n _willFallback();\\n _delegate(_implementation());\\n }\\n\\n /**\\n * @dev Storage slot with the address of the current implementation.\\n * This is the keccak-256 hash of \\\"eip1967.proxy.implementation\\\" subtracted by 1, and is\\n * validated in the constructor.\\n */\\n bytes32 internal constant IMPLEMENTATION_SLOT =\\n 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\\n\\n /**\\n * @dev Returns the current implementation.\\n * @return impl Address of the current implementation\\n */\\n function _implementation() internal view returns (address impl) {\\n bytes32 slot = IMPLEMENTATION_SLOT;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n impl := sload(slot)\\n }\\n }\\n\\n /**\\n * @dev Upgrades the proxy to a new implementation.\\n * @param newImplementation Address of the new implementation.\\n */\\n function _upgradeTo(address newImplementation) internal {\\n _setImplementation(newImplementation);\\n emit Upgraded(newImplementation);\\n }\\n\\n /**\\n * @dev Sets the implementation address of the proxy.\\n * @param newImplementation Address of the new implementation.\\n */\\n function _setImplementation(address newImplementation) internal {\\n require(\\n Address.isContract(newImplementation),\\n \\\"Cannot set a proxy implementation to a non-contract address\\\"\\n );\\n\\n bytes32 slot = IMPLEMENTATION_SLOT;\\n\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n sstore(slot, newImplementation)\\n }\\n }\\n}\\n\",\"keccak256\":\"0xcf9bc33957fa41a745726edb6461a4bddca875a038c848286a059f0f22b7f184\",\"license\":\"MIT\"},\"contracts/proxies/Proxies.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport { InitializeGovernedUpgradeabilityProxy } from \\\"./InitializeGovernedUpgradeabilityProxy.sol\\\";\\n\\n/**\\n * @notice OUSDProxy delegates calls to an OUSD implementation\\n */\\ncontract OUSDProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice WrappedOUSDProxy delegates calls to a WrappedOUSD implementation\\n */\\ncontract WrappedOUSDProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice VaultProxy delegates calls to a Vault implementation\\n */\\ncontract VaultProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice CompoundStrategyProxy delegates calls to a CompoundStrategy implementation\\n */\\ncontract CompoundStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice AaveStrategyProxy delegates calls to a AaveStrategy implementation\\n */\\ncontract AaveStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice ThreePoolStrategyProxy delegates calls to a ThreePoolStrategy implementation\\n */\\ncontract ThreePoolStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice ConvexStrategyProxy delegates calls to a ConvexStrategy implementation\\n */\\ncontract ConvexStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice HarvesterProxy delegates calls to a Harvester implementation\\n */\\ncontract HarvesterProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice DripperProxy delegates calls to a Dripper implementation\\n */\\ncontract DripperProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice MorphoCompoundStrategyProxy delegates calls to a MorphoCompoundStrategy implementation\\n */\\ncontract MorphoCompoundStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice ConvexOUSDMetaStrategyProxy delegates calls to a ConvexOUSDMetaStrategy implementation\\n */\\ncontract ConvexOUSDMetaStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice ConvexLUSDMetaStrategyProxy delegates calls to a ConvexalGeneralizedMetaStrategy implementation\\n */\\ncontract ConvexLUSDMetaStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice MorphoAaveStrategyProxy delegates calls to a MorphoCompoundStrategy implementation\\n */\\ncontract MorphoAaveStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice OETHProxy delegates calls to nowhere for now\\n */\\ncontract OETHProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice WOETHProxy delegates calls to nowhere for now\\n */\\ncontract WOETHProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice OETHVaultProxy delegates calls to a Vault implementation\\n */\\ncontract OETHVaultProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice OETHDripperProxy delegates calls to a OETHDripper implementation\\n */\\ncontract OETHDripperProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice OETHHarvesterProxy delegates calls to a Harvester implementation\\n */\\ncontract OETHHarvesterProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice FraxETHStrategyProxy delegates calls to a FraxETHStrategy implementation\\n */\\ncontract FraxETHStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice CurveEthStrategyProxy delegates calls to a CurveEthStrategy implementation\\n */\\ncontract ConvexEthMetaStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice BuybackProxy delegates calls to Buyback implementation\\n */\\ncontract BuybackProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice OETHMorphoAaveStrategyProxy delegates calls to a MorphoAaveStrategy implementation\\n */\\ncontract OETHMorphoAaveStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice OETHBalancerMetaPoolrEthStrategyProxy delegates calls to a BalancerMetaPoolStrategy implementation\\n */\\ncontract OETHBalancerMetaPoolrEthStrategyProxy is\\n InitializeGovernedUpgradeabilityProxy\\n{\\n\\n}\\n\\n/**\\n * @notice OETHBalancerMetaPoolwstEthStrategyProxy delegates calls to a BalancerMetaPoolStrategy implementation\\n */\\ncontract OETHBalancerMetaPoolwstEthStrategyProxy is\\n InitializeGovernedUpgradeabilityProxy\\n{\\n\\n}\\n\\n/**\\n * @notice FluxStrategyProxy delegates calls to a CompoundStrategy implementation\\n */\\ncontract FluxStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice MakerDsrStrategyProxy delegates calls to a Generalized4626Strategy implementation\\n */\\ncontract MakerDsrStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice FrxEthRedeemStrategyProxy delegates calls to a FrxEthRedeemStrategy implementation\\n */\\ncontract FrxEthRedeemStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice OETHBuybackProxy delegates calls to Buyback implementation\\n */\\ncontract OETHBuybackProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice BridgedWOETHProxy delegates calls to BridgedWOETH implementation\\n */\\ncontract BridgedWOETHProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice NativeStakingSSVStrategyProxy delegates calls to NativeStakingSSVStrategy implementation\\n */\\ncontract NativeStakingSSVStrategyProxy is\\n InitializeGovernedUpgradeabilityProxy\\n{\\n\\n}\\n\\n/**\\n * @notice NativeStakingFeeAccumulatorProxy delegates calls to NativeStakingFeeCollector implementation\\n */\\ncontract NativeStakingFeeAccumulatorProxy is\\n InitializeGovernedUpgradeabilityProxy\\n{\\n\\n}\\n\",\"keccak256\":\"0x2e294507edd91494e1020a2a1c43502d2f5cba01266c228406562ecde7a2d872\",\"license\":\"MIT\"}},\"version\":1}", + "bytecode": "0x608060405234801561001057600080fd5b506100273360008051602061099083398151915255565b600080516020610990833981519152546040516001600160a01b03909116906000907fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a908290a36109138061007d6000396000f3fe6080604052600436106100865760003560e01c80635d36b190116100595780635d36b1901461010a578063c7af33521461011f578063cf7a1d7714610144578063d38bfff414610157578063f851a4401461009057610086565b80630c340a24146100905780633659cfe6146100c25780634f1ef286146100e25780635c60da1b146100f5575b61008e610177565b005b34801561009c57600080fd5b506100a5610197565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156100ce57600080fd5b5061008e6100dd366004610745565b6101b4565b61008e6100f03660046107c8565b6101ed565b34801561010157600080fd5b506100a561028a565b34801561011657600080fd5b5061008e6102a2565b34801561012b57600080fd5b50610134610346565b60405190151581526020016100b9565b61008e610152366004610767565b610377565b34801561016357600080fd5b5061008e610172366004610745565b610491565b61019561019060008051602061089e8339815191525490565b610535565b565b60006101af6000805160206108be8339815191525490565b905090565b6101bc610346565b6101e15760405162461bcd60e51b81526004016101d89061082b565b60405180910390fd5b6101ea81610559565b50565b6101f5610346565b6102115760405162461bcd60e51b81526004016101d89061082b565b61021a83610559565b6000836001600160a01b0316838360405161023692919061081b565b600060405180830381855af49150503d8060008114610271576040519150601f19603f3d011682016040523d82523d6000602084013e610276565b606091505b505090508061028457600080fd5b50505050565b60006101af60008051602061089e8339815191525490565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b03161461033d5760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b60648201526084016101d8565b61019533610599565b600061035e6000805160206108be8339815191525490565b6001600160a01b0316336001600160a01b031614905090565b61037f610346565b61039b5760405162461bcd60e51b81526004016101d89061082b565b60006103b360008051602061089e8339815191525490565b6001600160a01b0316146103c657600080fd5b6103f160017f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbd610862565b60008051602061089e8339815191521461040d5761040d610887565b6104168461065a565b8015610488576000846001600160a01b0316838360405161043892919061081b565b600060405180830381855af49150503d8060008114610473576040519150601f19603f3d011682016040523d82523d6000602084013e610478565b606091505b505090508061048657600080fd5b505b61028483610599565b610499610346565b6104b55760405162461bcd60e51b81526004016101d89061082b565b6104dd817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b03166104fd6000805160206108be8339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b3660008037600080366000845af43d6000803e808015610554573d6000f35b3d6000fd5b6105628161065a565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b6001600160a01b0381166105ef5760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f72206973206164647265737328302900000000000060448201526064016101d8565b806001600160a01b031661060f6000805160206108be8339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a36101ea816000805160206108be83398151915255565b803b6106ce5760405162461bcd60e51b815260206004820152603b60248201527f43616e6e6f742073657420612070726f787920696d706c656d656e746174696f60448201527f6e20746f2061206e6f6e2d636f6e74726163742061646472657373000000000060648201526084016101d8565b60008051602061089e83398151915255565b80356001600160a01b03811681146106f757600080fd5b919050565b60008083601f84011261070e57600080fd5b50813567ffffffffffffffff81111561072657600080fd5b60208301915083602082850101111561073e57600080fd5b9250929050565b60006020828403121561075757600080fd5b610760826106e0565b9392505050565b6000806000806060858703121561077d57600080fd5b610786856106e0565b9350610794602086016106e0565b9250604085013567ffffffffffffffff8111156107b057600080fd5b6107bc878288016106fc565b95989497509550505050565b6000806000604084860312156107dd57600080fd5b6107e6846106e0565b9250602084013567ffffffffffffffff81111561080257600080fd5b61080e868287016106fc565b9497909650939450505050565b8183823760009101908152919050565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b60008282101561088257634e487b7160e01b600052601160045260246000fd5b500390565b634e487b7160e01b600052600160045260246000fdfe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa2646970667358221220c9221f795d84ec78bb6a84a3cb3a78aae0a56dca53a44a29dc80384cd96fa72864736f6c634300080700337bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a", + "deployedBytecode": "0x6080604052600436106100865760003560e01c80635d36b190116100595780635d36b1901461010a578063c7af33521461011f578063cf7a1d7714610144578063d38bfff414610157578063f851a4401461009057610086565b80630c340a24146100905780633659cfe6146100c25780634f1ef286146100e25780635c60da1b146100f5575b61008e610177565b005b34801561009c57600080fd5b506100a5610197565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156100ce57600080fd5b5061008e6100dd366004610745565b6101b4565b61008e6100f03660046107c8565b6101ed565b34801561010157600080fd5b506100a561028a565b34801561011657600080fd5b5061008e6102a2565b34801561012b57600080fd5b50610134610346565b60405190151581526020016100b9565b61008e610152366004610767565b610377565b34801561016357600080fd5b5061008e610172366004610745565b610491565b61019561019060008051602061089e8339815191525490565b610535565b565b60006101af6000805160206108be8339815191525490565b905090565b6101bc610346565b6101e15760405162461bcd60e51b81526004016101d89061082b565b60405180910390fd5b6101ea81610559565b50565b6101f5610346565b6102115760405162461bcd60e51b81526004016101d89061082b565b61021a83610559565b6000836001600160a01b0316838360405161023692919061081b565b600060405180830381855af49150503d8060008114610271576040519150601f19603f3d011682016040523d82523d6000602084013e610276565b606091505b505090508061028457600080fd5b50505050565b60006101af60008051602061089e8339815191525490565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b03161461033d5760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b60648201526084016101d8565b61019533610599565b600061035e6000805160206108be8339815191525490565b6001600160a01b0316336001600160a01b031614905090565b61037f610346565b61039b5760405162461bcd60e51b81526004016101d89061082b565b60006103b360008051602061089e8339815191525490565b6001600160a01b0316146103c657600080fd5b6103f160017f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbd610862565b60008051602061089e8339815191521461040d5761040d610887565b6104168461065a565b8015610488576000846001600160a01b0316838360405161043892919061081b565b600060405180830381855af49150503d8060008114610473576040519150601f19603f3d011682016040523d82523d6000602084013e610478565b606091505b505090508061048657600080fd5b505b61028483610599565b610499610346565b6104b55760405162461bcd60e51b81526004016101d89061082b565b6104dd817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b03166104fd6000805160206108be8339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b3660008037600080366000845af43d6000803e808015610554573d6000f35b3d6000fd5b6105628161065a565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b6001600160a01b0381166105ef5760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f72206973206164647265737328302900000000000060448201526064016101d8565b806001600160a01b031661060f6000805160206108be8339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a36101ea816000805160206108be83398151915255565b803b6106ce5760405162461bcd60e51b815260206004820152603b60248201527f43616e6e6f742073657420612070726f787920696d706c656d656e746174696f60448201527f6e20746f2061206e6f6e2d636f6e74726163742061646472657373000000000060648201526084016101d8565b60008051602061089e83398151915255565b80356001600160a01b03811681146106f757600080fd5b919050565b60008083601f84011261070e57600080fd5b50813567ffffffffffffffff81111561072657600080fd5b60208301915083602082850101111561073e57600080fd5b9250929050565b60006020828403121561075757600080fd5b610760826106e0565b9392505050565b6000806000806060858703121561077d57600080fd5b610786856106e0565b9350610794602086016106e0565b9250604085013567ffffffffffffffff8111156107b057600080fd5b6107bc878288016106fc565b95989497509550505050565b6000806000604084860312156107dd57600080fd5b6107e6846106e0565b9250602084013567ffffffffffffffff81111561080257600080fd5b61080e868287016106fc565b9497909650939450505050565b8183823760009101908152919050565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b60008282101561088257634e487b7160e01b600052601160045260246000fd5b500390565b634e487b7160e01b600052600160045260246000fdfe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa2646970667358221220c9221f795d84ec78bb6a84a3cb3a78aae0a56dca53a44a29dc80384cd96fa72864736f6c63430008070033", + "libraries": {}, + "devdoc": { + "kind": "dev", + "methods": { + "admin()": { + "returns": { + "_0": "The address of the proxy admin/it's also the governor." + } + }, + "implementation()": { + "returns": { + "_0": "The address of the implementation." + } + }, + "initialize(address,address,bytes)": { + "details": "Contract initializer with Governor enforcement", + "params": { + "_data": "Data to send as msg.data to the implementation to initialize the proxied contract. It should include the signature and the parameters of the function to be called, as described in https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding. This parameter is optional, if no data is given the initialization call to proxied contract will be skipped.", + "_initGovernor": "Address of the initial Governor.", + "_logic": "Address of the initial implementation." + } + }, + "transferGovernance(address)": { + "params": { + "_newGovernor": "Address of the new Governor" + } + }, + "upgradeTo(address)": { + "details": "Upgrade the backing implementation of the proxy. Only the admin can call this function.", + "params": { + "newImplementation": "Address of the new implementation." + } + }, + "upgradeToAndCall(address,bytes)": { + "details": "Upgrade the backing implementation of the proxy and call a function on the new implementation. This is useful to initialize the proxied contract.", + "params": { + "data": "Data to send as msg.data in the low level call. It should include the signature and the parameters of the function to be called, as described in https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.", + "newImplementation": "Address of the new implementation." + } + } + }, + "version": 1 + }, + "userdoc": { + "kind": "user", + "methods": { + "claimGovernance()": { + "notice": "Claim Governance of the contract to a new account (`newGovernor`). Can only be called by the new Governor." + }, + "governor()": { + "notice": "Returns the address of the current Governor." + }, + "isGovernor()": { + "notice": "Returns true if the caller is the current Governor." + }, + "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" + } + }, + "notice": "OETHDripperProxy delegates calls to a OETHDripper implementation", + "version": 1 + }, + "storageLayout": { + "storage": [], + "types": null + } +} \ No newline at end of file diff --git a/contracts/deployments/holesky/OETHHarvester.json b/contracts/deployments/holesky/OETHHarvester.json new file mode 100644 index 0000000000..bfc4c84482 --- /dev/null +++ b/contracts/deployments/holesky/OETHHarvester.json @@ -0,0 +1,1044 @@ +{ + "address": "0x22b00a89531E199bd90eC162F9810298b9FBC8b3", + "abi": [ + { + "inputs": [ + { + "internalType": "address", + "name": "_vault", + "type": "address" + }, + { + "internalType": "address", + "name": "_wethAddress", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "actualBalance", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minExpected", + "type": "uint256" + } + ], + "name": "BalanceMismatchAfterSwap", + "type": "error" + }, + { + "inputs": [], + "name": "EmptyAddress", + "type": "error" + }, + { + "inputs": [], + "name": "EmptyBalancerPoolId", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + } + ], + "name": "InvalidCurvePoolAssetIndex", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidHarvestRewardBps", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidSlippageBps", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "enum BaseHarvester.SwapPlatform", + "name": "swapPlatform", + "type": "uint8" + } + ], + "name": "InvalidSwapPlatform", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + } + ], + "name": "InvalidTokenInSwapPath", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidUniswapV2PathLength", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "actualBalance", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minExpected", + "type": "uint256" + } + ], + "name": "SlippageError", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "strategyAddress", + "type": "address" + } + ], + "name": "UnsupportedStrategy", + "type": "error" + }, + { + "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": 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": "newProceedsAddress", + "type": "address" + } + ], + "name": "RewardProceedsAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "farmer", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "protcolYield", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "farmerFee", + "type": "uint256" + } + ], + "name": "RewardProceedsTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "tokenAddress", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint16", + "name": "allowedSlippageBps", + "type": "uint16" + }, + { + "indexed": false, + "internalType": "uint16", + "name": "harvestRewardBps", + "type": "uint16" + }, + { + "indexed": false, + "internalType": "enum BaseHarvester.SwapPlatform", + "name": "swapPlatform", + "type": "uint8" + }, + { + "indexed": false, + "internalType": "address", + "name": "swapPlatformAddr", + "type": "address" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "swapData", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "liquidationLimit", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bool", + "name": "doSwapRewardToken", + "type": "bool" + } + ], + "name": "RewardTokenConfigUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "rewardToken", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "swappedInto", + "type": "address" + }, + { + "indexed": false, + "internalType": "enum BaseHarvester.SwapPlatform", + "name": "swapPlatform", + "type": "uint8" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + } + ], + "name": "RewardTokenSwapped", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "strategyAddress", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "isSupported", + "type": "bool" + } + ], + "name": "SupportedStrategyUpdate", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "balancerPoolId", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "baseTokenAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "baseTokenDecimals", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "claimGovernance", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "curvePoolIndices", + "outputs": [ + { + "internalType": "uint128", + "name": "rewardTokenIndex", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "baseTokenIndex", + "type": "uint128" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "governor", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_strategyAddr", + "type": "address" + } + ], + "name": "harvestAndSwap", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_strategyAddr", + "type": "address" + }, + { + "internalType": "address", + "name": "_rewardTo", + "type": "address" + } + ], + "name": "harvestAndSwap", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "isGovernor", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "rewardProceedsAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "rewardTokenConfigs", + "outputs": [ + { + "internalType": "uint16", + "name": "allowedSlippageBps", + "type": "uint16" + }, + { + "internalType": "uint16", + "name": "harvestRewardBps", + "type": "uint16" + }, + { + "internalType": "address", + "name": "swapPlatformAddr", + "type": "address" + }, + { + "internalType": "bool", + "name": "doSwapRewardToken", + "type": "bool" + }, + { + "internalType": "enum BaseHarvester.SwapPlatform", + "name": "swapPlatform", + "type": "uint8" + }, + { + "internalType": "uint256", + "name": "liquidationLimit", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_rewardProceedsAddress", + "type": "address" + } + ], + "name": "setRewardProceedsAddress", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_tokenAddress", + "type": "address" + }, + { + "components": [ + { + "internalType": "uint16", + "name": "allowedSlippageBps", + "type": "uint16" + }, + { + "internalType": "uint16", + "name": "harvestRewardBps", + "type": "uint16" + }, + { + "internalType": "address", + "name": "swapPlatformAddr", + "type": "address" + }, + { + "internalType": "bool", + "name": "doSwapRewardToken", + "type": "bool" + }, + { + "internalType": "enum BaseHarvester.SwapPlatform", + "name": "swapPlatform", + "type": "uint8" + }, + { + "internalType": "uint256", + "name": "liquidationLimit", + "type": "uint256" + } + ], + "internalType": "struct BaseHarvester.RewardTokenConfig", + "name": "tokenConfig", + "type": "tuple" + }, + { + "internalType": "bytes", + "name": "swapData", + "type": "bytes" + } + ], + "name": "setRewardTokenConfig", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_strategyAddress", + "type": "address" + }, + { + "internalType": "bool", + "name": "_isSupported", + "type": "bool" + } + ], + "name": "setSupportedStrategy", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "supportedStrategies", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "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": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "uniswapV2Path", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "uniswapV3Path", + "outputs": [ + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "vaultAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + } + ], + "transactionHash": "0x4b3113aba3207e3c1ef50452c3ee4f5c18a1606f38f31864acd0bb872f1c8baf", + "receipt": { + "to": null, + "from": "0x1b94CA50D3Ad9f8368851F8526132272d1a5028C", + "contractAddress": "0x22b00a89531E199bd90eC162F9810298b9FBC8b3", + "transactionIndex": 61, + "gasUsed": "2857566", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000020000000000000000001800000000000000000000000000000000000004000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000010000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000100000000", + "blockHash": "0x14116552a1bab414922c64f6ccf8f1135e30b3e731c71bce315c90c9c8cb2fc5", + "transactionHash": "0x4b3113aba3207e3c1ef50452c3ee4f5c18a1606f38f31864acd0bb872f1c8baf", + "logs": [ + { + "transactionIndex": 61, + "blockNumber": 1405153, + "transactionHash": "0x4b3113aba3207e3c1ef50452c3ee4f5c18a1606f38f31864acd0bb872f1c8baf", + "address": "0x22b00a89531E199bd90eC162F9810298b9FBC8b3", + "topics": [ + "0xc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000001b94ca50d3ad9f8368851f8526132272d1a5028c" + ], + "data": "0x", + "logIndex": 495, + "blockHash": "0x14116552a1bab414922c64f6ccf8f1135e30b3e731c71bce315c90c9c8cb2fc5" + } + ], + "blockNumber": 1405153, + "cumulativeGasUsed": "24006246", + "status": 1, + "byzantium": true + }, + "args": [ + "0x19d2bAaBA949eFfa163bFB9efB53ed8701aA5dD9", + "0x94373a4919b3240d86ea41593d5eba789fef3848" + ], + "numDeployments": 1, + "solcInputHash": "da4c2bc4af0be4b969e54f8b43895033", + "metadata": "{\"compiler\":{\"version\":\"0.8.7+commit.e28d00a7\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_vault\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_wethAddress\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"actualBalance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"minExpected\",\"type\":\"uint256\"}],\"name\":\"BalanceMismatchAfterSwap\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"EmptyAddress\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"EmptyBalancerPoolId\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"InvalidCurvePoolAssetIndex\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidHarvestRewardBps\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSlippageBps\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"enum BaseHarvester.SwapPlatform\",\"name\":\"swapPlatform\",\"type\":\"uint8\"}],\"name\":\"InvalidSwapPlatform\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"InvalidTokenInSwapPath\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidUniswapV2PathLength\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"actualBalance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"minExpected\",\"type\":\"uint256\"}],\"name\":\"SlippageError\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"strategyAddress\",\"type\":\"address\"}],\"name\":\"UnsupportedStrategy\",\"type\":\"error\"},{\"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\":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\":\"newProceedsAddress\",\"type\":\"address\"}],\"name\":\"RewardProceedsAddressChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"farmer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"protcolYield\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"farmerFee\",\"type\":\"uint256\"}],\"name\":\"RewardProceedsTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"tokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"allowedSlippageBps\",\"type\":\"uint16\"},{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"harvestRewardBps\",\"type\":\"uint16\"},{\"indexed\":false,\"internalType\":\"enum BaseHarvester.SwapPlatform\",\"name\":\"swapPlatform\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"swapPlatformAddr\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"swapData\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"liquidationLimit\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"doSwapRewardToken\",\"type\":\"bool\"}],\"name\":\"RewardTokenConfigUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"rewardToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"swappedInto\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"enum BaseHarvester.SwapPlatform\",\"name\":\"swapPlatform\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountIn\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountOut\",\"type\":\"uint256\"}],\"name\":\"RewardTokenSwapped\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"strategyAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"isSupported\",\"type\":\"bool\"}],\"name\":\"SupportedStrategyUpdate\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"balancerPoolId\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"baseTokenAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"baseTokenDecimals\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"claimGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"curvePoolIndices\",\"outputs\":[{\"internalType\":\"uint128\",\"name\":\"rewardTokenIndex\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"baseTokenIndex\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"governor\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_strategyAddr\",\"type\":\"address\"}],\"name\":\"harvestAndSwap\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_strategyAddr\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_rewardTo\",\"type\":\"address\"}],\"name\":\"harvestAndSwap\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isGovernor\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rewardProceedsAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"rewardTokenConfigs\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"allowedSlippageBps\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"harvestRewardBps\",\"type\":\"uint16\"},{\"internalType\":\"address\",\"name\":\"swapPlatformAddr\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"doSwapRewardToken\",\"type\":\"bool\"},{\"internalType\":\"enum BaseHarvester.SwapPlatform\",\"name\":\"swapPlatform\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"liquidationLimit\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_rewardProceedsAddress\",\"type\":\"address\"}],\"name\":\"setRewardProceedsAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_tokenAddress\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint16\",\"name\":\"allowedSlippageBps\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"harvestRewardBps\",\"type\":\"uint16\"},{\"internalType\":\"address\",\"name\":\"swapPlatformAddr\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"doSwapRewardToken\",\"type\":\"bool\"},{\"internalType\":\"enum BaseHarvester.SwapPlatform\",\"name\":\"swapPlatform\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"liquidationLimit\",\"type\":\"uint256\"}],\"internalType\":\"struct BaseHarvester.RewardTokenConfig\",\"name\":\"tokenConfig\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"swapData\",\"type\":\"bytes\"}],\"name\":\"setRewardTokenConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_strategyAddress\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"_isSupported\",\"type\":\"bool\"}],\"name\":\"setSupportedStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"supportedStrategies\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"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\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"uniswapV2Path\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"uniswapV3Path\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"vaultAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"harvestAndSwap(address)\":{\"details\":\"Collect reward tokens from a specific strategy and swap them for base token on the configured swap platform. Can be called by anyone. Rewards incentivizing the caller are sent to the caller of this function.\",\"params\":{\"_strategyAddr\":\"Address of the strategy to collect rewards from\"}},\"harvestAndSwap(address,address)\":{\"details\":\"Collect reward tokens from a specific strategy and swap them for base token on the configured swap platform. Can be called by anyone\",\"params\":{\"_rewardTo\":\"Address where to send a share of harvest rewards to as an incentive for executing this function\",\"_strategyAddr\":\"Address of the strategy to collect rewards from\"}},\"setRewardProceedsAddress(address)\":{\"params\":{\"_rewardProceedsAddress\":\"Address of the reward token\"}},\"setRewardTokenConfig(address,(uint16,uint16,address,bool,uint8,uint256),bytes)\":{\"details\":\"Add/update a reward token configuration that holds harvesting config variables\",\"params\":{\"_tokenAddress\":\"Address of the reward token\",\"swapData\":\"Additional data required for swapping\",\"tokenConfig\":\".swapPlatform SwapPlatform to use for Swapping\"}},\"setSupportedStrategy(address,bool)\":{\"details\":\"Flags a strategy as supported or not supported one\",\"params\":{\"_isSupported\":\"Bool marking strategy as supported or not supported\",\"_strategyAddress\":\"Address of the strategy\"}},\"transferGovernance(address)\":{\"params\":{\"_newGovernor\":\"Address of the new Governor\"}},\"transferToken(address,uint256)\":{\"details\":\"Transfer token to governor. Intended for recovering tokens stuck in contract, i.e. mistaken sends.\",\"params\":{\"_amount\":\"Amount of the asset to transfer\",\"_asset\":\"Address for the asset\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"baseTokenAddress()\":{\"notice\":\"All tokens are swapped to this token before it gets transferred to the `rewardProceedsAddress`. USDT for OUSD and WETH for OETH.*\"},\"claimGovernance()\":{\"notice\":\"Claim Governance of the contract to a new account (`newGovernor`). Can only be called by the new Governor.\"},\"governor()\":{\"notice\":\"Returns the address of the current Governor.\"},\"isGovernor()\":{\"notice\":\"Returns true if the caller is the current Governor.\"},\"rewardProceedsAddress()\":{\"notice\":\"Address receiving rewards proceeds. Initially the Vault contract later will possibly be replaced by another contract that eases out rewards distribution.*\"},\"setRewardProceedsAddress(address)\":{\"notice\":\"Set the Address receiving rewards proceeds.\"},\"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\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/harvest/OETHHarvester.sol\":\"OETHHarvester\"},\"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/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\",\"keccak256\":\"0xfaad496c1c944b6259b7dc70b4865eb1775d6402bc0c81b38a0b24d9f525ae37\",\"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/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 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 uint256 balance = IERC20(_swapToken).balanceOf(address(this));\\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 transfering `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 protcolYield = baseTokenBalance - farmerFee;\\n\\n baseToken.safeTransfer(rewardProceedsAddress, protcolYield);\\n baseToken.safeTransfer(_rewardTo, farmerFee);\\n emit RewardProceedsTransferred(\\n baseTokenAddress,\\n _rewardTo,\\n protcolYield,\\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\",\"keccak256\":\"0x909d6fcd5e294f04e1106bc0bedd344f5efc305db053cc678764ac64670df00d\",\"license\":\"MIT\"},\"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\",\"keccak256\":\"0x67255aabc4a8ec5d6650b3ab1daedffa093d8f6c324ee92281581c05990098bc\",\"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/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/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\",\"keccak256\":\"0x597796f9c5b3d174acbec8b520c633695c10d87762f7a0a7fec49b291694d7de\",\"license\":\"MIT\"},\"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\",\"keccak256\":\"0x3fdf2b91880f2b669202cc43bdceaf9d01537a9b955fc7a51159fb04fdbc68d4\",\"license\":\"MIT\"},\"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\",\"keccak256\":\"0xe32b76d23705979a297b164718aefa6b08e0ec3830883c020a5ac68d332a1dd2\",\"license\":\"MIT\"},\"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\",\"keccak256\":\"0x65e40829ff1f51c6c64fe991ed6a536b413ced85b9d9aa852d37fa14966d474c\",\"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/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\",\"keccak256\":\"0x5e17bb3db9f9e1014b7c5c836547f8fa81e02af7568c0bb8f2a2e0e7c2192db4\",\"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/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": "0x60e06040523480156200001157600080fd5b506040516200352f3803806200352f833981016040819052620000349162000215565b81816200004e336000805160206200350f83398151915255565b6000805160206200350f833981519152546040516001600160a01b03909116906000907fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a908290a36001600160a01b038216620000aa57600080fd5b6001600160a01b038116620000be57600080fd5b606082811b6001600160601b03199081166080529082901b1660a052620000f181620000ff602090811b62000d3217901c565b60c052506200027992505050565b600080826001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b1580156200013c57600080fd5b505afa15801562000151573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200017791906200024d565b60ff169050600481101580156200018f575060128111155b620001f25760405162461bcd60e51b815260206004820152602960248201527f546f6b656e206d75737420686176652073756666696369656e7420646563696d604482015268616c20706c6163657360b81b606482015260840160405180910390fd5b92915050565b80516001600160a01b03811681146200021057600080fd5b919050565b600080604083850312156200022957600080fd5b6200023483620001f8565b91506200024460208401620001f8565b90509250929050565b6000602082840312156200026057600080fd5b815160ff811681146200027257600080fd5b9392505050565b60805160601c60a05160601c60c05161320c62000303600039600081816102910152611a8401526000818161026a015281816110630152818161115c0152818161128001528181611486015281816114ca01528181611b3701528181611bbd01528181611cea01526122a70152600081816101a301528181610539015261158b015261320c6000f3fe608060405234801561001057600080fd5b506004361061012c5760003560e01c806382aa1c88116100ad578063d38bfff411610071578063d38bfff414610312578063da70696c14610325578063dac4db4e14610345578063e48d7fc514610358578063ee3be5f5146103ac57600080fd5b806382aa1c881461028c578063a994317f146102c1578063b13dc20a146102d4578063b76e83af146102e7578063c7af3352146102fa57600080fd5b8063548f5ae5116100f4578063548f5ae5146101c5578063587c8440146101d85780635d36b1901461024a57806365f6fa94146102525780637cb374bd1461026557600080fd5b80630c340a24146101315780631072cbea146101565780632579153d1461016b5780632dfbe8311461017e578063430bf08a1461019e575b600080fd5b6101396103cf565b6040516001600160a01b0390911681526020015b60405180910390f35b6101696101643660046126ec565b6103ec565b005b61016961017936600461264f565b610439565b61019161018c3660046125ae565b6108c8565b60405161014d9190612b1f565b6101397f000000000000000000000000000000000000000000000000000000000000000081565b6101696101d33660046125ae565b610962565b6102386101e63660046125ae565b6000602081905290815260409020805460019091015461ffff80831692620100008104909116916001600160a01b036401000000008304169160ff600160c01b8204811692600160c81b909204169086565b60405161014d96959493929190612cb0565b6101696109dd565b610169610260366004612621565b610a83565b6101397f000000000000000000000000000000000000000000000000000000000000000081565b6102b37f000000000000000000000000000000000000000000000000000000000000000081565b60405190815260200161014d565b6101696102cf3660046125e8565b610b0a565b6101696102e23660046125ae565b610b86565b600254610139906001600160a01b031681565b610302610c25565b604051901515815260200161014d565b6101696103203660046125ae565b610c56565b6102b36103333660046125ae565b60056020526000908152604090205481565b6101396103533660046126ec565b610cfa565b61038c6103663660046125ae565b6006602052600090815260409020546001600160801b0380821691600160801b90041682565b604080516001600160801b0393841681529290911660208301520161014d565b6103026103ba3660046125ae565b60016020526000908152604090205460ff1681565b60006103e76000805160206131b78339815191525490565b905090565b6103f4610c25565b6104195760405162461bcd60e51b815260040161041090612b5f565b60405180910390fd5b6104356104246103cf565b6001600160a01b0384169083610e21565b5050565b610441610c25565b61045d5760405162461bcd60e51b815260040161041090612b5f565b6103e861046d60208501856129aa565b61ffff1611156104905760405163faa3445560e01b815260040160405180910390fd5b6103e86104a360408501602086016129aa565b61ffff1611156104c657604051631633c8cd60e31b815260040160405180910390fd5b60006104d860608501604086016125ae565b90506001600160a01b03811661050157604051637138356f60e01b815260040160405180910390fd5b6001600160a01b03808616600090815260208190526040902080546401000000009004909116908590610534828261307b565b9050507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b888879e6040518163ffffffff1660e01b815260040160206040518083038186803b15801561059057600080fd5b505afa1580156105a4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105c891906125cb565b6040516315d5220f60e31b81526001600160a01b038881166004830152919091169063aea910789060240160206040518083038186803b15801561060b57600080fd5b505afa15801561061f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061064391906129c7565b50856001600160a01b0382161580159061066f5750826001600160a01b0316826001600160a01b031614155b15610689576106896001600160a01b038216836000610e89565b826001600160a01b0316826001600160a01b0316146106cd576106b76001600160a01b038216846000610e89565b6106cd6001600160a01b03821684600019610e89565b60006106df60a0880160808901612932565b905060008160038111156106f5576106f561301f565b14156107395761070686868a610fad565b6001600160a01b0389166000908152600360209081526040909120825161073393919291909101906124a4565b50610846565b600181600381111561074d5761074d61301f565b14156107815761075e86868a6110d9565b6001600160a01b038a166000908152600460205260409020610733929091612509565b60028160038111156107955761079561301f565b14156107c5576107a78686868b6111af565b6001600160a01b038916600090815260056020526040902055610846565b60038160038111156107d9576107d961301f565b141561082b576107eb8686868b611311565b6001600160a01b0389166000908152600660209081526040909120825192909101516001600160801b03908116600160801b029216919091179055610846565b806040516336cb1d2160e01b81526004016104109190612b32565b7f5eb6073ba3980477f03b1ce0dccba754d48454bbd65a115dcd42db65ca1fefd28861087560208a018a6129aa565b61088560408b0160208c016129aa565b84888b8b8e60a001358f60600160208101906108a191906128df565b6040516108b699989796959493929190612aa0565b60405180910390a15050505050505050565b600460205260009081526040902080546108e190612fb3565b80601f016020809104026020016040519081016040528092919081815260200182805461090d90612fb3565b801561095a5780601f1061092f5761010080835404028352916020019161095a565b820191906000526020600020905b81548152906001019060200180831161093d57829003601f168201915b505050505081565b7f53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac4535805460028114156109c75760405162461bcd60e51b815260206004820152600e60248201526d1499595b9d1c985b9d0818d85b1b60921b6044820152606401610410565b600282556109d58333611500565b506001905550565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b031614610a785760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b6064820152608401610410565b610a8133611667565b565b610a8b610c25565b610aa75760405162461bcd60e51b815260040161041090612b5f565b6001600160a01b038216600081815260016020908152604091829020805460ff19168515159081179091558251938452908301527f013ed61add17cbfcbbd95bf8543da67c89658c5477d3f3199a1a2d58ecf1913f910160405180910390a15050565b7f53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac453580546002811415610b6f5760405162461bcd60e51b815260206004820152600e60248201526d1499595b9d1c985b9d0818d85b1b60921b6044820152606401610410565b60028255610b7d8484611500565b50600190555050565b610b8e610c25565b610baa5760405162461bcd60e51b815260040161041090612b5f565b6001600160a01b038116610bd157604051637138356f60e01b815260040160405180910390fd5b600280546001600160a01b0319166001600160a01b0383169081179091556040519081527f50f4ca9002119593802480c412cb5e106ae726647a31dcf8a7e7ed4e6794bf5e9060200160405180910390a150565b6000610c3d6000805160206131b78339815191525490565b6001600160a01b0316336001600160a01b031614905090565b610c5e610c25565b610c7a5760405162461bcd60e51b815260040161041090612b5f565b610ca2817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b0316610cc26000805160206131b78339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b60036020528160005260406000208181548110610d1657600080fd5b6000918252602090912001546001600160a01b03169150829050565b600080826001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b158015610d6e57600080fd5b505afa158015610d82573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610da69190612a21565b60ff16905060048110158015610dbd575060128111155b610e1b5760405162461bcd60e51b815260206004820152602960248201527f546f6b656e206d75737420686176652073756666696369656e7420646563696d604482015268616c20706c6163657360b81b6064820152608401610410565b92915050565b6040516001600160a01b038316602482015260448101829052610e8490849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915261172b565b505050565b801580610f125750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e9060440160206040518083038186803b158015610ed857600080fd5b505afa158015610eec573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f1091906129c7565b155b610f7d5760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b6064820152608401610410565b6040516001600160a01b038316602482015260448101829052610e8490849063095ea7b360e01b90606401610e4d565b6060610fbb83850185612718565b80519091506002811015610fe2576040516360fa33db60e11b815260040160405180910390fd5b826001600160a01b031682600081518110610fff57610fff613035565b60200260200101516001600160a01b031614611059578160008151811061102857611028613035565b602002602001015160405163280d94a560e21b815260040161041091906001600160a01b0391909116815260200190565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168261108f600184612f37565b8151811061109f5761109f613035565b60200260200101516001600160a01b0316146110d157816110c1600183612f37565b8151811061102857611028613035565b509392505050565b828260006110ea6014828486612dbe565b6110f391612f4e565b60601c90506001600160a01b038416811461112c5760405163280d94a560e21b81526001600160a01b0382166004820152602401610410565b8585611139601485612f37565b611144928290612dbe565b61114d91612f4e565b60601c90506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001681146111a65760405163280d94a560e21b81526001600160a01b0382166004820152602401610410565b50935093915050565b60006111bd84860186612919565b9050806111dd57604051634bdc2c9560e01b815260040160405180910390fd5b60405163160bf1c960e31b8152600481018290526001600160a01b03838116602483015284919082169063b05f8e489060440160806040518083038186803b15801561122857600080fd5b505afa15801561123c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061126091906129e0565b505060405163160bf1c960e31b8152600481018590526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660248301528416925063b05f8e48915060440160806040518083038186803b1580156112cc57600080fd5b505afa1580156112e0573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061130491906129e0565b5050505050949350505050565b60408051808201909152600080825260208201526113318486018661294f565b805160405163c661065760e01b81526001600160801b03909116600482015290915083906001600160a01b0382169063c66106579060240160206040518083038186803b15801561138157600080fd5b505afa158015611395573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113b991906125cb565b6001600160a01b0316836001600160a01b0316146113f55760405163d658230160e01b81526001600160a01b0384166004820152602401610410565b602082015160405163c661065760e01b81526001600160801b0390911660048201526001600160a01b0382169063c66106579060240160206040518083038186803b15801561144357600080fd5b505afa158015611457573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061147b91906125cb565b6001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316146114f75760405163d658230160e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166004820152602401610410565b50949350505050565b611509826117fd565b60008290506000816001600160a01b031663f6ca71b06040518163ffffffff1660e01b815260040160006040518083038186803b15801561154957600080fd5b505afa15801561155d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261158591908101906127be565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b888879e6040518163ffffffff1660e01b815260040160206040518083038186803b1580156115e257600080fd5b505afa1580156115f6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061161a91906125cb565b825190915060005b8181101561165e5761164e84828151811061163f5761163f613035565b6020026020010151878561189d565b61165781612fee565b9050611622565b50505050505050565b6001600160a01b0381166116bd5760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f7220697320616464726573732830290000000000006044820152606401610410565b806001600160a01b03166116dd6000805160206131b78339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a3611728816000805160206131b783398151915255565b50565b6000611780826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611d489092919063ffffffff16565b805190915015610e84578080602001905181019061179e91906128fc565b610e845760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610410565b6001600160a01b03811660009081526001602052604090205460ff1661184157604051630211444960e11b81526001600160a01b0382166004820152602401610410565b6000819050806001600160a01b0316635a063f636040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561188157600080fd5b505af1158015611895573d6000803e3d6000fd5b505050505050565b6001600160a01b03808416600090815260208181526040808320815160c081018352815461ffff8082168352620100008204169482019490945264010000000084049095169185019190915260ff600160c01b830481161515606086015292939290916080840191600160c81b90910416600381111561191f5761191f61301f565b60038111156119305761193061301f565b81526020016001820154815250509050806060015161194f5750505050565b6040516370a0823160e01b81523060048201526000906001600160a01b038616906370a082319060240160206040518083038186803b15801561199157600080fd5b505afa1580156119a5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119c991906129c7565b9050806119d7575050505050565b60a0820151156119f2576119ef818360a00151611d61565b90505b6040516315d5220f60e31b81526001600160a01b0386811660048301526000919085169063aea910789060240160206040518083038186803b158015611a3757600080fd5b505afa158015611a4b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a6f91906129c7565b90506000670de0b6b3a7640000612710611adb7f0000000000000000000000000000000000000000000000000000000000000000611aac8b610d32565b88518790611abc90612710612f14565b611aca9061ffff168a612ef5565b611ad49190612ef5565b9190611d77565b611ae59190612de8565b611aef9190612de8565b90506000611b08856080015186604001518a8786611dd9565b905081811015611b35576040516302d96fff60e41b81526004810182905260248101839052604401610410565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316886001600160a01b03167fa861903141bc68b536d5048a576afcc645630e1b18a4296ef34cbd4d1407f70987608001518785604051611ba093929190612b40565b60405180910390a36040516370a0823160e01b81523060048201527f0000000000000000000000000000000000000000000000000000000000000000906000906001600160a01b038316906370a082319060240160206040518083038186803b158015611c0c57600080fd5b505afa158015611c20573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c4491906129c7565b905082811015611c715760405163315d50df60e11b81526004810182905260248101849052604401610410565b6020870151600090611c8b90859061ffff16612710611e9d565b90506000611c998284612f37565b600254909150611cb6906001600160a01b03868116911683610e21565b611cca6001600160a01b0385168c84610e21565b604080516001600160a01b038d81168252602082018490529181018490527f0000000000000000000000000000000000000000000000000000000000000000909116907f42e60aae8f000883c46e2f449fa76268e374ce1b962f46ca9360ab98b18f57999060600160405180910390a2505050505050505050505050565b6060611d578484600085611eb6565b90505b9392505050565b6000818310611d705781611d5a565b5090919050565b600081831115611da757611da0611d8e8385612f37565b611d9990600a612e4d565b8590611fde565b9350611dd1565b81831015611dd157611dce611dbc8484612f37565b611dc790600a612e4d565b8590611fea565b93505b509192915050565b600080866003811115611dee57611dee61301f565b1415611e0757611e0085858585611ff6565b9050611e94565b6001866003811115611e1b57611e1b61301f565b1415611e2d57611e0085858585612125565b6002866003811115611e4157611e4161301f565b1415611e5357611e0085858585612270565b6003866003811115611e6757611e6761301f565b1415611e7957611e0085858585612392565b856040516336cb1d2160e01b81526004016104109190612b32565b95945050505050565b600080611eaa8585611fde565b9050611e948184611fea565b606082471015611f175760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610410565b843b611f655760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610410565b600080866001600160a01b03168587604051611f819190612a84565b60006040518083038185875af1925050503d8060008114611fbe576040519150601f19603f3d011682016040523d82523d6000602084013e611fc3565b606091505b5091509150611fd382828661246b565b979650505050505050565b6000611d5a8284612ef5565b6000611d5a8284612de8565b6001600160a01b03831660009081526003602090815260408083208054825181850281018501909352808352849383018282801561205d57602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161203f575b505050505090506000866001600160a01b03166338ed173986868530426040518663ffffffff1660e01b815260040161209a959493929190612cf8565b600060405180830381600087803b1580156120b457600080fd5b505af11580156120c8573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526120f09190810190612853565b905080600182516121019190612f37565b8151811061211157612111613035565b602002602001015192505050949350505050565b6001600160a01b0383166000908152600460205260408120805482919061214b90612fb3565b80601f016020809104026020016040519081016040528092919081815260200182805461217790612fb3565b80156121c45780601f10612199576101008083540402835291602001916121c4565b820191906000526020600020905b8154815290600101906020018083116121a757829003601f168201915b50506040805160a0810182528581523060208201524281830152606081018a905260808101899052905163c04b8d5960e01b8152949550936001600160a01b038b16935063c04b8d59925061221e91508490600401612b96565b602060405180830381600087803b15801561223857600080fd5b505af115801561224c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fd391906129c7565b6001600160a01b03838116600081815260056020908152604080832054815160c081018352818152808401859052808301959095527f0000000000000000000000000000000000000000000000000000000000000000861660608087019190915260808087018a90528351808601855286815260a0880152835190810184523080825294810186905280840194909452830184905290516352bbbe2960e01b81529294909392908916906352bbbe299061233490859085908a904290600401612bee565b602060405180830381600087803b15801561234e57600080fd5b505af1158015612362573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061238691906129c7565b98975050505050505050565b6001600160a01b0383811660009081526006602090815260408083208151808301835290546001600160801b03808216808452600160801b909204169382018490529151630b68372160e31b81526004810192909252602482019290925260448101869052606481018590529192909190871690635b41b90890608401602060405180830381600087803b15801561242957600080fd5b505af115801561243d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061246191906129c7565b9695505050505050565b6060831561247a575081611d5a565b82511561248a5782518084602001fd5b8160405162461bcd60e51b81526004016104109190612b1f565b8280548282559060005260206000209081019282156124f9579160200282015b828111156124f957825182546001600160a01b0319166001600160a01b039091161782556020909201916001909101906124c4565b5061250592915061257d565b5090565b82805461251590612fb3565b90600052602060002090601f01602090048101928261253757600085556124f9565b82601f106125505782800160ff198235161785556124f9565b828001600101855582156124f9579182015b828111156124f9578235825591602001919060010190612562565b5b80821115612505576000815560010161257e565b80356001600160801b03811681146125a957600080fd5b919050565b6000602082840312156125c057600080fd5b8135611d5a81613176565b6000602082840312156125dd57600080fd5b8151611d5a81613176565b600080604083850312156125fb57600080fd5b823561260681613176565b9150602083013561261681613176565b809150509250929050565b6000806040838503121561263457600080fd5b823561263f81613176565b915060208301356126168161318b565b60008060008084860361010081121561266757600080fd5b853561267281613176565b945060c0601f198201121561268657600080fd5b5060208501925060e085013567ffffffffffffffff808211156126a857600080fd5b818701915087601f8301126126bc57600080fd5b8135818111156126cb57600080fd5b8860208285010111156126dd57600080fd5b95989497505060200194505050565b600080604083850312156126ff57600080fd5b823561270a81613176565b946020939093013593505050565b6000602080838503121561272b57600080fd5b823567ffffffffffffffff81111561274257600080fd5b8301601f8101851361275357600080fd5b803561276661276182612d9a565b612d69565b80828252848201915084840188868560051b870101111561278657600080fd5b600094505b838510156127b257803561279e81613176565b83526001949094019391850191850161278b565b50979650505050505050565b600060208083850312156127d157600080fd5b825167ffffffffffffffff8111156127e857600080fd5b8301601f810185136127f957600080fd5b805161280761276182612d9a565b80828252848201915084840188868560051b870101111561282757600080fd5b600094505b838510156127b257805161283f81613176565b83526001949094019391850191850161282c565b6000602080838503121561286657600080fd5b825167ffffffffffffffff81111561287d57600080fd5b8301601f8101851361288e57600080fd5b805161289c61276182612d9a565b80828252848201915084840188868560051b87010111156128bc57600080fd5b600094505b838510156127b25780518352600194909401939185019185016128c1565b6000602082840312156128f157600080fd5b8135611d5a8161318b565b60006020828403121561290e57600080fd5b8151611d5a8161318b565b60006020828403121561292b57600080fd5b5035919050565b60006020828403121561294457600080fd5b8135611d5a81613199565b60006040828403121561296157600080fd5b6040516040810181811067ffffffffffffffff821117156129845761298461304b565b60405261299083612592565b815261299e60208401612592565b60208201529392505050565b6000602082840312156129bc57600080fd5b8135611d5a816131a6565b6000602082840312156129d957600080fd5b5051919050565b600080600080608085870312156129f657600080fd5b8451935060208501519250604085015191506060850151612a1681613176565b939692955090935050565b600060208284031215612a3357600080fd5b815160ff81168114611d5a57600080fd5b60008151808452612a5c816020860160208601612f83565b601f01601f19169290920160200192915050565b60048110612a8057612a8061301f565b9052565b60008251612a96818460208701612f83565b9190910192915050565b6001600160a01b038a8116825261ffff8a811660208401528916604083015260009061010090612ad3606085018b612a70565b8816608084015260a083018190528201859052610120858782850137600083870182015260c08301949094525090151560e0820152601f909201601f1916909101019695505050505050565b602081526000611d5a6020830184612a44565b60208101610e1b8284612a70565b60608101612b4e8286612a70565b602082019390935260400152919050565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b602081526000825160a06020840152612bb260c0840182612a44565b905060018060a01b0360208501511660408401526040840151606084015260608401516080840152608084015160a08401528091505092915050565b60e08152845160e08201526000602086015160028110612c1057612c1061301f565b61010083015260408601516001600160a01b03908116610120840152606087015116610140830152608086015161016083015260a086015160c0610180840152612c5e6101a0840182612a44565b915050612c9e602083018680516001600160a01b039081168352602080830151151590840152604080830151909116908301526060908101511515910152565b60a082019390935260c0015292915050565b61ffff8781168252861660208201526001600160a01b0385166040820152831515606082015260c08101612ce76080830185612a70565b8260a0830152979650505050505050565b600060a082018783526020878185015260a0604085015281875180845260c086019150828901935060005b81811015612d485784516001600160a01b031683529383019391830191600101612d23565b50506001600160a01b03969096166060850152505050608001529392505050565b604051601f8201601f1916810167ffffffffffffffff81118282101715612d9257612d9261304b565b604052919050565b600067ffffffffffffffff821115612db457612db461304b565b5060051b60200190565b60008085851115612dce57600080fd5b83861115612ddb57600080fd5b5050820193919092039150565b600082612e0557634e487b7160e01b600052601260045260246000fd5b500490565b600181815b80851115612e45578160001904821115612e2b57612e2b613009565b80851615612e3857918102915b93841c9390800290612e0f565b509250929050565b6000611d5a8383600082612e6357506001610e1b565b81612e7057506000610e1b565b8160018114612e865760028114612e9057612eac565b6001915050610e1b565b60ff841115612ea157612ea1613009565b50506001821b610e1b565b5060208310610133831016604e8410600b8410161715612ecf575081810a610e1b565b612ed98383612e0a565b8060001904821115612eed57612eed613009565b029392505050565b6000816000190483118215151615612f0f57612f0f613009565b500290565b600061ffff83811690831681811015612f2f57612f2f613009565b039392505050565b600082821015612f4957612f49613009565b500390565b6bffffffffffffffffffffffff198135818116916014851015612f7b5780818660140360031b1b83161692505b505092915050565b60005b83811015612f9e578181015183820152602001612f86565b83811115612fad576000848401525b50505050565b600181811c90821680612fc757607f821691505b60208210811415612fe857634e487b7160e01b600052602260045260246000fd5b50919050565b600060001982141561300257613002613009565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b60008135610e1b8161318b565b60008135610e1b81613199565b8135613086816131a6565b61ffff8116905081548161ffff19821617835560208401356130a7816131a6565b63ffff00008160101b169050808363ffffffff1984161717845560408501356130cf81613176565b6001600160c01b0319929092169092179190911760209190911b640100000000600160c01b031617815561312661310860608401613061565b82805460ff60c01b191691151560c01b60ff60c01b16919091179055565b61313b6131356080840161306e565b82613149565b60a082013560018201555050565b600482106131595761315961301f565b805460ff60c81b191660c89290921b60ff60c81b16919091179055565b6001600160a01b038116811461172857600080fd5b801515811461172857600080fd5b6004811061172857600080fd5b61ffff8116811461172857600080fdfe7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa2646970667358221220a027d837b490da1a267b5f9d265801eb2ba7a5c697f983dfeceefae0e7d2981e64736f6c634300080700337bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a", + "deployedBytecode": "0x608060405234801561001057600080fd5b506004361061012c5760003560e01c806382aa1c88116100ad578063d38bfff411610071578063d38bfff414610312578063da70696c14610325578063dac4db4e14610345578063e48d7fc514610358578063ee3be5f5146103ac57600080fd5b806382aa1c881461028c578063a994317f146102c1578063b13dc20a146102d4578063b76e83af146102e7578063c7af3352146102fa57600080fd5b8063548f5ae5116100f4578063548f5ae5146101c5578063587c8440146101d85780635d36b1901461024a57806365f6fa94146102525780637cb374bd1461026557600080fd5b80630c340a24146101315780631072cbea146101565780632579153d1461016b5780632dfbe8311461017e578063430bf08a1461019e575b600080fd5b6101396103cf565b6040516001600160a01b0390911681526020015b60405180910390f35b6101696101643660046126ec565b6103ec565b005b61016961017936600461264f565b610439565b61019161018c3660046125ae565b6108c8565b60405161014d9190612b1f565b6101397f000000000000000000000000000000000000000000000000000000000000000081565b6101696101d33660046125ae565b610962565b6102386101e63660046125ae565b6000602081905290815260409020805460019091015461ffff80831692620100008104909116916001600160a01b036401000000008304169160ff600160c01b8204811692600160c81b909204169086565b60405161014d96959493929190612cb0565b6101696109dd565b610169610260366004612621565b610a83565b6101397f000000000000000000000000000000000000000000000000000000000000000081565b6102b37f000000000000000000000000000000000000000000000000000000000000000081565b60405190815260200161014d565b6101696102cf3660046125e8565b610b0a565b6101696102e23660046125ae565b610b86565b600254610139906001600160a01b031681565b610302610c25565b604051901515815260200161014d565b6101696103203660046125ae565b610c56565b6102b36103333660046125ae565b60056020526000908152604090205481565b6101396103533660046126ec565b610cfa565b61038c6103663660046125ae565b6006602052600090815260409020546001600160801b0380821691600160801b90041682565b604080516001600160801b0393841681529290911660208301520161014d565b6103026103ba3660046125ae565b60016020526000908152604090205460ff1681565b60006103e76000805160206131b78339815191525490565b905090565b6103f4610c25565b6104195760405162461bcd60e51b815260040161041090612b5f565b60405180910390fd5b6104356104246103cf565b6001600160a01b0384169083610e21565b5050565b610441610c25565b61045d5760405162461bcd60e51b815260040161041090612b5f565b6103e861046d60208501856129aa565b61ffff1611156104905760405163faa3445560e01b815260040160405180910390fd5b6103e86104a360408501602086016129aa565b61ffff1611156104c657604051631633c8cd60e31b815260040160405180910390fd5b60006104d860608501604086016125ae565b90506001600160a01b03811661050157604051637138356f60e01b815260040160405180910390fd5b6001600160a01b03808616600090815260208190526040902080546401000000009004909116908590610534828261307b565b9050507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b888879e6040518163ffffffff1660e01b815260040160206040518083038186803b15801561059057600080fd5b505afa1580156105a4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105c891906125cb565b6040516315d5220f60e31b81526001600160a01b038881166004830152919091169063aea910789060240160206040518083038186803b15801561060b57600080fd5b505afa15801561061f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061064391906129c7565b50856001600160a01b0382161580159061066f5750826001600160a01b0316826001600160a01b031614155b15610689576106896001600160a01b038216836000610e89565b826001600160a01b0316826001600160a01b0316146106cd576106b76001600160a01b038216846000610e89565b6106cd6001600160a01b03821684600019610e89565b60006106df60a0880160808901612932565b905060008160038111156106f5576106f561301f565b14156107395761070686868a610fad565b6001600160a01b0389166000908152600360209081526040909120825161073393919291909101906124a4565b50610846565b600181600381111561074d5761074d61301f565b14156107815761075e86868a6110d9565b6001600160a01b038a166000908152600460205260409020610733929091612509565b60028160038111156107955761079561301f565b14156107c5576107a78686868b6111af565b6001600160a01b038916600090815260056020526040902055610846565b60038160038111156107d9576107d961301f565b141561082b576107eb8686868b611311565b6001600160a01b0389166000908152600660209081526040909120825192909101516001600160801b03908116600160801b029216919091179055610846565b806040516336cb1d2160e01b81526004016104109190612b32565b7f5eb6073ba3980477f03b1ce0dccba754d48454bbd65a115dcd42db65ca1fefd28861087560208a018a6129aa565b61088560408b0160208c016129aa565b84888b8b8e60a001358f60600160208101906108a191906128df565b6040516108b699989796959493929190612aa0565b60405180910390a15050505050505050565b600460205260009081526040902080546108e190612fb3565b80601f016020809104026020016040519081016040528092919081815260200182805461090d90612fb3565b801561095a5780601f1061092f5761010080835404028352916020019161095a565b820191906000526020600020905b81548152906001019060200180831161093d57829003601f168201915b505050505081565b7f53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac4535805460028114156109c75760405162461bcd60e51b815260206004820152600e60248201526d1499595b9d1c985b9d0818d85b1b60921b6044820152606401610410565b600282556109d58333611500565b506001905550565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b031614610a785760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b6064820152608401610410565b610a8133611667565b565b610a8b610c25565b610aa75760405162461bcd60e51b815260040161041090612b5f565b6001600160a01b038216600081815260016020908152604091829020805460ff19168515159081179091558251938452908301527f013ed61add17cbfcbbd95bf8543da67c89658c5477d3f3199a1a2d58ecf1913f910160405180910390a15050565b7f53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac453580546002811415610b6f5760405162461bcd60e51b815260206004820152600e60248201526d1499595b9d1c985b9d0818d85b1b60921b6044820152606401610410565b60028255610b7d8484611500565b50600190555050565b610b8e610c25565b610baa5760405162461bcd60e51b815260040161041090612b5f565b6001600160a01b038116610bd157604051637138356f60e01b815260040160405180910390fd5b600280546001600160a01b0319166001600160a01b0383169081179091556040519081527f50f4ca9002119593802480c412cb5e106ae726647a31dcf8a7e7ed4e6794bf5e9060200160405180910390a150565b6000610c3d6000805160206131b78339815191525490565b6001600160a01b0316336001600160a01b031614905090565b610c5e610c25565b610c7a5760405162461bcd60e51b815260040161041090612b5f565b610ca2817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b0316610cc26000805160206131b78339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b60036020528160005260406000208181548110610d1657600080fd5b6000918252602090912001546001600160a01b03169150829050565b600080826001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b158015610d6e57600080fd5b505afa158015610d82573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610da69190612a21565b60ff16905060048110158015610dbd575060128111155b610e1b5760405162461bcd60e51b815260206004820152602960248201527f546f6b656e206d75737420686176652073756666696369656e7420646563696d604482015268616c20706c6163657360b81b6064820152608401610410565b92915050565b6040516001600160a01b038316602482015260448101829052610e8490849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915261172b565b505050565b801580610f125750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e9060440160206040518083038186803b158015610ed857600080fd5b505afa158015610eec573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f1091906129c7565b155b610f7d5760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b6064820152608401610410565b6040516001600160a01b038316602482015260448101829052610e8490849063095ea7b360e01b90606401610e4d565b6060610fbb83850185612718565b80519091506002811015610fe2576040516360fa33db60e11b815260040160405180910390fd5b826001600160a01b031682600081518110610fff57610fff613035565b60200260200101516001600160a01b031614611059578160008151811061102857611028613035565b602002602001015160405163280d94a560e21b815260040161041091906001600160a01b0391909116815260200190565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168261108f600184612f37565b8151811061109f5761109f613035565b60200260200101516001600160a01b0316146110d157816110c1600183612f37565b8151811061102857611028613035565b509392505050565b828260006110ea6014828486612dbe565b6110f391612f4e565b60601c90506001600160a01b038416811461112c5760405163280d94a560e21b81526001600160a01b0382166004820152602401610410565b8585611139601485612f37565b611144928290612dbe565b61114d91612f4e565b60601c90506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001681146111a65760405163280d94a560e21b81526001600160a01b0382166004820152602401610410565b50935093915050565b60006111bd84860186612919565b9050806111dd57604051634bdc2c9560e01b815260040160405180910390fd5b60405163160bf1c960e31b8152600481018290526001600160a01b03838116602483015284919082169063b05f8e489060440160806040518083038186803b15801561122857600080fd5b505afa15801561123c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061126091906129e0565b505060405163160bf1c960e31b8152600481018590526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660248301528416925063b05f8e48915060440160806040518083038186803b1580156112cc57600080fd5b505afa1580156112e0573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061130491906129e0565b5050505050949350505050565b60408051808201909152600080825260208201526113318486018661294f565b805160405163c661065760e01b81526001600160801b03909116600482015290915083906001600160a01b0382169063c66106579060240160206040518083038186803b15801561138157600080fd5b505afa158015611395573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113b991906125cb565b6001600160a01b0316836001600160a01b0316146113f55760405163d658230160e01b81526001600160a01b0384166004820152602401610410565b602082015160405163c661065760e01b81526001600160801b0390911660048201526001600160a01b0382169063c66106579060240160206040518083038186803b15801561144357600080fd5b505afa158015611457573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061147b91906125cb565b6001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316146114f75760405163d658230160e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166004820152602401610410565b50949350505050565b611509826117fd565b60008290506000816001600160a01b031663f6ca71b06040518163ffffffff1660e01b815260040160006040518083038186803b15801561154957600080fd5b505afa15801561155d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261158591908101906127be565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b888879e6040518163ffffffff1660e01b815260040160206040518083038186803b1580156115e257600080fd5b505afa1580156115f6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061161a91906125cb565b825190915060005b8181101561165e5761164e84828151811061163f5761163f613035565b6020026020010151878561189d565b61165781612fee565b9050611622565b50505050505050565b6001600160a01b0381166116bd5760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f7220697320616464726573732830290000000000006044820152606401610410565b806001600160a01b03166116dd6000805160206131b78339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a3611728816000805160206131b783398151915255565b50565b6000611780826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611d489092919063ffffffff16565b805190915015610e84578080602001905181019061179e91906128fc565b610e845760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610410565b6001600160a01b03811660009081526001602052604090205460ff1661184157604051630211444960e11b81526001600160a01b0382166004820152602401610410565b6000819050806001600160a01b0316635a063f636040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561188157600080fd5b505af1158015611895573d6000803e3d6000fd5b505050505050565b6001600160a01b03808416600090815260208181526040808320815160c081018352815461ffff8082168352620100008204169482019490945264010000000084049095169185019190915260ff600160c01b830481161515606086015292939290916080840191600160c81b90910416600381111561191f5761191f61301f565b60038111156119305761193061301f565b81526020016001820154815250509050806060015161194f5750505050565b6040516370a0823160e01b81523060048201526000906001600160a01b038616906370a082319060240160206040518083038186803b15801561199157600080fd5b505afa1580156119a5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119c991906129c7565b9050806119d7575050505050565b60a0820151156119f2576119ef818360a00151611d61565b90505b6040516315d5220f60e31b81526001600160a01b0386811660048301526000919085169063aea910789060240160206040518083038186803b158015611a3757600080fd5b505afa158015611a4b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a6f91906129c7565b90506000670de0b6b3a7640000612710611adb7f0000000000000000000000000000000000000000000000000000000000000000611aac8b610d32565b88518790611abc90612710612f14565b611aca9061ffff168a612ef5565b611ad49190612ef5565b9190611d77565b611ae59190612de8565b611aef9190612de8565b90506000611b08856080015186604001518a8786611dd9565b905081811015611b35576040516302d96fff60e41b81526004810182905260248101839052604401610410565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316886001600160a01b03167fa861903141bc68b536d5048a576afcc645630e1b18a4296ef34cbd4d1407f70987608001518785604051611ba093929190612b40565b60405180910390a36040516370a0823160e01b81523060048201527f0000000000000000000000000000000000000000000000000000000000000000906000906001600160a01b038316906370a082319060240160206040518083038186803b158015611c0c57600080fd5b505afa158015611c20573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c4491906129c7565b905082811015611c715760405163315d50df60e11b81526004810182905260248101849052604401610410565b6020870151600090611c8b90859061ffff16612710611e9d565b90506000611c998284612f37565b600254909150611cb6906001600160a01b03868116911683610e21565b611cca6001600160a01b0385168c84610e21565b604080516001600160a01b038d81168252602082018490529181018490527f0000000000000000000000000000000000000000000000000000000000000000909116907f42e60aae8f000883c46e2f449fa76268e374ce1b962f46ca9360ab98b18f57999060600160405180910390a2505050505050505050505050565b6060611d578484600085611eb6565b90505b9392505050565b6000818310611d705781611d5a565b5090919050565b600081831115611da757611da0611d8e8385612f37565b611d9990600a612e4d565b8590611fde565b9350611dd1565b81831015611dd157611dce611dbc8484612f37565b611dc790600a612e4d565b8590611fea565b93505b509192915050565b600080866003811115611dee57611dee61301f565b1415611e0757611e0085858585611ff6565b9050611e94565b6001866003811115611e1b57611e1b61301f565b1415611e2d57611e0085858585612125565b6002866003811115611e4157611e4161301f565b1415611e5357611e0085858585612270565b6003866003811115611e6757611e6761301f565b1415611e7957611e0085858585612392565b856040516336cb1d2160e01b81526004016104109190612b32565b95945050505050565b600080611eaa8585611fde565b9050611e948184611fea565b606082471015611f175760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610410565b843b611f655760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610410565b600080866001600160a01b03168587604051611f819190612a84565b60006040518083038185875af1925050503d8060008114611fbe576040519150601f19603f3d011682016040523d82523d6000602084013e611fc3565b606091505b5091509150611fd382828661246b565b979650505050505050565b6000611d5a8284612ef5565b6000611d5a8284612de8565b6001600160a01b03831660009081526003602090815260408083208054825181850281018501909352808352849383018282801561205d57602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161203f575b505050505090506000866001600160a01b03166338ed173986868530426040518663ffffffff1660e01b815260040161209a959493929190612cf8565b600060405180830381600087803b1580156120b457600080fd5b505af11580156120c8573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526120f09190810190612853565b905080600182516121019190612f37565b8151811061211157612111613035565b602002602001015192505050949350505050565b6001600160a01b0383166000908152600460205260408120805482919061214b90612fb3565b80601f016020809104026020016040519081016040528092919081815260200182805461217790612fb3565b80156121c45780601f10612199576101008083540402835291602001916121c4565b820191906000526020600020905b8154815290600101906020018083116121a757829003601f168201915b50506040805160a0810182528581523060208201524281830152606081018a905260808101899052905163c04b8d5960e01b8152949550936001600160a01b038b16935063c04b8d59925061221e91508490600401612b96565b602060405180830381600087803b15801561223857600080fd5b505af115801561224c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fd391906129c7565b6001600160a01b03838116600081815260056020908152604080832054815160c081018352818152808401859052808301959095527f0000000000000000000000000000000000000000000000000000000000000000861660608087019190915260808087018a90528351808601855286815260a0880152835190810184523080825294810186905280840194909452830184905290516352bbbe2960e01b81529294909392908916906352bbbe299061233490859085908a904290600401612bee565b602060405180830381600087803b15801561234e57600080fd5b505af1158015612362573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061238691906129c7565b98975050505050505050565b6001600160a01b0383811660009081526006602090815260408083208151808301835290546001600160801b03808216808452600160801b909204169382018490529151630b68372160e31b81526004810192909252602482019290925260448101869052606481018590529192909190871690635b41b90890608401602060405180830381600087803b15801561242957600080fd5b505af115801561243d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061246191906129c7565b9695505050505050565b6060831561247a575081611d5a565b82511561248a5782518084602001fd5b8160405162461bcd60e51b81526004016104109190612b1f565b8280548282559060005260206000209081019282156124f9579160200282015b828111156124f957825182546001600160a01b0319166001600160a01b039091161782556020909201916001909101906124c4565b5061250592915061257d565b5090565b82805461251590612fb3565b90600052602060002090601f01602090048101928261253757600085556124f9565b82601f106125505782800160ff198235161785556124f9565b828001600101855582156124f9579182015b828111156124f9578235825591602001919060010190612562565b5b80821115612505576000815560010161257e565b80356001600160801b03811681146125a957600080fd5b919050565b6000602082840312156125c057600080fd5b8135611d5a81613176565b6000602082840312156125dd57600080fd5b8151611d5a81613176565b600080604083850312156125fb57600080fd5b823561260681613176565b9150602083013561261681613176565b809150509250929050565b6000806040838503121561263457600080fd5b823561263f81613176565b915060208301356126168161318b565b60008060008084860361010081121561266757600080fd5b853561267281613176565b945060c0601f198201121561268657600080fd5b5060208501925060e085013567ffffffffffffffff808211156126a857600080fd5b818701915087601f8301126126bc57600080fd5b8135818111156126cb57600080fd5b8860208285010111156126dd57600080fd5b95989497505060200194505050565b600080604083850312156126ff57600080fd5b823561270a81613176565b946020939093013593505050565b6000602080838503121561272b57600080fd5b823567ffffffffffffffff81111561274257600080fd5b8301601f8101851361275357600080fd5b803561276661276182612d9a565b612d69565b80828252848201915084840188868560051b870101111561278657600080fd5b600094505b838510156127b257803561279e81613176565b83526001949094019391850191850161278b565b50979650505050505050565b600060208083850312156127d157600080fd5b825167ffffffffffffffff8111156127e857600080fd5b8301601f810185136127f957600080fd5b805161280761276182612d9a565b80828252848201915084840188868560051b870101111561282757600080fd5b600094505b838510156127b257805161283f81613176565b83526001949094019391850191850161282c565b6000602080838503121561286657600080fd5b825167ffffffffffffffff81111561287d57600080fd5b8301601f8101851361288e57600080fd5b805161289c61276182612d9a565b80828252848201915084840188868560051b87010111156128bc57600080fd5b600094505b838510156127b25780518352600194909401939185019185016128c1565b6000602082840312156128f157600080fd5b8135611d5a8161318b565b60006020828403121561290e57600080fd5b8151611d5a8161318b565b60006020828403121561292b57600080fd5b5035919050565b60006020828403121561294457600080fd5b8135611d5a81613199565b60006040828403121561296157600080fd5b6040516040810181811067ffffffffffffffff821117156129845761298461304b565b60405261299083612592565b815261299e60208401612592565b60208201529392505050565b6000602082840312156129bc57600080fd5b8135611d5a816131a6565b6000602082840312156129d957600080fd5b5051919050565b600080600080608085870312156129f657600080fd5b8451935060208501519250604085015191506060850151612a1681613176565b939692955090935050565b600060208284031215612a3357600080fd5b815160ff81168114611d5a57600080fd5b60008151808452612a5c816020860160208601612f83565b601f01601f19169290920160200192915050565b60048110612a8057612a8061301f565b9052565b60008251612a96818460208701612f83565b9190910192915050565b6001600160a01b038a8116825261ffff8a811660208401528916604083015260009061010090612ad3606085018b612a70565b8816608084015260a083018190528201859052610120858782850137600083870182015260c08301949094525090151560e0820152601f909201601f1916909101019695505050505050565b602081526000611d5a6020830184612a44565b60208101610e1b8284612a70565b60608101612b4e8286612a70565b602082019390935260400152919050565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b602081526000825160a06020840152612bb260c0840182612a44565b905060018060a01b0360208501511660408401526040840151606084015260608401516080840152608084015160a08401528091505092915050565b60e08152845160e08201526000602086015160028110612c1057612c1061301f565b61010083015260408601516001600160a01b03908116610120840152606087015116610140830152608086015161016083015260a086015160c0610180840152612c5e6101a0840182612a44565b915050612c9e602083018680516001600160a01b039081168352602080830151151590840152604080830151909116908301526060908101511515910152565b60a082019390935260c0015292915050565b61ffff8781168252861660208201526001600160a01b0385166040820152831515606082015260c08101612ce76080830185612a70565b8260a0830152979650505050505050565b600060a082018783526020878185015260a0604085015281875180845260c086019150828901935060005b81811015612d485784516001600160a01b031683529383019391830191600101612d23565b50506001600160a01b03969096166060850152505050608001529392505050565b604051601f8201601f1916810167ffffffffffffffff81118282101715612d9257612d9261304b565b604052919050565b600067ffffffffffffffff821115612db457612db461304b565b5060051b60200190565b60008085851115612dce57600080fd5b83861115612ddb57600080fd5b5050820193919092039150565b600082612e0557634e487b7160e01b600052601260045260246000fd5b500490565b600181815b80851115612e45578160001904821115612e2b57612e2b613009565b80851615612e3857918102915b93841c9390800290612e0f565b509250929050565b6000611d5a8383600082612e6357506001610e1b565b81612e7057506000610e1b565b8160018114612e865760028114612e9057612eac565b6001915050610e1b565b60ff841115612ea157612ea1613009565b50506001821b610e1b565b5060208310610133831016604e8410600b8410161715612ecf575081810a610e1b565b612ed98383612e0a565b8060001904821115612eed57612eed613009565b029392505050565b6000816000190483118215151615612f0f57612f0f613009565b500290565b600061ffff83811690831681811015612f2f57612f2f613009565b039392505050565b600082821015612f4957612f49613009565b500390565b6bffffffffffffffffffffffff198135818116916014851015612f7b5780818660140360031b1b83161692505b505092915050565b60005b83811015612f9e578181015183820152602001612f86565b83811115612fad576000848401525b50505050565b600181811c90821680612fc757607f821691505b60208210811415612fe857634e487b7160e01b600052602260045260246000fd5b50919050565b600060001982141561300257613002613009565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b60008135610e1b8161318b565b60008135610e1b81613199565b8135613086816131a6565b61ffff8116905081548161ffff19821617835560208401356130a7816131a6565b63ffff00008160101b169050808363ffffffff1984161717845560408501356130cf81613176565b6001600160c01b0319929092169092179190911760209190911b640100000000600160c01b031617815561312661310860608401613061565b82805460ff60c01b191691151560c01b60ff60c01b16919091179055565b61313b6131356080840161306e565b82613149565b60a082013560018201555050565b600482106131595761315961301f565b805460ff60c81b191660c89290921b60ff60c81b16919091179055565b6001600160a01b038116811461172857600080fd5b801515811461172857600080fd5b6004811061172857600080fd5b61ffff8116811461172857600080fdfe7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa2646970667358221220a027d837b490da1a267b5f9d265801eb2ba7a5c697f983dfeceefae0e7d2981e64736f6c63430008070033", + "libraries": {}, + "devdoc": { + "kind": "dev", + "methods": { + "harvestAndSwap(address)": { + "details": "Collect reward tokens from a specific strategy and swap them for base token on the configured swap platform. Can be called by anyone. Rewards incentivizing the caller are sent to the caller of this function.", + "params": { + "_strategyAddr": "Address of the strategy to collect rewards from" + } + }, + "harvestAndSwap(address,address)": { + "details": "Collect reward tokens from a specific strategy and swap them for base token on the configured swap platform. Can be called by anyone", + "params": { + "_rewardTo": "Address where to send a share of harvest rewards to as an incentive for executing this function", + "_strategyAddr": "Address of the strategy to collect rewards from" + } + }, + "setRewardProceedsAddress(address)": { + "params": { + "_rewardProceedsAddress": "Address of the reward token" + } + }, + "setRewardTokenConfig(address,(uint16,uint16,address,bool,uint8,uint256),bytes)": { + "details": "Add/update a reward token configuration that holds harvesting config variables", + "params": { + "_tokenAddress": "Address of the reward token", + "swapData": "Additional data required for swapping", + "tokenConfig": ".swapPlatform SwapPlatform to use for Swapping" + } + }, + "setSupportedStrategy(address,bool)": { + "details": "Flags a strategy as supported or not supported one", + "params": { + "_isSupported": "Bool marking strategy as supported or not supported", + "_strategyAddress": "Address of the strategy" + } + }, + "transferGovernance(address)": { + "params": { + "_newGovernor": "Address of the new Governor" + } + }, + "transferToken(address,uint256)": { + "details": "Transfer token to governor. Intended for recovering tokens stuck in contract, i.e. mistaken sends.", + "params": { + "_amount": "Amount of the asset to transfer", + "_asset": "Address for the asset" + } + } + }, + "version": 1 + }, + "userdoc": { + "kind": "user", + "methods": { + "baseTokenAddress()": { + "notice": "All tokens are swapped to this token before it gets transferred to the `rewardProceedsAddress`. USDT for OUSD and WETH for OETH.*" + }, + "claimGovernance()": { + "notice": "Claim Governance of the contract to a new account (`newGovernor`). Can only be called by the new Governor." + }, + "governor()": { + "notice": "Returns the address of the current Governor." + }, + "isGovernor()": { + "notice": "Returns true if the caller is the current Governor." + }, + "rewardProceedsAddress()": { + "notice": "Address receiving rewards proceeds. Initially the Vault contract later will possibly be replaced by another contract that eases out rewards distribution.*" + }, + "setRewardProceedsAddress(address)": { + "notice": "Set the Address receiving rewards proceeds." + }, + "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" + } + }, + "version": 1 + }, + "storageLayout": { + "storage": [ + { + "astId": 9253, + "contract": "contracts/harvest/OETHHarvester.sol:OETHHarvester", + "label": "rewardTokenConfigs", + "offset": 0, + "slot": "0", + "type": "t_mapping(t_address,t_struct(RewardTokenConfig)9248_storage)" + }, + { + "astId": 9257, + "contract": "contracts/harvest/OETHHarvester.sol:OETHHarvester", + "label": "supportedStrategies", + "offset": 0, + "slot": "1", + "type": "t_mapping(t_address,t_bool)" + }, + { + "astId": 9262, + "contract": "contracts/harvest/OETHHarvester.sol:OETHHarvester", + "label": "rewardProceedsAddress", + "offset": 0, + "slot": "2", + "type": "t_address" + }, + { + "astId": 9272, + "contract": "contracts/harvest/OETHHarvester.sol:OETHHarvester", + "label": "uniswapV2Path", + "offset": 0, + "slot": "3", + "type": "t_mapping(t_address,t_array(t_address)dyn_storage)" + }, + { + "astId": 9276, + "contract": "contracts/harvest/OETHHarvester.sol:OETHHarvester", + "label": "uniswapV3Path", + "offset": 0, + "slot": "4", + "type": "t_mapping(t_address,t_bytes_storage)" + }, + { + "astId": 9280, + "contract": "contracts/harvest/OETHHarvester.sol:OETHHarvester", + "label": "balancerPoolId", + "offset": 0, + "slot": "5", + "type": "t_mapping(t_address,t_bytes32)" + }, + { + "astId": 9290, + "contract": "contracts/harvest/OETHHarvester.sol:OETHHarvester", + "label": "curvePoolIndices", + "offset": 0, + "slot": "6", + "type": "t_mapping(t_address,t_struct(CurvePoolIndices)9285_storage)" + } + ], + "types": { + "t_address": { + "encoding": "inplace", + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_address)dyn_storage": { + "base": "t_address", + "encoding": "dynamic_array", + "label": "address[]", + "numberOfBytes": "32" + }, + "t_bool": { + "encoding": "inplace", + "label": "bool", + "numberOfBytes": "1" + }, + "t_bytes32": { + "encoding": "inplace", + "label": "bytes32", + "numberOfBytes": "32" + }, + "t_bytes_storage": { + "encoding": "bytes", + "label": "bytes", + "numberOfBytes": "32" + }, + "t_enum(SwapPlatform)9143": { + "encoding": "inplace", + "label": "enum BaseHarvester.SwapPlatform", + "numberOfBytes": "1" + }, + "t_mapping(t_address,t_array(t_address)dyn_storage)": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => address[])", + "numberOfBytes": "32", + "value": "t_array(t_address)dyn_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_bytes32)": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => bytes32)", + "numberOfBytes": "32", + "value": "t_bytes32" + }, + "t_mapping(t_address,t_bytes_storage)": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => bytes)", + "numberOfBytes": "32", + "value": "t_bytes_storage" + }, + "t_mapping(t_address,t_struct(CurvePoolIndices)9285_storage)": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => struct BaseHarvester.CurvePoolIndices)", + "numberOfBytes": "32", + "value": "t_struct(CurvePoolIndices)9285_storage" + }, + "t_mapping(t_address,t_struct(RewardTokenConfig)9248_storage)": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => struct BaseHarvester.RewardTokenConfig)", + "numberOfBytes": "32", + "value": "t_struct(RewardTokenConfig)9248_storage" + }, + "t_struct(CurvePoolIndices)9285_storage": { + "encoding": "inplace", + "label": "struct BaseHarvester.CurvePoolIndices", + "members": [ + { + "astId": 9282, + "contract": "contracts/harvest/OETHHarvester.sol:OETHHarvester", + "label": "rewardTokenIndex", + "offset": 0, + "slot": "0", + "type": "t_uint128" + }, + { + "astId": 9284, + "contract": "contracts/harvest/OETHHarvester.sol:OETHHarvester", + "label": "baseTokenIndex", + "offset": 16, + "slot": "0", + "type": "t_uint128" + } + ], + "numberOfBytes": "32" + }, + "t_struct(RewardTokenConfig)9248_storage": { + "encoding": "inplace", + "label": "struct BaseHarvester.RewardTokenConfig", + "members": [ + { + "astId": 9236, + "contract": "contracts/harvest/OETHHarvester.sol:OETHHarvester", + "label": "allowedSlippageBps", + "offset": 0, + "slot": "0", + "type": "t_uint16" + }, + { + "astId": 9238, + "contract": "contracts/harvest/OETHHarvester.sol:OETHHarvester", + "label": "harvestRewardBps", + "offset": 2, + "slot": "0", + "type": "t_uint16" + }, + { + "astId": 9240, + "contract": "contracts/harvest/OETHHarvester.sol:OETHHarvester", + "label": "swapPlatformAddr", + "offset": 4, + "slot": "0", + "type": "t_address" + }, + { + "astId": 9242, + "contract": "contracts/harvest/OETHHarvester.sol:OETHHarvester", + "label": "doSwapRewardToken", + "offset": 24, + "slot": "0", + "type": "t_bool" + }, + { + "astId": 9245, + "contract": "contracts/harvest/OETHHarvester.sol:OETHHarvester", + "label": "swapPlatform", + "offset": 25, + "slot": "0", + "type": "t_enum(SwapPlatform)9143" + }, + { + "astId": 9247, + "contract": "contracts/harvest/OETHHarvester.sol:OETHHarvester", + "label": "liquidationLimit", + "offset": 0, + "slot": "1", + "type": "t_uint256" + } + ], + "numberOfBytes": "64" + }, + "t_uint128": { + "encoding": "inplace", + "label": "uint128", + "numberOfBytes": "16" + }, + "t_uint16": { + "encoding": "inplace", + "label": "uint16", + "numberOfBytes": "2" + }, + "t_uint256": { + "encoding": "inplace", + "label": "uint256", + "numberOfBytes": "32" + } + } + } +} \ No newline at end of file diff --git a/contracts/deployments/holesky/OETHHarvesterProxy.json b/contracts/deployments/holesky/OETHHarvesterProxy.json new file mode 100644 index 0000000000..1fc8bec4e0 --- /dev/null +++ b/contracts/deployments/holesky/OETHHarvesterProxy.json @@ -0,0 +1,304 @@ +{ + "address": "0xB7491cdf36367C89001cc41312F22f63A3a17931", + "abi": [ + { + "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": true, + "internalType": "address", + "name": "previousGovernor", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newGovernor", + "type": "address" + } + ], + "name": "PendingGovernorshipTransfer", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "implementation", + "type": "address" + } + ], + "name": "Upgraded", + "type": "event" + }, + { + "stateMutability": "payable", + "type": "fallback" + }, + { + "inputs": [], + "name": "admin", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "claimGovernance", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "governor", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "implementation", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_logic", + "type": "address" + }, + { + "internalType": "address", + "name": "_initGovernor", + "type": "address" + }, + { + "internalType": "bytes", + "name": "_data", + "type": "bytes" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [], + "name": "isGovernor", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_newGovernor", + "type": "address" + } + ], + "name": "transferGovernance", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newImplementation", + "type": "address" + } + ], + "name": "upgradeTo", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newImplementation", + "type": "address" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "upgradeToAndCall", + "outputs": [], + "stateMutability": "payable", + "type": "function" + } + ], + "transactionHash": "0x4920b31813d9c3dee64893f0047547fc92c0576c2a6cc01505e48cc0f0a69c1d", + "receipt": { + "to": null, + "from": "0x1b94CA50D3Ad9f8368851F8526132272d1a5028C", + "contractAddress": "0xB7491cdf36367C89001cc41312F22f63A3a17931", + "transactionIndex": 69, + "gasUsed": "580428", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000000004000000000000002000000000000000002040001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000010000000000000001000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0xd85b240bd76fb07b4addf41c66da810e1df001de7d981da48ebd7b10733755a5", + "transactionHash": "0x4920b31813d9c3dee64893f0047547fc92c0576c2a6cc01505e48cc0f0a69c1d", + "logs": [ + { + "transactionIndex": 69, + "blockNumber": 1405149, + "transactionHash": "0x4920b31813d9c3dee64893f0047547fc92c0576c2a6cc01505e48cc0f0a69c1d", + "address": "0xB7491cdf36367C89001cc41312F22f63A3a17931", + "topics": [ + "0xc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000001b94ca50d3ad9f8368851f8526132272d1a5028c" + ], + "data": "0x", + "logIndex": 97, + "blockHash": "0xd85b240bd76fb07b4addf41c66da810e1df001de7d981da48ebd7b10733755a5" + } + ], + "blockNumber": 1405149, + "cumulativeGasUsed": "9722165", + "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\":true,\"internalType\":\"address\",\"name\":\"previousGovernor\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newGovernor\",\"type\":\"address\"}],\"name\":\"GovernorshipTransferred\",\"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\":true,\"internalType\":\"address\",\"name\":\"implementation\",\"type\":\"address\"}],\"name\":\"Upgraded\",\"type\":\"event\"},{\"stateMutability\":\"payable\",\"type\":\"fallback\"},{\"inputs\":[],\"name\":\"admin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"claimGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"governor\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"implementation\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_logic\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_initGovernor\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isGovernor\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_newGovernor\",\"type\":\"address\"}],\"name\":\"transferGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newImplementation\",\"type\":\"address\"}],\"name\":\"upgradeTo\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newImplementation\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"upgradeToAndCall\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"author\":\"Origin Protocol Inc\",\"details\":\"This contract combines an upgradeability proxy with our governor system. It is based on an older version of OpenZeppelins BaseUpgradeabilityProxy with Solidity ^0.8.0.\",\"events\":{\"Upgraded(address)\":{\"details\":\"Emitted when the implementation is upgraded.\",\"params\":{\"implementation\":\"Address of the new implementation.\"}}},\"kind\":\"dev\",\"methods\":{\"admin()\":{\"returns\":{\"_0\":\"The address of the proxy admin/it's also the governor.\"}},\"implementation()\":{\"returns\":{\"_0\":\"The address of the implementation.\"}},\"initialize(address,address,bytes)\":{\"details\":\"Contract initializer with Governor enforcement\",\"params\":{\"_data\":\"Data to send as msg.data to the implementation to initialize the proxied contract. It should include the signature and the parameters of the function to be called, as described in https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding. This parameter is optional, if no data is given the initialization call to proxied contract will be skipped.\",\"_initGovernor\":\"Address of the initial Governor.\",\"_logic\":\"Address of the initial implementation.\"}},\"transferGovernance(address)\":{\"params\":{\"_newGovernor\":\"Address of the new Governor\"}},\"upgradeTo(address)\":{\"details\":\"Upgrade the backing implementation of the proxy. Only the admin can call this function.\",\"params\":{\"newImplementation\":\"Address of the new implementation.\"}},\"upgradeToAndCall(address,bytes)\":{\"details\":\"Upgrade the backing implementation of the proxy and call a function on the new implementation. This is useful to initialize the proxied contract.\",\"params\":{\"data\":\"Data to send as msg.data in the low level call. It should include the signature and the parameters of the function to be called, as described in https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.\",\"newImplementation\":\"Address of the new implementation.\"}}},\"stateVariables\":{\"IMPLEMENTATION_SLOT\":{\"details\":\"Storage slot with the address of the current implementation. This is the keccak-256 hash of \\\"eip1967.proxy.implementation\\\" subtracted by 1, and is validated in the constructor.\"}},\"title\":\"BaseGovernedUpgradeabilityProxy\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"claimGovernance()\":{\"notice\":\"Claim Governance of the contract to a new account (`newGovernor`). Can only be called by the new Governor.\"},\"governor()\":{\"notice\":\"Returns the address of the current Governor.\"},\"isGovernor()\":{\"notice\":\"Returns true if the caller is the current Governor.\"},\"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\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/proxies/InitializeGovernedUpgradeabilityProxy.sol\":\"InitializeGovernedUpgradeabilityProxy\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@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\"},\"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/proxies/InitializeGovernedUpgradeabilityProxy.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport { Address } from \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\n\\nimport { Governable } from \\\"../governance/Governable.sol\\\";\\n\\n/**\\n * @title BaseGovernedUpgradeabilityProxy\\n * @dev This contract combines an upgradeability proxy with our governor system.\\n * It is based on an older version of OpenZeppelins BaseUpgradeabilityProxy\\n * with Solidity ^0.8.0.\\n * @author Origin Protocol Inc\\n */\\ncontract InitializeGovernedUpgradeabilityProxy is Governable {\\n /**\\n * @dev Emitted when the implementation is upgraded.\\n * @param implementation Address of the new implementation.\\n */\\n event Upgraded(address indexed implementation);\\n\\n /**\\n * @dev Contract initializer with Governor enforcement\\n * @param _logic Address of the initial implementation.\\n * @param _initGovernor Address of the initial Governor.\\n * @param _data Data to send as msg.data to the implementation to initialize\\n * the proxied contract.\\n * It should include the signature and the parameters of the function to be\\n * called, as described in\\n * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.\\n * This parameter is optional, if no data is given the initialization call\\n * to proxied contract will be skipped.\\n */\\n function initialize(\\n address _logic,\\n address _initGovernor,\\n bytes calldata _data\\n ) public payable onlyGovernor {\\n require(_implementation() == address(0));\\n assert(\\n IMPLEMENTATION_SLOT ==\\n bytes32(uint256(keccak256(\\\"eip1967.proxy.implementation\\\")) - 1)\\n );\\n _setImplementation(_logic);\\n if (_data.length > 0) {\\n (bool success, ) = _logic.delegatecall(_data);\\n require(success);\\n }\\n _changeGovernor(_initGovernor);\\n }\\n\\n /**\\n * @return The address of the proxy admin/it's also the governor.\\n */\\n function admin() external view returns (address) {\\n return _governor();\\n }\\n\\n /**\\n * @return The address of the implementation.\\n */\\n function implementation() external view returns (address) {\\n return _implementation();\\n }\\n\\n /**\\n * @dev Upgrade the backing implementation of the proxy.\\n * Only the admin can call this function.\\n * @param newImplementation Address of the new implementation.\\n */\\n function upgradeTo(address newImplementation) external onlyGovernor {\\n _upgradeTo(newImplementation);\\n }\\n\\n /**\\n * @dev Upgrade the backing implementation of the proxy and call a function\\n * on the new implementation.\\n * This is useful to initialize the proxied contract.\\n * @param newImplementation Address of the new implementation.\\n * @param data Data to send as msg.data in the low level call.\\n * It should include the signature and the parameters of the function to be called, as described in\\n * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.\\n */\\n function upgradeToAndCall(address newImplementation, bytes calldata data)\\n external\\n payable\\n onlyGovernor\\n {\\n _upgradeTo(newImplementation);\\n (bool success, ) = newImplementation.delegatecall(data);\\n require(success);\\n }\\n\\n /**\\n * @dev Fallback function.\\n * Implemented entirely in `_fallback`.\\n */\\n fallback() external payable {\\n _fallback();\\n }\\n\\n /**\\n * @dev Delegates execution to an implementation contract.\\n * This is a low level function that doesn't return to its internal call site.\\n * It will return to the external caller whatever the implementation returns.\\n * @param _impl Address to delegate.\\n */\\n function _delegate(address _impl) internal {\\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(gas(), _impl, 0, calldatasize(), 0, 0)\\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 /**\\n * @dev Function that is run as the first thing in the fallback function.\\n * Can be redefined in derived contracts to add functionality.\\n * Redefinitions must call super._willFallback().\\n */\\n function _willFallback() internal {}\\n\\n /**\\n * @dev fallback implementation.\\n * Extracted to enable manual triggering.\\n */\\n function _fallback() internal {\\n _willFallback();\\n _delegate(_implementation());\\n }\\n\\n /**\\n * @dev Storage slot with the address of the current implementation.\\n * This is the keccak-256 hash of \\\"eip1967.proxy.implementation\\\" subtracted by 1, and is\\n * validated in the constructor.\\n */\\n bytes32 internal constant IMPLEMENTATION_SLOT =\\n 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\\n\\n /**\\n * @dev Returns the current implementation.\\n * @return impl Address of the current implementation\\n */\\n function _implementation() internal view returns (address impl) {\\n bytes32 slot = IMPLEMENTATION_SLOT;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n impl := sload(slot)\\n }\\n }\\n\\n /**\\n * @dev Upgrades the proxy to a new implementation.\\n * @param newImplementation Address of the new implementation.\\n */\\n function _upgradeTo(address newImplementation) internal {\\n _setImplementation(newImplementation);\\n emit Upgraded(newImplementation);\\n }\\n\\n /**\\n * @dev Sets the implementation address of the proxy.\\n * @param newImplementation Address of the new implementation.\\n */\\n function _setImplementation(address newImplementation) internal {\\n require(\\n Address.isContract(newImplementation),\\n \\\"Cannot set a proxy implementation to a non-contract address\\\"\\n );\\n\\n bytes32 slot = IMPLEMENTATION_SLOT;\\n\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n sstore(slot, newImplementation)\\n }\\n }\\n}\\n\",\"keccak256\":\"0xcf9bc33957fa41a745726edb6461a4bddca875a038c848286a059f0f22b7f184\",\"license\":\"MIT\"}},\"version\":1}", + "bytecode": "0x608060405234801561001057600080fd5b506100273360008051602061099083398151915255565b600080516020610990833981519152546040516001600160a01b03909116906000907fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a908290a36109138061007d6000396000f3fe6080604052600436106100865760003560e01c80635d36b190116100595780635d36b1901461010a578063c7af33521461011f578063cf7a1d7714610144578063d38bfff414610157578063f851a4401461009057610086565b80630c340a24146100905780633659cfe6146100c25780634f1ef286146100e25780635c60da1b146100f5575b61008e610177565b005b34801561009c57600080fd5b506100a5610197565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156100ce57600080fd5b5061008e6100dd366004610745565b6101b4565b61008e6100f03660046107c8565b6101ed565b34801561010157600080fd5b506100a561028a565b34801561011657600080fd5b5061008e6102a2565b34801561012b57600080fd5b50610134610346565b60405190151581526020016100b9565b61008e610152366004610767565b610377565b34801561016357600080fd5b5061008e610172366004610745565b610491565b61019561019060008051602061089e8339815191525490565b610535565b565b60006101af6000805160206108be8339815191525490565b905090565b6101bc610346565b6101e15760405162461bcd60e51b81526004016101d89061082b565b60405180910390fd5b6101ea81610559565b50565b6101f5610346565b6102115760405162461bcd60e51b81526004016101d89061082b565b61021a83610559565b6000836001600160a01b0316838360405161023692919061081b565b600060405180830381855af49150503d8060008114610271576040519150601f19603f3d011682016040523d82523d6000602084013e610276565b606091505b505090508061028457600080fd5b50505050565b60006101af60008051602061089e8339815191525490565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b03161461033d5760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b60648201526084016101d8565b61019533610599565b600061035e6000805160206108be8339815191525490565b6001600160a01b0316336001600160a01b031614905090565b61037f610346565b61039b5760405162461bcd60e51b81526004016101d89061082b565b60006103b360008051602061089e8339815191525490565b6001600160a01b0316146103c657600080fd5b6103f160017f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbd610862565b60008051602061089e8339815191521461040d5761040d610887565b6104168461065a565b8015610488576000846001600160a01b0316838360405161043892919061081b565b600060405180830381855af49150503d8060008114610473576040519150601f19603f3d011682016040523d82523d6000602084013e610478565b606091505b505090508061048657600080fd5b505b61028483610599565b610499610346565b6104b55760405162461bcd60e51b81526004016101d89061082b565b6104dd817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b03166104fd6000805160206108be8339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b3660008037600080366000845af43d6000803e808015610554573d6000f35b3d6000fd5b6105628161065a565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b6001600160a01b0381166105ef5760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f72206973206164647265737328302900000000000060448201526064016101d8565b806001600160a01b031661060f6000805160206108be8339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a36101ea816000805160206108be83398151915255565b803b6106ce5760405162461bcd60e51b815260206004820152603b60248201527f43616e6e6f742073657420612070726f787920696d706c656d656e746174696f60448201527f6e20746f2061206e6f6e2d636f6e74726163742061646472657373000000000060648201526084016101d8565b60008051602061089e83398151915255565b80356001600160a01b03811681146106f757600080fd5b919050565b60008083601f84011261070e57600080fd5b50813567ffffffffffffffff81111561072657600080fd5b60208301915083602082850101111561073e57600080fd5b9250929050565b60006020828403121561075757600080fd5b610760826106e0565b9392505050565b6000806000806060858703121561077d57600080fd5b610786856106e0565b9350610794602086016106e0565b9250604085013567ffffffffffffffff8111156107b057600080fd5b6107bc878288016106fc565b95989497509550505050565b6000806000604084860312156107dd57600080fd5b6107e6846106e0565b9250602084013567ffffffffffffffff81111561080257600080fd5b61080e868287016106fc565b9497909650939450505050565b8183823760009101908152919050565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b60008282101561088257634e487b7160e01b600052601160045260246000fd5b500390565b634e487b7160e01b600052600160045260246000fdfe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa26469706673582212202f93620531087f6f22c06f197d768cc932c3f3bdb94475dfc01622fddbcb629264736f6c634300080700337bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a", + "deployedBytecode": "0x6080604052600436106100865760003560e01c80635d36b190116100595780635d36b1901461010a578063c7af33521461011f578063cf7a1d7714610144578063d38bfff414610157578063f851a4401461009057610086565b80630c340a24146100905780633659cfe6146100c25780634f1ef286146100e25780635c60da1b146100f5575b61008e610177565b005b34801561009c57600080fd5b506100a5610197565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156100ce57600080fd5b5061008e6100dd366004610745565b6101b4565b61008e6100f03660046107c8565b6101ed565b34801561010157600080fd5b506100a561028a565b34801561011657600080fd5b5061008e6102a2565b34801561012b57600080fd5b50610134610346565b60405190151581526020016100b9565b61008e610152366004610767565b610377565b34801561016357600080fd5b5061008e610172366004610745565b610491565b61019561019060008051602061089e8339815191525490565b610535565b565b60006101af6000805160206108be8339815191525490565b905090565b6101bc610346565b6101e15760405162461bcd60e51b81526004016101d89061082b565b60405180910390fd5b6101ea81610559565b50565b6101f5610346565b6102115760405162461bcd60e51b81526004016101d89061082b565b61021a83610559565b6000836001600160a01b0316838360405161023692919061081b565b600060405180830381855af49150503d8060008114610271576040519150601f19603f3d011682016040523d82523d6000602084013e610276565b606091505b505090508061028457600080fd5b50505050565b60006101af60008051602061089e8339815191525490565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b03161461033d5760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b60648201526084016101d8565b61019533610599565b600061035e6000805160206108be8339815191525490565b6001600160a01b0316336001600160a01b031614905090565b61037f610346565b61039b5760405162461bcd60e51b81526004016101d89061082b565b60006103b360008051602061089e8339815191525490565b6001600160a01b0316146103c657600080fd5b6103f160017f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbd610862565b60008051602061089e8339815191521461040d5761040d610887565b6104168461065a565b8015610488576000846001600160a01b0316838360405161043892919061081b565b600060405180830381855af49150503d8060008114610473576040519150601f19603f3d011682016040523d82523d6000602084013e610478565b606091505b505090508061048657600080fd5b505b61028483610599565b610499610346565b6104b55760405162461bcd60e51b81526004016101d89061082b565b6104dd817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b03166104fd6000805160206108be8339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b3660008037600080366000845af43d6000803e808015610554573d6000f35b3d6000fd5b6105628161065a565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b6001600160a01b0381166105ef5760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f72206973206164647265737328302900000000000060448201526064016101d8565b806001600160a01b031661060f6000805160206108be8339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a36101ea816000805160206108be83398151915255565b803b6106ce5760405162461bcd60e51b815260206004820152603b60248201527f43616e6e6f742073657420612070726f787920696d706c656d656e746174696f60448201527f6e20746f2061206e6f6e2d636f6e74726163742061646472657373000000000060648201526084016101d8565b60008051602061089e83398151915255565b80356001600160a01b03811681146106f757600080fd5b919050565b60008083601f84011261070e57600080fd5b50813567ffffffffffffffff81111561072657600080fd5b60208301915083602082850101111561073e57600080fd5b9250929050565b60006020828403121561075757600080fd5b610760826106e0565b9392505050565b6000806000806060858703121561077d57600080fd5b610786856106e0565b9350610794602086016106e0565b9250604085013567ffffffffffffffff8111156107b057600080fd5b6107bc878288016106fc565b95989497509550505050565b6000806000604084860312156107dd57600080fd5b6107e6846106e0565b9250602084013567ffffffffffffffff81111561080257600080fd5b61080e868287016106fc565b9497909650939450505050565b8183823760009101908152919050565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b60008282101561088257634e487b7160e01b600052601160045260246000fd5b500390565b634e487b7160e01b600052600160045260246000fdfe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa26469706673582212202f93620531087f6f22c06f197d768cc932c3f3bdb94475dfc01622fddbcb629264736f6c63430008070033", + "libraries": {}, + "devdoc": { + "author": "Origin Protocol Inc", + "details": "This contract combines an upgradeability proxy with our governor system. It is based on an older version of OpenZeppelins BaseUpgradeabilityProxy with Solidity ^0.8.0.", + "events": { + "Upgraded(address)": { + "details": "Emitted when the implementation is upgraded.", + "params": { + "implementation": "Address of the new implementation." + } + } + }, + "kind": "dev", + "methods": { + "admin()": { + "returns": { + "_0": "The address of the proxy admin/it's also the governor." + } + }, + "implementation()": { + "returns": { + "_0": "The address of the implementation." + } + }, + "initialize(address,address,bytes)": { + "details": "Contract initializer with Governor enforcement", + "params": { + "_data": "Data to send as msg.data to the implementation to initialize the proxied contract. It should include the signature and the parameters of the function to be called, as described in https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding. This parameter is optional, if no data is given the initialization call to proxied contract will be skipped.", + "_initGovernor": "Address of the initial Governor.", + "_logic": "Address of the initial implementation." + } + }, + "transferGovernance(address)": { + "params": { + "_newGovernor": "Address of the new Governor" + } + }, + "upgradeTo(address)": { + "details": "Upgrade the backing implementation of the proxy. Only the admin can call this function.", + "params": { + "newImplementation": "Address of the new implementation." + } + }, + "upgradeToAndCall(address,bytes)": { + "details": "Upgrade the backing implementation of the proxy and call a function on the new implementation. This is useful to initialize the proxied contract.", + "params": { + "data": "Data to send as msg.data in the low level call. It should include the signature and the parameters of the function to be called, as described in https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.", + "newImplementation": "Address of the new implementation." + } + } + }, + "stateVariables": { + "IMPLEMENTATION_SLOT": { + "details": "Storage slot with the address of the current implementation. This is the keccak-256 hash of \"eip1967.proxy.implementation\" subtracted by 1, and is validated in the constructor." + } + }, + "title": "BaseGovernedUpgradeabilityProxy", + "version": 1 + }, + "userdoc": { + "kind": "user", + "methods": { + "claimGovernance()": { + "notice": "Claim Governance of the contract to a new account (`newGovernor`). Can only be called by the new Governor." + }, + "governor()": { + "notice": "Returns the address of the current Governor." + }, + "isGovernor()": { + "notice": "Returns true if the caller is the current Governor." + }, + "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" + } + }, + "version": 1 + }, + "storageLayout": { + "storage": [], + "types": null + } +} \ No newline at end of file diff --git a/contracts/deployments/holesky/OETHOracleRouter.json b/contracts/deployments/holesky/OETHOracleRouter.json new file mode 100644 index 0000000000..ea076473a7 --- /dev/null +++ b/contracts/deployments/holesky/OETHOracleRouter.json @@ -0,0 +1,157 @@ +{ + "address": "0x7e2bf9A89180f20591EcFA42C0dd7e52b2C546E3", + "abi": [ + { + "inputs": [ + { + "internalType": "address", + "name": "_auraPriceFeed", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "auraPriceFeed", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "asset", + "type": "address" + } + ], + "name": "cacheDecimals", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "asset", + "type": "address" + } + ], + "name": "price", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + } + ], + "transactionHash": "0xa0dc01e277878a8c219fdb3f990de0a5e994af72f0a5c92f5b5fb02bce9ba0ca", + "receipt": { + "to": null, + "from": "0x1b94CA50D3Ad9f8368851F8526132272d1a5028C", + "contractAddress": "0x7e2bf9A89180f20591EcFA42C0dd7e52b2C546E3", + "transactionIndex": 30, + "gasUsed": "207407", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x542a6f59c20dda4221eb29a8126bb653cac11738383da50e34e87aae437522fb", + "transactionHash": "0xa0dc01e277878a8c219fdb3f990de0a5e994af72f0a5c92f5b5fb02bce9ba0ca", + "logs": [], + "blockNumber": 1405041, + "cumulativeGasUsed": "3080838", + "status": 1, + "byzantium": true + }, + "args": [ + "0x0000000000000000000000000000000000000000" + ], + "numDeployments": 1, + "solcInputHash": "e8f6f73d56d3c5372e8e110ffa009f0b", + "metadata": "{\"compiler\":{\"version\":\"0.8.7+commit.e28d00a7\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_auraPriceFeed\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"auraPriceFeed\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"asset\",\"type\":\"address\"}],\"name\":\"cacheDecimals\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"asset\",\"type\":\"address\"}],\"name\":\"price\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"cacheDecimals(address)\":{\"params\":{\"asset\":\"address of the asset\"},\"returns\":{\"_0\":\"uint8 corresponding asset decimals\"}},\"price(address)\":{\"params\":{\"asset\":\"address of the asset\"},\"returns\":{\"_0\":\"uint256 unit price for 1 asset unit, in 18 decimal fixed\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"cacheDecimals(address)\":{\"notice\":\"Before an asset/feed price is fetches for the first time the decimals need to be cached. This is a gas optimization\"},\"price(address)\":{\"notice\":\"Returns the total price in 18 digit units for a given asset. This implementation does not (!) do range checks as the parent OracleRouter does.\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/oracle/OETHFixedOracle.sol\":\"OETHFixedOracle\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@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/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/chainlink/AggregatorV3Interface.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface AggregatorV3Interface {\\n function decimals() external view returns (uint8);\\n\\n function description() external view returns (string memory);\\n\\n function version() external view returns (uint256);\\n\\n // getRoundData and latestRoundData should both raise \\\"No data present\\\"\\n // if they do not have data to report, instead of returning unset values\\n // which could be misinterpreted as actual reported values.\\n function getRoundData(uint80 _roundId)\\n external\\n view\\n returns (\\n uint80 roundId,\\n int256 answer,\\n uint256 startedAt,\\n uint256 updatedAt,\\n uint80 answeredInRound\\n );\\n\\n function latestRoundData()\\n external\\n view\\n returns (\\n uint80 roundId,\\n int256 answer,\\n uint256 startedAt,\\n uint256 updatedAt,\\n uint80 answeredInRound\\n );\\n}\\n\",\"keccak256\":\"0x18fb68de95136c49f3874fe7795a7bda730339198b2816690ddbdf1eacd4e273\",\"license\":\"MIT\"},\"contracts/oracle/OETHFixedOracle.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport { OETHOracleRouter } from \\\"./OETHOracleRouter.sol\\\";\\n\\n// @notice Oracle Router that denominates all prices in ETH\\ncontract OETHFixedOracle is OETHOracleRouter {\\n constructor(address _auraPriceFeed) OETHOracleRouter(_auraPriceFeed) {}\\n\\n /**\\n * @dev The price feed contract to use for a particular asset along with\\n * maximum data staleness\\n * @param asset address of the asset\\n * @return feedAddress address of the price feed for the asset\\n * @return maxStaleness maximum acceptable data staleness duration\\n */\\n function feedMetadata(address asset)\\n internal\\n view\\n virtual\\n override\\n returns (address feedAddress, uint256 maxStaleness)\\n {\\n // fixes price for all of the assets\\n feedAddress = FIXED_PRICE;\\n maxStaleness = 0;\\n }\\n}\\n\",\"keccak256\":\"0x9d3a7b28e4b465fc6abc7189a0713d6c91082f8aef3aa01f025d739b1f88425c\",\"license\":\"MIT\"},\"contracts/oracle/OETHOracleRouter.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport \\\"../interfaces/chainlink/AggregatorV3Interface.sol\\\";\\nimport { OracleRouterBase } from \\\"./OracleRouterBase.sol\\\";\\nimport { StableMath } from \\\"../utils/StableMath.sol\\\";\\n\\n// @notice Oracle Router that denominates all prices in ETH\\ncontract OETHOracleRouter is OracleRouterBase {\\n using StableMath for uint256;\\n\\n address public immutable auraPriceFeed;\\n\\n constructor(address _auraPriceFeed) {\\n auraPriceFeed = _auraPriceFeed;\\n }\\n\\n /**\\n * @notice Returns the total price in 18 digit units for a given asset.\\n * This implementation does not (!) do range checks as the\\n * parent OracleRouter does.\\n * @param asset address of the asset\\n * @return uint256 unit price for 1 asset unit, in 18 decimal fixed\\n */\\n function price(address asset)\\n external\\n view\\n virtual\\n override\\n returns (uint256)\\n {\\n (address _feed, uint256 maxStaleness) = feedMetadata(asset);\\n if (_feed == FIXED_PRICE) {\\n return 1e18;\\n }\\n require(_feed != address(0), \\\"Asset not available\\\");\\n\\n // slither-disable-next-line unused-return\\n (, int256 _iprice, , uint256 updatedAt, ) = AggregatorV3Interface(_feed)\\n .latestRoundData();\\n\\n require(\\n updatedAt + maxStaleness >= block.timestamp,\\n \\\"Oracle price too old\\\"\\n );\\n\\n uint8 decimals = getDecimals(_feed);\\n uint256 _price = uint256(_iprice).scaleBy(18, decimals);\\n return _price;\\n }\\n\\n /**\\n * @dev The price feed contract to use for a particular asset along with\\n * maximum data staleness\\n * @param asset address of the asset\\n * @return feedAddress address of the price feed for the asset\\n * @return maxStaleness maximum acceptable data staleness duration\\n */\\n function feedMetadata(address asset)\\n internal\\n view\\n virtual\\n override\\n returns (address feedAddress, uint256 maxStaleness)\\n {\\n if (asset == 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2) {\\n // FIXED_PRICE: WETH/ETH\\n feedAddress = FIXED_PRICE;\\n maxStaleness = 0;\\n } else if (asset == 0x5E8422345238F34275888049021821E8E08CAa1f) {\\n // frxETH/ETH\\n feedAddress = 0xC58F3385FBc1C8AD2c0C9a061D7c13b141D7A5Df;\\n maxStaleness = 18 hours + STALENESS_BUFFER;\\n } else if (asset == 0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84) {\\n // https://data.chain.link/ethereum/mainnet/crypto-eth/steth-eth\\n // Chainlink: stETH/ETH\\n feedAddress = 0x86392dC19c0b719886221c78AB11eb8Cf5c52812;\\n maxStaleness = 1 days + STALENESS_BUFFER;\\n } else if (asset == 0xae78736Cd615f374D3085123A210448E74Fc6393) {\\n // https://data.chain.link/ethereum/mainnet/crypto-eth/reth-eth\\n // Chainlink: rETH/ETH\\n feedAddress = 0x536218f9E9Eb48863970252233c8F271f554C2d0;\\n maxStaleness = 1 days + STALENESS_BUFFER;\\n } else if (asset == 0xD533a949740bb3306d119CC777fa900bA034cd52) {\\n // https://data.chain.link/ethereum/mainnet/crypto-eth/crv-eth\\n // Chainlink: CRV/ETH\\n feedAddress = 0x8a12Be339B0cD1829b91Adc01977caa5E9ac121e;\\n maxStaleness = 1 days + STALENESS_BUFFER;\\n } else if (asset == 0x4e3FBD56CD56c3e72c1403e103b45Db9da5B9D2B) {\\n // https://data.chain.link/ethereum/mainnet/crypto-eth/cvx-eth\\n // Chainlink: CVX/ETH\\n feedAddress = 0xC9CbF687f43176B302F03f5e58470b77D07c61c6;\\n maxStaleness = 1 days + STALENESS_BUFFER;\\n } else if (asset == 0xBe9895146f7AF43049ca1c1AE358B0541Ea49704) {\\n // https://data.chain.link/ethereum/mainnet/crypto-eth/cbeth-eth\\n // Chainlink: cbETH/ETH\\n feedAddress = 0xF017fcB346A1885194689bA23Eff2fE6fA5C483b;\\n maxStaleness = 1 days + STALENESS_BUFFER;\\n } else if (asset == 0xba100000625a3754423978a60c9317c58a424e3D) {\\n // https://data.chain.link/ethereum/mainnet/crypto-eth/bal-eth\\n // Chainlink: BAL/ETH\\n feedAddress = 0xC1438AA3823A6Ba0C159CfA8D98dF5A994bA120b;\\n maxStaleness = 1 days + STALENESS_BUFFER;\\n } else if (asset == 0xC0c293ce456fF0ED870ADd98a0828Dd4d2903DBF) {\\n // AURA/ETH\\n feedAddress = auraPriceFeed;\\n maxStaleness = 0;\\n } else {\\n revert(\\\"Asset not available\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0x06a62190a726e637f6eec5914b9292a7ef52c3c5a9f603a3299f6e862c81b096\",\"license\":\"MIT\"},\"contracts/oracle/OracleRouterBase.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport \\\"../interfaces/chainlink/AggregatorV3Interface.sol\\\";\\nimport { IOracle } from \\\"../interfaces/IOracle.sol\\\";\\nimport { Helpers } from \\\"../utils/Helpers.sol\\\";\\nimport { StableMath } from \\\"../utils/StableMath.sol\\\";\\nimport { SafeCast } from \\\"@openzeppelin/contracts/utils/math/SafeCast.sol\\\";\\n\\n// @notice Abstract functionality that is shared between various Oracle Routers\\nabstract contract OracleRouterBase is IOracle {\\n using StableMath for uint256;\\n using SafeCast for int256;\\n\\n uint256 internal constant MIN_DRIFT = 0.7e18;\\n uint256 internal constant MAX_DRIFT = 1.3e18;\\n address internal constant FIXED_PRICE =\\n 0x0000000000000000000000000000000000000001;\\n // Maximum allowed staleness buffer above normal Oracle maximum staleness\\n uint256 internal constant STALENESS_BUFFER = 1 days;\\n mapping(address => uint8) internal decimalsCache;\\n\\n /**\\n * @dev The price feed contract to use for a particular asset along with\\n * maximum data staleness\\n * @param asset address of the asset\\n * @return feedAddress address of the price feed for the asset\\n * @return maxStaleness maximum acceptable data staleness duration\\n */\\n function feedMetadata(address asset)\\n internal\\n view\\n virtual\\n returns (address feedAddress, uint256 maxStaleness);\\n\\n /**\\n * @notice Returns the total price in 18 digit unit for a given asset.\\n * @param asset address of the asset\\n * @return uint256 unit price for 1 asset unit, in 18 decimal fixed\\n */\\n function price(address asset)\\n external\\n view\\n virtual\\n override\\n returns (uint256)\\n {\\n (address _feed, uint256 maxStaleness) = feedMetadata(asset);\\n require(_feed != address(0), \\\"Asset not available\\\");\\n require(_feed != FIXED_PRICE, \\\"Fixed price feeds not supported\\\");\\n\\n // slither-disable-next-line unused-return\\n (, int256 _iprice, , uint256 updatedAt, ) = AggregatorV3Interface(_feed)\\n .latestRoundData();\\n\\n require(\\n updatedAt + maxStaleness >= block.timestamp,\\n \\\"Oracle price too old\\\"\\n );\\n\\n uint8 decimals = getDecimals(_feed);\\n\\n uint256 _price = _iprice.toUint256().scaleBy(18, decimals);\\n if (shouldBePegged(asset)) {\\n require(_price <= MAX_DRIFT, \\\"Oracle: Price exceeds max\\\");\\n require(_price >= MIN_DRIFT, \\\"Oracle: Price under min\\\");\\n }\\n return _price;\\n }\\n\\n function getDecimals(address _feed) internal view virtual returns (uint8) {\\n uint8 decimals = decimalsCache[_feed];\\n require(decimals > 0, \\\"Oracle: Decimals not cached\\\");\\n return decimals;\\n }\\n\\n /**\\n * @notice Before an asset/feed price is fetches for the first time the\\n * decimals need to be cached. This is a gas optimization\\n * @param asset address of the asset\\n * @return uint8 corresponding asset decimals\\n */\\n function cacheDecimals(address asset) external returns (uint8) {\\n (address _feed, ) = feedMetadata(asset);\\n require(_feed != address(0), \\\"Asset not available\\\");\\n require(_feed != FIXED_PRICE, \\\"Fixed price feeds not supported\\\");\\n\\n uint8 decimals = AggregatorV3Interface(_feed).decimals();\\n decimalsCache[_feed] = decimals;\\n return decimals;\\n }\\n\\n function shouldBePegged(address _asset) internal view returns (bool) {\\n string memory symbol = Helpers.getSymbol(_asset);\\n bytes32 symbolHash = keccak256(abi.encodePacked(symbol));\\n return\\n symbolHash == keccak256(abi.encodePacked(\\\"DAI\\\")) ||\\n symbolHash == keccak256(abi.encodePacked(\\\"USDC\\\")) ||\\n symbolHash == keccak256(abi.encodePacked(\\\"USDT\\\"));\\n }\\n}\\n\",\"keccak256\":\"0x25fd5ee51877c4e5339855cb590c75107e8facd7ca962bcd105677e8ee2d06de\",\"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/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\"}},\"version\":1}", + "bytecode": "0x60a060405234801561001057600080fd5b5060405161035338038061035383398101604081905261002f91610044565b60601b6001600160601b031916608052610074565b60006020828403121561005657600080fd5b81516001600160a01b038116811461006d57600080fd5b9392505050565b60805160601c6102c26100916000396000604b01526102c26000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c806323e2c52f1461004657806336b6d9441461008a578063aea91078146100af575b600080fd5b61006d7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020015b60405180910390f35b61009d6100983660046101ec565b6100d8565b60405160ff9091168152602001610081565b6100ca6100bd3660046101ec565b50670de0b6b3a764000090565b604051908152602001610081565b600060016100ea565b60405180910390fd5b6001600160a01b038116600114156101445760405162461bcd60e51b815260206004820152601f60248201527f4669786564207072696365206665656473206e6f7420737570706f727465640060448201526064016100e1565b6000816001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b15801561017f57600080fd5b505afa158015610193573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101b79190610215565b6001600160a01b03929092166000908152602081905260409020805460ff191660ff84161790555092915050565b9392505050565b6000602082840312156101fe57600080fd5b81356001600160a01b03811681146101e557600080fd5b60006020828403121561022757600080fd5b815160ff811681146101e557600080fd5b8085111561026e57816000190482111561025457610254610276565b8085161561026157918102915b93841c9390800290610238565b509250929050565b634e487b7160e01b600052601160045260246000fdfea26469706673582212205f15a9f597388280428218a28c46008f73d4c04de95632b7ef72b28d6181f26a64736f6c63430008070033", + "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106100415760003560e01c806323e2c52f1461004657806336b6d9441461008a578063aea91078146100af575b600080fd5b61006d7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020015b60405180910390f35b61009d6100983660046101ec565b6100d8565b60405160ff9091168152602001610081565b6100ca6100bd3660046101ec565b50670de0b6b3a764000090565b604051908152602001610081565b600060016100ea565b60405180910390fd5b6001600160a01b038116600114156101445760405162461bcd60e51b815260206004820152601f60248201527f4669786564207072696365206665656473206e6f7420737570706f727465640060448201526064016100e1565b6000816001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b15801561017f57600080fd5b505afa158015610193573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101b79190610215565b6001600160a01b03929092166000908152602081905260409020805460ff191660ff84161790555092915050565b9392505050565b6000602082840312156101fe57600080fd5b81356001600160a01b03811681146101e557600080fd5b60006020828403121561022757600080fd5b815160ff811681146101e557600080fd5b8085111561026e57816000190482111561025457610254610276565b8085161561026157918102915b93841c9390800290610238565b509250929050565b634e487b7160e01b600052601160045260246000fdfea26469706673582212205f15a9f597388280428218a28c46008f73d4c04de95632b7ef72b28d6181f26a64736f6c63430008070033", + "libraries": {}, + "devdoc": { + "kind": "dev", + "methods": { + "cacheDecimals(address)": { + "params": { + "asset": "address of the asset" + }, + "returns": { + "_0": "uint8 corresponding asset decimals" + } + }, + "price(address)": { + "params": { + "asset": "address of the asset" + }, + "returns": { + "_0": "uint256 unit price for 1 asset unit, in 18 decimal fixed" + } + } + }, + "version": 1 + }, + "userdoc": { + "kind": "user", + "methods": { + "cacheDecimals(address)": { + "notice": "Before an asset/feed price is fetches for the first time the decimals need to be cached. This is a gas optimization" + }, + "price(address)": { + "notice": "Returns the total price in 18 digit units for a given asset. This implementation does not (!) do range checks as the parent OracleRouter does." + } + }, + "version": 1 + }, + "storageLayout": { + "storage": [ + { + "astId": 1092, + "contract": "contracts/oracle/OETHFixedOracle.sol:OETHFixedOracle", + "label": "decimalsCache", + "offset": 0, + "slot": "0", + "type": "t_mapping(t_address,t_uint8)" + } + ], + "types": { + "t_address": { + "encoding": "inplace", + "label": "address", + "numberOfBytes": "20" + }, + "t_mapping(t_address,t_uint8)": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => uint8)", + "numberOfBytes": "32", + "value": "t_uint8" + }, + "t_uint8": { + "encoding": "inplace", + "label": "uint8", + "numberOfBytes": "1" + } + } + } +} \ No newline at end of file diff --git a/contracts/deployments/holesky/OETHProxy.json b/contracts/deployments/holesky/OETHProxy.json new file mode 100644 index 0000000000..ecec1423ff --- /dev/null +++ b/contracts/deployments/holesky/OETHProxy.json @@ -0,0 +1,289 @@ +{ + "address": "0xB1876706d2402d300bf263F9e53335CEFc53d9Cb", + "abi": [ + { + "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": true, + "internalType": "address", + "name": "previousGovernor", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newGovernor", + "type": "address" + } + ], + "name": "PendingGovernorshipTransfer", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "implementation", + "type": "address" + } + ], + "name": "Upgraded", + "type": "event" + }, + { + "stateMutability": "payable", + "type": "fallback" + }, + { + "inputs": [], + "name": "admin", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "claimGovernance", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "governor", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "implementation", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_logic", + "type": "address" + }, + { + "internalType": "address", + "name": "_initGovernor", + "type": "address" + }, + { + "internalType": "bytes", + "name": "_data", + "type": "bytes" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [], + "name": "isGovernor", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_newGovernor", + "type": "address" + } + ], + "name": "transferGovernance", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newImplementation", + "type": "address" + } + ], + "name": "upgradeTo", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newImplementation", + "type": "address" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "upgradeToAndCall", + "outputs": [], + "stateMutability": "payable", + "type": "function" + } + ], + "transactionHash": "0x514878f56bf2b8648177661967224cec86da8ca821a6a1e94d4c9866e38abaae", + "receipt": { + "to": null, + "from": "0x1b94CA50D3Ad9f8368851F8526132272d1a5028C", + "contractAddress": "0xB1876706d2402d300bf263F9e53335CEFc53d9Cb", + "transactionIndex": 23, + "gasUsed": "580428", + "logsBloom": "0x00000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000100000000000000800000000000000000000000000000000000004000000000000002000000000000000000040000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000010000000000010000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x648632ee62d1c76ec3ac43694f243c6c80f628b6c737ce1be5e25a63b5aee369", + "transactionHash": "0x514878f56bf2b8648177661967224cec86da8ca821a6a1e94d4c9866e38abaae", + "logs": [ + { + "transactionIndex": 23, + "blockNumber": 1405045, + "transactionHash": "0x514878f56bf2b8648177661967224cec86da8ca821a6a1e94d4c9866e38abaae", + "address": "0xB1876706d2402d300bf263F9e53335CEFc53d9Cb", + "topics": [ + "0xc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000001b94ca50d3ad9f8368851f8526132272d1a5028c" + ], + "data": "0x", + "logIndex": 34, + "blockHash": "0x648632ee62d1c76ec3ac43694f243c6c80f628b6c737ce1be5e25a63b5aee369" + } + ], + "blockNumber": 1405045, + "cumulativeGasUsed": "3181338", + "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\":true,\"internalType\":\"address\",\"name\":\"previousGovernor\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newGovernor\",\"type\":\"address\"}],\"name\":\"GovernorshipTransferred\",\"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\":true,\"internalType\":\"address\",\"name\":\"implementation\",\"type\":\"address\"}],\"name\":\"Upgraded\",\"type\":\"event\"},{\"stateMutability\":\"payable\",\"type\":\"fallback\"},{\"inputs\":[],\"name\":\"admin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"claimGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"governor\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"implementation\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_logic\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_initGovernor\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isGovernor\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_newGovernor\",\"type\":\"address\"}],\"name\":\"transferGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newImplementation\",\"type\":\"address\"}],\"name\":\"upgradeTo\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newImplementation\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"upgradeToAndCall\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"admin()\":{\"returns\":{\"_0\":\"The address of the proxy admin/it's also the governor.\"}},\"implementation()\":{\"returns\":{\"_0\":\"The address of the implementation.\"}},\"initialize(address,address,bytes)\":{\"details\":\"Contract initializer with Governor enforcement\",\"params\":{\"_data\":\"Data to send as msg.data to the implementation to initialize the proxied contract. It should include the signature and the parameters of the function to be called, as described in https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding. This parameter is optional, if no data is given the initialization call to proxied contract will be skipped.\",\"_initGovernor\":\"Address of the initial Governor.\",\"_logic\":\"Address of the initial implementation.\"}},\"transferGovernance(address)\":{\"params\":{\"_newGovernor\":\"Address of the new Governor\"}},\"upgradeTo(address)\":{\"details\":\"Upgrade the backing implementation of the proxy. Only the admin can call this function.\",\"params\":{\"newImplementation\":\"Address of the new implementation.\"}},\"upgradeToAndCall(address,bytes)\":{\"details\":\"Upgrade the backing implementation of the proxy and call a function on the new implementation. This is useful to initialize the proxied contract.\",\"params\":{\"data\":\"Data to send as msg.data in the low level call. It should include the signature and the parameters of the function to be called, as described in https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.\",\"newImplementation\":\"Address of the new implementation.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"claimGovernance()\":{\"notice\":\"Claim Governance of the contract to a new account (`newGovernor`). Can only be called by the new Governor.\"},\"governor()\":{\"notice\":\"Returns the address of the current Governor.\"},\"isGovernor()\":{\"notice\":\"Returns true if the caller is the current Governor.\"},\"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\"}},\"notice\":\"OETHProxy delegates calls to nowhere for now\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/proxies/Proxies.sol\":\"OETHProxy\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@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\"},\"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/proxies/InitializeGovernedUpgradeabilityProxy.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport { Address } from \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\n\\nimport { Governable } from \\\"../governance/Governable.sol\\\";\\n\\n/**\\n * @title BaseGovernedUpgradeabilityProxy\\n * @dev This contract combines an upgradeability proxy with our governor system.\\n * It is based on an older version of OpenZeppelins BaseUpgradeabilityProxy\\n * with Solidity ^0.8.0.\\n * @author Origin Protocol Inc\\n */\\ncontract InitializeGovernedUpgradeabilityProxy is Governable {\\n /**\\n * @dev Emitted when the implementation is upgraded.\\n * @param implementation Address of the new implementation.\\n */\\n event Upgraded(address indexed implementation);\\n\\n /**\\n * @dev Contract initializer with Governor enforcement\\n * @param _logic Address of the initial implementation.\\n * @param _initGovernor Address of the initial Governor.\\n * @param _data Data to send as msg.data to the implementation to initialize\\n * the proxied contract.\\n * It should include the signature and the parameters of the function to be\\n * called, as described in\\n * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.\\n * This parameter is optional, if no data is given the initialization call\\n * to proxied contract will be skipped.\\n */\\n function initialize(\\n address _logic,\\n address _initGovernor,\\n bytes calldata _data\\n ) public payable onlyGovernor {\\n require(_implementation() == address(0));\\n assert(\\n IMPLEMENTATION_SLOT ==\\n bytes32(uint256(keccak256(\\\"eip1967.proxy.implementation\\\")) - 1)\\n );\\n _setImplementation(_logic);\\n if (_data.length > 0) {\\n (bool success, ) = _logic.delegatecall(_data);\\n require(success);\\n }\\n _changeGovernor(_initGovernor);\\n }\\n\\n /**\\n * @return The address of the proxy admin/it's also the governor.\\n */\\n function admin() external view returns (address) {\\n return _governor();\\n }\\n\\n /**\\n * @return The address of the implementation.\\n */\\n function implementation() external view returns (address) {\\n return _implementation();\\n }\\n\\n /**\\n * @dev Upgrade the backing implementation of the proxy.\\n * Only the admin can call this function.\\n * @param newImplementation Address of the new implementation.\\n */\\n function upgradeTo(address newImplementation) external onlyGovernor {\\n _upgradeTo(newImplementation);\\n }\\n\\n /**\\n * @dev Upgrade the backing implementation of the proxy and call a function\\n * on the new implementation.\\n * This is useful to initialize the proxied contract.\\n * @param newImplementation Address of the new implementation.\\n * @param data Data to send as msg.data in the low level call.\\n * It should include the signature and the parameters of the function to be called, as described in\\n * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.\\n */\\n function upgradeToAndCall(address newImplementation, bytes calldata data)\\n external\\n payable\\n onlyGovernor\\n {\\n _upgradeTo(newImplementation);\\n (bool success, ) = newImplementation.delegatecall(data);\\n require(success);\\n }\\n\\n /**\\n * @dev Fallback function.\\n * Implemented entirely in `_fallback`.\\n */\\n fallback() external payable {\\n _fallback();\\n }\\n\\n /**\\n * @dev Delegates execution to an implementation contract.\\n * This is a low level function that doesn't return to its internal call site.\\n * It will return to the external caller whatever the implementation returns.\\n * @param _impl Address to delegate.\\n */\\n function _delegate(address _impl) internal {\\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(gas(), _impl, 0, calldatasize(), 0, 0)\\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 /**\\n * @dev Function that is run as the first thing in the fallback function.\\n * Can be redefined in derived contracts to add functionality.\\n * Redefinitions must call super._willFallback().\\n */\\n function _willFallback() internal {}\\n\\n /**\\n * @dev fallback implementation.\\n * Extracted to enable manual triggering.\\n */\\n function _fallback() internal {\\n _willFallback();\\n _delegate(_implementation());\\n }\\n\\n /**\\n * @dev Storage slot with the address of the current implementation.\\n * This is the keccak-256 hash of \\\"eip1967.proxy.implementation\\\" subtracted by 1, and is\\n * validated in the constructor.\\n */\\n bytes32 internal constant IMPLEMENTATION_SLOT =\\n 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\\n\\n /**\\n * @dev Returns the current implementation.\\n * @return impl Address of the current implementation\\n */\\n function _implementation() internal view returns (address impl) {\\n bytes32 slot = IMPLEMENTATION_SLOT;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n impl := sload(slot)\\n }\\n }\\n\\n /**\\n * @dev Upgrades the proxy to a new implementation.\\n * @param newImplementation Address of the new implementation.\\n */\\n function _upgradeTo(address newImplementation) internal {\\n _setImplementation(newImplementation);\\n emit Upgraded(newImplementation);\\n }\\n\\n /**\\n * @dev Sets the implementation address of the proxy.\\n * @param newImplementation Address of the new implementation.\\n */\\n function _setImplementation(address newImplementation) internal {\\n require(\\n Address.isContract(newImplementation),\\n \\\"Cannot set a proxy implementation to a non-contract address\\\"\\n );\\n\\n bytes32 slot = IMPLEMENTATION_SLOT;\\n\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n sstore(slot, newImplementation)\\n }\\n }\\n}\\n\",\"keccak256\":\"0xcf9bc33957fa41a745726edb6461a4bddca875a038c848286a059f0f22b7f184\",\"license\":\"MIT\"},\"contracts/proxies/Proxies.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport { InitializeGovernedUpgradeabilityProxy } from \\\"./InitializeGovernedUpgradeabilityProxy.sol\\\";\\n\\n/**\\n * @notice OUSDProxy delegates calls to an OUSD implementation\\n */\\ncontract OUSDProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice WrappedOUSDProxy delegates calls to a WrappedOUSD implementation\\n */\\ncontract WrappedOUSDProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice VaultProxy delegates calls to a Vault implementation\\n */\\ncontract VaultProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice CompoundStrategyProxy delegates calls to a CompoundStrategy implementation\\n */\\ncontract CompoundStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice AaveStrategyProxy delegates calls to a AaveStrategy implementation\\n */\\ncontract AaveStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice ThreePoolStrategyProxy delegates calls to a ThreePoolStrategy implementation\\n */\\ncontract ThreePoolStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice ConvexStrategyProxy delegates calls to a ConvexStrategy implementation\\n */\\ncontract ConvexStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice HarvesterProxy delegates calls to a Harvester implementation\\n */\\ncontract HarvesterProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice DripperProxy delegates calls to a Dripper implementation\\n */\\ncontract DripperProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice MorphoCompoundStrategyProxy delegates calls to a MorphoCompoundStrategy implementation\\n */\\ncontract MorphoCompoundStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice ConvexOUSDMetaStrategyProxy delegates calls to a ConvexOUSDMetaStrategy implementation\\n */\\ncontract ConvexOUSDMetaStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice ConvexLUSDMetaStrategyProxy delegates calls to a ConvexalGeneralizedMetaStrategy implementation\\n */\\ncontract ConvexLUSDMetaStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice MorphoAaveStrategyProxy delegates calls to a MorphoCompoundStrategy implementation\\n */\\ncontract MorphoAaveStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice OETHProxy delegates calls to nowhere for now\\n */\\ncontract OETHProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice WOETHProxy delegates calls to nowhere for now\\n */\\ncontract WOETHProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice OETHVaultProxy delegates calls to a Vault implementation\\n */\\ncontract OETHVaultProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice OETHDripperProxy delegates calls to a OETHDripper implementation\\n */\\ncontract OETHDripperProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice OETHHarvesterProxy delegates calls to a Harvester implementation\\n */\\ncontract OETHHarvesterProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice FraxETHStrategyProxy delegates calls to a FraxETHStrategy implementation\\n */\\ncontract FraxETHStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice CurveEthStrategyProxy delegates calls to a CurveEthStrategy implementation\\n */\\ncontract ConvexEthMetaStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice BuybackProxy delegates calls to Buyback implementation\\n */\\ncontract BuybackProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice OETHMorphoAaveStrategyProxy delegates calls to a MorphoAaveStrategy implementation\\n */\\ncontract OETHMorphoAaveStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice OETHBalancerMetaPoolrEthStrategyProxy delegates calls to a BalancerMetaPoolStrategy implementation\\n */\\ncontract OETHBalancerMetaPoolrEthStrategyProxy is\\n InitializeGovernedUpgradeabilityProxy\\n{\\n\\n}\\n\\n/**\\n * @notice OETHBalancerMetaPoolwstEthStrategyProxy delegates calls to a BalancerMetaPoolStrategy implementation\\n */\\ncontract OETHBalancerMetaPoolwstEthStrategyProxy is\\n InitializeGovernedUpgradeabilityProxy\\n{\\n\\n}\\n\\n/**\\n * @notice FluxStrategyProxy delegates calls to a CompoundStrategy implementation\\n */\\ncontract FluxStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice MakerDsrStrategyProxy delegates calls to a Generalized4626Strategy implementation\\n */\\ncontract MakerDsrStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice FrxEthRedeemStrategyProxy delegates calls to a FrxEthRedeemStrategy implementation\\n */\\ncontract FrxEthRedeemStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice OETHBuybackProxy delegates calls to Buyback implementation\\n */\\ncontract OETHBuybackProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice BridgedWOETHProxy delegates calls to BridgedWOETH implementation\\n */\\ncontract BridgedWOETHProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice NativeStakingSSVStrategyProxy delegates calls to NativeStakingSSVStrategy implementation\\n */\\ncontract NativeStakingSSVStrategyProxy is\\n InitializeGovernedUpgradeabilityProxy\\n{\\n\\n}\\n\\n/**\\n * @notice NativeStakingFeeAccumulatorProxy delegates calls to NativeStakingFeeCollector implementation\\n */\\ncontract NativeStakingFeeAccumulatorProxy is\\n InitializeGovernedUpgradeabilityProxy\\n{\\n\\n}\\n\",\"keccak256\":\"0x2e294507edd91494e1020a2a1c43502d2f5cba01266c228406562ecde7a2d872\",\"license\":\"MIT\"}},\"version\":1}", + "bytecode": "0x608060405234801561001057600080fd5b506100273360008051602061099083398151915255565b600080516020610990833981519152546040516001600160a01b03909116906000907fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a908290a36109138061007d6000396000f3fe6080604052600436106100865760003560e01c80635d36b190116100595780635d36b1901461010a578063c7af33521461011f578063cf7a1d7714610144578063d38bfff414610157578063f851a4401461009057610086565b80630c340a24146100905780633659cfe6146100c25780634f1ef286146100e25780635c60da1b146100f5575b61008e610177565b005b34801561009c57600080fd5b506100a5610197565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156100ce57600080fd5b5061008e6100dd366004610745565b6101b4565b61008e6100f03660046107c8565b6101ed565b34801561010157600080fd5b506100a561028a565b34801561011657600080fd5b5061008e6102a2565b34801561012b57600080fd5b50610134610346565b60405190151581526020016100b9565b61008e610152366004610767565b610377565b34801561016357600080fd5b5061008e610172366004610745565b610491565b61019561019060008051602061089e8339815191525490565b610535565b565b60006101af6000805160206108be8339815191525490565b905090565b6101bc610346565b6101e15760405162461bcd60e51b81526004016101d89061082b565b60405180910390fd5b6101ea81610559565b50565b6101f5610346565b6102115760405162461bcd60e51b81526004016101d89061082b565b61021a83610559565b6000836001600160a01b0316838360405161023692919061081b565b600060405180830381855af49150503d8060008114610271576040519150601f19603f3d011682016040523d82523d6000602084013e610276565b606091505b505090508061028457600080fd5b50505050565b60006101af60008051602061089e8339815191525490565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b03161461033d5760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b60648201526084016101d8565b61019533610599565b600061035e6000805160206108be8339815191525490565b6001600160a01b0316336001600160a01b031614905090565b61037f610346565b61039b5760405162461bcd60e51b81526004016101d89061082b565b60006103b360008051602061089e8339815191525490565b6001600160a01b0316146103c657600080fd5b6103f160017f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbd610862565b60008051602061089e8339815191521461040d5761040d610887565b6104168461065a565b8015610488576000846001600160a01b0316838360405161043892919061081b565b600060405180830381855af49150503d8060008114610473576040519150601f19603f3d011682016040523d82523d6000602084013e610478565b606091505b505090508061048657600080fd5b505b61028483610599565b610499610346565b6104b55760405162461bcd60e51b81526004016101d89061082b565b6104dd817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b03166104fd6000805160206108be8339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b3660008037600080366000845af43d6000803e808015610554573d6000f35b3d6000fd5b6105628161065a565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b6001600160a01b0381166105ef5760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f72206973206164647265737328302900000000000060448201526064016101d8565b806001600160a01b031661060f6000805160206108be8339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a36101ea816000805160206108be83398151915255565b803b6106ce5760405162461bcd60e51b815260206004820152603b60248201527f43616e6e6f742073657420612070726f787920696d706c656d656e746174696f60448201527f6e20746f2061206e6f6e2d636f6e74726163742061646472657373000000000060648201526084016101d8565b60008051602061089e83398151915255565b80356001600160a01b03811681146106f757600080fd5b919050565b60008083601f84011261070e57600080fd5b50813567ffffffffffffffff81111561072657600080fd5b60208301915083602082850101111561073e57600080fd5b9250929050565b60006020828403121561075757600080fd5b610760826106e0565b9392505050565b6000806000806060858703121561077d57600080fd5b610786856106e0565b9350610794602086016106e0565b9250604085013567ffffffffffffffff8111156107b057600080fd5b6107bc878288016106fc565b95989497509550505050565b6000806000604084860312156107dd57600080fd5b6107e6846106e0565b9250602084013567ffffffffffffffff81111561080257600080fd5b61080e868287016106fc565b9497909650939450505050565b8183823760009101908152919050565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b60008282101561088257634e487b7160e01b600052601160045260246000fd5b500390565b634e487b7160e01b600052600160045260246000fdfe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa2646970667358221220b3f929c3c69d1d03671d5b3b3a689cea57e98352cc408801db470a634a99c09864736f6c634300080700337bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a", + "deployedBytecode": "0x6080604052600436106100865760003560e01c80635d36b190116100595780635d36b1901461010a578063c7af33521461011f578063cf7a1d7714610144578063d38bfff414610157578063f851a4401461009057610086565b80630c340a24146100905780633659cfe6146100c25780634f1ef286146100e25780635c60da1b146100f5575b61008e610177565b005b34801561009c57600080fd5b506100a5610197565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156100ce57600080fd5b5061008e6100dd366004610745565b6101b4565b61008e6100f03660046107c8565b6101ed565b34801561010157600080fd5b506100a561028a565b34801561011657600080fd5b5061008e6102a2565b34801561012b57600080fd5b50610134610346565b60405190151581526020016100b9565b61008e610152366004610767565b610377565b34801561016357600080fd5b5061008e610172366004610745565b610491565b61019561019060008051602061089e8339815191525490565b610535565b565b60006101af6000805160206108be8339815191525490565b905090565b6101bc610346565b6101e15760405162461bcd60e51b81526004016101d89061082b565b60405180910390fd5b6101ea81610559565b50565b6101f5610346565b6102115760405162461bcd60e51b81526004016101d89061082b565b61021a83610559565b6000836001600160a01b0316838360405161023692919061081b565b600060405180830381855af49150503d8060008114610271576040519150601f19603f3d011682016040523d82523d6000602084013e610276565b606091505b505090508061028457600080fd5b50505050565b60006101af60008051602061089e8339815191525490565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b03161461033d5760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b60648201526084016101d8565b61019533610599565b600061035e6000805160206108be8339815191525490565b6001600160a01b0316336001600160a01b031614905090565b61037f610346565b61039b5760405162461bcd60e51b81526004016101d89061082b565b60006103b360008051602061089e8339815191525490565b6001600160a01b0316146103c657600080fd5b6103f160017f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbd610862565b60008051602061089e8339815191521461040d5761040d610887565b6104168461065a565b8015610488576000846001600160a01b0316838360405161043892919061081b565b600060405180830381855af49150503d8060008114610473576040519150601f19603f3d011682016040523d82523d6000602084013e610478565b606091505b505090508061048657600080fd5b505b61028483610599565b610499610346565b6104b55760405162461bcd60e51b81526004016101d89061082b565b6104dd817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b03166104fd6000805160206108be8339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b3660008037600080366000845af43d6000803e808015610554573d6000f35b3d6000fd5b6105628161065a565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b6001600160a01b0381166105ef5760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f72206973206164647265737328302900000000000060448201526064016101d8565b806001600160a01b031661060f6000805160206108be8339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a36101ea816000805160206108be83398151915255565b803b6106ce5760405162461bcd60e51b815260206004820152603b60248201527f43616e6e6f742073657420612070726f787920696d706c656d656e746174696f60448201527f6e20746f2061206e6f6e2d636f6e74726163742061646472657373000000000060648201526084016101d8565b60008051602061089e83398151915255565b80356001600160a01b03811681146106f757600080fd5b919050565b60008083601f84011261070e57600080fd5b50813567ffffffffffffffff81111561072657600080fd5b60208301915083602082850101111561073e57600080fd5b9250929050565b60006020828403121561075757600080fd5b610760826106e0565b9392505050565b6000806000806060858703121561077d57600080fd5b610786856106e0565b9350610794602086016106e0565b9250604085013567ffffffffffffffff8111156107b057600080fd5b6107bc878288016106fc565b95989497509550505050565b6000806000604084860312156107dd57600080fd5b6107e6846106e0565b9250602084013567ffffffffffffffff81111561080257600080fd5b61080e868287016106fc565b9497909650939450505050565b8183823760009101908152919050565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b60008282101561088257634e487b7160e01b600052601160045260246000fd5b500390565b634e487b7160e01b600052600160045260246000fdfe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa2646970667358221220b3f929c3c69d1d03671d5b3b3a689cea57e98352cc408801db470a634a99c09864736f6c63430008070033", + "libraries": {}, + "devdoc": { + "kind": "dev", + "methods": { + "admin()": { + "returns": { + "_0": "The address of the proxy admin/it's also the governor." + } + }, + "implementation()": { + "returns": { + "_0": "The address of the implementation." + } + }, + "initialize(address,address,bytes)": { + "details": "Contract initializer with Governor enforcement", + "params": { + "_data": "Data to send as msg.data to the implementation to initialize the proxied contract. It should include the signature and the parameters of the function to be called, as described in https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding. This parameter is optional, if no data is given the initialization call to proxied contract will be skipped.", + "_initGovernor": "Address of the initial Governor.", + "_logic": "Address of the initial implementation." + } + }, + "transferGovernance(address)": { + "params": { + "_newGovernor": "Address of the new Governor" + } + }, + "upgradeTo(address)": { + "details": "Upgrade the backing implementation of the proxy. Only the admin can call this function.", + "params": { + "newImplementation": "Address of the new implementation." + } + }, + "upgradeToAndCall(address,bytes)": { + "details": "Upgrade the backing implementation of the proxy and call a function on the new implementation. This is useful to initialize the proxied contract.", + "params": { + "data": "Data to send as msg.data in the low level call. It should include the signature and the parameters of the function to be called, as described in https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.", + "newImplementation": "Address of the new implementation." + } + } + }, + "version": 1 + }, + "userdoc": { + "kind": "user", + "methods": { + "claimGovernance()": { + "notice": "Claim Governance of the contract to a new account (`newGovernor`). Can only be called by the new Governor." + }, + "governor()": { + "notice": "Returns the address of the current Governor." + }, + "isGovernor()": { + "notice": "Returns true if the caller is the current Governor." + }, + "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" + } + }, + "notice": "OETHProxy delegates calls to nowhere for now", + "version": 1 + }, + "storageLayout": { + "storage": [], + "types": null + } +} \ No newline at end of file diff --git a/contracts/deployments/holesky/OETHVault.json b/contracts/deployments/holesky/OETHVault.json new file mode 100644 index 0000000000..6356d624af --- /dev/null +++ b/contracts/deployments/holesky/OETHVault.json @@ -0,0 +1,1876 @@ +{ + "address": "0xa7191fEE1Ed313908FCb09D09b82ABB7BC56F71B", + "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": [ + { + "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": [], + "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" + } + ], + "transactionHash": "0x303a9d73b60a05e93c91590b0f8da9c9549d6953c980c21b518af3d2155d8482", + "receipt": { + "to": null, + "from": "0x1b94CA50D3Ad9f8368851F8526132272d1a5028C", + "contractAddress": "0xa7191fEE1Ed313908FCb09D09b82ABB7BC56F71B", + "transactionIndex": 31, + "gasUsed": "3292765", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020200000000000000000800000000000000000000000000000000000004000000000000002000000000100000000040000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000010000000000010000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0xc85ed1a0003622a8ae087a6b18f630a7b5dafd2a1ed4bade52146d665dff8d75", + "transactionHash": "0x303a9d73b60a05e93c91590b0f8da9c9549d6953c980c21b518af3d2155d8482", + "logs": [ + { + "transactionIndex": 31, + "blockNumber": 1405059, + "transactionHash": "0x303a9d73b60a05e93c91590b0f8da9c9549d6953c980c21b518af3d2155d8482", + "address": "0xa7191fEE1Ed313908FCb09D09b82ABB7BC56F71B", + "topics": [ + "0xc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000001b94ca50d3ad9f8368851f8526132272d1a5028c" + ], + "data": "0x", + "logIndex": 77, + "blockHash": "0xc85ed1a0003622a8ae087a6b18f630a7b5dafd2a1ed4bade52146d665dff8d75" + } + ], + "blockNumber": 1405059, + "cumulativeGasUsed": "6440889", + "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\":[{\"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\":[],\"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 Vault 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/OETHVault.sol\":\"OETHVault\"},\"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/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\",\"keccak256\":\"0x7c4d2c2b5b3c81f7a57b54ea04ec8f9a695f19eb972c406746040a45b31f1ef7\",\"license\":\"MIT\"},\"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\",\"keccak256\":\"0x52e100641bfeb95769b37b5723b123a101d443fc62d115ecd8816b15b4a37c82\",\"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/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": "0x6037805461ffff60a01b1916600160a81b179055603d80546001600160a01b0319908116909155603e805482169055603f80548216905560458054909116905560006046819055604781905560c0604052608081905260a052604880546001600160b01b03191690553480156200007557600080fd5b506200008e3360008051602062003a4e83398151915255565b60008051602062003a4e833981519152546040516001600160a01b03909116906000907fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a908290a361396880620000e66000396000f3fe608060405234801561001057600080fd5b506004361061030c5760003560e01c80636c7561e81161019d578063b888879e116100e9578063d38bfff4116100a2578063e6cc54321161007c578063e6cc54321461064b578063e829cc161461065f578063eb03654b14610672578063fc0cfeee1461068557600080fd5b8063d38bfff41461061c578063d58e3b3a1461062f578063e45cc9f01461064257600080fd5b8063b888879e146105cb578063b890ebf6146105de578063bc90106b146105f1578063c5f0084114610604578063c7af33521461060c578063c99191121461061457600080fd5b80638ec489a2116101565780639fa1826e116101305780639fa1826e14610573578063a403e4d51461057c578063ae69f3cb146105a5578063b2c9336d146105b857600080fd5b80638ec489a21461054557806394828ffd146105585780639c82f2a41461056057600080fd5b80636c7561e8146104e7578063773540b3146104fa5780637a2202f31461050d5780637b9a709614610516578063840c4c7a146105295780638e510b521461053c57600080fd5b80633b8ae3971161025c57806352d38e5d11610215578063597c8910116101ef578063597c8910146104a65780635d36b190146104b9578063636e6c40146104c1578063663e64ce146104d457600080fd5b806352d38e5d1461046657806353ca9f241461046f578063570d8e1d1461049357600080fd5b80633b8ae397146103ff5780633dbc911f14610412578063485cc9551461041a57806349c1d54d1461042d5780634bed3bc01461044057806350ba711c1461045357600080fd5b806318ce56bd116102c95780632b3297f9116102a35780632b3297f9146103b55780632da845a8146103c657806336b6d944146103d9578063372aa224146103ec57600080fd5b806318ce56bd146103905780631edfe3da146103a3578063207134b0146103ac57600080fd5b806309f49bf51461031157806309f6442c1461031b5780630acbda75146103375780630c340a241461034a5780631072cbea1461036a578063175188e81461037d575b600080fd5b610319610698565b005b61032460385481565b6040519081526020015b60405180910390f35b610319610345366004613537565b610711565b6103526107c3565b6040516001600160a01b03909116815260200161032e565b610319610378366004613499565b6107e0565b61031961038b3660046132fa565b61088d565b604554610352906001600160a01b031681565b61032460395481565b61032460435481565b6048546001600160a01b0316610352565b6103196103d43660046132fa565b610b8e565b6103196103e73660046132fa565b610c00565b6103196103fa3660046132fa565b610c30565b61031961040d3660046132fa565b610ca2565b610319610ddf565b610319610428366004613315565b610e55565b604254610352906001600160a01b031681565b604854600160a01b900461ffff16610324565b610324610461366004613348565b611057565b610324603b5481565b60375461048390600160a01b900460ff1681565b604051901515815260200161032e565b603f54610352906001600160a01b031681565b6103196104b43660046132fa565b611877565b610319611973565b6103196104cf366004613537565b611a19565b6103196104e2366004613537565b611a77565b6103196104f53660046134c3565b611ad0565b6103196105083660046132fa565b611d4e565b61032460475481565b61031961052436600461346f565b611dc0565b6103196105373660046133ee565b611ef6565b61032460415481565b610319610553366004613537565b611f8f565b610319612044565b61031961056e3660046132fa565b6120b4565b610324603a5481565b61035261058a3660046132fa565b6040602081905260009182529020546001600160a01b031681565b6103196105b33660046133ee565b612126565b6103196105c6366004613537565b6121b4565b603754610352906001600160a01b031681565b6103196105ec366004613537565b61220d565b6103196105ff366004613315565b612266565b6103196124a8565b61048361251e565b61031961254f565b61031961062a3660046132fa565b612619565b61031961063d3660046132fa565b6126bd565b61032460465481565b60375461048390600160a81b900460ff1681565b61031961066d36600461351c565b61272f565b610319610680366004613537565b6127ef565b6103196106933660046132fa565b6128a4565b603f546001600160a01b03163314806106b457506106b461251e565b6106d95760405162461bcd60e51b81526004016106d090613668565b60405180910390fd5b6037805460ff60a01b191690556040517fbc044409505c95b6b851433df96e1beae715c909d8e7c1d6d7ab783300d4e3b990600090a1565b61071961251e565b6107355760405162461bcd60e51b81526004016106d090613631565b6113888111156107875760405162461bcd60e51b815260206004820152601760248201527f62617369732063616e6e6f74206578636565642035302500000000000000000060448201526064016106d0565b60438190556040518181527f56287a45051933ea374811b3d5d165033047be5572cac676f7c28b8be4f746c7906020015b60405180910390a150565b60006107db6000805160206139138339815191525490565b905090565b6107e861251e565b6108045760405162461bcd60e51b81526004016106d090613631565b6001600160a01b03821660009081526033602052604090205460ff161561086d5760405162461bcd60e51b815260206004820152601760248201527f4f6e6c7920756e737570706f727465642061737365747300000000000000000060448201526064016106d0565b6108896108786107c3565b6001600160a01b0384169083612946565b5050565b61089561251e565b6108b15760405162461bcd60e51b81526004016106d090613631565b6001600160a01b03811660009081526035602052604090205460ff166109115760405162461bcd60e51b815260206004820152601560248201527414dd1c985d1959de481b9bdd08185c1c1c9bdd9959605a1b60448201526064016106d0565b60345460005b818110156109c957826001600160a01b03166040600060348481548110610940576109406138ed565b60009182526020808320909101546001600160a01b0390811684529083019390935260409091019020541614156109b95760405162461bcd60e51b815260206004820181905260248201527f53747261746567792069732064656661756c7420666f7220616e20617373657460448201526064016106d0565b6109c281613890565b9050610917565b506036548060005b82811015610a2957846001600160a01b0316603682815481106109f6576109f66138ed565b6000918252602090912001546001600160a01b03161415610a1957809150610a29565b610a2281613890565b90506109d1565b5081811015610b88576036610a3f60018461384d565b81548110610a4f57610a4f6138ed565b600091825260209091200154603680546001600160a01b039092169183908110610a7b57610a7b6138ed565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055506036805480610aba57610aba6138d7565b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b03861680835260359091526040808320805460ff19169055805163429c145b60e11b81529051879363853828b6926004808201939182900301818387803b158015610b3157600080fd5b505af1158015610b45573d6000803e3d6000fd5b50506040516001600160a01b03881681527f09a1db4b80c32706328728508c941a6b954f31eb5affd32f236c1fd405f8fea49250602001905060405180910390a1505b50505050565b610b9661251e565b610bb25760405162461bcd60e51b81526004016106d090613631565b604280546001600160a01b0319166001600160a01b0383169081179091556040519081527f1e4af5ac389e8cde1bdaa6830881b6c987c62a45cfb3b33d27d805cde3b57750906020016107b8565b610c0861251e565b610c245760405162461bcd60e51b81526004016106d090613631565b610c2d81612998565b50565b610c3861251e565b610c545760405162461bcd60e51b81526004016106d090613631565b603780546001600160a01b0319166001600160a01b0383169081179091556040519081527fb266add5f3044b17d27db796af992cecbe413921b4e8aaaee03c719e16b9806a906020016107b8565b610caa61251e565b610cc65760405162461bcd60e51b81526004016106d090613631565b6001600160a01b03811660009081526035602052604090205460ff1615610d2f5760405162461bcd60e51b815260206004820152601960248201527f537472617465677920616c726561647920617070726f7665640000000000000060448201526064016106d0565b6040805180820182526001808252600060208084018281526001600160a01b038716808452603583528684209551865460ff19169015151786559051948401949094556036805493840181559091527f4a11f94e20a93c79f6ec743a1954ec4fc2c08429ae2122118bf234b2185c81b890910180546001600160a01b0319168317905591519081527f960dd94cbb79169f09a4e445d58b895df2d9bffa5b31055d0932d801724a20d191016107b8565b603f546001600160a01b0316331480610dfb5750610dfb61251e565b610e175760405162461bcd60e51b81526004016106d090613668565b6037805460ff60a81b1916600160a81b1790556040517f71f0e5b62f846a22e0b4d159e516e62fa9c2b8eb570be15f83e67d98a2ee51e090600090a1565b610e5d61251e565b610e795760405162461bcd60e51b81526004016106d090613631565b600054610100900460ff1680610e92575060005460ff16155b610ef55760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016106d0565b600054610100900460ff16158015610f17576000805461ffff19166101011790555b6001600160a01b038316610f6d5760405162461bcd60e51b815260206004820152601d60248201527f507269636550726f76696465722061646472657373206973207a65726f00000060448201526064016106d0565b6001600160a01b038216610fbc5760405162461bcd60e51b81526020600482015260166024820152756f546f6b656e2061646472657373206973207a65726f60501b60448201526064016106d0565b603c80546001600160a01b038481166001600160a01b031990921691909117909155603780546001600160b01b03191691851691909117600160a81b17905560006038819055603981905569054b40b1f852bda00000603a55683635c9adc5dea00000603b55604080519182526020820190819052905161103f91603691613206565b508015611052576000805461ff00191690555b505050565b7f53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac4535805460009190600281141561109f5760405162461bcd60e51b81526004016106d0906136b0565b60028255603f546001600160a01b03163314806110bf57506110bf61251e565b6110db5760405162461bcd60e51b81526004016106d090613668565b6001600160a01b0389166000908152603360209081526040808320815160808101909252805460ff80821615158452929391929184019161010090910416600181111561112a5761112a6138c1565b600181111561113b5761113b6138c1565b8152905462010000810460ff908116602080850191909152630100000090920461ffff166040938401526001600160a01b038d16600090815260338352838120845160808101909552805480841615158652959650909490928401916101009091041660018111156111af576111af6138c1565b60018111156111c0576111c06138c1565b8152905462010000810460ff1660208301526301000000900461ffff1660409091015282519091506112345760405162461bcd60e51b815260206004820152601b60248201527f46726f6d206173736574206973206e6f7420737570706f72746564000000000060448201526064016106d0565b80516112825760405162461bcd60e51b815260206004820152601960248201527f546f206173736574206973206e6f7420737570706f727465640000000000000060448201526064016106d0565b6040805180820182526048546001600160a01b038082168352600160a01b90910461ffff16602083015291516370a0823160e01b81523060048201529091600091908d16906370a082319060240160206040518083038186803b1580156112e857600080fd5b505afa1580156112fc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113209190613550565b825190915061133a906001600160a01b038f16908d612946565b81600001516001600160a01b0316632506c0188e8e60018f61135c919061384d565b8e8e8e6040518763ffffffff1660e01b8152600401611380969594939291906135a2565b602060405180830381600087803b15801561139a57600080fd5b505af11580156113ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113d29190613550565b506040516370a0823160e01b815230600482015281906001600160a01b038e16906370a082319060240160206040518083038186803b15801561141457600080fd5b505afa158015611428573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061144c9190613550565b611456919061384d565b965050888610156114a95760405162461bcd60e51b815260206004820152601960248201527f5374726174656769737420736c697070616765206c696d69740000000000000060448201526064016106d0565b600082606001516127106114bd91906136d8565b6037546040516315d5220f60e31b81526001600160a01b038f8116600483015261ffff93909316929091169063aea910789060240160206040518083038186803b15801561150a57600080fd5b505afa15801561151e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115429190613550565b61154c919061380b565b603760009054906101000a90046001600160a01b03166001600160a01b031663aea910788f6040518263ffffffff1660e01b815260040161159c91906001600160a01b0391909116815260200190565b60206040518083038186803b1580156115b457600080fd5b505afa1580156115c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115ec9190613550565b60608601516115fd9061271061382a565b61160b9061ffff168e61380b565b611615919061380b565b61161f91906136fe565b905061163e6012856040015160ff1683612aae9092919063ffffffff16565b604084015161165490899060129060ff16612aae565b10156116a25760405162461bcd60e51b815260206004820152601e60248201527f4f7261636c6520736c697070616765206c696d6974206578636565646564000060448201526064016106d0565b5061271081602001516127106116b8919061382a565b61ffff16603c60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561170a57600080fd5b505afa15801561171e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117429190613550565b61174c919061380b565b61175691906136fe565b306001600160a01b031663d4c3eea06040518163ffffffff1660e01b815260040160206040518083038186803b15801561178f57600080fd5b505afa1580156117a3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117c79190613550565b101561180e5760405162461bcd60e51b8152602060048201526016602482015275416c6c6f7765642076616c7565203c20737570706c7960501b60448201526064016106d0565b8a6001600160a01b03168c6001600160a01b03167fa078c4190abe07940190effc1846be0ccf03ad6007bc9e93f9697d0b460befbb8c8960405161185c929190918252602082015260400190565b60405180910390a35050506001825550509695505050505050565b603f546001600160a01b0316331480611893575061189361251e565b6118af5760405162461bcd60e51b81526004016106d090613668565b6001600160a01b03811660009081526035602052604090205460ff166119175760405162461bcd60e51b815260206004820152601960248201527f5374726174656779206973206e6f7420737570706f727465640000000000000060448201526064016106d0565b6000819050806001600160a01b031663853828b66040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561195757600080fd5b505af115801561196b573d6000803e3d6000fd5b505050505050565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b031614611a0e5760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b60648201526084016106d0565b611a1733612b12565b565b611a2161251e565b611a3d5760405162461bcd60e51b81526004016106d090613631565b600060465560478190556040518181527fc29d6fedbc6bdf267a08166c2b976fbd72aca5d6a769528616f8b9224c8f197f906020016107b8565b611a7f61251e565b611a9b5760405162461bcd60e51b81526004016106d090613631565b60418190556040518181527f95201f9c21f26877223b1ff4073936a6484c35495649e60e55730497aeb60d93906020016107b8565b611ad861251e565b611af45760405162461bcd60e51b81526004016106d090613631565b6001600160a01b03821660009081526033602052604090205460ff1615611b5d5760405162461bcd60e51b815260206004820152601760248201527f417373657420616c726561647920737570706f7274656400000000000000000060448201526064016106d0565b60405180608001604052806001151581526020018260ff166001811115611b8657611b866138c1565b6001811115611b9757611b976138c1565b81526000602080830182905260409283018290526001600160a01b0386168252603381529190208251815490151560ff19821681178355928401519192839161ff001990911661ffff1990911617610100836001811115611bfa57611bfa6138c1565b02179055506040820151815460609093015161ffff1663010000000264ffff0000001960ff90921662010000029190911664ffffff00001990931692909217919091179055611c4882612998565b603480546001810182556000919091527f46bddb1178e94d7f2892ff5f366840eb658911794f2c3a44c450aa2c505186c10180546001600160a01b0319166001600160a01b038481169182179092556037546040516315d5220f60e31b815260048101929092529091169063aea910789060240160206040518083038186803b158015611cd457600080fd5b505afa158015611ce8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d0c9190613550565b506040516001600160a01b03831681527f4f1ac48525e50059cc1cc6e0e1940ece0dd653a4db4841538d6aef036be2fb7b906020015b60405180910390a15050565b611d5661251e565b611d725760405162461bcd60e51b81526004016106d090613631565b603f80546001600160a01b0319166001600160a01b0383169081179091556040519081527f869e0abd13cc3a975de7b93be3df1cb2255c802b1cead85963cc79d99f131bee906020016107b8565b611dc861251e565b611de45760405162461bcd60e51b81526004016106d090613631565b6001600160a01b03821660009081526033602052604090205460ff16611e425760405162461bcd60e51b8152602060048201526013602482015272105cdcd95d081b9bdd081cdd5c1c1bdc9d1959606a1b60448201526064016106d0565b6103e88161ffff1610611e8b5760405162461bcd60e51b81526020600482015260116024820152700a6d8d2e0e0c2ceca40e8dede40d0d2ced607b1b60448201526064016106d0565b6001600160a01b038216600081815260336020908152604091829020805464ffff0000001916630100000061ffff8716908102919091179091558251938452908301527f8d22e9d2cbe8bb65a3c4412bd8970743864512a1a0e004e8d00fb96277b78b949101611d42565b603f546001600160a01b0316331480611f125750611f1261251e565b611f2e5760405162461bcd60e51b81526004016106d090613668565b7f53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac453580546002811415611f725760405162461bcd60e51b81526004016106d0906136b0565b60028255611f838787878787612bd3565b50600190555050505050565b603f546001600160a01b0316331480611fab5750611fab61251e565b611fc75760405162461bcd60e51b81526004016106d090613668565b670de0b6b3a764000081111561200f5760405162461bcd60e51b815260206004820152600d60248201526c496e76616c69642076616c756560981b60448201526064016106d0565b60398190556040518181527f41ecb23a0e7865b25f38c268b7c3012220d822929e9edff07326e89d5bb822b5906020016107b8565b603f546001600160a01b0316331480612060575061206061251e565b61207c5760405162461bcd60e51b81526004016106d090613668565b6037805460ff60a81b191690556040517f891ebab18da80ebeeea06b1b1cede098329c4c008906a98370c2ac7a80b571cb90600090a1565b6120bc61251e565b6120d85760405162461bcd60e51b81526004016106d090613631565b604880546001600160a01b0319166001600160a01b0383169081179091556040519081527f7d7719313229e558c5a3893cad2eb86a86a049156d1d9ebd5c63a8eedefd1c03906020016107b8565b603f546001600160a01b0316331480612142575061214261251e565b61215e5760405162461bcd60e51b81526004016106d090613668565b7f53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac4535805460028114156121a25760405162461bcd60e51b81526004016106d0906136b0565b60028255611f83308888888888612e11565b6121bc61251e565b6121d85760405162461bcd60e51b81526004016106d090613631565b603a8190556040518181527f2ec5fb5a3d2703edc461252d92ccd2799c3c74f01d97212b20388207fa17ae45906020016107b8565b61221561251e565b6122315760405162461bcd60e51b81526004016106d090613631565b603b8190556040518181527f39367850377ac04920a9a670f2180e7a94d83b15ad302e59875ec58fd10bd37d906020016107b8565b603f546001600160a01b0316331480612282575061228261251e565b61229e5760405162461bcd60e51b81526004016106d090613668565b604080516001600160a01b038085168252831660208201527fba58ce12801c949fa65f41c46ed108671c219baf945fa48d21026cea99ff252a910160405180910390a16001600160a01b0381161561247a576001600160a01b03811660009081526035602052604090205460ff166123505760405162461bcd60e51b815260206004820152601560248201527414dd1c985d1959de481b9bdd08185c1c1c9bdd9959605a1b60448201526064016106d0565b6001600160a01b038216600090815260336020526040902054819060ff166123b35760405162461bcd60e51b8152602060048201526016602482015275105cdcd95d081a5cc81b9bdd081cdd5c1c1bdc9d195960521b60448201526064016106d0565b60405163551c457b60e11b81526001600160a01b03848116600483015282169063aa388af69060240160206040518083038186803b1580156123f457600080fd5b505afa158015612408573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061242c91906134fa565b6124785760405162461bcd60e51b815260206004820152601f60248201527f4173736574206e6f7420737570706f727465642062792053747261746567790060448201526064016106d0565b505b6001600160a01b03918216600090815260406020819052902080546001600160a01b03191691909216179055565b603f546001600160a01b03163314806124c457506124c461251e565b6124e05760405162461bcd60e51b81526004016106d090613668565b6037805460ff60a01b1916600160a01b1790556040517f8cff26a5985614b3d30629cc4ab83824bf115aec971b718d8f2f99562032e97290600090a1565b60006125366000805160206139138339815191525490565b6001600160a01b0316336001600160a01b031614905090565b603f546001600160a01b031633148061256b575061256b61251e565b6125875760405162461bcd60e51b81526004016106d090613668565b60365460005b8181101561088957603681815481106125a8576125a86138ed565b60009182526020822001546040805163429c145b60e11b815290516001600160a01b039092169263853828b69260048084019382900301818387803b1580156125f057600080fd5b505af1158015612604573d6000803e3d6000fd5b505050508061261290613890565b905061258d565b61262161251e565b61263d5760405162461bcd60e51b81526004016106d090613631565b612665817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b03166126856000805160206139138339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b6126c561251e565b6126e15760405162461bcd60e51b81526004016106d090613631565b604580546001600160a01b0319166001600160a01b0383169081179091556040519081527fa12850fb726e0b2b7b3c9a9342031e1268a8148d0eb06b4bea8613204ffcd2b8906020016107b8565b61273761251e565b6127535760405162461bcd60e51b81526004016106d090613631565b6127118161ffff161061279f5760405162461bcd60e51b8152602060048201526014602482015273496e76616c696420626173697320706f696e747360601b60448201526064016106d0565b6048805461ffff60a01b1916600160a01b61ffff8416908102919091179091556040519081527ff12c00256bee2b6facb111a88a9b1cff86e79132939b44f1353212d6f7469557906020016107b8565b6127f761251e565b6128135760405162461bcd60e51b81526004016106d090613631565b6103e881111561286f5760405162461bcd60e51b815260206004820152602160248201527f52656465656d206665652073686f756c64206e6f74206265206f7665722031306044820152602560f81b60648201526084016106d0565b60388190556040518181527fd6c7508d6658ccee36b7b7d7fd72e5cbaeefb40c64eff24e9ae7470e846304ee906020016107b8565b6128ac61251e565b6128c85760405162461bcd60e51b81526004016106d090613631565b803b6129225760405162461bcd60e51b8152602060048201526024808201527f6e657720696d706c656d656e746174696f6e206973206e6f74206120636f6e746044820152631c9858dd60e21b60648201526084016106d0565b7fa2bd3d3cf188a41358c8b401076eb59066b09dec5775650c0de4c55187d17bd955565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052611052908490612f9b565b6001600160a01b0381166000908152603360205260409020805462010000900460ff16156129c4575050565b6000826001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b1580156129ff57600080fd5b505afa158015612a13573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a379190613569565b905060068160ff1610158015612a51575060128160ff1611155b612a945760405162461bcd60e51b81526020600482015260146024820152732ab732bc3832b1ba32b210383932b1b4b9b4b7b760611b60448201526064016106d0565b815460ff909116620100000262ff00001990911617905550565b600081831115612ade57612ad7612ac5838561384d565b612ad090600a613763565b859061306d565b9350612b08565b81831015612b0857612b05612af3848461384d565b612afe90600a613763565b8590613082565b93505b50825b9392505050565b6001600160a01b038116612b685760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f72206973206164647265737328302900000000000060448201526064016106d0565b806001600160a01b0316612b886000805160206139138339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a3610c2d8160008051602061391383398151915255565b6001600160a01b03851660009081526035602052604090205460ff16612c315760405162461bcd60e51b8152602060048201526013602482015272496e76616c696420746f20537472617465677960681b60448201526064016106d0565b828114612c7c5760405162461bcd60e51b81526020600482015260196024820152780a0c2e4c2dacae8cae440d8cadccee8d040dad2e6dac2e8c6d603b1b60448201526064016106d0565b8260005b81811015612db5576000868683818110612c9c57612c9c6138ed565b9050602002016020810190612cb191906132fa565b60405163551c457b60e11b81526001600160a01b0380831660048301529192509089169063aa388af69060240160206040518083038186803b158015612cf657600080fd5b505afa158015612d0a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d2e91906134fa565b612d6e5760405162461bcd60e51b8152602060048201526011602482015270105cdcd95d081d5b9cdd5c1c1bdc9d1959607a1b60448201526064016106d0565b612da488868685818110612d8457612d846138ed565b90506020020135836001600160a01b03166129469092919063ffffffff16565b50612dae81613890565b9050612c80565b50856001600160a01b031663de5f62686040518163ffffffff1660e01b8152600401600060405180830381600087803b158015612df157600080fd5b505af1158015612e05573d6000803e3d6000fd5b50505050505050505050565b6001600160a01b03851660009081526035602052604090205460ff16612e715760405162461bcd60e51b8152602060048201526015602482015274496e76616c69642066726f6d20537472617465677960581b60448201526064016106d0565b828114612ebc5760405162461bcd60e51b81526020600482015260196024820152780a0c2e4c2dacae8cae440d8cadccee8d040dad2e6dac2e8c6d603b1b60448201526064016106d0565b8260005b81811015612f9157866001600160a01b031663d9caed1289888885818110612eea57612eea6138ed565b9050602002016020810190612eff91906132fa565b878786818110612f1157612f116138ed565b6040516001600160e01b031960e088901b1681526001600160a01b03958616600482015294909316602485015250602090910201356044820152606401600060405180830381600087803b158015612f6857600080fd5b505af1158015612f7c573d6000803e3d6000fd5b5050505080612f8a90613890565b9050612ec0565b5050505050505050565b6000612ff0826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661308e9092919063ffffffff16565b805190915015611052578080602001905181019061300e91906134fa565b6110525760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016106d0565b6000613079828461380b565b90505b92915050565b600061307982846136fe565b606061309d84846000856130a5565b949350505050565b6060824710156131065760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016106d0565b843b6131545760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016106d0565b600080866001600160a01b031685876040516131709190613586565b60006040518083038185875af1925050503d80600081146131ad576040519150601f19603f3d011682016040523d82523d6000602084013e6131b2565b606091505b50915091506131c28282866131cd565b979650505050505050565b606083156131dc575081612b0b565b8251156131ec5782518084602001fd5b8160405162461bcd60e51b81526004016106d091906135fe565b82805482825590600052602060002090810192821561325b579160200282015b8281111561325b57825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190613226565b5061326792915061326b565b5090565b5b80821115613267576000815560010161326c565b80356001600160a01b038116811461329757600080fd5b919050565b60008083601f8401126132ae57600080fd5b50813567ffffffffffffffff8111156132c657600080fd5b6020830191508360208260051b85010111156132e157600080fd5b9250929050565b803561ffff8116811461329757600080fd5b60006020828403121561330c57600080fd5b61307982613280565b6000806040838503121561332857600080fd5b61333183613280565b915061333f60208401613280565b90509250929050565b60008060008060008060a0878903121561336157600080fd5b61336a87613280565b955061337860208801613280565b94506040870135935060608701359250608087013567ffffffffffffffff808211156133a357600080fd5b818901915089601f8301126133b757600080fd5b8135818111156133c657600080fd5b8a60208285010111156133d857600080fd5b6020830194508093505050509295509295509295565b60008060008060006060868803121561340657600080fd5b61340f86613280565b9450602086013567ffffffffffffffff8082111561342c57600080fd5b61343889838a0161329c565b9096509450604088013591508082111561345157600080fd5b5061345e8882890161329c565b969995985093965092949392505050565b6000806040838503121561348257600080fd5b61348b83613280565b915061333f602084016132e8565b600080604083850312156134ac57600080fd5b6134b583613280565b946020939093013593505050565b600080604083850312156134d657600080fd5b6134df83613280565b915060208301356134ef81613903565b809150509250929050565b60006020828403121561350c57600080fd5b81518015158114612b0b57600080fd5b60006020828403121561352e57600080fd5b613079826132e8565b60006020828403121561354957600080fd5b5035919050565b60006020828403121561356257600080fd5b5051919050565b60006020828403121561357b57600080fd5b8151612b0b81613903565b60008251613598818460208701613864565b9190910192915050565b6001600160a01b03878116825286166020820152604081018590526060810184905260a06080820181905281018290526000828460c0840137600060c0848401015260c0601f19601f8501168301019050979650505050505050565b602081526000825180602084015261361d816040850160208701613864565b601f01601f19169190910160400192915050565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b60208082526028908201527f43616c6c6572206973206e6f74207468652053747261746567697374206f722060408201526723b7bb32b93737b960c11b606082015260800190565b6020808252600e908201526d1499595b9d1c985b9d0818d85b1b60921b604082015260600190565b600061ffff8083168185168083038211156136f5576136f56138ab565b01949350505050565b60008261371b57634e487b7160e01b600052601260045260246000fd5b500490565b600181815b8085111561375b578160001904821115613741576137416138ab565b8085161561374e57918102915b93841c9390800290613725565b509250929050565b600061307983836000826137795750600161307c565b816137865750600061307c565b816001811461379c57600281146137a6576137c2565b600191505061307c565b60ff8411156137b7576137b76138ab565b50506001821b61307c565b5060208310610133831016604e8410600b84101617156137e5575081810a61307c565b6137ef8383613720565b8060001904821115613803576138036138ab565b029392505050565b6000816000190483118215151615613825576138256138ab565b500290565b600061ffff83811690831681811015613845576138456138ab565b039392505050565b60008282101561385f5761385f6138ab565b500390565b60005b8381101561387f578181015183820152602001613867565b83811115610b885750506000910152565b60006000198214156138a4576138a46138ab565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b60ff81168114610c2d57600080fdfe7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa26469706673582212207a6690771a7821646dbb572f3b08316402cac9922dd783c54f7b555adcd31abe64736f6c634300080700337bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a", + "deployedBytecode": "0x608060405234801561001057600080fd5b506004361061030c5760003560e01c80636c7561e81161019d578063b888879e116100e9578063d38bfff4116100a2578063e6cc54321161007c578063e6cc54321461064b578063e829cc161461065f578063eb03654b14610672578063fc0cfeee1461068557600080fd5b8063d38bfff41461061c578063d58e3b3a1461062f578063e45cc9f01461064257600080fd5b8063b888879e146105cb578063b890ebf6146105de578063bc90106b146105f1578063c5f0084114610604578063c7af33521461060c578063c99191121461061457600080fd5b80638ec489a2116101565780639fa1826e116101305780639fa1826e14610573578063a403e4d51461057c578063ae69f3cb146105a5578063b2c9336d146105b857600080fd5b80638ec489a21461054557806394828ffd146105585780639c82f2a41461056057600080fd5b80636c7561e8146104e7578063773540b3146104fa5780637a2202f31461050d5780637b9a709614610516578063840c4c7a146105295780638e510b521461053c57600080fd5b80633b8ae3971161025c57806352d38e5d11610215578063597c8910116101ef578063597c8910146104a65780635d36b190146104b9578063636e6c40146104c1578063663e64ce146104d457600080fd5b806352d38e5d1461046657806353ca9f241461046f578063570d8e1d1461049357600080fd5b80633b8ae397146103ff5780633dbc911f14610412578063485cc9551461041a57806349c1d54d1461042d5780634bed3bc01461044057806350ba711c1461045357600080fd5b806318ce56bd116102c95780632b3297f9116102a35780632b3297f9146103b55780632da845a8146103c657806336b6d944146103d9578063372aa224146103ec57600080fd5b806318ce56bd146103905780631edfe3da146103a3578063207134b0146103ac57600080fd5b806309f49bf51461031157806309f6442c1461031b5780630acbda75146103375780630c340a241461034a5780631072cbea1461036a578063175188e81461037d575b600080fd5b610319610698565b005b61032460385481565b6040519081526020015b60405180910390f35b610319610345366004613537565b610711565b6103526107c3565b6040516001600160a01b03909116815260200161032e565b610319610378366004613499565b6107e0565b61031961038b3660046132fa565b61088d565b604554610352906001600160a01b031681565b61032460395481565b61032460435481565b6048546001600160a01b0316610352565b6103196103d43660046132fa565b610b8e565b6103196103e73660046132fa565b610c00565b6103196103fa3660046132fa565b610c30565b61031961040d3660046132fa565b610ca2565b610319610ddf565b610319610428366004613315565b610e55565b604254610352906001600160a01b031681565b604854600160a01b900461ffff16610324565b610324610461366004613348565b611057565b610324603b5481565b60375461048390600160a01b900460ff1681565b604051901515815260200161032e565b603f54610352906001600160a01b031681565b6103196104b43660046132fa565b611877565b610319611973565b6103196104cf366004613537565b611a19565b6103196104e2366004613537565b611a77565b6103196104f53660046134c3565b611ad0565b6103196105083660046132fa565b611d4e565b61032460475481565b61031961052436600461346f565b611dc0565b6103196105373660046133ee565b611ef6565b61032460415481565b610319610553366004613537565b611f8f565b610319612044565b61031961056e3660046132fa565b6120b4565b610324603a5481565b61035261058a3660046132fa565b6040602081905260009182529020546001600160a01b031681565b6103196105b33660046133ee565b612126565b6103196105c6366004613537565b6121b4565b603754610352906001600160a01b031681565b6103196105ec366004613537565b61220d565b6103196105ff366004613315565b612266565b6103196124a8565b61048361251e565b61031961254f565b61031961062a3660046132fa565b612619565b61031961063d3660046132fa565b6126bd565b61032460465481565b60375461048390600160a81b900460ff1681565b61031961066d36600461351c565b61272f565b610319610680366004613537565b6127ef565b6103196106933660046132fa565b6128a4565b603f546001600160a01b03163314806106b457506106b461251e565b6106d95760405162461bcd60e51b81526004016106d090613668565b60405180910390fd5b6037805460ff60a01b191690556040517fbc044409505c95b6b851433df96e1beae715c909d8e7c1d6d7ab783300d4e3b990600090a1565b61071961251e565b6107355760405162461bcd60e51b81526004016106d090613631565b6113888111156107875760405162461bcd60e51b815260206004820152601760248201527f62617369732063616e6e6f74206578636565642035302500000000000000000060448201526064016106d0565b60438190556040518181527f56287a45051933ea374811b3d5d165033047be5572cac676f7c28b8be4f746c7906020015b60405180910390a150565b60006107db6000805160206139138339815191525490565b905090565b6107e861251e565b6108045760405162461bcd60e51b81526004016106d090613631565b6001600160a01b03821660009081526033602052604090205460ff161561086d5760405162461bcd60e51b815260206004820152601760248201527f4f6e6c7920756e737570706f727465642061737365747300000000000000000060448201526064016106d0565b6108896108786107c3565b6001600160a01b0384169083612946565b5050565b61089561251e565b6108b15760405162461bcd60e51b81526004016106d090613631565b6001600160a01b03811660009081526035602052604090205460ff166109115760405162461bcd60e51b815260206004820152601560248201527414dd1c985d1959de481b9bdd08185c1c1c9bdd9959605a1b60448201526064016106d0565b60345460005b818110156109c957826001600160a01b03166040600060348481548110610940576109406138ed565b60009182526020808320909101546001600160a01b0390811684529083019390935260409091019020541614156109b95760405162461bcd60e51b815260206004820181905260248201527f53747261746567792069732064656661756c7420666f7220616e20617373657460448201526064016106d0565b6109c281613890565b9050610917565b506036548060005b82811015610a2957846001600160a01b0316603682815481106109f6576109f66138ed565b6000918252602090912001546001600160a01b03161415610a1957809150610a29565b610a2281613890565b90506109d1565b5081811015610b88576036610a3f60018461384d565b81548110610a4f57610a4f6138ed565b600091825260209091200154603680546001600160a01b039092169183908110610a7b57610a7b6138ed565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055506036805480610aba57610aba6138d7565b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b03861680835260359091526040808320805460ff19169055805163429c145b60e11b81529051879363853828b6926004808201939182900301818387803b158015610b3157600080fd5b505af1158015610b45573d6000803e3d6000fd5b50506040516001600160a01b03881681527f09a1db4b80c32706328728508c941a6b954f31eb5affd32f236c1fd405f8fea49250602001905060405180910390a1505b50505050565b610b9661251e565b610bb25760405162461bcd60e51b81526004016106d090613631565b604280546001600160a01b0319166001600160a01b0383169081179091556040519081527f1e4af5ac389e8cde1bdaa6830881b6c987c62a45cfb3b33d27d805cde3b57750906020016107b8565b610c0861251e565b610c245760405162461bcd60e51b81526004016106d090613631565b610c2d81612998565b50565b610c3861251e565b610c545760405162461bcd60e51b81526004016106d090613631565b603780546001600160a01b0319166001600160a01b0383169081179091556040519081527fb266add5f3044b17d27db796af992cecbe413921b4e8aaaee03c719e16b9806a906020016107b8565b610caa61251e565b610cc65760405162461bcd60e51b81526004016106d090613631565b6001600160a01b03811660009081526035602052604090205460ff1615610d2f5760405162461bcd60e51b815260206004820152601960248201527f537472617465677920616c726561647920617070726f7665640000000000000060448201526064016106d0565b6040805180820182526001808252600060208084018281526001600160a01b038716808452603583528684209551865460ff19169015151786559051948401949094556036805493840181559091527f4a11f94e20a93c79f6ec743a1954ec4fc2c08429ae2122118bf234b2185c81b890910180546001600160a01b0319168317905591519081527f960dd94cbb79169f09a4e445d58b895df2d9bffa5b31055d0932d801724a20d191016107b8565b603f546001600160a01b0316331480610dfb5750610dfb61251e565b610e175760405162461bcd60e51b81526004016106d090613668565b6037805460ff60a81b1916600160a81b1790556040517f71f0e5b62f846a22e0b4d159e516e62fa9c2b8eb570be15f83e67d98a2ee51e090600090a1565b610e5d61251e565b610e795760405162461bcd60e51b81526004016106d090613631565b600054610100900460ff1680610e92575060005460ff16155b610ef55760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016106d0565b600054610100900460ff16158015610f17576000805461ffff19166101011790555b6001600160a01b038316610f6d5760405162461bcd60e51b815260206004820152601d60248201527f507269636550726f76696465722061646472657373206973207a65726f00000060448201526064016106d0565b6001600160a01b038216610fbc5760405162461bcd60e51b81526020600482015260166024820152756f546f6b656e2061646472657373206973207a65726f60501b60448201526064016106d0565b603c80546001600160a01b038481166001600160a01b031990921691909117909155603780546001600160b01b03191691851691909117600160a81b17905560006038819055603981905569054b40b1f852bda00000603a55683635c9adc5dea00000603b55604080519182526020820190819052905161103f91603691613206565b508015611052576000805461ff00191690555b505050565b7f53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac4535805460009190600281141561109f5760405162461bcd60e51b81526004016106d0906136b0565b60028255603f546001600160a01b03163314806110bf57506110bf61251e565b6110db5760405162461bcd60e51b81526004016106d090613668565b6001600160a01b0389166000908152603360209081526040808320815160808101909252805460ff80821615158452929391929184019161010090910416600181111561112a5761112a6138c1565b600181111561113b5761113b6138c1565b8152905462010000810460ff908116602080850191909152630100000090920461ffff166040938401526001600160a01b038d16600090815260338352838120845160808101909552805480841615158652959650909490928401916101009091041660018111156111af576111af6138c1565b60018111156111c0576111c06138c1565b8152905462010000810460ff1660208301526301000000900461ffff1660409091015282519091506112345760405162461bcd60e51b815260206004820152601b60248201527f46726f6d206173736574206973206e6f7420737570706f72746564000000000060448201526064016106d0565b80516112825760405162461bcd60e51b815260206004820152601960248201527f546f206173736574206973206e6f7420737570706f727465640000000000000060448201526064016106d0565b6040805180820182526048546001600160a01b038082168352600160a01b90910461ffff16602083015291516370a0823160e01b81523060048201529091600091908d16906370a082319060240160206040518083038186803b1580156112e857600080fd5b505afa1580156112fc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113209190613550565b825190915061133a906001600160a01b038f16908d612946565b81600001516001600160a01b0316632506c0188e8e60018f61135c919061384d565b8e8e8e6040518763ffffffff1660e01b8152600401611380969594939291906135a2565b602060405180830381600087803b15801561139a57600080fd5b505af11580156113ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113d29190613550565b506040516370a0823160e01b815230600482015281906001600160a01b038e16906370a082319060240160206040518083038186803b15801561141457600080fd5b505afa158015611428573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061144c9190613550565b611456919061384d565b965050888610156114a95760405162461bcd60e51b815260206004820152601960248201527f5374726174656769737420736c697070616765206c696d69740000000000000060448201526064016106d0565b600082606001516127106114bd91906136d8565b6037546040516315d5220f60e31b81526001600160a01b038f8116600483015261ffff93909316929091169063aea910789060240160206040518083038186803b15801561150a57600080fd5b505afa15801561151e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115429190613550565b61154c919061380b565b603760009054906101000a90046001600160a01b03166001600160a01b031663aea910788f6040518263ffffffff1660e01b815260040161159c91906001600160a01b0391909116815260200190565b60206040518083038186803b1580156115b457600080fd5b505afa1580156115c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115ec9190613550565b60608601516115fd9061271061382a565b61160b9061ffff168e61380b565b611615919061380b565b61161f91906136fe565b905061163e6012856040015160ff1683612aae9092919063ffffffff16565b604084015161165490899060129060ff16612aae565b10156116a25760405162461bcd60e51b815260206004820152601e60248201527f4f7261636c6520736c697070616765206c696d6974206578636565646564000060448201526064016106d0565b5061271081602001516127106116b8919061382a565b61ffff16603c60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561170a57600080fd5b505afa15801561171e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117429190613550565b61174c919061380b565b61175691906136fe565b306001600160a01b031663d4c3eea06040518163ffffffff1660e01b815260040160206040518083038186803b15801561178f57600080fd5b505afa1580156117a3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117c79190613550565b101561180e5760405162461bcd60e51b8152602060048201526016602482015275416c6c6f7765642076616c7565203c20737570706c7960501b60448201526064016106d0565b8a6001600160a01b03168c6001600160a01b03167fa078c4190abe07940190effc1846be0ccf03ad6007bc9e93f9697d0b460befbb8c8960405161185c929190918252602082015260400190565b60405180910390a35050506001825550509695505050505050565b603f546001600160a01b0316331480611893575061189361251e565b6118af5760405162461bcd60e51b81526004016106d090613668565b6001600160a01b03811660009081526035602052604090205460ff166119175760405162461bcd60e51b815260206004820152601960248201527f5374726174656779206973206e6f7420737570706f727465640000000000000060448201526064016106d0565b6000819050806001600160a01b031663853828b66040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561195757600080fd5b505af115801561196b573d6000803e3d6000fd5b505050505050565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b031614611a0e5760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b60648201526084016106d0565b611a1733612b12565b565b611a2161251e565b611a3d5760405162461bcd60e51b81526004016106d090613631565b600060465560478190556040518181527fc29d6fedbc6bdf267a08166c2b976fbd72aca5d6a769528616f8b9224c8f197f906020016107b8565b611a7f61251e565b611a9b5760405162461bcd60e51b81526004016106d090613631565b60418190556040518181527f95201f9c21f26877223b1ff4073936a6484c35495649e60e55730497aeb60d93906020016107b8565b611ad861251e565b611af45760405162461bcd60e51b81526004016106d090613631565b6001600160a01b03821660009081526033602052604090205460ff1615611b5d5760405162461bcd60e51b815260206004820152601760248201527f417373657420616c726561647920737570706f7274656400000000000000000060448201526064016106d0565b60405180608001604052806001151581526020018260ff166001811115611b8657611b866138c1565b6001811115611b9757611b976138c1565b81526000602080830182905260409283018290526001600160a01b0386168252603381529190208251815490151560ff19821681178355928401519192839161ff001990911661ffff1990911617610100836001811115611bfa57611bfa6138c1565b02179055506040820151815460609093015161ffff1663010000000264ffff0000001960ff90921662010000029190911664ffffff00001990931692909217919091179055611c4882612998565b603480546001810182556000919091527f46bddb1178e94d7f2892ff5f366840eb658911794f2c3a44c450aa2c505186c10180546001600160a01b0319166001600160a01b038481169182179092556037546040516315d5220f60e31b815260048101929092529091169063aea910789060240160206040518083038186803b158015611cd457600080fd5b505afa158015611ce8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d0c9190613550565b506040516001600160a01b03831681527f4f1ac48525e50059cc1cc6e0e1940ece0dd653a4db4841538d6aef036be2fb7b906020015b60405180910390a15050565b611d5661251e565b611d725760405162461bcd60e51b81526004016106d090613631565b603f80546001600160a01b0319166001600160a01b0383169081179091556040519081527f869e0abd13cc3a975de7b93be3df1cb2255c802b1cead85963cc79d99f131bee906020016107b8565b611dc861251e565b611de45760405162461bcd60e51b81526004016106d090613631565b6001600160a01b03821660009081526033602052604090205460ff16611e425760405162461bcd60e51b8152602060048201526013602482015272105cdcd95d081b9bdd081cdd5c1c1bdc9d1959606a1b60448201526064016106d0565b6103e88161ffff1610611e8b5760405162461bcd60e51b81526020600482015260116024820152700a6d8d2e0e0c2ceca40e8dede40d0d2ced607b1b60448201526064016106d0565b6001600160a01b038216600081815260336020908152604091829020805464ffff0000001916630100000061ffff8716908102919091179091558251938452908301527f8d22e9d2cbe8bb65a3c4412bd8970743864512a1a0e004e8d00fb96277b78b949101611d42565b603f546001600160a01b0316331480611f125750611f1261251e565b611f2e5760405162461bcd60e51b81526004016106d090613668565b7f53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac453580546002811415611f725760405162461bcd60e51b81526004016106d0906136b0565b60028255611f838787878787612bd3565b50600190555050505050565b603f546001600160a01b0316331480611fab5750611fab61251e565b611fc75760405162461bcd60e51b81526004016106d090613668565b670de0b6b3a764000081111561200f5760405162461bcd60e51b815260206004820152600d60248201526c496e76616c69642076616c756560981b60448201526064016106d0565b60398190556040518181527f41ecb23a0e7865b25f38c268b7c3012220d822929e9edff07326e89d5bb822b5906020016107b8565b603f546001600160a01b0316331480612060575061206061251e565b61207c5760405162461bcd60e51b81526004016106d090613668565b6037805460ff60a81b191690556040517f891ebab18da80ebeeea06b1b1cede098329c4c008906a98370c2ac7a80b571cb90600090a1565b6120bc61251e565b6120d85760405162461bcd60e51b81526004016106d090613631565b604880546001600160a01b0319166001600160a01b0383169081179091556040519081527f7d7719313229e558c5a3893cad2eb86a86a049156d1d9ebd5c63a8eedefd1c03906020016107b8565b603f546001600160a01b0316331480612142575061214261251e565b61215e5760405162461bcd60e51b81526004016106d090613668565b7f53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac4535805460028114156121a25760405162461bcd60e51b81526004016106d0906136b0565b60028255611f83308888888888612e11565b6121bc61251e565b6121d85760405162461bcd60e51b81526004016106d090613631565b603a8190556040518181527f2ec5fb5a3d2703edc461252d92ccd2799c3c74f01d97212b20388207fa17ae45906020016107b8565b61221561251e565b6122315760405162461bcd60e51b81526004016106d090613631565b603b8190556040518181527f39367850377ac04920a9a670f2180e7a94d83b15ad302e59875ec58fd10bd37d906020016107b8565b603f546001600160a01b0316331480612282575061228261251e565b61229e5760405162461bcd60e51b81526004016106d090613668565b604080516001600160a01b038085168252831660208201527fba58ce12801c949fa65f41c46ed108671c219baf945fa48d21026cea99ff252a910160405180910390a16001600160a01b0381161561247a576001600160a01b03811660009081526035602052604090205460ff166123505760405162461bcd60e51b815260206004820152601560248201527414dd1c985d1959de481b9bdd08185c1c1c9bdd9959605a1b60448201526064016106d0565b6001600160a01b038216600090815260336020526040902054819060ff166123b35760405162461bcd60e51b8152602060048201526016602482015275105cdcd95d081a5cc81b9bdd081cdd5c1c1bdc9d195960521b60448201526064016106d0565b60405163551c457b60e11b81526001600160a01b03848116600483015282169063aa388af69060240160206040518083038186803b1580156123f457600080fd5b505afa158015612408573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061242c91906134fa565b6124785760405162461bcd60e51b815260206004820152601f60248201527f4173736574206e6f7420737570706f727465642062792053747261746567790060448201526064016106d0565b505b6001600160a01b03918216600090815260406020819052902080546001600160a01b03191691909216179055565b603f546001600160a01b03163314806124c457506124c461251e565b6124e05760405162461bcd60e51b81526004016106d090613668565b6037805460ff60a01b1916600160a01b1790556040517f8cff26a5985614b3d30629cc4ab83824bf115aec971b718d8f2f99562032e97290600090a1565b60006125366000805160206139138339815191525490565b6001600160a01b0316336001600160a01b031614905090565b603f546001600160a01b031633148061256b575061256b61251e565b6125875760405162461bcd60e51b81526004016106d090613668565b60365460005b8181101561088957603681815481106125a8576125a86138ed565b60009182526020822001546040805163429c145b60e11b815290516001600160a01b039092169263853828b69260048084019382900301818387803b1580156125f057600080fd5b505af1158015612604573d6000803e3d6000fd5b505050508061261290613890565b905061258d565b61262161251e565b61263d5760405162461bcd60e51b81526004016106d090613631565b612665817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b03166126856000805160206139138339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b6126c561251e565b6126e15760405162461bcd60e51b81526004016106d090613631565b604580546001600160a01b0319166001600160a01b0383169081179091556040519081527fa12850fb726e0b2b7b3c9a9342031e1268a8148d0eb06b4bea8613204ffcd2b8906020016107b8565b61273761251e565b6127535760405162461bcd60e51b81526004016106d090613631565b6127118161ffff161061279f5760405162461bcd60e51b8152602060048201526014602482015273496e76616c696420626173697320706f696e747360601b60448201526064016106d0565b6048805461ffff60a01b1916600160a01b61ffff8416908102919091179091556040519081527ff12c00256bee2b6facb111a88a9b1cff86e79132939b44f1353212d6f7469557906020016107b8565b6127f761251e565b6128135760405162461bcd60e51b81526004016106d090613631565b6103e881111561286f5760405162461bcd60e51b815260206004820152602160248201527f52656465656d206665652073686f756c64206e6f74206265206f7665722031306044820152602560f81b60648201526084016106d0565b60388190556040518181527fd6c7508d6658ccee36b7b7d7fd72e5cbaeefb40c64eff24e9ae7470e846304ee906020016107b8565b6128ac61251e565b6128c85760405162461bcd60e51b81526004016106d090613631565b803b6129225760405162461bcd60e51b8152602060048201526024808201527f6e657720696d706c656d656e746174696f6e206973206e6f74206120636f6e746044820152631c9858dd60e21b60648201526084016106d0565b7fa2bd3d3cf188a41358c8b401076eb59066b09dec5775650c0de4c55187d17bd955565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052611052908490612f9b565b6001600160a01b0381166000908152603360205260409020805462010000900460ff16156129c4575050565b6000826001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b1580156129ff57600080fd5b505afa158015612a13573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a379190613569565b905060068160ff1610158015612a51575060128160ff1611155b612a945760405162461bcd60e51b81526020600482015260146024820152732ab732bc3832b1ba32b210383932b1b4b9b4b7b760611b60448201526064016106d0565b815460ff909116620100000262ff00001990911617905550565b600081831115612ade57612ad7612ac5838561384d565b612ad090600a613763565b859061306d565b9350612b08565b81831015612b0857612b05612af3848461384d565b612afe90600a613763565b8590613082565b93505b50825b9392505050565b6001600160a01b038116612b685760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f72206973206164647265737328302900000000000060448201526064016106d0565b806001600160a01b0316612b886000805160206139138339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a3610c2d8160008051602061391383398151915255565b6001600160a01b03851660009081526035602052604090205460ff16612c315760405162461bcd60e51b8152602060048201526013602482015272496e76616c696420746f20537472617465677960681b60448201526064016106d0565b828114612c7c5760405162461bcd60e51b81526020600482015260196024820152780a0c2e4c2dacae8cae440d8cadccee8d040dad2e6dac2e8c6d603b1b60448201526064016106d0565b8260005b81811015612db5576000868683818110612c9c57612c9c6138ed565b9050602002016020810190612cb191906132fa565b60405163551c457b60e11b81526001600160a01b0380831660048301529192509089169063aa388af69060240160206040518083038186803b158015612cf657600080fd5b505afa158015612d0a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d2e91906134fa565b612d6e5760405162461bcd60e51b8152602060048201526011602482015270105cdcd95d081d5b9cdd5c1c1bdc9d1959607a1b60448201526064016106d0565b612da488868685818110612d8457612d846138ed565b90506020020135836001600160a01b03166129469092919063ffffffff16565b50612dae81613890565b9050612c80565b50856001600160a01b031663de5f62686040518163ffffffff1660e01b8152600401600060405180830381600087803b158015612df157600080fd5b505af1158015612e05573d6000803e3d6000fd5b50505050505050505050565b6001600160a01b03851660009081526035602052604090205460ff16612e715760405162461bcd60e51b8152602060048201526015602482015274496e76616c69642066726f6d20537472617465677960581b60448201526064016106d0565b828114612ebc5760405162461bcd60e51b81526020600482015260196024820152780a0c2e4c2dacae8cae440d8cadccee8d040dad2e6dac2e8c6d603b1b60448201526064016106d0565b8260005b81811015612f9157866001600160a01b031663d9caed1289888885818110612eea57612eea6138ed565b9050602002016020810190612eff91906132fa565b878786818110612f1157612f116138ed565b6040516001600160e01b031960e088901b1681526001600160a01b03958616600482015294909316602485015250602090910201356044820152606401600060405180830381600087803b158015612f6857600080fd5b505af1158015612f7c573d6000803e3d6000fd5b5050505080612f8a90613890565b9050612ec0565b5050505050505050565b6000612ff0826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661308e9092919063ffffffff16565b805190915015611052578080602001905181019061300e91906134fa565b6110525760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016106d0565b6000613079828461380b565b90505b92915050565b600061307982846136fe565b606061309d84846000856130a5565b949350505050565b6060824710156131065760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016106d0565b843b6131545760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016106d0565b600080866001600160a01b031685876040516131709190613586565b60006040518083038185875af1925050503d80600081146131ad576040519150601f19603f3d011682016040523d82523d6000602084013e6131b2565b606091505b50915091506131c28282866131cd565b979650505050505050565b606083156131dc575081612b0b565b8251156131ec5782518084602001fd5b8160405162461bcd60e51b81526004016106d091906135fe565b82805482825590600052602060002090810192821561325b579160200282015b8281111561325b57825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190613226565b5061326792915061326b565b5090565b5b80821115613267576000815560010161326c565b80356001600160a01b038116811461329757600080fd5b919050565b60008083601f8401126132ae57600080fd5b50813567ffffffffffffffff8111156132c657600080fd5b6020830191508360208260051b85010111156132e157600080fd5b9250929050565b803561ffff8116811461329757600080fd5b60006020828403121561330c57600080fd5b61307982613280565b6000806040838503121561332857600080fd5b61333183613280565b915061333f60208401613280565b90509250929050565b60008060008060008060a0878903121561336157600080fd5b61336a87613280565b955061337860208801613280565b94506040870135935060608701359250608087013567ffffffffffffffff808211156133a357600080fd5b818901915089601f8301126133b757600080fd5b8135818111156133c657600080fd5b8a60208285010111156133d857600080fd5b6020830194508093505050509295509295509295565b60008060008060006060868803121561340657600080fd5b61340f86613280565b9450602086013567ffffffffffffffff8082111561342c57600080fd5b61343889838a0161329c565b9096509450604088013591508082111561345157600080fd5b5061345e8882890161329c565b969995985093965092949392505050565b6000806040838503121561348257600080fd5b61348b83613280565b915061333f602084016132e8565b600080604083850312156134ac57600080fd5b6134b583613280565b946020939093013593505050565b600080604083850312156134d657600080fd5b6134df83613280565b915060208301356134ef81613903565b809150509250929050565b60006020828403121561350c57600080fd5b81518015158114612b0b57600080fd5b60006020828403121561352e57600080fd5b613079826132e8565b60006020828403121561354957600080fd5b5035919050565b60006020828403121561356257600080fd5b5051919050565b60006020828403121561357b57600080fd5b8151612b0b81613903565b60008251613598818460208701613864565b9190910192915050565b6001600160a01b03878116825286166020820152604081018590526060810184905260a06080820181905281018290526000828460c0840137600060c0848401015260c0601f19601f8501168301019050979650505050505050565b602081526000825180602084015261361d816040850160208701613864565b601f01601f19169190910160400192915050565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b60208082526028908201527f43616c6c6572206973206e6f74207468652053747261746567697374206f722060408201526723b7bb32b93737b960c11b606082015260800190565b6020808252600e908201526d1499595b9d1c985b9d0818d85b1b60921b604082015260600190565b600061ffff8083168185168083038211156136f5576136f56138ab565b01949350505050565b60008261371b57634e487b7160e01b600052601260045260246000fd5b500490565b600181815b8085111561375b578160001904821115613741576137416138ab565b8085161561374e57918102915b93841c9390800290613725565b509250929050565b600061307983836000826137795750600161307c565b816137865750600061307c565b816001811461379c57600281146137a6576137c2565b600191505061307c565b60ff8411156137b7576137b76138ab565b50506001821b61307c565b5060208310610133831016604e8410600b84101617156137e5575081810a61307c565b6137ef8383613720565b8060001904821115613803576138036138ab565b029392505050565b6000816000190483118215151615613825576138256138ab565b500290565b600061ffff83811690831681811015613845576138456138ab565b039392505050565b60008282101561385f5761385f6138ab565b500390565b60005b8381101561387f578181015183820152602001613867565b83811115610b885750506000910152565b60006000198214156138a4576138a46138ab565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b60ff81168114610c2d57600080fdfe7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa26469706673582212207a6690771a7821646dbb572f3b08316402cac9922dd783c54f7b555adcd31abe64736f6c63430008070033", + "libraries": {}, + "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 Vault 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 + }, + "storageLayout": { + "storage": [ + { + "astId": 41419, + "contract": "contracts/vault/OETHVault.sol:OETHVault", + "label": "initialized", + "offset": 0, + "slot": "0", + "type": "t_bool" + }, + { + "astId": 41422, + "contract": "contracts/vault/OETHVault.sol:OETHVault", + "label": "initializing", + "offset": 1, + "slot": "0", + "type": "t_bool" + }, + { + "astId": 41462, + "contract": "contracts/vault/OETHVault.sol:OETHVault", + "label": "______gap", + "offset": 0, + "slot": "1", + "type": "t_array(t_uint256)50_storage" + }, + { + "astId": 46069, + "contract": "contracts/vault/OETHVault.sol:OETHVault", + "label": "assets", + "offset": 0, + "slot": "51", + "type": "t_mapping(t_address,t_struct(Asset)46063_storage)" + }, + { + "astId": 46073, + "contract": "contracts/vault/OETHVault.sol:OETHVault", + "label": "allAssets", + "offset": 0, + "slot": "52", + "type": "t_array(t_address)dyn_storage" + }, + { + "astId": 46084, + "contract": "contracts/vault/OETHVault.sol:OETHVault", + "label": "strategies", + "offset": 0, + "slot": "53", + "type": "t_mapping(t_address,t_struct(Strategy)46078_storage)" + }, + { + "astId": 46088, + "contract": "contracts/vault/OETHVault.sol:OETHVault", + "label": "allStrategies", + "offset": 0, + "slot": "54", + "type": "t_array(t_address)dyn_storage" + }, + { + "astId": 46091, + "contract": "contracts/vault/OETHVault.sol:OETHVault", + "label": "priceProvider", + "offset": 0, + "slot": "55", + "type": "t_address" + }, + { + "astId": 46095, + "contract": "contracts/vault/OETHVault.sol:OETHVault", + "label": "rebasePaused", + "offset": 20, + "slot": "55", + "type": "t_bool" + }, + { + "astId": 46099, + "contract": "contracts/vault/OETHVault.sol:OETHVault", + "label": "capitalPaused", + "offset": 21, + "slot": "55", + "type": "t_bool" + }, + { + "astId": 46102, + "contract": "contracts/vault/OETHVault.sol:OETHVault", + "label": "redeemFeeBps", + "offset": 0, + "slot": "56", + "type": "t_uint256" + }, + { + "astId": 46105, + "contract": "contracts/vault/OETHVault.sol:OETHVault", + "label": "vaultBuffer", + "offset": 0, + "slot": "57", + "type": "t_uint256" + }, + { + "astId": 46108, + "contract": "contracts/vault/OETHVault.sol:OETHVault", + "label": "autoAllocateThreshold", + "offset": 0, + "slot": "58", + "type": "t_uint256" + }, + { + "astId": 46111, + "contract": "contracts/vault/OETHVault.sol:OETHVault", + "label": "rebaseThreshold", + "offset": 0, + "slot": "59", + "type": "t_uint256" + }, + { + "astId": 46115, + "contract": "contracts/vault/OETHVault.sol:OETHVault", + "label": "oUSD", + "offset": 0, + "slot": "60", + "type": "t_contract(OUSD)40245" + }, + { + "astId": 46124, + "contract": "contracts/vault/OETHVault.sol:OETHVault", + "label": "_deprecated_rebaseHooksAddr", + "offset": 0, + "slot": "61", + "type": "t_address" + }, + { + "astId": 46130, + "contract": "contracts/vault/OETHVault.sol:OETHVault", + "label": "_deprecated_uniswapAddr", + "offset": 0, + "slot": "62", + "type": "t_address" + }, + { + "astId": 46137, + "contract": "contracts/vault/OETHVault.sol:OETHVault", + "label": "strategistAddr", + "offset": 0, + "slot": "63", + "type": "t_address" + }, + { + "astId": 46142, + "contract": "contracts/vault/OETHVault.sol:OETHVault", + "label": "assetDefaultStrategies", + "offset": 0, + "slot": "64", + "type": "t_mapping(t_address,t_address)" + }, + { + "astId": 46145, + "contract": "contracts/vault/OETHVault.sol:OETHVault", + "label": "maxSupplyDiff", + "offset": 0, + "slot": "65", + "type": "t_uint256" + }, + { + "astId": 46148, + "contract": "contracts/vault/OETHVault.sol:OETHVault", + "label": "trusteeAddress", + "offset": 0, + "slot": "66", + "type": "t_address" + }, + { + "astId": 46151, + "contract": "contracts/vault/OETHVault.sol:OETHVault", + "label": "trusteeFeeBps", + "offset": 0, + "slot": "67", + "type": "t_uint256" + }, + { + "astId": 46155, + "contract": "contracts/vault/OETHVault.sol:OETHVault", + "label": "_deprecated_swapTokens", + "offset": 0, + "slot": "68", + "type": "t_array(t_address)dyn_storage" + }, + { + "astId": 46165, + "contract": "contracts/vault/OETHVault.sol:OETHVault", + "label": "ousdMetaStrategy", + "offset": 0, + "slot": "69", + "type": "t_address" + }, + { + "astId": 46169, + "contract": "contracts/vault/OETHVault.sol:OETHVault", + "label": "netOusdMintedForStrategy", + "offset": 0, + "slot": "70", + "type": "t_int256" + }, + { + "astId": 46173, + "contract": "contracts/vault/OETHVault.sol:OETHVault", + "label": "netOusdMintForStrategyThreshold", + "offset": 0, + "slot": "71", + "type": "t_uint256" + }, + { + "astId": 46194, + "contract": "contracts/vault/OETHVault.sol:OETHVault", + "label": "swapConfig", + "offset": 0, + "slot": "72", + "type": "t_struct(SwapConfig)46184_storage" + }, + { + "astId": 46198, + "contract": "contracts/vault/OETHVault.sol:OETHVault", + "label": "__gap", + "offset": 0, + "slot": "73", + "type": "t_array(t_uint256)50_storage" + } + ], + "types": { + "t_address": { + "encoding": "inplace", + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_address)dyn_storage": { + "base": "t_address", + "encoding": "dynamic_array", + "label": "address[]", + "numberOfBytes": "32" + }, + "t_array(t_uint256)50_storage": { + "base": "t_uint256", + "encoding": "inplace", + "label": "uint256[50]", + "numberOfBytes": "1600" + }, + "t_bool": { + "encoding": "inplace", + "label": "bool", + "numberOfBytes": "1" + }, + "t_contract(OUSD)40245": { + "encoding": "inplace", + "label": "contract OUSD", + "numberOfBytes": "20" + }, + "t_enum(UnitConversion)46053": { + "encoding": "inplace", + "label": "enum VaultStorage.UnitConversion", + "numberOfBytes": "1" + }, + "t_int256": { + "encoding": "inplace", + "label": "int256", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_address)": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => address)", + "numberOfBytes": "32", + "value": "t_address" + }, + "t_mapping(t_address,t_struct(Asset)46063_storage)": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => struct VaultStorage.Asset)", + "numberOfBytes": "32", + "value": "t_struct(Asset)46063_storage" + }, + "t_mapping(t_address,t_struct(Strategy)46078_storage)": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => struct VaultStorage.Strategy)", + "numberOfBytes": "32", + "value": "t_struct(Strategy)46078_storage" + }, + "t_struct(Asset)46063_storage": { + "encoding": "inplace", + "label": "struct VaultStorage.Asset", + "members": [ + { + "astId": 46055, + "contract": "contracts/vault/OETHVault.sol:OETHVault", + "label": "isSupported", + "offset": 0, + "slot": "0", + "type": "t_bool" + }, + { + "astId": 46058, + "contract": "contracts/vault/OETHVault.sol:OETHVault", + "label": "unitConversion", + "offset": 1, + "slot": "0", + "type": "t_enum(UnitConversion)46053" + }, + { + "astId": 46060, + "contract": "contracts/vault/OETHVault.sol:OETHVault", + "label": "decimals", + "offset": 2, + "slot": "0", + "type": "t_uint8" + }, + { + "astId": 46062, + "contract": "contracts/vault/OETHVault.sol:OETHVault", + "label": "allowedOracleSlippageBps", + "offset": 3, + "slot": "0", + "type": "t_uint16" + } + ], + "numberOfBytes": "32" + }, + "t_struct(Strategy)46078_storage": { + "encoding": "inplace", + "label": "struct VaultStorage.Strategy", + "members": [ + { + "astId": 46075, + "contract": "contracts/vault/OETHVault.sol:OETHVault", + "label": "isSupported", + "offset": 0, + "slot": "0", + "type": "t_bool" + }, + { + "astId": 46077, + "contract": "contracts/vault/OETHVault.sol:OETHVault", + "label": "_deprecated", + "offset": 0, + "slot": "1", + "type": "t_uint256" + } + ], + "numberOfBytes": "64" + }, + "t_struct(SwapConfig)46184_storage": { + "encoding": "inplace", + "label": "struct VaultStorage.SwapConfig", + "members": [ + { + "astId": 46181, + "contract": "contracts/vault/OETHVault.sol:OETHVault", + "label": "swapper", + "offset": 0, + "slot": "0", + "type": "t_address" + }, + { + "astId": 46183, + "contract": "contracts/vault/OETHVault.sol:OETHVault", + "label": "allowedUndervalueBps", + "offset": 20, + "slot": "0", + "type": "t_uint16" + } + ], + "numberOfBytes": "32" + }, + "t_uint16": { + "encoding": "inplace", + "label": "uint16", + "numberOfBytes": "2" + }, + "t_uint256": { + "encoding": "inplace", + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint8": { + "encoding": "inplace", + "label": "uint8", + "numberOfBytes": "1" + } + } + } +} \ No newline at end of file diff --git a/contracts/deployments/holesky/OETHVaultAdmin.json b/contracts/deployments/holesky/OETHVaultAdmin.json new file mode 100644 index 0000000000..c58d7d080f --- /dev/null +++ b/contracts/deployments/holesky/OETHVaultAdmin.json @@ -0,0 +1,1858 @@ +{ + "address": "0xa94c4aab0Cf9f6E79bB064DB145fBe2506b9Fa75", + "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" + } + ], + "transactionHash": "0xe29b0302a257a781d787f590e9502246b3ac3fe2f2d3c39d37d3ac9e856057eb", + "receipt": { + "to": null, + "from": "0x1b94CA50D3Ad9f8368851F8526132272d1a5028C", + "contractAddress": "0xa94c4aab0Cf9f6E79bB064DB145fBe2506b9Fa75", + "transactionIndex": 39, + "gasUsed": "3146556", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000040000010000000000000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000000004000000000000002000000000000000000040000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000010000000000010000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x50619ec9fad9061d57a94456471009c7fa5c0cf4d68201956bf36a07a219f708", + "transactionHash": "0xe29b0302a257a781d787f590e9502246b3ac3fe2f2d3c39d37d3ac9e856057eb", + "logs": [ + { + "transactionIndex": 39, + "blockNumber": 1405067, + "transactionHash": "0xe29b0302a257a781d787f590e9502246b3ac3fe2f2d3c39d37d3ac9e856057eb", + "address": "0xa94c4aab0Cf9f6E79bB064DB145fBe2506b9Fa75", + "topics": [ + "0xc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000001b94ca50d3ad9f8368851f8526132272d1a5028c" + ], + "data": "0x", + "logIndex": 121, + "blockHash": "0x50619ec9fad9061d57a94456471009c7fa5c0cf4d68201956bf36a07a219f708" + } + ], + "blockNumber": 1405067, + "cumulativeGasUsed": "6442389", + "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", + "libraries": {}, + "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 + }, + "storageLayout": { + "storage": [ + { + "astId": 41419, + "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", + "label": "initialized", + "offset": 0, + "slot": "0", + "type": "t_bool" + }, + { + "astId": 41422, + "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", + "label": "initializing", + "offset": 1, + "slot": "0", + "type": "t_bool" + }, + { + "astId": 41462, + "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", + "label": "______gap", + "offset": 0, + "slot": "1", + "type": "t_array(t_uint256)50_storage" + }, + { + "astId": 46069, + "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", + "label": "assets", + "offset": 0, + "slot": "51", + "type": "t_mapping(t_address,t_struct(Asset)46063_storage)" + }, + { + "astId": 46073, + "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", + "label": "allAssets", + "offset": 0, + "slot": "52", + "type": "t_array(t_address)dyn_storage" + }, + { + "astId": 46084, + "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", + "label": "strategies", + "offset": 0, + "slot": "53", + "type": "t_mapping(t_address,t_struct(Strategy)46078_storage)" + }, + { + "astId": 46088, + "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", + "label": "allStrategies", + "offset": 0, + "slot": "54", + "type": "t_array(t_address)dyn_storage" + }, + { + "astId": 46091, + "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", + "label": "priceProvider", + "offset": 0, + "slot": "55", + "type": "t_address" + }, + { + "astId": 46095, + "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", + "label": "rebasePaused", + "offset": 20, + "slot": "55", + "type": "t_bool" + }, + { + "astId": 46099, + "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", + "label": "capitalPaused", + "offset": 21, + "slot": "55", + "type": "t_bool" + }, + { + "astId": 46102, + "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", + "label": "redeemFeeBps", + "offset": 0, + "slot": "56", + "type": "t_uint256" + }, + { + "astId": 46105, + "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", + "label": "vaultBuffer", + "offset": 0, + "slot": "57", + "type": "t_uint256" + }, + { + "astId": 46108, + "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", + "label": "autoAllocateThreshold", + "offset": 0, + "slot": "58", + "type": "t_uint256" + }, + { + "astId": 46111, + "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", + "label": "rebaseThreshold", + "offset": 0, + "slot": "59", + "type": "t_uint256" + }, + { + "astId": 46115, + "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", + "label": "oUSD", + "offset": 0, + "slot": "60", + "type": "t_contract(OUSD)40245" + }, + { + "astId": 46124, + "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", + "label": "_deprecated_rebaseHooksAddr", + "offset": 0, + "slot": "61", + "type": "t_address" + }, + { + "astId": 46130, + "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", + "label": "_deprecated_uniswapAddr", + "offset": 0, + "slot": "62", + "type": "t_address" + }, + { + "astId": 46137, + "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", + "label": "strategistAddr", + "offset": 0, + "slot": "63", + "type": "t_address" + }, + { + "astId": 46142, + "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", + "label": "assetDefaultStrategies", + "offset": 0, + "slot": "64", + "type": "t_mapping(t_address,t_address)" + }, + { + "astId": 46145, + "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", + "label": "maxSupplyDiff", + "offset": 0, + "slot": "65", + "type": "t_uint256" + }, + { + "astId": 46148, + "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", + "label": "trusteeAddress", + "offset": 0, + "slot": "66", + "type": "t_address" + }, + { + "astId": 46151, + "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", + "label": "trusteeFeeBps", + "offset": 0, + "slot": "67", + "type": "t_uint256" + }, + { + "astId": 46155, + "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", + "label": "_deprecated_swapTokens", + "offset": 0, + "slot": "68", + "type": "t_array(t_address)dyn_storage" + }, + { + "astId": 46165, + "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", + "label": "ousdMetaStrategy", + "offset": 0, + "slot": "69", + "type": "t_address" + }, + { + "astId": 46169, + "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", + "label": "netOusdMintedForStrategy", + "offset": 0, + "slot": "70", + "type": "t_int256" + }, + { + "astId": 46173, + "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", + "label": "netOusdMintForStrategyThreshold", + "offset": 0, + "slot": "71", + "type": "t_uint256" + }, + { + "astId": 46194, + "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", + "label": "swapConfig", + "offset": 0, + "slot": "72", + "type": "t_struct(SwapConfig)46184_storage" + }, + { + "astId": 46198, + "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", + "label": "__gap", + "offset": 0, + "slot": "73", + "type": "t_array(t_uint256)50_storage" + } + ], + "types": { + "t_address": { + "encoding": "inplace", + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_address)dyn_storage": { + "base": "t_address", + "encoding": "dynamic_array", + "label": "address[]", + "numberOfBytes": "32" + }, + "t_array(t_uint256)50_storage": { + "base": "t_uint256", + "encoding": "inplace", + "label": "uint256[50]", + "numberOfBytes": "1600" + }, + "t_bool": { + "encoding": "inplace", + "label": "bool", + "numberOfBytes": "1" + }, + "t_contract(OUSD)40245": { + "encoding": "inplace", + "label": "contract OUSD", + "numberOfBytes": "20" + }, + "t_enum(UnitConversion)46053": { + "encoding": "inplace", + "label": "enum VaultStorage.UnitConversion", + "numberOfBytes": "1" + }, + "t_int256": { + "encoding": "inplace", + "label": "int256", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_address)": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => address)", + "numberOfBytes": "32", + "value": "t_address" + }, + "t_mapping(t_address,t_struct(Asset)46063_storage)": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => struct VaultStorage.Asset)", + "numberOfBytes": "32", + "value": "t_struct(Asset)46063_storage" + }, + "t_mapping(t_address,t_struct(Strategy)46078_storage)": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => struct VaultStorage.Strategy)", + "numberOfBytes": "32", + "value": "t_struct(Strategy)46078_storage" + }, + "t_struct(Asset)46063_storage": { + "encoding": "inplace", + "label": "struct VaultStorage.Asset", + "members": [ + { + "astId": 46055, + "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", + "label": "isSupported", + "offset": 0, + "slot": "0", + "type": "t_bool" + }, + { + "astId": 46058, + "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", + "label": "unitConversion", + "offset": 1, + "slot": "0", + "type": "t_enum(UnitConversion)46053" + }, + { + "astId": 46060, + "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", + "label": "decimals", + "offset": 2, + "slot": "0", + "type": "t_uint8" + }, + { + "astId": 46062, + "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", + "label": "allowedOracleSlippageBps", + "offset": 3, + "slot": "0", + "type": "t_uint16" + } + ], + "numberOfBytes": "32" + }, + "t_struct(Strategy)46078_storage": { + "encoding": "inplace", + "label": "struct VaultStorage.Strategy", + "members": [ + { + "astId": 46075, + "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", + "label": "isSupported", + "offset": 0, + "slot": "0", + "type": "t_bool" + }, + { + "astId": 46077, + "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", + "label": "_deprecated", + "offset": 0, + "slot": "1", + "type": "t_uint256" + } + ], + "numberOfBytes": "64" + }, + "t_struct(SwapConfig)46184_storage": { + "encoding": "inplace", + "label": "struct VaultStorage.SwapConfig", + "members": [ + { + "astId": 46181, + "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", + "label": "swapper", + "offset": 0, + "slot": "0", + "type": "t_address" + }, + { + "astId": 46183, + "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", + "label": "allowedUndervalueBps", + "offset": 20, + "slot": "0", + "type": "t_uint16" + } + ], + "numberOfBytes": "32" + }, + "t_uint16": { + "encoding": "inplace", + "label": "uint16", + "numberOfBytes": "2" + }, + "t_uint256": { + "encoding": "inplace", + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint8": { + "encoding": "inplace", + "label": "uint8", + "numberOfBytes": "1" + } + } + } +} \ No newline at end of file diff --git a/contracts/deployments/holesky/OETHVaultCore.json b/contracts/deployments/holesky/OETHVaultCore.json new file mode 100644 index 0000000000..d3580e13ac --- /dev/null +++ b/contracts/deployments/holesky/OETHVaultCore.json @@ -0,0 +1,1696 @@ +{ + "address": "0xE92e25B81E44B8377Df1362f8fFBc426A00d6ef4", + "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" + } + ], + "transactionHash": "0x9f75d36ce4de616c56e32c5f1e66ea8b705994a63d163d096f71d3e5c1eecdc1", + "receipt": { + "to": null, + "from": "0x1b94CA50D3Ad9f8368851F8526132272d1a5028C", + "contractAddress": "0xE92e25B81E44B8377Df1362f8fFBc426A00d6ef4", + "transactionIndex": 68, + "gasUsed": "3024025", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000020000000000000000000800000000000000000000000000000000000004000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000010000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000080000000000000", + "blockHash": "0xf2aa29665c1af068ced76d7b539f3bcc67a7d534c1019c51316beecb731cbc01", + "transactionHash": "0x9f75d36ce4de616c56e32c5f1e66ea8b705994a63d163d096f71d3e5c1eecdc1", + "logs": [ + { + "transactionIndex": 68, + "blockNumber": 1405063, + "transactionHash": "0x9f75d36ce4de616c56e32c5f1e66ea8b705994a63d163d096f71d3e5c1eecdc1", + "address": "0xE92e25B81E44B8377Df1362f8fFBc426A00d6ef4", + "topics": [ + "0xc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000001b94ca50d3ad9f8368851f8526132272d1a5028c" + ], + "data": "0x", + "logIndex": 80, + "blockHash": "0xf2aa29665c1af068ced76d7b539f3bcc67a7d534c1019c51316beecb731cbc01" + } + ], + "blockNumber": 1405063, + "cumulativeGasUsed": "14256235", + "status": 1, + "byzantium": true + }, + "args": [ + "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", + "libraries": {}, + "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 + }, + "storageLayout": { + "storage": [ + { + "astId": 41419, + "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", + "label": "initialized", + "offset": 0, + "slot": "0", + "type": "t_bool" + }, + { + "astId": 41422, + "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", + "label": "initializing", + "offset": 1, + "slot": "0", + "type": "t_bool" + }, + { + "astId": 41462, + "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", + "label": "______gap", + "offset": 0, + "slot": "1", + "type": "t_array(t_uint256)50_storage" + }, + { + "astId": 46069, + "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", + "label": "assets", + "offset": 0, + "slot": "51", + "type": "t_mapping(t_address,t_struct(Asset)46063_storage)" + }, + { + "astId": 46073, + "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", + "label": "allAssets", + "offset": 0, + "slot": "52", + "type": "t_array(t_address)dyn_storage" + }, + { + "astId": 46084, + "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", + "label": "strategies", + "offset": 0, + "slot": "53", + "type": "t_mapping(t_address,t_struct(Strategy)46078_storage)" + }, + { + "astId": 46088, + "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", + "label": "allStrategies", + "offset": 0, + "slot": "54", + "type": "t_array(t_address)dyn_storage" + }, + { + "astId": 46091, + "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", + "label": "priceProvider", + "offset": 0, + "slot": "55", + "type": "t_address" + }, + { + "astId": 46095, + "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", + "label": "rebasePaused", + "offset": 20, + "slot": "55", + "type": "t_bool" + }, + { + "astId": 46099, + "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", + "label": "capitalPaused", + "offset": 21, + "slot": "55", + "type": "t_bool" + }, + { + "astId": 46102, + "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", + "label": "redeemFeeBps", + "offset": 0, + "slot": "56", + "type": "t_uint256" + }, + { + "astId": 46105, + "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", + "label": "vaultBuffer", + "offset": 0, + "slot": "57", + "type": "t_uint256" + }, + { + "astId": 46108, + "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", + "label": "autoAllocateThreshold", + "offset": 0, + "slot": "58", + "type": "t_uint256" + }, + { + "astId": 46111, + "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", + "label": "rebaseThreshold", + "offset": 0, + "slot": "59", + "type": "t_uint256" + }, + { + "astId": 46115, + "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", + "label": "oUSD", + "offset": 0, + "slot": "60", + "type": "t_contract(OUSD)40245" + }, + { + "astId": 46124, + "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", + "label": "_deprecated_rebaseHooksAddr", + "offset": 0, + "slot": "61", + "type": "t_address" + }, + { + "astId": 46130, + "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", + "label": "_deprecated_uniswapAddr", + "offset": 0, + "slot": "62", + "type": "t_address" + }, + { + "astId": 46137, + "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", + "label": "strategistAddr", + "offset": 0, + "slot": "63", + "type": "t_address" + }, + { + "astId": 46142, + "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", + "label": "assetDefaultStrategies", + "offset": 0, + "slot": "64", + "type": "t_mapping(t_address,t_address)" + }, + { + "astId": 46145, + "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", + "label": "maxSupplyDiff", + "offset": 0, + "slot": "65", + "type": "t_uint256" + }, + { + "astId": 46148, + "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", + "label": "trusteeAddress", + "offset": 0, + "slot": "66", + "type": "t_address" + }, + { + "astId": 46151, + "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", + "label": "trusteeFeeBps", + "offset": 0, + "slot": "67", + "type": "t_uint256" + }, + { + "astId": 46155, + "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", + "label": "_deprecated_swapTokens", + "offset": 0, + "slot": "68", + "type": "t_array(t_address)dyn_storage" + }, + { + "astId": 46165, + "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", + "label": "ousdMetaStrategy", + "offset": 0, + "slot": "69", + "type": "t_address" + }, + { + "astId": 46169, + "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", + "label": "netOusdMintedForStrategy", + "offset": 0, + "slot": "70", + "type": "t_int256" + }, + { + "astId": 46173, + "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", + "label": "netOusdMintForStrategyThreshold", + "offset": 0, + "slot": "71", + "type": "t_uint256" + }, + { + "astId": 46194, + "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", + "label": "swapConfig", + "offset": 0, + "slot": "72", + "type": "t_struct(SwapConfig)46184_storage" + }, + { + "astId": 46198, + "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", + "label": "__gap", + "offset": 0, + "slot": "73", + "type": "t_array(t_uint256)50_storage" + }, + { + "astId": 42360, + "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", + "label": "wethAssetIndex", + "offset": 0, + "slot": "123", + "type": "t_uint256" + } + ], + "types": { + "t_address": { + "encoding": "inplace", + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_address)dyn_storage": { + "base": "t_address", + "encoding": "dynamic_array", + "label": "address[]", + "numberOfBytes": "32" + }, + "t_array(t_uint256)50_storage": { + "base": "t_uint256", + "encoding": "inplace", + "label": "uint256[50]", + "numberOfBytes": "1600" + }, + "t_bool": { + "encoding": "inplace", + "label": "bool", + "numberOfBytes": "1" + }, + "t_contract(OUSD)40245": { + "encoding": "inplace", + "label": "contract OUSD", + "numberOfBytes": "20" + }, + "t_enum(UnitConversion)46053": { + "encoding": "inplace", + "label": "enum VaultStorage.UnitConversion", + "numberOfBytes": "1" + }, + "t_int256": { + "encoding": "inplace", + "label": "int256", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_address)": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => address)", + "numberOfBytes": "32", + "value": "t_address" + }, + "t_mapping(t_address,t_struct(Asset)46063_storage)": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => struct VaultStorage.Asset)", + "numberOfBytes": "32", + "value": "t_struct(Asset)46063_storage" + }, + "t_mapping(t_address,t_struct(Strategy)46078_storage)": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => struct VaultStorage.Strategy)", + "numberOfBytes": "32", + "value": "t_struct(Strategy)46078_storage" + }, + "t_struct(Asset)46063_storage": { + "encoding": "inplace", + "label": "struct VaultStorage.Asset", + "members": [ + { + "astId": 46055, + "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", + "label": "isSupported", + "offset": 0, + "slot": "0", + "type": "t_bool" + }, + { + "astId": 46058, + "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", + "label": "unitConversion", + "offset": 1, + "slot": "0", + "type": "t_enum(UnitConversion)46053" + }, + { + "astId": 46060, + "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", + "label": "decimals", + "offset": 2, + "slot": "0", + "type": "t_uint8" + }, + { + "astId": 46062, + "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", + "label": "allowedOracleSlippageBps", + "offset": 3, + "slot": "0", + "type": "t_uint16" + } + ], + "numberOfBytes": "32" + }, + "t_struct(Strategy)46078_storage": { + "encoding": "inplace", + "label": "struct VaultStorage.Strategy", + "members": [ + { + "astId": 46075, + "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", + "label": "isSupported", + "offset": 0, + "slot": "0", + "type": "t_bool" + }, + { + "astId": 46077, + "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", + "label": "_deprecated", + "offset": 0, + "slot": "1", + "type": "t_uint256" + } + ], + "numberOfBytes": "64" + }, + "t_struct(SwapConfig)46184_storage": { + "encoding": "inplace", + "label": "struct VaultStorage.SwapConfig", + "members": [ + { + "astId": 46181, + "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", + "label": "swapper", + "offset": 0, + "slot": "0", + "type": "t_address" + }, + { + "astId": 46183, + "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", + "label": "allowedUndervalueBps", + "offset": 20, + "slot": "0", + "type": "t_uint16" + } + ], + "numberOfBytes": "32" + }, + "t_uint16": { + "encoding": "inplace", + "label": "uint16", + "numberOfBytes": "2" + }, + "t_uint256": { + "encoding": "inplace", + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint8": { + "encoding": "inplace", + "label": "uint8", + "numberOfBytes": "1" + } + } + } +} \ No newline at end of file diff --git a/contracts/deployments/holesky/OETHVaultProxy.json b/contracts/deployments/holesky/OETHVaultProxy.json new file mode 100644 index 0000000000..056f2eb68f --- /dev/null +++ b/contracts/deployments/holesky/OETHVaultProxy.json @@ -0,0 +1,289 @@ +{ + "address": "0x19d2bAaBA949eFfa163bFB9efB53ed8701aA5dD9", + "abi": [ + { + "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": true, + "internalType": "address", + "name": "previousGovernor", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newGovernor", + "type": "address" + } + ], + "name": "PendingGovernorshipTransfer", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "implementation", + "type": "address" + } + ], + "name": "Upgraded", + "type": "event" + }, + { + "stateMutability": "payable", + "type": "fallback" + }, + { + "inputs": [], + "name": "admin", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "claimGovernance", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "governor", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "implementation", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_logic", + "type": "address" + }, + { + "internalType": "address", + "name": "_initGovernor", + "type": "address" + }, + { + "internalType": "bytes", + "name": "_data", + "type": "bytes" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [], + "name": "isGovernor", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_newGovernor", + "type": "address" + } + ], + "name": "transferGovernance", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newImplementation", + "type": "address" + } + ], + "name": "upgradeTo", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newImplementation", + "type": "address" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "upgradeToAndCall", + "outputs": [], + "stateMutability": "payable", + "type": "function" + } + ], + "transactionHash": "0x30d68961caf058163678c331718227669ac559e79bc8acbff4a5c14c9bdebc6e", + "receipt": { + "to": null, + "from": "0x1b94CA50D3Ad9f8368851F8526132272d1a5028C", + "contractAddress": "0x19d2bAaBA949eFfa163bFB9efB53ed8701aA5dD9", + "transactionIndex": 44, + "gasUsed": "580428", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000000004000000000000002000000000000000000040000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000010000000000010010800000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0xc1b0a50df110f026ea932b45dea094477c722b29db3ef3234225e8d9e07067db", + "transactionHash": "0x30d68961caf058163678c331718227669ac559e79bc8acbff4a5c14c9bdebc6e", + "logs": [ + { + "transactionIndex": 44, + "blockNumber": 1405049, + "transactionHash": "0x30d68961caf058163678c331718227669ac559e79bc8acbff4a5c14c9bdebc6e", + "address": "0x19d2bAaBA949eFfa163bFB9efB53ed8701aA5dD9", + "topics": [ + "0xc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000001b94ca50d3ad9f8368851f8526132272d1a5028c" + ], + "data": "0x", + "logIndex": 65, + "blockHash": "0xc1b0a50df110f026ea932b45dea094477c722b29db3ef3234225e8d9e07067db" + } + ], + "blockNumber": 1405049, + "cumulativeGasUsed": "5786646", + "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\":true,\"internalType\":\"address\",\"name\":\"previousGovernor\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newGovernor\",\"type\":\"address\"}],\"name\":\"GovernorshipTransferred\",\"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\":true,\"internalType\":\"address\",\"name\":\"implementation\",\"type\":\"address\"}],\"name\":\"Upgraded\",\"type\":\"event\"},{\"stateMutability\":\"payable\",\"type\":\"fallback\"},{\"inputs\":[],\"name\":\"admin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"claimGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"governor\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"implementation\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_logic\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_initGovernor\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isGovernor\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_newGovernor\",\"type\":\"address\"}],\"name\":\"transferGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newImplementation\",\"type\":\"address\"}],\"name\":\"upgradeTo\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newImplementation\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"upgradeToAndCall\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"admin()\":{\"returns\":{\"_0\":\"The address of the proxy admin/it's also the governor.\"}},\"implementation()\":{\"returns\":{\"_0\":\"The address of the implementation.\"}},\"initialize(address,address,bytes)\":{\"details\":\"Contract initializer with Governor enforcement\",\"params\":{\"_data\":\"Data to send as msg.data to the implementation to initialize the proxied contract. It should include the signature and the parameters of the function to be called, as described in https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding. This parameter is optional, if no data is given the initialization call to proxied contract will be skipped.\",\"_initGovernor\":\"Address of the initial Governor.\",\"_logic\":\"Address of the initial implementation.\"}},\"transferGovernance(address)\":{\"params\":{\"_newGovernor\":\"Address of the new Governor\"}},\"upgradeTo(address)\":{\"details\":\"Upgrade the backing implementation of the proxy. Only the admin can call this function.\",\"params\":{\"newImplementation\":\"Address of the new implementation.\"}},\"upgradeToAndCall(address,bytes)\":{\"details\":\"Upgrade the backing implementation of the proxy and call a function on the new implementation. This is useful to initialize the proxied contract.\",\"params\":{\"data\":\"Data to send as msg.data in the low level call. It should include the signature and the parameters of the function to be called, as described in https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.\",\"newImplementation\":\"Address of the new implementation.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"claimGovernance()\":{\"notice\":\"Claim Governance of the contract to a new account (`newGovernor`). Can only be called by the new Governor.\"},\"governor()\":{\"notice\":\"Returns the address of the current Governor.\"},\"isGovernor()\":{\"notice\":\"Returns true if the caller is the current Governor.\"},\"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\"}},\"notice\":\"OETHVaultProxy delegates calls to a Vault implementation\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/proxies/Proxies.sol\":\"OETHVaultProxy\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@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\"},\"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/proxies/InitializeGovernedUpgradeabilityProxy.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport { Address } from \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\n\\nimport { Governable } from \\\"../governance/Governable.sol\\\";\\n\\n/**\\n * @title BaseGovernedUpgradeabilityProxy\\n * @dev This contract combines an upgradeability proxy with our governor system.\\n * It is based on an older version of OpenZeppelins BaseUpgradeabilityProxy\\n * with Solidity ^0.8.0.\\n * @author Origin Protocol Inc\\n */\\ncontract InitializeGovernedUpgradeabilityProxy is Governable {\\n /**\\n * @dev Emitted when the implementation is upgraded.\\n * @param implementation Address of the new implementation.\\n */\\n event Upgraded(address indexed implementation);\\n\\n /**\\n * @dev Contract initializer with Governor enforcement\\n * @param _logic Address of the initial implementation.\\n * @param _initGovernor Address of the initial Governor.\\n * @param _data Data to send as msg.data to the implementation to initialize\\n * the proxied contract.\\n * It should include the signature and the parameters of the function to be\\n * called, as described in\\n * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.\\n * This parameter is optional, if no data is given the initialization call\\n * to proxied contract will be skipped.\\n */\\n function initialize(\\n address _logic,\\n address _initGovernor,\\n bytes calldata _data\\n ) public payable onlyGovernor {\\n require(_implementation() == address(0));\\n assert(\\n IMPLEMENTATION_SLOT ==\\n bytes32(uint256(keccak256(\\\"eip1967.proxy.implementation\\\")) - 1)\\n );\\n _setImplementation(_logic);\\n if (_data.length > 0) {\\n (bool success, ) = _logic.delegatecall(_data);\\n require(success);\\n }\\n _changeGovernor(_initGovernor);\\n }\\n\\n /**\\n * @return The address of the proxy admin/it's also the governor.\\n */\\n function admin() external view returns (address) {\\n return _governor();\\n }\\n\\n /**\\n * @return The address of the implementation.\\n */\\n function implementation() external view returns (address) {\\n return _implementation();\\n }\\n\\n /**\\n * @dev Upgrade the backing implementation of the proxy.\\n * Only the admin can call this function.\\n * @param newImplementation Address of the new implementation.\\n */\\n function upgradeTo(address newImplementation) external onlyGovernor {\\n _upgradeTo(newImplementation);\\n }\\n\\n /**\\n * @dev Upgrade the backing implementation of the proxy and call a function\\n * on the new implementation.\\n * This is useful to initialize the proxied contract.\\n * @param newImplementation Address of the new implementation.\\n * @param data Data to send as msg.data in the low level call.\\n * It should include the signature and the parameters of the function to be called, as described in\\n * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.\\n */\\n function upgradeToAndCall(address newImplementation, bytes calldata data)\\n external\\n payable\\n onlyGovernor\\n {\\n _upgradeTo(newImplementation);\\n (bool success, ) = newImplementation.delegatecall(data);\\n require(success);\\n }\\n\\n /**\\n * @dev Fallback function.\\n * Implemented entirely in `_fallback`.\\n */\\n fallback() external payable {\\n _fallback();\\n }\\n\\n /**\\n * @dev Delegates execution to an implementation contract.\\n * This is a low level function that doesn't return to its internal call site.\\n * It will return to the external caller whatever the implementation returns.\\n * @param _impl Address to delegate.\\n */\\n function _delegate(address _impl) internal {\\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(gas(), _impl, 0, calldatasize(), 0, 0)\\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 /**\\n * @dev Function that is run as the first thing in the fallback function.\\n * Can be redefined in derived contracts to add functionality.\\n * Redefinitions must call super._willFallback().\\n */\\n function _willFallback() internal {}\\n\\n /**\\n * @dev fallback implementation.\\n * Extracted to enable manual triggering.\\n */\\n function _fallback() internal {\\n _willFallback();\\n _delegate(_implementation());\\n }\\n\\n /**\\n * @dev Storage slot with the address of the current implementation.\\n * This is the keccak-256 hash of \\\"eip1967.proxy.implementation\\\" subtracted by 1, and is\\n * validated in the constructor.\\n */\\n bytes32 internal constant IMPLEMENTATION_SLOT =\\n 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\\n\\n /**\\n * @dev Returns the current implementation.\\n * @return impl Address of the current implementation\\n */\\n function _implementation() internal view returns (address impl) {\\n bytes32 slot = IMPLEMENTATION_SLOT;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n impl := sload(slot)\\n }\\n }\\n\\n /**\\n * @dev Upgrades the proxy to a new implementation.\\n * @param newImplementation Address of the new implementation.\\n */\\n function _upgradeTo(address newImplementation) internal {\\n _setImplementation(newImplementation);\\n emit Upgraded(newImplementation);\\n }\\n\\n /**\\n * @dev Sets the implementation address of the proxy.\\n * @param newImplementation Address of the new implementation.\\n */\\n function _setImplementation(address newImplementation) internal {\\n require(\\n Address.isContract(newImplementation),\\n \\\"Cannot set a proxy implementation to a non-contract address\\\"\\n );\\n\\n bytes32 slot = IMPLEMENTATION_SLOT;\\n\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n sstore(slot, newImplementation)\\n }\\n }\\n}\\n\",\"keccak256\":\"0xcf9bc33957fa41a745726edb6461a4bddca875a038c848286a059f0f22b7f184\",\"license\":\"MIT\"},\"contracts/proxies/Proxies.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport { InitializeGovernedUpgradeabilityProxy } from \\\"./InitializeGovernedUpgradeabilityProxy.sol\\\";\\n\\n/**\\n * @notice OUSDProxy delegates calls to an OUSD implementation\\n */\\ncontract OUSDProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice WrappedOUSDProxy delegates calls to a WrappedOUSD implementation\\n */\\ncontract WrappedOUSDProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice VaultProxy delegates calls to a Vault implementation\\n */\\ncontract VaultProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice CompoundStrategyProxy delegates calls to a CompoundStrategy implementation\\n */\\ncontract CompoundStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice AaveStrategyProxy delegates calls to a AaveStrategy implementation\\n */\\ncontract AaveStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice ThreePoolStrategyProxy delegates calls to a ThreePoolStrategy implementation\\n */\\ncontract ThreePoolStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice ConvexStrategyProxy delegates calls to a ConvexStrategy implementation\\n */\\ncontract ConvexStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice HarvesterProxy delegates calls to a Harvester implementation\\n */\\ncontract HarvesterProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice DripperProxy delegates calls to a Dripper implementation\\n */\\ncontract DripperProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice MorphoCompoundStrategyProxy delegates calls to a MorphoCompoundStrategy implementation\\n */\\ncontract MorphoCompoundStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice ConvexOUSDMetaStrategyProxy delegates calls to a ConvexOUSDMetaStrategy implementation\\n */\\ncontract ConvexOUSDMetaStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice ConvexLUSDMetaStrategyProxy delegates calls to a ConvexalGeneralizedMetaStrategy implementation\\n */\\ncontract ConvexLUSDMetaStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice MorphoAaveStrategyProxy delegates calls to a MorphoCompoundStrategy implementation\\n */\\ncontract MorphoAaveStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice OETHProxy delegates calls to nowhere for now\\n */\\ncontract OETHProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice WOETHProxy delegates calls to nowhere for now\\n */\\ncontract WOETHProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice OETHVaultProxy delegates calls to a Vault implementation\\n */\\ncontract OETHVaultProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice OETHDripperProxy delegates calls to a OETHDripper implementation\\n */\\ncontract OETHDripperProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice OETHHarvesterProxy delegates calls to a Harvester implementation\\n */\\ncontract OETHHarvesterProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice FraxETHStrategyProxy delegates calls to a FraxETHStrategy implementation\\n */\\ncontract FraxETHStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice CurveEthStrategyProxy delegates calls to a CurveEthStrategy implementation\\n */\\ncontract ConvexEthMetaStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice BuybackProxy delegates calls to Buyback implementation\\n */\\ncontract BuybackProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice OETHMorphoAaveStrategyProxy delegates calls to a MorphoAaveStrategy implementation\\n */\\ncontract OETHMorphoAaveStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice OETHBalancerMetaPoolrEthStrategyProxy delegates calls to a BalancerMetaPoolStrategy implementation\\n */\\ncontract OETHBalancerMetaPoolrEthStrategyProxy is\\n InitializeGovernedUpgradeabilityProxy\\n{\\n\\n}\\n\\n/**\\n * @notice OETHBalancerMetaPoolwstEthStrategyProxy delegates calls to a BalancerMetaPoolStrategy implementation\\n */\\ncontract OETHBalancerMetaPoolwstEthStrategyProxy is\\n InitializeGovernedUpgradeabilityProxy\\n{\\n\\n}\\n\\n/**\\n * @notice FluxStrategyProxy delegates calls to a CompoundStrategy implementation\\n */\\ncontract FluxStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice MakerDsrStrategyProxy delegates calls to a Generalized4626Strategy implementation\\n */\\ncontract MakerDsrStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice FrxEthRedeemStrategyProxy delegates calls to a FrxEthRedeemStrategy implementation\\n */\\ncontract FrxEthRedeemStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice OETHBuybackProxy delegates calls to Buyback implementation\\n */\\ncontract OETHBuybackProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice BridgedWOETHProxy delegates calls to BridgedWOETH implementation\\n */\\ncontract BridgedWOETHProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice NativeStakingSSVStrategyProxy delegates calls to NativeStakingSSVStrategy implementation\\n */\\ncontract NativeStakingSSVStrategyProxy is\\n InitializeGovernedUpgradeabilityProxy\\n{\\n\\n}\\n\\n/**\\n * @notice NativeStakingFeeAccumulatorProxy delegates calls to NativeStakingFeeCollector implementation\\n */\\ncontract NativeStakingFeeAccumulatorProxy is\\n InitializeGovernedUpgradeabilityProxy\\n{\\n\\n}\\n\",\"keccak256\":\"0x2e294507edd91494e1020a2a1c43502d2f5cba01266c228406562ecde7a2d872\",\"license\":\"MIT\"}},\"version\":1}", + "bytecode": "0x608060405234801561001057600080fd5b506100273360008051602061099083398151915255565b600080516020610990833981519152546040516001600160a01b03909116906000907fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a908290a36109138061007d6000396000f3fe6080604052600436106100865760003560e01c80635d36b190116100595780635d36b1901461010a578063c7af33521461011f578063cf7a1d7714610144578063d38bfff414610157578063f851a4401461009057610086565b80630c340a24146100905780633659cfe6146100c25780634f1ef286146100e25780635c60da1b146100f5575b61008e610177565b005b34801561009c57600080fd5b506100a5610197565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156100ce57600080fd5b5061008e6100dd366004610745565b6101b4565b61008e6100f03660046107c8565b6101ed565b34801561010157600080fd5b506100a561028a565b34801561011657600080fd5b5061008e6102a2565b34801561012b57600080fd5b50610134610346565b60405190151581526020016100b9565b61008e610152366004610767565b610377565b34801561016357600080fd5b5061008e610172366004610745565b610491565b61019561019060008051602061089e8339815191525490565b610535565b565b60006101af6000805160206108be8339815191525490565b905090565b6101bc610346565b6101e15760405162461bcd60e51b81526004016101d89061082b565b60405180910390fd5b6101ea81610559565b50565b6101f5610346565b6102115760405162461bcd60e51b81526004016101d89061082b565b61021a83610559565b6000836001600160a01b0316838360405161023692919061081b565b600060405180830381855af49150503d8060008114610271576040519150601f19603f3d011682016040523d82523d6000602084013e610276565b606091505b505090508061028457600080fd5b50505050565b60006101af60008051602061089e8339815191525490565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b03161461033d5760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b60648201526084016101d8565b61019533610599565b600061035e6000805160206108be8339815191525490565b6001600160a01b0316336001600160a01b031614905090565b61037f610346565b61039b5760405162461bcd60e51b81526004016101d89061082b565b60006103b360008051602061089e8339815191525490565b6001600160a01b0316146103c657600080fd5b6103f160017f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbd610862565b60008051602061089e8339815191521461040d5761040d610887565b6104168461065a565b8015610488576000846001600160a01b0316838360405161043892919061081b565b600060405180830381855af49150503d8060008114610473576040519150601f19603f3d011682016040523d82523d6000602084013e610478565b606091505b505090508061048657600080fd5b505b61028483610599565b610499610346565b6104b55760405162461bcd60e51b81526004016101d89061082b565b6104dd817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b03166104fd6000805160206108be8339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b3660008037600080366000845af43d6000803e808015610554573d6000f35b3d6000fd5b6105628161065a565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b6001600160a01b0381166105ef5760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f72206973206164647265737328302900000000000060448201526064016101d8565b806001600160a01b031661060f6000805160206108be8339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a36101ea816000805160206108be83398151915255565b803b6106ce5760405162461bcd60e51b815260206004820152603b60248201527f43616e6e6f742073657420612070726f787920696d706c656d656e746174696f60448201527f6e20746f2061206e6f6e2d636f6e74726163742061646472657373000000000060648201526084016101d8565b60008051602061089e83398151915255565b80356001600160a01b03811681146106f757600080fd5b919050565b60008083601f84011261070e57600080fd5b50813567ffffffffffffffff81111561072657600080fd5b60208301915083602082850101111561073e57600080fd5b9250929050565b60006020828403121561075757600080fd5b610760826106e0565b9392505050565b6000806000806060858703121561077d57600080fd5b610786856106e0565b9350610794602086016106e0565b9250604085013567ffffffffffffffff8111156107b057600080fd5b6107bc878288016106fc565b95989497509550505050565b6000806000604084860312156107dd57600080fd5b6107e6846106e0565b9250602084013567ffffffffffffffff81111561080257600080fd5b61080e868287016106fc565b9497909650939450505050565b8183823760009101908152919050565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b60008282101561088257634e487b7160e01b600052601160045260246000fd5b500390565b634e487b7160e01b600052600160045260246000fdfe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa26469706673582212205bd4080b4c23f48d2b8904d2a87b9f714f80e32f5716bdd83886d820985ee0df64736f6c634300080700337bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a", + "deployedBytecode": "0x6080604052600436106100865760003560e01c80635d36b190116100595780635d36b1901461010a578063c7af33521461011f578063cf7a1d7714610144578063d38bfff414610157578063f851a4401461009057610086565b80630c340a24146100905780633659cfe6146100c25780634f1ef286146100e25780635c60da1b146100f5575b61008e610177565b005b34801561009c57600080fd5b506100a5610197565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156100ce57600080fd5b5061008e6100dd366004610745565b6101b4565b61008e6100f03660046107c8565b6101ed565b34801561010157600080fd5b506100a561028a565b34801561011657600080fd5b5061008e6102a2565b34801561012b57600080fd5b50610134610346565b60405190151581526020016100b9565b61008e610152366004610767565b610377565b34801561016357600080fd5b5061008e610172366004610745565b610491565b61019561019060008051602061089e8339815191525490565b610535565b565b60006101af6000805160206108be8339815191525490565b905090565b6101bc610346565b6101e15760405162461bcd60e51b81526004016101d89061082b565b60405180910390fd5b6101ea81610559565b50565b6101f5610346565b6102115760405162461bcd60e51b81526004016101d89061082b565b61021a83610559565b6000836001600160a01b0316838360405161023692919061081b565b600060405180830381855af49150503d8060008114610271576040519150601f19603f3d011682016040523d82523d6000602084013e610276565b606091505b505090508061028457600080fd5b50505050565b60006101af60008051602061089e8339815191525490565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b03161461033d5760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b60648201526084016101d8565b61019533610599565b600061035e6000805160206108be8339815191525490565b6001600160a01b0316336001600160a01b031614905090565b61037f610346565b61039b5760405162461bcd60e51b81526004016101d89061082b565b60006103b360008051602061089e8339815191525490565b6001600160a01b0316146103c657600080fd5b6103f160017f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbd610862565b60008051602061089e8339815191521461040d5761040d610887565b6104168461065a565b8015610488576000846001600160a01b0316838360405161043892919061081b565b600060405180830381855af49150503d8060008114610473576040519150601f19603f3d011682016040523d82523d6000602084013e610478565b606091505b505090508061048657600080fd5b505b61028483610599565b610499610346565b6104b55760405162461bcd60e51b81526004016101d89061082b565b6104dd817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b03166104fd6000805160206108be8339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b3660008037600080366000845af43d6000803e808015610554573d6000f35b3d6000fd5b6105628161065a565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b6001600160a01b0381166105ef5760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f72206973206164647265737328302900000000000060448201526064016101d8565b806001600160a01b031661060f6000805160206108be8339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a36101ea816000805160206108be83398151915255565b803b6106ce5760405162461bcd60e51b815260206004820152603b60248201527f43616e6e6f742073657420612070726f787920696d706c656d656e746174696f60448201527f6e20746f2061206e6f6e2d636f6e74726163742061646472657373000000000060648201526084016101d8565b60008051602061089e83398151915255565b80356001600160a01b03811681146106f757600080fd5b919050565b60008083601f84011261070e57600080fd5b50813567ffffffffffffffff81111561072657600080fd5b60208301915083602082850101111561073e57600080fd5b9250929050565b60006020828403121561075757600080fd5b610760826106e0565b9392505050565b6000806000806060858703121561077d57600080fd5b610786856106e0565b9350610794602086016106e0565b9250604085013567ffffffffffffffff8111156107b057600080fd5b6107bc878288016106fc565b95989497509550505050565b6000806000604084860312156107dd57600080fd5b6107e6846106e0565b9250602084013567ffffffffffffffff81111561080257600080fd5b61080e868287016106fc565b9497909650939450505050565b8183823760009101908152919050565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b60008282101561088257634e487b7160e01b600052601160045260246000fd5b500390565b634e487b7160e01b600052600160045260246000fdfe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa26469706673582212205bd4080b4c23f48d2b8904d2a87b9f714f80e32f5716bdd83886d820985ee0df64736f6c63430008070033", + "libraries": {}, + "devdoc": { + "kind": "dev", + "methods": { + "admin()": { + "returns": { + "_0": "The address of the proxy admin/it's also the governor." + } + }, + "implementation()": { + "returns": { + "_0": "The address of the implementation." + } + }, + "initialize(address,address,bytes)": { + "details": "Contract initializer with Governor enforcement", + "params": { + "_data": "Data to send as msg.data to the implementation to initialize the proxied contract. It should include the signature and the parameters of the function to be called, as described in https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding. This parameter is optional, if no data is given the initialization call to proxied contract will be skipped.", + "_initGovernor": "Address of the initial Governor.", + "_logic": "Address of the initial implementation." + } + }, + "transferGovernance(address)": { + "params": { + "_newGovernor": "Address of the new Governor" + } + }, + "upgradeTo(address)": { + "details": "Upgrade the backing implementation of the proxy. Only the admin can call this function.", + "params": { + "newImplementation": "Address of the new implementation." + } + }, + "upgradeToAndCall(address,bytes)": { + "details": "Upgrade the backing implementation of the proxy and call a function on the new implementation. This is useful to initialize the proxied contract.", + "params": { + "data": "Data to send as msg.data in the low level call. It should include the signature and the parameters of the function to be called, as described in https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.", + "newImplementation": "Address of the new implementation." + } + } + }, + "version": 1 + }, + "userdoc": { + "kind": "user", + "methods": { + "claimGovernance()": { + "notice": "Claim Governance of the contract to a new account (`newGovernor`). Can only be called by the new Governor." + }, + "governor()": { + "notice": "Returns the address of the current Governor." + }, + "isGovernor()": { + "notice": "Returns true if the caller is the current Governor." + }, + "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" + } + }, + "notice": "OETHVaultProxy delegates calls to a Vault implementation", + "version": 1 + }, + "storageLayout": { + "storage": [], + "types": null + } +} \ No newline at end of file diff --git a/contracts/deployments/holesky/solcInputs/0213c8dc30149ba5fb281c6d46803d0b.json b/contracts/deployments/holesky/solcInputs/0213c8dc30149ba5fb281c6d46803d0b.json new file mode 100644 index 0000000000..95028ec69a --- /dev/null +++ b/contracts/deployments/holesky/solcInputs/0213c8dc30149ba5fb281c6d46803d0b.json @@ -0,0 +1,104 @@ +{ + "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/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/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/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" + }, + "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/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/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/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 error ApprovalNotWithinTimeframe();\n error CallerNotOwner();\n error CallerNotWhitelisted();\n error ClusterAlreadyEnabled();\n error ClusterDoesNotExists();\n error ClusterIsLiquidated();\n error ClusterNotLiquidatable();\n error ExceedValidatorLimit();\n error FeeExceedsIncreaseLimit();\n error FeeIncreaseNotAllowed();\n error FeeTooHigh();\n error FeeTooLow();\n error IncorrectClusterState();\n error IncorrectValidatorState();\n error InsufficientBalance();\n error InvalidOperatorIdsLength();\n error InvalidPublicKeyLength();\n error MaxValueExceeded();\n error NewBlockPeriodIsBelowMinimum();\n error NoFeeDeclared();\n error NotAuthorized();\n error OperatorAlreadyExists();\n error OperatorDoesNotExist();\n error OperatorsListNotUnique();\n error SameFeeChangeNotAllowed();\n error TargetModuleDoesNotExist();\n error TokenTransferFailed();\n error UnsortedOperatorsList();\n error ValidatorAlreadyExists();\n error ValidatorDoesNotExist();\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 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 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 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/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" + }, + "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/strategies/NativeStaking/FeeAccumulator.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { Address } from \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport { Governable } from \"../../governance/Governable.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 is Governable {\n /// @notice The address of the Native Staking Strategy\n address public immutable STRATEGY;\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 }\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\";\n\nimport { InitializableAbstractStrategy } from \"../../utils/InitializableAbstractStrategy.sol\";\nimport { ISSVNetwork, Cluster } from \"../../interfaces/ISSVNetwork.sol\";\nimport { IWETH9 } from \"../../interfaces/IWETH9.sol\";\nimport { FeeAccumulator } from \"./FeeAccumulator.sol\";\nimport { ValidatorAccountant } from \"./ValidatorAccountant.sol\";\nimport { Cluster } from \"../../interfaces/ISSVNetwork.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\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_ADDRESS;\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 public immutable FEE_ACCUMULATOR_ADDRESS;\n\n // For future use\n uint256[50] 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 _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 address _feeAccumulator,\n address _beaconChainDepositContract\n )\n InitializableAbstractStrategy(_baseConfig)\n ValidatorAccountant(\n _wethAddress,\n _baseConfig.vaultAddress,\n _beaconChainDepositContract,\n _ssvNetwork\n )\n {\n SSV_TOKEN_ADDRESS = _ssvToken;\n FEE_ACCUMULATOR_ADDRESS = _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 /// @dev Convert accumulated ETH to WETH and send to the Harvester.\n function _collectRewardTokens() internal override {\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_TOKEN_ADDRESS).deposit{ value: ethRewards }();\n\n emit RewardTokenCollected(\n harvesterAddress,\n WETH_TOKEN_ADDRESS,\n ethRewards\n );\n IERC20(WETH_TOKEN_ADDRESS).safeTransfer(\n harvesterAddress,\n ethRewards\n );\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 function deposit(address _asset, uint256 _amount)\n external\n override\n onlyVault\n nonReentrant\n {\n _deposit(_asset, _amount);\n }\n\n /// @dev Deposit WETH to this contract to enable automated action to stake it\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 Deposit the entire balance of WETH asset in the strategy into the underlying platform\n function depositAll() external override onlyVault nonReentrant {\n uint256 wethBalance = IERC20(WETH_TOKEN_ADDRESS).balanceOf(\n address(this)\n );\n if (wethBalance > 0) {\n _deposit(WETH_TOKEN_ADDRESS, wethBalance);\n }\n }\n\n /// @notice Withdraw WETH from this contract. Used only if some WETH for is lingering on the contract. That\n /// can happen when:\n /// - the deposit was not a multiple of 32 WETH\n /// - someone sent WETH directly to this contract\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 _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 emit Withdrawal(_asset, address(0), _amount);\n IERC20(_asset).safeTransfer(_recipient, _amount);\n }\n\n /// @notice Remove all supported assets from the underlying platform and send them to Vault contract.\n function withdrawAll() external override onlyVaultOrGovernor nonReentrant {\n uint256 wethBalance = IERC20(WETH_TOKEN_ADDRESS).balanceOf(\n address(this)\n );\n if (wethBalance > 0) {\n _withdraw(vaultAddress, WETH_TOKEN_ADDRESS, wethBalance);\n }\n }\n\n function _abstractSetPToken(address _asset, address) internal override {}\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_TOKEN_ADDRESS, \"Unsupported asset\");\n\n balance =\n // add the ETH that has been staked in validators\n activeDepositedValidators *\n 32 ether +\n // add the WETH in the strategy from deposits that are still to be staked\n IERC20(WETH_TOKEN_ADDRESS).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_TOKEN_ADDRESS;\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_ADDRESS).approve(\n SSV_NETWORK_ADDRESS,\n type(uint256).max\n );\n }\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 cluster The SSV cluster details that must be derived from emitted events from the SSVNetwork contract.\n function depositSSV(\n uint64[] memory operatorIds,\n uint256 amount,\n Cluster memory cluster\n ) external onlyStrategist {\n ISSVNetwork(SSV_NETWORK_ADDRESS).deposit(\n address(this),\n operatorIds,\n amount,\n cluster\n );\n }\n\n /**\n * @notice Only accept ETH from the FeeAccumulator\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,\n \"eth not sent from Fee Accumulator\"\n );\n }\n}\n" + }, + "contracts/strategies/NativeStaking/ValidatorAccountant.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { Pausable } from \"@openzeppelin/contracts/security/Pausable.sol\";\nimport { ValidatorRegistrator } from \"./ValidatorRegistrator.sol\";\nimport { IVault } from \"../../interfaces/IVault.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 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 MAX_STAKE = 32 ether;\n /// @notice Address of the OETH Vault proxy contract\n address public immutable VAULT_ADDRESS;\n\n /// @notice Keeps track of the total consensus rewards swept from the beacon chain\n uint256 public consensusRewards = 0;\n\n /// @notice start of fuse interval\n uint256 public fuseIntervalStart = 0;\n /// @notice end of fuse interval\n uint256 public fuseIntervalEnd = 0;\n /// @notice Governor that can manually correct the accounting\n address public accountingGovernor;\n\n uint256[50] private __gap;\n\n event FuseIntervalUpdated(\n uint256 oldStart,\n uint256 oldEnd,\n uint256 start,\n uint256 end\n );\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 AccountingGovernorAddressChanged(\n address oldAddress,\n address newAddress\n );\n event AccountingBeaconChainRewards(uint256 amount);\n\n event AccountingManuallyFixed(\n uint256 oldActiveDepositedValidators,\n uint256 activeDepositedValidators,\n uint256 oldBeaconChainRewards,\n uint256 beaconChainRewards,\n uint256 ethToWeth,\n uint256 wethToBeSentToVault\n );\n\n /// @dev Throws if called by any account other than the Accounting Governor\n modifier onlyAccountingGovernor() {\n require(\n msg.sender == accountingGovernor,\n \"Caller is not the Accounting Governor\"\n );\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 constructor(\n address _wethAddress,\n address _vaultAddress,\n address _beaconChainDepositContract,\n address _ssvNetwork\n )\n ValidatorRegistrator(\n _wethAddress,\n _beaconChainDepositContract,\n _ssvNetwork\n )\n {\n VAULT_ADDRESS = _vaultAddress;\n }\n\n function setAccountingGovernor(address _address) external onlyGovernor {\n emit AccountingGovernorAddressChanged(accountingGovernor, _address);\n accountingGovernor = _address;\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 _fuseIntervalStart < 32 ether &&\n _fuseIntervalEnd < 32 ether &&\n _fuseIntervalEnd - _fuseIntervalStart >= 4 ether,\n \"incorrect fuse interval\"\n );\n\n emit FuseIntervalUpdated(\n fuseIntervalStart,\n fuseIntervalEnd,\n _fuseIntervalStart,\n _fuseIntervalEnd\n );\n\n fuseIntervalStart = _fuseIntervalStart;\n fuseIntervalEnd = _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 the accounting\n /// function will treat that ETH as a Beacon Chain Reward ETH.\n /// On the contrary if after dividing by 32 the ETH remaining on the contract falls between fuseIntervalEnd and 32 the\n /// 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 /* solhint-enable max-line-length */\n function doAccounting()\n external\n onlyRegistrator\n returns (bool accountingValid)\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 >= MAX_STAKE) {\n uint256 fullyWithdrawnValidators = newSweptETH / MAX_STAKE;\n activeDepositedValidators -= fullyWithdrawnValidators;\n\n uint256 wethToVault = MAX_STAKE * fullyWithdrawnValidators;\n IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: wethToVault }();\n IWETH9(WETH_TOKEN_ADDRESS).transfer(VAULT_ADDRESS, wethToVault);\n\n emit AccountingFullyWithdrawnValidator(\n fullyWithdrawnValidators,\n activeDepositedValidators,\n wethToVault\n );\n }\n\n uint256 ethRemaining = address(this).balance;\n // should be less than a whole validator stake\n require(ethRemaining < 32 ether, \"unexpected accounting\");\n\n // Beacon chain rewards swept (partial validator withdrawals)\n if (ethRemaining <= fuseIntervalStart) {\n // solhint-disable-next-line reentrancy\n consensusRewards += ethRemaining;\n emit AccountingBeaconChainRewards(ethRemaining);\n }\n // Beacon chain rewards swept but also a slashed validator fully exited\n else if (ethRemaining >= fuseIntervalEnd) {\n IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: ethRemaining }();\n IWETH9(WETH_TOKEN_ADDRESS).transfer(VAULT_ADDRESS, ethRemaining);\n activeDepositedValidators -= 1;\n\n emit AccountingValidatorSlashed(\n activeDepositedValidators,\n ethRemaining\n );\n }\n // Oh no... Fuse is blown. The governor (Multisig not OGV Governor) needs to set the\n // record straight by manually set the accounting values.\n else {\n // will emit a paused event\n _pause();\n accountingValid = false;\n }\n }\n\n /// @dev allow the accounting governor to fix the accounting of this strategy and unpause\n /// @param _activeDepositedValidators the override value of activeDepositedValidators\n /// @param _ethToWeth the amount of ETH to be converted to WETH\n /// @param _wethToBeSentToVault the amount of WETH to be sent to the Vault\n /// @param _consensusRewards the override value for consensusRewards\n /// @param _ethThresholdCheck maximum allowed ETH balance on the contract for the function to run\n /// @param _wethThresholdCheck maximum allowed WETH balance on the contract for the function to run\n /// the above 2 checks are done so transaction doesn't get front run and cause\n /// unexpected behaviour\n function manuallyFixAccounting(\n uint256 _activeDepositedValidators,\n uint256 _ethToWeth,\n uint256 _wethToBeSentToVault,\n uint256 _consensusRewards,\n uint256 _ethThresholdCheck,\n uint256 _wethThresholdCheck\n ) external onlyAccountingGovernor {\n require(paused(), \"not paused\");\n\n uint256 ethBalance = address(this).balance;\n uint256 wethBalance = IWETH9(WETH_TOKEN_ADDRESS).balanceOf(\n address(this)\n );\n\n require(\n ethBalance <= _ethThresholdCheck &&\n wethBalance <= _wethThresholdCheck,\n \"over accounting threshold\"\n );\n\n emit AccountingManuallyFixed(\n activeDepositedValidators,\n _activeDepositedValidators,\n consensusRewards,\n _consensusRewards,\n _ethToWeth,\n _wethToBeSentToVault\n );\n\n activeDepositedValidators = _activeDepositedValidators;\n consensusRewards = _consensusRewards;\n if (_ethToWeth > 0) {\n require(_ethToWeth <= ethBalance, \"insufficient ETH\");\n\n IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: _ethToWeth }();\n }\n if (_wethToBeSentToVault > 0) {\n IWETH9(WETH_TOKEN_ADDRESS).transfer(\n VAULT_ADDRESS,\n _wethToBeSentToVault\n );\n }\n\n _unpause();\n }\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 { 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 address of the Wrapped ETH (WETH) token contract\n address public immutable WETH_TOKEN_ADDRESS;\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_ADDRESS;\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 activeDepositedValidators;\n /// @notice State of the validators keccak256(pubKey) => state\n mapping(bytes32 => VALIDATOR_STATE) public validatorsStates;\n\n // For future use\n uint256[50] private __gap;\n\n enum VALIDATOR_STATE {\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 RegistratorAddressChanged(address oldAddress, address newAddress);\n event ETHStaked(bytes pubkey, uint256 amount, bytes withdrawal_credentials);\n event SSVValidatorRegistered(bytes pubkey, uint64[] operatorIds);\n event SSVValidatorExitInitiated(bytes pubkey, uint64[] operatorIds);\n event SSVValidatorExitCompleted(bytes pubkey, uint64[] operatorIds);\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 /// @param _wethAddress Address of the Erc20 WETH Token contract\n /// @param _beaconChainDepositContract Address of the beacon chain deposit contract\n /// @param _ssvNetwork Address of the SSV Network contract\n constructor(\n address _wethAddress,\n address _beaconChainDepositContract,\n address _ssvNetwork\n ) {\n WETH_TOKEN_ADDRESS = _wethAddress;\n BEACON_CHAIN_DEPOSIT_CONTRACT = _beaconChainDepositContract;\n SSV_NETWORK_ADDRESS = _ssvNetwork;\n }\n\n /// @notice Set the address of the registrator\n function setRegistratorAddress(address _address) external onlyGovernor {\n emit RegistratorAddressChanged(validatorRegistrator, _address);\n validatorRegistrator = _address;\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 function stakeEth(ValidatorStakeData[] calldata validators)\n external\n onlyRegistrator\n whenNotPaused\n {\n uint256 requiredETH = validators.length * 32 ether;\n\n // Check there is enough WETH from the deposits sitting in this strategy contract\n require(\n requiredETH <= IWETH9(WETH_TOKEN_ADDRESS).balanceOf(address(this)),\n \"insufficient WETH\"\n );\n\n // Convert required ETH from WETH\n IWETH9(WETH_TOKEN_ADDRESS).withdraw(requiredETH);\n\n // For each validator\n for (uint256 i = 0; i < validators.length; ) {\n bytes32 pubkeyHash = keccak256(validators[i].pubkey);\n VALIDATOR_STATE currentState = validatorsStates[pubkeyHash];\n\n require(\n currentState == VALIDATOR_STATE.REGISTERED,\n \"Validator not registered\"\n );\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 withdrawal_credentials = abi.encodePacked(\n bytes1(0x01),\n bytes11(0),\n address(this)\n );\n IDepositContract(BEACON_CHAIN_DEPOSIT_CONTRACT).deposit(\n validators[i].pubkey,\n withdrawal_credentials,\n validators[i].signature,\n validators[i].depositDataRoot\n );\n\n activeDepositedValidators += 1;\n emit ETHStaked(\n validators[i].pubkey,\n 32 ether,\n withdrawal_credentials\n );\n\n validatorsStates[pubkeyHash] = VALIDATOR_STATE.STAKED;\n\n unchecked {\n ++i;\n }\n }\n }\n\n /// @notice Registers a new validator in the SSV Cluster.\n /// Only the registrator can call this function.\n function registerSsvValidator(\n bytes calldata publicKey,\n uint64[] calldata operatorIds,\n bytes calldata sharesData,\n uint256 amount,\n Cluster calldata cluster\n ) external onlyRegistrator whenNotPaused {\n ISSVNetwork(SSV_NETWORK_ADDRESS).registerValidator(\n publicKey,\n operatorIds,\n sharesData,\n amount,\n cluster\n );\n validatorsStates[keccak256(publicKey)] = VALIDATOR_STATE.REGISTERED;\n emit SSVValidatorRegistered(publicKey, operatorIds);\n }\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 function exitSsvValidator(\n bytes calldata publicKey,\n uint64[] calldata operatorIds\n ) external onlyRegistrator whenNotPaused {\n VALIDATOR_STATE currentState = validatorsStates[keccak256(publicKey)];\n require(currentState == VALIDATOR_STATE.STAKED, \"Validator not staked\");\n\n ISSVNetwork(SSV_NETWORK_ADDRESS).exitValidator(publicKey, operatorIds);\n emit SSVValidatorExitInitiated(publicKey, operatorIds);\n\n validatorsStates[keccak256(publicKey)] = VALIDATOR_STATE.EXITING;\n }\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 function removeSsvValidator(\n bytes calldata publicKey,\n uint64[] calldata operatorIds,\n Cluster calldata cluster\n ) external onlyRegistrator whenNotPaused {\n VALIDATOR_STATE currentState = validatorsStates[keccak256(publicKey)];\n require(\n currentState == VALIDATOR_STATE.EXITING,\n \"Validator not exiting\"\n );\n\n ISSVNetwork(SSV_NETWORK_ADDRESS).removeValidator(\n publicKey,\n operatorIds,\n cluster\n );\n emit SSVValidatorExitCompleted(publicKey, operatorIds);\n\n validatorsStates[keccak256(publicKey)] = VALIDATOR_STATE.EXIT_COMPLETE;\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/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/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" + } + }, + "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/46be8b80ad6bb26f70e58a31071e073e.json b/contracts/deployments/holesky/solcInputs/46be8b80ad6bb26f70e58a31071e073e.json new file mode 100644 index 0000000000..3e979061e7 --- /dev/null +++ b/contracts/deployments/holesky/solcInputs/46be8b80ad6bb26f70e58a31071e073e.json @@ -0,0 +1,104 @@ +{ + "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/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/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/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" + }, + "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/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/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/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 error ApprovalNotWithinTimeframe();\n error CallerNotOwner();\n error CallerNotWhitelisted();\n error ClusterAlreadyEnabled();\n error ClusterDoesNotExists();\n error ClusterIsLiquidated();\n error ClusterNotLiquidatable();\n error ExceedValidatorLimit();\n error FeeExceedsIncreaseLimit();\n error FeeIncreaseNotAllowed();\n error FeeTooHigh();\n error FeeTooLow();\n error IncorrectClusterState();\n error IncorrectValidatorState();\n error InsufficientBalance();\n error InvalidOperatorIdsLength();\n error InvalidPublicKeyLength();\n error MaxValueExceeded();\n error NewBlockPeriodIsBelowMinimum();\n error NoFeeDeclared();\n error NotAuthorized();\n error OperatorAlreadyExists();\n error OperatorDoesNotExist();\n error OperatorsListNotUnique();\n error SameFeeChangeNotAllowed();\n error TargetModuleDoesNotExist();\n error TokenTransferFailed();\n error UnsortedOperatorsList();\n error ValidatorAlreadyExists();\n error ValidatorDoesNotExist();\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 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 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 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/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" + }, + "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/strategies/NativeStaking/FeeAccumulator.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { Address } from \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport { Governable } from \"../../governance/Governable.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 is Governable {\n /// @notice The address of the Native Staking Strategy\n address public immutable STRATEGY;\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 }\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\";\n\nimport { InitializableAbstractStrategy } from \"../../utils/InitializableAbstractStrategy.sol\";\nimport { ISSVNetwork, Cluster } from \"../../interfaces/ISSVNetwork.sol\";\nimport { IWETH9 } from \"../../interfaces/IWETH9.sol\";\nimport { FeeAccumulator } from \"./FeeAccumulator.sol\";\nimport { ValidatorAccountant } from \"./ValidatorAccountant.sol\";\nimport { Cluster } from \"../../interfaces/ISSVNetwork.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\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_ADDRESS;\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 public immutable FEE_ACCUMULATOR_ADDRESS;\n\n // For future use\n uint256[50] 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 _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 address _feeAccumulator,\n address _beaconChainDepositContract\n )\n InitializableAbstractStrategy(_baseConfig)\n ValidatorAccountant(\n _wethAddress,\n _baseConfig.vaultAddress,\n _beaconChainDepositContract,\n _ssvNetwork\n )\n {\n SSV_TOKEN_ADDRESS = _ssvToken;\n FEE_ACCUMULATOR_ADDRESS = _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 /// @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_TOKEN_ADDRESS).deposit{ value: ethRewards }();\n\n emit RewardTokenCollected(\n harvesterAddress,\n WETH_TOKEN_ADDRESS,\n ethRewards\n );\n IERC20(WETH_TOKEN_ADDRESS).safeTransfer(\n harvesterAddress,\n ethRewards\n );\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_TOKEN_ADDRESS, \"Unsupported asset\");\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_TOKEN_ADDRESS).balanceOf(\n address(this)\n );\n if (wethBalance > 0) {\n _deposit(WETH_TOKEN_ADDRESS, wethBalance);\n }\n }\n\n /// @notice Withdraw WETH from this contract. Used only if some WETH for is lingering on the contract. That\n /// can happen when:\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 _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 emit Withdrawal(_asset, address(0), _amount);\n IERC20(_asset).safeTransfer(_recipient, _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_TOKEN_ADDRESS).balanceOf(\n address(this)\n );\n if (wethBalance > 0) {\n _withdraw(vaultAddress, WETH_TOKEN_ADDRESS, wethBalance);\n }\n }\n\n function _abstractSetPToken(address _asset, address) internal override {}\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_TOKEN_ADDRESS, \"Unsupported asset\");\n\n balance =\n // add the ETH that has been staked in validators\n activeDepositedValidators *\n 32 ether +\n // add the WETH in the strategy from deposits that are still to be staked\n IERC20(WETH_TOKEN_ADDRESS).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_TOKEN_ADDRESS;\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_ADDRESS).approve(\n SSV_NETWORK_ADDRESS,\n type(uint256).max\n );\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_TOKEN_ADDRESS,\n \"eth not from allowed contracts\"\n );\n }\n}\n" + }, + "contracts/strategies/NativeStaking/ValidatorAccountant.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { Pausable } from \"@openzeppelin/contracts/security/Pausable.sol\";\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 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 MAX_STAKE = 32 ether;\n\n /// @notice Keeps track of the total consensus rewards swept from the beacon chain\n uint256 public consensusRewards = 0;\n\n /// @notice start of fuse interval\n uint256 public fuseIntervalStart = 0;\n /// @notice end of fuse interval\n uint256 public fuseIntervalEnd = 0;\n /// @notice Governor that can manually correct the accounting\n address public accountingGovernor;\n\n uint256[50] 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 AccountingGovernorChanged(address newAddress);\n event AccountingConsensusRewards(uint256 amount);\n\n event AccountingManuallyFixed(\n uint256 oldActiveDepositedValidators,\n uint256 activeDepositedValidators,\n uint256 oldBeaconChainRewards,\n uint256 beaconChainRewards,\n uint256 ethToWeth,\n uint256 wethToBeSentToVault\n );\n\n /// @dev Throws if called by any account other than the Accounting Governor\n modifier onlyAccountingGovernor() {\n require(\n msg.sender == accountingGovernor,\n \"Caller is not the Accounting Governor\"\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 constructor(\n address _wethAddress,\n address _vaultAddress,\n address _beaconChainDepositContract,\n address _ssvNetwork\n )\n ValidatorRegistrator(\n _wethAddress,\n _vaultAddress,\n _beaconChainDepositContract,\n _ssvNetwork\n )\n {}\n\n function setAccountingGovernor(address _address) external onlyGovernor {\n emit AccountingGovernorChanged(_address);\n accountingGovernor = _address;\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 _fuseIntervalStart < 32 ether &&\n _fuseIntervalEnd < 32 ether &&\n _fuseIntervalEnd - _fuseIntervalStart >= 4 ether,\n \"incorrect fuse interval\"\n );\n\n emit FuseIntervalUpdated(_fuseIntervalStart, _fuseIntervalEnd);\n\n fuseIntervalStart = _fuseIntervalStart;\n fuseIntervalEnd = _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 /* solhint-enable max-line-length */\n function doAccounting()\n external\n onlyRegistrator\n whenNotPaused\n returns (bool accountingValid)\n {\n if (address(this).balance < consensusRewards) {\n // pause and fail the accounting\n _pause();\n return false;\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 >= MAX_STAKE) {\n uint256 fullyWithdrawnValidators = newSweptETH / MAX_STAKE;\n activeDepositedValidators -= fullyWithdrawnValidators;\n\n uint256 wethToVault = MAX_STAKE * fullyWithdrawnValidators;\n IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: wethToVault }();\n IWETH9(WETH_TOKEN_ADDRESS).transfer(VAULT_ADDRESS, 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 < 32 ether, \"unexpected accounting\");\n\n // If no Beacon chain consensus rewards swept\n if (ethRemaining == 0) {\n // do nothing\n return accountingValid;\n }\n // Beacon chain consensus rewards swept (partial validator withdrawals)\n else if (ethRemaining < fuseIntervalStart) {\n // solhint-disable-next-line reentrancy\n consensusRewards += ethRemaining;\n emit AccountingConsensusRewards(ethRemaining);\n }\n // Beacon chain consensus rewards swept but also a slashed validator fully exited\n else if (ethRemaining > fuseIntervalEnd) {\n IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: ethRemaining }();\n IWETH9(WETH_TOKEN_ADDRESS).transfer(VAULT_ADDRESS, ethRemaining);\n activeDepositedValidators -= 1;\n\n emit AccountingValidatorSlashed(\n activeDepositedValidators,\n ethRemaining\n );\n }\n // Oh no... Fuse is blown. The governor (Multisig not OGV Governor) needs to set the\n // record straight by manually set the accounting values.\n else {\n // will emit a paused event\n _pause();\n accountingValid = false;\n }\n }\n\n /// @dev allow the accounting governor to fix the accounting of this strategy and unpause\n /// @param _activeDepositedValidators the override value of activeDepositedValidators\n /// @param _ethToWeth the amount of ETH to be converted to WETH\n /// @param _wethToBeSentToVault the amount of WETH to be sent to the Vault\n /// @param _consensusRewards the override value for consensusRewards\n /// @param _ethThresholdCheck maximum allowed ETH balance on the contract for the function to run\n /// @param _wethThresholdCheck maximum allowed WETH balance on the contract for the function to run\n /// the above 2 checks are done so transaction doesn't get front run and cause\n /// unexpected behaviour\n function manuallyFixAccounting(\n uint256 _activeDepositedValidators,\n uint256 _ethToWeth,\n uint256 _wethToBeSentToVault,\n uint256 _consensusRewards,\n uint256 _ethThresholdCheck,\n uint256 _wethThresholdCheck\n ) external onlyAccountingGovernor whenPaused {\n uint256 ethBalance = address(this).balance;\n uint256 wethBalance = IWETH9(WETH_TOKEN_ADDRESS).balanceOf(\n address(this)\n );\n\n require(\n ethBalance <= _ethThresholdCheck &&\n wethBalance <= _wethThresholdCheck,\n \"over accounting threshold\"\n );\n\n emit AccountingManuallyFixed(\n activeDepositedValidators,\n _activeDepositedValidators,\n consensusRewards,\n _consensusRewards,\n _ethToWeth,\n _wethToBeSentToVault\n );\n\n activeDepositedValidators = _activeDepositedValidators;\n consensusRewards = _consensusRewards;\n if (_ethToWeth > 0) {\n require(_ethToWeth <= ethBalance, \"insufficient ETH\");\n\n IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: _ethToWeth }();\n }\n if (_wethToBeSentToVault > 0) {\n IWETH9(WETH_TOKEN_ADDRESS).transfer(\n VAULT_ADDRESS,\n _wethToBeSentToVault\n );\n }\n\n _unpause();\n }\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 address of the Wrapped ETH (WETH) token contract\n address public immutable WETH_TOKEN_ADDRESS;\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_ADDRESS;\n /// @notice Address of the OETH Vault proxy contract\n address public immutable VAULT_ADDRESS;\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 activeDepositedValidators;\n /// @notice State of the validators keccak256(pubKey) => state\n mapping(bytes32 => VALIDATOR_STATE) public validatorsStates;\n\n // For future use\n uint256[50] private __gap;\n\n enum VALIDATOR_STATE {\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 newAddress);\n event ETHStaked(bytes pubkey, uint256 amount, bytes withdrawal_credentials);\n event SSVValidatorRegistered(bytes pubkey, uint64[] operatorIds);\n event SSVValidatorExitInitiated(bytes pubkey, uint64[] operatorIds);\n event SSVValidatorExitCompleted(bytes pubkey, uint64[] operatorIds);\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 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 constructor(\n address _wethAddress,\n address _vaultAddress,\n address _beaconChainDepositContract,\n address _ssvNetwork\n ) {\n WETH_TOKEN_ADDRESS = _wethAddress;\n BEACON_CHAIN_DEPOSIT_CONTRACT = _beaconChainDepositContract;\n SSV_NETWORK_ADDRESS = _ssvNetwork;\n VAULT_ADDRESS = _vaultAddress;\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 emit RegistratorChanged(_address);\n validatorRegistrator = _address;\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 function stakeEth(ValidatorStakeData[] calldata validators)\n external\n onlyRegistrator\n whenNotPaused\n {\n uint256 requiredETH = validators.length * 32 ether;\n\n // Check there is enough WETH from the deposits sitting in this strategy contract\n require(\n requiredETH <= IWETH9(WETH_TOKEN_ADDRESS).balanceOf(address(this)),\n \"insufficient WETH\"\n );\n\n // Convert required ETH from WETH\n IWETH9(WETH_TOKEN_ADDRESS).withdraw(requiredETH);\n\n // For each validator\n for (uint256 i = 0; i < validators.length; ) {\n bytes32 pubkeyHash = keccak256(validators[i].pubkey);\n VALIDATOR_STATE currentState = validatorsStates[pubkeyHash];\n\n require(\n currentState == VALIDATOR_STATE.REGISTERED,\n \"Validator not registered\"\n );\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 withdrawal_credentials = abi.encodePacked(\n bytes1(0x01),\n bytes11(0),\n address(this)\n );\n IDepositContract(BEACON_CHAIN_DEPOSIT_CONTRACT).deposit(\n validators[i].pubkey,\n withdrawal_credentials,\n validators[i].signature,\n validators[i].depositDataRoot\n );\n\n activeDepositedValidators += 1;\n emit ETHStaked(\n validators[i].pubkey,\n 32 ether,\n withdrawal_credentials\n );\n\n validatorsStates[pubkeyHash] = VALIDATOR_STATE.STAKED;\n\n unchecked {\n ++i;\n }\n }\n }\n\n /// @notice Registers a new validator in the SSV Cluster.\n /// Only the registrator can call this function.\n function registerSsvValidator(\n bytes calldata publicKey,\n uint64[] calldata operatorIds,\n bytes calldata sharesData,\n uint256 amount,\n Cluster calldata cluster\n ) external onlyRegistrator whenNotPaused {\n ISSVNetwork(SSV_NETWORK_ADDRESS).registerValidator(\n publicKey,\n operatorIds,\n sharesData,\n amount,\n cluster\n );\n validatorsStates[keccak256(publicKey)] = VALIDATOR_STATE.REGISTERED;\n emit SSVValidatorRegistered(publicKey, operatorIds);\n }\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 function exitSsvValidator(\n bytes calldata publicKey,\n uint64[] calldata operatorIds\n ) external onlyRegistrator whenNotPaused {\n VALIDATOR_STATE currentState = validatorsStates[keccak256(publicKey)];\n require(currentState == VALIDATOR_STATE.STAKED, \"Validator not staked\");\n\n ISSVNetwork(SSV_NETWORK_ADDRESS).exitValidator(publicKey, operatorIds);\n emit SSVValidatorExitInitiated(publicKey, operatorIds);\n\n validatorsStates[keccak256(publicKey)] = VALIDATOR_STATE.EXITING;\n }\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 function removeSsvValidator(\n bytes calldata publicKey,\n uint64[] calldata operatorIds,\n Cluster calldata cluster\n ) external onlyRegistrator whenNotPaused {\n VALIDATOR_STATE currentState = validatorsStates[keccak256(publicKey)];\n require(\n currentState == VALIDATOR_STATE.EXITING,\n \"Validator not exiting\"\n );\n\n ISSVNetwork(SSV_NETWORK_ADDRESS).removeValidator(\n publicKey,\n operatorIds,\n cluster\n );\n emit SSVValidatorExitCompleted(publicKey, operatorIds);\n\n validatorsStates[keccak256(publicKey)] = VALIDATOR_STATE.EXIT_COMPLETE;\n }\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 cluster The SSV cluster details that must be derived from emitted events from the SSVNetwork contract.\n function depositSSV(\n uint64[] memory operatorIds,\n uint256 amount,\n Cluster memory cluster\n ) external onlyStrategist {\n ISSVNetwork(SSV_NETWORK_ADDRESS).deposit(\n address(this),\n operatorIds,\n amount,\n cluster\n );\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/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/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" + } + }, + "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/da4c2bc4af0be4b969e54f8b43895033.json b/contracts/deployments/holesky/solcInputs/da4c2bc4af0be4b969e54f8b43895033.json new file mode 100644 index 0000000000..654092310a --- /dev/null +++ b/contracts/deployments/holesky/solcInputs/da4c2bc4af0be4b969e54f8b43895033.json @@ -0,0 +1,671 @@ +{ + "language": "Solidity", + "sources": { + "@openzeppelin/contracts/access/AccessControl.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/AccessControl.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IAccessControl.sol\";\nimport \"../utils/Context.sol\";\nimport \"../utils/Strings.sol\";\nimport \"../utils/introspection/ERC165.sol\";\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address => bool) members;\n bytes32 adminRole;\n }\n\n mapping(bytes32 => RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with a standardized message including the required role.\n *\n * The format of the revert reason is given by the following regular expression:\n *\n * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/\n *\n * _Available since v4.1._\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role, _msgSender());\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view override returns (bool) {\n return _roles[role].members[account];\n }\n\n /**\n * @dev Revert with a standard message if `account` is missing `role`.\n *\n * The format of the revert reason is given by the following regular expression:\n *\n * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/\n */\n function _checkRole(bytes32 role, address account) internal view {\n if (!hasRole(role, account)) {\n revert(\n string(\n abi.encodePacked(\n \"AccessControl: account \",\n Strings.toHexString(uint160(account), 20),\n \" is missing role \",\n Strings.toHexString(uint256(role), 32)\n )\n )\n );\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view override returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `account`.\n */\n function renounceRole(bytes32 role, address account) public virtual override {\n require(account == _msgSender(), \"AccessControl: can only renounce roles for self\");\n\n _revokeRole(role, account);\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event. Note that unlike {grantRole}, this function doesn't perform any\n * checks on the calling account.\n *\n * [WARNING]\n * ====\n * This function should only be called from the constructor when setting\n * up the initial roles for the system.\n *\n * Using this function in any other way is effectively circumventing the admin\n * system imposed by {AccessControl}.\n * ====\n *\n * NOTE: This function is deprecated in favor of {_grantRole}.\n */\n function _setupRole(bytes32 role, address account) internal virtual {\n _grantRole(role, account);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * Internal function without access restriction.\n */\n function _grantRole(bytes32 role, address account) internal virtual {\n if (!hasRole(role, account)) {\n _roles[role].members[account] = true;\n emit RoleGranted(role, account, _msgSender());\n }\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * Internal function without access restriction.\n */\n function _revokeRole(bytes32 role, address account) internal virtual {\n if (hasRole(role, account)) {\n _roles[role].members[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n }\n }\n}\n" + }, + "@openzeppelin/contracts/access/AccessControlEnumerable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/AccessControlEnumerable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IAccessControlEnumerable.sol\";\nimport \"./AccessControl.sol\";\nimport \"../utils/structs/EnumerableSet.sol\";\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 => EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view override returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view override returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override {\n super._grantRole(role, account);\n _roleMembers[role].add(account);\n }\n\n /**\n * @dev Overload {_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override {\n super._revokeRole(role, account);\n _roleMembers[role].remove(account);\n }\n}\n" + }, + "@openzeppelin/contracts/access/IAccessControl.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n *\n * _Available since v3.1._\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `account`.\n */\n function renounceRole(bytes32 role, address account) external;\n}\n" + }, + "@openzeppelin/contracts/access/IAccessControlEnumerable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/IAccessControlEnumerable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IAccessControl.sol\";\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n" + }, + "@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/introspection/ERC165.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC165.sol\";\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n *\n * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n" + }, + "@openzeppelin/contracts/utils/introspection/IERC165.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\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" + }, + "@openzeppelin/contracts/utils/structs/EnumerableSet.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/structs/EnumerableSet.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position of the value in the `values` array, plus 1 because index 0\n // means a value is not in the set.\n mapping(bytes32 => uint256) _indexes;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._indexes[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We read and store the value's index to prevent multiple reads from the same storage slot\n uint256 valueIndex = set._indexes[value];\n\n if (valueIndex != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 toDeleteIndex = valueIndex - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (lastIndex != toDeleteIndex) {\n bytes32 lastvalue = set._values[lastIndex];\n\n // Move the last value to the index where the value to delete is\n set._values[toDeleteIndex] = lastvalue;\n // Update the index for the moved value\n set._indexes[lastvalue] = valueIndex; // Replace lastvalue's index to valueIndex\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the index for the deleted slot\n delete set._indexes[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._indexes[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n return _values(set._inner);\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n assembly {\n result := store\n }\n\n return result;\n }\n}\n" + }, + "contracts/buyback/BaseBuyback.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { Strategizable } from \"../governance/Strategizable.sol\";\nimport \"../interfaces/chainlink/AggregatorV3Interface.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { ICVXLocker } from \"../interfaces/ICVXLocker.sol\";\nimport { ISwapper } from \"../interfaces/ISwapper.sol\";\n\nimport { Initializable } from \"../utils/Initializable.sol\";\n\nabstract contract BaseBuyback is Initializable, Strategizable {\n using SafeERC20 for IERC20;\n\n event SwapRouterUpdated(address indexed _address);\n\n event RewardsSourceUpdated(address indexed _address);\n event TreasuryManagerUpdated(address indexed _address);\n event CVXShareBpsUpdated(uint256 bps);\n\n // Emitted whenever OUSD/OETH is swapped for OGV/CVX or any other token\n event OTokenBuyback(\n address indexed oToken,\n address indexed swappedFor,\n uint256 swapAmountIn,\n uint256 minExpected\n );\n\n // Address of 1-inch Swap Router\n address public swapRouter;\n\n // slither-disable-next-line constable-states\n address private __deprecated_ousd;\n // slither-disable-next-line constable-states\n address private __deprecated_ogv;\n // slither-disable-next-line constable-states\n address private __deprecated_usdt;\n // slither-disable-next-line constable-states\n address private __deprecated_weth9;\n\n // Address that receives OGV after swaps\n address public rewardsSource;\n\n // Address that receives all other tokens after swaps\n address public treasuryManager;\n\n // slither-disable-next-line constable-states\n uint256 private __deprecated_treasuryBps;\n\n address public immutable oToken;\n address public immutable ogv;\n address public immutable cvx;\n address public immutable cvxLocker;\n\n // Amount of `oToken` balance to use for OGV buyback\n uint256 public balanceForOGV;\n\n // Amount of `oToken` balance to use for CVX buyback\n uint256 public balanceForCVX;\n\n // Percentage of `oToken` balance to be used for CVX\n uint256 public cvxShareBps; // 10000 = 100%\n\n constructor(\n address _oToken,\n address _ogv,\n address _cvx,\n address _cvxLocker\n ) {\n // Make sure nobody owns the implementation contract\n _setGovernor(address(0));\n\n oToken = _oToken;\n ogv = _ogv;\n cvx = _cvx;\n cvxLocker = _cvxLocker;\n }\n\n /**\n * @param _swapRouter Address of Uniswap V3 Router\n * @param _strategistAddr Address of Strategist multi-sig wallet\n * @param _treasuryManagerAddr Address that receives the treasury's share of OUSD\n * @param _rewardsSource Address of RewardsSource contract\n * @param _cvxShareBps Percentage of balance to use for CVX\n */\n function initialize(\n address _swapRouter,\n address _strategistAddr,\n address _treasuryManagerAddr,\n address _rewardsSource,\n uint256 _cvxShareBps\n ) external onlyGovernor initializer {\n _setStrategistAddr(_strategistAddr);\n\n _setSwapRouter(_swapRouter);\n _setRewardsSource(_rewardsSource);\n\n _setTreasuryManager(_treasuryManagerAddr);\n\n _setCVXShareBps(_cvxShareBps);\n }\n\n /**\n * @dev Set address of Uniswap Universal Router for performing liquidation\n * of platform fee tokens. Setting to 0x0 will pause swaps.\n *\n * @param _router Address of the Uniswap Universal router\n */\n function setSwapRouter(address _router) external onlyGovernor {\n _setSwapRouter(_router);\n }\n\n function _setSwapRouter(address _router) internal {\n address oldRouter = swapRouter;\n swapRouter = _router;\n\n if (oldRouter != address(0)) {\n // Remove allowance of old router, if any\n\n if (IERC20(ogv).allowance(address(this), oldRouter) != 0) {\n // slither-disable-next-line unused-return\n IERC20(ogv).safeApprove(oldRouter, 0);\n }\n\n if (IERC20(cvx).allowance(address(this), oldRouter) != 0) {\n // slither-disable-next-line unused-return\n IERC20(cvx).safeApprove(oldRouter, 0);\n }\n }\n\n emit SwapRouterUpdated(_router);\n }\n\n /**\n * @dev Sets the address that receives the OGV buyback rewards\n * @param _address Address\n */\n function setRewardsSource(address _address) external onlyGovernor {\n _setRewardsSource(_address);\n }\n\n function _setRewardsSource(address _address) internal {\n require(_address != address(0), \"Address not set\");\n rewardsSource = _address;\n emit RewardsSourceUpdated(_address);\n }\n\n /**\n * @dev Sets the address that can receive and manage the funds for Treasury\n * @param _address Address\n */\n function setTreasuryManager(address _address) external onlyGovernor {\n _setTreasuryManager(_address);\n }\n\n function _setTreasuryManager(address _address) internal {\n require(_address != address(0), \"Address not set\");\n treasuryManager = _address;\n emit TreasuryManagerUpdated(_address);\n }\n\n /**\n * @dev Sets the percentage of oToken to use for Flywheel tokens\n * @param _bps BPS, 10000 to 100%\n */\n function setCVXShareBps(uint256 _bps) external onlyGovernor {\n _setCVXShareBps(_bps);\n }\n\n function _setCVXShareBps(uint256 _bps) internal {\n require(_bps <= 10000, \"Invalid bps value\");\n cvxShareBps = _bps;\n emit CVXShareBpsUpdated(_bps);\n }\n\n /**\n * @dev Computes the split of oToken balance that can be\n * used for OGV and CVX buybacks.\n */\n function _updateBuybackSplits()\n internal\n returns (uint256 _balanceForOGV, uint256 _balanceForCVX)\n {\n _balanceForOGV = balanceForOGV;\n _balanceForCVX = balanceForCVX;\n\n uint256 totalBalance = IERC20(oToken).balanceOf(address(this));\n uint256 unsplitBalance = totalBalance - _balanceForOGV - _balanceForCVX;\n\n // Check if all balance is accounted for\n if (unsplitBalance != 0) {\n // If not, split unaccounted balance based on `cvxShareBps`\n uint256 addToCVX = (unsplitBalance * cvxShareBps) / 10000;\n _balanceForCVX = _balanceForCVX + addToCVX;\n _balanceForOGV = _balanceForOGV + unsplitBalance - addToCVX;\n\n // Update storage\n balanceForOGV = _balanceForOGV;\n balanceForCVX = _balanceForCVX;\n }\n }\n\n function updateBuybackSplits() external onlyGovernor {\n // slither-disable-next-line unused-return\n _updateBuybackSplits();\n }\n\n function _swapToken(\n address tokenOut,\n uint256 oTokenAmount,\n uint256 minAmountOut,\n bytes calldata swapData\n ) internal returns (uint256 amountOut) {\n require(oTokenAmount > 0, \"Invalid Swap Amount\");\n require(swapRouter != address(0), \"Swap Router not set\");\n require(minAmountOut > 0, \"Invalid minAmount\");\n\n // Transfer OToken to Swapper for swapping\n // slither-disable-next-line unchecked-transfer unused-return\n IERC20(oToken).transfer(swapRouter, oTokenAmount);\n\n // Swap\n amountOut = ISwapper(swapRouter).swap(\n oToken,\n tokenOut,\n oTokenAmount,\n minAmountOut,\n swapData\n );\n\n require(amountOut >= minAmountOut, \"Higher Slippage\");\n\n emit OTokenBuyback(oToken, tokenOut, minAmountOut, amountOut);\n }\n\n /**\n * @dev Swaps `oTokenAmount` to OGV\n * @param oTokenAmount Amount of OUSD/OETH to swap\n * @param minOGV Minimum OGV to receive for oTokenAmount\n * @param swapData 1inch Swap Data\n */\n function swapForOGV(\n uint256 oTokenAmount,\n uint256 minOGV,\n bytes calldata swapData\n ) external onlyGovernorOrStrategist nonReentrant {\n (uint256 _amountForOGV, ) = _updateBuybackSplits();\n require(_amountForOGV >= oTokenAmount, \"Balance underflow\");\n require(rewardsSource != address(0), \"RewardsSource contract not set\");\n\n unchecked {\n // Subtract the amount to swap from net balance\n balanceForOGV = _amountForOGV - oTokenAmount;\n }\n\n uint256 ogvReceived = _swapToken(ogv, oTokenAmount, minOGV, swapData);\n\n // Transfer OGV received to RewardsSource contract\n // slither-disable-next-line unchecked-transfer unused-return\n IERC20(ogv).transfer(rewardsSource, ogvReceived);\n }\n\n /**\n * @dev Swaps `oTokenAmount` to CVX\n * @param oTokenAmount Amount of OUSD/OETH to swap\n * @param minCVX Minimum CVX to receive for oTokenAmount\n * @param swapData 1inch Swap Data\n */\n function swapForCVX(\n uint256 oTokenAmount,\n uint256 minCVX,\n bytes calldata swapData\n ) external onlyGovernorOrStrategist nonReentrant {\n (, uint256 _amountForCVX) = _updateBuybackSplits();\n require(_amountForCVX >= oTokenAmount, \"Balance underflow\");\n\n unchecked {\n // Subtract the amount to swap from net balance\n balanceForCVX = _amountForCVX - oTokenAmount;\n }\n\n uint256 cvxReceived = _swapToken(cvx, oTokenAmount, minCVX, swapData);\n\n // Lock all CVX\n _lockAllCVX(cvxReceived);\n }\n\n /**\n * @dev Locks all CVX held by the contract on behalf of the Treasury Manager\n */\n function lockAllCVX() external onlyGovernorOrStrategist {\n _lockAllCVX(IERC20(cvx).balanceOf(address(this)));\n }\n\n function _lockAllCVX(uint256 cvxAmount) internal {\n require(\n treasuryManager != address(0),\n \"Treasury manager address not set\"\n );\n\n // Lock all available CVX on behalf of `treasuryManager`\n ICVXLocker(cvxLocker).lock(treasuryManager, cvxAmount, 0);\n }\n\n /**\n * @dev Approve CVX Locker to move CVX held by this contract\n */\n function safeApproveAllTokens() external onlyGovernorOrStrategist {\n IERC20(cvx).safeApprove(cvxLocker, type(uint256).max);\n }\n\n /**\n * @notice Owner function to withdraw a specific amount of a token\n * @param token token to be transferered\n * @param amount amount of the token to be transferred\n */\n function transferToken(address token, uint256 amount)\n external\n onlyGovernor\n nonReentrant\n {\n IERC20(token).safeTransfer(_governor(), amount);\n }\n}\n" + }, + "contracts/buyback/OETHBuyback.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { BaseBuyback } from \"./BaseBuyback.sol\";\n\ncontract OETHBuyback is BaseBuyback {\n constructor(\n address _oToken,\n address _ogv,\n address _cvx,\n address _cvxLocker\n ) BaseBuyback(_oToken, _ogv, _cvx, _cvxLocker) {}\n}\n" + }, + "contracts/buyback/OUSDBuyback.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { BaseBuyback } from \"./BaseBuyback.sol\";\n\ncontract OUSDBuyback is BaseBuyback {\n constructor(\n address _oToken,\n address _ogv,\n address _cvx,\n address _cvxLocker\n ) BaseBuyback(_oToken, _ogv, _cvx, _cvxLocker) {}\n}\n" + }, + "contracts/compensation/CompensationClaims.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\";\n\nimport { Initializable } from \"../utils/Initializable.sol\";\nimport { Governable } from \"../governance/Governable.sol\";\n\n/**\n * @title Compensation Claims\n * @author Origin Protocol Inc\n * @dev Airdrop for ERC20 tokens.\n *\n * Provides a coin airdrop with a verification period in which everyone\n * can check that all claims are correct before any actual funds are moved\n * to the contract.\n *\n * - Users can claim funds during the claim period.\n *\n * - The adjuster can set the amount of each user's claim,\n * but only when unlocked, and not during the claim period.\n *\n * - The governor can unlock and lock the adjuster, outside the claim period.\n * - The governor can start the claim period, if it's not started.\n * - The governor can collect any remaining funds after the claim period is over.\n *\n * Intended use sequence:\n *\n * 1. Governor unlocks the adjuster\n * 2. Adjuster uploads claims\n * 3. Governor locks the adjuster\n * 4. Everyone verifies that the claim amounts and totals are correct\n * 5. Payout funds are moved to the contract\n * 6. The claim period starts\n * 7. Users claim funds\n * 8. The claim period ends\n * 9. Governor can collect any remaing funds\n *\n */\ncontract CompensationClaims is Governable {\n address public adjuster;\n address public token;\n uint256 public end;\n uint256 public totalClaims;\n mapping(address => uint256) claims;\n bool public isAdjusterLocked;\n\n using SafeMath for uint256;\n\n event Claim(address indexed recipient, uint256 amount);\n event ClaimSet(address indexed recipient, uint256 amount);\n event Start(uint256 end);\n event Lock();\n event Unlock();\n event Collect(address indexed coin, uint256 amount);\n\n constructor(address _token, address _adjuster) onlyGovernor {\n token = _token;\n adjuster = _adjuster;\n isAdjusterLocked = true;\n }\n\n function balanceOf(address _account) external view returns (uint256) {\n return claims[_account];\n }\n\n function decimals() external view returns (uint8) {\n return IERC20Decimals(token).decimals();\n }\n\n /* -- User -- */\n\n function claim(address _recipient) external onlyInClaimPeriod nonReentrant {\n uint256 amount = claims[_recipient];\n require(amount > 0, \"Amount must be greater than 0\");\n claims[_recipient] = 0;\n totalClaims = totalClaims.sub(amount);\n SafeERC20.safeTransfer(IERC20(token), _recipient, amount);\n emit Claim(_recipient, amount);\n }\n\n /* -- Adjustor -- */\n\n function setClaims(\n address[] calldata _addresses,\n uint256[] calldata _amounts\n ) external notInClaimPeriod onlyUnlockedAdjuster {\n require(\n _addresses.length == _amounts.length,\n \"Addresses and amounts must match\"\n );\n uint256 len = _addresses.length;\n for (uint256 i = 0; i < len; i++) {\n address recipient = _addresses[i];\n uint256 newAmount = _amounts[i];\n uint256 oldAmount = claims[recipient];\n claims[recipient] = newAmount;\n totalClaims = totalClaims.add(newAmount).sub(oldAmount);\n emit ClaimSet(recipient, newAmount);\n }\n }\n\n /* -- Governor -- */\n\n function lockAdjuster() external onlyGovernor notInClaimPeriod {\n _lockAdjuster();\n }\n\n function _lockAdjuster() internal {\n isAdjusterLocked = true;\n emit Lock();\n }\n\n function unlockAdjuster() external onlyGovernor notInClaimPeriod {\n isAdjusterLocked = false;\n emit Unlock();\n }\n\n function start(uint256 _seconds)\n external\n onlyGovernor\n notInClaimPeriod\n nonReentrant\n {\n require(totalClaims > 0, \"No claims\");\n uint256 funding = IERC20(token).balanceOf(address(this));\n require(funding >= totalClaims, \"Insufficient funds for all claims\");\n _lockAdjuster();\n end = block.timestamp.add(_seconds);\n require(end.sub(block.timestamp) < 31622400, \"Duration too long\"); // 31622400 = 366*24*60*60\n emit Start(end);\n }\n\n function collect(address _coin)\n external\n onlyGovernor\n notInClaimPeriod\n nonReentrant\n {\n uint256 amount = IERC20(_coin).balanceOf(address(this));\n SafeERC20.safeTransfer(IERC20(_coin), address(governor()), amount);\n emit Collect(_coin, amount);\n }\n\n /* -- modifiers -- */\n\n modifier onlyInClaimPeriod() {\n require(block.timestamp <= end, \"Should be in claim period\");\n _;\n }\n\n modifier notInClaimPeriod() {\n require(block.timestamp > end, \"Should not be in claim period\");\n _;\n }\n\n modifier onlyUnlockedAdjuster() {\n require(isAdjusterLocked == false, \"Adjuster must be unlocked\");\n require(msg.sender == adjuster, \"Must be adjuster\");\n _;\n }\n}\n\ninterface IERC20Decimals {\n function decimals() external view returns (uint8);\n}\n" + }, + "contracts/echidna/Debugger.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nlibrary Debugger {\n event Debug(string debugString);\n event Debug(string description, string data);\n event Debug(string prefix, string description, string data);\n event Debug(string description, bytes32 data);\n event Debug(string prefix, string description, bytes32 data);\n event Debug(string description, uint256 data);\n event Debug(string prefix, string description, uint256 data);\n event Debug(string description, int256 data);\n event Debug(string prefix, string description, int256 data);\n event Debug(string description, address data);\n event Debug(string prefix, string description, address data);\n event Debug(string description, bool data);\n event Debug(string prefix, string description, bool data);\n\n function log(string memory debugString) internal {\n emit Debug(debugString);\n }\n\n function log(string memory description, string memory data) internal {\n emit Debug(description, data);\n }\n\n function log(\n string memory prefix,\n string memory description,\n string memory data\n ) internal {\n emit Debug(prefix, description, data);\n }\n\n function log(string memory description, bytes32 data) internal {\n emit Debug(description, data);\n }\n\n function log(\n string memory prefix,\n string memory description,\n bytes32 data\n ) internal {\n emit Debug(prefix, description, data);\n }\n\n function log(string memory description, uint256 data) internal {\n emit Debug(description, data);\n }\n\n function log(\n string memory prefix,\n string memory description,\n uint256 data\n ) internal {\n emit Debug(prefix, description, data);\n }\n\n function log(string memory description, int256 data) internal {\n emit Debug(description, data);\n }\n\n function log(\n string memory prefix,\n string memory description,\n int256 data\n ) internal {\n emit Debug(prefix, description, data);\n }\n\n function log(string memory description, address data) internal {\n emit Debug(description, data);\n }\n\n function log(\n string memory prefix,\n string memory description,\n address data\n ) internal {\n emit Debug(prefix, description, data);\n }\n\n function log(string memory description, bool data) internal {\n emit Debug(description, data);\n }\n\n function log(\n string memory prefix,\n string memory description,\n bool data\n ) internal {\n emit Debug(prefix, description, data);\n }\n}\n" + }, + "contracts/echidna/Echidna.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./EchidnaTestApproval.sol\";\n\n/**\n * @title Echidna test contract for OUSD\n * @notice Target contract to be tested, containing all mixins\n * @author Rappie\n */\ncontract Echidna is EchidnaTestApproval {\n\n}\n" + }, + "contracts/echidna/EchidnaConfig.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @title Top-level mixin for configuring the desired fuzzing setup\n * @author Rappie\n */\ncontract EchidnaConfig {\n address internal constant ADDRESS_VAULT = address(0x10000);\n address internal constant ADDRESS_OUTSIDER_USER = address(0x20000);\n\n address internal constant ADDRESS_USER0 = address(0x30000);\n address internal constant ADDRESS_USER1 = address(0x40000);\n\n // Will be set in EchidnaSetup constructor\n address internal ADDRESS_OUTSIDER_CONTRACT;\n address internal ADDRESS_CONTRACT0;\n address internal ADDRESS_CONTRACT1;\n\n // Toggle known issues\n //\n // This can be used to skip tests that are known to fail. This is useful\n // when debugging a specific issue, but should be disabled when running\n // the full test suite.\n //\n // True => skip tests that are known to fail\n // False => run all tests\n //\n bool internal constant TOGGLE_KNOWN_ISSUES = false;\n\n // Toggle known issues within limits\n //\n // Same as TOGGLE_KNOWN_ISSUES, but also skip tests that are known to fail\n // within limits set by the variables below.\n //\n bool internal constant TOGGLE_KNOWN_ISSUES_WITHIN_LIMITS = true;\n\n // Starting balance\n //\n // Gives OUSD a non-zero starting supply, which can be useful to ignore\n // certain edge cases.\n //\n // The starting balance is given to outsider accounts that are not used as\n // accounts while fuzzing.\n //\n bool internal constant TOGGLE_STARTING_BALANCE = true;\n uint256 internal constant STARTING_BALANCE = 1_000_000e18;\n\n // Change supply\n //\n // Set a limit to the amount of change per rebase, which can be useful to\n // ignore certain edge cases.\n //\n // True => limit the amount of change to a percentage of total supply\n // False => no limit\n //\n bool internal constant TOGGLE_CHANGESUPPLY_LIMIT = true;\n uint256 internal constant CHANGESUPPLY_DIVISOR = 10; // 10% of total supply\n\n // Mint limit\n //\n // Set a limit the the amount minted per mint, which can be useful to\n // ignore certain edge cases.\n //\n // True => limit the amount of minted tokens\n // False => no limit\n //\n bool internal constant TOGGLE_MINT_LIMIT = true;\n uint256 internal constant MINT_MODULO = 1_000_000_000_000e18;\n\n // Known rounding errors\n uint256 internal constant TRANSFER_ROUNDING_ERROR = 1e18 - 1;\n uint256 internal constant OPT_IN_ROUNDING_ERROR = 1e18 - 1;\n uint256 internal constant MINT_ROUNDING_ERROR = 1e18 - 1;\n\n /**\n * @notice Modifier to skip tests that are known to fail\n * @dev see TOGGLE_KNOWN_ISSUES for more information\n */\n modifier hasKnownIssue() {\n if (TOGGLE_KNOWN_ISSUES) return;\n _;\n }\n\n /**\n * @notice Modifier to skip tests that are known to fail within limits\n * @dev see TOGGLE_KNOWN_ISSUES_WITHIN_LIMITS for more information\n */\n modifier hasKnownIssueWithinLimits() {\n if (TOGGLE_KNOWN_ISSUES_WITHIN_LIMITS) return;\n _;\n }\n\n /**\n * @notice Translate an account ID to an address\n * @param accountId The ID of the account\n * @return account The address of the account\n */\n function getAccount(uint8 accountId)\n internal\n view\n returns (address account)\n {\n accountId = accountId / 64;\n if (accountId == 0) return account = ADDRESS_USER0;\n if (accountId == 1) return account = ADDRESS_USER1;\n if (accountId == 2) return account = ADDRESS_CONTRACT0;\n if (accountId == 3) return account = ADDRESS_CONTRACT1;\n require(false, \"Unknown account ID\");\n }\n}\n" + }, + "contracts/echidna/EchidnaDebug.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { Address } from \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport \"./EchidnaHelper.sol\";\nimport \"./Debugger.sol\";\n\nimport \"../token/OUSD.sol\";\n\n/**\n * @title Room for random debugging functions\n * @author Rappie\n */\ncontract EchidnaDebug is EchidnaHelper {\n function debugOUSD() public pure {\n // assert(ousd.balanceOf(ADDRESS_USER0) == 1000);\n // assert(ousd.rebaseState(ADDRESS_USER0) != OUSD.RebaseOptions.OptIn);\n // assert(Address.isContract(ADDRESS_CONTRACT0));\n // Debugger.log(\"nonRebasingSupply\", ousd.nonRebasingSupply());\n // assert(false);\n }\n}\n" + }, + "contracts/echidna/EchidnaHelper.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./EchidnaSetup.sol\";\nimport \"./Debugger.sol\";\n\n/**\n * @title Mixin containing helper functions\n * @author Rappie\n */\ncontract EchidnaHelper is EchidnaSetup {\n /**\n * @notice Mint tokens to an account\n * @param toAcc Account to mint to\n * @param amount Amount to mint\n * @return Amount minted (in case of capped mint with modulo)\n */\n function mint(uint8 toAcc, uint256 amount) public returns (uint256) {\n address to = getAccount(toAcc);\n\n if (TOGGLE_MINT_LIMIT) {\n amount = amount % MINT_MODULO;\n }\n\n hevm.prank(ADDRESS_VAULT);\n ousd.mint(to, amount);\n\n return amount;\n }\n\n /**\n * @notice Burn tokens from an account\n * @param fromAcc Account to burn from\n * @param amount Amount to burn\n */\n function burn(uint8 fromAcc, uint256 amount) public {\n address from = getAccount(fromAcc);\n hevm.prank(ADDRESS_VAULT);\n ousd.burn(from, amount);\n }\n\n /**\n * @notice Change the total supply of OUSD (rebase)\n * @param amount New total supply\n */\n function changeSupply(uint256 amount) public {\n if (TOGGLE_CHANGESUPPLY_LIMIT) {\n amount =\n ousd.totalSupply() +\n (amount % (ousd.totalSupply() / CHANGESUPPLY_DIVISOR));\n }\n\n hevm.prank(ADDRESS_VAULT);\n ousd.changeSupply(amount);\n }\n\n /**\n * @notice Transfer tokens between accounts\n * @param fromAcc Account to transfer from\n * @param toAcc Account to transfer to\n * @param amount Amount to transfer\n */\n function transfer(\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public {\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n hevm.prank(from);\n // slither-disable-next-line unchecked-transfer\n ousd.transfer(to, amount);\n }\n\n /**\n * @notice Transfer approved tokens between accounts\n * @param authorizedAcc Account that is authorized to transfer\n * @param fromAcc Account to transfer from\n * @param toAcc Account to transfer to\n * @param amount Amount to transfer\n */\n function transferFrom(\n uint8 authorizedAcc,\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public {\n address authorized = getAccount(authorizedAcc);\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n hevm.prank(authorized);\n // slither-disable-next-line unchecked-transfer\n ousd.transferFrom(from, to, amount);\n }\n\n /**\n * @notice Opt in to rebasing\n * @param targetAcc Account to opt in\n */\n function optIn(uint8 targetAcc) public {\n address target = getAccount(targetAcc);\n hevm.prank(target);\n ousd.rebaseOptIn();\n }\n\n /**\n * @notice Opt out of rebasing\n * @param targetAcc Account to opt out\n */\n function optOut(uint8 targetAcc) public {\n address target = getAccount(targetAcc);\n hevm.prank(target);\n ousd.rebaseOptOut();\n }\n\n /**\n * @notice Approve an account to spend OUSD\n * @param ownerAcc Account that owns the OUSD\n * @param spenderAcc Account that is approved to spend the OUSD\n * @param amount Amount to approve\n */\n function approve(\n uint8 ownerAcc,\n uint8 spenderAcc,\n uint256 amount\n ) public {\n address owner = getAccount(ownerAcc);\n address spender = getAccount(spenderAcc);\n hevm.prank(owner);\n // slither-disable-next-line unused-return\n ousd.approve(spender, amount);\n }\n\n /**\n * @notice Increase the allowance of an account to spend OUSD\n * @param ownerAcc Account that owns the OUSD\n * @param spenderAcc Account that is approved to spend the OUSD\n * @param amount Amount to increase the allowance by\n */\n function increaseAllowance(\n uint8 ownerAcc,\n uint8 spenderAcc,\n uint256 amount\n ) public {\n address owner = getAccount(ownerAcc);\n address spender = getAccount(spenderAcc);\n hevm.prank(owner);\n // slither-disable-next-line unused-return\n ousd.increaseAllowance(spender, amount);\n }\n\n /**\n * @notice Decrease the allowance of an account to spend OUSD\n * @param ownerAcc Account that owns the OUSD\n * @param spenderAcc Account that is approved to spend the OUSD\n * @param amount Amount to decrease the allowance by\n */\n function decreaseAllowance(\n uint8 ownerAcc,\n uint8 spenderAcc,\n uint256 amount\n ) public {\n address owner = getAccount(ownerAcc);\n address spender = getAccount(spenderAcc);\n hevm.prank(owner);\n // slither-disable-next-line unused-return\n ousd.decreaseAllowance(spender, amount);\n }\n\n /**\n * @notice Get the sum of all OUSD balances\n * @return total Total balance\n */\n function getTotalBalance() public view returns (uint256 total) {\n total += ousd.balanceOf(ADDRESS_VAULT);\n total += ousd.balanceOf(ADDRESS_OUTSIDER_USER);\n total += ousd.balanceOf(ADDRESS_OUTSIDER_CONTRACT);\n total += ousd.balanceOf(ADDRESS_USER0);\n total += ousd.balanceOf(ADDRESS_USER1);\n total += ousd.balanceOf(ADDRESS_CONTRACT0);\n total += ousd.balanceOf(ADDRESS_CONTRACT1);\n }\n\n /**\n * @notice Get the sum of all non-rebasing OUSD balances\n * @return total Total balance\n */\n function getTotalNonRebasingBalance() public returns (uint256 total) {\n total += ousd._isNonRebasingAccountEchidna(ADDRESS_VAULT)\n ? ousd.balanceOf(ADDRESS_VAULT)\n : 0;\n total += ousd._isNonRebasingAccountEchidna(ADDRESS_OUTSIDER_USER)\n ? ousd.balanceOf(ADDRESS_OUTSIDER_USER)\n : 0;\n total += ousd._isNonRebasingAccountEchidna(ADDRESS_OUTSIDER_CONTRACT)\n ? ousd.balanceOf(ADDRESS_OUTSIDER_CONTRACT)\n : 0;\n total += ousd._isNonRebasingAccountEchidna(ADDRESS_USER0)\n ? ousd.balanceOf(ADDRESS_USER0)\n : 0;\n total += ousd._isNonRebasingAccountEchidna(ADDRESS_USER1)\n ? ousd.balanceOf(ADDRESS_USER1)\n : 0;\n total += ousd._isNonRebasingAccountEchidna(ADDRESS_CONTRACT0)\n ? ousd.balanceOf(ADDRESS_CONTRACT0)\n : 0;\n total += ousd._isNonRebasingAccountEchidna(ADDRESS_CONTRACT1)\n ? ousd.balanceOf(ADDRESS_CONTRACT1)\n : 0;\n }\n}\n" + }, + "contracts/echidna/EchidnaSetup.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./IHevm.sol\";\nimport \"./EchidnaConfig.sol\";\nimport \"./OUSDEchidna.sol\";\n\ncontract Dummy {}\n\n/**\n * @title Mixin for setup and deployment\n * @author Rappie\n */\ncontract EchidnaSetup is EchidnaConfig {\n IHevm hevm = IHevm(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D);\n OUSDEchidna ousd = new OUSDEchidna();\n\n /**\n * @notice Deploy the OUSD contract and set up initial state\n */\n constructor() {\n ousd.initialize(\"Origin Dollar\", \"OUSD\", ADDRESS_VAULT, 1e18);\n\n // Deploy dummny contracts as users\n Dummy outsider = new Dummy();\n ADDRESS_OUTSIDER_CONTRACT = address(outsider);\n Dummy dummy0 = new Dummy();\n ADDRESS_CONTRACT0 = address(dummy0);\n Dummy dummy1 = new Dummy();\n ADDRESS_CONTRACT1 = address(dummy1);\n\n // Start out with a reasonable amount of OUSD\n if (TOGGLE_STARTING_BALANCE) {\n // Rebasing tokens\n hevm.prank(ADDRESS_VAULT);\n ousd.mint(ADDRESS_OUTSIDER_USER, STARTING_BALANCE / 2);\n\n // Non-rebasing tokens\n hevm.prank(ADDRESS_VAULT);\n ousd.mint(ADDRESS_OUTSIDER_CONTRACT, STARTING_BALANCE / 2);\n }\n }\n}\n" + }, + "contracts/echidna/EchidnaTestAccounting.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./EchidnaDebug.sol\";\nimport \"./EchidnaTestSupply.sol\";\n\n/**\n * @title Mixin for testing accounting functions\n * @author Rappie\n */\ncontract EchidnaTestAccounting is EchidnaTestSupply {\n /**\n * @notice After opting in, balance should not increase. (Ok to lose rounding funds doing this)\n * @param targetAcc Account to opt in\n */\n function testOptInBalance(uint8 targetAcc) public {\n address target = getAccount(targetAcc);\n\n uint256 balanceBefore = ousd.balanceOf(target);\n optIn(targetAcc);\n uint256 balanceAfter = ousd.balanceOf(target);\n\n assert(balanceAfter <= balanceBefore);\n }\n\n /**\n * @notice After opting out, balance should remain the same\n * @param targetAcc Account to opt out\n */\n function testOptOutBalance(uint8 targetAcc) public {\n address target = getAccount(targetAcc);\n\n uint256 balanceBefore = ousd.balanceOf(target);\n optOut(targetAcc);\n uint256 balanceAfter = ousd.balanceOf(target);\n\n assert(balanceAfter == balanceBefore);\n }\n\n /**\n * @notice Account balance should remain the same after opting in minus rounding error\n * @param targetAcc Account to opt in\n */\n function testOptInBalanceRounding(uint8 targetAcc) public {\n address target = getAccount(targetAcc);\n\n uint256 balanceBefore = ousd.balanceOf(target);\n optIn(targetAcc);\n uint256 balanceAfter = ousd.balanceOf(target);\n\n int256 delta = int256(balanceAfter) - int256(balanceBefore);\n Debugger.log(\"delta\", delta);\n\n // slither-disable-next-line tautology\n assert(-1 * delta >= 0);\n assert(-1 * delta <= int256(OPT_IN_ROUNDING_ERROR));\n }\n\n /**\n * @notice After opting in, total supply should remain the same\n * @param targetAcc Account to opt in\n */\n function testOptInTotalSupply(uint8 targetAcc) public {\n uint256 totalSupplyBefore = ousd.totalSupply();\n optIn(targetAcc);\n uint256 totalSupplyAfter = ousd.totalSupply();\n\n assert(totalSupplyAfter == totalSupplyBefore);\n }\n\n /**\n * @notice After opting out, total supply should remain the same\n * @param targetAcc Account to opt out\n */\n function testOptOutTotalSupply(uint8 targetAcc) public {\n uint256 totalSupplyBefore = ousd.totalSupply();\n optOut(targetAcc);\n uint256 totalSupplyAfter = ousd.totalSupply();\n\n assert(totalSupplyAfter == totalSupplyBefore);\n }\n\n /**\n * @notice Account balance should remain the same when a smart contract auto converts\n * @param targetAcc Account to auto convert\n */\n function testAutoConvertBalance(uint8 targetAcc) public {\n address target = getAccount(targetAcc);\n\n uint256 balanceBefore = ousd.balanceOf(target);\n // slither-disable-next-line unused-return\n ousd._isNonRebasingAccountEchidna(target);\n uint256 balanceAfter = ousd.balanceOf(target);\n\n assert(balanceAfter == balanceBefore);\n }\n\n /**\n * @notice The `balanceOf` function should never revert\n * @param targetAcc Account to check balance of\n */\n function testBalanceOfShouldNotRevert(uint8 targetAcc) public {\n address target = getAccount(targetAcc);\n\n // slither-disable-next-line unused-return\n try ousd.balanceOf(target) {\n assert(true);\n } catch {\n assert(false);\n }\n }\n}\n" + }, + "contracts/echidna/EchidnaTestApproval.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./EchidnaTestMintBurn.sol\";\nimport \"./Debugger.sol\";\n\n/**\n * @title Mixin for testing approval related functions\n * @author Rappie\n */\ncontract EchidnaTestApproval is EchidnaTestMintBurn {\n /**\n * @notice Performing `transferFrom` with an amount inside the allowance should not revert\n * @param authorizedAcc The account that is authorized to transfer\n * @param fromAcc The account that is transferring\n * @param toAcc The account that is receiving\n * @param amount The amount to transfer\n */\n function testTransferFromShouldNotRevert(\n uint8 authorizedAcc,\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public {\n address authorized = getAccount(authorizedAcc);\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n\n require(amount <= ousd.balanceOf(from));\n require(amount <= ousd.allowance(from, authorized));\n\n hevm.prank(authorized);\n // slither-disable-next-line unchecked-transfer\n try ousd.transferFrom(from, to, amount) {\n // pass\n } catch {\n assert(false);\n }\n }\n\n /**\n * @notice Performing `transferFrom` with an amount outside the allowance should revert\n * @param authorizedAcc The account that is authorized to transfer\n * @param fromAcc The account that is transferring\n * @param toAcc The account that is receiving\n * @param amount The amount to transfer\n */\n function testTransferFromShouldRevert(\n uint8 authorizedAcc,\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public {\n address authorized = getAccount(authorizedAcc);\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n\n require(amount > 0);\n require(\n !(amount <= ousd.balanceOf(from) &&\n amount <= ousd.allowance(from, authorized))\n );\n\n hevm.prank(authorized);\n // slither-disable-next-line unchecked-transfer\n try ousd.transferFrom(from, to, amount) {\n assert(false);\n } catch {\n // pass\n }\n }\n\n /**\n * @notice Approving an amount should update the allowance and overwrite any previous allowance\n * @param ownerAcc The account that is approving\n * @param spenderAcc The account that is being approved\n * @param amount The amount to approve\n */\n function testApprove(\n uint8 ownerAcc,\n uint8 spenderAcc,\n uint256 amount\n ) public {\n address owner = getAccount(ownerAcc);\n address spender = getAccount(spenderAcc);\n\n approve(ownerAcc, spenderAcc, amount);\n uint256 allowanceAfter1 = ousd.allowance(owner, spender);\n\n assert(allowanceAfter1 == amount);\n\n approve(ownerAcc, spenderAcc, amount / 2);\n uint256 allowanceAfter2 = ousd.allowance(owner, spender);\n\n assert(allowanceAfter2 == amount / 2);\n }\n\n /**\n * @notice Increasing the allowance should raise it by the amount provided\n * @param ownerAcc The account that is approving\n * @param spenderAcc The account that is being approved\n * @param amount The amount to approve\n */\n function testIncreaseAllowance(\n uint8 ownerAcc,\n uint8 spenderAcc,\n uint256 amount\n ) public {\n address owner = getAccount(ownerAcc);\n address spender = getAccount(spenderAcc);\n\n uint256 allowanceBefore = ousd.allowance(owner, spender);\n increaseAllowance(ownerAcc, spenderAcc, amount);\n uint256 allowanceAfter = ousd.allowance(owner, spender);\n\n assert(allowanceAfter == allowanceBefore + amount);\n }\n\n /**\n * @notice Decreasing the allowance should lower it by the amount provided\n * @param ownerAcc The account that is approving\n * @param spenderAcc The account that is being approved\n * @param amount The amount to approve\n */\n function testDecreaseAllowance(\n uint8 ownerAcc,\n uint8 spenderAcc,\n uint256 amount\n ) public {\n address owner = getAccount(ownerAcc);\n address spender = getAccount(spenderAcc);\n\n uint256 allowanceBefore = ousd.allowance(owner, spender);\n decreaseAllowance(ownerAcc, spenderAcc, amount);\n uint256 allowanceAfter = ousd.allowance(owner, spender);\n\n assert(allowanceAfter == allowanceBefore - amount);\n }\n}\n" + }, + "contracts/echidna/EchidnaTestMintBurn.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./EchidnaDebug.sol\";\nimport \"./EchidnaTestAccounting.sol\";\n\n/**\n * @title Mixin for testing Mint and Burn functions\n * @author Rappie\n */\ncontract EchidnaTestMintBurn is EchidnaTestAccounting {\n /**\n * @notice Minting 0 tokens should not affect account balance\n * @param targetAcc Account to mint to\n */\n function testMintZeroBalance(uint8 targetAcc) public {\n address target = getAccount(targetAcc);\n\n uint256 balanceBefore = ousd.balanceOf(target);\n mint(targetAcc, 0);\n uint256 balanceAfter = ousd.balanceOf(target);\n\n assert(balanceAfter == balanceBefore);\n }\n\n /**\n * @notice Burning 0 tokens should not affect account balance\n * @param targetAcc Account to burn from\n */\n function testBurnZeroBalance(uint8 targetAcc) public {\n address target = getAccount(targetAcc);\n\n uint256 balanceBefore = ousd.balanceOf(target);\n burn(targetAcc, 0);\n uint256 balanceAfter = ousd.balanceOf(target);\n\n assert(balanceAfter == balanceBefore);\n }\n\n /**\n * @notice Minting tokens must increase the account balance by at least amount\n * @param targetAcc Account to mint to\n * @param amount Amount to mint\n * @custom:error testMintBalance(uint8,uint256): failed!💥\n * Call sequence:\n * changeSupply(1)\n * testMintBalance(0,1)\n * Event sequence:\n * Debug(«balanceBefore», 0)\n * Debug(«balanceAfter», 0)\n */\n function testMintBalance(uint8 targetAcc, uint256 amount)\n public\n hasKnownIssue\n hasKnownIssueWithinLimits\n {\n address target = getAccount(targetAcc);\n\n uint256 balanceBefore = ousd.balanceOf(target);\n uint256 amountMinted = mint(targetAcc, amount);\n uint256 balanceAfter = ousd.balanceOf(target);\n\n Debugger.log(\"amountMinted\", amountMinted);\n Debugger.log(\"balanceBefore\", balanceBefore);\n Debugger.log(\"balanceAfter\", balanceAfter);\n\n assert(balanceAfter >= balanceBefore + amountMinted);\n }\n\n /**\n * @notice Burning tokens must decrease the account balance by at least amount\n * @param targetAcc Account to burn from\n * @param amount Amount to burn\n * @custom:error testBurnBalance(uint8,uint256): failed!💥\n * Call sequence:\n * changeSupply(1)\n * mint(0,3)\n * testBurnBalance(0,1)\n * Event sequence:\n * Debug(«balanceBefore», 2)\n * Debug(«balanceAfter», 2)\n */\n function testBurnBalance(uint8 targetAcc, uint256 amount)\n public\n hasKnownIssue\n hasKnownIssueWithinLimits\n {\n address target = getAccount(targetAcc);\n\n uint256 balanceBefore = ousd.balanceOf(target);\n burn(targetAcc, amount);\n uint256 balanceAfter = ousd.balanceOf(target);\n\n Debugger.log(\"balanceBefore\", balanceBefore);\n Debugger.log(\"balanceAfter\", balanceAfter);\n\n assert(balanceAfter <= balanceBefore - amount);\n }\n\n /**\n * @notice Minting tokens should not increase the account balance by less than rounding error above amount\n * @param targetAcc Account to mint to\n * @param amount Amount to mint\n */\n function testMintBalanceRounding(uint8 targetAcc, uint256 amount) public {\n address target = getAccount(targetAcc);\n\n uint256 balanceBefore = ousd.balanceOf(target);\n uint256 amountMinted = mint(targetAcc, amount);\n uint256 balanceAfter = ousd.balanceOf(target);\n\n int256 delta = int256(balanceAfter) - int256(balanceBefore);\n\n // delta == amount, if no error\n // delta < amount, if too little is minted\n // delta > amount, if too much is minted\n int256 error = int256(amountMinted) - delta;\n\n assert(error >= 0);\n assert(error <= int256(MINT_ROUNDING_ERROR));\n }\n\n /**\n * @notice A burn of an account balance must result in a zero balance\n * @param targetAcc Account to burn from\n */\n function testBurnAllBalanceToZero(uint8 targetAcc) public hasKnownIssue {\n address target = getAccount(targetAcc);\n\n burn(targetAcc, ousd.balanceOf(target));\n assert(ousd.balanceOf(target) == 0);\n }\n\n /**\n * @notice You should always be able to burn an account's balance\n * @param targetAcc Account to burn from\n */\n function testBurnAllBalanceShouldNotRevert(uint8 targetAcc)\n public\n hasKnownIssue\n {\n address target = getAccount(targetAcc);\n uint256 balance = ousd.balanceOf(target);\n\n hevm.prank(ADDRESS_VAULT);\n try ousd.burn(target, balance) {\n assert(true);\n } catch {\n assert(false);\n }\n }\n}\n" + }, + "contracts/echidna/EchidnaTestSupply.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./EchidnaDebug.sol\";\nimport \"./EchidnaTestTransfer.sol\";\n\nimport { StableMath } from \"../utils/StableMath.sol\";\n\n/**\n * @title Mixin for testing supply related functions\n * @author Rappie\n */\ncontract EchidnaTestSupply is EchidnaTestTransfer {\n using StableMath for uint256;\n\n uint256 prevRebasingCreditsPerToken = type(uint256).max;\n\n /**\n * @notice After a `changeSupply`, the total supply should exactly\n * match the target total supply. (This is needed to ensure successive\n * rebases are correct).\n * @param supply New total supply\n * @custom:error testChangeSupply(uint256): failed!💥\n * Call sequence:\n * testChangeSupply(1044505275072865171609)\n * Event sequence:\n * TotalSupplyUpdatedHighres(1044505275072865171610, 1000000000000000000000000, 957391048054055578595)\n */\n function testChangeSupply(uint256 supply)\n public\n hasKnownIssue\n hasKnownIssueWithinLimits\n {\n hevm.prank(ADDRESS_VAULT);\n ousd.changeSupply(supply);\n\n assert(ousd.totalSupply() == supply);\n }\n\n /**\n * @notice The total supply must not be less than the sum of account balances.\n * (The difference will go into future rebases)\n * @custom:error testTotalSupplyLessThanTotalBalance(): failed!💥\n * Call sequence:\n * mint(0,1)\n * changeSupply(1)\n * optOut(64)\n * transfer(0,64,1)\n * testTotalSupplyLessThanTotalBalance()\n * Event sequence:\n * Debug(«totalSupply», 1000000000000000001000001)\n * Debug(«totalBalance», 1000000000000000001000002)\n */\n function testTotalSupplyLessThanTotalBalance()\n public\n hasKnownIssue\n hasKnownIssueWithinLimits\n {\n uint256 totalSupply = ousd.totalSupply();\n uint256 totalBalance = getTotalBalance();\n\n Debugger.log(\"totalSupply\", totalSupply);\n Debugger.log(\"totalBalance\", totalBalance);\n\n assert(totalSupply >= totalBalance);\n }\n\n /**\n * @notice Non-rebasing supply should not be larger than total supply\n * @custom:error testNonRebasingSupplyVsTotalSupply(): failed!💥\n * Call sequence:\n * mint(0,2)\n * changeSupply(3)\n * burn(0,1)\n * optOut(0)\n * testNonRebasingSupplyVsTotalSupply()\n */\n function testNonRebasingSupplyVsTotalSupply() public hasKnownIssue {\n uint256 nonRebasingSupply = ousd.nonRebasingSupply();\n uint256 totalSupply = ousd.totalSupply();\n\n assert(nonRebasingSupply <= totalSupply);\n }\n\n /**\n * @notice Global `rebasingCreditsPerToken` should never increase\n * @custom:error testRebasingCreditsPerTokenNotIncreased(): failed!💥\n * Call sequence:\n * testRebasingCreditsPerTokenNotIncreased()\n * changeSupply(1)\n * testRebasingCreditsPerTokenNotIncreased()\n */\n function testRebasingCreditsPerTokenNotIncreased() public hasKnownIssue {\n uint256 curRebasingCreditsPerToken = ousd\n .rebasingCreditsPerTokenHighres();\n\n Debugger.log(\n \"prevRebasingCreditsPerToken\",\n prevRebasingCreditsPerToken\n );\n Debugger.log(\"curRebasingCreditsPerToken\", curRebasingCreditsPerToken);\n\n assert(curRebasingCreditsPerToken <= prevRebasingCreditsPerToken);\n\n prevRebasingCreditsPerToken = curRebasingCreditsPerToken;\n }\n\n /**\n * @notice The rebasing credits per token ratio must greater than zero\n */\n function testRebasingCreditsPerTokenAboveZero() public {\n assert(ousd.rebasingCreditsPerTokenHighres() > 0);\n }\n\n /**\n * @notice The sum of all non-rebasing balances should not be larger than\n * non-rebasing supply\n * @custom:error testTotalNonRebasingSupplyLessThanTotalBalance(): failed!💥\n * Call sequence\n * mint(0,2)\n * changeSupply(1)\n * optOut(0)\n * burn(0,1)\n * testTotalNonRebasingSupplyLessThanTotalBalance()\n * Event sequence:\n * Debug(«totalNonRebasingSupply», 500000000000000000000001)\n * Debug(«totalNonRebasingBalance», 500000000000000000000002)\n */\n function testTotalNonRebasingSupplyLessThanTotalBalance()\n public\n hasKnownIssue\n hasKnownIssueWithinLimits\n {\n uint256 totalNonRebasingSupply = ousd.nonRebasingSupply();\n uint256 totalNonRebasingBalance = getTotalNonRebasingBalance();\n\n Debugger.log(\"totalNonRebasingSupply\", totalNonRebasingSupply);\n Debugger.log(\"totalNonRebasingBalance\", totalNonRebasingBalance);\n\n assert(totalNonRebasingSupply >= totalNonRebasingBalance);\n }\n\n /**\n * @notice An accounts credits / credits per token should not be larger it's balance\n * @param targetAcc The account to check\n */\n function testCreditsPerTokenVsBalance(uint8 targetAcc) public {\n address target = getAccount(targetAcc);\n\n (uint256 credits, uint256 creditsPerToken, ) = ousd\n .creditsBalanceOfHighres(target);\n uint256 expectedBalance = credits.divPrecisely(creditsPerToken);\n\n uint256 balance = ousd.balanceOf(target);\n\n Debugger.log(\"credits\", credits);\n Debugger.log(\"creditsPerToken\", creditsPerToken);\n Debugger.log(\"expectedBalance\", expectedBalance);\n Debugger.log(\"balance\", balance);\n\n assert(expectedBalance == balance);\n }\n}\n" + }, + "contracts/echidna/EchidnaTestTransfer.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./EchidnaDebug.sol\";\nimport \"./Debugger.sol\";\n\n/**\n * @title Mixin for testing transfer related functions\n * @author Rappie\n */\ncontract EchidnaTestTransfer is EchidnaDebug {\n /**\n * @notice The receiving account's balance after a transfer must not increase by\n * less than the amount transferred\n * @param fromAcc Account to transfer from\n * @param toAcc Account to transfer to\n * @param amount Amount to transfer\n * @custom:error testTransferBalanceReceivedLess(uint8,uint8,uint256): failed!💥\n * Call sequence:\n * changeSupply(1)\n * mint(64,2)\n * testTransferBalanceReceivedLess(64,0,1)\n * Event sequence:\n * Debug(«totalSupply», 1000000000000000000500002)\n * Debug(«toBalBefore», 0)\n * Debug(«toBalAfter», 0)\n */\n function testTransferBalanceReceivedLess(\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public hasKnownIssue hasKnownIssueWithinLimits {\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n\n require(from != to);\n\n uint256 toBalBefore = ousd.balanceOf(to);\n transfer(fromAcc, toAcc, amount);\n uint256 toBalAfter = ousd.balanceOf(to);\n\n Debugger.log(\"totalSupply\", ousd.totalSupply());\n Debugger.log(\"toBalBefore\", toBalBefore);\n Debugger.log(\"toBalAfter\", toBalAfter);\n\n assert(toBalAfter >= toBalBefore + amount);\n }\n\n /**\n * @notice The receiving account's balance after a transfer must not\n * increase by more than the amount transferred\n * @param fromAcc Account to transfer from\n * @param toAcc Account to transfer to\n * @param amount Amount to transfer\n */\n function testTransferBalanceReceivedMore(\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public {\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n\n require(from != to);\n\n uint256 toBalBefore = ousd.balanceOf(to);\n transfer(fromAcc, toAcc, amount);\n uint256 toBalAfter = ousd.balanceOf(to);\n\n Debugger.log(\"totalSupply\", ousd.totalSupply());\n Debugger.log(\"toBalBefore\", toBalBefore);\n Debugger.log(\"toBalAfter\", toBalAfter);\n\n assert(toBalAfter <= toBalBefore + amount);\n }\n\n /**\n * @notice The sending account's balance after a transfer must not\n * decrease by less than the amount transferred\n * @param fromAcc Account to transfer from\n * @param toAcc Account to transfer to\n * @param amount Amount to transfer\n * @custom:error testTransferBalanceSentLess(uint8,uint8,uint256): failed!💥\n * Call sequence:\n * mint(0,1)\n * changeSupply(1)\n * testTransferBalanceSentLess(0,64,1)\n * Event sequence:\n * Debug(«totalSupply», 1000000000000000000500001)\n * Debug(«fromBalBefore», 1)\n * Debug(«fromBalAfter», 1)\n */\n function testTransferBalanceSentLess(\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public hasKnownIssue hasKnownIssueWithinLimits {\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n\n require(from != to);\n\n uint256 fromBalBefore = ousd.balanceOf(from);\n transfer(fromAcc, toAcc, amount);\n uint256 fromBalAfter = ousd.balanceOf(from);\n\n Debugger.log(\"totalSupply\", ousd.totalSupply());\n Debugger.log(\"fromBalBefore\", fromBalBefore);\n Debugger.log(\"fromBalAfter\", fromBalAfter);\n\n assert(fromBalAfter <= fromBalBefore - amount);\n }\n\n /**\n * @notice The sending account's balance after a transfer must not\n * decrease by more than the amount transferred\n * @param fromAcc Account to transfer from\n * @param toAcc Account to transfer to\n * @param amount Amount to transfer\n */\n function testTransferBalanceSentMore(\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public {\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n\n require(from != to);\n\n uint256 fromBalBefore = ousd.balanceOf(from);\n transfer(fromAcc, toAcc, amount);\n uint256 fromBalAfter = ousd.balanceOf(from);\n\n Debugger.log(\"totalSupply\", ousd.totalSupply());\n Debugger.log(\"fromBalBefore\", fromBalBefore);\n Debugger.log(\"fromBalAfter\", fromBalAfter);\n\n assert(fromBalAfter >= fromBalBefore - amount);\n }\n\n /**\n * @notice The receiving account's balance after a transfer must not\n * increase by less than the amount transferred (minus rounding error)\n * @param fromAcc Account to transfer from\n * @param toAcc Account to transfer to\n * @param amount Amount to transfer\n */\n function testTransferBalanceReceivedLessRounding(\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public {\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n\n require(from != to);\n\n uint256 toBalBefore = ousd.balanceOf(to);\n transfer(fromAcc, toAcc, amount);\n uint256 toBalAfter = ousd.balanceOf(to);\n\n int256 toDelta = int256(toBalAfter) - int256(toBalBefore);\n\n // delta == amount, if no error\n // delta < amount, if too little is sent\n // delta > amount, if too much is sent\n int256 error = int256(amount) - toDelta;\n\n Debugger.log(\"totalSupply\", ousd.totalSupply());\n Debugger.log(\"toBalBefore\", toBalBefore);\n Debugger.log(\"toBalAfter\", toBalAfter);\n Debugger.log(\"toDelta\", toDelta);\n Debugger.log(\"error\", error);\n\n assert(error >= 0);\n assert(error <= int256(TRANSFER_ROUNDING_ERROR));\n }\n\n /**\n * @notice The sending account's balance after a transfer must\n * not decrease by less than the amount transferred (minus rounding error)\n * @param fromAcc Account to transfer from\n * @param toAcc Account to transfer to\n * @param amount Amount to transfer\n */\n function testTransferBalanceSentLessRounding(\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public {\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n\n require(from != to);\n\n uint256 fromBalBefore = ousd.balanceOf(from);\n transfer(fromAcc, toAcc, amount);\n uint256 fromBalAfter = ousd.balanceOf(from);\n\n int256 fromDelta = int256(fromBalAfter) - int256(fromBalBefore);\n\n // delta == -amount, if no error\n // delta < -amount, if too much is sent\n // delta > -amount, if too little is sent\n int256 error = int256(amount) + fromDelta;\n\n Debugger.log(\"totalSupply\", ousd.totalSupply());\n Debugger.log(\"fromBalBefore\", fromBalBefore);\n Debugger.log(\"fromBalAfter\", fromBalAfter);\n Debugger.log(\"fromDelta\", fromDelta);\n Debugger.log(\"error\", error);\n\n assert(error >= 0);\n assert(error <= int256(TRANSFER_ROUNDING_ERROR));\n }\n\n /**\n * @notice An account should always be able to successfully transfer\n * an amount within its balance.\n * @param fromAcc Account to transfer from\n * @param toAcc Account to transfer to\n * @param amount Amount to transfer\n * @custom:error testTransferWithinBalanceDoesNotRevert(uint8,uint8,uint8): failed!💥\n * Call sequence:\n * mint(0,1)\n * changeSupply(3)\n * optOut(0)\n * testTransferWithinBalanceDoesNotRevert(0,128,2)\n * optIn(0)\n * testTransferWithinBalanceDoesNotRevert(128,0,1)\n * Event sequence:\n * error Revert Panic(17): SafeMath over-/under-flows\n */\n function testTransferWithinBalanceDoesNotRevert(\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public hasKnownIssue {\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n\n require(amount > 0);\n amount = amount % ousd.balanceOf(from);\n\n Debugger.log(\"Total supply\", ousd.totalSupply());\n\n hevm.prank(from);\n // slither-disable-next-line unchecked-transfer\n try ousd.transfer(to, amount) {\n assert(true);\n } catch {\n assert(false);\n }\n }\n\n /**\n * @notice An account should never be able to successfully transfer\n * an amount greater than their balance.\n * @param fromAcc Account to transfer from\n * @param toAcc Account to transfer to\n * @param amount Amount to transfer\n */\n function testTransferExceedingBalanceReverts(\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public {\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n\n amount = ousd.balanceOf(from) + 1 + amount;\n\n hevm.prank(from);\n // slither-disable-next-line unchecked-transfer\n try ousd.transfer(to, amount) {\n assert(false);\n } catch {\n assert(true);\n }\n }\n\n /**\n * @notice A transfer to the same account should not change that account's balance\n * @param targetAcc Account to transfer to\n * @param amount Amount to transfer\n */\n function testTransferSelf(uint8 targetAcc, uint256 amount) public {\n address target = getAccount(targetAcc);\n\n uint256 balanceBefore = ousd.balanceOf(target);\n transfer(targetAcc, targetAcc, amount);\n uint256 balanceAfter = ousd.balanceOf(target);\n\n assert(balanceBefore == balanceAfter);\n }\n\n /**\n * @notice Transfers to the zero account revert\n * @param fromAcc Account to transfer from\n * @param amount Amount to transfer\n */\n function testTransferToZeroAddress(uint8 fromAcc, uint256 amount) public {\n address from = getAccount(fromAcc);\n\n hevm.prank(from);\n // slither-disable-next-line unchecked-transfer\n try ousd.transfer(address(0), amount) {\n assert(false);\n } catch {\n assert(true);\n }\n }\n}\n" + }, + "contracts/echidna/IHevm.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n// https://github.com/ethereum/hevm/blob/main/doc/src/controlling-the-unit-testing-environment.md#cheat-codes\n\ninterface IHevm {\n function warp(uint256 x) external;\n\n function roll(uint256 x) external;\n\n function store(\n address c,\n bytes32 loc,\n bytes32 val\n ) external;\n\n function load(address c, bytes32 loc) external returns (bytes32 val);\n\n function sign(uint256 sk, bytes32 digest)\n external\n returns (\n uint8 v,\n bytes32 r,\n bytes32 s\n );\n\n function addr(uint256 sk) external returns (address addr);\n\n function ffi(string[] calldata) external returns (bytes memory);\n\n function prank(address sender) external;\n}\n" + }, + "contracts/echidna/OUSDEchidna.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../token/OUSD.sol\";\n\ncontract OUSDEchidna is OUSD {\n constructor() OUSD() {}\n\n function _isNonRebasingAccountEchidna(address _account)\n public\n returns (bool)\n {\n return _isNonRebasingAccount(_account);\n }\n}\n" + }, + "contracts/flipper/Flipper.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../governance/Governable.sol\";\nimport \"../token/OUSD.sol\";\nimport \"../interfaces/Tether.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Contract to exchange usdt, usdc, dai from and to ousd.\n// - 1 to 1. No slippage\n// - Optimized for low gas usage\n// - No guarantee of availability\n\ncontract Flipper is Governable {\n using SafeERC20 for IERC20;\n\n uint256 constant MAXIMUM_PER_TRADE = (25000 * 1e18);\n\n // Settable coin addresses allow easy testing and use of mock currencies.\n IERC20 immutable dai;\n OUSD immutable ousd;\n IERC20 immutable usdc;\n Tether immutable usdt;\n\n // ---------------------\n // Dev constructor\n // ---------------------\n constructor(\n address _dai,\n address _ousd,\n address _usdc,\n address _usdt\n ) {\n require(address(_dai) != address(0));\n require(address(_ousd) != address(0));\n require(address(_usdc) != address(0));\n require(address(_usdt) != address(0));\n dai = IERC20(_dai);\n ousd = OUSD(_ousd);\n usdc = IERC20(_usdc);\n usdt = Tether(_usdt);\n }\n\n // -----------------\n // Trading functions\n // -----------------\n\n /// @notice Purchase OUSD with Dai\n /// @param amount Amount of OUSD to purchase, in 18 fixed decimals.\n function buyOusdWithDai(uint256 amount) external {\n require(amount <= MAXIMUM_PER_TRADE, \"Amount too large\");\n require(\n dai.transferFrom(msg.sender, address(this), amount),\n \"DAI transfer failed\"\n );\n require(ousd.transfer(msg.sender, amount), \"OUSD transfer failed\");\n }\n\n /// @notice Sell OUSD for Dai\n /// @param amount Amount of OUSD to sell, in 18 fixed decimals.\n function sellOusdForDai(uint256 amount) external {\n require(amount <= MAXIMUM_PER_TRADE, \"Amount too large\");\n require(dai.transfer(msg.sender, amount), \"DAI transfer failed\");\n require(\n ousd.transferFrom(msg.sender, address(this), amount),\n \"OUSD transfer failed\"\n );\n }\n\n /// @notice Purchase OUSD with USDC\n /// @param amount Amount of OUSD to purchase, in 18 fixed decimals.\n function buyOusdWithUsdc(uint256 amount) external {\n require(amount <= MAXIMUM_PER_TRADE, \"Amount too large\");\n // Potential rounding error is an intentional trade off\n require(\n usdc.transferFrom(msg.sender, address(this), amount / 1e12),\n \"USDC transfer failed\"\n );\n require(ousd.transfer(msg.sender, amount), \"OUSD transfer failed\");\n }\n\n /// @notice Sell OUSD for USDC\n /// @param amount Amount of OUSD to sell, in 18 fixed decimals.\n function sellOusdForUsdc(uint256 amount) external {\n require(amount <= MAXIMUM_PER_TRADE, \"Amount too large\");\n require(\n usdc.transfer(msg.sender, amount / 1e12),\n \"USDC transfer failed\"\n );\n require(\n ousd.transferFrom(msg.sender, address(this), amount),\n \"OUSD transfer failed\"\n );\n }\n\n /// @notice Purchase OUSD with USDT\n /// @param amount Amount of OUSD to purchase, in 18 fixed decimals.\n function buyOusdWithUsdt(uint256 amount) external {\n require(amount <= MAXIMUM_PER_TRADE, \"Amount too large\");\n // Potential rounding error is an intentional trade off\n // USDT does not return a boolean and reverts,\n // so no need for a require.\n usdt.transferFrom(msg.sender, address(this), amount / 1e12);\n require(ousd.transfer(msg.sender, amount), \"OUSD transfer failed\");\n }\n\n /// @notice Sell OUSD for USDT\n /// @param amount Amount of OUSD to sell, in 18 fixed decimals.\n function sellOusdForUsdt(uint256 amount) external {\n require(amount <= MAXIMUM_PER_TRADE, \"Amount too large\");\n // USDT does not return a boolean and reverts,\n // so no need for a require.\n usdt.transfer(msg.sender, amount / 1e12);\n require(\n ousd.transferFrom(msg.sender, address(this), amount),\n \"OUSD transfer failed\"\n );\n }\n\n // --------------------\n // Governance functions\n // --------------------\n\n /// @dev Opting into yield reduces the gas cost per transfer by about 4K, since\n /// ousd needs to do less accounting and one less storage write.\n function rebaseOptIn() external onlyGovernor nonReentrant {\n ousd.rebaseOptIn();\n }\n\n /// @notice Owner function to withdraw a specific amount of a token\n function withdraw(address token, uint256 amount)\n external\n onlyGovernor\n nonReentrant\n {\n IERC20(token).safeTransfer(_governor(), amount);\n }\n\n /// @notice Owner function to withdraw all tradable tokens\n /// @dev Contract will not perform any swaps until liquidity is provided\n /// again by transferring assets to the contract.\n function withdrawAll() external onlyGovernor nonReentrant {\n IERC20(dai).safeTransfer(_governor(), dai.balanceOf(address(this)));\n IERC20(ousd).safeTransfer(_governor(), ousd.balanceOf(address(this)));\n IERC20(address(usdt)).safeTransfer(\n _governor(),\n usdt.balanceOf(address(this))\n );\n IERC20(usdc).safeTransfer(_governor(), usdc.balanceOf(address(this)));\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/governance/Governor.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./../timelock/Timelock.sol\";\n\n// Modeled off of Compound's Governor Alpha\n// https://github.com/compound-finance/compound-protocol/blob/master/contracts/Governance/GovernorAlpha.sol\ncontract Governor is Timelock {\n // @notice The total number of proposals\n uint256 public proposalCount;\n\n struct Proposal {\n // @notice Unique id for looking up a proposal\n uint256 id;\n // @notice Creator of the proposal\n address proposer;\n // @notice The timestamp that the proposal will be available for\n // execution, set once the vote succeeds\n uint256 eta;\n // @notice the ordered list of target addresses for calls to be made\n address[] targets;\n // @notice The ordered list of function signatures to be called\n string[] signatures;\n // @notice The ordered list of calldata to be passed to each call\n bytes[] calldatas;\n // @notice Flag marking whether the proposal has been executed\n bool executed;\n }\n\n // @notice The official record of all proposals ever proposed\n mapping(uint256 => Proposal) public proposals;\n\n // @notice An event emitted when a new proposal is created\n event ProposalCreated(\n uint256 id,\n address proposer,\n address[] targets,\n string[] signatures,\n bytes[] calldatas,\n string description\n );\n\n // @notice An event emitted when a proposal has been queued in the Timelock\n event ProposalQueued(uint256 id, uint256 eta);\n\n // @notice An event emitted when a proposal has been executed in the Timelock\n event ProposalExecuted(uint256 id);\n\n // @notice An event emitted when a proposal has been cancelled\n event ProposalCancelled(uint256 id);\n\n uint256 public constant MAX_OPERATIONS = 32;\n\n // @notice Possible states that a proposal may be in\n enum ProposalState {\n Pending,\n Queued,\n Expired,\n Executed\n }\n\n constructor(address admin_, uint256 delay_) Timelock(admin_, delay_) {}\n\n /**\n * @notice Propose Governance call(s)\n * @param targets Ordered list of targeted addresses\n * @param signatures Orderd list of function signatures to be called\n * @param calldatas Orderded list of calldata to be passed with each call\n * @param description Description of the governance\n * @return uint256 id of the proposal\n */\n function propose(\n address[] memory targets,\n string[] memory signatures,\n bytes[] memory calldatas,\n string memory description\n ) public returns (uint256) {\n // Allow anyone to propose for now, since only admin can queue the\n // transaction it should be harmless, you just need to pay the gas\n require(\n targets.length == signatures.length &&\n targets.length == calldatas.length,\n \"Governor::propose: proposal function information arity mismatch\"\n );\n require(targets.length != 0, \"Governor::propose: must provide actions\");\n require(\n targets.length <= MAX_OPERATIONS,\n \"Governor::propose: too many actions\"\n );\n\n proposalCount++;\n Proposal memory newProposal = Proposal({\n id: proposalCount,\n proposer: msg.sender,\n eta: 0,\n targets: targets,\n signatures: signatures,\n calldatas: calldatas,\n executed: false\n });\n\n proposals[newProposal.id] = newProposal;\n\n emit ProposalCreated(\n newProposal.id,\n msg.sender,\n targets,\n signatures,\n calldatas,\n description\n );\n return newProposal.id;\n }\n\n /**\n * @notice Queue a proposal for execution\n * @param proposalId id of the proposal to queue\n */\n function queue(uint256 proposalId) public onlyAdmin {\n require(\n state(proposalId) == ProposalState.Pending,\n \"Governor::queue: proposal can only be queued if it is pending\"\n );\n Proposal storage proposal = proposals[proposalId];\n proposal.eta = block.timestamp + delay;\n\n for (uint256 i = 0; i < proposal.targets.length; i++) {\n _queueOrRevert(\n proposal.targets[i],\n proposal.signatures[i],\n proposal.calldatas[i],\n proposal.eta\n );\n }\n\n emit ProposalQueued(proposal.id, proposal.eta);\n }\n\n /**\n * @notice Get the state of a proposal\n * @param proposalId id of the proposal\n * @return ProposalState\n */\n function state(uint256 proposalId) public view returns (ProposalState) {\n require(\n proposalCount >= proposalId && proposalId > 0,\n \"Governor::state: invalid proposal id\"\n );\n Proposal storage proposal = proposals[proposalId];\n if (proposal.executed) {\n return ProposalState.Executed;\n } else if (proposal.eta == 0) {\n return ProposalState.Pending;\n } else if (block.timestamp >= proposal.eta + GRACE_PERIOD) {\n return ProposalState.Expired;\n } else {\n return ProposalState.Queued;\n }\n }\n\n function _queueOrRevert(\n address target,\n string memory signature,\n bytes memory data,\n uint256 eta\n ) internal {\n require(\n !queuedTransactions[\n keccak256(abi.encode(target, signature, keccak256(data), eta))\n ],\n \"Governor::_queueOrRevert: proposal action already queued at eta\"\n );\n require(\n queuedTransactions[queueTransaction(target, signature, data, eta)],\n \"Governor::_queueOrRevert: failed to queue transaction\"\n );\n }\n\n /**\n * @notice Execute a proposal.\n * @param proposalId id of the proposal\n */\n function execute(uint256 proposalId) public {\n require(\n state(proposalId) == ProposalState.Queued,\n \"Governor::execute: proposal can only be executed if it is queued\"\n );\n Proposal storage proposal = proposals[proposalId];\n proposal.executed = true;\n for (uint256 i = 0; i < proposal.targets.length; i++) {\n executeTransaction(\n proposal.targets[i],\n proposal.signatures[i],\n proposal.calldatas[i],\n proposal.eta\n );\n }\n emit ProposalExecuted(proposalId);\n }\n\n /**\n * @notice Cancel a proposal.\n * @param proposalId id of the proposal\n */\n function cancel(uint256 proposalId) public onlyAdmin {\n ProposalState proposalState = state(proposalId);\n\n require(\n proposalState == ProposalState.Queued ||\n proposalState == ProposalState.Pending,\n \"Governor::execute: proposal can only be cancelled if it is queued or pending\"\n );\n Proposal storage proposal = proposals[proposalId];\n proposal.eta = 1; // To mark the proposal as `Expired`\n for (uint256 i = 0; i < proposal.targets.length; i++) {\n cancelTransaction(\n proposal.targets[i],\n proposal.signatures[i],\n proposal.calldatas[i],\n proposal.eta\n );\n }\n emit ProposalCancelled(proposalId);\n }\n\n /**\n * @notice Get the actions that a proposal will take.\n * @param proposalId id of the proposal\n */\n function getActions(uint256 proposalId)\n public\n view\n returns (\n address[] memory targets,\n string[] memory signatures,\n bytes[] memory calldatas\n )\n {\n Proposal storage p = proposals[proposalId];\n return (p.targets, p.signatures, p.calldatas);\n }\n}\n" + }, + "contracts/governance/InitializableGovernable.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @title OUSD InitializableGovernable Contract\n * @author Origin Protocol Inc\n */\nimport { Initializable } from \"../utils/Initializable.sol\";\n\nimport { Governable } from \"./Governable.sol\";\n\ncontract InitializableGovernable is Governable, Initializable {\n function _initialize(address _newGovernor) internal {\n _changeGovernor(_newGovernor);\n }\n}\n" + }, + "contracts/governance/Strategizable.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { Governable } from \"./Governable.sol\";\n\ncontract Strategizable is Governable {\n event StrategistUpdated(address _address);\n\n // Address of strategist\n address public strategistAddr;\n\n // For future use\n uint256[50] private __gap;\n\n /**\n * @dev Verifies that the caller is either 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 * @dev Set address of Strategist\n * @param _address Address of Strategist\n */\n function setStrategistAddr(address _address) external onlyGovernor {\n _setStrategistAddr(_address);\n }\n\n /**\n * @dev Set address of Strategist\n * @param _address Address of Strategist\n */\n function _setStrategistAddr(address _address) internal {\n strategistAddr = _address;\n emit StrategistUpdated(_address);\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 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 uint256 balance = IERC20(_swapToken).balanceOf(address(this));\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 transfering `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 protcolYield = baseTokenBalance - farmerFee;\n\n baseToken.safeTransfer(rewardProceedsAddress, protcolYield);\n baseToken.safeTransfer(_rewardTo, farmerFee);\n emit RewardProceedsTransferred(\n baseTokenAddress,\n _rewardTo,\n protcolYield,\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/IOracleWeightedPool.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n// The three values that can be queried:\n//\n// - PAIR_PRICE: the price of the tokens in the Pool, expressed as the price of the second token in units of the\n// first token. For example, if token A is worth $2, and token B is worth $4, the pair price will be 2.0.\n// Note that the price is computed *including* the tokens decimals. This means that the pair price of a Pool with\n// DAI and USDC will be close to 1.0, despite DAI having 18 decimals and USDC 6.\n//\n// - BPT_PRICE: the price of the Pool share token (BPT), in units of the first token.\n// Note that the price is computed *including* the tokens decimals. This means that the BPT price of a Pool with\n// USDC in which BPT is worth $5 will be 5.0, despite the BPT having 18 decimals and USDC 6.\n//\n// - INVARIANT: the value of the Pool's invariant, which serves as a measure of its liquidity.\nenum Variable {\n PAIR_PRICE,\n BPT_PRICE,\n INVARIANT\n}\n\n/**\n * @dev Information for a Time Weighted Average query.\n *\n * Each query computes the average over a window of duration `secs` seconds that ended `ago` seconds ago. For\n * example, the average over the past 30 minutes is computed by settings secs to 1800 and ago to 0. If secs is 1800\n * and ago is 1800 as well, the average between 60 and 30 minutes ago is computed instead.\n */\nstruct OracleAverageQuery {\n Variable variable;\n uint256 secs;\n uint256 ago;\n}\n\ninterface IOracleWeightedPool {\n /**\n * @dev Returns the time average weighted price corresponding to each of `queries`. Prices are represented as 18\n * decimal fixed point values.\n */\n function getTimeWeightedAverage(OracleAverageQuery[] memory queries)\n external\n view\n returns (uint256[] memory results);\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/chainlink/AggregatorV3Interface.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface AggregatorV3Interface {\n function decimals() external view returns (uint8);\n\n function description() external view returns (string memory);\n\n function version() external view returns (uint256);\n\n // getRoundData and latestRoundData should both raise \"No data present\"\n // if they do not have data to report, instead of returning unset values\n // which could be misinterpreted as actual reported values.\n function getRoundData(uint80 _roundId)\n external\n view\n returns (\n uint80 roundId,\n int256 answer,\n uint256 startedAt,\n uint256 updatedAt,\n uint80 answeredInRound\n );\n\n function latestRoundData()\n external\n view\n returns (\n uint80 roundId,\n int256 answer,\n uint256 startedAt,\n uint256 updatedAt,\n uint80 answeredInRound\n );\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/IBuyback.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IBuyback {\n function swap() external;\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/ICVXLocker.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface ICVXLocker {\n function lock(\n address _account,\n uint256 _amount,\n uint256 _spendRatio\n ) external;\n\n function lockedBalanceOf(address _account) external view returns (uint256);\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}" + }, + "contracts/interfaces/IEthUsdOracle.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IEthUsdOracle {\n /**\n * @notice Returns ETH price in USD.\n * @return Price in USD with 6 decimal digits.\n */\n function ethUsdPrice() external view returns (uint256);\n\n /**\n * @notice Returns token price in USD.\n * @param symbol. Asset symbol. For ex. \"DAI\".\n * @return Price in USD with 6 decimal digits.\n */\n function tokUsdPrice(string calldata symbol)\n external\n view\n returns (uint256);\n\n /**\n * @notice Returns the asset price in ETH.\n * @param symbol. Asset symbol. For ex. \"DAI\".\n * @return Price in ETH with 8 decimal digits.\n */\n function tokEthPrice(string calldata symbol)\n external\n view\n returns (uint256);\n}\n\ninterface IViewEthUsdOracle {\n /**\n * @notice Returns ETH price in USD.\n * @return Price in USD with 6 decimal digits.\n */\n function ethUsdPrice() external view returns (uint256);\n\n /**\n * @notice Returns token price in USD.\n * @param symbol. Asset symbol. For ex. \"DAI\".\n * @return Price in USD with 6 decimal digits.\n */\n function tokUsdPrice(string calldata symbol)\n external\n view\n returns (uint256);\n\n /**\n * @notice Returns the asset price in ETH.\n * @param symbol. Asset symbol. For ex. \"DAI\".\n * @return Price in ETH with 8 decimal digits.\n */\n function tokEthPrice(string calldata symbol)\n external\n view\n returns (uint256);\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/IMinMaxOracle.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IMinMaxOracle {\n //Assuming 8 decimals\n function priceMin(string calldata symbol) external view returns (uint256);\n\n function priceMax(string calldata symbol) external view returns (uint256);\n}\n" + }, + "contracts/interfaces/IOneInch.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/// 1Inch swap data\nstruct SwapDescription {\n IERC20 srcToken; // contract address of a token to sell\n IERC20 dstToken; // contract address of a token to buy\n address payable srcReceiver;\n address payable dstReceiver; // Receiver of destination currency. default: fromAddress\n uint256 amount;\n uint256 minReturnAmount;\n uint256 flags;\n}\n\n/// @title Interface for making arbitrary calls during swap\ninterface IAggregationExecutor {\n /// @notice propagates information about original msg.sender and executes arbitrary data\n function execute(address msgSender) external payable; // 0x4b64e492\n}\n\ninterface IOneInchRouter {\n /// @notice Performs a swap, delegating all calls encoded in `data` to `executor`.\n function swap(\n IAggregationExecutor executor,\n SwapDescription calldata desc,\n bytes calldata permit,\n bytes calldata data\n ) external returns (uint256 returnAmount, uint256 spentAmount);\n\n /// @notice Performs swap using Uniswap exchange. Wraps and unwraps ETH if required.\n function unoswapTo(\n address payable recipient,\n IERC20 srcToken,\n uint256 amount,\n uint256 minReturn,\n uint256[] calldata pools\n ) external payable returns (uint256 returnAmount);\n\n /// @notice Performs swap using Uniswap V3 exchange. Wraps and unwraps ETH if required.\n function uniswapV3SwapTo(\n address payable recipient,\n uint256 amount,\n uint256 minReturn,\n uint256[] calldata pools\n ) external payable returns (uint256 returnAmount);\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/IPriceOracle.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IPriceOracle {\n /**\n * @dev returns the asset price in USD, 6 decimal digits.\n * Compatible with the Open Price Feed.\n */\n function price(string calldata symbol) external view returns (uint256);\n}\n" + }, + "contracts/interfaces/IRETH.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IRETH {\n function getEthValue(uint256 _rethAmount) external view returns (uint256);\n\n function getRethValue(uint256 _ethAmount) external view returns (uint256);\n\n function getExchangeRate() external view returns (uint256);\n\n function totalSupply() external view returns (uint256);\n\n function balanceOf(address account) external view returns (uint256);\n\n function transfer(address recipient, uint256 amount)\n external\n returns (bool);\n\n function allowance(address owner, address spender)\n external\n view\n returns (uint256);\n\n function approve(address spender, uint256 amount) external returns (bool);\n\n function transferFrom(\n address sender,\n address recipient,\n uint256 amount\n ) external returns (bool);\n\n function name() external view returns (string memory);\n\n function symbol() external view returns (string memory);\n\n function decimals() external view returns (uint8);\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 error ApprovalNotWithinTimeframe();\n error CallerNotOwner();\n error CallerNotWhitelisted();\n error ClusterAlreadyEnabled();\n error ClusterDoesNotExists();\n error ClusterIsLiquidated();\n error ClusterNotLiquidatable();\n error ExceedValidatorLimit();\n error FeeExceedsIncreaseLimit();\n error FeeIncreaseNotAllowed();\n error FeeTooHigh();\n error FeeTooLow();\n error IncorrectClusterState();\n error IncorrectValidatorState();\n error InsufficientBalance();\n error InvalidOperatorIdsLength();\n error InvalidPublicKeyLength();\n error MaxValueExceeded();\n error NewBlockPeriodIsBelowMinimum();\n error NoFeeDeclared();\n error NotAuthorized();\n error OperatorAlreadyExists();\n error OperatorDoesNotExist();\n error OperatorsListNotUnique();\n error SameFeeChangeNotAllowed();\n error TargetModuleDoesNotExist();\n error TokenTransferFailed();\n error UnsortedOperatorsList();\n error ValidatorAlreadyExists();\n error ValidatorDoesNotExist();\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 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 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 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/ITimelock.sol": { + "content": "pragma solidity ^0.8.0;\n\ninterface ITimelock {\n function delay() external view returns (uint256);\n\n function GRACE_PERIOD() external view returns (uint256);\n\n function acceptAdmin() external;\n\n function queuedTransactions(bytes32 hash) external view returns (bool);\n\n function queueTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) external returns (bytes32);\n\n function cancelTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) external;\n\n function executeTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) external payable returns (bytes memory);\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\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" + }, + "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/Tether.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface Tether {\n function transfer(address to, uint256 value) external;\n\n function transferFrom(\n address from,\n address to,\n uint256 value\n ) external;\n\n function balanceOf(address) external returns (uint256);\n}\n" + }, + "contracts/interfaces/uniswap/IUniswapUniversalRouter.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IUniswapUniversalRouter {\n /// @notice Executes encoded commands along with provided inputs. Reverts if deadline has expired.\n /// @param commands A set of concatenated commands, each 1 byte in length\n /// @param inputs An array of byte strings containing abi encoded inputs for each command\n /// @param deadline The deadline by which the transaction must be executed\n function execute(\n bytes calldata commands,\n bytes[] calldata inputs,\n uint256 deadline\n ) external payable;\n\n function execute(bytes calldata commands, bytes[] calldata inputs)\n external\n payable;\n}\n" + }, + "contracts/interfaces/uniswap/IUniswapV2Pair.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IUniswapV2Pair {\n function token0() external view returns (address);\n\n function token1() external view returns (address);\n\n function getReserves()\n external\n view\n returns (\n uint112 reserve0,\n uint112 reserve1,\n uint32 blockTimestampLast\n );\n\n function price0CumulativeLast() external view returns (uint256);\n\n function price1CumulativeLast() external view returns (uint256);\n\n function sync() external;\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/liquidity/LiquidityReward.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { SafeMath } from \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\n\nimport { Initializable } from \"../utils/Initializable.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\nimport { Governable } from \"../governance/Governable.sol\";\n\n//\n// LiquidityReward contract doles out reward for liquidity\n// base off of Sushiswap's MasterChef: https://github.com/sushiswap/sushiswap/blob/master/contracts/MasterChef.sol\n//\ncontract LiquidityReward is Initializable, Governable {\n using SafeMath for uint256;\n using StableMath for uint256;\n using SafeERC20 for IERC20;\n\n // Info of each user.\n struct UserInfo {\n uint256 amount; // How many LP tokens the user has provided.\n int256 rewardDebt; // Reward debt. See explanation below.\n //\n // We do some fancy math here. Basically, any point in time, the amount of Reward Tokens\n // entitled to a user but is pending to be distributed is:\n //\n // pending reward = (user.amount * pool.accRewardPerShare) - user.rewardDebt\n //\n // Whenever a user deposits or withdraws LP tokens to a pool. Here's what happens:\n // 1. The pool's `accRewardPerShare` (and `lastRewardBlock`) gets updated.\n // 2. User receives the pending reward sent to his/her address.\n // 3. User's `amount` gets updated.\n // 4. User's `rewardDebt` gets updated.\n //\n // NOTE: rewardDebt can go negative because we allow withdraws without claiming the reward\n // in that case we owe the account holder some reward.\n }\n\n // Info of each pool.\n struct PoolInfo {\n IERC20 lpToken; // Address of LP token contract.\n uint256 lastRewardBlock; // Last block number that Reward calculation occurs.\n uint256 accRewardPerShare; // Accumulated Reward per share in reward precision. See below.\n }\n\n // The Reward token\n IERC20 public reward;\n\n // Reward tokens created per block in 1e18 precision.\n uint256 public rewardPerBlock;\n\n // Info on the LP.\n PoolInfo public pool;\n // total Reward debt, useful to calculate if we have enough to pay out all rewards\n int256 public totalRewardDebt;\n // total Supply that is accounted for via deposit/withdraw so that our rewards calc are stable\n uint256 public totalSupply;\n // Info of each user that stakes LP tokens.\n mapping(address => UserInfo) public userInfo;\n // The block number when Liquidity rewards ends.\n uint256 public endBlock;\n\n event CampaignStarted(\n uint256 rewardRate,\n uint256 startBlock,\n uint256 endBlock\n );\n event CampaignStopped(uint256 endBlock);\n event Deposit(address indexed user, uint256 amount);\n event Withdraw(address indexed user, uint256 amount);\n event Claim(address indexed user, uint256 amount);\n event DrainExtraReward(address indexed user, uint256 amount);\n event DrainExtraLP(address indexed user, uint256 amount);\n\n /**\n * Initializer for setting up Liquidity Reward internal state.\n * @param _reward Address of the reward token(OGN)\n * @param _lpToken Address of the LP token(Uniswap Pair)\n */\n function initialize(IERC20 _reward, IERC20 _lpToken)\n external\n onlyGovernor\n initializer\n {\n reward = _reward;\n pool.lpToken = _lpToken;\n pool.lastRewardBlock = block.number;\n }\n\n /**\n * @dev start a new reward campaign.\n * This will calculate all rewards up to the current block at the old rate.\n * This ensures that we pay everyone at the promised rate before update to the new rate.\n * @param _rewardPerBlock Amount rewarded per block\n * @param _startBlock Block number that we want to start the rewards at (0 for current block)\n * @param _numBlocks number of blocks that the campaign should last\n */\n function startCampaign(\n uint256 _rewardPerBlock,\n uint256 _startBlock,\n uint256 _numBlocks\n ) external onlyGovernor {\n // Calculate up to the current block at the current rate for everyone.\n updatePool();\n\n // total Pending calculated at the current pool rate\n uint256 totalPending = subDebt(\n pool.accRewardPerShare.mulTruncate(totalSupply),\n totalRewardDebt\n );\n\n require(_numBlocks > 0, \"startCampaign: zero blocks\");\n\n require(\n reward.balanceOf(address(this)) >=\n _rewardPerBlock.mul(_numBlocks).add(totalPending),\n \"startCampaign: insufficient rewards\"\n );\n\n uint256 startBlock = _startBlock;\n if (startBlock == 0) {\n // start block number isn't given so we start at the current\n startBlock = block.number;\n }\n require(\n startBlock >= block.number,\n \"startCampaign: _startBlock can't be in the past\"\n );\n endBlock = startBlock.add(_numBlocks);\n // we don't start accrue until the startBlock\n pool.lastRewardBlock = startBlock;\n // new blocks start at the new reward rate\n rewardPerBlock = _rewardPerBlock;\n emit CampaignStarted(rewardPerBlock, startBlock, endBlock);\n }\n\n function stopCampaign() external onlyGovernor {\n //calculate until current pool\n updatePool();\n //end the block here (the CampaignMultiplier will be zero)\n endBlock = block.number;\n emit CampaignStopped(endBlock);\n }\n\n function drainExtraRewards() external onlyGovernor {\n require(endBlock < block.number, \"drainExtraRewards:Campaign active\");\n updatePool();\n uint256 extraRewards = reward.balanceOf(address(this)).sub(\n subDebt(\n pool.accRewardPerShare.mulTruncate(totalSupply),\n totalRewardDebt\n )\n );\n if (extraRewards > 0) {\n emit DrainExtraReward(msg.sender, extraRewards);\n reward.safeTransfer(msg.sender, extraRewards);\n }\n }\n\n function drainExtraLP() external onlyGovernor {\n uint256 extraLP = pool.lpToken.balanceOf(address(this)).sub(\n totalSupply\n );\n require(extraLP > 0, \"drainExtraLP:no extra\");\n emit DrainExtraLP(msg.sender, extraLP);\n pool.lpToken.safeTransfer(msg.sender, extraLP);\n }\n\n function campaignActive() external view returns (bool) {\n return endBlock > block.number && block.number >= pool.lastRewardBlock;\n }\n\n function balanceOf(address _account) external view returns (uint256) {\n return userInfo[_account].amount;\n }\n\n /**\n * @dev calculate the number of blocks since we last updated\n * within start and end as constraints\n * @param _to Block number of the ending point.\n * @return multiplier Multiplier over the given _from to _to block.\n */\n function getCampaignMultiplier(uint256 _to)\n internal\n view\n returns (uint256)\n {\n uint256 from = pool.lastRewardBlock;\n if (from > endBlock) {\n return 0;\n } else {\n return (_to < endBlock ? _to : endBlock).sub(from);\n }\n }\n\n /**\n * @dev View function to see pending rewards for each account on frontend.\n * @param _user Address of the account we're looking up.\n * @return reward Total rewards owed to this account.\n */\n function pendingRewards(address _user) external view returns (uint256) {\n UserInfo storage user = userInfo[_user];\n return _pendingRewards(user);\n }\n\n function _pendingRewards(UserInfo storage user)\n internal\n view\n returns (uint256)\n {\n uint256 accRewardPerShare = pool.accRewardPerShare;\n if (block.number > pool.lastRewardBlock) {\n if (totalSupply != 0) {\n uint256 multiplier = getCampaignMultiplier(block.number);\n uint256 incReward = multiplier.mul(rewardPerBlock);\n accRewardPerShare = accRewardPerShare.add(\n incReward.divPrecisely(totalSupply)\n );\n }\n }\n return\n subDebt(\n user.amount.mulTruncate(accRewardPerShare),\n user.rewardDebt\n );\n }\n\n /**\n * @dev View function to see total outstanding rewards for the entire contract.\n * This is how much is owed when everyone pulls out.\n * @return reward Total rewards owed to everyone.\n */\n function totalOutstandingRewards() external view returns (uint256) {\n if (block.number > pool.lastRewardBlock && totalSupply != 0) {\n uint256 multiplier = getCampaignMultiplier(block.number);\n uint256 incReward = multiplier.mul(rewardPerBlock);\n uint256 accRewardPerShare = pool.accRewardPerShare;\n accRewardPerShare = accRewardPerShare.add(\n incReward.divPrecisely(totalSupply)\n );\n return\n subDebt(\n accRewardPerShare.mulTruncate(totalSupply),\n totalRewardDebt\n );\n }\n // no supply or not even started\n return 0;\n }\n\n /**\n * @dev External call for updating the pool.\n */\n function doUpdatePool() external {\n // There should be no harm allowing anyone to call this function.\n // It just updates the latest accRewardPerShare for the pool.\n updatePool();\n }\n\n /**\n * @dev Update the Liquidity Pool reward multiplier.\n * This locks in the accRewardPerShare from the last update block number to now.\n * Will fail if we do not have enough to pay everyone.\n * Always call updatePool whenever the balance changes!\n */\n function updatePool() internal {\n if (\n block.number <= pool.lastRewardBlock ||\n endBlock <= pool.lastRewardBlock\n ) {\n return;\n }\n\n if (totalSupply == 0) {\n pool.lastRewardBlock = block.number;\n return;\n }\n\n uint256 incReward = getCampaignMultiplier(block.number).mul(\n rewardPerBlock\n );\n // we are of course assuming lpTokens are in 1e18 precision\n uint256 accRewardPerShare = pool.accRewardPerShare.add(\n incReward.divPrecisely(totalSupply)\n );\n\n pool.accRewardPerShare = accRewardPerShare;\n pool.lastRewardBlock = block.number;\n }\n\n /**\n * @dev Deposit LP tokens into contract, must be preapproved.\n * @param _amount Amount of LPToken to deposit.\n */\n function deposit(uint256 _amount) external {\n UserInfo storage user = userInfo[msg.sender];\n updatePool();\n if (_amount > 0) {\n user.amount = user.amount.add(_amount);\n // newDebt is equal to the change in amount * accRewardPerShare (note accRewardPerShare is historic)\n int256 newDebt = int256(\n _amount.mulTruncate(pool.accRewardPerShare)\n );\n user.rewardDebt += newDebt;\n totalRewardDebt += newDebt;\n totalSupply = totalSupply.add(_amount);\n emit Deposit(msg.sender, _amount);\n pool.lpToken.safeTransferFrom(\n address(msg.sender),\n address(this),\n _amount\n );\n }\n }\n\n /**\n * @dev Exit out of the contract completely, withdraw LP tokens and claim rewards\n */\n function exit() external {\n UserInfo storage user = userInfo[msg.sender];\n // withdraw everything\n _withdraw(user, user.amount, true);\n }\n\n /**\n * @dev Withdraw LP tokens from contract.\n * @param _amount Amount of LPToken to withdraw.\n * @param _claim Boolean do we want to claim our rewards or not\n */\n function withdraw(uint256 _amount, bool _claim) external {\n UserInfo storage user = userInfo[msg.sender];\n _withdraw(user, _amount, _claim);\n }\n\n function _withdraw(\n UserInfo storage user,\n uint256 _amount,\n bool _claim\n ) internal {\n require(user.amount >= _amount, \"withdraw: overflow\");\n updatePool();\n\n // newDebt is equal to the change in amount * accRewardPerShare (note accRewardPerShare is historic)\n int256 newDebt = -int256(_amount.mulTruncate(pool.accRewardPerShare));\n uint256 pending = 0;\n if (_claim) {\n //This is an optimization so we don't modify the storage variable twice\n pending = subDebt(\n user.amount.mulTruncate(pool.accRewardPerShare),\n user.rewardDebt\n );\n\n newDebt += int256(pending);\n }\n\n user.rewardDebt += newDebt;\n totalRewardDebt += newDebt;\n emit Withdraw(msg.sender, _amount);\n // actually make the changes to the amount and debt\n if (_amount > 0) {\n user.amount = user.amount.sub(_amount);\n totalSupply = totalSupply.sub(_amount, \"withdraw: total overflow\");\n }\n //putting this all at the end to avoid reentrancy error\n if (pending > 0) {\n emit Claim(msg.sender, pending);\n reward.safeTransfer(msg.sender, pending);\n }\n if (_amount > 0) {\n pool.lpToken.safeTransfer(address(msg.sender), _amount);\n }\n }\n\n /**\n * @dev Claim all pending rewards up to current block\n */\n function claim() external {\n UserInfo storage user = userInfo[msg.sender];\n uint256 pending = _pendingRewards(user);\n if (pending > 0) {\n emit Claim(msg.sender, pending);\n int256 debtDelta = int256(pending);\n user.rewardDebt += debtDelta;\n totalRewardDebt += debtDelta;\n reward.safeTransfer(msg.sender, pending);\n }\n }\n\n function subDebt(uint256 amount, int256 debt)\n internal\n pure\n returns (uint256 result)\n {\n if (debt < 0) {\n result = amount.add(uint256(-debt));\n } else {\n result = amount.sub(uint256(debt));\n }\n }\n}\n" + }, + "contracts/mocks/BeaconChainDepositContractMock.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ncontract BeaconChainDepositContractMock {\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 // Extended ABI length checks since dynamic types are used.\n require(pubkey.length == 48, \"DepositContract: invalid pubkey length\");\n require(withdrawal_credentials.length == 32, \"DepositContract: invalid withdrawal_credentials length\");\n require(signature.length == 96, \"DepositContract: invalid signature length\");\n\n // Check deposit amount\n require(msg.value >= 1 ether, \"DepositContract: deposit value too low\");\n require(msg.value % 1 gwei == 0, \"DepositContract: deposit value not multiple of gwei\");\n uint deposit_amount = msg.value / 1 gwei;\n require(deposit_amount <= type(uint64).max, \"DepositContract: deposit value too high\");\n }\n}" + }, + "contracts/mocks/BurnableERC20.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { ERC20 } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ninterface IBurnableERC20 {\n function burn(uint256 value) external returns (bool);\n\n function burnFrom(address account, uint256 value) external returns (bool);\n}\n\n/**\n * @title BurnableERC20\n * @dev Exposes the burn function of ERC20 for tests\n */\nabstract contract BurnableERC20 is IBurnableERC20, ERC20 {\n /**\n * @dev Function to burn tokens\n * @param value The amount of tokens to burn.\n * @return A boolean that indicates if the operation was successful.\n */\n function burn(uint256 value) public virtual override returns (bool) {\n _burn(msg.sender, value);\n return true;\n }\n\n /**\n * @dev Function to burn tokens from a specific account\n * @param account The address with the tokens to burn.\n * @param value The amount of tokens to burn.\n * @return A boolean that indicates if the operation was successful.\n */\n function burnFrom(address account, uint256 value)\n public\n override\n returns (bool)\n {\n _burn(account, value);\n return true;\n }\n}\n" + }, + "contracts/mocks/curve/Mock3CRV.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { ERC20, MintableERC20 } from \"../MintableERC20.sol\";\nimport { BurnableERC20 } from \"../BurnableERC20.sol\";\n\ncontract Mock3CRV is MintableERC20, BurnableERC20 {\n constructor() ERC20(\"Curve.fi DAI/USDC/USDT\", \"3Crv\") {}\n\n function decimals() public pure override returns (uint8) {\n return 18;\n }\n}\n" + }, + "contracts/mocks/curve/MockBooster.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 { MockRewardPool } from \"./MockRewardPool.sol\";\n\nimport { IRewardStaking } from \"../../strategies/IRewardStaking.sol\";\nimport { IMintableERC20, MintableERC20, ERC20 } from \"../MintableERC20.sol\";\nimport { IBurnableERC20, BurnableERC20 } from \"../BurnableERC20.sol\";\n\ncontract MockDepositToken is MintableERC20, BurnableERC20 {\n constructor() ERC20(\"DCVX\", \"CVX Deposit Token\") {}\n}\n\ncontract MockBooster {\n using SafeERC20 for IERC20;\n\n struct PoolInfo {\n address lptoken;\n address token;\n address crvRewards;\n }\n\n address public minter; // this is CVx for the booster on live\n address public crv; // Curve rewards token\n address public cvx; // Convex rewards token\n mapping(uint256 => PoolInfo) public poolInfo;\n\n constructor(\n address _rewardsMinter,\n address _crv,\n address _cvx\n ) public {\n minter = _rewardsMinter;\n crv = _crv;\n cvx = _cvx;\n }\n\n function setPool(uint256 pid, address _lpToken)\n external\n returns (address rewards)\n {\n address token = address(new MockDepositToken());\n // Deploy a new Convex Rewards Pool\n rewards = address(\n new MockRewardPool(pid, token, crv, cvx, address(this))\n );\n\n poolInfo[pid] = PoolInfo({\n lptoken: _lpToken,\n token: token,\n crvRewards: rewards\n });\n }\n\n function deposit(\n uint256 _pid,\n uint256 _amount,\n bool _stake\n ) public returns (bool) {\n PoolInfo storage pool = poolInfo[_pid];\n\n address lptoken = pool.lptoken;\n\n // hold on to the Curve LP tokens\n IERC20(lptoken).safeTransferFrom(msg.sender, address(this), _amount);\n\n address token = pool.token;\n if (_stake) {\n // mint Convex pool LP tokens and stake in rewards contract on user behalf\n IMintableERC20(token).mint(_amount);\n address rewardContract = pool.crvRewards;\n IERC20(token).safeApprove(rewardContract, 0);\n IERC20(token).safeApprove(rewardContract, _amount);\n IRewardStaking(rewardContract).stakeFor(msg.sender, _amount);\n } else {\n // mint Convex pool LP tokens and send to user\n IMintableERC20(token).mint(_amount);\n IERC20(token).transfer(msg.sender, _amount);\n }\n return true;\n }\n\n // Deposit all Curve LP tokens and stake\n function depositAll(uint256 _pid, bool _stake) external returns (bool) {\n address lptoken = poolInfo[_pid].lptoken;\n uint256 balance = IERC20(lptoken).balanceOf(msg.sender);\n deposit(_pid, balance, _stake);\n return true;\n }\n\n // withdraw Curve LP tokens\n function _withdraw(\n uint256 _pid,\n uint256 _amount,\n address _from,\n address _to\n ) internal {\n PoolInfo storage pool = poolInfo[_pid];\n\n // burn the Convex pool LP tokens\n IBurnableERC20(pool.token).burnFrom(_from, _amount);\n\n // return the Curve LP tokens\n IERC20(pool.lptoken).safeTransfer(_to, _amount);\n }\n\n // withdraw Curve LP tokens\n function withdraw(uint256 _pid, uint256 _amount) public returns (bool) {\n _withdraw(_pid, _amount, msg.sender, msg.sender);\n return true;\n }\n\n // withdraw all Curve LP tokens\n function withdrawAll(uint256 _pid) public returns (bool) {\n address token = poolInfo[_pid].token;\n uint256 userBal = IERC20(token).balanceOf(msg.sender);\n withdraw(_pid, userBal);\n return true;\n }\n\n // allow reward contracts to send here and withdraw to user\n function withdrawTo(\n uint256 _pid,\n uint256 _amount,\n address _to\n ) external returns (bool) {\n address rewardContract = poolInfo[_pid].crvRewards;\n require(msg.sender == rewardContract, \"!auth\");\n\n _withdraw(_pid, _amount, msg.sender, _to);\n return true;\n }\n\n // callback from reward contract when crv is received.\n function rewardClaimed(\n uint256 _pid,\n // solhint-disable-next-line no-unused-vars\n address _address,\n uint256 _amount\n ) external returns (bool) {\n address rewardContract = poolInfo[_pid].crvRewards;\n require(msg.sender == rewardContract, \"!auth\");\n\n //mint reward tokens\n // and transfer it\n IMintableERC20(minter).mint(_amount);\n IERC20(minter).transfer(msg.sender, _amount);\n return true;\n }\n}\n" + }, + "contracts/mocks/curve/MockCRV.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../MintableERC20.sol\";\n\ncontract MockCRV is MintableERC20 {\n constructor() ERC20(\"Curve DAO Token\", \"CRV\") {}\n\n function decimals() public pure override returns (uint8) {\n return 18;\n }\n}\n" + }, + "contracts/mocks/curve/MockCRVMinter.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\nimport { IMintableERC20 } from \"../MintableERC20.sol\";\n\ncontract MockCRVMinter {\n address crv;\n\n constructor(address _crv) {\n crv = _crv;\n }\n\n function mint(address _address) external {\n uint256 amount = 2e18;\n IMintableERC20(crv).mint(amount);\n IERC20(crv).transfer(_address, amount);\n }\n}\n" + }, + "contracts/mocks/curve/MockCurveAbstractMetapool.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\nimport { MintableERC20, IMintableERC20 } from \"../MintableERC20.sol\";\nimport { StableMath } from \"../../utils/StableMath.sol\";\nimport \"../../utils/Helpers.sol\";\n\nabstract contract MockCurveAbstractMetapool is MintableERC20 {\n using StableMath for uint256;\n\n address[] public coins;\n uint256[2] public balances;\n\n // Returns the same amount of LP tokens in 1e18 decimals\n function add_liquidity(uint256[2] calldata _amounts, uint256 _minAmount)\n external\n returns (uint256 lpAmount)\n {\n for (uint256 i = 0; i < _amounts.length; i++) {\n if (_amounts[i] > 0) {\n IERC20(coins[i]).transferFrom(\n msg.sender,\n address(this),\n _amounts[i]\n );\n uint256 assetDecimals = Helpers.getDecimals(coins[i]);\n // Convert to 1e18 and add to sum\n lpAmount += _amounts[i].scaleBy(18, assetDecimals);\n balances[i] = balances[i] + _amounts[i];\n }\n }\n // Hacky way of simulating slippage to check _minAmount\n if (lpAmount == 29000e18) lpAmount = 14500e18;\n require(lpAmount >= _minAmount, \"Slippage ruined your day\");\n // Send LP token to sender, e.g. 3CRV\n _mint(msg.sender, lpAmount);\n }\n\n // Dumb implementation that returns the same amount\n function calc_withdraw_one_coin(uint256 _amount, int128 _index)\n public\n view\n returns (uint256 lpAmount)\n {\n uint256 assetDecimals = Helpers.getDecimals(coins[uint128(_index)]);\n lpAmount = _amount.scaleBy(assetDecimals, 18);\n }\n\n function remove_liquidity_one_coin(\n uint256 _lpAmount,\n int128 _index,\n // solhint-disable-next-line no-unused-vars\n uint256 _minAmount\n ) external returns (uint256 amount) {\n _burn(msg.sender, _lpAmount);\n uint256[] memory amounts = new uint256[](coins.length);\n amounts[uint128(_index)] = _lpAmount;\n amount = calc_withdraw_one_coin(_lpAmount, _index);\n balances[uint128(_index)] -= amount;\n IERC20(coins[uint128(_index)]).transfer(msg.sender, amount);\n }\n\n function get_virtual_price() external pure returns (uint256) {\n return 1e18;\n }\n\n // solhint-disable-next-line no-unused-vars\n function remove_liquidity(uint256 _amount, uint256[2] memory _min_amounts)\n public\n returns (uint256[2] memory amounts)\n {\n _burn(msg.sender, _amount);\n uint256 totalSupply = totalSupply();\n for (uint256 i = 0; i < 2; i++) {\n amounts[i] = totalSupply > 0\n ? (_amount * IERC20(coins[i]).balanceOf(address(this))) /\n totalSupply\n : IERC20(coins[i]).balanceOf(address(this));\n balances[i] -= amounts[i];\n IERC20(coins[i]).transfer(msg.sender, amounts[i]);\n }\n }\n\n function remove_liquidity_imbalance(\n uint256[2] memory _amounts,\n uint256 _max_burned_tokens\n ) public returns (uint256) {\n return\n _remove_liquidity_imbalance(\n _amounts,\n _max_burned_tokens,\n msg.sender\n );\n }\n\n function remove_liquidity_imbalance(\n uint256[2] memory _amounts,\n uint256 _max_burned_tokens,\n address _reveiver\n ) public returns (uint256) {\n return\n _remove_liquidity_imbalance(\n _amounts,\n _max_burned_tokens,\n _reveiver\n );\n }\n\n function _remove_liquidity_imbalance(\n uint256[2] memory _amounts,\n uint256 _max_burned_tokens,\n address _reveiver\n ) internal returns (uint256 lpTokens) {\n lpTokens = _max_burned_tokens;\n _burn(msg.sender, lpTokens);\n for (uint256 i = 0; i < _amounts.length; i++) {\n balances[i] -= _amounts[i];\n if (_amounts[i] > 0) {\n IERC20(coins[i]).transfer(_reveiver, _amounts[i]);\n }\n }\n }\n\n // Dumb implementation that sums the scaled amounts\n function calc_token_amount(uint256[2] memory _amounts, bool)\n public\n view\n returns (uint256 lpTokens)\n {\n for (uint256 i = 0; i < _amounts.length; i++) {\n uint256 assetDecimals = Helpers.getDecimals(coins[i]);\n // Convert to 1e18 and add to lpTokens\n lpTokens += _amounts[i].scaleBy(18, assetDecimals);\n }\n }\n\n /// @notice 0.02% fee\n function fee() external pure returns (uint256) {\n return 2000000;\n }\n\n function decimals() public pure override returns (uint8) {\n return 18;\n }\n\n function burnFrom(address from, uint256 value) public {\n _burn(from, value);\n }\n}\n" + }, + "contracts/mocks/curve/MockCurveGauge.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\nimport { ICurveGauge } from \"../../strategies/ICurveGauge.sol\";\n\ncontract MockCurveGauge is ICurveGauge {\n mapping(address => uint256) private _balances;\n address lpToken;\n\n constructor(address _lpToken) {\n lpToken = _lpToken;\n }\n\n function balanceOf(address account) public view override returns (uint256) {\n return _balances[account];\n }\n\n function deposit(uint256 _value, address _account) external override {\n IERC20(lpToken).transferFrom(msg.sender, address(this), _value);\n _balances[_account] += _value;\n }\n\n function withdraw(uint256 _value) external override {\n IERC20(lpToken).transfer(msg.sender, _value);\n // solhint-disable-next-line reentrancy\n _balances[msg.sender] -= _value;\n }\n}\n" + }, + "contracts/mocks/curve/MockCurveLUSDMetapool.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { MockCurveAbstractMetapool } from \"./MockCurveAbstractMetapool.sol\";\nimport \"../MintableERC20.sol\";\n\ncontract MockCurveLUSDMetapool is MockCurveAbstractMetapool {\n constructor(address[2] memory _coins)\n ERC20(\"Curve.fi Factory USD Metapool: LUSD\", \"LUSD3CRV-f\")\n {\n coins = _coins;\n }\n}\n" + }, + "contracts/mocks/curve/MockCurveMetapool.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { MockCurveAbstractMetapool } from \"./MockCurveAbstractMetapool.sol\";\nimport \"../MintableERC20.sol\";\n\ncontract MockCurveMetapool is MockCurveAbstractMetapool {\n constructor(address[2] memory _coins)\n ERC20(\"Curve.fi 3pool/OUSD metapool\", \"3crv_OUSD\")\n {\n coins = _coins;\n }\n}\n" + }, + "contracts/mocks/curve/MockCurvePool.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { IBurnableERC20 } from \"../BurnableERC20.sol\";\n\nimport { IMintableERC20 } from \"../MintableERC20.sol\";\nimport { ICurvePool } from \"../../strategies/ICurvePool.sol\";\nimport { StableMath } from \"../../utils/StableMath.sol\";\nimport \"../../utils/Helpers.sol\";\n\ncontract MockCurvePool {\n using StableMath for uint256;\n\n address[] public coins;\n uint256[3] public balances;\n address lpToken;\n uint256 public slippage = 1 ether;\n\n constructor(address[3] memory _coins, address _lpToken) {\n coins = _coins;\n lpToken = _lpToken;\n }\n\n function setCoins(address[] memory _coins) external {\n coins = _coins;\n }\n\n // Returns the same amount of LP tokens in 1e18 decimals\n function add_liquidity(uint256[3] calldata _amounts, uint256 _minAmount)\n external\n {\n uint256 sum = 0;\n for (uint256 i = 0; i < _amounts.length; i++) {\n if (_amounts[i] > 0) {\n IERC20(coins[i]).transferFrom(\n msg.sender,\n address(this),\n _amounts[i]\n );\n uint256 assetDecimals = Helpers.getDecimals(coins[i]);\n // Convert to 1e18 and add to sum\n sum += _amounts[i].scaleBy(18, assetDecimals);\n balances[i] = balances[i] + _amounts[i];\n }\n }\n // Hacky way of simulating slippage to check _minAmount\n if (sum == 29000e18) sum = 14500e18;\n require(sum >= _minAmount, \"Slippage ruined your day\");\n // Send LP token to sender, e.g. 3CRV\n IMintableERC20(lpToken).mint(sum);\n IERC20(lpToken).transfer(msg.sender, sum);\n }\n\n // Dumb implementation that returns the same amount\n function calc_withdraw_one_coin(uint256 _amount, int128 _index)\n public\n view\n returns (uint256)\n {\n uint256 assetDecimals = Helpers.getDecimals(coins[uint128(_index)]);\n return _amount.scaleBy(assetDecimals, 18);\n }\n\n function remove_liquidity_one_coin(\n uint256 _amount,\n int128 _index,\n // solhint-disable-next-line no-unused-vars\n uint256 _minAmount\n ) external {\n // Burn the Curve LP tokens\n IBurnableERC20(lpToken).burnFrom(msg.sender, _amount);\n uint256[] memory amounts = new uint256[](coins.length);\n amounts[uint128(_index)] = _amount;\n uint256 coinAmount = calc_withdraw_one_coin(_amount, _index);\n balances[uint128(_index)] -= coinAmount;\n IERC20(coins[uint128(_index)]).transfer(msg.sender, coinAmount);\n }\n\n function get_virtual_price() external pure returns (uint256) {\n return 1e18;\n }\n\n // solhint-disable-next-line no-unused-vars\n function remove_liquidity(uint256 _lpAmount, uint256[3] memory _min_amounts)\n public\n {\n // Burn the Curve LP tokens\n IBurnableERC20(lpToken).burnFrom(msg.sender, _lpAmount);\n uint256 totalSupply = IERC20(lpToken).totalSupply();\n for (uint256 i = 0; i < 3; i++) {\n uint256 coinAmount = totalSupply > 0\n ? (_lpAmount * IERC20(coins[i]).balanceOf(address(this))) /\n totalSupply\n : IERC20(coins[i]).balanceOf(address(this));\n balances[i] -= coinAmount;\n IERC20(coins[i]).transfer(msg.sender, coinAmount);\n }\n }\n\n function remove_liquidity_imbalance(\n uint256[3] memory _amounts,\n uint256 _max_burned_tokens\n ) public {\n // Burn the Curve LP tokens\n IBurnableERC20(lpToken).burnFrom(msg.sender, _max_burned_tokens);\n // For each coin, transfer to the caller\n for (uint256 i = 0; i < _amounts.length; i++) {\n balances[i] -= _amounts[i];\n if (_amounts[i] > 0) {\n IERC20(coins[i]).transfer(msg.sender, _amounts[i]);\n }\n }\n }\n\n // Dumb implementation that sums the scaled amounts\n function calc_token_amount(uint256[3] memory _amounts, bool)\n public\n view\n returns (uint256 lpTokens)\n {\n for (uint256 i = 0; i < _amounts.length; i++) {\n uint256 assetDecimals = Helpers.getDecimals(coins[i]);\n // Convert to 1e18 and add to lpTokens\n lpTokens += _amounts[i].scaleBy(18, assetDecimals);\n }\n }\n\n function fee() external pure returns (uint256) {\n return 1000000;\n }\n\n function exchange(\n uint256 coin0,\n uint256 coin1,\n uint256 amountIn,\n uint256 minAmountOut\n ) external returns (uint256 amountOut) {\n IERC20(coins[coin0]).transferFrom(msg.sender, address(this), amountIn);\n amountOut = (minAmountOut * slippage) / 1 ether;\n require(amountOut >= minAmountOut, \"Slippage error\");\n IMintableERC20(coins[coin1]).mintTo(msg.sender, amountOut);\n }\n\n function setSlippage(uint256 _slippage) external {\n slippage = _slippage;\n }\n}\n" + }, + "contracts/mocks/curve/MockCVX.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../MintableERC20.sol\";\n\ncontract MockCVX is MintableERC20 {\n constructor() ERC20(\"CVX\", \"CVX DAO Token\") {}\n}\n" + }, + "contracts/mocks/curve/MockLUSD.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../MintableERC20.sol\";\n\ncontract MockLUSD is MintableERC20 {\n constructor() ERC20(\"LUSD\", \"Liquity Token\") {}\n}\n" + }, + "contracts/mocks/curve/MockRewardPool.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 { IMintableERC20 } from \"../MintableERC20.sol\";\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\n\ninterface IDeposit {\n function poolInfo(uint256)\n external\n view\n returns (\n address,\n address,\n address,\n address,\n address,\n bool\n );\n\n function rewardClaimed(\n uint256,\n address,\n uint256\n ) external;\n\n function withdrawTo(\n uint256,\n uint256,\n address\n ) external;\n}\n\ncontract MockRewardPool {\n using SafeMath for uint256;\n using SafeERC20 for IERC20;\n\n uint256 public pid;\n address public stakingToken;\n address public rewardTokenA;\n address public rewardTokenB;\n address public operator;\n\n uint256 private _totalSupply;\n\n mapping(address => uint256) private _balances;\n mapping(address => uint256) public rewards;\n\n constructor(\n uint256 _pid,\n address _stakingToken,\n address _rewardTokenA,\n address _rewardTokenB,\n address _operator\n ) public {\n pid = _pid;\n stakingToken = _stakingToken;\n rewardTokenA = _rewardTokenA;\n rewardTokenB = _rewardTokenB;\n operator = _operator;\n }\n\n function totalSupply() public view returns (uint256) {\n return _totalSupply;\n }\n\n function balanceOf(address account) public view returns (uint256) {\n return _balances[account];\n }\n\n function stakeFor(address _for, uint256 _amount) public returns (bool) {\n require(_amount > 0, \"RewardPool : Cannot stake 0\");\n\n //give to _for\n _totalSupply = _totalSupply.add(_amount);\n _balances[_for] = _balances[_for].add(_amount);\n\n //take away from sender\n IERC20(stakingToken).safeTransferFrom(\n msg.sender,\n address(this),\n _amount\n );\n\n return true;\n }\n\n function withdrawAndUnwrap(uint256 amount, bool claim)\n public\n returns (bool)\n {\n _totalSupply = _totalSupply.sub(amount);\n _balances[msg.sender] = _balances[msg.sender].sub(amount);\n\n //tell operator to withdraw from here directly to user\n IDeposit(operator).withdrawTo(pid, amount, msg.sender);\n\n //get rewards too\n if (claim) {\n getReward(msg.sender, true);\n }\n return true;\n }\n\n function withdrawAllAndUnwrap(bool claim) external {\n withdrawAndUnwrap(_balances[msg.sender], claim);\n }\n\n // solhint-disable-next-line no-unused-vars\n function getReward(address _account, bool _claimExtras)\n public\n returns (bool)\n {\n IMintableERC20(rewardTokenA).mint(2 * 1e18);\n IERC20(rewardTokenA).transfer(_account, 2 * 1e18);\n\n IMintableERC20(rewardTokenB).mint(3 * 1e18);\n IERC20(rewardTokenB).transfer(_account, 3 * 1e18);\n\n return true;\n }\n\n function getReward() public returns (bool) {\n getReward(msg.sender, true);\n }\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/Mock1InchSwapRouter.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\";\n\nimport { SwapDescription } from \"../interfaces/IOneInch.sol\";\n\ncontract Mock1InchSwapRouter {\n using SafeERC20 for IERC20;\n\n event MockSwap(address executor, bytes permitData, bytes executorData);\n\n event MockSwapDesc(\n address srcToken,\n address dstToken,\n address srcReceiver,\n address dstReceiver,\n uint256 amount,\n uint256 minReturnAmount,\n uint256 flags\n );\n\n event MockUnoswapTo(\n address recipient,\n address srcToken,\n uint256 amount,\n uint256 minReturn,\n uint256[] pools\n );\n\n event MockUniswapV3SwapTo(\n address recipient,\n uint256 amount,\n uint256 minReturn,\n uint256[] pools\n );\n\n /**\n * @dev transfers the shource asset and returns the minReturnAmount of the destination asset.\n */\n function swap(\n address executor,\n SwapDescription calldata desc,\n bytes calldata permitData,\n bytes calldata executorData\n ) public returns (uint256 returnAmount, uint256 spentAmount) {\n // Transfer the source tokens to the receiver contract\n IERC20(desc.srcToken).safeTransferFrom(\n msg.sender,\n desc.srcReceiver,\n desc.amount\n );\n\n // Transfer the destination tokens to the recipient\n IERC20(desc.dstToken).safeTransfer(\n desc.dstReceiver,\n desc.minReturnAmount\n );\n\n emit MockSwap(executor, permitData, executorData);\n _swapDesc(desc);\n returnAmount = 0;\n spentAmount = 0;\n }\n\n function _swapDesc(SwapDescription calldata desc) public {\n emit MockSwapDesc(\n address(desc.srcToken),\n address(desc.dstToken),\n desc.srcReceiver,\n desc.dstReceiver,\n desc.amount,\n desc.minReturnAmount,\n desc.flags\n );\n }\n\n /**\n * @dev only transfers the source asset to this contract.\n * Ideally it would return the destination asset but that's encoded in the pools array.\n */\n function unoswapTo(\n address payable recipient,\n address srcToken,\n uint256 amount,\n uint256 minReturn,\n uint256[] calldata pools\n ) public returns (uint256 returnAmount) {\n // transfer the from asset from the caller\n IERC20(srcToken).safeTransferFrom(msg.sender, address(this), amount);\n\n emit MockUnoswapTo(recipient, srcToken, amount, minReturn, pools);\n returnAmount = 0;\n }\n\n /**\n * @dev does not do any transfers. Just emits MockUniswapV3SwapTo.\n */\n function uniswapV3SwapTo(\n address payable recipient,\n uint256 amount,\n uint256 minReturn,\n uint256[] calldata pools\n ) public returns (uint256 returnAmount) {\n emit MockUniswapV3SwapTo(recipient, amount, minReturn, pools);\n returnAmount = 0;\n }\n}\n" + }, + "contracts/mocks/MockAave.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { IERC20, ERC20 } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\nimport { MintableERC20 } from \"./MintableERC20.sol\";\nimport { IAaveLendingPool, ILendingPoolAddressesProvider } from \"../strategies/IAave.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\n\n// 1. User calls 'getLendingPool'\n// 2. User calls 'deposit' (Aave)\n// - Deposit their underlying\n// - Mint aToken to them\n// 3. User calls redeem (aToken)\n// - Retrieve their aToken\n// - Return equal amount of underlying\n\ncontract MockAToken is MintableERC20 {\n address public lendingPool;\n IERC20 public underlyingToken;\n using SafeERC20 for IERC20;\n\n constructor(\n address _lendingPool,\n string memory _name,\n string memory _symbol,\n IERC20 _underlyingToken\n ) ERC20(_name, _symbol) {\n lendingPool = _lendingPool;\n underlyingToken = _underlyingToken;\n // addMinter(_lendingPool);\n }\n\n function decimals() public view override returns (uint8) {\n return ERC20(address(underlyingToken)).decimals();\n }\n\n function poolRedeem(uint256 _amount, address _to) external {\n require(msg.sender == lendingPool, \"pool only\");\n // Redeem these a Tokens\n _burn(_to, _amount);\n // For the underlying\n underlyingToken.safeTransferFrom(lendingPool, _to, _amount);\n }\n}\n\ncontract MockAave is IAaveLendingPool, ILendingPoolAddressesProvider {\n using SafeERC20 for IERC20;\n using StableMath for uint256;\n\n mapping(address => address) reserveToAToken;\n address pool = address(this);\n address payable core = payable(address(this));\n uint256 factor;\n\n function addAToken(address _aToken, address _underlying) public {\n IERC20(_underlying).safeApprove(_aToken, 0);\n IERC20(_underlying).safeApprove(_aToken, type(uint256).max);\n reserveToAToken[_underlying] = _aToken;\n }\n\n // set the reserve factor / basically the interest on deposit\n // in 18 precision\n // so 0.5% would be 5 * 10 ^ 15\n function setFactor(uint256 factor_) public {\n factor = factor_;\n }\n\n function deposit(\n address _reserve,\n uint256 _amount,\n address _to,\n uint16 /*_referralCode*/\n ) external override {\n uint256 previousBal = IERC20(reserveToAToken[_reserve]).balanceOf(\n msg.sender\n );\n uint256 interest = previousBal.mulTruncate(factor);\n MintableERC20(reserveToAToken[_reserve]).mintTo(msg.sender, interest);\n // Take their reserve\n IERC20(_reserve).safeTransferFrom(msg.sender, address(this), _amount);\n // Credit them with aToken\n MintableERC20(reserveToAToken[_reserve]).mintTo(_to, _amount);\n }\n\n function withdraw(\n address asset,\n uint256 amount,\n address to\n ) external override returns (uint256) {\n MockAToken atoken = MockAToken(reserveToAToken[asset]);\n atoken.poolRedeem(amount, to);\n return amount;\n }\n\n function getLendingPool() external view override returns (address) {\n return pool;\n }\n}\n" + }, + "contracts/mocks/MockAaveIncentivesController.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { MockStkAave } from \"./MockStkAave.sol\";\n\ncontract MockAaveIncentivesController {\n mapping(address => uint256) private rewards;\n MockStkAave public REWARD_TOKEN;\n\n constructor(address _reward_token) {\n REWARD_TOKEN = MockStkAave(_reward_token);\n }\n\n function setRewardsBalance(address user, uint256 amount) external {\n rewards[user] = amount;\n }\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 // solhint-disable-next-line no-unused-vars\n function getRewardsBalance(address[] calldata assets, address user)\n external\n view\n returns (uint256)\n {\n return rewards[user];\n }\n\n /**\n * @dev Claims reward for an user, on all the assets of the lending pool, 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 // solhint-disable-next-line no-unused-vars\n address[] calldata assets,\n uint256 amount,\n address to\n ) external returns (uint256) {\n require(amount > 0);\n require(rewards[to] == amount);\n REWARD_TOKEN.mint(amount);\n require(REWARD_TOKEN.transfer(to, amount));\n // solhint-disable-next-line reentrancy\n rewards[to] = 0;\n return amount;\n }\n}\n" + }, + "contracts/mocks/MockAAVEToken.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./MintableERC20.sol\";\n\ncontract MockAAVEToken is MintableERC20 {\n constructor() ERC20(\"AAVE\", \"AAVE\") {}\n}\n" + }, + "contracts/mocks/MockAura.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./MintableERC20.sol\";\n\ncontract MockAura is MintableERC20 {\n constructor() ERC20(\"Aura\", \"AURA\") {}\n}\n" + }, + "contracts/mocks/MockBAL.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./MintableERC20.sol\";\n\ncontract MockBAL is MintableERC20 {\n constructor() ERC20(\"Balancer\", \"BAL\") {}\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/MockBuyback.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { BaseBuyback } from \"../buyback/BaseBuyback.sol\";\n\ncontract MockBuyback is BaseBuyback {\n constructor(\n address _oToken,\n address _ogv,\n address _cvx,\n address _cvxLocker\n ) BaseBuyback(_oToken, _ogv, _cvx, _cvxLocker) {}\n}\n" + }, + "contracts/mocks/MockChainlinkOracleFeed.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../interfaces/chainlink/AggregatorV3Interface.sol\";\n\ncontract MockChainlinkOracleFeed is AggregatorV3Interface {\n int256 price;\n uint8 numDecimals;\n\n constructor(int256 _price, uint8 _decimals) {\n price = _price;\n numDecimals = _decimals;\n }\n\n function decimals() external view override returns (uint8) {\n return numDecimals;\n }\n\n function description() external pure override returns (string memory) {\n return \"MockOracleEthFeed\";\n }\n\n function version() external pure override returns (uint256) {\n return 1;\n }\n\n function setPrice(int256 _price) public {\n price = _price;\n }\n\n function setDecimals(uint8 _decimals) public {\n numDecimals = _decimals;\n }\n\n // getRoundData and latestRoundData should both raise \"No data present\"\n // if they do not have data to report, instead of returning unset values\n // which could be misinterpreted as actual reported values.\n function getRoundData(uint80 _roundId)\n external\n view\n override\n returns (\n uint80 roundId,\n int256 answer,\n uint256 startedAt,\n uint256 updatedAt,\n uint80 answeredInRound\n )\n {\n roundId = _roundId;\n answer = price;\n startedAt = 0;\n updatedAt = 0;\n answeredInRound = 0;\n }\n\n function latestRoundData()\n external\n view\n override\n returns (\n uint80 roundId,\n int256 answer,\n uint256 startedAt,\n uint256 updatedAt,\n uint80 answeredInRound\n )\n {\n roundId = 0;\n answer = price;\n startedAt = 0;\n updatedAt = block.timestamp;\n answeredInRound = 0;\n }\n}\n" + }, + "contracts/mocks/MockCOMP.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./MintableERC20.sol\";\n\ncontract MockCOMP is MintableERC20 {\n constructor() ERC20(\"COMP\", \"COMP\") {}\n}\n" + }, + "contracts/mocks/MockComptroller.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ncontract MockComptroller {\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" + }, + "contracts/mocks/MockCToken.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { IERC20, ERC20 } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\nimport { ICERC20 } from \"../strategies/ICompound.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\n\ncontract MockCToken is ICERC20, ERC20 {\n using StableMath for uint256;\n\n IERC20 public underlyingToken;\n // underlying = cToken * exchangeRate\n // cToken = underlying / exchangeRate\n uint256 exchangeRate;\n address public override comptroller;\n\n constructor(ERC20 _underlyingToken, address _comptroller)\n ERC20(\"cMock\", \"cMK\")\n {\n uint8 underlyingDecimals = _underlyingToken.decimals();\n // if has 18 dp, exchange rate should be 1e26\n // if has 8 dp, exchange rate should be 1e18\n if (underlyingDecimals > 8) {\n exchangeRate = 10**uint256(18 + underlyingDecimals - 10);\n } else if (underlyingDecimals < 8) {\n // e.g. 18-8+6 = 16\n exchangeRate = 10**uint256(18 - 8 + underlyingDecimals);\n } else {\n exchangeRate = 1e18;\n }\n underlyingToken = _underlyingToken;\n comptroller = _comptroller;\n }\n\n function decimals() public pure override returns (uint8) {\n return 8;\n }\n\n function mint(uint256 mintAmount) public override returns (uint256) {\n // Credit them with cToken\n _mint(msg.sender, mintAmount.divPrecisely(exchangeRate));\n // Take their reserve\n underlyingToken.transferFrom(msg.sender, address(this), mintAmount);\n return 0;\n }\n\n function redeem(uint256 redeemAmount) external override returns (uint256) {\n uint256 tokenAmount = redeemAmount.mulTruncate(exchangeRate);\n // Burn the cToken\n _burn(msg.sender, redeemAmount);\n // Transfer underlying to caller\n underlyingToken.transfer(msg.sender, tokenAmount);\n return 0;\n }\n\n function redeemUnderlying(uint256 redeemAmount)\n external\n override\n returns (uint256)\n {\n uint256 cTokens = redeemAmount.divPrecisely(exchangeRate);\n // Burn the cToken\n _burn(msg.sender, cTokens);\n // Transfer underlying to caller\n underlyingToken.transfer(msg.sender, redeemAmount);\n return 0;\n }\n\n function balanceOfUnderlying(address owner)\n external\n view\n override\n returns (uint256)\n {\n uint256 cTokenBal = this.balanceOf(owner);\n return cTokenBal.mulTruncate(exchangeRate);\n }\n\n function balanceOf(address owner)\n public\n view\n override(ICERC20, ERC20)\n returns (uint256)\n {\n return ERC20.balanceOf(owner);\n }\n\n function updateExchangeRate()\n internal\n view\n returns (uint256 newExchangeRate)\n {\n uint256 factor = 100002 * (10**13); // 0.002%\n newExchangeRate = exchangeRate.mulTruncate(factor);\n }\n\n function exchangeRateStored() external view override returns (uint256) {\n return exchangeRate;\n }\n\n function supplyRatePerBlock() external pure override returns (uint256) {\n return 141 * (10**8);\n }\n}\n" + }, + "contracts/mocks/MockCVXLocker.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { ERC20 } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ncontract MockCVXLocker {\n address public immutable cvx;\n mapping(address => uint256) public lockedBalanceOf;\n\n constructor(address _cvx) {\n cvx = _cvx;\n }\n\n function lock(\n address _account,\n uint256 _amount,\n uint256\n ) external {\n lockedBalanceOf[_account] += _amount;\n ERC20(cvx).transferFrom(msg.sender, address(this), _amount);\n }\n\n function unlockAllTokens(address _account) external {\n lockedBalanceOf[_account] = 0;\n ERC20(cvx).transfer(_account, lockedBalanceOf[_account]);\n }\n}\n" + }, + "contracts/mocks/MockDAI.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./MintableERC20.sol\";\n\ncontract MockDAI is MintableERC20 {\n constructor() ERC20(\"DAI\", \"DAI\") {}\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/MockfrxETH.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./MintableERC20.sol\";\n\ncontract MockfrxETH is MintableERC20 {\n constructor() ERC20(\"frxETH\", \"frxETH\") {}\n}\n" + }, + "contracts/mocks/MockFrxETHMinter.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./MintableERC20.sol\";\n\ncontract MockFrxETHMinter {\n address public immutable frxETH;\n address public immutable sfrxETH;\n\n constructor(address _frxETH, address _sfrxETH) {\n frxETH = _frxETH;\n sfrxETH = _sfrxETH;\n }\n\n function submitAndDeposit(address recipient)\n external\n payable\n returns (uint256 shares)\n {\n IMintableERC20(frxETH).mintTo(sfrxETH, msg.value);\n IMintableERC20(sfrxETH).mintTo(recipient, msg.value);\n shares = msg.value;\n }\n}\n" + }, + "contracts/mocks/MockLimitedWrappedOusd.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { WrappedOusd } from \"../token/WrappedOusd.sol\";\nimport { ERC20 } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ncontract MockLimitedWrappedOusd is WrappedOusd {\n constructor(\n ERC20 underlying_,\n string memory name_,\n string memory symbol_\n ) WrappedOusd(underlying_, name_, symbol_) {}\n\n function maxDeposit(address)\n public\n view\n virtual\n override\n returns (uint256)\n {\n return 1e18;\n }\n}\n" + }, + "contracts/mocks/MockMetadataToken.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n// IERC20Metadata is used in the resolveAsset function in contracts/utils/assets.js\n// We just need to import it here to make its ABI available to Hardhat\nimport { IERC20Metadata } from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\n" + }, + "contracts/mocks/MockMintableUniswapPair.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./MintableERC20.sol\";\nimport \"./MockUniswapPair.sol\";\n\ncontract MockMintableUniswapPair is MockUniswapPair, MintableERC20 {\n constructor(\n address _token0,\n address _token1,\n uint112 _reserve0,\n uint112 _reserve1\n )\n MockUniswapPair(_token0, _token1, _reserve0, _reserve1)\n ERC20(\"Uniswap V2\", \"UNI-v2\")\n {}\n\n function decimals() public pure override returns (uint8) {\n return 18;\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/MockNonStandardToken.sol": { + "content": "pragma solidity ^0.8.0;\n\nimport { SafeMath } from \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\n\nimport \"./MintableERC20.sol\";\n\n/**\n * Mock token contract to simulate tokens that don't\n * throw/revert when a transfer/transferFrom call fails\n */\ncontract MockNonStandardToken is MintableERC20 {\n using SafeMath for uint256;\n\n constructor() ERC20(\"NonStandardToken\", \"NonStandardToken\") {}\n\n function decimals() public pure override returns (uint8) {\n return 6;\n }\n\n function transfer(address recipient, uint256 amount)\n public\n override\n returns (bool)\n {\n if (balanceOf(msg.sender) < amount) {\n // Fail silently\n return false;\n }\n\n _transfer(_msgSender(), recipient, amount);\n return true;\n }\n\n function transferFrom(\n address sender,\n address recipient,\n uint256 amount\n ) public override returns (bool) {\n if (balanceOf(sender) < amount) {\n // Fail silently\n return false;\n }\n\n _transfer(sender, recipient, amount);\n _approve(\n sender,\n _msgSender(),\n allowance(sender, _msgSender()).sub(\n amount,\n \"ERC20: transfer amount exceeds allowance\"\n )\n );\n return true;\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/MockOGN.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./BurnableERC20.sol\";\nimport \"./MintableERC20.sol\";\n\n/**\n * @title Origin token (OGN).\n *\n * @dev Token that allows minting and burning.\n * @dev Important note:\n * @dev There is a known race condition in the ERC20 standard on the approve() method.\n * @dev See details: https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n * @dev The Origin token contract implements the increaseApproval() and decreaseApproval() methods.\n * @dev It is strongly recommended to use those methods rather than approve()\n * @dev when updating the token allowance.\n */\ncontract MockOGN is MintableERC20, BurnableERC20 {\n event SetWhitelistExpiration(uint256 expiration);\n event AllowedTransactorAdded(address sender);\n event AllowedTransactorRemoved(address sender);\n event AddCallSpenderWhitelist(address enabler, address spender);\n event RemoveCallSpenderWhitelist(address disabler, address spender);\n\n mapping(address => bool) public callSpenderWhitelist;\n address public owner = msg.sender;\n // UNIX timestamp (in seconds) after which this whitelist no longer applies\n uint256 public whitelistExpiration;\n // While the whitelist is active, either the sender or recipient must be\n // in allowedTransactors.\n mapping(address => bool) public allowedTransactors;\n\n // @dev Constructor that gives msg.sender all initial tokens.\n constructor(uint256 _initialSupply) ERC20(\"OriginToken\", \"OGN\") {\n owner = msg.sender;\n _mint(owner, _initialSupply);\n }\n\n //\n // approveAndCall methods\n //\n\n // @dev Add spender to whitelist of spenders for approveAndCall\n // @param _spender Address to add\n function addCallSpenderWhitelist(address _spender) public onlyOwner {\n callSpenderWhitelist[_spender] = true;\n emit AddCallSpenderWhitelist(msg.sender, _spender);\n }\n\n // @dev Remove spender from whitelist of spenders for approveAndCall\n // @param _spender Address to remove\n function removeCallSpenderWhitelist(address _spender) public onlyOwner {\n delete callSpenderWhitelist[_spender];\n emit RemoveCallSpenderWhitelist(msg.sender, _spender);\n }\n\n // @dev Approve transfer of tokens and make a contract call in a single\n // @dev transaction. This allows a DApp to avoid requiring two MetaMask\n // @dev approvals for a single logical action, such as creating a listing,\n // @dev which requires the seller to approve a token transfer and the\n // @dev marketplace contract to transfer tokens from the seller.\n //\n // @dev This is based on the ERC827 function approveAndCall and avoids\n // @dev security issues by only working with a whitelisted set of _spender\n // @dev addresses. The other difference is that the combination of this\n // @dev function ensures that the proxied function call receives the\n // @dev msg.sender for this function as its first parameter.\n //\n // @param _spender The address that will spend the funds.\n // @param _value The amount of tokens to be spent.\n // @param _selector Function selector for function to be called.\n // @param _callParams Packed, encoded parameters, omitting the first parameter which is always msg.sender\n function approveAndCallWithSender(\n address _spender,\n uint256 _value,\n bytes4 _selector,\n bytes memory _callParams\n ) public payable returns (bool) {\n require(_spender != address(this), \"token contract can't be approved\");\n require(callSpenderWhitelist[_spender], \"spender not in whitelist\");\n\n require(super.approve(_spender, _value), \"approve failed\");\n\n bytes memory callData = abi.encodePacked(\n _selector,\n uint256(uint160(msg.sender)),\n _callParams\n );\n // solium-disable-next-line security/no-call-value\n (bool success, ) = _spender.call{ value: msg.value }(callData);\n require(success, \"proxied call failed\");\n return true;\n }\n\n //\n // Functions for maintaining whitelist\n //\n\n modifier onlyOwner() {\n require(msg.sender == owner);\n _;\n }\n modifier allowedTransfer(address _from, address _to) {\n require(\n // solium-disable-next-line operator-whitespace\n !whitelistActive() ||\n allowedTransactors[_from] ||\n allowedTransactors[_to],\n \"neither sender nor recipient are allowed\"\n );\n _;\n }\n\n function whitelistActive() public view returns (bool) {\n return block.timestamp < whitelistExpiration;\n }\n\n function addAllowedTransactor(address _transactor) public onlyOwner {\n emit AllowedTransactorAdded(_transactor);\n allowedTransactors[_transactor] = true;\n }\n\n function removeAllowedTransactor(address _transactor) public onlyOwner {\n emit AllowedTransactorRemoved(_transactor);\n delete allowedTransactors[_transactor];\n }\n\n /**\n * @dev Set the whitelist expiration, after which the whitelist no longer\n * applies.\n */\n function setWhitelistExpiration(uint256 _expiration) public onlyOwner {\n // allow only if whitelist expiration hasn't yet been set, or if the\n // whitelist expiration hasn't passed yet\n require(\n whitelistExpiration == 0 || whitelistActive(),\n \"an expired whitelist cannot be extended\"\n );\n // prevent possible mistakes in calling this function\n require(\n _expiration >= block.timestamp + 1 days,\n \"whitelist expiration not far enough into the future\"\n );\n emit SetWhitelistExpiration(_expiration);\n whitelistExpiration = _expiration;\n }\n\n //\n // ERC20 transfer functions that have been overridden to enforce the\n // whitelist.\n //\n\n function transfer(address _to, uint256 _value)\n public\n override\n allowedTransfer(msg.sender, _to)\n returns (bool)\n {\n return super.transfer(_to, _value);\n }\n\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n ) public override allowedTransfer(_from, _to) returns (bool) {\n return super.transferFrom(_from, _to, _value);\n }\n}\n" + }, + "contracts/mocks/MockOGV.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./MintableERC20.sol\";\n\ncontract MockOGV is MintableERC20 {\n constructor() ERC20(\"OGV\", \"OGV\") {}\n}\n" + }, + "contracts/mocks/MockOracle.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../interfaces/IPriceOracle.sol\";\nimport \"../interfaces/IMinMaxOracle.sol\";\n\n/**\n * Mock of both price Oracle and min max oracles\n */\ncontract MockOracle is IPriceOracle, IMinMaxOracle {\n mapping(bytes32 => uint256) prices;\n mapping(bytes32 => uint256[]) pricesMinMax;\n uint256 ethMin;\n uint256 ethMax;\n\n /**\n * @dev returns the asset price in USD, 6 decimal digits.\n * Compatible with the Open Price Feed.\n */\n function price(string calldata symbol)\n external\n view\n override\n returns (uint256)\n {\n return prices[keccak256(abi.encodePacked(symbol))];\n }\n\n /**\n * @dev sets the price of the asset in USD, 6 decimal digits\n *\n */\n function setPrice(string calldata symbol, uint256 _price) external {\n prices[keccak256(abi.encodePacked(symbol))] = _price;\n }\n\n /**\n * @dev sets the min and max price of ETH in USD, 6 decimal digits\n *\n */\n function setEthPriceMinMax(uint256 _min, uint256 _max) external {\n ethMin = _min;\n ethMax = _max;\n }\n\n /**\n * @dev sets the prices Min Max for a specific symbol in ETH, 8 decimal digits\n *\n */\n function setTokPriceMinMax(\n string calldata symbol,\n uint256 _min,\n uint256 _max\n ) external {\n pricesMinMax[keccak256(abi.encodePacked(symbol))] = [_min, _max];\n }\n\n /**\n * @dev get the price of asset in ETH, 8 decimal digits.\n */\n function priceMin(string calldata symbol)\n external\n view\n override\n returns (uint256)\n {\n uint256[] storage pMinMax = pricesMinMax[\n keccak256(abi.encodePacked(symbol))\n ];\n return (pMinMax[0] * ethMin) / 1e6;\n }\n\n /**\n * @dev get the price of asset in USD, 8 decimal digits.\n * Not needed for now\n */\n function priceMax(string calldata symbol)\n external\n view\n override\n returns (uint256)\n {\n uint256[] storage pMinMax = pricesMinMax[\n keccak256(abi.encodePacked(symbol))\n ];\n return (pMinMax[1] * ethMax) / 1e6;\n }\n}\n" + }, + "contracts/mocks/MockOracleRouter.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../interfaces/chainlink/AggregatorV3Interface.sol\";\nimport { IOracle } from \"../interfaces/IOracle.sol\";\nimport { Helpers } from \"../utils/Helpers.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\nimport { SafeCast } from \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\nimport { OracleRouterBase } from \"../oracle/OracleRouterBase.sol\";\n\n// @notice Oracle Router required for testing environment\ncontract MockOracleRouter is OracleRouterBase {\n struct FeedMetadata {\n address feedAddress;\n uint256 maxStaleness;\n }\n\n mapping(address => FeedMetadata) public assetToFeedMetadata;\n\n /* @dev Override feed and maxStaleness information for a particular asset\n * @param _asset the asset to override feed for\n * @param _feed new feed\n * @param _maxStaleness new maximum time allowed for feed data to be stale\n */\n function setFeed(\n address _asset,\n address _feed,\n uint256 _maxStaleness\n ) external {\n assetToFeedMetadata[_asset] = FeedMetadata(_feed, _maxStaleness);\n }\n\n /*\n * The dev version of the Oracle doesn't need to gas optimize and cache the decimals\n */\n function getDecimals(address _feed) internal view override returns (uint8) {\n require(_feed != address(0), \"Asset not available\");\n require(_feed != FIXED_PRICE, \"Fixed price feeds not supported\");\n\n return AggregatorV3Interface(_feed).decimals();\n }\n\n /**\n * @dev The price feed contract to use for a particular asset along with\n * maximum data staleness\n * @param asset address of the asset\n * @return feedAddress address of the price feed for the asset\n * @return maxStaleness maximum acceptable data staleness duration\n */\n function feedMetadata(address asset)\n internal\n view\n override\n returns (address feedAddress, uint256 maxStaleness)\n {\n FeedMetadata storage fm = assetToFeedMetadata[asset];\n feedAddress = fm.feedAddress;\n maxStaleness = fm.maxStaleness;\n }\n}\n" + }, + "contracts/mocks/MockOracleRouterNoStale.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../interfaces/chainlink/AggregatorV3Interface.sol\";\nimport { IOracle } from \"../interfaces/IOracle.sol\";\nimport { Helpers } from \"../utils/Helpers.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\nimport { SafeCast } from \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\nimport { OracleRouter } from \"../oracle/OracleRouter.sol\";\nimport { OETHOracleRouter } from \"../oracle/OETHOracleRouter.sol\";\n\n// @notice Oracle Router used to bypass staleness\ncontract MockOracleRouterNoStale is OracleRouter {\n function feedMetadata(address asset)\n internal\n pure\n virtual\n override\n returns (address feedAddress, uint256 maxStaleness)\n {\n (feedAddress, ) = super.feedMetadata(asset);\n maxStaleness = 365 days;\n }\n}\n\n// @notice Oracle Router used to bypass staleness\ncontract MockOETHOracleRouterNoStale is OETHOracleRouter {\n constructor(address auraPriceFeed) OETHOracleRouter(auraPriceFeed) {}\n\n function feedMetadata(address asset)\n internal\n view\n virtual\n override\n returns (address feedAddress, uint256 maxStaleness)\n {\n (feedAddress, ) = super.feedMetadata(asset);\n maxStaleness = 365 days;\n }\n}\n" + }, + "contracts/mocks/MockOracleWeightedPool.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { Variable, OracleAverageQuery, IOracleWeightedPool } from \"../interfaces/balancer/IOracleWeightedPool.sol\";\n\ncontract MockOracleWeightedPool is IOracleWeightedPool {\n uint256[] public nextResults;\n\n constructor() {\n nextResults = [1 ether, 1 ether];\n }\n\n function getTimeWeightedAverage(OracleAverageQuery[] memory)\n external\n view\n override\n returns (uint256[] memory results)\n {\n return nextResults;\n }\n\n function setNextResults(uint256[] calldata results) external {\n nextResults = results;\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/MockRETH.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./MintableERC20.sol\";\nimport \"../interfaces/IGetExchangeRateToken.sol\";\n\ncontract MockRETH is MintableERC20, IGetExchangeRateToken {\n uint256 private exchangeRate = 12e17;\n\n constructor() ERC20(\"Rocket Pool ETH\", \"rETH\") {}\n\n function getExchangeRate() external view override returns (uint256) {\n return exchangeRate;\n }\n\n function setExchangeRate(uint256 _rate) external {\n exchangeRate = _rate;\n }\n}\n" + }, + "contracts/mocks/MocksfrxETH.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./MintableERC20.sol\";\n\ncontract MocksfrxETH is MintableERC20 {\n address public frxETH;\n\n constructor(address _frxETH) ERC20(\"sfrxETH\", \"sfrxETH\") {\n frxETH = _frxETH;\n }\n\n function setMockfrxETHAddress(address _frxETH) external {\n frxETH = _frxETH;\n }\n\n function deposit(uint256 assets, address receiver)\n external\n returns (uint256 shares)\n {\n ERC20(frxETH).transferFrom(msg.sender, address(this), assets);\n\n _mint(receiver, assets);\n\n return assets;\n }\n\n function maxWithdraw(address owner) external view returns (uint256) {\n return balanceOf(owner);\n }\n\n function setMaxWithdrawableBalance(address owner, uint256 balance)\n external\n {\n uint256 currentBalance = balanceOf(owner);\n if (currentBalance > balance) {\n _burn(owner, currentBalance - balance);\n } else if (balance > currentBalance) {\n _mint(owner, balance - currentBalance);\n }\n }\n\n function redeem(\n uint256 shares,\n address receiver,\n address owner\n ) external returns (uint256 assets) {\n _burn(owner, shares);\n\n ERC20(frxETH).transfer(receiver, shares);\n\n assets = shares;\n }\n\n function withdraw(\n uint256 assets,\n address receiver,\n address owner\n ) external returns (uint256 shares) {\n _burn(owner, assets);\n\n ERC20(frxETH).transfer(receiver, assets);\n\n shares = assets;\n }\n\n function submitAndDeposit(address recipient)\n external\n payable\n returns (uint256 shares)\n {\n _mint(recipient, msg.value);\n shares = msg.value;\n }\n}\n" + }, + "contracts/mocks/MockSSV.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./MintableERC20.sol\";\n\ncontract MockSSV is MintableERC20 {\n constructor() ERC20(\"SSV Token\", \"SSV\") {}\n}\n" + }, + "contracts/mocks/MockSSVNetwork.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ncontract MockSSVNetwork {\n constructor() {}\n}\n" + }, + "contracts/mocks/MockstETH.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./MintableERC20.sol\";\n\ncontract MockstETH is MintableERC20 {\n constructor() ERC20(\"stETH\", \"stETH\") {}\n}\n" + }, + "contracts/mocks/MockStkAave.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 \"./MintableERC20.sol\";\n\ncontract MockStkAave is MintableERC20 {\n uint256 public COOLDOWN_SECONDS = 864000;\n uint256 public UNSTAKE_WINDOW = 172800;\n address public STAKED_TOKEN;\n\n mapping(address => uint256) public stakerRewardsToClaim;\n mapping(address => uint256) public stakersCooldowns;\n\n using SafeERC20 for IERC20;\n\n constructor(address _stakedToken) ERC20(\"Staked Aave\", \"stkAAVE\") {\n STAKED_TOKEN = _stakedToken;\n }\n\n function decimals() public pure override returns (uint8) {\n return 18;\n }\n\n function setStakedToken(address _stakedToken) external {\n STAKED_TOKEN = _stakedToken;\n }\n\n /**\n * @dev Redeems staked tokens, and stop earning rewards\n * @param to Address to redeem to\n * @param amount Amount to redeem\n **/\n function redeem(address to, uint256 amount) external {\n uint256 cooldownStartTimestamp = stakersCooldowns[msg.sender];\n uint256 windowStart = cooldownStartTimestamp + COOLDOWN_SECONDS;\n require(amount != 0, \"INVALID_ZERO_AMOUNT\");\n require(block.timestamp > windowStart, \"INSUFFICIENT_COOLDOWN\");\n require(\n block.timestamp - windowStart <= UNSTAKE_WINDOW,\n \"UNSTAKE_WINDOW_FINISHED\"\n );\n uint256 balanceOfMessageSender = balanceOf(msg.sender);\n uint256 amountToRedeem = (amount > balanceOfMessageSender)\n ? balanceOfMessageSender\n : amount;\n\n stakersCooldowns[msg.sender] = 0;\n _burn(msg.sender, amountToRedeem);\n IERC20(STAKED_TOKEN).safeTransfer(to, amountToRedeem);\n }\n\n /**\n * @dev Activates the cooldown period to unstake\n * - It can't be called if the user is not staking\n **/\n function cooldown() external {\n require(balanceOf(msg.sender) != 0, \"INVALID_BALANCE_ON_COOLDOWN\");\n stakersCooldowns[msg.sender] = block.timestamp;\n }\n\n /**\n * @dev Test helper function to allow changing the cooldown\n **/\n function setCooldown(address account, uint256 _cooldown) external {\n stakersCooldowns[account] = _cooldown;\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 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 require(false, \"Not implemented\");\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" + }, + "contracts/mocks/MockSwapper.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { IMintableERC20 } from \"./MintableERC20.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\ncontract MockSwapper {\n uint256 public nextOutAmount;\n\n function swap(\n // solhint-disable-next-line no-unused-vars\n address _fromAsset,\n address _toAsset,\n // solhint-disable-next-line no-unused-vars\n uint256 _fromAssetAmount,\n uint256 _minToAssetAmount,\n // solhint-disable-next-line no-unused-vars\n bytes calldata _data\n ) external returns (uint256 toAssetAmount) {\n toAssetAmount = (nextOutAmount > 0) ? nextOutAmount : _minToAssetAmount;\n nextOutAmount = 0;\n IMintableERC20(_toAsset).mint(toAssetAmount);\n IERC20(_toAsset).transfer(msg.sender, toAssetAmount);\n }\n\n function setNextOutAmount(uint256 _nextOutAmount) public {\n nextOutAmount = _nextOutAmount;\n }\n}\n" + }, + "contracts/mocks/MockTUSD.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./MintableERC20.sol\";\n\ncontract MockTUSD is MintableERC20 {\n constructor() ERC20(\"TrueUSD\", \"TUSD\") {}\n\n function decimals() public pure override returns (uint8) {\n return 18;\n }\n}\n" + }, + "contracts/mocks/MockUniswapPair.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { IUniswapV2Pair } from \"../interfaces/uniswap/IUniswapV2Pair.sol\";\n\ncontract MockUniswapPair is IUniswapV2Pair {\n address tok0;\n address tok1;\n uint112 reserve0;\n uint112 reserve1;\n uint256 blockTimestampLast;\n\n bool public hasSynced = false;\n\n constructor(\n address _token0,\n address _token1,\n uint112 _reserve0,\n uint112 _reserve1\n ) {\n tok0 = _token0;\n tok1 = _token1;\n reserve0 = _reserve0;\n reserve1 = _reserve1;\n blockTimestampLast = block.timestamp;\n }\n\n function token0() external view override returns (address) {\n return tok0;\n }\n\n function token1() external view override returns (address) {\n return tok1;\n }\n\n function getReserves()\n external\n view\n override\n returns (\n uint112,\n uint112,\n uint32\n )\n {\n return (reserve0, reserve1, uint32(blockTimestampLast));\n }\n\n function setReserves(uint112 _reserve0, uint112 _reserve1) public {\n reserve0 = _reserve0;\n reserve1 = _reserve1;\n blockTimestampLast = block.timestamp;\n }\n\n // CAUTION This will not work if you setReserves multiple times over\n // multiple different blocks because then it wouldn't be a continuous\n // reserve factor over that blockTimestamp, this assumes an even reserve\n // ratio all the way through\n function price0CumulativeLast() external view override returns (uint256) {\n return\n uint256(FixedPoint.fraction(reserve1, reserve0)._x) *\n blockTimestampLast;\n }\n\n function price1CumulativeLast() external view override returns (uint256) {\n return\n uint256(FixedPoint.fraction(reserve0, reserve1)._x) *\n blockTimestampLast;\n }\n\n function sync() external override {\n hasSynced = true;\n }\n\n function checkHasSynced() external view {\n require(hasSynced, \"Not synced\");\n }\n}\n\n// a library for handling binary fixed point numbers (https://en.wikipedia.org/wiki/Q_(number_format))\nlibrary FixedPoint {\n // range: [0, 2**112 - 1]\n // resolution: 1 / 2**112\n struct uq112x112 {\n uint224 _x;\n }\n\n // returns a uq112x112 which represents the ratio of the numerator to the denominator\n // equivalent to encode(numerator).div(denominator)\n function fraction(uint112 numerator, uint112 denominator)\n internal\n pure\n returns (uq112x112 memory)\n {\n require(denominator > 0, \"FixedPoint: DIV_BY_ZERO\");\n return uq112x112((uint224(numerator) << 112) / denominator);\n }\n}\n" + }, + "contracts/mocks/MockUniswapRouter.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { MintableERC20 } from \"./MintableERC20.sol\";\nimport { IUniswapV2Router } from \"../interfaces/uniswap/IUniswapV2Router02.sol\";\nimport { Helpers } from \"../utils/Helpers.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\n\ncontract MockUniswapRouter is IUniswapV2Router {\n using StableMath for uint256;\n\n mapping(address => address) public pairMaps;\n uint256 public slippage = 1 ether;\n\n function initialize(\n address[] calldata _0tokens,\n address[] calldata _1tokens\n ) public {\n require(\n _0tokens.length == _1tokens.length,\n \"Mock token pairs should be of the same length\"\n );\n for (uint256 i = 0; i < _0tokens.length; i++) {\n pairMaps[_0tokens[i]] = _1tokens[i];\n }\n }\n\n function setSlippage(uint256 _slippage) external {\n slippage = _slippage;\n }\n\n function swapExactTokensForTokens(\n uint256 amountIn,\n uint256 amountOutMin,\n address[] calldata path,\n address to,\n // solhint-disable-next-line no-unused-vars\n uint256\n ) external override returns (uint256[] memory amountsOut) {\n address tok0 = path[0];\n address tok1 = path[path.length - 1];\n\n uint256 amountOut = (amountOutMin * slippage) / 1 ether;\n require(amountOut >= amountOutMin, \"Slippage error\");\n\n IERC20(tok0).transferFrom(msg.sender, address(this), amountIn);\n MintableERC20(tok1).mintTo(to, amountOut);\n\n amountsOut = new uint256[](path.length);\n amountsOut[path.length - 1] = amountOut;\n }\n\n struct ExactInputParams {\n bytes path;\n address recipient;\n uint256 deadline;\n uint256 amountIn;\n uint256 amountOutMinimum;\n }\n\n function exactInput(ExactInputParams calldata params)\n external\n payable\n returns (uint256 amountOut)\n {\n (address tok0, address tok1) = _getFirstAndLastToken(params.path);\n\n amountOut = (params.amountOutMinimum * slippage) / 1 ether;\n\n IERC20(tok0).transferFrom(msg.sender, address(this), params.amountIn);\n MintableERC20(tok1).mintTo(params.recipient, amountOut);\n\n require(\n amountOut >= params.amountOutMinimum,\n \"UniswapMock: amountOut less than amountOutMinimum\"\n );\n return amountOut;\n }\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 override\n returns (\n uint256 amountA,\n uint256 amountB,\n uint256 liquidity\n )\n {\n // this is needed to make this contract whole else it'd be just virtual\n }\n\n function WETH() external pure override returns (address) {\n return address(0);\n }\n\n // Universal router mock\n function execute(\n bytes calldata,\n bytes[] calldata inputs,\n uint256\n ) external payable {\n uint256 inLen = inputs.length;\n for (uint256 i = 0; i < inLen; ++i) {\n (\n address recipient,\n ,\n uint256 amountOutMinimum,\n bytes memory path,\n\n ) = abi.decode(inputs[i], (address, uint256, uint256, bytes, bool));\n\n (address token0, address token1) = _getFirstAndLastToken(path);\n\n amountOutMinimum = amountOutMinimum.scaleBy(\n Helpers.getDecimals(token0),\n Helpers.getDecimals(token1)\n );\n\n MintableERC20(token1).mintTo(recipient, amountOutMinimum);\n }\n }\n\n function _getFirstAndLastToken(bytes memory path)\n internal\n view\n returns (address token0, address token1)\n {\n bytes memory tok0Bytes = new bytes(20);\n for (uint256 j = 0; j < 20; ++j) {\n tok0Bytes[j] = path[j];\n }\n token0 = address(bytes20(tok0Bytes));\n\n if (pairMaps[token0] != address(0)) {\n token0 = pairMaps[token0];\n }\n\n bytes memory tok1Bytes = new bytes(20);\n uint256 tok1Offset = path.length - 20;\n for (uint256 j = 0; j < 20; ++j) {\n tok1Bytes[j] = path[j + tok1Offset];\n }\n token1 = address(bytes20(tok1Bytes));\n\n if (pairMaps[token1] != address(0)) {\n token1 = pairMaps[token1];\n }\n }\n}\n" + }, + "contracts/mocks/MockUSDC.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./MintableERC20.sol\";\n\ncontract MockUSDC is MintableERC20 {\n constructor() ERC20(\"USDC Coin\", \"USDC\") {}\n\n function decimals() public pure override returns (uint8) {\n return 6;\n }\n}\n" + }, + "contracts/mocks/MockUSDT.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./MintableERC20.sol\";\n\ncontract MockUSDT is MintableERC20 {\n constructor() ERC20(\"USDT Coin\", \"USDT\") {}\n\n function decimals() public pure override returns (uint8) {\n return 6;\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/mocks/MockWETH.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./MintableERC20.sol\";\n\ncontract MockWETH is MintableERC20 {\n constructor() ERC20(\"WETH\", \"WETH\") {}\n\n function deposit() external payable {\n _mint(msg.sender, msg.value);\n }\n\n function withdraw(uint256 wad) external {\n _burn(msg.sender, wad);\n payable(msg.sender).transfer(wad);\n }\n}\n" + }, + "contracts/oracle/AuraWETHPriceFeed.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { Variable, OracleAverageQuery, IOracleWeightedPool } from \"../interfaces/balancer/IOracleWeightedPool.sol\";\nimport { Strategizable } from \"../governance/Strategizable.sol\";\nimport { AggregatorV3Interface } from \"../interfaces/chainlink/AggregatorV3Interface.sol\";\nimport { SafeCast } from \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\n\ncontract AuraWETHPriceFeed is AggregatorV3Interface, Strategizable {\n using SafeCast for uint256;\n using SafeCast for int256;\n\n event PriceFeedPaused();\n event PriceFeedUnpaused();\n event ToleranceChanged(uint256 oldTolerance, uint256 newTolerance);\n\n error PriceFeedPausedError();\n error PriceFeedUnpausedError();\n error InvalidToleranceBps();\n error HighPriceVolatility(uint256 deviation);\n\n bool public paused;\n uint256 public tolerance = 0.02 ether; // 2% by default\n\n // Fields to make it compatible with `AggregatorV3Interface`\n uint8 public constant override decimals = 18;\n string public constant override description = \"\";\n uint256 public constant override version = 1;\n\n IOracleWeightedPool public immutable auraOracleWeightedPool;\n\n constructor(address _auraOracleWeightedPool, address _governor) {\n _setGovernor(_governor);\n auraOracleWeightedPool = IOracleWeightedPool(_auraOracleWeightedPool);\n }\n\n /**\n * @dev Queries the OracleWeightedPool for TWAP of two intervals\n * (1h data from 5m ago and the recent 5m data) and ensures that\n * the price hasn't deviated too much and returns the most recent\n * TWAP price.\n *\n * @return price The price scaled to 18 decimals\n **/\n function price() external view returns (int256) {\n return _price();\n }\n\n function _price() internal view returns (int256) {\n if (paused) {\n revert PriceFeedPausedError();\n }\n OracleAverageQuery[] memory queries = new OracleAverageQuery[](2);\n\n queries[0] = OracleAverageQuery({\n variable: Variable.PAIR_PRICE,\n secs: 3600, // Get 1h data\n ago: 300 // From 5min ago\n });\n queries[1] = OracleAverageQuery({\n variable: Variable.PAIR_PRICE,\n secs: 300, // Get 5min data\n ago: 0 // From now\n });\n\n uint256[] memory prices = auraOracleWeightedPool.getTimeWeightedAverage(\n queries\n );\n int256 price_1h = prices[0].toInt256();\n int256 price_5m = prices[1].toInt256();\n\n int256 diff = (1e18 * (price_1h - price_5m)) /\n ((price_1h + price_5m) / 2);\n uint256 absDiff = diff >= 0 ? diff.toUint256() : (-diff).toUint256();\n\n // Ensure the price hasn't moved too much (2% tolerance)\n // between now and the past hour\n if (absDiff > tolerance) {\n revert HighPriceVolatility(absDiff);\n }\n\n // Return the recent price\n return price_5m;\n }\n\n /**\n * Pauses the price feed. Callable by Strategist as well.\n **/\n function pause() external onlyGovernorOrStrategist {\n if (paused) {\n revert PriceFeedPausedError();\n }\n paused = true;\n emit PriceFeedPaused();\n }\n\n /**\n * Unpauses the price feed. Only Governor can call it\n **/\n function unpause() external onlyGovernor {\n if (!paused) {\n revert PriceFeedUnpausedError();\n }\n paused = false;\n emit PriceFeedUnpaused();\n }\n\n /**\n * Set the max amount of tolerance acceptable between\n * two different price points.\n *\n * @param _tolerance New tolerance value\n **/\n function setTolerance(uint256 _tolerance) external onlyGovernor {\n if (_tolerance > 0.1 ether) {\n revert InvalidToleranceBps();\n }\n emit ToleranceChanged(tolerance, _tolerance);\n tolerance = _tolerance;\n }\n\n /**\n * @dev This function exists to make the contract compatible\n * with AggregatorV3Interface (which OETHOracleRouter uses to\n * get the price).\n *\n * The `answer` returned by this is same as what `price()` would return.\n *\n * It doesn't return any data about rounds (since those doesn't exist).\n **/\n function latestRoundData()\n external\n view\n override\n returns (\n uint80,\n int256 answer,\n uint256,\n uint256 updatedAt,\n uint80\n )\n {\n answer = _price();\n updatedAt = block.timestamp;\n }\n\n /**\n * @dev This function exists to make the contract compatible\n * with AggregatorV3Interface.\n *\n * Always reverts since there're no round data in this contract.\n **/\n function getRoundData(uint80)\n external\n pure\n override\n returns (\n uint80,\n int256,\n uint256,\n uint256,\n uint80\n )\n {\n revert(\"No data present\");\n }\n}\n" + }, + "contracts/oracle/OETHOracleRouter.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../interfaces/chainlink/AggregatorV3Interface.sol\";\nimport { OracleRouterBase } from \"./OracleRouterBase.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\n\n// @notice Oracle Router that denominates all prices in ETH\ncontract OETHOracleRouter is OracleRouterBase {\n using StableMath for uint256;\n\n address public immutable auraPriceFeed;\n\n constructor(address _auraPriceFeed) {\n auraPriceFeed = _auraPriceFeed;\n }\n\n /**\n * @notice Returns the total price in 18 digit units for a given asset.\n * This implementation does not (!) do range checks as the\n * parent OracleRouter does.\n * @param asset address of the asset\n * @return uint256 unit price for 1 asset unit, in 18 decimal fixed\n */\n function price(address asset)\n external\n view\n virtual\n override\n returns (uint256)\n {\n (address _feed, uint256 maxStaleness) = feedMetadata(asset);\n if (_feed == FIXED_PRICE) {\n return 1e18;\n }\n require(_feed != address(0), \"Asset not available\");\n\n // slither-disable-next-line unused-return\n (, int256 _iprice, , uint256 updatedAt, ) = AggregatorV3Interface(_feed)\n .latestRoundData();\n\n require(\n updatedAt + maxStaleness >= block.timestamp,\n \"Oracle price too old\"\n );\n\n uint8 decimals = getDecimals(_feed);\n uint256 _price = uint256(_iprice).scaleBy(18, decimals);\n return _price;\n }\n\n /**\n * @dev The price feed contract to use for a particular asset along with\n * maximum data staleness\n * @param asset address of the asset\n * @return feedAddress address of the price feed for the asset\n * @return maxStaleness maximum acceptable data staleness duration\n */\n function feedMetadata(address asset)\n internal\n view\n virtual\n override\n returns (address feedAddress, uint256 maxStaleness)\n {\n if (asset == 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2) {\n // FIXED_PRICE: WETH/ETH\n feedAddress = FIXED_PRICE;\n maxStaleness = 0;\n } else if (asset == 0x5E8422345238F34275888049021821E8E08CAa1f) {\n // frxETH/ETH\n feedAddress = 0xC58F3385FBc1C8AD2c0C9a061D7c13b141D7A5Df;\n maxStaleness = 18 hours + STALENESS_BUFFER;\n } else if (asset == 0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84) {\n // https://data.chain.link/ethereum/mainnet/crypto-eth/steth-eth\n // Chainlink: stETH/ETH\n feedAddress = 0x86392dC19c0b719886221c78AB11eb8Cf5c52812;\n maxStaleness = 1 days + STALENESS_BUFFER;\n } else if (asset == 0xae78736Cd615f374D3085123A210448E74Fc6393) {\n // https://data.chain.link/ethereum/mainnet/crypto-eth/reth-eth\n // Chainlink: rETH/ETH\n feedAddress = 0x536218f9E9Eb48863970252233c8F271f554C2d0;\n maxStaleness = 1 days + STALENESS_BUFFER;\n } else if (asset == 0xD533a949740bb3306d119CC777fa900bA034cd52) {\n // https://data.chain.link/ethereum/mainnet/crypto-eth/crv-eth\n // Chainlink: CRV/ETH\n feedAddress = 0x8a12Be339B0cD1829b91Adc01977caa5E9ac121e;\n maxStaleness = 1 days + STALENESS_BUFFER;\n } else if (asset == 0x4e3FBD56CD56c3e72c1403e103b45Db9da5B9D2B) {\n // https://data.chain.link/ethereum/mainnet/crypto-eth/cvx-eth\n // Chainlink: CVX/ETH\n feedAddress = 0xC9CbF687f43176B302F03f5e58470b77D07c61c6;\n maxStaleness = 1 days + STALENESS_BUFFER;\n } else if (asset == 0xBe9895146f7AF43049ca1c1AE358B0541Ea49704) {\n // https://data.chain.link/ethereum/mainnet/crypto-eth/cbeth-eth\n // Chainlink: cbETH/ETH\n feedAddress = 0xF017fcB346A1885194689bA23Eff2fE6fA5C483b;\n maxStaleness = 1 days + STALENESS_BUFFER;\n } else if (asset == 0xba100000625a3754423978a60c9317c58a424e3D) {\n // https://data.chain.link/ethereum/mainnet/crypto-eth/bal-eth\n // Chainlink: BAL/ETH\n feedAddress = 0xC1438AA3823A6Ba0C159CfA8D98dF5A994bA120b;\n maxStaleness = 1 days + STALENESS_BUFFER;\n } else if (asset == 0xC0c293ce456fF0ED870ADd98a0828Dd4d2903DBF) {\n // AURA/ETH\n feedAddress = auraPriceFeed;\n maxStaleness = 0;\n } else {\n revert(\"Asset not available\");\n }\n }\n}\n" + }, + "contracts/oracle/OracleRouter.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../interfaces/chainlink/AggregatorV3Interface.sol\";\nimport { OracleRouterBase } from \"./OracleRouterBase.sol\";\n\n// @notice Oracle Router that denominates all prices in USD\ncontract OracleRouter is OracleRouterBase {\n /**\n * @dev The price feed contract to use for a particular asset along with\n * maximum data staleness\n * @param asset address of the asset\n * @return feedAddress address of the price feed for the asset\n * @return maxStaleness maximum acceptable data staleness duration\n */\n function feedMetadata(address asset)\n internal\n pure\n virtual\n override\n returns (address feedAddress, uint256 maxStaleness)\n {\n /* + STALENESS_BUFFER is added in case Oracle for some reason doesn't\n * update on heartbeat and we add a generous buffer amount.\n */\n if (asset == 0x6B175474E89094C44Da98b954EedeAC495271d0F) {\n // https://data.chain.link/ethereum/mainnet/stablecoins/dai-usd\n // Chainlink: DAI/USD\n feedAddress = 0xAed0c38402a5d19df6E4c03F4E2DceD6e29c1ee9;\n maxStaleness = 1 hours + STALENESS_BUFFER;\n } else if (asset == 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48) {\n // https://data.chain.link/ethereum/mainnet/stablecoins/usdc-usd\n // Chainlink: USDC/USD\n feedAddress = 0x8fFfFfd4AfB6115b954Bd326cbe7B4BA576818f6;\n maxStaleness = 1 days + STALENESS_BUFFER;\n } else if (asset == 0xdAC17F958D2ee523a2206206994597C13D831ec7) {\n // https://data.chain.link/ethereum/mainnet/stablecoins/usdt-usd\n // Chainlink: USDT/USD\n feedAddress = 0x3E7d1eAB13ad0104d2750B8863b489D65364e32D;\n maxStaleness = 1 days + STALENESS_BUFFER;\n } else if (asset == 0xc00e94Cb662C3520282E6f5717214004A7f26888) {\n // https://data.chain.link/ethereum/mainnet/crypto-usd/comp-usd\n // Chainlink: COMP/USD\n feedAddress = 0xdbd020CAeF83eFd542f4De03e3cF0C28A4428bd5;\n maxStaleness = 1 hours + STALENESS_BUFFER;\n } else if (asset == 0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9) {\n // https://data.chain.link/ethereum/mainnet/crypto-usd/aave-usd\n // Chainlink: AAVE/USD\n feedAddress = 0x547a514d5e3769680Ce22B2361c10Ea13619e8a9;\n maxStaleness = 1 hours + STALENESS_BUFFER;\n } else if (asset == 0xD533a949740bb3306d119CC777fa900bA034cd52) {\n // https://data.chain.link/ethereum/mainnet/crypto-usd/crv-usd\n // Chainlink: CRV/USD\n feedAddress = 0xCd627aA160A6fA45Eb793D19Ef54f5062F20f33f;\n maxStaleness = 1 days + STALENESS_BUFFER;\n } else if (asset == 0x4e3FBD56CD56c3e72c1403e103b45Db9da5B9D2B) {\n // Chainlink: CVX/USD\n feedAddress = 0xd962fC30A72A84cE50161031391756Bf2876Af5D;\n maxStaleness = 1 days + STALENESS_BUFFER;\n } else {\n revert(\"Asset not available\");\n }\n }\n}\n" + }, + "contracts/oracle/OracleRouterBase.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../interfaces/chainlink/AggregatorV3Interface.sol\";\nimport { IOracle } from \"../interfaces/IOracle.sol\";\nimport { Helpers } from \"../utils/Helpers.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\nimport { SafeCast } from \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\n\n// @notice Abstract functionality that is shared between various Oracle Routers\nabstract contract OracleRouterBase is IOracle {\n using StableMath for uint256;\n using SafeCast for int256;\n\n uint256 internal constant MIN_DRIFT = 0.7e18;\n uint256 internal constant MAX_DRIFT = 1.3e18;\n address internal constant FIXED_PRICE =\n 0x0000000000000000000000000000000000000001;\n // Maximum allowed staleness buffer above normal Oracle maximum staleness\n uint256 internal constant STALENESS_BUFFER = 1 days;\n mapping(address => uint8) internal decimalsCache;\n\n /**\n * @dev The price feed contract to use for a particular asset along with\n * maximum data staleness\n * @param asset address of the asset\n * @return feedAddress address of the price feed for the asset\n * @return maxStaleness maximum acceptable data staleness duration\n */\n function feedMetadata(address asset)\n internal\n view\n virtual\n returns (address feedAddress, uint256 maxStaleness);\n\n /**\n * @notice Returns the total price in 18 digit unit for a given asset.\n * @param asset address of the asset\n * @return uint256 unit price for 1 asset unit, in 18 decimal fixed\n */\n function price(address asset)\n external\n view\n virtual\n override\n returns (uint256)\n {\n (address _feed, uint256 maxStaleness) = feedMetadata(asset);\n require(_feed != address(0), \"Asset not available\");\n require(_feed != FIXED_PRICE, \"Fixed price feeds not supported\");\n\n // slither-disable-next-line unused-return\n (, int256 _iprice, , uint256 updatedAt, ) = AggregatorV3Interface(_feed)\n .latestRoundData();\n\n require(\n updatedAt + maxStaleness >= block.timestamp,\n \"Oracle price too old\"\n );\n\n uint8 decimals = getDecimals(_feed);\n\n uint256 _price = _iprice.toUint256().scaleBy(18, decimals);\n if (shouldBePegged(asset)) {\n require(_price <= MAX_DRIFT, \"Oracle: Price exceeds max\");\n require(_price >= MIN_DRIFT, \"Oracle: Price under min\");\n }\n return _price;\n }\n\n function getDecimals(address _feed) internal view virtual returns (uint8) {\n uint8 decimals = decimalsCache[_feed];\n require(decimals > 0, \"Oracle: Decimals not cached\");\n return decimals;\n }\n\n /**\n * @notice Before an asset/feed price is fetches for the first time the\n * decimals need to be cached. This is a gas optimization\n * @param asset address of the asset\n * @return uint8 corresponding asset decimals\n */\n function cacheDecimals(address asset) external returns (uint8) {\n (address _feed, ) = feedMetadata(asset);\n require(_feed != address(0), \"Asset not available\");\n require(_feed != FIXED_PRICE, \"Fixed price feeds not supported\");\n\n uint8 decimals = AggregatorV3Interface(_feed).decimals();\n decimalsCache[_feed] = decimals;\n return decimals;\n }\n\n function shouldBePegged(address _asset) internal view returns (bool) {\n string memory symbol = Helpers.getSymbol(_asset);\n bytes32 symbolHash = keccak256(abi.encodePacked(symbol));\n return\n symbolHash == keccak256(abi.encodePacked(\"DAI\")) ||\n symbolHash == keccak256(abi.encodePacked(\"USDC\")) ||\n symbolHash == keccak256(abi.encodePacked(\"USDT\"));\n }\n}\n" + }, + "contracts/proxies/InitializeGovernedUpgradeabilityProxy.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { Address } from \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport { Governable } from \"../governance/Governable.sol\";\n\n/**\n * @title BaseGovernedUpgradeabilityProxy\n * @dev This contract combines an upgradeability proxy with our governor system.\n * It is based on an older version of OpenZeppelins BaseUpgradeabilityProxy\n * with Solidity ^0.8.0.\n * @author Origin Protocol Inc\n */\ncontract InitializeGovernedUpgradeabilityProxy is Governable {\n /**\n * @dev Emitted when the implementation is upgraded.\n * @param implementation Address of the new implementation.\n */\n event Upgraded(address indexed implementation);\n\n /**\n * @dev Contract initializer with Governor enforcement\n * @param _logic Address of the initial implementation.\n * @param _initGovernor Address of the initial Governor.\n * @param _data Data to send as msg.data to the implementation to initialize\n * the proxied contract.\n * It should include the signature and the parameters of the function to be\n * called, as described in\n * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.\n * This parameter is optional, if no data is given the initialization call\n * to proxied contract will be skipped.\n */\n function initialize(\n address _logic,\n address _initGovernor,\n bytes calldata _data\n ) public payable onlyGovernor {\n require(_implementation() == address(0));\n assert(\n IMPLEMENTATION_SLOT ==\n bytes32(uint256(keccak256(\"eip1967.proxy.implementation\")) - 1)\n );\n _setImplementation(_logic);\n if (_data.length > 0) {\n (bool success, ) = _logic.delegatecall(_data);\n require(success);\n }\n _changeGovernor(_initGovernor);\n }\n\n /**\n * @return The address of the proxy admin/it's also the governor.\n */\n function admin() external view returns (address) {\n return _governor();\n }\n\n /**\n * @return The address of the implementation.\n */\n function implementation() external view returns (address) {\n return _implementation();\n }\n\n /**\n * @dev Upgrade the backing implementation of the proxy.\n * Only the admin can call this function.\n * @param newImplementation Address of the new implementation.\n */\n function upgradeTo(address newImplementation) external onlyGovernor {\n _upgradeTo(newImplementation);\n }\n\n /**\n * @dev Upgrade the backing implementation of the proxy and call a function\n * on the new implementation.\n * This is useful to initialize the proxied contract.\n * @param newImplementation Address of the new implementation.\n * @param data Data to send as msg.data in the low level call.\n * It should include the signature and the parameters of the function to be called, as described in\n * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.\n */\n function upgradeToAndCall(address newImplementation, bytes calldata data)\n external\n payable\n onlyGovernor\n {\n _upgradeTo(newImplementation);\n (bool success, ) = newImplementation.delegatecall(data);\n require(success);\n }\n\n /**\n * @dev Fallback function.\n * Implemented entirely in `_fallback`.\n */\n fallback() external payable {\n _fallback();\n }\n\n /**\n * @dev Delegates execution to an implementation contract.\n * This is a low level function that doesn't return to its internal call site.\n * It will return to the external caller whatever the implementation returns.\n * @param _impl Address to delegate.\n */\n function _delegate(address _impl) internal {\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(gas(), _impl, 0, calldatasize(), 0, 0)\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 /**\n * @dev Function that is run as the first thing in the fallback function.\n * Can be redefined in derived contracts to add functionality.\n * Redefinitions must call super._willFallback().\n */\n function _willFallback() internal {}\n\n /**\n * @dev fallback implementation.\n * Extracted to enable manual triggering.\n */\n function _fallback() internal {\n _willFallback();\n _delegate(_implementation());\n }\n\n /**\n * @dev Storage slot with the address of the current implementation.\n * This is the keccak-256 hash of \"eip1967.proxy.implementation\" subtracted by 1, and is\n * validated in the constructor.\n */\n bytes32 internal constant IMPLEMENTATION_SLOT =\n 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\n\n /**\n * @dev Returns the current implementation.\n * @return impl Address of the current implementation\n */\n function _implementation() internal view returns (address impl) {\n bytes32 slot = IMPLEMENTATION_SLOT;\n // solhint-disable-next-line no-inline-assembly\n assembly {\n impl := sload(slot)\n }\n }\n\n /**\n * @dev Upgrades the proxy to a new implementation.\n * @param newImplementation Address of the new implementation.\n */\n function _upgradeTo(address newImplementation) internal {\n _setImplementation(newImplementation);\n emit Upgraded(newImplementation);\n }\n\n /**\n * @dev Sets the implementation address of the proxy.\n * @param newImplementation Address of the new implementation.\n */\n function _setImplementation(address newImplementation) internal {\n require(\n Address.isContract(newImplementation),\n \"Cannot set a proxy implementation to a non-contract address\"\n );\n\n bytes32 slot = IMPLEMENTATION_SLOT;\n\n // solhint-disable-next-line no-inline-assembly\n assembly {\n sstore(slot, newImplementation)\n }\n }\n}\n" + }, + "contracts/proxies/Proxies.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { InitializeGovernedUpgradeabilityProxy } from \"./InitializeGovernedUpgradeabilityProxy.sol\";\n\n/**\n * @notice OUSDProxy delegates calls to an OUSD implementation\n */\ncontract OUSDProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice WrappedOUSDProxy delegates calls to a WrappedOUSD implementation\n */\ncontract WrappedOUSDProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice VaultProxy delegates calls to a Vault implementation\n */\ncontract VaultProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice CompoundStrategyProxy delegates calls to a CompoundStrategy implementation\n */\ncontract CompoundStrategyProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice AaveStrategyProxy delegates calls to a AaveStrategy implementation\n */\ncontract AaveStrategyProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice ThreePoolStrategyProxy delegates calls to a ThreePoolStrategy implementation\n */\ncontract ThreePoolStrategyProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice ConvexStrategyProxy delegates calls to a ConvexStrategy implementation\n */\ncontract ConvexStrategyProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice HarvesterProxy delegates calls to a Harvester implementation\n */\ncontract HarvesterProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice DripperProxy delegates calls to a Dripper implementation\n */\ncontract DripperProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice MorphoCompoundStrategyProxy delegates calls to a MorphoCompoundStrategy implementation\n */\ncontract MorphoCompoundStrategyProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice ConvexOUSDMetaStrategyProxy delegates calls to a ConvexOUSDMetaStrategy implementation\n */\ncontract ConvexOUSDMetaStrategyProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice ConvexLUSDMetaStrategyProxy delegates calls to a ConvexalGeneralizedMetaStrategy implementation\n */\ncontract ConvexLUSDMetaStrategyProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice MorphoAaveStrategyProxy delegates calls to a MorphoCompoundStrategy implementation\n */\ncontract MorphoAaveStrategyProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice OETHProxy delegates calls to nowhere for now\n */\ncontract OETHProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice WOETHProxy delegates calls to nowhere for now\n */\ncontract WOETHProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice OETHVaultProxy delegates calls to a Vault implementation\n */\ncontract OETHVaultProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice OETHDripperProxy delegates calls to a OETHDripper implementation\n */\ncontract OETHDripperProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice OETHHarvesterProxy delegates calls to a Harvester implementation\n */\ncontract OETHHarvesterProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice FraxETHStrategyProxy delegates calls to a FraxETHStrategy implementation\n */\ncontract FraxETHStrategyProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice CurveEthStrategyProxy delegates calls to a CurveEthStrategy implementation\n */\ncontract ConvexEthMetaStrategyProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice BuybackProxy delegates calls to Buyback implementation\n */\ncontract BuybackProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice OETHMorphoAaveStrategyProxy delegates calls to a MorphoAaveStrategy implementation\n */\ncontract OETHMorphoAaveStrategyProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice OETHBalancerMetaPoolrEthStrategyProxy delegates calls to a BalancerMetaPoolStrategy implementation\n */\ncontract OETHBalancerMetaPoolrEthStrategyProxy is\n InitializeGovernedUpgradeabilityProxy\n{\n\n}\n\n/**\n * @notice OETHBalancerMetaPoolwstEthStrategyProxy delegates calls to a BalancerMetaPoolStrategy implementation\n */\ncontract OETHBalancerMetaPoolwstEthStrategyProxy is\n InitializeGovernedUpgradeabilityProxy\n{\n\n}\n\n/**\n * @notice FluxStrategyProxy delegates calls to a CompoundStrategy implementation\n */\ncontract FluxStrategyProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice MakerDsrStrategyProxy delegates calls to a Generalized4626Strategy implementation\n */\ncontract MakerDsrStrategyProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice FrxEthRedeemStrategyProxy delegates calls to a FrxEthRedeemStrategy implementation\n */\ncontract FrxEthRedeemStrategyProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice OETHBuybackProxy delegates calls to Buyback implementation\n */\ncontract OETHBuybackProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice BridgedWOETHProxy delegates calls to BridgedWOETH implementation\n */\ncontract BridgedWOETHProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice NativeStakingSSVStrategyProxy delegates calls to NativeStakingSSVStrategy implementation\n */\ncontract NativeStakingSSVStrategyProxy is\n InitializeGovernedUpgradeabilityProxy\n{\n\n}\n\n/**\n * @notice NativeStakingFeeAccumulatorProxy delegates calls to NativeStakingFeeCollector implementation\n */\ncontract NativeStakingFeeAccumulatorProxy is\n InitializeGovernedUpgradeabilityProxy\n{\n\n}\n" + }, + "contracts/staking/SingleAssetStaking.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeMath } from \"@openzeppelin/contracts/utils/math/SafeMath.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 { StableMath } from \"../utils/StableMath.sol\";\n\ncontract SingleAssetStaking is Initializable, Governable {\n using SafeMath for uint256;\n using StableMath for uint256;\n using SafeERC20 for IERC20;\n\n /* ========== STATE VARIABLES ========== */\n\n IERC20 public stakingToken; // this is both the staking and rewards\n\n struct Stake {\n uint256 amount; // amount to stake\n uint256 end; // when does the staking period end\n uint256 duration; // the duration of the stake\n uint240 rate; // rate to charge use 248 to reserve 8 bits for the bool\n bool paid;\n uint8 stakeType;\n }\n\n struct DropRoot {\n bytes32 hash;\n uint256 depth;\n }\n\n uint256[] public durations; // allowed durations\n uint256[] public rates; // rates that correspond with the allowed durations\n\n uint256 public totalOutstanding;\n bool public paused;\n\n mapping(address => Stake[]) public userStakes;\n\n mapping(uint8 => DropRoot) public dropRoots;\n\n // type 0 is reserved for stakes done by the user, all other types will be drop/preApproved stakes\n uint8 constant USER_STAKE_TYPE = 0;\n uint256 constant MAX_STAKES = 256;\n\n address public transferAgent;\n\n /* ========== Initialize ========== */\n\n /**\n * @dev Initialize the contracts, sets up durations, rates, and preApprover\n * for preApproved contracts can only be called once\n * @param _stakingToken Address of the token that we are staking\n * @param _durations Array of allowed durations in seconds\n * @param _rates Array of rates(0.3 is 30%) that correspond to the allowed\n * durations in 1e18 precision\n */\n function initialize(\n address _stakingToken,\n uint256[] calldata _durations,\n uint256[] calldata _rates\n ) external onlyGovernor initializer {\n stakingToken = IERC20(_stakingToken);\n _setDurationRates(_durations, _rates);\n }\n\n /* ========= Internal helper functions ======== */\n\n /**\n * @dev Validate and set the duration and corresponding rates, will emit\n * events NewRate and NewDurations\n */\n function _setDurationRates(\n uint256[] memory _durations,\n uint256[] memory _rates\n ) internal {\n require(\n _rates.length == _durations.length,\n \"Mismatch durations and rates\"\n );\n\n for (uint256 i = 0; i < _rates.length; i++) {\n require(_rates[i] < type(uint240).max, \"Max rate exceeded\");\n }\n\n rates = _rates;\n durations = _durations;\n\n emit NewRates(msg.sender, rates);\n emit NewDurations(msg.sender, durations);\n }\n\n function _totalExpectedRewards(Stake[] storage stakes)\n internal\n view\n returns (uint256 total)\n {\n for (uint256 i = 0; i < stakes.length; i++) {\n Stake storage stake = stakes[i];\n if (!stake.paid) {\n total = total.add(stake.amount.mulTruncate(stake.rate));\n }\n }\n }\n\n function _totalExpected(Stake storage _stake)\n internal\n view\n returns (uint256)\n {\n return _stake.amount.add(_stake.amount.mulTruncate(_stake.rate));\n }\n\n function _airDroppedStakeClaimed(address account, uint8 stakeType)\n internal\n view\n returns (bool)\n {\n Stake[] storage stakes = userStakes[account];\n for (uint256 i = 0; i < stakes.length; i++) {\n if (stakes[i].stakeType == stakeType) {\n return true;\n }\n }\n return false;\n }\n\n function _findDurationRate(uint256 duration)\n internal\n view\n returns (uint240)\n {\n for (uint256 i = 0; i < durations.length; i++) {\n if (duration == durations[i]) {\n return uint240(rates[i]);\n }\n }\n return 0;\n }\n\n /**\n * @dev Internal staking function\n * will insert the stake into the stakes array and verify we have\n * enough to pay off stake + reward\n * @param staker Address of the staker\n * @param stakeType Number that represent the type of the stake, 0 is user\n * initiated all else is currently preApproved\n * @param duration Number of seconds this stake will be held for\n * @param rate Rate(0.3 is 30%) of reward for this stake in 1e18, uint240 =\n * to fit the bool and type in struct Stake\n * @param amount Number of tokens to stake in 1e18\n */\n function _stake(\n address staker,\n uint8 stakeType,\n uint256 duration,\n uint240 rate,\n uint256 amount\n ) internal {\n require(!paused, \"Staking paused\");\n\n Stake[] storage stakes = userStakes[staker];\n\n uint256 end = block.timestamp.add(duration);\n\n uint256 i = stakes.length; // start at the end of the current array\n\n require(i < MAX_STAKES, \"Max stakes\");\n\n stakes.push(); // grow the array\n // find the spot where we can insert the current stake\n // this should make an increasing list sorted by end\n while (i != 0 && stakes[i - 1].end > end) {\n // shift it back one\n stakes[i] = stakes[i - 1];\n i -= 1;\n }\n\n // insert the stake\n Stake storage newStake = stakes[i];\n newStake.rate = rate;\n newStake.stakeType = stakeType;\n newStake.end = end;\n newStake.duration = duration;\n newStake.amount = amount;\n\n totalOutstanding = totalOutstanding.add(_totalExpected(newStake));\n\n emit Staked(staker, amount, duration, rate);\n }\n\n function _stakeWithChecks(\n address staker,\n uint256 amount,\n uint256 duration\n ) internal {\n require(amount > 0, \"Cannot stake 0\");\n\n uint240 rewardRate = _findDurationRate(duration);\n require(rewardRate > 0, \"Invalid duration\"); // we couldn't find the rate that correspond to the passed duration\n\n _stake(staker, USER_STAKE_TYPE, duration, rewardRate, amount);\n // transfer in the token so that we can stake the correct amount\n stakingToken.safeTransferFrom(staker, address(this), amount);\n }\n\n modifier requireLiquidity() {\n // we need to have enough balance to cover the rewards after the operation is complete\n _;\n require(\n stakingToken.balanceOf(address(this)) >= totalOutstanding,\n \"Insufficient rewards\"\n );\n }\n\n /* ========== VIEWS ========== */\n\n function getAllDurations() external view returns (uint256[] memory) {\n return durations;\n }\n\n function getAllRates() external view returns (uint256[] memory) {\n return rates;\n }\n\n /**\n * @dev Return all the stakes paid and unpaid for a given user\n * @param account Address of the account that we want to look up\n */\n function getAllStakes(address account)\n external\n view\n returns (Stake[] memory)\n {\n return userStakes[account];\n }\n\n /**\n * @dev Find the rate that corresponds to a given duration\n * @param _duration Number of seconds\n */\n function durationRewardRate(uint256 _duration)\n external\n view\n returns (uint256)\n {\n return _findDurationRate(_duration);\n }\n\n /**\n * @dev Has the airdropped stake already been claimed\n */\n function airDroppedStakeClaimed(address account, uint8 stakeType)\n external\n view\n returns (bool)\n {\n return _airDroppedStakeClaimed(account, stakeType);\n }\n\n /**\n * @dev Calculate all the staked value a user has put into the contract,\n * rewards not included\n * @param account Address of the account that we want to look up\n */\n function totalStaked(address account)\n external\n view\n returns (uint256 total)\n {\n Stake[] storage stakes = userStakes[account];\n\n for (uint256 i = 0; i < stakes.length; i++) {\n if (!stakes[i].paid) {\n total = total.add(stakes[i].amount);\n }\n }\n }\n\n /**\n * @dev Calculate all the rewards a user can expect to receive.\n * @param account Address of the account that we want to look up\n */\n function totalExpectedRewards(address account)\n external\n view\n returns (uint256)\n {\n return _totalExpectedRewards(userStakes[account]);\n }\n\n /**\n * @dev Calculate all current holdings of a user: staked value + prorated rewards\n * @param account Address of the account that we want to look up\n */\n function totalCurrentHoldings(address account)\n external\n view\n returns (uint256 total)\n {\n Stake[] storage stakes = userStakes[account];\n\n for (uint256 i = 0; i < stakes.length; i++) {\n Stake storage stake = stakes[i];\n if (stake.paid) {\n continue;\n } else if (stake.end < block.timestamp) {\n total = total.add(_totalExpected(stake));\n } else {\n //calcualte the precentage accrued in term of rewards\n total = total.add(\n stake.amount.add(\n stake.amount.mulTruncate(stake.rate).mulTruncate(\n stake\n .duration\n .sub(stake.end.sub(block.timestamp))\n .divPrecisely(stake.duration)\n )\n )\n );\n }\n }\n }\n\n /* ========== MUTATIVE FUNCTIONS ========== */\n\n /**\n * @dev Make a preapproved stake for the user, this is a presigned voucher that the user can redeem either from\n * an airdrop or a compensation program.\n * Only 1 of each type is allowed per user. The proof must match the root hash\n * @param index Number that is zero base index of the stake in the payout entry\n * @param stakeType Number that represent the type of the stake, must not be 0 which is user stake\n * @param duration Number of seconds this stake will be held for\n * @param rate Rate(0.3 is 30%) of reward for this stake in 1e18, uint240 to fit the bool and type in struct Stake\n * @param amount Number of tokens to stake in 1e18\n * @param merkleProof Array of proofs for that amount\n */\n function airDroppedStake(\n uint256 index,\n uint8 stakeType,\n uint256 duration,\n uint256 rate,\n uint256 amount,\n bytes32[] calldata merkleProof\n ) external requireLiquidity {\n require(stakeType != USER_STAKE_TYPE, \"Cannot be normal staking\");\n require(rate < type(uint240).max, \"Max rate exceeded\");\n require(index < 2**merkleProof.length, \"Invalid index\");\n DropRoot storage dropRoot = dropRoots[stakeType];\n require(merkleProof.length == dropRoot.depth, \"Invalid proof\");\n\n // Compute the merkle root\n bytes32 node = keccak256(\n abi.encodePacked(\n index,\n stakeType,\n address(this),\n msg.sender,\n duration,\n rate,\n amount\n )\n );\n uint256 path = index;\n for (uint16 i = 0; i < merkleProof.length; i++) {\n if ((path & 0x01) == 1) {\n node = keccak256(abi.encodePacked(merkleProof[i], node));\n } else {\n node = keccak256(abi.encodePacked(node, merkleProof[i]));\n }\n path /= 2;\n }\n\n // Check the merkle proof\n require(node == dropRoot.hash, \"Stake not approved\");\n\n // verify that we haven't already staked\n require(\n !_airDroppedStakeClaimed(msg.sender, stakeType),\n \"Already staked\"\n );\n\n _stake(msg.sender, stakeType, duration, uint240(rate), amount);\n }\n\n /**\n * @dev Stake an approved amount of staking token into the contract.\n * User must have already approved the contract for specified amount.\n * @param amount Number of tokens to stake in 1e18\n * @param duration Number of seconds this stake will be held for\n */\n function stake(uint256 amount, uint256 duration) external requireLiquidity {\n // no checks are performed in this function since those are already present in _stakeWithChecks\n _stakeWithChecks(msg.sender, amount, duration);\n }\n\n /**\n * @dev Stake an approved amount of staking token into the contract. This function\n * can only be called by OGN token contract.\n * @param staker Address of the account that is creating the stake\n * @param amount Number of tokens to stake in 1e18\n * @param duration Number of seconds this stake will be held for\n */\n function stakeWithSender(\n address staker,\n uint256 amount,\n uint256 duration\n ) external requireLiquidity returns (bool) {\n require(\n msg.sender == address(stakingToken),\n \"Only token contract can make this call\"\n );\n\n _stakeWithChecks(staker, amount, duration);\n return true;\n }\n\n /**\n * @dev Exit out of all possible stakes\n */\n function exit() external requireLiquidity {\n Stake[] storage stakes = userStakes[msg.sender];\n require(stakes.length > 0, \"Nothing staked\");\n\n uint256 totalWithdraw = 0;\n uint256 stakedAmount = 0;\n uint256 l = stakes.length;\n do {\n Stake storage exitStake = stakes[l - 1];\n // stop on the first ended stake that's already been paid\n if (exitStake.end < block.timestamp && exitStake.paid) {\n break;\n }\n //might not be ended\n if (exitStake.end < block.timestamp) {\n //we are paying out the stake\n exitStake.paid = true;\n totalWithdraw = totalWithdraw.add(_totalExpected(exitStake));\n stakedAmount = stakedAmount.add(exitStake.amount);\n }\n l--;\n } while (l > 0);\n require(totalWithdraw > 0, \"All stakes in lock-up\");\n\n totalOutstanding = totalOutstanding.sub(totalWithdraw);\n emit Withdrawn(msg.sender, totalWithdraw, stakedAmount);\n stakingToken.safeTransfer(msg.sender, totalWithdraw);\n }\n\n /**\n * @dev Use to transfer all the stakes of an account in the case that the account is compromised\n * Requires access to both the account itself and the transfer agent\n * @param _frmAccount the address to transfer from\n * @param _dstAccount the address to transfer to(must be a clean address with no stakes)\n * @param r r portion of the signature by the transfer agent\n * @param s s portion of the signature\n * @param v v portion of the signature\n */\n function transferStakes(\n address _frmAccount,\n address _dstAccount,\n bytes32 r,\n bytes32 s,\n uint8 v\n ) external {\n require(transferAgent == msg.sender, \"must be transfer agent\");\n Stake[] storage dstStakes = userStakes[_dstAccount];\n require(dstStakes.length == 0, \"Dest stakes must be empty\");\n require(_frmAccount != address(0), \"from account not set\");\n Stake[] storage stakes = userStakes[_frmAccount];\n require(stakes.length > 0, \"Nothing to transfer\");\n\n // matches ethers.signMsg(ethers.utils.solidityPack([string(4), address, adddress, address]))\n bytes32 hash = keccak256(\n abi.encodePacked(\n \"\\x19Ethereum Signed Message:\\n64\",\n abi.encodePacked(\n \"tran\",\n address(this),\n _frmAccount,\n _dstAccount\n )\n )\n );\n require(ecrecover(hash, v, r, s) == _frmAccount, \"Transfer not authed\");\n\n // copy the stakes into the dstAccount array and delete the old one\n userStakes[_dstAccount] = stakes;\n delete userStakes[_frmAccount];\n emit StakesTransfered(_frmAccount, _dstAccount, stakes.length);\n }\n\n /* ========== MODIFIERS ========== */\n\n function setPaused(bool _paused) external onlyGovernor {\n paused = _paused;\n emit Paused(msg.sender, paused);\n }\n\n /**\n * @dev Set new durations and rates will not effect existing stakes\n * @param _durations Array of durations in seconds\n * @param _rates Array of rates that corresponds to the durations (0.01 is 1%) in 1e18\n */\n function setDurationRates(\n uint256[] calldata _durations,\n uint256[] calldata _rates\n ) external onlyGovernor {\n _setDurationRates(_durations, _rates);\n }\n\n /**\n * @dev Set the agent that will authorize transfers\n * @param _agent Address of agent\n */\n function setTransferAgent(address _agent) external onlyGovernor {\n transferAgent = _agent;\n }\n\n /**\n * @dev Set air drop root for a specific stake type\n * @param _stakeType Type of staking must be greater than 0\n * @param _rootHash Root hash of the Merkle Tree\n * @param _proofDepth Depth of the Merklke Tree\n */\n function setAirDropRoot(\n uint8 _stakeType,\n bytes32 _rootHash,\n uint256 _proofDepth\n ) external onlyGovernor {\n require(_stakeType != USER_STAKE_TYPE, \"Cannot be normal staking\");\n dropRoots[_stakeType].hash = _rootHash;\n dropRoots[_stakeType].depth = _proofDepth;\n emit NewAirDropRootHash(_stakeType, _rootHash, _proofDepth);\n }\n\n /* ========== EVENTS ========== */\n\n event Staked(\n address indexed user,\n uint256 amount,\n uint256 duration,\n uint256 rate\n );\n event Withdrawn(address indexed user, uint256 amount, uint256 stakedAmount);\n event Paused(address indexed user, bool yes);\n event NewDurations(address indexed user, uint256[] durations);\n event NewRates(address indexed user, uint256[] rates);\n event NewAirDropRootHash(\n uint8 stakeType,\n bytes32 rootHash,\n uint256 proofDepth\n );\n event StakesTransfered(\n address indexed fromUser,\n address toUser,\n uint256 numStakes\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 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/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 { Governable } from \"../../governance/Governable.sol\";\nimport { IWETH9 } from \"../../interfaces/IWETH9.sol\";\n\n/**\n * @title Fee Accumulator for Native Staking SSV Strategy\n * @notice This contract is setup to receive fees from processing transactions on the beacon chain\n * which includes priority fees and any MEV rewards\n * @author Origin Protocol Inc\n */\ncontract FeeAccumulator is Governable {\n /// @dev ETH is sent to the collector address\n address public immutable COLLECTOR;\n /// @notice WETH token address\n address public immutable WETH_TOKEN_ADDRESS;\n\n error CallerNotCollector(address caller, address expectedCaller);\n\n // For future use\n uint256[50] private __gap;\n\n /**\n * @param _collector Address of the contract that collects the fees\n */\n constructor(address _collector, address _weth) {\n COLLECTOR = _collector;\n WETH_TOKEN_ADDRESS = _weth;\n }\n\n /*\n * @notice Asserts that the caller is the collector\n */\n function _assertIsCollector() internal view {\n if (msg.sender != COLLECTOR) {\n revert CallerNotCollector(msg.sender, COLLECTOR);\n }\n }\n\n /*\n * @notice Send all the ETH to the collector\n */\n function collect() external returns (uint256 wethReturned) {\n _assertIsCollector();\n wethReturned = address(this).balance;\n if (wethReturned > 0) {\n IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: wethReturned }();\n IWETH9(WETH_TOKEN_ADDRESS).transfer(COLLECTOR, wethReturned);\n }\n }\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\";\n\nimport { InitializableAbstractStrategy } from \"../../utils/InitializableAbstractStrategy.sol\";\nimport { IWETH9 } from \"../../interfaces/IWETH9.sol\";\nimport { FeeAccumulator } from \"./FeeAccumulator.sol\";\nimport { ValidatorAccountant } from \"./ValidatorAccountant.sol\";\nimport { Cluster } from \"../../interfaces/ISSVNetwork.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\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_ADDRESS;\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 public immutable FEE_ACCUMULATOR_ADDRESS;\n\n // For future use\n uint256[50] private __gap;\n\n error EmptyRecipient();\n error NotWeth();\n error InsuffiscientWethBalance(\n uint256 requiredBalance,\n uint256 availableBalance\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 _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 _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 address _feeAccumulator,\n address _beaconChainDepositContract\n )\n InitializableAbstractStrategy(_baseConfig)\n ValidatorAccountant(_wethAddress, _baseConfig.vaultAddress, _beaconChainDepositContract, _ssvNetwork)\n {\n SSV_TOKEN_ADDRESS = _ssvToken;\n FEE_ACCUMULATOR_ADDRESS = _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 return the WETH balance on the contract that can be used to for beacon chain\n /// staking - staking on the validators. Because WETH on this contract can be present as\n /// a result of deposits and beacon chain rewards this function needs to return only WETH\n /// that is present due to deposits.\n function getWETHBalanceEligibleForStaking()\n public\n view\n override\n returns (uint256 _amount)\n {\n // if below amount results in a negative number there is a bug with accounting\n _amount =\n IWETH9(WETH_TOKEN_ADDRESS).balanceOf(address(this)) -\n beaconChainRewardWETH;\n }\n\n /// @notice Collect accumulated WETH & SSV tokens and send to the Harvester.\n function collectRewardTokens()\n external\n virtual\n override\n onlyHarvester\n nonReentrant\n {\n // collect WETH from fee collector and wrap it into WETH\n uint256 wethCollected = FeeAccumulator(FEE_ACCUMULATOR_ADDRESS)\n .collect();\n\n /* add up the WETH collected from the fee accumulator to beaconChainRewardWETH\n * so it can be sent to the harvester in one swoop in the \"_collectRewardTokens\"\n * step.\n */\n beaconChainRewardWETH += wethCollected;\n _collectRewardTokens();\n }\n\n /// @dev Need to override this function since the strategy doesn't allow for all the WETH\n /// to be collected. Some might be there as a result of deposit and is waiting for the Registrar\n /// to be deposited to the validators.\n function _collectRewardTokens() internal override {\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 if (address(rewardToken) == WETH_TOKEN_ADDRESS) {\n if (beaconChainRewardWETH > balance) {\n revert InsuffiscientWethBalance(\n beaconChainRewardWETH,\n balance\n );\n }\n\n // only allow for the WETH that is part of beacon chain rewards to be harvested\n balance = beaconChainRewardWETH;\n // reset the counter keeping track of beacon chain WETH rewards\n beaconChainRewardWETH = 0;\n }\n\n emit RewardTokenCollected(\n harvesterAddress,\n address(rewardToken),\n balance\n );\n rewardToken.safeTransfer(harvesterAddress, balance);\n }\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 function deposit(address _asset, uint256 _amount)\n external\n override\n onlyVault\n nonReentrant\n {\n _deposit(_asset, _amount);\n }\n\n /// @dev Deposit WETH to this contract to enable automated action to stake it\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 Deposit the entire balance of WETH asset in the strategy into the underlying platform\n function depositAll() external override onlyVault nonReentrant {\n uint256 wethBalance = IERC20(WETH_TOKEN_ADDRESS).balanceOf(\n address(this)\n );\n if (wethBalance > 0) {\n _deposit(WETH_TOKEN_ADDRESS, wethBalance);\n }\n }\n\n /// @notice Withdraw WETH from this contract. Used only if some WETH for is lingering on the contract. That\n /// can happen when:\n /// - the deposit was not a multiple of 32 WETH\n /// - someone sent WETH directly to this contract\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 _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 if (_recipient == address(0)) {\n revert EmptyRecipient();\n }\n\n emit Withdrawal(_asset, address(0), _amount);\n IERC20(_asset).safeTransfer(_recipient, _amount);\n }\n\n /// @notice Remove all supported assets from the underlying platform and send them to Vault contract.\n function withdrawAll() external override onlyVaultOrGovernor nonReentrant {\n uint256 wethBalance = IERC20(WETH_TOKEN_ADDRESS).balanceOf(\n address(this)\n );\n if (wethBalance > 0) {\n _withdraw(vaultAddress, WETH_TOKEN_ADDRESS, wethBalance);\n }\n }\n\n function _abstractSetPToken(address _asset, address) internal override {}\n\n /// @notice Returns the total value of (W)ETH that is staked to the validators\n /// and also present on the native staking and fee accumulator contracts\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 if (_asset != WETH_TOKEN_ADDRESS) {\n revert NotWeth();\n }\n\n balance = activeDepositedValidators * 32 ether;\n balance += beaconChainRewardWETH;\n balance += FEE_ACCUMULATOR_ADDRESS.balance;\n }\n\n function pause() external onlyStrategist {\n _pause();\n }\n\n /// @dev Retuns bool indicating whether asset is supported by strategy\n /// @param _asset Address of the asset\n function supportsAsset(address _asset) public view override returns (bool) {\n return _asset == WETH_TOKEN_ADDRESS;\n }\n\n /// @notice Approve the spending of all assets\n /// @dev 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_ADDRESS).approve(\n SSV_NETWORK_ADDRESS,\n type(uint256).max\n );\n }\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 fron-running can't DOS our maintenance service\n /// that tries to top us SSV tokens. \n function depositSSV(\n uint64[] memory operatorIds,\n uint256 amount,\n Cluster memory cluster\n ) \n onlyStrategist\n external {\n // address SSV_NETWORK_ADDRESS = lrtConfig.getContract(LRTConstants.SSV_NETWORK);\n // ISSVNetwork(SSV_NETWORK_ADDRESS).deposit(address(this), operatorIds, amount, cluster);\n }\n}\n" + }, + "contracts/strategies/NativeStaking/ValidatorAccountant.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { Pausable } from \"@openzeppelin/contracts/security/Pausable.sol\";\nimport { ValidatorRegistrator } from \"./ValidatorRegistrator.sol\";\nimport { IWETH9 } from \"../../interfaces/IWETH9.sol\";\n\n/// @title Accountant of the rewards Beacon Chain ETH\n/// @notice This contract contains the logic to attribute the Beacon Chain swept ETH either to full\n/// or partial withdrawals\n/// @author Origin Protocol Inc\nabstract contract ValidatorAccountant is ValidatorRegistrator {\n address public immutable VAULT_ADDRESS;\n\n /// @dev The WETH present on this contract will come from 2 sources:\n /// - as a result of deposits from the VaultAdmin\n /// - accounting function converting beaconChain rewards from ETH to WETH\n ///\n /// We need to be able to keep a separate accounting of the WETH so we understand how much we can pass oh to\n /// the harvester as a consequence of rewards harvesting and how much registrator can pick up as a result of WETH\n /// deposit into the strategy contract.\n /// To achieve this the beacon chain rewards are accounted for using below variable, all other WETH is assumed to be\n /// present as a result of a deposit.\n uint256 public beaconChainRewardWETH = 0;\n\n /// @dev start of fuse interval\n uint256 public fuseIntervalStart = 0;\n /// @dev end of fuse interval\n uint256 public fuseIntervalEnd = 0;\n /// @dev Governor that can manually correct the accounting\n address public accountingGovernor;\n /// @dev Strategist that can pause the accounting\n address public strategist;\n\n uint256[50] private __gap;\n\n event FuseIntervalUpdated(\n uint256 oldStart,\n uint256 oldEnd,\n uint256 start,\n uint256 end\n );\n event AccuntingFullyWithdrawnValidator(\n uint256 noOfValidators,\n uint256 remainingValidators,\n uint256 wethSentToVault\n );\n event AccuntingValidatorSlashed(\n uint256 remainingValidators,\n uint256 wethSentToVault\n );\n event AccountingGovernorAddressChanged(\n address oldAddress,\n address newAddress\n );\n event AccountingBeaconChainRewards(uint256 amount);\n event StrategistAddressChanged(\n address oldStrategist,\n address newStrategist\n );\n\n event AccountingManuallyFixed(\n uint256 oldActiveDepositedValidators,\n uint256 activeDepositedValidators,\n uint256 oldBeaconChainRewardWETH,\n uint256 beaconChainRewardWETH,\n uint256 ethToWeth,\n uint256 wethToBeSentToVault\n );\n\n error UnexpectedEthAccountingInterval(uint256 errorneousEthAmount);\n error ManualFixAccountingThresholdReached();\n error FuseIntervalValuesIncorrect();\n error NotPaused();\n error InsuffiscientETHbalance();\n\n /// @dev Throws if called by any account other than the Accounting Governor\n modifier onlyAccountingGovernor() {\n require(\n msg.sender == accountingGovernor,\n \"Caller is not the Accounting Governor\"\n );\n _;\n }\n\n /// @dev Throws if called by any account other than the Strategist\n modifier onlyStrategist() {\n require(msg.sender == strategist, \"Caller is not the Strategist\");\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 constructor(address _wethAddress, address _vaultAddress, address _beaconChainDepositContract, address _ssvNetwork)\n ValidatorRegistrator(_wethAddress, _beaconChainDepositContract, _ssvNetwork) {\n VAULT_ADDRESS = _vaultAddress;\n }\n\n function setAccountingGovernor(address _address) external onlyGovernor {\n emit AccountingGovernorAddressChanged(accountingGovernor, _address);\n accountingGovernor = _address;\n }\n\n function setStrategist(address _address) external onlyGovernor {\n emit StrategistAddressChanged(strategist, _address);\n strategist = _address;\n }\n\n /// @notice set fuse interval values\n function setFuseInterval(\n uint256 _fuseIntervalStart,\n uint256 _fuseIntervalEnd\n ) external onlyGovernor {\n if (\n _fuseIntervalStart > _fuseIntervalEnd ||\n _fuseIntervalStart >= 32 ether ||\n _fuseIntervalEnd >= 32 ether ||\n _fuseIntervalEnd - _fuseIntervalStart < 4 ether\n ) {\n revert FuseIntervalValuesIncorrect();\n }\n\n emit FuseIntervalUpdated(\n fuseIntervalStart,\n fuseIntervalEnd,\n _fuseIntervalStart,\n _fuseIntervalEnd\n );\n\n fuseIntervalStart = _fuseIntervalStart;\n fuseIntervalEnd = _fuseIntervalEnd;\n }\n\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 the accounting\n /// function will treat that ETH as a Beacon Chain Reward ETH.\n /// On the contrary if after dividing by 32 the ETH remaining on the contract falls between fuseIntervalEnd and 32 the\n /// 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 function doAccounting() external onlyRegistrator returns (bool accountingValid) {\n uint256 ethBalance = address(this).balance;\n uint256 MAX_STAKE = 32 ether;\n accountingValid = true;\n\n // send the WETH that is from fully withdrawn validators to the Vault\n if (ethBalance >= MAX_STAKE) {\n uint256 fullyWithdrawnValidators = ethBalance / MAX_STAKE;\n activeDepositedValidators -= fullyWithdrawnValidators;\n\n uint256 wethToVault = MAX_STAKE * fullyWithdrawnValidators;\n IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: wethToVault }();\n IWETH9(WETH_TOKEN_ADDRESS).transfer(VAULT_ADDRESS, wethToVault);\n\n emit AccuntingFullyWithdrawnValidator(\n fullyWithdrawnValidators,\n activeDepositedValidators,\n wethToVault\n );\n }\n\n uint256 ethRemaining = address(this).balance;\n // should never happen\n if (ethRemaining > 32 ether) {\n revert UnexpectedEthAccountingInterval(ethRemaining);\n }\n\n // Beacon chain rewards swept (partial validator withdrawals)\n if (ethRemaining <= fuseIntervalStart) {\n IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: ethRemaining }();\n beaconChainRewardWETH += ethRemaining;\n emit AccountingBeaconChainRewards(ethRemaining);\n }\n // Beacon chain rewards swept but also a slashed validator fully exited\n else if (ethRemaining >= fuseIntervalEnd) {\n IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: ethRemaining }();\n IWETH9(WETH_TOKEN_ADDRESS).transfer(VAULT_ADDRESS, ethRemaining);\n activeDepositedValidators -= 1;\n\n emit AccuntingValidatorSlashed(\n activeDepositedValidators,\n ethRemaining\n );\n }\n // Oh no... Fuse is blown. The governor (Multisig not OGV Governor) needs to set the\n // record straight by manually set the accounting values.\n else {\n // will emit a paused event\n _pause();\n accountingValid = false;\n }\n }\n\n /// @dev allow the accounting governor to fix the accounting of this strategy and unpause\n /// @param _activeDepositedValidators the override value of activeDepositedValidators\n /// @param _ethToWeth the amount of ETH to be converted to WETH\n /// @param _wethToBeSentToVault the amount of WETH to be sent to the Vault\n /// @param _beaconChainRewardWETH the override value for beaconChainRewardWETH\n /// @param _ethThresholdCheck maximum allowed ETH balance on the contract for the function to run\n /// @param _wethThresholdCheck maximum allowed WETH balance on the contract for the function to run\n /// the above 2 checks are done so transaction doesn't get front run and cause\n /// unexpected behaviour\n function manuallyFixAccounting(\n uint256 _activeDepositedValidators,\n uint256 _ethToWeth,\n uint256 _wethToBeSentToVault,\n uint256 _beaconChainRewardWETH,\n uint256 _ethThresholdCheck,\n uint256 _wethThresholdCheck\n ) external onlyAccountingGovernor {\n if (!paused()) {\n revert NotPaused();\n }\n\n uint256 ethBalance = address(this).balance;\n uint256 wethBalance = IWETH9(WETH_TOKEN_ADDRESS).balanceOf(\n address(this)\n );\n\n if (\n ethBalance > _ethThresholdCheck || wethBalance > _wethThresholdCheck\n ) {\n revert ManualFixAccountingThresholdReached();\n }\n\n emit AccountingManuallyFixed(\n activeDepositedValidators,\n _activeDepositedValidators,\n beaconChainRewardWETH,\n _beaconChainRewardWETH,\n _ethToWeth,\n _wethToBeSentToVault\n );\n\n activeDepositedValidators = _activeDepositedValidators;\n beaconChainRewardWETH = _beaconChainRewardWETH;\n if (_ethToWeth > 0) {\n if (ethBalance < _ethToWeth) {\n revert InsuffiscientETHbalance();\n }\n IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: _ethToWeth }();\n }\n if (_wethToBeSentToVault > 0) {\n IWETH9(WETH_TOKEN_ADDRESS).transfer(\n VAULT_ADDRESS,\n _wethToBeSentToVault\n );\n }\n\n _unpause();\n }\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 { 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 validators\n * @author Origin Protocol Inc\n */\nabstract contract ValidatorRegistrator is Governable, Pausable {\n /// @notice The Wrapped ETH (WETH) contract address\n address public immutable WETH_TOKEN_ADDRESS;\n /// @notice Address of the beacon chain deposit contract\n address public immutable BEACON_CHAIN_DEPOSIT_CONTRACT;\n /// @notice SSV Network contract used to interface with\n address public immutable SSV_NETWORK_ADDRESS; \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 activeDepositedValidators;\n /// @notice State of the validators keccak256(pubKey) => state\n mapping(bytes32 => VALIDATOR_STATE) public validatorsStates;\n\n // For future use\n uint256[50] private __gap;\n\n enum VALIDATOR_STATE {\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 RegistratorAddressChanged(address oldAddress, address newAddress);\n event ETHStaked(bytes pubkey, uint256 amount, bytes withdrawal_credentials);\n event SSVValidatorRegistered(bytes pubkey, uint64[] operatorIds);\n event SSVValidatorExitInitiated(bytes pubkey, uint64[] operatorIds);\n event SSVValidatorExitCompleted(bytes pubkey, uint64[] operatorIds);\n\n error InsufficientWETH(uint256 wethBalance, uint256 requiredWethBalance);\n error ValidatorInUnexpectedState(bytes pubkey, VALIDATOR_STATE state);\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 /// @param _wethAddress Address of the Erc20 WETH Token contract\n /// @param _beaconChainDepositContract Address of the beacon chain deposit contract\n /// @param _ssvNetwork Address of the SSV Network contract\n constructor(address _wethAddress, address _beaconChainDepositContract, address _ssvNetwork) {\n WETH_TOKEN_ADDRESS = _wethAddress;\n BEACON_CHAIN_DEPOSIT_CONTRACT = _beaconChainDepositContract;\n SSV_NETWORK_ADDRESS = _ssvNetwork;\n }\n\n /// @notice Set the address of the registrator\n function setRegistratorAddress(address _address) external onlyGovernor {\n emit RegistratorAddressChanged(validatorRegistrator, _address);\n validatorRegistrator = _address;\n }\n\n /// @notice return the WETH balance on the contract that can be used to for beacon chain\n /// staking - staking on the validators\n function getWETHBalanceEligibleForStaking()\n public\n view\n virtual\n returns (uint256 _amount);\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 /// @dev Only accounts with the Operator role can call this function.\n function stakeEth(ValidatorStakeData[] calldata validators) \n onlyRegistrator\n whenNotPaused\n external {\n uint256 requiredWETH = validators.length * 32 ether;\n uint256 wethBalance = getWETHBalanceEligibleForStaking();\n if (wethBalance < requiredWETH) {\n revert InsufficientWETH(wethBalance, requiredWETH);\n }\n\n // Convert WETH asset to native ETH\n IWETH9(WETH_TOKEN_ADDRESS).withdraw(wethBalance);\n\n // For each validator\n for (uint256 i = 0; i < validators.length;) {\n bytes32 pubkeyHash = keccak256(validators[i].pubkey);\n VALIDATOR_STATE currentState = validatorsStates[pubkeyHash];\n\n if (currentState != VALIDATOR_STATE.REGISTERED) {\n revert ValidatorInUnexpectedState(validators[i].pubkey, currentState);\n }\n\n _stakeEth(validators[i].pubkey, validators[i].signature, validators[i].depositDataRoot);\n validatorsStates[pubkeyHash] = VALIDATOR_STATE.STAKED;\n\n unchecked {\n ++i;\n }\n }\n }\n\n /// @dev Deposit WETH to the beacon chain deposit contract\n /// @dev The public functions that call this internal function are responsible for access control.\n function _stakeEth(bytes calldata pubkey, bytes calldata signature, bytes32 depositDataRoot) internal {\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 withdrawal_credentials = abi.encodePacked(bytes1(0x01), bytes11(0), address(this));\n IDepositContract(BEACON_CHAIN_DEPOSIT_CONTRACT).deposit(\n pubkey, withdrawal_credentials, signature, depositDataRoot\n );\n\n activeDepositedValidators += 1;\n emit ETHStaked(pubkey, 32 ether, withdrawal_credentials);\n\n }\n\n /// @dev Registers a new validator in the SSV Cluster\n function registerSsvValidator(\n bytes calldata publicKey,\n uint64[] calldata operatorIds,\n bytes calldata sharesData,\n uint256 amount,\n Cluster calldata cluster\n )\n external\n onlyRegistrator\n whenNotPaused\n {\n ISSVNetwork(SSV_NETWORK_ADDRESS).registerValidator(publicKey, operatorIds, sharesData, amount, cluster);\n validatorsStates[keccak256(publicKey)] = VALIDATOR_STATE.REGISTERED;\n emit SSVValidatorRegistered(publicKey, operatorIds);\n }\n\n /// @dev Exit a validator from the Beacon chain.\n /// The staked ETH will be sent to the EigenPod.\n function exitSsvValidator(\n bytes calldata publicKey,\n uint64[] calldata operatorIds\n )\n external\n onlyRegistrator\n whenNotPaused\n { \n VALIDATOR_STATE currentState = validatorsStates[keccak256(publicKey)];\n if (currentState != VALIDATOR_STATE.STAKED) {\n revert ValidatorInUnexpectedState(publicKey, currentState);\n }\n\n ISSVNetwork(SSV_NETWORK_ADDRESS).exitValidator(publicKey, operatorIds);\n emit SSVValidatorExitInitiated(publicKey, operatorIds);\n\n validatorsStates[keccak256(publicKey)] = VALIDATOR_STATE.EXITING;\n }\n\n /// @dev 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 function removeSsvValidator(\n bytes calldata publicKey,\n uint64[] calldata operatorIds,\n Cluster calldata cluster\n )\n external\n onlyRegistrator\n whenNotPaused\n {\n VALIDATOR_STATE currentState = validatorsStates[keccak256(publicKey)];\n if (currentState != VALIDATOR_STATE.EXITING) {\n revert ValidatorInUnexpectedState(publicKey, currentState);\n }\n\n ISSVNetwork(SSV_NETWORK_ADDRESS).removeValidator(publicKey, operatorIds, cluster);\n emit SSVValidatorExitCompleted(publicKey, operatorIds);\n\n validatorsStates[keccak256(publicKey)] = VALIDATOR_STATE.EXIT_COMPLETE;\n }\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/swapper/Swapper1InchV5.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @notice 1Inch Pathfinder V5 implementation of the general ISwapper interface.\n * @author Origin Protocol Inc\n * @dev It is possible that dust token amounts are left in this contract after a swap.\n * This can happen with some tokens that don't send the full transfer amount.\n * These dust amounts can build up over time and be used by anyone who calls the `swap` function.\n */\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nimport { IAggregationExecutor, IOneInchRouter, SwapDescription } from \"../interfaces/IOneInch.sol\";\nimport { ISwapper } from \"../interfaces/ISwapper.sol\";\n\ncontract Swapper1InchV5 is ISwapper {\n using SafeERC20 for IERC20;\n\n /// @notice 1Inch router contract to give allowance to perform swaps\n address public constant SWAP_ROUTER =\n 0x1111111254EEB25477B68fb85Ed929f73A960582;\n\n // swap(address,(address,address,address,address,uint256,uint256,uint256),bytes,bytes)\n bytes4 internal constant SWAP_SELECTOR = 0x12aa3caf;\n // unoswapTo(address,address,uint256,uint256,uint256[])\n bytes4 internal constant UNISWAP_SELECTOR = 0xf78dc253;\n // uniswapV3SwapTo(address,uint256,uint256,uint256[])\n bytes4 internal constant UNISWAPV3_SELECTOR = 0xbc80f1a8;\n\n /**\n * @notice Strategist swaps assets sitting in the contract of the `assetHolder`.\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 RLP encoded executer address and bytes data. This is re-encoded tx.data from 1Inch swap API\n */\n function swap(\n address _fromAsset,\n address _toAsset,\n uint256 _fromAssetAmount,\n uint256 _minToAssetAmount,\n bytes calldata _data\n ) external override returns (uint256 toAssetAmount) {\n // Decode the function selector from the RLP encoded _data param\n bytes4 swapSelector = bytes4(_data[:4]);\n\n if (swapSelector == SWAP_SELECTOR) {\n // Decode the executer address and data from the RLP encoded _data param\n (, address executer, bytes memory executerData) = abi.decode(\n _data,\n (bytes4, address, bytes)\n );\n SwapDescription memory swapDesc = SwapDescription({\n srcToken: IERC20(_fromAsset),\n dstToken: IERC20(_toAsset),\n srcReceiver: payable(executer),\n dstReceiver: payable(msg.sender),\n amount: _fromAssetAmount,\n minReturnAmount: _minToAssetAmount,\n flags: 4 // 1st bit _PARTIAL_FILL, 2nd bit _REQUIRES_EXTRA_ETH, 3rd bit _SHOULD_CLAIM\n });\n (toAssetAmount, ) = IOneInchRouter(SWAP_ROUTER).swap(\n IAggregationExecutor(executer),\n swapDesc,\n hex\"\",\n executerData\n );\n } else if (swapSelector == UNISWAP_SELECTOR) {\n // Need to get the Uniswap pools data from the _data param\n (, uint256[] memory pools) = abi.decode(_data, (bytes4, uint256[]));\n toAssetAmount = IOneInchRouter(SWAP_ROUTER).unoswapTo(\n payable(msg.sender),\n IERC20(_fromAsset),\n _fromAssetAmount,\n _minToAssetAmount,\n pools\n );\n } else if (swapSelector == UNISWAPV3_SELECTOR) {\n // Need to get the Uniswap pools data from the _data param\n // slither-disable-next-line uninitialized-storage\n (, uint256[] memory pools) = abi.decode(_data, (bytes4, uint256[]));\n toAssetAmount = IOneInchRouter(SWAP_ROUTER).uniswapV3SwapTo(\n payable(msg.sender),\n _fromAssetAmount,\n _minToAssetAmount,\n pools\n );\n } else {\n revert(\"Unsupported swap function\");\n }\n }\n\n /**\n * @notice Approve assets for swapping.\n * @param _assets Array of token addresses to approve.\n * @dev unlimited approval is used as no tokens sit in this contract outside a transaction.\n */\n function approveAssets(address[] memory _assets) external {\n for (uint256 i = 0; i < _assets.length; ++i) {\n // Give the 1Inch router approval to transfer unlimited assets\n IERC20(_assets[i]).safeApprove(SWAP_ROUTER, type(uint256).max);\n }\n }\n}\n" + }, + "contracts/timelock/Timelock.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @title OUSD Timelock Contract\n * @author Origin Protocol Inc\n */\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\n\ninterface CapitalPausable {\n function pauseCapital() external;\n\n function unpauseCapital() external;\n}\n\ncontract Timelock {\n using SafeMath for uint256;\n\n event NewAdmin(address indexed newAdmin);\n event NewPendingAdmin(address indexed newPendingAdmin);\n event NewDelay(uint256 indexed newDelay);\n event CancelTransaction(\n bytes32 indexed txHash,\n address indexed target,\n string signature,\n bytes data,\n uint256 eta\n );\n event ExecuteTransaction(\n bytes32 indexed txHash,\n address indexed target,\n string signature,\n bytes data,\n uint256 eta\n );\n event QueueTransaction(\n bytes32 indexed txHash,\n address indexed target,\n string signature,\n bytes data,\n uint256 eta\n );\n\n uint256 public constant GRACE_PERIOD = 3 days;\n uint256 public constant MINIMUM_DELAY = 1 minutes;\n uint256 public constant MAXIMUM_DELAY = 2 days;\n\n address public admin;\n address public pendingAdmin;\n uint256 public delay;\n\n mapping(bytes32 => bool) public queuedTransactions;\n\n /**\n * @dev Throws if called by any account other than the Admin.\n */\n modifier onlyAdmin() {\n require(msg.sender == admin, \"Caller is not the admin\");\n _;\n }\n\n constructor(address admin_, uint256 delay_) {\n require(\n delay_ >= MINIMUM_DELAY,\n \"Timelock::constructor: Delay must exceed minimum delay.\"\n );\n require(\n delay_ <= MAXIMUM_DELAY,\n \"Timelock::setDelay: Delay must not exceed maximum delay.\"\n );\n\n admin = admin_;\n delay = delay_;\n }\n\n function setDelay(uint256 delay_) public {\n require(\n msg.sender == address(this),\n \"Timelock::setDelay: Call must come from Timelock.\"\n );\n require(\n delay_ >= MINIMUM_DELAY,\n \"Timelock::setDelay: Delay must exceed minimum delay.\"\n );\n require(\n delay_ <= MAXIMUM_DELAY,\n \"Timelock::setDelay: Delay must not exceed maximum delay.\"\n );\n delay = delay_;\n\n emit NewDelay(delay);\n }\n\n function acceptAdmin() public {\n require(\n msg.sender == pendingAdmin,\n \"Timelock::acceptAdmin: Call must come from pendingAdmin.\"\n );\n admin = msg.sender;\n pendingAdmin = address(0);\n\n emit NewAdmin(admin);\n }\n\n function setPendingAdmin(address pendingAdmin_) public onlyAdmin {\n pendingAdmin = pendingAdmin_;\n\n emit NewPendingAdmin(pendingAdmin);\n }\n\n function queueTransaction(\n address target,\n string memory signature,\n bytes memory data,\n uint256 eta\n ) internal returns (bytes32) {\n require(\n msg.sender == admin,\n \"Timelock::queueTransaction: Call must come from admin.\"\n );\n require(\n eta >= getBlockTimestamp().add(delay),\n \"Timelock::queueTransaction: Estimated execution block must satisfy delay.\"\n );\n\n bytes32 txHash = keccak256(\n abi.encode(target, signature, keccak256(data), eta)\n );\n queuedTransactions[txHash] = true;\n\n emit QueueTransaction(txHash, target, signature, data, eta);\n return txHash;\n }\n\n function cancelTransaction(\n address target,\n string memory signature,\n bytes memory data,\n uint256 eta\n ) internal {\n require(\n msg.sender == admin,\n \"Timelock::cancelTransaction: Call must come from admin.\"\n );\n\n bytes32 txHash = keccak256(\n abi.encode(target, signature, keccak256(data), eta)\n );\n queuedTransactions[txHash] = false;\n\n emit CancelTransaction(txHash, target, signature, data, eta);\n }\n\n function _getRevertMsg(bytes memory _returnData)\n internal\n pure\n returns (string memory)\n {\n // If the _res length is less than 68, then the transaction failed\n // silently (without a revert message)\n if (_returnData.length < 68) return \"Transaction reverted silently\";\n\n // solhint-disable-next-line no-inline-assembly\n assembly {\n // Slice the sighash.\n _returnData := add(_returnData, 0x04)\n }\n return abi.decode(_returnData, (string));\n }\n\n function executeTransaction(\n address target,\n string memory signature,\n bytes memory data,\n uint256 eta\n ) internal returns (bytes memory) {\n require(\n msg.sender == admin,\n \"Timelock::executeTransaction: Call must come from admin.\"\n );\n\n bytes32 txHash = keccak256(\n abi.encode(target, signature, keccak256(data), eta)\n );\n require(\n queuedTransactions[txHash],\n \"Timelock::executeTransaction: Transaction hasn't been queued.\"\n );\n require(\n getBlockTimestamp() >= eta,\n \"Timelock::executeTransaction: Transaction hasn't surpassed time lock.\"\n );\n require(\n getBlockTimestamp() <= eta.add(GRACE_PERIOD),\n \"Timelock::executeTransaction: Transaction is stale.\"\n );\n\n queuedTransactions[txHash] = false;\n\n bytes memory callData;\n\n if (bytes(signature).length == 0) {\n callData = data;\n } else {\n callData = abi.encodePacked(\n bytes4(keccak256(bytes(signature))),\n data\n );\n }\n\n (bool success, bytes memory returnData) = target.call(callData);\n\n if (!success) {\n revert(_getRevertMsg(returnData));\n }\n\n emit ExecuteTransaction(txHash, target, signature, data, eta);\n\n return returnData;\n }\n\n function getBlockTimestamp() internal view returns (uint256) {\n // solium-disable-next-line security/no-block-members\n return block.timestamp;\n }\n\n function pauseCapital(address target) external {\n require(\n msg.sender == admin,\n \"Timelock::pauseCapital: Call must come from admin.\"\n );\n CapitalPausable(target).pauseCapital();\n }\n\n function unpauseCapital(address target) external {\n require(\n msg.sender == admin,\n \"Timelock::unpauseCapital: Call must come from admin.\"\n );\n CapitalPausable(target).unpauseCapital();\n }\n}\n" + }, + "contracts/token/BridgedWOETH.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { ERC20 } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport { AccessControlEnumerable } from \"@openzeppelin/contracts/access/AccessControlEnumerable.sol\";\nimport { Governable } from \"../governance/Governable.sol\";\nimport { Initializable } from \"../utils/Initializable.sol\";\n\ncontract BridgedWOETH is\n Governable,\n AccessControlEnumerable,\n Initializable,\n ERC20\n{\n bytes32 public constant MINTER_ROLE = keccak256(\"MINTER_ROLE\");\n bytes32 public constant BURNER_ROLE = keccak256(\"BURNER_ROLE\");\n\n constructor() ERC20(\"Wrapped OETH\", \"WOETH\") {\n // Nobody owns the implementation\n _setGovernor(address(0));\n }\n\n /**\n * @dev Initialize the proxy and set the Governor\n */\n function initialize() external initializer {\n // Governor can grant Minter/Burner roles\n _setupRole(DEFAULT_ADMIN_ROLE, _governor());\n }\n\n /**\n * @dev Mint tokens for `account`\n * @param account Address to mint tokens for\n * @param amount Amount of tokens to mint\n */\n function mint(address account, uint256 amount)\n external\n onlyRole(MINTER_ROLE)\n nonReentrant\n {\n _mint(account, amount);\n }\n\n /**\n * @dev Burns tokens from `account`\n * @param account Address to burn tokens from\n * @param amount Amount of tokens to burn\n */\n function burn(address account, uint256 amount)\n external\n onlyRole(BURNER_ROLE)\n nonReentrant\n {\n _burn(account, amount);\n }\n\n /**\n * @dev Burns tokens from `msg.sender`\n * @param amount Amount of tokens to burn\n */\n function burn(uint256 amount) external onlyRole(BURNER_ROLE) nonReentrant {\n _burn(msg.sender, amount);\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual override returns (string memory) {\n return \"Wrapped OETH\";\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 \"WOETH\";\n }\n\n /**\n * @dev Returns the decimals of the token\n */\n function decimals() public view virtual override returns (uint8) {\n return 18;\n }\n}\n" + }, + "contracts/token/OETH.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { OUSD } from \"./OUSD.sol\";\n\n/**\n * @title OETH Token Contract\n * @author Origin Protocol Inc\n */\ncontract OETH is 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/token/OUSDResolutionUpgrade.sol": { + "content": "pragma solidity ^0.8.0;\n\ncontract OUSDResolutionUpgrade {\n enum RebaseOptions {\n NotSet,\n OptOut,\n OptIn\n }\n\n // From Initializable\n bool private initialized;\n bool private initializing;\n uint256[50] private ______igap;\n\n // From InitializableERC20Detailed\n uint256[100] private _____ugap;\n string private _name;\n string private _symbol;\n uint8 private _decimals;\n\n // From OUSD\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 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 /**\n * @return High resolution rebasingCreditsPerToken\n */\n function rebasingCreditsPerToken() public view returns (uint256) {\n return _rebasingCreditsPerToken / RESOLUTION_INCREASE;\n }\n\n /**\n * @return High 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 function upgradeGlobals() external {\n require(isUpgraded[address(0)] == 0, \"Globals already upgraded\");\n require(_rebasingCredits > 0, \"Sanity _rebasingCredits\");\n require(\n _rebasingCreditsPerToken > 0,\n \"Sanity _rebasingCreditsPerToken\"\n );\n isUpgraded[address(0)] = 1;\n _rebasingCredits = _rebasingCredits * RESOLUTION_INCREASE;\n _rebasingCreditsPerToken =\n _rebasingCreditsPerToken *\n RESOLUTION_INCREASE;\n }\n\n function upgradeAccounts(address[] calldata accounts) external {\n for (uint256 i = 0; i < accounts.length; i++) {\n address account = accounts[i];\n require(account != address(0), \"Reserved\");\n require(isUpgraded[account] == 0, \"Account already upgraded\");\n isUpgraded[account] = 1;\n\n // Handle special for non-rebasing accounts\n uint256 nrc = nonRebasingCreditsPerToken[account];\n if (nrc > 0) {\n require(nrc < 1e18, \"Account already highres\");\n nonRebasingCreditsPerToken[account] = nrc * RESOLUTION_INCREASE;\n }\n // Upgrade balance\n uint256 balance = _creditBalances[account];\n require(balance > 0, \"Will not upgrade zero balance\");\n _creditBalances[account] = balance * RESOLUTION_INCREASE;\n }\n }\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 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" + }, + "contracts/token/WOETH.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { ERC4626 } from \"../../lib/openzeppelin/contracts/token/ERC20/extensions/ERC4626.sol\";\nimport { ERC20 } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nimport { Governable } from \"../governance/Governable.sol\";\nimport { Initializable } from \"../utils/Initializable.sol\";\nimport { OETH } from \"./OETH.sol\";\n\n/**\n * @title OETH Token Contract\n * @author Origin Protocol Inc\n */\n\ncontract WOETH is ERC4626, Governable, Initializable {\n using SafeERC20 for IERC20;\n\n constructor(\n ERC20 underlying_,\n string memory name_,\n string memory symbol_\n ) ERC20(name_, symbol_) ERC4626(underlying_) Governable() {}\n\n /**\n * @notice Enable OETH rebasing for this contract\n */\n function initialize() external onlyGovernor initializer {\n OETH(address(asset())).rebaseOptIn();\n }\n\n function name() public view override returns (string memory) {\n return \"Wrapped OETH\";\n }\n\n function symbol() public view override returns (string memory) {\n return \"WOETH\";\n }\n\n /**\n * @notice Transfer token to governor. Intended for recovering tokens stuck in\n * contract, i.e. mistaken sends. Cannot transfer OETH\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(asset_ != address(asset()), \"Cannot collect OETH\");\n IERC20(asset_).safeTransfer(governor(), amount_);\n }\n}\n" + }, + "contracts/token/WrappedOusd.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { ERC4626 } from \"../../lib/openzeppelin/contracts/token/ERC20/extensions/ERC4626.sol\";\nimport { ERC20 } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nimport { Governable } from \"../governance/Governable.sol\";\nimport { Initializable } from \"../utils/Initializable.sol\";\nimport { OUSD } from \"./OUSD.sol\";\n\ncontract WrappedOusd is ERC4626, Governable, Initializable {\n using SafeERC20 for IERC20;\n\n constructor(\n ERC20 underlying_,\n string memory name_,\n string memory symbol_\n ) ERC20(name_, symbol_) ERC4626(underlying_) Governable() {}\n\n /**\n * @notice Enable OUSD rebasing for this contract\n */\n function initialize() external onlyGovernor initializer {\n OUSD(address(asset())).rebaseOptIn();\n }\n\n function name() public view override returns (string memory) {\n return \"Wrapped OUSD\";\n }\n\n function symbol() public view override returns (string memory) {\n return \"WOUSD\";\n }\n\n /**\n * @notice Transfer token to governor. Intended for recovering tokens stuck in\n * contract, i.e. mistaken sends. Cannot transfer OUSD\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(asset_ != address(asset()), \"Cannot collect OUSD\");\n IERC20(asset_).safeTransfer(governor(), amount_);\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 { VaultAdmin } from \"./VaultAdmin.sol\";\n\n/**\n * @title OETH VaultAdmin Contract\n * @author Origin Protocol Inc\n */\ncontract OETHVaultAdmin is VaultAdmin {\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\";\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" + }, + "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 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" + }, + "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" + }, + "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 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" + }, + "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/contracts/token/ERC20/extensions/ERC4626.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\nimport { IERC4626 } from \"../../../../interfaces/IERC4626.sol\";\nimport { ERC20 } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { IERC20Metadata } from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\n\n// From Open Zeppelin draft PR commit:\n// fac43034dca85ff539db3fc8aa2a7084b843d454\n// https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3171\n\nabstract contract ERC4626 is ERC20, IERC4626 {\n IERC20Metadata private immutable _asset;\n\n constructor(IERC20Metadata __asset) {\n _asset = __asset;\n }\n\n /** @dev See {IERC4262-asset} */\n function asset() public view virtual override returns (address) {\n return address(_asset);\n }\n\n /** @dev See {IERC4262-totalAssets} */\n function totalAssets() public view virtual override returns (uint256) {\n return _asset.balanceOf(address(this));\n }\n\n /**\n * @dev See {IERC4262-convertToShares}\n *\n * Will revert if asserts > 0, totalSupply > 0 and totalAssets = 0. That corresponds to a case where any asset\n * would represent an infinite amout of shares.\n */\n function convertToShares(uint256 assets) public view virtual override returns (uint256 shares) {\n uint256 supply = totalSupply();\n\n return\n (assets == 0 || supply == 0)\n ? (assets * 10**decimals()) / 10**_asset.decimals()\n : (assets * supply) / totalAssets();\n }\n\n /** @dev See {IERC4262-convertToAssets} */\n function convertToAssets(uint256 shares) public view virtual override returns (uint256 assets) {\n uint256 supply = totalSupply();\n\n return (supply == 0) ? (shares * 10**_asset.decimals()) / 10**decimals() : (shares * totalAssets()) / supply;\n }\n\n /** @dev See {IERC4262-maxDeposit} */\n function maxDeposit(address) public view virtual override returns (uint256) {\n return type(uint256).max;\n }\n\n /** @dev See {IERC4262-maxMint} */\n function maxMint(address) public view virtual override returns (uint256) {\n return type(uint256).max;\n }\n\n /** @dev See {IERC4262-maxWithdraw} */\n function maxWithdraw(address owner) public view virtual override returns (uint256) {\n return convertToAssets(balanceOf(owner));\n }\n\n /** @dev See {IERC4262-maxRedeem} */\n function maxRedeem(address owner) public view virtual override returns (uint256) {\n return balanceOf(owner);\n }\n\n /** @dev See {IERC4262-previewDeposit} */\n function previewDeposit(uint256 assets) public view virtual override returns (uint256) {\n return convertToShares(assets);\n }\n\n /** @dev See {IERC4262-previewMint} */\n function previewMint(uint256 shares) public view virtual override returns (uint256) {\n uint256 assets = convertToAssets(shares);\n return assets + (convertToShares(assets) < shares ? 1 : 0);\n }\n\n /** @dev See {IERC4262-previewWithdraw} */\n function previewWithdraw(uint256 assets) public view virtual override returns (uint256) {\n uint256 shares = convertToShares(assets);\n return shares + (convertToAssets(shares) < assets ? 1 : 0);\n }\n\n /** @dev See {IERC4262-previewRedeem} */\n function previewRedeem(uint256 shares) public view virtual override returns (uint256) {\n return convertToAssets(shares);\n }\n\n /** @dev See {IERC4262-deposit} */\n function deposit(uint256 assets, address receiver) public virtual override returns (uint256) {\n require(assets <= maxDeposit(receiver), \"ERC4626: deposit more then max\");\n\n address caller = _msgSender();\n uint256 shares = previewDeposit(assets);\n\n // if _asset is ERC777, transferFrom can call reenter BEFORE the transfer happens through\n // the tokensToSend hook, so we need to transfer before we mint to keep the invariants.\n SafeERC20.safeTransferFrom(_asset, caller, address(this), assets);\n _mint(receiver, shares);\n\n emit Deposit(caller, receiver, assets, shares);\n\n return shares;\n }\n\n /** @dev See {IERC4262-mint} */\n function mint(uint256 shares, address receiver) public virtual override returns (uint256) {\n require(shares <= maxMint(receiver), \"ERC4626: mint more then max\");\n\n address caller = _msgSender();\n uint256 assets = previewMint(shares);\n\n // if _asset is ERC777, transferFrom can call reenter BEFORE the transfer happens through\n // the tokensToSend hook, so we need to transfer before we mint to keep the invariants.\n SafeERC20.safeTransferFrom(_asset, caller, address(this), assets);\n _mint(receiver, shares);\n\n emit Deposit(caller, receiver, assets, shares);\n\n return assets;\n }\n\n /** @dev See {IERC4262-withdraw} */\n function withdraw(\n uint256 assets,\n address receiver,\n address owner\n ) public virtual override returns (uint256) {\n require(assets <= maxWithdraw(owner), \"ERC4626: withdraw more then max\");\n\n address caller = _msgSender();\n uint256 shares = previewWithdraw(assets);\n\n if (caller != owner) {\n _spendAllowance(owner, caller, shares);\n }\n\n // if _asset is ERC777, transfer can call reenter AFTER the transfer happens through\n // the tokensReceived hook, so we need to transfer after we burn to keep the invariants.\n _burn(owner, shares);\n SafeERC20.safeTransfer(_asset, receiver, assets);\n\n emit Withdraw(caller, receiver, owner, assets, shares);\n\n return shares;\n }\n\n /** @dev See {IERC4262-redeem} */\n function redeem(\n uint256 shares,\n address receiver,\n address owner\n ) public virtual override returns (uint256) {\n require(shares <= maxRedeem(owner), \"ERC4626: redeem more then max\");\n\n address caller = _msgSender();\n uint256 assets = previewRedeem(shares);\n\n if (caller != owner) {\n _spendAllowance(owner, caller, shares);\n }\n\n // if _asset is ERC777, transfer can call reenter AFTER the transfer happens through\n // the tokensReceived hook, so we need to transfer after we burn to keep the invariants.\n _burn(owner, shares);\n SafeERC20.safeTransfer(_asset, receiver, assets);\n\n emit Withdraw(caller, receiver, owner, assets, shares);\n\n return assets;\n }\n\n // Included here, since this method was not yet present in\n // the version of Open Zeppelin ERC20 code we use.\n function _spendAllowance(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n uint256 currentAllowance = allowance(owner, spender);\n if (currentAllowance != type(uint256).max) {\n require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n unchecked {\n _approve(owner, spender, currentAllowance - amount);\n }\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/e8f6f73d56d3c5372e8e110ffa009f0b.json b/contracts/deployments/holesky/solcInputs/e8f6f73d56d3c5372e8e110ffa009f0b.json new file mode 100644 index 0000000000..de43dc382f --- /dev/null +++ b/contracts/deployments/holesky/solcInputs/e8f6f73d56d3c5372e8e110ffa009f0b.json @@ -0,0 +1,62 @@ +{ + "language": "Solidity", + "sources": { + "@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" + }, + "contracts/interfaces/chainlink/AggregatorV3Interface.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface AggregatorV3Interface {\n function decimals() external view returns (uint8);\n\n function description() external view returns (string memory);\n\n function version() external view returns (uint256);\n\n // getRoundData and latestRoundData should both raise \"No data present\"\n // if they do not have data to report, instead of returning unset values\n // which could be misinterpreted as actual reported values.\n function getRoundData(uint80 _roundId)\n external\n view\n returns (\n uint80 roundId,\n int256 answer,\n uint256 startedAt,\n uint256 updatedAt,\n uint80 answeredInRound\n );\n\n function latestRoundData()\n external\n view\n returns (\n uint80 roundId,\n int256 answer,\n uint256 startedAt,\n uint256 updatedAt,\n uint80 answeredInRound\n );\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/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/oracle/OETHFixedOracle.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { OETHOracleRouter } from \"./OETHOracleRouter.sol\";\n\n// @notice Oracle Router that denominates all prices in ETH\ncontract OETHFixedOracle is OETHOracleRouter {\n constructor(address _auraPriceFeed) OETHOracleRouter(_auraPriceFeed) {}\n\n /**\n * @dev The price feed contract to use for a particular asset along with\n * maximum data staleness\n * @param asset address of the asset\n * @return feedAddress address of the price feed for the asset\n * @return maxStaleness maximum acceptable data staleness duration\n */\n function feedMetadata(address asset)\n internal\n view\n virtual\n override\n returns (address feedAddress, uint256 maxStaleness)\n {\n // fixes price for all of the assets\n feedAddress = FIXED_PRICE;\n maxStaleness = 0;\n }\n}\n" + }, + "contracts/oracle/OETHOracleRouter.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../interfaces/chainlink/AggregatorV3Interface.sol\";\nimport { OracleRouterBase } from \"./OracleRouterBase.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\n\n// @notice Oracle Router that denominates all prices in ETH\ncontract OETHOracleRouter is OracleRouterBase {\n using StableMath for uint256;\n\n address public immutable auraPriceFeed;\n\n constructor(address _auraPriceFeed) {\n auraPriceFeed = _auraPriceFeed;\n }\n\n /**\n * @notice Returns the total price in 18 digit units for a given asset.\n * This implementation does not (!) do range checks as the\n * parent OracleRouter does.\n * @param asset address of the asset\n * @return uint256 unit price for 1 asset unit, in 18 decimal fixed\n */\n function price(address asset)\n external\n view\n virtual\n override\n returns (uint256)\n {\n (address _feed, uint256 maxStaleness) = feedMetadata(asset);\n if (_feed == FIXED_PRICE) {\n return 1e18;\n }\n require(_feed != address(0), \"Asset not available\");\n\n // slither-disable-next-line unused-return\n (, int256 _iprice, , uint256 updatedAt, ) = AggregatorV3Interface(_feed)\n .latestRoundData();\n\n require(\n updatedAt + maxStaleness >= block.timestamp,\n \"Oracle price too old\"\n );\n\n uint8 decimals = getDecimals(_feed);\n uint256 _price = uint256(_iprice).scaleBy(18, decimals);\n return _price;\n }\n\n /**\n * @dev The price feed contract to use for a particular asset along with\n * maximum data staleness\n * @param asset address of the asset\n * @return feedAddress address of the price feed for the asset\n * @return maxStaleness maximum acceptable data staleness duration\n */\n function feedMetadata(address asset)\n internal\n view\n virtual\n override\n returns (address feedAddress, uint256 maxStaleness)\n {\n if (asset == 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2) {\n // FIXED_PRICE: WETH/ETH\n feedAddress = FIXED_PRICE;\n maxStaleness = 0;\n } else if (asset == 0x5E8422345238F34275888049021821E8E08CAa1f) {\n // frxETH/ETH\n feedAddress = 0xC58F3385FBc1C8AD2c0C9a061D7c13b141D7A5Df;\n maxStaleness = 18 hours + STALENESS_BUFFER;\n } else if (asset == 0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84) {\n // https://data.chain.link/ethereum/mainnet/crypto-eth/steth-eth\n // Chainlink: stETH/ETH\n feedAddress = 0x86392dC19c0b719886221c78AB11eb8Cf5c52812;\n maxStaleness = 1 days + STALENESS_BUFFER;\n } else if (asset == 0xae78736Cd615f374D3085123A210448E74Fc6393) {\n // https://data.chain.link/ethereum/mainnet/crypto-eth/reth-eth\n // Chainlink: rETH/ETH\n feedAddress = 0x536218f9E9Eb48863970252233c8F271f554C2d0;\n maxStaleness = 1 days + STALENESS_BUFFER;\n } else if (asset == 0xD533a949740bb3306d119CC777fa900bA034cd52) {\n // https://data.chain.link/ethereum/mainnet/crypto-eth/crv-eth\n // Chainlink: CRV/ETH\n feedAddress = 0x8a12Be339B0cD1829b91Adc01977caa5E9ac121e;\n maxStaleness = 1 days + STALENESS_BUFFER;\n } else if (asset == 0x4e3FBD56CD56c3e72c1403e103b45Db9da5B9D2B) {\n // https://data.chain.link/ethereum/mainnet/crypto-eth/cvx-eth\n // Chainlink: CVX/ETH\n feedAddress = 0xC9CbF687f43176B302F03f5e58470b77D07c61c6;\n maxStaleness = 1 days + STALENESS_BUFFER;\n } else if (asset == 0xBe9895146f7AF43049ca1c1AE358B0541Ea49704) {\n // https://data.chain.link/ethereum/mainnet/crypto-eth/cbeth-eth\n // Chainlink: cbETH/ETH\n feedAddress = 0xF017fcB346A1885194689bA23Eff2fE6fA5C483b;\n maxStaleness = 1 days + STALENESS_BUFFER;\n } else if (asset == 0xba100000625a3754423978a60c9317c58a424e3D) {\n // https://data.chain.link/ethereum/mainnet/crypto-eth/bal-eth\n // Chainlink: BAL/ETH\n feedAddress = 0xC1438AA3823A6Ba0C159CfA8D98dF5A994bA120b;\n maxStaleness = 1 days + STALENESS_BUFFER;\n } else if (asset == 0xC0c293ce456fF0ED870ADd98a0828Dd4d2903DBF) {\n // AURA/ETH\n feedAddress = auraPriceFeed;\n maxStaleness = 0;\n } else {\n revert(\"Asset not available\");\n }\n }\n}\n" + }, + "contracts/oracle/OracleRouterBase.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../interfaces/chainlink/AggregatorV3Interface.sol\";\nimport { IOracle } from \"../interfaces/IOracle.sol\";\nimport { Helpers } from \"../utils/Helpers.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\nimport { SafeCast } from \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\n\n// @notice Abstract functionality that is shared between various Oracle Routers\nabstract contract OracleRouterBase is IOracle {\n using StableMath for uint256;\n using SafeCast for int256;\n\n uint256 internal constant MIN_DRIFT = 0.7e18;\n uint256 internal constant MAX_DRIFT = 1.3e18;\n address internal constant FIXED_PRICE =\n 0x0000000000000000000000000000000000000001;\n // Maximum allowed staleness buffer above normal Oracle maximum staleness\n uint256 internal constant STALENESS_BUFFER = 1 days;\n mapping(address => uint8) internal decimalsCache;\n\n /**\n * @dev The price feed contract to use for a particular asset along with\n * maximum data staleness\n * @param asset address of the asset\n * @return feedAddress address of the price feed for the asset\n * @return maxStaleness maximum acceptable data staleness duration\n */\n function feedMetadata(address asset)\n internal\n view\n virtual\n returns (address feedAddress, uint256 maxStaleness);\n\n /**\n * @notice Returns the total price in 18 digit unit for a given asset.\n * @param asset address of the asset\n * @return uint256 unit price for 1 asset unit, in 18 decimal fixed\n */\n function price(address asset)\n external\n view\n virtual\n override\n returns (uint256)\n {\n (address _feed, uint256 maxStaleness) = feedMetadata(asset);\n require(_feed != address(0), \"Asset not available\");\n require(_feed != FIXED_PRICE, \"Fixed price feeds not supported\");\n\n // slither-disable-next-line unused-return\n (, int256 _iprice, , uint256 updatedAt, ) = AggregatorV3Interface(_feed)\n .latestRoundData();\n\n require(\n updatedAt + maxStaleness >= block.timestamp,\n \"Oracle price too old\"\n );\n\n uint8 decimals = getDecimals(_feed);\n\n uint256 _price = _iprice.toUint256().scaleBy(18, decimals);\n if (shouldBePegged(asset)) {\n require(_price <= MAX_DRIFT, \"Oracle: Price exceeds max\");\n require(_price >= MIN_DRIFT, \"Oracle: Price under min\");\n }\n return _price;\n }\n\n function getDecimals(address _feed) internal view virtual returns (uint8) {\n uint8 decimals = decimalsCache[_feed];\n require(decimals > 0, \"Oracle: Decimals not cached\");\n return decimals;\n }\n\n /**\n * @notice Before an asset/feed price is fetches for the first time the\n * decimals need to be cached. This is a gas optimization\n * @param asset address of the asset\n * @return uint8 corresponding asset decimals\n */\n function cacheDecimals(address asset) external returns (uint8) {\n (address _feed, ) = feedMetadata(asset);\n require(_feed != address(0), \"Asset not available\");\n require(_feed != FIXED_PRICE, \"Fixed price feeds not supported\");\n\n uint8 decimals = AggregatorV3Interface(_feed).decimals();\n decimalsCache[_feed] = decimals;\n return decimals;\n }\n\n function shouldBePegged(address _asset) internal view returns (bool) {\n string memory symbol = Helpers.getSymbol(_asset);\n bytes32 symbolHash = keccak256(abi.encodePacked(symbol));\n return\n symbolHash == keccak256(abi.encodePacked(\"DAI\")) ||\n symbolHash == keccak256(abi.encodePacked(\"USDC\")) ||\n symbolHash == keccak256(abi.encodePacked(\"USDT\"));\n }\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/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" + } + }, + "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/ea04f995873c65a558ae1a10ef794843.json b/contracts/deployments/holesky/solcInputs/ea04f995873c65a558ae1a10ef794843.json new file mode 100644 index 0000000000..2b21e8f479 --- /dev/null +++ b/contracts/deployments/holesky/solcInputs/ea04f995873c65a558ae1a10ef794843.json @@ -0,0 +1,122 @@ +{ + "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/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/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/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" + }, + "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/interfaces/chainlink/AggregatorV3Interface.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface AggregatorV3Interface {\n function decimals() external view returns (uint8);\n\n function description() external view returns (string memory);\n\n function version() external view returns (uint256);\n\n // getRoundData and latestRoundData should both raise \"No data present\"\n // if they do not have data to report, instead of returning unset values\n // which could be misinterpreted as actual reported values.\n function getRoundData(uint80 _roundId)\n external\n view\n returns (\n uint80 roundId,\n int256 answer,\n uint256 startedAt,\n uint256 updatedAt,\n uint80 answeredInRound\n );\n\n function latestRoundData()\n external\n view\n returns (\n uint80 roundId,\n int256 answer,\n uint256 startedAt,\n uint256 updatedAt,\n uint80 answeredInRound\n );\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/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/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/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 error ApprovalNotWithinTimeframe();\n error CallerNotOwner();\n error CallerNotWhitelisted();\n error ClusterAlreadyEnabled();\n error ClusterDoesNotExists();\n error ClusterIsLiquidated();\n error ClusterNotLiquidatable();\n error ExceedValidatorLimit();\n error FeeExceedsIncreaseLimit();\n error FeeIncreaseNotAllowed();\n error FeeTooHigh();\n error FeeTooLow();\n error IncorrectClusterState();\n error IncorrectValidatorState();\n error InsufficientBalance();\n error InvalidOperatorIdsLength();\n error InvalidPublicKeyLength();\n error MaxValueExceeded();\n error NewBlockPeriodIsBelowMinimum();\n error NoFeeDeclared();\n error NotAuthorized();\n error OperatorAlreadyExists();\n error OperatorDoesNotExist();\n error OperatorsListNotUnique();\n error SameFeeChangeNotAllowed();\n error TargetModuleDoesNotExist();\n error TokenTransferFailed();\n error UnsortedOperatorsList();\n error ValidatorAlreadyExists();\n error ValidatorDoesNotExist();\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 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 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 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/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" + }, + "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/oracle/OETHFixedOracle.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { OETHOracleRouter } from \"./OETHOracleRouter.sol\";\n\n// @notice Oracle Router that returns 1e18 for all prices\n// used solely for deployment to testnets\ncontract OETHFixedOracle is OETHOracleRouter {\n constructor(address _auraPriceFeed) OETHOracleRouter(_auraPriceFeed) {}\n\n /**\n * @dev The price feed contract to use for a particular asset along with\n * maximum data staleness\n * @param asset address of the asset\n * @return feedAddress address of the price feed for the asset\n * @return maxStaleness maximum acceptable data staleness duration\n */\n function feedMetadata(address asset)\n internal\n view\n virtual\n override\n returns (address feedAddress, uint256 maxStaleness)\n {\n // fixes price for all of the assets\n feedAddress = FIXED_PRICE;\n maxStaleness = 0;\n }\n}\n" + }, + "contracts/oracle/OETHOracleRouter.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../interfaces/chainlink/AggregatorV3Interface.sol\";\nimport { OracleRouterBase } from \"./OracleRouterBase.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\n\n// @notice Oracle Router that denominates all prices in ETH\ncontract OETHOracleRouter is OracleRouterBase {\n using StableMath for uint256;\n\n address public immutable auraPriceFeed;\n\n constructor(address _auraPriceFeed) {\n auraPriceFeed = _auraPriceFeed;\n }\n\n /**\n * @notice Returns the total price in 18 digit units for a given asset.\n * This implementation does not (!) do range checks as the\n * parent OracleRouter does.\n * @param asset address of the asset\n * @return uint256 unit price for 1 asset unit, in 18 decimal fixed\n */\n function price(address asset)\n external\n view\n virtual\n override\n returns (uint256)\n {\n (address _feed, uint256 maxStaleness) = feedMetadata(asset);\n if (_feed == FIXED_PRICE) {\n return 1e18;\n }\n require(_feed != address(0), \"Asset not available\");\n\n // slither-disable-next-line unused-return\n (, int256 _iprice, , uint256 updatedAt, ) = AggregatorV3Interface(_feed)\n .latestRoundData();\n\n require(\n updatedAt + maxStaleness >= block.timestamp,\n \"Oracle price too old\"\n );\n\n uint8 decimals = getDecimals(_feed);\n uint256 _price = uint256(_iprice).scaleBy(18, decimals);\n return _price;\n }\n\n /**\n * @dev The price feed contract to use for a particular asset along with\n * maximum data staleness\n * @param asset address of the asset\n * @return feedAddress address of the price feed for the asset\n * @return maxStaleness maximum acceptable data staleness duration\n */\n function feedMetadata(address asset)\n internal\n view\n virtual\n override\n returns (address feedAddress, uint256 maxStaleness)\n {\n if (asset == 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2) {\n // FIXED_PRICE: WETH/ETH\n feedAddress = FIXED_PRICE;\n maxStaleness = 0;\n } else if (asset == 0x5E8422345238F34275888049021821E8E08CAa1f) {\n // frxETH/ETH\n feedAddress = 0xC58F3385FBc1C8AD2c0C9a061D7c13b141D7A5Df;\n maxStaleness = 18 hours + STALENESS_BUFFER;\n } else if (asset == 0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84) {\n // https://data.chain.link/ethereum/mainnet/crypto-eth/steth-eth\n // Chainlink: stETH/ETH\n feedAddress = 0x86392dC19c0b719886221c78AB11eb8Cf5c52812;\n maxStaleness = 1 days + STALENESS_BUFFER;\n } else if (asset == 0xae78736Cd615f374D3085123A210448E74Fc6393) {\n // https://data.chain.link/ethereum/mainnet/crypto-eth/reth-eth\n // Chainlink: rETH/ETH\n feedAddress = 0x536218f9E9Eb48863970252233c8F271f554C2d0;\n maxStaleness = 1 days + STALENESS_BUFFER;\n } else if (asset == 0xD533a949740bb3306d119CC777fa900bA034cd52) {\n // https://data.chain.link/ethereum/mainnet/crypto-eth/crv-eth\n // Chainlink: CRV/ETH\n feedAddress = 0x8a12Be339B0cD1829b91Adc01977caa5E9ac121e;\n maxStaleness = 1 days + STALENESS_BUFFER;\n } else if (asset == 0x4e3FBD56CD56c3e72c1403e103b45Db9da5B9D2B) {\n // https://data.chain.link/ethereum/mainnet/crypto-eth/cvx-eth\n // Chainlink: CVX/ETH\n feedAddress = 0xC9CbF687f43176B302F03f5e58470b77D07c61c6;\n maxStaleness = 1 days + STALENESS_BUFFER;\n } else if (asset == 0xBe9895146f7AF43049ca1c1AE358B0541Ea49704) {\n // https://data.chain.link/ethereum/mainnet/crypto-eth/cbeth-eth\n // Chainlink: cbETH/ETH\n feedAddress = 0xF017fcB346A1885194689bA23Eff2fE6fA5C483b;\n maxStaleness = 1 days + STALENESS_BUFFER;\n } else if (asset == 0xba100000625a3754423978a60c9317c58a424e3D) {\n // https://data.chain.link/ethereum/mainnet/crypto-eth/bal-eth\n // Chainlink: BAL/ETH\n feedAddress = 0xC1438AA3823A6Ba0C159CfA8D98dF5A994bA120b;\n maxStaleness = 1 days + STALENESS_BUFFER;\n } else if (asset == 0xC0c293ce456fF0ED870ADd98a0828Dd4d2903DBF) {\n // AURA/ETH\n feedAddress = auraPriceFeed;\n maxStaleness = 0;\n } else {\n revert(\"Asset not available\");\n }\n }\n}\n" + }, + "contracts/oracle/OracleRouterBase.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../interfaces/chainlink/AggregatorV3Interface.sol\";\nimport { IOracle } from \"../interfaces/IOracle.sol\";\nimport { Helpers } from \"../utils/Helpers.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\nimport { SafeCast } from \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\n\n// @notice Abstract functionality that is shared between various Oracle Routers\nabstract contract OracleRouterBase is IOracle {\n using StableMath for uint256;\n using SafeCast for int256;\n\n uint256 internal constant MIN_DRIFT = 0.7e18;\n uint256 internal constant MAX_DRIFT = 1.3e18;\n address internal constant FIXED_PRICE =\n 0x0000000000000000000000000000000000000001;\n // Maximum allowed staleness buffer above normal Oracle maximum staleness\n uint256 internal constant STALENESS_BUFFER = 1 days;\n mapping(address => uint8) internal decimalsCache;\n\n /**\n * @dev The price feed contract to use for a particular asset along with\n * maximum data staleness\n * @param asset address of the asset\n * @return feedAddress address of the price feed for the asset\n * @return maxStaleness maximum acceptable data staleness duration\n */\n function feedMetadata(address asset)\n internal\n view\n virtual\n returns (address feedAddress, uint256 maxStaleness);\n\n /**\n * @notice Returns the total price in 18 digit unit for a given asset.\n * @param asset address of the asset\n * @return uint256 unit price for 1 asset unit, in 18 decimal fixed\n */\n function price(address asset)\n external\n view\n virtual\n override\n returns (uint256)\n {\n (address _feed, uint256 maxStaleness) = feedMetadata(asset);\n require(_feed != address(0), \"Asset not available\");\n require(_feed != FIXED_PRICE, \"Fixed price feeds not supported\");\n\n // slither-disable-next-line unused-return\n (, int256 _iprice, , uint256 updatedAt, ) = AggregatorV3Interface(_feed)\n .latestRoundData();\n\n require(\n updatedAt + maxStaleness >= block.timestamp,\n \"Oracle price too old\"\n );\n\n uint8 decimals = getDecimals(_feed);\n\n uint256 _price = _iprice.toUint256().scaleBy(18, decimals);\n if (shouldBePegged(asset)) {\n require(_price <= MAX_DRIFT, \"Oracle: Price exceeds max\");\n require(_price >= MIN_DRIFT, \"Oracle: Price under min\");\n }\n return _price;\n }\n\n function getDecimals(address _feed) internal view virtual returns (uint8) {\n uint8 decimals = decimalsCache[_feed];\n require(decimals > 0, \"Oracle: Decimals not cached\");\n return decimals;\n }\n\n /**\n * @notice Before an asset/feed price is fetches for the first time the\n * decimals need to be cached. This is a gas optimization\n * @param asset address of the asset\n * @return uint8 corresponding asset decimals\n */\n function cacheDecimals(address asset) external returns (uint8) {\n (address _feed, ) = feedMetadata(asset);\n require(_feed != address(0), \"Asset not available\");\n require(_feed != FIXED_PRICE, \"Fixed price feeds not supported\");\n\n uint8 decimals = AggregatorV3Interface(_feed).decimals();\n decimalsCache[_feed] = decimals;\n return decimals;\n }\n\n function shouldBePegged(address _asset) internal view returns (bool) {\n string memory symbol = Helpers.getSymbol(_asset);\n bytes32 symbolHash = keccak256(abi.encodePacked(symbol));\n return\n symbolHash == keccak256(abi.encodePacked(\"DAI\")) ||\n symbolHash == keccak256(abi.encodePacked(\"USDC\")) ||\n symbolHash == keccak256(abi.encodePacked(\"USDT\"));\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\nimport { Governable } from \"../../governance/Governable.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 is Governable {\n /// @notice The address of the Native Staking Strategy\n address public immutable STRATEGY;\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 }\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\";\n\nimport { InitializableAbstractStrategy } from \"../../utils/InitializableAbstractStrategy.sol\";\nimport { ISSVNetwork, Cluster } from \"../../interfaces/ISSVNetwork.sol\";\nimport { IWETH9 } from \"../../interfaces/IWETH9.sol\";\nimport { FeeAccumulator } from \"./FeeAccumulator.sol\";\nimport { ValidatorAccountant } from \"./ValidatorAccountant.sol\";\nimport { Cluster } from \"../../interfaces/ISSVNetwork.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\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_ADDRESS;\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 public immutable FEE_ACCUMULATOR_ADDRESS;\n\n // For future use\n uint256[50] 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 _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 address _feeAccumulator,\n address _beaconChainDepositContract\n )\n InitializableAbstractStrategy(_baseConfig)\n ValidatorAccountant(\n _wethAddress,\n _baseConfig.vaultAddress,\n _beaconChainDepositContract,\n _ssvNetwork\n )\n {\n SSV_TOKEN_ADDRESS = _ssvToken;\n FEE_ACCUMULATOR_ADDRESS = _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 /// @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_TOKEN_ADDRESS).deposit{ value: ethRewards }();\n\n emit RewardTokenCollected(\n harvesterAddress,\n WETH_TOKEN_ADDRESS,\n ethRewards\n );\n IERC20(WETH_TOKEN_ADDRESS).safeTransfer(\n harvesterAddress,\n ethRewards\n );\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_TOKEN_ADDRESS, \"Unsupported asset\");\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_TOKEN_ADDRESS).balanceOf(\n address(this)\n );\n if (wethBalance > 0) {\n _deposit(WETH_TOKEN_ADDRESS, wethBalance);\n }\n }\n\n /// @notice Withdraw WETH from this contract. Used only if some WETH for is lingering on the contract. That\n /// can happen when:\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 _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 emit Withdrawal(_asset, address(0), _amount);\n IERC20(_asset).safeTransfer(_recipient, _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_TOKEN_ADDRESS).balanceOf(\n address(this)\n );\n if (wethBalance > 0) {\n _withdraw(vaultAddress, WETH_TOKEN_ADDRESS, wethBalance);\n }\n }\n\n function _abstractSetPToken(address _asset, address) internal override {}\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_TOKEN_ADDRESS, \"Unsupported asset\");\n\n balance =\n // add the ETH that has been staked in validators\n activeDepositedValidators *\n 32 ether +\n // add the WETH in the strategy from deposits that are still to be staked\n IERC20(WETH_TOKEN_ADDRESS).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_TOKEN_ADDRESS;\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_ADDRESS).approve(\n SSV_NETWORK_ADDRESS,\n type(uint256).max\n );\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_TOKEN_ADDRESS,\n \"eth not from allowed contracts\"\n );\n }\n}\n" + }, + "contracts/strategies/NativeStaking/ValidatorAccountant.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { Pausable } from \"@openzeppelin/contracts/security/Pausable.sol\";\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 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 MAX_STAKE = 32 ether;\n\n /// @notice Keeps track of the total consensus rewards swept from the beacon chain\n uint256 public consensusRewards = 0;\n\n /// @notice start of fuse interval\n uint256 public fuseIntervalStart = 0;\n /// @notice end of fuse interval\n uint256 public fuseIntervalEnd = 0;\n /// @notice Governor that can manually correct the accounting\n address public accountingGovernor;\n\n uint256[50] 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 AccountingGovernorChanged(address newAddress);\n event AccountingConsensusRewards(uint256 amount);\n\n event AccountingManuallyFixed(\n uint256 oldActiveDepositedValidators,\n uint256 activeDepositedValidators,\n uint256 oldBeaconChainRewards,\n uint256 beaconChainRewards,\n uint256 ethToWeth,\n uint256 wethToBeSentToVault\n );\n\n /// @dev Throws if called by any account other than the Accounting Governor\n modifier onlyAccountingGovernor() {\n require(\n msg.sender == accountingGovernor,\n \"Caller is not the Accounting Governor\"\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 constructor(\n address _wethAddress,\n address _vaultAddress,\n address _beaconChainDepositContract,\n address _ssvNetwork\n )\n ValidatorRegistrator(\n _wethAddress,\n _vaultAddress,\n _beaconChainDepositContract,\n _ssvNetwork\n )\n {}\n\n function setAccountingGovernor(address _address) external onlyGovernor {\n emit AccountingGovernorChanged(_address);\n accountingGovernor = _address;\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 _fuseIntervalStart < 32 ether &&\n _fuseIntervalEnd < 32 ether &&\n _fuseIntervalEnd - _fuseIntervalStart >= 4 ether,\n \"incorrect fuse interval\"\n );\n\n emit FuseIntervalUpdated(_fuseIntervalStart, _fuseIntervalEnd);\n\n fuseIntervalStart = _fuseIntervalStart;\n fuseIntervalEnd = _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 /* solhint-enable max-line-length */\n function doAccounting()\n external\n onlyRegistrator\n whenNotPaused\n returns (bool accountingValid)\n {\n if (address(this).balance < consensusRewards) {\n // pause and fail the accounting\n _pause();\n return false;\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 >= MAX_STAKE) {\n uint256 fullyWithdrawnValidators = newSweptETH / MAX_STAKE;\n activeDepositedValidators -= fullyWithdrawnValidators;\n\n uint256 wethToVault = MAX_STAKE * fullyWithdrawnValidators;\n IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: wethToVault }();\n IWETH9(WETH_TOKEN_ADDRESS).transfer(VAULT_ADDRESS, 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 < 32 ether, \"unexpected accounting\");\n\n // If no Beacon chain consensus rewards swept\n if (ethRemaining == 0) {\n // do nothing\n return accountingValid;\n }\n // Beacon chain consensus rewards swept (partial validator withdrawals)\n else if (ethRemaining < fuseIntervalStart) {\n // solhint-disable-next-line reentrancy\n consensusRewards += ethRemaining;\n emit AccountingConsensusRewards(ethRemaining);\n }\n // Beacon chain consensus rewards swept but also a slashed validator fully exited\n else if (ethRemaining > fuseIntervalEnd) {\n IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: ethRemaining }();\n IWETH9(WETH_TOKEN_ADDRESS).transfer(VAULT_ADDRESS, ethRemaining);\n activeDepositedValidators -= 1;\n\n emit AccountingValidatorSlashed(\n activeDepositedValidators,\n ethRemaining\n );\n }\n // Oh no... Fuse is blown. The governor (Multisig not OGV Governor) needs to set the\n // record straight by manually set the accounting values.\n else {\n // will emit a paused event\n _pause();\n accountingValid = false;\n }\n }\n\n /// @dev allow the accounting governor to fix the accounting of this strategy and unpause\n /// @param _activeDepositedValidators the override value of activeDepositedValidators\n /// @param _ethToWeth the amount of ETH to be converted to WETH\n /// @param _wethToBeSentToVault the amount of WETH to be sent to the Vault\n /// @param _consensusRewards the override value for consensusRewards\n /// @param _ethThresholdCheck maximum allowed ETH balance on the contract for the function to run\n /// @param _wethThresholdCheck maximum allowed WETH balance on the contract for the function to run\n /// the above 2 checks are done so transaction doesn't get front run and cause\n /// unexpected behaviour\n function manuallyFixAccounting(\n uint256 _activeDepositedValidators,\n uint256 _ethToWeth,\n uint256 _wethToBeSentToVault,\n uint256 _consensusRewards,\n uint256 _ethThresholdCheck,\n uint256 _wethThresholdCheck\n ) external onlyAccountingGovernor whenPaused {\n uint256 ethBalance = address(this).balance;\n uint256 wethBalance = IWETH9(WETH_TOKEN_ADDRESS).balanceOf(\n address(this)\n );\n\n require(\n ethBalance <= _ethThresholdCheck &&\n wethBalance <= _wethThresholdCheck,\n \"over accounting threshold\"\n );\n\n emit AccountingManuallyFixed(\n activeDepositedValidators,\n _activeDepositedValidators,\n consensusRewards,\n _consensusRewards,\n _ethToWeth,\n _wethToBeSentToVault\n );\n\n activeDepositedValidators = _activeDepositedValidators;\n consensusRewards = _consensusRewards;\n if (_ethToWeth > 0) {\n require(_ethToWeth <= ethBalance, \"insufficient ETH\");\n\n IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: _ethToWeth }();\n }\n if (_wethToBeSentToVault > 0) {\n IWETH9(WETH_TOKEN_ADDRESS).transfer(\n VAULT_ADDRESS,\n _wethToBeSentToVault\n );\n }\n\n _unpause();\n }\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 address of the Wrapped ETH (WETH) token contract\n address public immutable WETH_TOKEN_ADDRESS;\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_ADDRESS;\n /// @notice Address of the OETH Vault proxy contract\n address public immutable VAULT_ADDRESS;\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 activeDepositedValidators;\n /// @notice State of the validators keccak256(pubKey) => state\n mapping(bytes32 => VALIDATOR_STATE) public validatorsStates;\n\n // For future use\n uint256[50] private __gap;\n\n enum VALIDATOR_STATE {\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 newAddress);\n event ETHStaked(bytes pubkey, uint256 amount, bytes withdrawal_credentials);\n event SSVValidatorRegistered(bytes pubkey, uint64[] operatorIds);\n event SSVValidatorExitInitiated(bytes pubkey, uint64[] operatorIds);\n event SSVValidatorExitCompleted(bytes pubkey, uint64[] operatorIds);\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 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 constructor(\n address _wethAddress,\n address _vaultAddress,\n address _beaconChainDepositContract,\n address _ssvNetwork\n ) {\n WETH_TOKEN_ADDRESS = _wethAddress;\n BEACON_CHAIN_DEPOSIT_CONTRACT = _beaconChainDepositContract;\n SSV_NETWORK_ADDRESS = _ssvNetwork;\n VAULT_ADDRESS = _vaultAddress;\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 emit RegistratorChanged(_address);\n validatorRegistrator = _address;\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 function stakeEth(ValidatorStakeData[] calldata validators)\n external\n onlyRegistrator\n whenNotPaused\n {\n uint256 requiredETH = validators.length * 32 ether;\n\n // Check there is enough WETH from the deposits sitting in this strategy contract\n require(\n requiredETH <= IWETH9(WETH_TOKEN_ADDRESS).balanceOf(address(this)),\n \"insufficient WETH\"\n );\n\n // Convert required ETH from WETH\n IWETH9(WETH_TOKEN_ADDRESS).withdraw(requiredETH);\n\n // For each validator\n for (uint256 i = 0; i < validators.length; ) {\n bytes32 pubkeyHash = keccak256(validators[i].pubkey);\n VALIDATOR_STATE currentState = validatorsStates[pubkeyHash];\n\n require(\n currentState == VALIDATOR_STATE.REGISTERED,\n \"Validator not registered\"\n );\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 withdrawal_credentials = abi.encodePacked(\n bytes1(0x01),\n bytes11(0),\n address(this)\n );\n IDepositContract(BEACON_CHAIN_DEPOSIT_CONTRACT).deposit{ value: 32 ether }(\n validators[i].pubkey,\n withdrawal_credentials,\n validators[i].signature,\n validators[i].depositDataRoot\n );\n\n activeDepositedValidators += 1;\n emit ETHStaked(\n validators[i].pubkey,\n 32 ether,\n withdrawal_credentials\n );\n\n validatorsStates[pubkeyHash] = VALIDATOR_STATE.STAKED;\n\n unchecked {\n ++i;\n }\n }\n }\n\n /// @notice Registers a new validator in the SSV Cluster.\n /// Only the registrator can call this function.\n function registerSsvValidator(\n bytes calldata publicKey,\n uint64[] calldata operatorIds,\n bytes calldata sharesData,\n uint256 amount,\n Cluster calldata cluster\n ) external onlyRegistrator whenNotPaused {\n ISSVNetwork(SSV_NETWORK_ADDRESS).registerValidator(\n publicKey,\n operatorIds,\n sharesData,\n amount,\n cluster\n );\n validatorsStates[keccak256(publicKey)] = VALIDATOR_STATE.REGISTERED;\n emit SSVValidatorRegistered(publicKey, operatorIds);\n }\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 function exitSsvValidator(\n bytes calldata publicKey,\n uint64[] calldata operatorIds\n ) external onlyRegistrator whenNotPaused {\n VALIDATOR_STATE currentState = validatorsStates[keccak256(publicKey)];\n require(currentState == VALIDATOR_STATE.STAKED, \"Validator not staked\");\n\n ISSVNetwork(SSV_NETWORK_ADDRESS).exitValidator(publicKey, operatorIds);\n emit SSVValidatorExitInitiated(publicKey, operatorIds);\n\n validatorsStates[keccak256(publicKey)] = VALIDATOR_STATE.EXITING;\n }\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 function removeSsvValidator(\n bytes calldata publicKey,\n uint64[] calldata operatorIds,\n Cluster calldata cluster\n ) external onlyRegistrator whenNotPaused {\n VALIDATOR_STATE currentState = validatorsStates[keccak256(publicKey)];\n require(\n currentState == VALIDATOR_STATE.EXITING,\n \"Validator not exiting\"\n );\n\n ISSVNetwork(SSV_NETWORK_ADDRESS).removeValidator(\n publicKey,\n operatorIds,\n cluster\n );\n emit SSVValidatorExitCompleted(publicKey, operatorIds);\n\n validatorsStates[keccak256(publicKey)] = VALIDATOR_STATE.EXIT_COMPLETE;\n }\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 cluster The SSV cluster details that must be derived from emitted events from the SSVNetwork contract.\n function depositSSV(\n uint64[] memory operatorIds,\n uint256 amount,\n Cluster memory cluster\n ) external onlyStrategist {\n ISSVNetwork(SSV_NETWORK_ADDRESS).deposit(\n address(this),\n operatorIds,\n amount,\n cluster\n );\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/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/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" + } + }, + "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 8b38880f76..874bf5275d 100644 --- a/contracts/dev.env +++ b/contracts/dev.env @@ -1,6 +1,10 @@ +#providers PROVIDER_URL=[SET PROVIDER URL HERE] +HOLESKY_PROVIDER_URL=[SET HOLESKY PROVIDER URL HERE] + # Set it to latest block number or leave it empty BLOCK_NUMBER= +HOLESKY_BLOCK_NUMBER= # Add a list of comma separated accounts you want funded in node running forked mode ACCOUNTS_TO_FUND= diff --git a/contracts/fork-test.sh b/contracts/fork-test.sh index 5634a9391f..5640a26eee 100755 --- a/contracts/fork-test.sh +++ b/contracts/fork-test.sh @@ -37,8 +37,12 @@ main() params=() if [[ $FORK_NETWORK_NAME == "arbitrumOne" ]]; then - PROVIDER_URL=$ARBITRUM_PROVIDER_URL; - BLOCK_NUMBER=$ARBITRUM_BLOCK_NUMBER; + PROVIDER_URL=$ARBITRUM_PROVIDER_URL; + BLOCK_NUMBER=$ARBITRUM_BLOCK_NUMBER; + params+=" --tags arbitrumOne"; + elif [[ $FORK_NETWORK_NAME == "holesky" ]]; then + PROVIDER_URL=$HOLESKY_PROVIDER_URL; + BLOCK_NUMBER=$HOLESKY_BLOCK_NUMBER; fi if $is_local; then @@ -67,9 +71,15 @@ main() fi if [ -z "$1" ]; then - # Run all files with `.fork-test.js` suffix when no file name param is given - # pass all other params along - params+="test/**/*.fork-test.js" + if [[ $FORK_NETWORK_NAME == "holesky" ]]; then + # Run all files with `.holesky.fork-test.js` suffix when no file name param is given + # pass all other params along + params+="test/**/*.holesky.fork-test.js" + else + # Run all files with `.fork-test.js` suffix when no file name param is given + # pass all other params along + params+="test/**/*.fork-test.js" + fi else # Run specifc files when a param is given params+="$@" diff --git a/contracts/hardhat.config.js b/contracts/hardhat.config.js index f66eee5934..3e571382d4 100644 --- a/contracts/hardhat.config.js +++ b/contracts/hardhat.config.js @@ -1,6 +1,19 @@ const ethers = require("ethers"); const { task } = require("hardhat/config"); -const fetch = require("sync-fetch"); +const { + isFork, + isArbitrumFork, + isHoleskyFork, + isHolesky, + isForkTest, + isArbForkTest, + isHoleskyForkTest, + providerUrl, + arbitrumProviderUrl, + holeskyProviderUrl, + adjustTheForkBlockNumber, + getHardhatNetworkProperties, +} = require("./utils/hardhat-helpers.js"); require("@nomiclabs/hardhat-etherscan"); require("@nomiclabs/hardhat-waffle"); @@ -29,6 +42,7 @@ const MAINNET_GOVERNOR = "0x72426ba137dec62657306b12b1e869d43fec6ec7"; const MAINNET_MULTISIG = "0xbe2AB3d3d8F6a32b96414ebbd865dBD276d3d899"; const MAINNET_CLAIM_ADJUSTER = MAINNET_DEPLOYER; const MAINNET_STRATEGIST = "0xf14bbdf064e3f67f51cd9bd646ae3716ad938fdc"; +const HOLESKY_DEPLOYER = "0x1b94CA50D3Ad9f8368851F8526132272d1a5028C"; const mnemonic = "replace hover unaware super where filter stone fine garlic address matrix basic"; @@ -46,63 +60,20 @@ task("accounts", "Prints the list of accounts", async (taskArguments, hre) => { return accounts(taskArguments, hre, privateKeys); }); -const isFork = process.env.FORK === "true"; -const isArbitrumFork = process.env.FORK_NETWORK_NAME === "arbitrumOne"; -const isForkTest = isFork && process.env.IS_TEST === "true"; -const isArbForkTest = isForkTest && isArbitrumFork; -const providerUrl = `${ - process.env.LOCAL_PROVIDER_URL || process.env.PROVIDER_URL -}`; -const arbitrumProviderUrl = `${process.env.ARBITRUM_PROVIDER_URL}`; -const standaloneLocalNodeRunning = !!process.env.LOCAL_PROVIDER_URL; +let forkBlockNumber = adjustTheForkBlockNumber(); -let forkBlockNumber = - Number( - isArbForkTest ? process.env.ARBITRUM_BLOCK_NUMBER : process.env.BLOCK_NUMBER - ) || undefined; -if (isForkTest && standaloneLocalNodeRunning) { - const jsonResponse = fetch( - isArbForkTest ? arbitrumProviderUrl : providerUrl, - { - method: "post", - body: JSON.stringify({ - jsonrpc: "2.0", - method: "eth_blockNumber", - id: 1, - }), - headers: { - "Content-Type": "application/json", - }, - } - ).json(); - - /* - * We source the block number from the hardhat context rather than from - * node-test.sh startup script, so that block number from an already - * running local node can be fetched after the deployments have already - * been applied. - * - */ - forkBlockNumber = parseInt(jsonResponse.result, 16); - - console.log(`Connecting to local node on block: ${forkBlockNumber}`); - - // Mine 40 blocks so hardhat wont complain about block fork being too recent - fetch(isArbForkTest ? arbitrumProviderUrl : providerUrl, { - method: "post", - body: JSON.stringify({ - jsonrpc: "2.0", - method: "hardhat_mine", - params: ["0x28"], // 40 - id: 1, - }), - headers: { - "Content-Type": "application/json", - }, - }).json(); -} else if (isForkTest) { - console.log(`Starting a fresh node on block: ${forkBlockNumber}`); +const paths = {}; +if (isHolesky || isHoleskyForkTest || isHoleskyFork) { + // holesky deployment files are in contracts/deploy/holesky + paths.deploy = "deploy/holesky"; +} else { + // holesky deployment files are in contracts/deploy/mainnet + paths.deploy = "deploy/mainnet"; +} +if (process.env.HARDHAT_CACHE_DIR) { + paths.cache = process.env.HARDHAT_CACHE_DIR; } +const { provider, chainId } = getHardhatNetworkProperties(); module.exports = { solidity: { @@ -124,7 +95,7 @@ module.exports = { accounts: { mnemonic, }, - chainId: isFork ? (isArbitrumFork ? 42161 : 1) : 1337, + chainId, ...(isArbitrumFork ? { tags: ["arbitrumOne"] } : {}), ...(isForkTest ? { @@ -132,7 +103,7 @@ module.exports = { initialBaseFeePerGas: 0, forking: { enabled: true, - url: isArbForkTest ? arbitrumProviderUrl : providerUrl, + url: provider, blockNumber: forkBlockNumber, timeout: 0, }, @@ -154,6 +125,15 @@ module.exports = { process.env.GOVERNOR_PK || privateKeys[0], ], }, + holesky: { + url: holeskyProviderUrl, + accounts: [ + process.env.DEPLOYER_PK || privateKeys[0], + process.env.GOVERNOR_PK || privateKeys[0], + ], + chainId: 17000, + live: true, + }, arbitrumOne: { url: arbitrumProviderUrl, accounts: [ @@ -167,11 +147,6 @@ module.exports = { // Fails if gas limit is anything less than 20M on Arbitrum One gas: 20000000, // initialBaseFeePerGas: 0, - // forking: { - // enabled: true, - // url: arbitrumProviderUrl, - // timeout: 0 - // } }, }, mocha: { @@ -182,17 +157,39 @@ module.exports = { namedAccounts: { deployerAddr: { default: 0, - localhost: process.env.FORK === "true" ? MAINNET_DEPLOYER : 0, - hardhat: process.env.FORK === "true" ? MAINNET_DEPLOYER : 0, + localhost: + process.env.FORK === "true" + ? isHoleskyFork + ? HOLESKY_DEPLOYER + : MAINNET_DEPLOYER + : 0, + hardhat: + process.env.FORK === "true" + ? isHoleskyFork + ? HOLESKY_DEPLOYER + : MAINNET_DEPLOYER + : 0, mainnet: MAINNET_DEPLOYER, arbitrumOne: MAINNET_DEPLOYER, + holesky: HOLESKY_DEPLOYER, }, governorAddr: { default: 1, // On Mainnet and fork, the governor is the Governor contract. - localhost: process.env.FORK === "true" ? MAINNET_GOVERNOR : 1, - hardhat: process.env.FORK === "true" ? MAINNET_GOVERNOR : 1, + localhost: + process.env.FORK === "true" + ? isHoleskyFork + ? HOLESKY_DEPLOYER + : MAINNET_DEPLOYER + : 1, + hardhat: + process.env.FORK === "true" + ? isHoleskyFork + ? HOLESKY_DEPLOYER + : MAINNET_DEPLOYER + : 1, mainnet: MAINNET_GOVERNOR, + holesky: HOLESKY_DEPLOYER, // on Holesky the deployer is also the governor }, /* Local node environment currently has no access to Decentralized governance * address, since the contract is in another repo. Once we merge the ousd-governance @@ -243,9 +240,20 @@ module.exports = { }, strategistAddr: { default: 0, - localhost: process.env.FORK === "true" ? MAINNET_STRATEGIST : 0, - hardhat: process.env.FORK === "true" ? MAINNET_STRATEGIST : 0, + localhost: + process.env.FORK === "true" + ? isHoleskyFork + ? HOLESKY_DEPLOYER + : MAINNET_STRATEGIST + : 0, + hardhat: + process.env.FORK === "true" + ? isHoleskyFork + ? HOLESKY_DEPLOYER + : MAINNET_STRATEGIST + : 0, mainnet: MAINNET_STRATEGIST, + holesky: HOLESKY_DEPLOYER, // on Holesky the deployer is also the strategist }, }, contractSizer: { @@ -256,14 +264,21 @@ module.exports = { apiKey: { mainnet: process.env.ETHERSCAN_API_KEY, arbitrumOne: process.env.ARBISCAN_API_KEY, + holesky: process.env.ETHERSCAN_API_KEY, }, + customChains: [ + { + network: "holesky", + chainId: 17000, + urls: { + apiURL: "https://api-holesky.etherscan.io/api", + browserURL: "https://holesky.etherscan.io", + }, + }, + ], }, gasReporter: { enabled: process.env.REPORT_GAS ? true : false, }, - paths: process.env.HARDHAT_CACHE_DIR - ? { - cache: process.env.HARDHAT_CACHE_DIR, - } - : {}, + paths, }; diff --git a/contracts/node.sh b/contracts/node.sh index da3d9880c7..4494479f9a 100755 --- a/contracts/node.sh +++ b/contracts/node.sh @@ -30,6 +30,9 @@ main() PROVIDER_URL=$ARBITRUM_PROVIDER_URL; BLOCK_NUMBER=$ARBITRUM_BLOCK_NUMBER; params+=" --tags arbitrumOne"; + elif [[ $FORK_NETWORK_NAME == "holesky" ]]; then + PROVIDER_URL=$HOLESKY_PROVIDER_URL; + BLOCK_NUMBER=$HOLESKY_BLOCK_NUMBER; fi echo "Fork Network: $FORK_NETWORK_NAME" @@ -51,7 +54,6 @@ main() nodeOutput=$(mktemp "${TMPDIR:-/tmp/}$(basename 0).XXX") # the --no-install is here so npx doesn't download some package on its own if it can not find one in the repo FORK_NETWORK_NAME=$FORK_NETWORK_NAME FORK=true npx --no-install hardhat node --no-reset ${params[@]} > $nodeOutput 2>&1 & - tail -f $nodeOutput & i=0 diff --git a/contracts/package.json b/contracts/package.json index 74100a2bb0..5abce09f9e 100644 --- a/contracts/package.json +++ b/contracts/package.json @@ -7,11 +7,13 @@ "deploy": "rm -rf deployments/hardhat && npx hardhat deploy", "deploy:mainnet": "npx hardhat deploy --network mainnet --verbose", "deploy:arbitrum": "npx hardhat deploy --network arbitrumOne --tags arbitrumOne --verbose", + "deploy:holesky": "NETWORK_NAME=holesky npx hardhat deploy --network holesky --verbose", "abi:generate": "(rm -rf deployments/hardhat && mkdir -p dist/abi && npx hardhat deploy --export '../dist/network.json')", "abi:dist": "find ./artifacts/contracts -name \"*.json\" -type f -exec cp {} ./dist/abi \\; && rm -rf dist/abi/*.dbg.json dist/abi/Mock*.json && cp ./abi.package.json dist/package.json && cp ./.npmrc.abi dist/.npmrc", "node": "yarn run node:fork", "node:fork": "./node.sh fork", "node:arb": "FORK_NETWORK_NAME=arbitrumOne yarn run node:fork", + "node:hol": "FORK_NETWORK_NAME=holesky yarn run node:fork", "lint": "yarn run lint:js && yarn run lint:sol", "lint:js": "eslint \"test/**/*.js\" \"tasks/**/*.js\" \"deploy/**/*.js\"", "lint:sol": "solhint \"contracts/**/*.sol\"", @@ -22,6 +24,7 @@ "test": "rm -rf deployments/hardhat && IS_TEST=true npx hardhat test", "test:fork": "./fork-test.sh", "test:arb-fork": "FORK_NETWORK_NAME=arbitrumOne ./fork-test.sh", + "test:hol-fork": "FORK_NETWORK_NAME=holesky ./fork-test.sh", "test:fork:w_trace": "TRACE=true ./fork-test.sh", "fund": "FORK=true npx hardhat fund --network localhost", "echidna": "yarn run clean && rm -rf echidna-corpus && echidna . --contract Echidna --config echidna-config.yaml", @@ -33,7 +36,8 @@ "cache-clean:light": "rm -rf cache/hardhat-network-fork/network-1337/", "test:coverage": "IS_TEST=true npx hardhat coverage", "test:coverage:fork": "REPORT_COVERAGE=true ./fork-test.sh", - "test:coverage:arb-fork": "REPORT_COVERAGE=true FORK_NETWORK_NAME=arbitrumOne ./fork-test.sh" + "test:coverage:arb-fork": "REPORT_COVERAGE=true FORK_NETWORK_NAME=arbitrumOne ./fork-test.sh", + "test:coverage:hol-fork": "REPORT_COVERAGE=true FORK_NETWORK_NAME=holesky ./fork-test.sh" }, "author": "Origin Protocol Inc ", "license": "MIT", @@ -71,6 +75,7 @@ "solhint": "^3.4.1", "solidifier": "^2.2.3", "solidity-coverage": "^0.8.2", + "ssv-scanner": "github:bloxapp/ssv-scanner", "sync-fetch": "^0.5.2", "web3-utils": "^1.5.2" }, diff --git a/contracts/scripts/deploy/verifySimpleOETHDeployment.sh b/contracts/scripts/deploy/verifySimpleOETHDeployment.sh new file mode 100644 index 0000000000..1dbdc7bc0c --- /dev/null +++ b/contracts/scripts/deploy/verifySimpleOETHDeployment.sh @@ -0,0 +1,47 @@ +#!/bin/bash + +export OETH_VAULT=0xa7191fEE1Ed313908FCb09D09b82ABB7BC56F71B +export OETH_VAULT_PROXY=0x19d2bAaBA949eFfa163bFB9efB53ed8701aA5dD9 +export OETH_VAULT_CORE=0xE92e25B81E44B8377Df1362f8fFBc426A00d6ef4 +export OETH_VAULT_ADMIN=0xa94c4aab0Cf9f6E79bB064DB145fBe2506b9Fa75 +export OETH_PROXY=0xB1876706d2402d300bf263F9e53335CEFc53d9Cb +export OETH=0x7909c19E355E95043e277e76Dd6680fE899F61D6 +export FEE_ACC=0x79681d3f14a0068479420eE5fDdF59B62301f810 +export FEE_ACC_PROXY=0x590B781b511e953dbFC49e7E7864A6E787aFBDCc +export OETH_DRIPPER=0x3833C32826A7f2a93C48D50ae44D45F45Ab17B7F +export OETH_DRIPPER_PROXY=0xaFF1E6263F4004C95Ae611DEb2ADaC049B5aD121 +export OETH_HARVESTER=0x22b00a89531E199bd90eC162F9810298b9FBC8b3 +export OETH_HARVESTER_PROXY=0xB7491cdf36367C89001cc41312F22f63A3a17931 +export OETH_ORACLE_ROUTER=0x7e2bf9A89180f20591EcFA42C0dd7e52b2C546E3 +export NATIVE_STAKING=0x33Eeb0996f6981ff7d11F643630734856BEc09f5 +export NATIVE_STAKING_PROXY=0x4Eac8847c7AE50e3A3551B1Aa4FF7Cc162151410 +export WETH=0x94373a4919b3240d86ea41593d5eba789fef3848 +export ZERO=0x0000000000000000000000000000000000000000 +export SSV=0xad45A78180961079BFaeEe349704F411dfF947C6 +export SSVNetwork=0x38A4794cCEd47d3baf7370CcC43B560D3a1beEFA +export beaconChainDepositContract=0x4242424242424242424242424242424242424242 + +yarn run hardhat verify --contract contracts/vault/OETHVault.sol:OETHVault --network holesky $OETH_VAULT +echo "module.exports = [\"0xD8724322f44E5c58D7A815F542036fb17DbbF839\"]" > vault_args.js +yarn run hardhat verify --contract contracts/vault/OETHVaultCore.sol:OETHVaultCore --network holesky --constructor-args vault_args.js $OETH_VAULT_CORE +yarn run hardhat verify --contract contracts/proxies/Proxies.sol:OETHVaultAdmin --network holesky --constructor-args vault_args.js $OETH_VAULT_ADMIN +yarn run hardhat verify --contract contracts/proxies/Proxies.sol:OETHVaultProxy --network holesky $OETH_VAULT_PROXY +yarn run hardhat verify --contract contracts/proxies/Proxies.sol:OETHProxy --network holesky $OETH_PROXY +yarn run hardhat verify --contract contracts/token/OETH.sol:OETH --network holesky $OETH + +echo "module.exports = [\"$NATIVE_STAKING_PROXY\"]" > fee_acc_args.js +yarn run hardhat verify --contract contracts/strategies/NativeStaking/FeeAccumulator.sol:FeeAccumulator --network holesky --constructor-args fee_acc_args.js $FEE_ACC +yarn run hardhat verify --contract contracts/proxies/Proxies.sol:NativeStakingFeeAccumulatorProxy --network holesky $FEE_ACC_PROXY +echo "module.exports = [\"$OETH_VAULT_PROXY\", \"$OETH_PROXY\"]" > dripper_acc_args.js +yarn run hardhat verify --contract contracts/harvest/OETHDripper.sol:OETHDripper --network holesky --constructor-args dripper_acc_args.js $OETH_DRIPPER +yarn run hardhat verify --contract contracts/proxies/Proxies.sol:OETHDripperProxy --network holesky $OETH_DRIPPER_PROXY +echo "module.exports = [\"$OETH_VAULT_PROXY\", \"$WETH\"]" > harvester_acc_args.js +yarn run hardhat verify --contract contracts/harvest/OETHHarvester.sol:OETHHarvester --network holesky --constructor-args harvester_acc_args.js $OETH_HARVESTER +yarn run hardhat verify --contract contracts/proxies/Proxies.sol:OETHHarvesterProxy --network holesky $OETH_HARVESTER_PROXY +echo "module.exports = [\"$ZERO\"]" > oracle_acc_args.js +yarn run hardhat verify --contract contracts/oracle/OETHFixedOracle.sol:OETHFixedOracle --network holesky --constructor-args oracle_acc_args.js $OETH_ORACLE_ROUTER +echo "module.exports = [[\"$ZERO\", \"$OETH_VAULT_PROXY\"], \"$WETH\", \"$SSV\", \"$SSVNetwork\", \"$FEE_ACC_PROXY\", \"$beaconChainDepositContract\"]" > strategy_acc_args.js +yarn run hardhat verify --contract contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy --network holesky --constructor-args strategy_acc_args.js $NATIVE_STAKING +yarn run hardhat verify --contract contracts/proxies/Proxies.sol:NativeStakingSSVStrategyProxy --network holesky $NATIVE_STAKING_PROXY + +rm -f vault_args.js fee_acc_args.js dripper_acc_args.js harvester_acc_args.js oracle_acc_args.js strategy_acc_args.js \ No newline at end of file diff --git a/contracts/scripts/test/signAndBroadcastHolesky.js b/contracts/scripts/test/signAndBroadcastHolesky.js new file mode 100644 index 0000000000..7b3988e4a3 --- /dev/null +++ b/contracts/scripts/test/signAndBroadcastHolesky.js @@ -0,0 +1,60 @@ +require("dotenv").config(); +const { ethers } = require("ethers"); + +async function signAndBroadcast() { + console.log("Started"); + + // Enter the serialized transaction + const rawTransaction = process.env.RAW_TRANSACTION; + + // Enter the private key of the address used to transfer the stake amount + const privateKey = process.env.HOLESKY_DEPLOYER_PRIVATE_KEY; + + // Enter the selected RPC URL + const rpcURL = process.env.HOLESKY_PROVIDER_URL; + + // Initialize the provider using the RPC URL + const provider = new ethers.providers.JsonRpcProvider(rpcURL); + + // Initialize a new Wallet instance + const wallet = new ethers.Wallet(privateKey, provider); + + // Parse the raw transaction + const tx = ethers.utils.parseTransaction(rawTransaction); + + const newTx = { + to: tx.to, + data: tx.data, + chainId: tx.chainId, + value: tx.value, + gasLimit: tx.gasLimit, + type: 2, + + nonce: await provider.getTransactionCount(wallet.address), + // Enter the max fee per gas and prirorty fee + maxFeePerGas: ethers.utils.parseUnits("5", "gwei"), + maxPriorityFeePerGas: ethers.utils.parseUnits("1", "gwei"), + }; + + // Sign the transaction + const signedTransaction = await wallet.signTransaction(newTx); + + // Send the signed transaction + const transactionResponse = await provider.sendTransaction(signedTransaction); + + return transactionResponse; +} + +signAndBroadcast() + .then((transactionResponse) => { + console.log( + "Transaction broadcasted, transaction hash:", + transactionResponse.hash + ); + }) + .catch((error) => { + console.error("Error:", error); + }) + .finally(() => { + console.log("Finished"); + }); diff --git a/contracts/tasks/ssv.js b/contracts/tasks/ssv.js new file mode 100644 index 0000000000..539ef986cc --- /dev/null +++ b/contracts/tasks/ssv.js @@ -0,0 +1,83 @@ +const { ClusterScanner, NonceScanner } = require("ssv-scanner"); +const log = require("../utils/logger")("task:ssv"); + +const getClusterInfo = async ({ + ownerAddress, + operatorids, + chainId, + ssvNetwork, +}) => { + const operatorIds = operatorids.split(".").map((id) => parseInt(id)); + + const ssvNetworkName = chainId === 1 ? "MAINNET" : "PRATER"; + const providerUrl = + chainId === 1 ? process.env.PROVIDER_URL : process.env.HOLESKY_PROVIDER_URL; + + const params = { + nodeUrl: providerUrl, // this can be an Infura, or Alchemy node, necessary to query the blockchain + contractAddress: ssvNetwork, // this is the address of SSV smart contract + ownerAddress, // this is the wallet address of the cluster owner + /* Based on the network they fetch contract ABIs. See code: https://github.com/bloxapp/ssv-scanner/blob/v1.0.3/src/lib/contract.provider.ts#L16-L22 + * and the ABIs are fetched from here: https://github.com/bloxapp/ssv-scanner/tree/v1.0.3/src/shared/abi + * + * Prater seems to work for Goerli at the moment + */ + network: ssvNetworkName, + operatorIds: operatorIds, // this is a list of operator IDs chosen by the owner for their cluster + }; + + // ClusterScanner is initialized with the given parameters + const clusterScanner = new ClusterScanner(params); + // and when run, it returns the Cluster Snapshot + const result = await clusterScanner.run(params.operatorIds); + const cluster = { + block: result.payload.Block, + snapshot: result.cluster, + cluster: Object.values(result.cluster), + }; + log(`Cluster info ${JSON.stringify(cluster)}`); + return cluster; +}; + +const getClusterNonce = async ({ + ownerAddress, + operatorids, + chainId, + ssvNetwork, +}) => { + const operatorIds = operatorids.split(".").map((id) => parseInt(id)); + + const ssvNetworkName = chainId === 1 ? "MAINNET" : "PRATER"; + const providerUrl = + chainId === 1 ? process.env.PROVIDER_URL : process.env.HOLESKY_PROVIDER_URL; + + const params = { + nodeUrl: providerUrl, // this can be an Infura, or Alchemy node, necessary to query the blockchain + contractAddress: ssvNetwork, // this is the address of SSV smart contract + ownerAddress, // this is the wallet address of the cluster owner + /* Based on the network they fetch contract ABIs. See code: https://github.com/bloxapp/ssv-scanner/blob/v1.0.3/src/lib/contract.provider.ts#L16-L22 + * and the ABIs are fetched from here: https://github.com/bloxapp/ssv-scanner/tree/v1.0.3/src/shared/abi + * + * Prater seems to work for Goerli at the moment + */ + network: ssvNetworkName, + operatorIds: operatorIds, // this is a list of operator IDs chosen by the owner for their cluster + }; + + const nonceScanner = new NonceScanner(params); + const nextNonce = await nonceScanner.run(); + return nextNonce; +}; + +const printClusterInfo = async (options) => { + const cluster = await getClusterInfo(options); + const nextNonce = await getClusterNonce(options); + console.log(`block ${cluster.block}`); + console.log(`Cluster: ${JSON.stringify(cluster.snapshot, null, " ")}`); + console.log("Next Nonce:", nextNonce); +}; + +module.exports = { + printClusterInfo, + getClusterInfo, +}; diff --git a/contracts/tasks/tasks.js b/contracts/tasks/tasks.js index e013cbd41b..6a6e08518d 100644 --- a/contracts/tasks/tasks.js +++ b/contracts/tasks/tasks.js @@ -1,10 +1,12 @@ const { subtask, task, types } = require("hardhat/config"); - const { fund } = require("./account"); const { debug } = require("./debug"); const { env } = require("./env"); const { execute, executeOnFork, proposal, governors } = require("./governance"); const { smokeTest, smokeTestCheck } = require("./smokeTest"); +const addresses = require("../utils/addresses"); +const { networkMap } = require("../utils/hardhat-helpers"); + const { storeStorageLayoutForAllContracts, assertStorageLayoutChangeSafe, @@ -46,6 +48,7 @@ const { curveSwapTask, curvePoolTask, } = require("./curve"); +const { printClusterInfo } = require("./ssv"); const { amoStrategyTask, mintAndAddOTokensTask, @@ -53,6 +56,7 @@ const { removeOnlyAssetsTask, } = require("./amoStrategy"); const { proxyUpgrades } = require("./proxy"); +const log = require("../utils/logger")("tasks"); // Environment tasks. task("env", "Check env vars are properly set for a Mainnet deployment", env); @@ -739,3 +743,34 @@ task("proxyUpgrades", "Lists all proxy implementation changes") types.int ) .setAction(proxyUpgrades); + +subtask("getClusterInfo", "Print out information regarding SSV cluster") + .addParam( + "operatorids", + "4 operator ids separated with a dot: same as IP format. E.g. 60.79.220.349", + "", + types.string + ) + .addParam( + "owner", + "Address of the cluster owner. Default to NodeDelegator", + undefined, + types.string + ) + .setAction(async (taskArgs) => { + const network = await ethers.provider.getNetwork(); + const ssvNetwork = addresses[networkMap[network.chainId]].SSVNetwork; + + log( + `Fetching cluster info for cluster owner ${taskArgs.owner} with operator ids: ${taskArgs.operatorids} from the ${network.name} network using ssvNetworkContract ${ssvNetwork}` + ); + await printClusterInfo({ + ...taskArgs, + ownerAddress: taskArgs.owner, + chainId: network.chainId, + ssvNetwork, + }); + }); +task("getClusterInfo").setAction(async (_, __, runSuper) => { + return runSuper(); +}); diff --git a/contracts/test/_fixture.js b/contracts/test/_fixture.js index 91714bc6f2..93c71a49bd 100644 --- a/contracts/test/_fixture.js +++ b/contracts/test/_fixture.js @@ -27,6 +27,8 @@ const { ousdUnits, units, isFork, + isHolesky, + isHoleskyFork, } = require("./helpers"); const { hardhatSetBalance, setERC20TokenBalance } = require("./_fund"); @@ -53,6 +55,139 @@ const log = require("../utils/logger")("test:fixtures"); let snapshotId; +const simpleOETHFixture = deployments.createFixture(async () => { + if (!snapshotId && !isFork) { + snapshotId = await nodeSnapshot(); + } + + log(`Forked from block: ${await hre.ethers.provider.getBlockNumber()}`); + log(`Before deployments with param "${isFork ? undefined : ["unit_tests"]}"`); + // Run the contract deployments + await deployments.fixture(isFork ? undefined : ["unit_tests"], { + keepExistingDeployments: true, + fallbackToGlobal: true, + }); + log(`Block after deployments: ${await hre.ethers.provider.getBlockNumber()}`); + + const { governorAddr, strategistAddr } = await getNamedAccounts(); + const sGovernor = await ethers.provider.getSigner(governorAddr); + + const oethProxy = await ethers.getContract("OETHProxy"); + const OETHVaultProxy = await ethers.getContract("OETHVaultProxy"); + const oethVault = await ethers.getContractAt( + "IVault", + OETHVaultProxy.address + ); + const oeth = await ethers.getContractAt("OETH", oethProxy.address); + + const oethHarvesterProxy = await ethers.getContract("OETHHarvesterProxy"); + const oethHarvester = await ethers.getContractAt( + "OETHHarvester", + oethHarvesterProxy.address + ); + + const oethOracleRouter = await ethers.getContract( + isFork ? "OETHOracleRouter" : "OracleRouter" + ); + + let weth, ssv, nativeStakingSSVStrategy, oethDripper; + + if (isFork) { + let addressContext = addresses.mainnet; + if (isHolesky || isHoleskyFork) { + addressContext = addresses.holesky; + } + + console.log("addressContext.WETH", addressContext.WETH); + + weth = await ethers.getContractAt("IWETH9", addressContext.WETH); + ssv = await ethers.getContractAt(erc20Abi, addressContext.SSV); + + const oethDripperProxy = await ethers.getContract("OETHDripperProxy"); + oethDripper = await ethers.getContractAt( + "OETHDripper", + oethDripperProxy.address + ); + + const nativeStakingStrategyProxy = await ethers.getContract( + "NativeStakingSSVStrategyProxy" + ); + + nativeStakingSSVStrategy = await ethers.getContractAt( + "NativeStakingSSVStrategy", + nativeStakingStrategyProxy.address + ); + } else { + weth = await ethers.getContractAt("MockWETH"); + ssv = await ethers.getContract("MockSSV"); + + const nativeStakingStrategyProxy = await ethers.getContract( + "NativeStakingSSVStrategyProxy" + ); + nativeStakingSSVStrategy = await ethers.getContractAt( + "NativeStakingSSVStrategy", + nativeStakingStrategyProxy.address + ); + } + + if (!isFork) { + // Enable capital movement + await oethVault.connect(sGovernor).unpauseCapital(); + } + + const signers = await hre.ethers.getSigners(); + let governor = signers[1]; + let strategist = signers[0]; + + const [matt, josh, anna, domen, daniel, franck] = signers.slice(4); + + if (isFork) { + governor = await ethers.provider.getSigner(governorAddr); + strategist = await ethers.provider.getSigner(strategistAddr); + + for (const user of [matt, josh, anna, domen, daniel, franck]) { + // Everyone gets free weth + await setERC20TokenBalance(user.address, weth, "1000000", hre); + // And vault can rug them all + await resetAllowance(weth, user, oethVault.address); + } + } else { + // Fund WETH contract + await hardhatSetBalance(weth.address, "999999999999999"); + + // Fund all with mockTokens + await fundAccountsForOETHUnitTests(); + + // Reset allowances + for (const user of [matt, josh, domen, daniel, franck]) { + await resetAllowance(weth, user, oethVault.address); + } + } + + return { + // Accounts + matt, + josh, + anna, + governor, + strategist, + domen, + daniel, + franck, + // Contracts + oethOracleRouter, + // Assets + ssv, + weth, + // OETH + oethVault, + oeth, + nativeStakingSSVStrategy, + oethDripper, + oethHarvester, + }; +}); + const defaultFixture = deployments.createFixture(async () => { if (!snapshotId && !isFork) { snapshotId = await nodeSnapshot(); @@ -2215,6 +2350,10 @@ async function loadDefaultFixture() { return await defaultFixture(); } +async function loadSimpleOETHFixture() { + return await simpleOETHFixture(); +} + mocha.after(async () => { if (snapshotId) { await nodeRevert(snapshotId); @@ -2223,7 +2362,9 @@ mocha.after(async () => { module.exports = { createFixtureLoader, + simpleOETHFixture, loadDefaultFixture, + loadSimpleOETHFixture, resetAllowance, defaultFixture, oethDefaultFixture, diff --git a/contracts/test/helpers.js b/contracts/test/helpers.js index ae8f1a05d5..5db24cc0b0 100644 --- a/contracts/test/helpers.js +++ b/contracts/test/helpers.js @@ -254,13 +254,17 @@ async function humanBalance(user, contract) { const isFork = process.env.FORK === "true"; const isLocalhost = !isFork && hre.network.name === "localhost"; const isMainnet = hre.network.name === "mainnet"; +const isHolesky = hre.network.name == "holesky"; +const isExternalNet = isMainnet || isHolesky; const isTest = process.env.IS_TEST === "true"; const isSmokeTest = process.env.SMOKE_TEST === "true"; const isMainnetOrFork = isMainnet || isFork; const isForkTest = isFork && isTest; const isForkWithLocalNode = isFork && process.env.LOCAL_PROVIDER_URL; const isArbitrumOne = hre.network.name == "arbitrumOne"; +const isTestnetSimplifiedDeploy = isHolesky; const isArbFork = isFork && process.env.FORK_NETWORK_NAME == "arbitrumOne"; +const isHoleskyFork = isFork && process.env.FORK_NETWORK_NAME == "holesky"; const isArbitrumOneOrFork = isArbitrumOne || isArbFork; const isCI = process.env.GITHUB_ACTIONS; @@ -429,6 +433,13 @@ const getAssetAddresses = async (deployments) => { SSVNetwork: addresses.mainnet.SSVNetwork, beaconChainDepositContract: addresses.mainnet.beaconChainDepositContract, }; + } else if (isHolesky) { + return { + WETH: addresses.holesky.WETH, + SSV: addresses.holesky.SSV, + SSVNetwork: addresses.holesky.SSVNetwork, + beaconChainDepositContract: addresses.holesky.beaconChainDepositContract, + }; } else { const addressMap = { USDT: (await deployments.get("MockUSDT")).address, @@ -771,6 +782,7 @@ module.exports = { advanceTime, getBlockTimestamp, isMainnet, + isExternalNet, isFork, isTest, isSmokeTest, @@ -779,6 +791,9 @@ module.exports = { isForkTest, isForkWithLocalNode, isArbitrumOne, + isHolesky, + isHoleskyFork, + isTestnetSimplifiedDeploy, isArbitrumOneOrFork, isArbFork, isCI, diff --git a/contracts/test/strategies/nativeSsvStaking.fork-test.js b/contracts/test/strategies/nativeSsvStaking.fork-test.js deleted file mode 100644 index 3fbd13a3c5..0000000000 --- a/contracts/test/strategies/nativeSsvStaking.fork-test.js +++ /dev/null @@ -1,46 +0,0 @@ -const { expect } = require("chai"); - -const addresses = require("../../utils/addresses"); - -const { - createFixtureLoader, - nativeStakingSSVStrategyFixture, -} = require("./../_fixture"); - -const loadFixture = createFixtureLoader(nativeStakingSSVStrategyFixture); - -describe("ForkTest: Native SSV Staking Strategy", function () { - this.timeout(0); - - // Retry up to 3 times on CI - // this.retries(isCI ? 3 : 0); - - let fixture; - beforeEach(async () => { - fixture = await loadFixture(); - }); - - describe("Initial setup", function () { - it("Should verify the initial state", async () => { - const { nativeStakingSSVStrategy } = fixture; - await expect( - await nativeStakingSSVStrategy.WETH_TOKEN_ADDRESS() - ).to.equal(addresses.mainnet.WETH, "Incorrect WETH address set"); - await expect(await nativeStakingSSVStrategy.SSV_TOKEN_ADDRESS()).to.equal( - addresses.mainnet.SSV, - "Incorrect SSV Token address" - ); - await expect( - await nativeStakingSSVStrategy.SSV_NETWORK_ADDRESS() - ).to.equal(addresses.mainnet.SSVNetwork, "Incorrect SSV Network address"); - }); - - it.skip("Should check that the fuse interval is configured correctly", async () => {}); - }); - - describe("Deposit/Allocation", function () {}); - - describe("Withdraw", function () {}); - - describe("Balance/Assets", function () {}); -}); diff --git a/contracts/test/strategies/nativeSsvStaking.holesky.fork-test.js b/contracts/test/strategies/nativeSsvStaking.holesky.fork-test.js new file mode 100644 index 0000000000..ec838941c6 --- /dev/null +++ b/contracts/test/strategies/nativeSsvStaking.holesky.fork-test.js @@ -0,0 +1,147 @@ +const { expect } = require("chai"); +const { utils, BigNumber } = require("ethers"); +const addresses = require("../../utils/addresses"); +const { units, oethUnits } = require("../helpers"); + +const { loadSimpleOETHFixture } = require("./../_fixture"); + +describe("Holesky ForkTest: Native SSV Staking Strategy", function () { + this.timeout(0); + + // Retry up to 3 times on CI + // this.retries(isCI ? 3 : 0); + + let fixture; + beforeEach(async () => { + fixture = await loadSimpleOETHFixture(); + }); + + describe("Initial setup", function () { + it("Should verify the initial state", async () => { + const { nativeStakingSSVStrategy } = fixture; + await expect( + await nativeStakingSSVStrategy.WETH_TOKEN_ADDRESS() + ).to.equal(addresses.holesky.WETH, "Incorrect WETH address set"); + await expect(await nativeStakingSSVStrategy.SSV_TOKEN_ADDRESS()).to.equal( + addresses.holesky.SSV, + "Incorrect SSV Token address" + ); + await expect( + await nativeStakingSSVStrategy.SSV_NETWORK_ADDRESS() + ).to.equal(addresses.holesky.SSVNetwork, "Incorrect SSV Network address"); + }); + + it("Should check that the fuse interval is configured correctly", async () => { + const { nativeStakingSSVStrategy } = fixture; + + await expect(utils.parseEther("21.6")).to.equal( + await nativeStakingSSVStrategy.fuseIntervalStart() + ); + await expect(utils.parseEther("25.6")).to.equal( + await nativeStakingSSVStrategy.fuseIntervalEnd() + ); + }); + }); + + describe("Deposit/Allocation register validators", function () { + it("Should mint using WETH and see balance on the strategy contract", async () => { + const { josh, weth } = fixture; + await mintTest(fixture, josh, weth, "32"); + }); + + it("Should mint using WETH and deposit to a validator", async () => { + const { josh, weth } = fixture; + await mintTest(fixture, josh, weth, "32"); + + await registerAndDepositTest(fixture); + }); + }); + + describe("Withdraw", function () {}); + + describe("Balance/Assets", function () {}); + + const registerAndDepositTest = async (fixture) => { + const { nativeStakingSSVStrategy, strategist } = fixture; + + await nativeStakingSSVStrategy + .connect(strategist) // TODO this will be a Defender relayer + .registerSsvValidator( + // pubkey + "0xb279166b18ca9ced3e0a83385799ae33b27c6cd2ad2083b9b7c33c555d091933a09b1af9fb65c6c4d51c40ca931447a9", + // operator ids + [111, 119, 230, 252], + // shares data + "0xb1edfddfdf70c8c56cfba3f00ae09815db2383c4faa328733df73dd4616492a58648d543642078c72e2bad60a22322d70ea44cc953c05aa0404681fb57498daa9cbd5c8cc98f736c75a8bf908f0eb98d6448b6778f35b1ce724fee8a1bb53f9ab60f29c5fc7c53e1577a27581b8aff689ac2fdeda72e9620f6991edb7779acef68ed2e6ea4ccfaecd00ccac09b7ed8b7abc72ea5c5469e1b5603c73fe3d054e074c88446c4e31abbc34ee309022524da5aacecb4aa83bf0ac658931813a402e4a4b1d9f83d54404b730e04e61dc82e872fa397e3a9ea249715c861ef0d4b309fdba762cd07f0506925a7a4e3e52d2c0e8f07ae01b8bb393df14c17648340c55e3a82564efb943de4033308d197d562c8bf377a589c87e4c7757afe5964ec92a616622138797c4a647dda550e3b94e3a6152cdda20d4a7b491218ab7df46a2eb9c3963811bf0555b272bf4ef5a8c0c2496e133d1cc34b01c7a5cb40d379e607d0bd7f0d8fcb965ab8d5c7634d80dbd3fac67227b53ec6fbd1a5207bfea8cb202ac88fef732328a2b717b6284af9f34a251e5ecf5eb744a4cf4df35abb423ca02556df957cd8bc645b83d497235b92f310996748c54a89106937cfcf182744ad423b104ca0a61a351d15aa9ae98093f64de31e14a7203304021ebbe2ee0e3f91e1641ff7da84396a83643101cfe67640c05467ffa8de458ebb4db0fcffe9210b72c50f8835cb636e1f5e7356092f15b29fb11761ce36a6601d599eb02d82aa02ce300a7e6c538ca72133036e5f3634c29b27c66964f65086e3f725d535f5e7d92f6a0b589a71caa7d0ca572c5192fe6ef5a4b44ad05cbb8c214a444a399b035263a1d2853bfe43b457873e700be599d3ff03532df1f52be09f6607acfc466f8bb4c4d98d74908c7394d516b738a6143a5456dc43a45f1f00a6515e11b5efc6f4dabfb3d967941ac159a8b6f7c464760c4770082b1d97600cabb1dc286d20c321e6bcb36138507915c399d8639d8a66143bff1f5a6d6cb63d0a8b560134dab42e9d23100c05e51104e068c0c76ecb5382d04e34375efea6467dfb096f6dc12b67609ea1d8310044ab8e80f75341b4aa3eb8dd5f465a3dc6b3f1dea8f25c77cdc34f0eb04247c1ac73bde467c8048cc4d57afefcb33de7520048baeaa9401fc175061881d5c60c89a4fe71cf6af8ed7ba3f6b5da42ef2ee5454f422ecf0b02d09f1ba77d35b56240232237810ffe4ff8e49c4a40a9aab7880ea91472440f30b22797f97d90a68e7904513a4267af47d988d96a17c5a2e90c4ad7c6fb56de8ba7e5488cfc16d1015963e2778e2b3def5ffdda1439cf8750b5823e31f4ba59f1eaf17c7ee98a69495a3c38c177175554b343c21f91a708c6313f146bbdde18b1fcead4e0d0274c8c1010c96f79b81060b850ab5c1da001fc908e45b84d57837fbbd272a4349261e500ce56560939cba45a58f2d0bdba3c6631e52d4e0b7a29ea50f14ed36c1ccb5fca6fdc45f881764b3ee39949ef5df255d9afdedfdf390409dadd31df7540d25174cf21a33dce1a2fd6097967be67267aa7e9353db71821bd89db0b3887eebc01cb64a4116edefac323fdde618a34d91545bab38f920e8e6f38b22a3a243b261fd56f0ec1ff6187b3ed42ddeeadf2c7a78c154d44ab332e293ca2b03e77ae1fe628378e336bc73149df4d7cbc86df73d04b9d35a9fe6a87a865f92337a8df10d5a5cf4dcc6cfba73bdd9b13d3b671acfc829b87f869ed42a48ced74099f92ac79721a79ac93d7c4d5e9be780fe1a78f807fd6a222fac05c3c8b9cd4182cb84617abaa72815b5dceec1d58b1278bf90498e4be3a456428866170046c", + // amount + BigNumber.from("1534241968000000000"), + // cluster tuple + [0, 0, 0, true, 0] + ); + + await nativeStakingSSVStrategy + .connect(strategist) // TODO this will be a Defender relayer + .stakeEth([ + [ + //pubkey + "0xb279166b18ca9ced3e0a83385799ae33b27c6cd2ad2083b9b7c33c555d091933a09b1af9fb65c6c4d51c40ca931447a9", + //signature + "0xa450d596551c7fb7aca201e9a075b034d8da1ec7bf8806740ca53c0e8653465ed9cd26d6ce10290581586676eb0dd896022a243dc42179337c9c4c2a60969a11bb9e4a2dcf57a783daf880999f6db34d1e42163cb96287b3bb91b03361942b80", + //depositDataRoot + "0x3f327f69bb527386ff4c2f820e6e375fcc632b1b7ee826bd53d4d2807cfd6769", + ], + ]); + }; + + const mintTest = async (fixture, user, asset, amount = "32") => { + const { oethVault, oeth, weth, nativeStakingSSVStrategy, strategist } = + fixture; + + const unitAmount = await units(amount, asset); + + if (asset.address != weth.address) { + const tx = oethVault.connect(user).mint(asset.address, unitAmount, "0"); + await expect(tx).to.be.revertedWith("Unsupported asset for minting"); + return; + } + + await oethVault.connect(user).allocate(); + await oethVault.connect(user).rebase(); + + const currentSupply = await oeth.totalSupply(); + const currentBalance = await oeth.connect(user).balanceOf(user.address); + const currentStrategyBalance = await nativeStakingSSVStrategy.checkBalance( + weth.address + ); + + // Mint OETH w/ asset + await oethVault.connect(user).mint(asset.address, unitAmount, 0); + + await oethVault + .connect(strategist) + .depositToStrategy( + nativeStakingSSVStrategy.address, + [asset.address], + [unitAmount] + ); + + await oethVault.connect(user).allocate(); + + const newBalance = await oeth.connect(user).balanceOf(user.address); + const newSupply = await oeth.totalSupply(); + const newStrategyBalance = await nativeStakingSSVStrategy.checkBalance( + weth.address + ); + + const balanceDiff = newBalance.sub(currentBalance); + // Ensure user has correct balance (w/ 1% slippage tolerance) + expect(balanceDiff).to.approxEqualTolerance(oethUnits(amount), 2); + + // Supply checks + const supplyDiff = newSupply.sub(currentSupply); + const oethUnitAmount = oethUnits(amount); + expect(supplyDiff).to.approxEqualTolerance(oethUnitAmount, 1); + + expect(unitAmount).to.equal(newStrategyBalance.sub(currentStrategyBalance)); + }; +}); diff --git a/contracts/utils/addresses.js b/contracts/utils/addresses.js index 36c557e3b1..65eb7d4494 100644 --- a/contracts/utils/addresses.js +++ b/contracts/utils/addresses.js @@ -6,6 +6,7 @@ addresses.dead = "0x0000000000000000000000000000000000000001"; addresses.ETH = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE"; addresses.mainnet = {}; +addresses.holesky = {}; addresses.mainnet.ORIGINTEAM = "0x449e0b5564e0d141b3bc3829e74ffa0ea8c08ad5"; @@ -250,4 +251,13 @@ addresses.mainnet.beaconChainDepositContract = addresses.arbitrumOne = {}; addresses.arbitrumOne.WOETHProxy = "0xD8724322f44E5c58D7A815F542036fb17DbbF839"; +// Holesky +addresses.holesky.WETH = "0x94373a4919B3240D86eA41593D5eBa789FEF3848"; + +// SSV network +addresses.holesky.SSV = "0xad45A78180961079BFaeEe349704F411dfF947C6"; +addresses.holesky.SSVNetwork = "0x38A4794cCEd47d3baf7370CcC43B560D3a1beEFA"; +addresses.holesky.beaconChainDepositContract = + "0x4242424242424242424242424242424242424242"; + module.exports = addresses; diff --git a/contracts/utils/deploy.js b/contracts/utils/deploy.js index 50de832405..19d4152a04 100644 --- a/contracts/utils/deploy.js +++ b/contracts/utils/deploy.js @@ -9,6 +9,7 @@ const { advanceTime, advanceBlocks, isMainnet, + isHolesky, isFork, isMainnetOrFork, getOracleAddresses, @@ -42,7 +43,8 @@ const { const { keccak256, defaultAbiCoder } = require("ethers/lib/utils.js"); // Wait for 3 blocks confirmation on Mainnet. -const NUM_CONFIRMATIONS = isMainnet ? 3 : 0; +let NUM_CONFIRMATIONS = isMainnet ? 3 : 0; +NUM_CONFIRMATIONS = isHolesky ? 4 : NUM_CONFIRMATIONS; function log(msg, deployResult = null) { if (isMainnetOrFork || process.env.VERBOSE) { @@ -705,7 +707,9 @@ const submitProposalToOgvGovernance = async ( /** * Sanity checks to perform before running the deploy */ -const sanityCheckOgvGovernance = async ({ deployerIsProposer = false }) => { +const sanityCheckOgvGovernance = async ({ + deployerIsProposer = false, +} = {}) => { if (isMainnet) { // only applicable when OGV governance is the governor if (deployerIsProposer) { diff --git a/contracts/utils/hardhat-helpers.js b/contracts/utils/hardhat-helpers.js new file mode 100644 index 0000000000..9474f402ad --- /dev/null +++ b/contracts/utils/hardhat-helpers.js @@ -0,0 +1,134 @@ +const fetch = require("sync-fetch"); +require("dotenv").config(); + +const isFork = process.env.FORK === "true"; +const isArbitrumFork = process.env.FORK_NETWORK_NAME === "arbitrumOne"; +const isHoleskyFork = process.env.FORK_NETWORK_NAME === "holesky"; +const isHolesky = process.env.NETWORK_NAME === "holesky"; +const isForkTest = isFork && process.env.IS_TEST === "true"; +const isArbForkTest = isForkTest && isArbitrumFork; +const isHoleskyForkTest = isForkTest && isHoleskyFork; +const providerUrl = `${ + process.env.LOCAL_PROVIDER_URL || process.env.PROVIDER_URL +}`; +const arbitrumProviderUrl = `${process.env.ARBITRUM_PROVIDER_URL}`; +const holeskyProviderUrl = `${process.env.HOLESKY_PROVIDER_URL}`; +const standaloneLocalNodeRunning = !!process.env.LOCAL_PROVIDER_URL; + +/** + * - Reads the fork block number from environmental variables depending on the context of the run + * - In case a local node is running (and it could have deployments executed) the updated block number is queried + * from the node and that one is used. + * - Local node is forwarded by 40 blocks + */ +const adjustTheForkBlockNumber = () => { + let forkBlockNumber = undefined; + + if (isForkTest) { + if (isArbForkTest) { + forkBlockNumber = process.env.ARBITRUM_BLOCK_NUMBER + ? process.env.ARBITRUM_BLOCK_NUMBER + : undefined; + } else if (isHoleskyForkTest) { + forkBlockNumber = process.env.HOLESKY_BLOCK_NUMBER + ? process.env.HOLESKY_BLOCK_NUMBER + : undefined; + } else { + forkBlockNumber = process.env.BLOCK_NUMBER + ? process.env.BLOCK_NUMBER + : undefined; + } + } + + if (isForkTest && standaloneLocalNodeRunning) { + const jsonResponse = fetch(providerUrl, { + method: "post", + body: JSON.stringify({ + jsonrpc: "2.0", + method: "eth_blockNumber", + id: 1, + }), + headers: { + "Content-Type": "application/json", + }, + }).json(); + + /* + * We source the block number from the hardhat context rather than from + * node-test.sh startup script, so that block number from an already + * running local node can be fetched after the deployments have already + * been applied. + * + */ + forkBlockNumber = parseInt(jsonResponse.result, 16); + + console.log(`Connecting to local node on block: ${forkBlockNumber}`); + + // Mine 40 blocks so hardhat wont complain about block fork being too recent + // On Holesky running this causes repeated tests connecting to a local node + // to fail + if (!isHoleskyFork && !isHolesky) { + fetch(providerUrl, { + method: "post", + body: JSON.stringify({ + jsonrpc: "2.0", + method: "hardhat_mine", + params: ["0x28"], // 40 + id: 1, + }), + headers: { + "Content-Type": "application/json", + }, + }).json(); + } + } else if (isForkTest) { + console.log(`Starting a fresh node on block: ${forkBlockNumber}`); + } + + return forkBlockNumber; +}; + +// returns hardhat network chainId and provider +const getHardhatNetworkProperties = () => { + let chainId = 1337; + if (isArbitrumFork && isFork) { + chainId = 42161; + } else if (isHoleskyFork && isFork) { + chainId = 17000; + } else if (isFork) { + // is mainnet fork + chainId = 1; + } + + let provider = providerUrl; + if (isArbForkTest) { + provider = arbitrumProviderUrl; + } else if (isHoleskyForkTest) { + provider = holeskyProviderUrl; + } + + return { chainId, provider }; +}; + +const networkMap = { + 1: "mainnet", + 17000: "holesky", + 42161: "arbitrumOne", + 1337: "hardhat", +}; + +module.exports = { + isFork, + isArbitrumFork, + isHoleskyFork, + isHolesky, + isForkTest, + isArbForkTest, + isHoleskyForkTest, + providerUrl, + arbitrumProviderUrl, + holeskyProviderUrl, + adjustTheForkBlockNumber, + getHardhatNetworkProperties, + networkMap, +}; diff --git a/contracts/yarn.lock b/contracts/yarn.lock index 8aa18ddbbc..df633b97f9 100644 --- a/contracts/yarn.lock +++ b/contracts/yarn.lock @@ -233,7 +233,7 @@ crc-32 "^1.2.0" ethereumjs-util "^7.1.3" -"@ethereumjs/common@^2.6.0", "@ethereumjs/common@^2.6.4", "@ethereumjs/common@^2.6.5": +"@ethereumjs/common@2.6.5", "@ethereumjs/common@^2.6.0", "@ethereumjs/common@^2.6.4", "@ethereumjs/common@^2.6.5": version "2.6.5" resolved "https://registry.yarnpkg.com/@ethereumjs/common/-/common-2.6.5.tgz#0a75a22a046272579d91919cb12d84f2756e8d30" integrity sha512-lRyVQOeCDaIVtgfbowla32pzeDv2Obr8oR8Put5RdUBNRGr1VGPGQNGP6elWIpgK3YdpzqTOh4GyUGOureVeeA== @@ -252,6 +252,11 @@ ethereumjs-util "^7.1.1" miller-rabin "^4.0.0" +"@ethereumjs/rlp@^4.0.1": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@ethereumjs/rlp/-/rlp-4.0.1.tgz#626fabfd9081baab3d0a3074b0c7ecaf674aaa41" + integrity sha512-tqsQiBQDQdmPWE1xkkBq4rlSW5QZpLOUJ5RJh2/9fug+q9tnUhuZoVLk7s0scUIKTOzEtR72DFBXI4WiZcMpvw== + "@ethereumjs/tx@3.4.0": version "3.4.0" resolved "https://registry.yarnpkg.com/@ethereumjs/tx/-/tx-3.4.0.tgz#7eb1947eefa55eb9cf05b3ca116fb7a3dbd0bce7" @@ -260,7 +265,7 @@ "@ethereumjs/common" "^2.6.0" ethereumjs-util "^7.1.3" -"@ethereumjs/tx@^3.4.0", "@ethereumjs/tx@^3.5.2": +"@ethereumjs/tx@3.5.2", "@ethereumjs/tx@^3.4.0", "@ethereumjs/tx@^3.5.2": version "3.5.2" resolved "https://registry.yarnpkg.com/@ethereumjs/tx/-/tx-3.5.2.tgz#197b9b6299582ad84f9527ca961466fce2296c1c" integrity sha512-gQDNJWKrSDGu2w7w0PzVXVBNMzb7wwdDOmOqczmhNjqFxFuIbhVJDwiGEnxFNC2/b8ifcZzY7MLcluizohRzNw== @@ -268,6 +273,15 @@ "@ethereumjs/common" "^2.6.4" ethereumjs-util "^7.1.5" +"@ethereumjs/util@^8.1.0": + version "8.1.0" + resolved "https://registry.yarnpkg.com/@ethereumjs/util/-/util-8.1.0.tgz#299df97fb6b034e0577ce9f94c7d9d1004409ed4" + integrity sha512-zQ0IqbdX8FZ9aw11vP+dZkKDkS+kgIvQPHnSAXzP9pLu+Rfu3D3XEeLbicvoXJTYnhZiPmsZUxgdzXwNKxRPbA== + dependencies: + "@ethereumjs/rlp" "^4.0.1" + ethereum-cryptography "^2.0.0" + micro-ftch "^0.3.1" + "@ethereumjs/vm@5.6.0": version "5.6.0" resolved "https://registry.yarnpkg.com/@ethereumjs/vm/-/vm-5.6.0.tgz#e0ca62af07de820143674c30b776b86c1983a464" @@ -561,7 +575,7 @@ "@ethersproject/constants" "^5.7.0" "@ethersproject/logger" "^5.7.0" -"@ethersproject/transactions@5.7.0", "@ethersproject/transactions@^5.7.0": +"@ethersproject/transactions@5.7.0", "@ethersproject/transactions@^5.6.2", "@ethersproject/transactions@^5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/transactions/-/transactions-5.7.0.tgz#91318fc24063e057885a6af13fdb703e1f993d3b" integrity sha512-kmcNicCp1lp8qanMTC3RIikGgoJ80ztTyvtsFvCYpSCfkjhD0jZ2LOrnbcuxuToLIUYYf+4XwD1rP+B/erDIhQ== @@ -715,11 +729,23 @@ tweetnacl "^1.0.3" tweetnacl-util "^0.15.1" +"@noble/curves@1.3.0", "@noble/curves@~1.3.0": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.3.0.tgz#01be46da4fd195822dab821e72f71bf4aeec635e" + integrity sha512-t01iSXPuN+Eqzb4eBX0S5oubSqXbK/xXa1Ne18Hj8f9pStxztHCE2gfboSp/dZRLSqfuLpRK2nDXDK+W9puocA== + dependencies: + "@noble/hashes" "1.3.3" + "@noble/hashes@1.2.0", "@noble/hashes@~1.2.0": version "1.2.0" resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.2.0.tgz#a3150eeb09cc7ab207ebf6d7b9ad311a9bdbed12" integrity sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ== +"@noble/hashes@1.3.3", "@noble/hashes@~1.3.2": + version "1.3.3" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.3.tgz#39908da56a4adc270147bb07968bf3b16cfe1699" + integrity sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA== + "@noble/secp256k1@1.7.1", "@noble/secp256k1@~1.7.0": version "1.7.1" resolved "https://registry.yarnpkg.com/@noble/secp256k1/-/secp256k1-1.7.1.tgz#b251c70f824ce3ca7f8dc3df08d58f005cc0507c" @@ -1189,6 +1215,11 @@ resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.1.1.tgz#ebb651ee52ff84f420097055f4bf46cfba403938" integrity sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA== +"@scure/base@~1.1.4": + version "1.1.6" + resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.1.6.tgz#8ce5d304b436e4c84f896e0550c83e4d88cb917d" + integrity sha512-ok9AWwhcgYuGG3Zfhyqg+zwl+Wn5uE+dwC0NV/2qQkx4dABbb/bx96vWu8NSj+BNjjSjno+JRYRjle1jV08k3g== + "@scure/bip32@1.1.5": version "1.1.5" resolved "https://registry.yarnpkg.com/@scure/bip32/-/bip32-1.1.5.tgz#d2ccae16dcc2e75bc1d75f5ef3c66a338d1ba300" @@ -1198,6 +1229,15 @@ "@noble/secp256k1" "~1.7.0" "@scure/base" "~1.1.0" +"@scure/bip32@1.3.3": + version "1.3.3" + resolved "https://registry.yarnpkg.com/@scure/bip32/-/bip32-1.3.3.tgz#a9624991dc8767087c57999a5d79488f48eae6c8" + integrity sha512-LJaN3HwRbfQK0X1xFSi0Q9amqOgzQnnDngIt+ZlsBC3Bm7/nE7K0kwshZHyaru79yIVRv/e1mQAjZyuZG6jOFQ== + dependencies: + "@noble/curves" "~1.3.0" + "@noble/hashes" "~1.3.2" + "@scure/base" "~1.1.4" + "@scure/bip39@1.1.1": version "1.1.1" resolved "https://registry.yarnpkg.com/@scure/bip39/-/bip39-1.1.1.tgz#b54557b2e86214319405db819c4b6a370cf340c5" @@ -1206,6 +1246,14 @@ "@noble/hashes" "~1.2.0" "@scure/base" "~1.1.0" +"@scure/bip39@1.2.2": + version "1.2.2" + resolved "https://registry.yarnpkg.com/@scure/bip39/-/bip39-1.2.2.tgz#f3426813f4ced11a47489cbcf7294aa963966527" + integrity sha512-HYf9TUXG80beW+hGAt3TRM8wU6pQoYur9iNypTROm42dorCGmLnFe3eWjz3gOq6G62H2WRh0FCzAR1PI+29zIA== + dependencies: + "@noble/hashes" "~1.3.2" + "@scure/base" "~1.1.4" + "@sentry/core@5.30.0": version "5.30.0" resolved "https://registry.yarnpkg.com/@sentry/core/-/core-5.30.0.tgz#6b203664f69e75106ee8b5a2fe1d717379b331f3" @@ -1274,6 +1322,11 @@ "@sentry/types" "5.30.0" tslib "^1.9.3" +"@sindresorhus/is@^4.0.0", "@sindresorhus/is@^4.6.0": + version "4.6.0" + resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-4.6.0.tgz#3c7c9c46e678feefe7a2e5bb609d3dbd665ffb3f" + integrity sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw== + "@solidity-parser/parser@0.12.1": version "0.12.1" resolved "https://registry.yarnpkg.com/@solidity-parser/parser/-/parser-0.12.1.tgz#10ce249890d32ba500e9ce449e60a2b26b11be7a" @@ -1300,6 +1353,20 @@ dependencies: antlr4ts "^0.5.0-alpha.4" +"@szmarczak/http-timer@^4.0.5": + version "4.0.6" + resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-4.0.6.tgz#b4a914bb62e7c272d4e5989fe4440f812ab1d807" + integrity sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w== + dependencies: + defer-to-connect "^2.0.0" + +"@szmarczak/http-timer@^5.0.1": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-5.0.1.tgz#c7c1bf1141cdd4751b0399c8fc7b8b664cd5be3a" + integrity sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw== + dependencies: + defer-to-connect "^2.0.1" + "@trufflesuite/bigint-buffer@1.1.10": version "1.1.10" resolved "https://registry.yarnpkg.com/@trufflesuite/bigint-buffer/-/bigint-buffer-1.1.10.tgz#a1d9ca22d3cad1a138b78baaf15543637a3e1692" @@ -1341,6 +1408,23 @@ dependencies: "@types/node" "*" +"@types/bn.js@^5.1.1": + version "5.1.5" + resolved "https://registry.yarnpkg.com/@types/bn.js/-/bn.js-5.1.5.tgz#2e0dacdcce2c0f16b905d20ff87aedbc6f7b4bf0" + integrity sha512-V46N0zwKRF5Q00AZ6hWtN0T8gGmDUaUzLWQvHFo5yThtVwK/VCenFY3wXVbOvNfajEpsTfQM4IN9k/d6gUVX3A== + dependencies: + "@types/node" "*" + +"@types/cacheable-request@^6.0.1", "@types/cacheable-request@^6.0.2": + version "6.0.3" + resolved "https://registry.yarnpkg.com/@types/cacheable-request/-/cacheable-request-6.0.3.tgz#a430b3260466ca7b5ca5bfd735693b36e7a9d183" + integrity sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw== + dependencies: + "@types/http-cache-semantics" "*" + "@types/keyv" "^3.1.4" + "@types/node" "*" + "@types/responselike" "^1.0.0" + "@types/concat-stream@^1.6.0": version "1.6.1" resolved "https://registry.yarnpkg.com/@types/concat-stream/-/concat-stream-1.6.1.tgz#24bcfc101ecf68e886aaedce60dfd74b632a1b74" @@ -1348,6 +1432,11 @@ dependencies: "@types/node" "*" +"@types/figlet@^1.5.4": + version "1.5.8" + resolved "https://registry.yarnpkg.com/@types/figlet/-/figlet-1.5.8.tgz#96b8186c7e2a388b4f8d09ee3276cba2af88bb0b" + integrity sha512-G22AUvy4Tl95XLE7jmUM8s8mKcoz+Hr+Xm9W90gJsppJq9f9tHvOGkrpn4gRX0q/cLtBdNkWtWCKDg2UDZoZvQ== + "@types/form-data@0.0.33": version "0.0.33" resolved "https://registry.yarnpkg.com/@types/form-data/-/form-data-0.0.33.tgz#c9ac85b2a5fd18435b8c85d9ecb50e6d6c893ff8" @@ -1363,6 +1452,18 @@ "@types/minimatch" "*" "@types/node" "*" +"@types/http-cache-semantics@*": + version "4.0.4" + resolved "https://registry.yarnpkg.com/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz#b979ebad3919799c979b17c72621c0bc0a31c6c4" + integrity sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA== + +"@types/keyv@^3.1.4": + version "3.1.4" + resolved "https://registry.yarnpkg.com/@types/keyv/-/keyv-3.1.4.tgz#3ccdb1c6751b0c7e52300bcdacd5bcbf8faa75b6" + integrity sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg== + dependencies: + "@types/node" "*" + "@types/level-errors@*": version "3.0.0" resolved "https://registry.yarnpkg.com/@types/level-errors/-/level-errors-3.0.0.tgz#15c1f4915a5ef763b51651b15e90f6dc081b96a8" @@ -1417,6 +1518,11 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.60.tgz#35f3d6213daed95da7f0f73e75bcc6980e90597b" integrity sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw== +"@types/node@^12.12.6": + version "12.20.55" + resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.55.tgz#c329cbd434c42164f846b909bd6f85b5537f6240" + integrity sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ== + "@types/node@^8.0.0": version "8.10.66" resolved "https://registry.yarnpkg.com/@types/node/-/node-8.10.66.tgz#dd035d409df322acc83dff62a602f12a5783bbb3" @@ -1447,6 +1553,13 @@ "@types/node" "*" safe-buffer "~5.1.1" +"@types/responselike@^1.0.0": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@types/responselike/-/responselike-1.0.3.tgz#cc29706f0a397cfe6df89debfe4bf5cea159db50" + integrity sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw== + dependencies: + "@types/node" "*" + "@types/secp256k1@^4.0.1": version "4.0.3" resolved "https://registry.yarnpkg.com/@types/secp256k1/-/secp256k1-4.0.3.tgz#1b8e55d8e00f08ee7220b4d59a6abe89c37a901c" @@ -1507,6 +1620,11 @@ abort-controller@^3.0.0: dependencies: event-target-shim "^5.0.0" +abortcontroller-polyfill@^1.7.5: + version "1.7.5" + resolved "https://registry.yarnpkg.com/abortcontroller-polyfill/-/abortcontroller-polyfill-1.7.5.tgz#6738495f4e901fbb57b6c0611d0c75f76c485bed" + integrity sha512-JMJ5soJWP18htbbxJjG7bG6yuI6pRhgJ0scHHTfkUjf6wjP912xZWvM+A4sJK3gqd9E8fcPbDnOefbA9Th/FIQ== + abstract-level@^1.0.0, abstract-level@^1.0.2, abstract-level@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/abstract-level/-/abstract-level-1.0.3.tgz#78a67d3d84da55ee15201486ab44c09560070741" @@ -1554,6 +1672,14 @@ abstract-leveldown@~6.2.1: level-supports "~1.0.0" xtend "~4.0.0" +accepts@~1.3.8: + version "1.3.8" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" + integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== + dependencies: + mime-types "~2.1.34" + negotiator "0.6.3" + acorn-jsx@^5.0.0, acorn-jsx@^5.3.1: version "5.3.2" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" @@ -1744,6 +1870,11 @@ array-buffer-byte-length@^1.0.0: call-bind "^1.0.2" is-array-buffer "^3.0.1" +array-flatten@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + integrity sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg== + array-union@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" @@ -1809,6 +1940,11 @@ async-eventemitter@^0.2.4: dependencies: async "^2.4.0" +async-limiter@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" + integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ== + async-retry@^1.3.3: version "1.3.3" resolved "https://registry.yarnpkg.com/async-retry/-/async-retry-1.3.3.tgz#0e7f36c04d8478e7a58bdbed80cedf977785f280" @@ -1838,6 +1974,13 @@ available-typed-arrays@^1.0.5: resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7" integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw== +available-typed-arrays@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz#a5cc375d6a03c2efc87a553f3e0b1522def14846" + integrity sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ== + dependencies: + possible-typed-array-names "^1.0.0" + aws-sign2@~0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" @@ -1869,7 +2012,7 @@ balanced-match@^1.0.0: resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== -base-x@^3.0.2: +base-x@^3.0.2, base-x@^3.0.8: version "3.0.9" resolved "https://registry.yarnpkg.com/base-x/-/base-x-3.0.9.tgz#6349aaabb58526332de9f60995e548a53fe21320" integrity sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ== @@ -1928,12 +2071,17 @@ blakejs@^1.1.0: resolved "https://registry.yarnpkg.com/blakejs/-/blakejs-1.2.1.tgz#5057e4206eadb4a97f7c0b6e197a505042fc3814" integrity sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ== +bluebird@^3.5.0: + version "3.7.2" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" + integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== + bn.js@4.11.6: version "4.11.6" resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.6.tgz#53344adb14617a13f6e8dd2ce28905d1c0ba3215" integrity sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA== -bn.js@^4.0.0, bn.js@^4.11.0, bn.js@^4.11.1, bn.js@^4.11.8, bn.js@^4.11.9: +bn.js@^4.0.0, bn.js@^4.11.0, bn.js@^4.11.1, bn.js@^4.11.6, bn.js@^4.11.8, bn.js@^4.11.9: version "4.12.0" resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== @@ -1943,6 +2091,24 @@ bn.js@^5.1.2, bn.js@^5.2.0, bn.js@^5.2.1: resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70" integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ== +body-parser@1.20.2, body-parser@^1.16.0: + version "1.20.2" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.2.tgz#6feb0e21c4724d06de7ff38da36dad4f57a747fd" + integrity sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA== + dependencies: + bytes "3.1.2" + content-type "~1.0.5" + debug "2.6.9" + depd "2.0.0" + destroy "1.2.0" + http-errors "2.0.0" + iconv-lite "0.4.24" + on-finished "2.4.1" + qs "6.11.0" + raw-body "2.5.2" + type-is "~1.6.18" + unpipe "1.0.0" + brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" @@ -2018,6 +2184,11 @@ buffer-from@^1.0.0: resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== +buffer-to-arraybuffer@^0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/buffer-to-arraybuffer/-/buffer-to-arraybuffer-0.0.5.tgz#6064a40fa76eb43c723aba9ef8f6e1216d10511a" + integrity sha512-3dthu5CYiVB1DEJp61FtApNnNndTckcqe4pFcLdvHtrpG+kcyekCJKg4MRiDcFW7A6AODnXB9U4dwQiCW5kzJQ== + buffer-xor@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" @@ -2039,7 +2210,7 @@ buffer@4.9.2: ieee754 "^1.1.4" isarray "^1.0.0" -buffer@^5.5.0, buffer@^5.6.0: +buffer@^5.0.5, buffer@^5.5.0, buffer@^5.6.0: version "5.7.1" resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== @@ -2062,6 +2233,13 @@ bufferutil@4.0.5: dependencies: node-gyp-build "^4.3.0" +bufferutil@^4.0.1: + version "4.0.8" + resolved "https://registry.yarnpkg.com/bufferutil/-/bufferutil-4.0.8.tgz#1de6a71092d65d7766c4d8a522b261a6e787e8ea" + integrity sha512-4T53u4PdgsXqKaIctwF8ifXlRTTmEPJ8iEPWFdGZvcf7sbwYo6FKFEX9eNNAnzFZ7EzJAQ3CJeOtCRA4rDp7Pw== + dependencies: + node-gyp-build "^4.3.0" + bufio@^1.0.7: version "1.2.1" resolved "https://registry.yarnpkg.com/bufio/-/bufio-1.2.1.tgz#8d4ab3ddfcd5faa90f996f922f9397d41cbaf2de" @@ -2079,6 +2257,29 @@ bytes@3.1.2: resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== +cacheable-lookup@^5.0.3: + version "5.0.4" + resolved "https://registry.yarnpkg.com/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz#5a6b865b2c44357be3d5ebc2a467b032719a7005" + integrity sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA== + +cacheable-lookup@^6.0.4: + version "6.1.0" + resolved "https://registry.yarnpkg.com/cacheable-lookup/-/cacheable-lookup-6.1.0.tgz#0330a543471c61faa4e9035db583aad753b36385" + integrity sha512-KJ/Dmo1lDDhmW2XDPMo+9oiy/CeqosPguPCrgcVzKyZrL6pM1gU2GmPY/xo6OQPTUaA/c0kwHuywB4E6nmT9ww== + +cacheable-request@^7.0.2: + version "7.0.4" + resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-7.0.4.tgz#7a33ebf08613178b403635be7b899d3e69bbe817" + integrity sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg== + dependencies: + clone-response "^1.0.2" + get-stream "^5.1.0" + http-cache-semantics "^4.0.0" + keyv "^4.0.0" + lowercase-keys "^2.0.0" + normalize-url "^6.0.1" + responselike "^2.0.0" + call-bind@^1.0.0, call-bind@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" @@ -2087,6 +2288,17 @@ call-bind@^1.0.0, call-bind@^1.0.2: function-bind "^1.1.1" get-intrinsic "^1.0.2" +call-bind@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9" + integrity sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w== + dependencies: + es-define-property "^1.0.0" + es-errors "^1.3.0" + function-bind "^1.1.2" + get-intrinsic "^1.2.4" + set-function-length "^1.2.1" + caller-callsite@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/caller-callsite/-/caller-callsite-2.0.0.tgz#847e0fce0a223750a9a027c54b33731ad3154134" @@ -2218,11 +2430,27 @@ chokidar@3.5.3, chokidar@^3.4.0, chokidar@^3.5.2: optionalDependencies: fsevents "~2.3.2" +chownr@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" + integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== + ci-info@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== +cids@^0.7.1: + version "0.7.5" + resolved "https://registry.yarnpkg.com/cids/-/cids-0.7.5.tgz#60a08138a99bfb69b6be4ceb63bfef7a396b28b2" + integrity sha512-zT7mPeghoWAu+ppn8+BS1tQ5qGmbMfB4AregnQjA/qHY3GC1m1ptI9GkWNlgeu38r7CuRdXB47uY2XgAYt6QVA== + dependencies: + buffer "^5.5.0" + class-is "^1.1.0" + multibase "~0.6.0" + multicodec "^1.0.0" + multihashes "~0.4.15" + cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" @@ -2231,6 +2459,11 @@ cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: inherits "^2.0.1" safe-buffer "^5.0.1" +class-is@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/class-is/-/class-is-1.1.0.tgz#9d3c0fba0440d211d843cec3dedfa48055005825" + integrity sha512-rhjH9AG1fvabIDoGRVH587413LPjTZgmDF9fOFCbFJQV4yuocX1mHxxvXI4g3cGwbVY9wAYIoKlg1N79frJKQw== + classic-level@^1.2.0: version "1.3.0" resolved "https://registry.yarnpkg.com/classic-level/-/classic-level-1.3.0.tgz#5e36680e01dc6b271775c093f2150844c5edd5c8" @@ -2254,6 +2487,13 @@ cli-cursor@^2.1.0: dependencies: restore-cursor "^2.0.0" +cli-progress@^3.11.2: + version "3.12.0" + resolved "https://registry.yarnpkg.com/cli-progress/-/cli-progress-3.12.0.tgz#807ee14b66bcc086258e444ad0f19e7d42577942" + integrity sha512-tRkV3HJ1ASwm19THiiLIXLO7Im7wlTuKnvkYaTkyoAPefqjNg7W7DHKUlGRxy9vxDvbyCYQkQozvptuMkGCg8A== + dependencies: + string-width "^4.2.3" + cli-table3@^0.5.0: version "0.5.1" resolved "https://registry.yarnpkg.com/cli-table3/-/cli-table3-0.5.1.tgz#0252372d94dfc40dbd8df06005f48f31f656f202" @@ -2296,6 +2536,13 @@ cliui@^7.0.2: strip-ansi "^6.0.0" wrap-ansi "^7.0.0" +clone-response@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.3.tgz#af2032aa47816399cf5f0a1d0db902f517abb8c3" + integrity sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA== + dependencies: + mimic-response "^1.0.0" + color-convert@^1.9.0: version "1.9.3" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" @@ -2397,6 +2644,37 @@ concat-stream@^1.6.0, concat-stream@^1.6.2: readable-stream "^2.2.2" typedarray "^0.0.6" +content-disposition@0.5.4: + version "0.5.4" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" + integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== + dependencies: + safe-buffer "5.2.1" + +content-hash@^2.5.2: + version "2.5.2" + resolved "https://registry.yarnpkg.com/content-hash/-/content-hash-2.5.2.tgz#bbc2655e7c21f14fd3bfc7b7d4bfe6e454c9e211" + integrity sha512-FvIQKy0S1JaWV10sMsA7TRx8bpU+pqPkhbsfvOJAdjRXvYxEckAwQWGwtRjiaJfh+E0DvcWUGqcdjwMGFjsSdw== + dependencies: + cids "^0.7.1" + multicodec "^0.5.5" + multihashes "^0.4.15" + +content-type@~1.0.4, content-type@~1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918" + integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== + +cookie-signature@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ== + +cookie@0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.6.0.tgz#2798b04b071b0ecbff0dbb62a505a8efa4e19051" + integrity sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw== + cookie@^0.4.1: version "0.4.2" resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.2.tgz#0e41f24de5ecf317947c82fc789e06a884824432" @@ -2417,6 +2695,14 @@ core-util-is@~1.0.0: resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== +cors@^2.8.1: + version "2.8.5" + resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29" + integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g== + dependencies: + object-assign "^4" + vary "^1" + cosmiconfig@^5.0.7: version "5.2.1" resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-5.2.1.tgz#040f726809c591e77a17c0a3626ca45b4f168b1a" @@ -2465,6 +2751,13 @@ create-hmac@^1.1.4, create-hmac@^1.1.7: safe-buffer "^5.0.1" sha.js "^2.4.8" +cross-fetch@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-4.0.0.tgz#f037aef1580bb3a1a35164ea2a848ba81b445983" + integrity sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g== + dependencies: + node-fetch "^2.6.12" + cross-spawn@^6.0.5: version "6.0.5" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" @@ -2490,6 +2783,14 @@ cross-spawn@^7.0.2: resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b" integrity sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow== +d@1, d@^1.0.1, d@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/d/-/d-1.0.2.tgz#2aefd554b81981e7dccf72d6842ae725cb17e5de" + integrity sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw== + dependencies: + es5-ext "^0.10.64" + type "^2.7.2" + dashdash@^1.12.0: version "1.14.1" resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" @@ -2502,6 +2803,13 @@ death@^1.1.0: resolved "https://registry.yarnpkg.com/death/-/death-1.1.0.tgz#01aa9c401edd92750514470b8266390c66c67318" integrity sha512-vsV6S4KVHvTGxbEcij7hkWRv0It+sGGWVOM67dQde/o5Xjnr+KmLjxWJii2uEObIrt1CcM9w0Yaovx+iOlIL+w== +debug@2.6.9, debug@^2.2.0: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + debug@3.2.6: version "3.2.6" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" @@ -2516,13 +2824,6 @@ debug@4, debug@4.3.4, debug@^4.0.1, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, de dependencies: ms "2.1.2" -debug@^2.2.0: - version "2.6.9" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" - integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== - dependencies: - ms "2.0.0" - debug@^3.1.0: version "3.2.7" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" @@ -2540,6 +2841,25 @@ decamelize@^4.0.0: resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837" integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ== +decode-uri-component@^0.2.0: + version "0.2.2" + resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.2.tgz#e69dbe25d37941171dd540e024c444cd5188e1e9" + integrity sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ== + +decompress-response@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3" + integrity sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA== + dependencies: + mimic-response "^1.0.0" + +decompress-response@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-6.0.0.tgz#ca387612ddb7e104bd16d85aab00d5ecf09c66fc" + integrity sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ== + dependencies: + mimic-response "^3.1.0" + deep-eql@^4.1.2: version "4.1.3" resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-4.1.3.tgz#7c7775513092f7df98d8df9996dd085eb668cc6d" @@ -2568,6 +2888,11 @@ defender-base-client@^1.44.0: lodash "^4.17.19" node-fetch "^2.6.0" +defer-to-connect@^2.0.0, defer-to-connect@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-2.0.1.tgz#8016bdb4143e4632b77a3449c6236277de520587" + integrity sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg== + deferred-leveldown@~5.3.0: version "5.3.0" resolved "https://registry.yarnpkg.com/deferred-leveldown/-/deferred-leveldown-5.3.0.tgz#27a997ad95408b61161aa69bd489b86c71b78058" @@ -2576,6 +2901,15 @@ deferred-leveldown@~5.3.0: abstract-leveldown "~6.2.1" inherits "^2.0.3" +define-data-property@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e" + integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A== + dependencies: + es-define-property "^1.0.0" + es-errors "^1.3.0" + gopd "^1.0.1" + define-properties@^1.1.2, define-properties@^1.1.3, define-properties@^1.1.4, define-properties@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.0.tgz#52988570670c9eacedd8064f4a990f2405849bd5" @@ -2594,6 +2928,11 @@ depd@2.0.0: resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== +destroy@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" + integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== + detect-port@^1.3.0: version "1.5.1" resolved "https://registry.yarnpkg.com/detect-port/-/detect-port-1.5.1.tgz#451ca9b6eaf20451acb0799b8ab40dff7718727b" @@ -2633,6 +2972,11 @@ doctrine@^3.0.0: dependencies: esutils "^2.0.2" +dom-walk@^0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.2.tgz#0c548bef048f4d1f2a97249002236060daa3fd84" + integrity sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w== + dotenv@^10.0.0: version "10.0.0" resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-10.0.0.tgz#3d4227b8fb95f81096cdd2b66653fb2c7085ba81" @@ -2646,6 +2990,11 @@ ecc-jsbn@~0.1.1: jsbn "~0.1.0" safer-buffer "^2.1.0" +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== + elliptic@6.5.4, elliptic@^6.5.2, elliptic@^6.5.4: version "6.5.4" resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb" @@ -2659,6 +3008,19 @@ elliptic@6.5.4, elliptic@^6.5.2, elliptic@^6.5.4: minimalistic-assert "^1.0.1" minimalistic-crypto-utils "^1.0.1" +elliptic@^6.4.0: + version "6.5.5" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.5.tgz#c715e09f78b6923977610d4c2346d6ce22e6dded" + integrity sha512-7EjbcmUm17NQFu4Pmgmq2olYMj8nwMnpcddByChSUjArp8F5DQWcIcpriwO4ZToLNAJig0yiyjswfyGNje/ixw== + dependencies: + bn.js "^4.11.9" + brorand "^1.1.0" + hash.js "^1.0.0" + hmac-drbg "^1.0.1" + inherits "^2.0.4" + minimalistic-assert "^1.0.1" + minimalistic-crypto-utils "^1.0.1" + emittery@0.10.0: version "0.10.0" resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.10.0.tgz#bb373c660a9d421bb44706ec4967ed50c02a8026" @@ -2684,6 +3046,11 @@ encode-utf8@^1.0.2: resolved "https://registry.yarnpkg.com/encode-utf8/-/encode-utf8-1.0.3.tgz#f30fdd31da07fb596f281beb2f6b027851994cda" integrity sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw== +encodeurl@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== + encoding-down@^6.3.0: version "6.3.0" resolved "https://registry.yarnpkg.com/encoding-down/-/encoding-down-6.3.0.tgz#b1c4eb0e1728c146ecaef8e32963c549e76d082b" @@ -2694,6 +3061,13 @@ encoding-down@^6.3.0: level-codec "^9.0.0" level-errors "^2.0.0" +end-of-stream@^1.1.0: + version "1.4.4" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" + integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== + dependencies: + once "^1.4.0" + enquirer@^2.3.0, enquirer@^2.3.5, enquirer@^2.3.6: version "2.3.6" resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.3.6.tgz#2a7fe5dd634a1e4125a975ec994ff5456dc3734d" @@ -2765,6 +3139,18 @@ es-array-method-boxes-properly@^1.0.0: resolved "https://registry.yarnpkg.com/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz#873f3e84418de4ee19c5be752990b2e44718d09e" integrity sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA== +es-define-property@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.0.tgz#c7faefbdff8b2696cf5f46921edfb77cc4ba3845" + integrity sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ== + dependencies: + get-intrinsic "^1.2.4" + +es-errors@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" + integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== + es-set-tostringtag@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz#338d502f6f674301d710b80c8592de8a15f09cd8" @@ -2783,11 +3169,48 @@ es-to-primitive@^1.2.1: is-date-object "^1.0.1" is-symbol "^1.0.2" +es5-ext@^0.10.35, es5-ext@^0.10.50, es5-ext@^0.10.62, es5-ext@^0.10.64, es5-ext@~0.10.14: + version "0.10.64" + resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.64.tgz#12e4ffb48f1ba2ea777f1fcdd1918ef73ea21714" + integrity sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg== + dependencies: + es6-iterator "^2.0.3" + es6-symbol "^3.1.3" + esniff "^2.0.1" + next-tick "^1.1.0" + +es6-iterator@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7" + integrity sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g== + dependencies: + d "1" + es5-ext "^0.10.35" + es6-symbol "^3.1.1" + +es6-promise@^4.2.8: + version "4.2.8" + resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a" + integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w== + +es6-symbol@^3.1.1, es6-symbol@^3.1.3: + version "3.1.4" + resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.4.tgz#f4e7d28013770b4208ecbf3e0bf14d3bcb557b8c" + integrity sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg== + dependencies: + d "^1.0.2" + ext "^1.7.0" + escalade@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== +escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== + escape-string-regexp@1.0.5, escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" @@ -2938,6 +3361,16 @@ eslint@^7.32.0: text-table "^0.2.0" v8-compile-cache "^2.0.3" +esniff@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/esniff/-/esniff-2.0.1.tgz#a4d4b43a5c71c7ec51c51098c1d8a29081f9b308" + integrity sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg== + dependencies: + d "^1.0.1" + es5-ext "^0.10.62" + event-emitter "^0.3.5" + type "^2.7.2" + espree@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/espree/-/espree-5.0.1.tgz#5d6526fa4fc7f0788a5cf75b15f30323e2f81f7a" @@ -3000,6 +3433,19 @@ esutils@^2.0.2: resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== +etag@~1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" + integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== + +eth-ens-namehash@2.0.8: + version "2.0.8" + resolved "https://registry.yarnpkg.com/eth-ens-namehash/-/eth-ens-namehash-2.0.8.tgz#229ac46eca86d52e0c991e7cb2aef83ff0f68bcf" + integrity sha512-VWEI1+KJfz4Km//dadyvBBoBeSQ0MHTXPvr8UIXiLW6IanxvAV+DmlZAijZwAyggqGUfwQBeHf7tc9wzc1piSw== + dependencies: + idna-uts46-hx "^2.3.1" + js-sha3 "^0.5.7" + eth-gas-reporter@^0.2.25: version "0.2.25" resolved "https://registry.yarnpkg.com/eth-gas-reporter/-/eth-gas-reporter-0.2.25.tgz#546dfa946c1acee93cb1a94c2a1162292d6ff566" @@ -3021,6 +3467,27 @@ eth-gas-reporter@^0.2.25: sha1 "^1.1.1" sync-request "^6.0.0" +eth-lib@0.2.8: + version "0.2.8" + resolved "https://registry.yarnpkg.com/eth-lib/-/eth-lib-0.2.8.tgz#b194058bef4b220ad12ea497431d6cb6aa0623c8" + integrity sha512-ArJ7x1WcWOlSpzdoTBX8vkwlkSQ85CjjifSZtV4co64vWxSV8geWfPI9x4SVYu3DSxnX4yWFVTtGL+j9DUFLNw== + dependencies: + bn.js "^4.11.6" + elliptic "^6.4.0" + xhr-request-promise "^0.1.2" + +eth-lib@^0.1.26: + version "0.1.29" + resolved "https://registry.yarnpkg.com/eth-lib/-/eth-lib-0.1.29.tgz#0c11f5060d42da9f931eab6199084734f4dbd1d9" + integrity sha512-bfttrr3/7gG4E02HoWTDUcDDslN003OlOoBxk9virpAZQ1ja/jDgwkWB8QfJF7ojuEowrqy+lzp9VcJG7/k5bQ== + dependencies: + bn.js "^4.11.6" + elliptic "^6.4.0" + nano-json-stream-parser "^0.1.2" + servify "^0.1.12" + ws "^3.0.0" + xhr-request-promise "^0.1.2" + ethereum-bloom-filters@^1.0.6: version "1.0.10" resolved "https://registry.yarnpkg.com/ethereum-bloom-filters/-/ethereum-bloom-filters-1.0.10.tgz#3ca07f4aed698e75bd134584850260246a5fed8a" @@ -3059,6 +3526,16 @@ ethereum-cryptography@^1.0.3: "@scure/bip32" "1.1.5" "@scure/bip39" "1.1.1" +ethereum-cryptography@^2.0.0, ethereum-cryptography@^2.1.2: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ethereum-cryptography/-/ethereum-cryptography-2.1.3.tgz#1352270ed3b339fe25af5ceeadcf1b9c8e30768a" + integrity sha512-BlwbIL7/P45W8FGW2r7LGuvoEZ+7PWsniMvQ4p5s2xCyw9tmaDlpfsN9HjAucbF+t/qpVHwZUisgfK24TCW8aA== + dependencies: + "@noble/curves" "1.3.0" + "@noble/hashes" "1.3.3" + "@scure/bip32" "1.3.3" + "@scure/bip39" "1.2.2" + ethereum-waffle@^4.0.10: version "4.0.10" resolved "https://registry.yarnpkg.com/ethereum-waffle/-/ethereum-waffle-4.0.10.tgz#f1ef1564c0155236f1a66c6eae362a5d67c9f64c" @@ -3181,11 +3658,24 @@ ethjs-util@0.1.6, ethjs-util@^0.1.6: is-hex-prefixed "1.0.0" strip-hex-prefix "1.0.0" +event-emitter@^0.3.5: + version "0.3.5" + resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39" + integrity sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA== + dependencies: + d "1" + es5-ext "~0.10.14" + event-target-shim@^5.0.0: version "5.0.1" resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== +eventemitter3@4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.4.tgz#b5463ace635a083d018bdc7c917b4c5f10a85384" + integrity sha512-rlaVLnVxtxvoyLsQQFBx53YmXHDxRIzzTLbdfxqi4yocpSjAxXwkU0cScM5JgSKMqEhrZpnvQ2D9gjylR0AimQ== + evp_bytestokey@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" @@ -3194,6 +3684,50 @@ evp_bytestokey@^1.0.3: md5.js "^1.3.4" safe-buffer "^5.1.1" +express@^4.14.0: + version "4.19.2" + resolved "https://registry.yarnpkg.com/express/-/express-4.19.2.tgz#e25437827a3aa7f2a827bc8171bbbb664a356465" + integrity sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q== + dependencies: + accepts "~1.3.8" + array-flatten "1.1.1" + body-parser "1.20.2" + content-disposition "0.5.4" + content-type "~1.0.4" + cookie "0.6.0" + cookie-signature "1.0.6" + debug "2.6.9" + depd "2.0.0" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + finalhandler "1.2.0" + fresh "0.5.2" + http-errors "2.0.0" + merge-descriptors "1.0.1" + methods "~1.1.2" + on-finished "2.4.1" + parseurl "~1.3.3" + path-to-regexp "0.1.7" + proxy-addr "~2.0.7" + qs "6.11.0" + range-parser "~1.2.1" + safe-buffer "5.2.1" + send "0.18.0" + serve-static "1.15.0" + setprototypeof "1.2.0" + statuses "2.0.1" + type-is "~1.6.18" + utils-merge "1.0.1" + vary "~1.1.2" + +ext@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/ext/-/ext-1.7.0.tgz#0ea4383c0103d60e70be99e9a7f11027a33c4f5f" + integrity sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw== + dependencies: + type "^2.7.2" + extend@~3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" @@ -3261,6 +3795,11 @@ fastq@^1.6.0: dependencies: reusify "^1.0.4" +figlet@^1.5.2: + version "1.7.0" + resolved "https://registry.yarnpkg.com/figlet/-/figlet-1.7.0.tgz#46903a04603fd19c3e380358418bb2703587a72e" + integrity sha512-gO8l3wvqo0V7wEFLXPbkX83b7MVjRrk1oRLfYlZXol8nEpb/ON9pcKLI4qpBv5YtOTfrINtqb7b40iYY2FTWFg== + figures@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" @@ -3289,6 +3828,19 @@ fill-range@^7.0.1: dependencies: to-regex-range "^5.0.1" +finalhandler@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.2.0.tgz#7d23fe5731b207b4640e4fcd00aec1f9207a7b32" + integrity sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg== + dependencies: + debug "2.6.9" + encodeurl "~1.0.2" + escape-html "~1.0.3" + on-finished "2.4.1" + parseurl "~1.3.3" + statuses "2.0.1" + unpipe "~1.0.0" + find-replace@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/find-replace/-/find-replace-3.0.0.tgz#3e7e23d3b05167a76f770c9fbd5258b0def68c38" @@ -3381,6 +3933,11 @@ forever-agent@~0.6.1: resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" integrity sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw== +form-data-encoder@1.7.1: + version "1.7.1" + resolved "https://registry.yarnpkg.com/form-data-encoder/-/form-data-encoder-1.7.1.tgz#ac80660e4f87ee0d3d3c3638b7da8278ddb8ec96" + integrity sha512-EFRDrsMm/kyqbTQocNvRXMLjc7Es2Vk+IQFx/YW7hkUH1eBl4J1fqiP34l74Yt0pFLCNpc06fkbVk00008mzjg== + form-data@^2.2.0: version "2.5.1" resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.5.1.tgz#f2cbec57b5e59e23716e128fe44d4e5dd23895f4" @@ -3417,6 +3974,11 @@ form-data@~2.3.2: combined-stream "^1.0.6" mime-types "^2.1.12" +forwarded@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" + integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== + fp-ts@1.19.3: version "1.19.3" resolved "https://registry.yarnpkg.com/fp-ts/-/fp-ts-1.19.3.tgz#261a60d1088fbff01f91256f91d21d0caaaaa96f" @@ -3427,6 +3989,11 @@ fp-ts@^1.0.0: resolved "https://registry.yarnpkg.com/fp-ts/-/fp-ts-1.19.5.tgz#3da865e585dfa1fdfd51785417357ac50afc520a" integrity sha512-wDNqTimnzs8QqpldiId9OavWK2NptormjXnRJTQecNjzwfyp6P/8s/zG8e4h3ja3oqkKaY72UlTjQYt/1yXf9A== +fresh@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q== + fs-extra@^0.30.0: version "0.30.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-0.30.0.tgz#f233ffcc08d4da7d432daa449776989db1df93f0" @@ -3447,6 +4014,15 @@ fs-extra@^10.0.0: jsonfile "^6.0.1" universalify "^2.0.0" +fs-extra@^4.0.2: + version "4.0.3" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-4.0.3.tgz#0d852122e5bc5beb453fb028e9c0c9bf36340c94" + integrity sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg== + dependencies: + graceful-fs "^4.1.2" + jsonfile "^4.0.0" + universalify "^0.1.0" + fs-extra@^7.0.0, fs-extra@^7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9" @@ -3465,6 +4041,13 @@ fs-extra@^8.1.0: jsonfile "^4.0.0" universalify "^0.1.0" +fs-minipass@^1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.7.tgz#ccff8570841e7fe4265693da88936c55aed7f7c7" + integrity sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA== + dependencies: + minipass "^2.6.0" + fs-readdir-recursive@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz#e32fc030a2ccee44a6b5371308da54be0b397d27" @@ -3490,6 +4073,11 @@ function-bind@^1.1.1: resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== +function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== + function.prototype.name@^1.1.5: version "1.1.5" resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.5.tgz#cce0505fe1ffb80503e6f9e46cc64e46a12a9621" @@ -3547,11 +4135,34 @@ get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@ has-proto "^1.0.1" has-symbols "^1.0.3" +get-intrinsic@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd" + integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ== + dependencies: + es-errors "^1.3.0" + function-bind "^1.1.2" + has-proto "^1.0.1" + has-symbols "^1.0.3" + hasown "^2.0.0" + get-port@^3.1.0: version "3.2.0" resolved "https://registry.yarnpkg.com/get-port/-/get-port-3.2.0.tgz#dd7ce7de187c06c8bf353796ac71e099f0980ebc" integrity sha512-x5UJKlgeUiNT8nyo/AcnwLnZuZNcSjSw0kogRB+Whd1fjjFq4B1hySFxSFWWSn4mIBzg3sRNUDFYc4g5gjPoLg== +get-stream@^5.1.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3" + integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA== + dependencies: + pump "^3.0.0" + +get-stream@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" + integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== + get-symbol-description@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.0.tgz#7fdb81c900101fbd564dd5f1a30af5aadc1e58d6" @@ -3668,6 +4279,14 @@ global-prefix@^3.0.0: kind-of "^6.0.2" which "^1.3.1" +global@~4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/global/-/global-4.4.0.tgz#3e7b105179006a323ed71aafca3e9c57a5cc6406" + integrity sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w== + dependencies: + min-document "^2.19.0" + process "^0.11.10" + globals@^11.7.0: version "11.12.0" resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" @@ -3708,6 +4327,42 @@ gopd@^1.0.1: dependencies: get-intrinsic "^1.1.3" +got@12.1.0: + version "12.1.0" + resolved "https://registry.yarnpkg.com/got/-/got-12.1.0.tgz#099f3815305c682be4fd6b0ee0726d8e4c6b0af4" + integrity sha512-hBv2ty9QN2RdbJJMK3hesmSkFTjVIHyIDDbssCKnSmq62edGgImJWD10Eb1k77TiV1bxloxqcFAVK8+9pkhOig== + dependencies: + "@sindresorhus/is" "^4.6.0" + "@szmarczak/http-timer" "^5.0.1" + "@types/cacheable-request" "^6.0.2" + "@types/responselike" "^1.0.0" + cacheable-lookup "^6.0.4" + cacheable-request "^7.0.2" + decompress-response "^6.0.0" + form-data-encoder "1.7.1" + get-stream "^6.0.1" + http2-wrapper "^2.1.10" + lowercase-keys "^3.0.0" + p-cancelable "^3.0.0" + responselike "^2.0.0" + +got@^11.8.5: + version "11.8.6" + resolved "https://registry.yarnpkg.com/got/-/got-11.8.6.tgz#276e827ead8772eddbcfc97170590b841823233a" + integrity sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g== + dependencies: + "@sindresorhus/is" "^4.0.0" + "@szmarczak/http-timer" "^4.0.5" + "@types/cacheable-request" "^6.0.1" + "@types/responselike" "^1.0.0" + cacheable-lookup "^5.0.3" + cacheable-request "^7.0.2" + decompress-response "^6.0.0" + http2-wrapper "^1.0.0-beta.5.2" + lowercase-keys "^2.0.0" + p-cancelable "^2.0.0" + responselike "^2.0.0" + graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9, graceful-fs@^4.2.0, graceful-fs@^4.2.4: version "4.2.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" @@ -3887,6 +4542,13 @@ has-property-descriptors@^1.0.0: dependencies: get-intrinsic "^1.1.1" +has-property-descriptors@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854" + integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg== + dependencies: + es-define-property "^1.0.0" + has-proto@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.1.tgz#1885c1305538958aff469fef37937c22795408e0" @@ -3904,6 +4566,13 @@ has-tostringtag@^1.0.0: dependencies: has-symbols "^1.0.2" +has-tostringtag@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc" + integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw== + dependencies: + has-symbols "^1.0.3" + has@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" @@ -3936,6 +4605,13 @@ hash.js@1.1.7, hash.js@^1.0.0, hash.js@^1.0.3, hash.js@^1.1.7: inherits "^2.0.3" minimalistic-assert "^1.0.1" +hasown@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" + integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== + dependencies: + function-bind "^1.1.2" + he@1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" @@ -3970,6 +4646,11 @@ http-basic@^8.1.1: http-response-object "^3.0.1" parse-cache-control "^1.0.1" +http-cache-semantics@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz#abe02fcb2985460bf0323be664436ec3476a6d5a" + integrity sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ== + http-errors@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" @@ -3981,6 +4662,11 @@ http-errors@2.0.0: statuses "2.0.1" toidentifier "1.0.1" +http-https@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/http-https/-/http-https-1.0.0.tgz#2f908dd5f1db4068c058cd6e6d4ce392c913389b" + integrity sha512-o0PWwVCSp3O0wS6FvNr6xfBCHgt0m1tvPLFOCc2iFDKTRAXhB7m8klDf7ErowFH8POa6dVdGatKU5I1YYwzUyg== + http-response-object@^3.0.1: version "3.0.2" resolved "https://registry.yarnpkg.com/http-response-object/-/http-response-object-3.0.2.tgz#7f435bb210454e4360d074ef1f989d5ea8aa9810" @@ -3997,6 +4683,22 @@ http-signature@~1.2.0: jsprim "^1.2.2" sshpk "^1.7.0" +http2-wrapper@^1.0.0-beta.5.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/http2-wrapper/-/http2-wrapper-1.0.3.tgz#b8f55e0c1f25d4ebd08b3b0c2c079f9590800b3d" + integrity sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg== + dependencies: + quick-lru "^5.1.1" + resolve-alpn "^1.0.0" + +http2-wrapper@^2.1.10: + version "2.2.1" + resolved "https://registry.yarnpkg.com/http2-wrapper/-/http2-wrapper-2.2.1.tgz#310968153dcdedb160d8b72114363ef5fce1f64a" + integrity sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ== + dependencies: + quick-lru "^5.1.1" + resolve-alpn "^1.2.0" + https-proxy-agent@^5.0.0: version "5.0.1" resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6" @@ -4017,6 +4719,13 @@ iconv-lite@0.4.24, iconv-lite@^0.4.24: dependencies: safer-buffer ">= 2.1.2 < 3" +idna-uts46-hx@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/idna-uts46-hx/-/idna-uts46-hx-2.3.1.tgz#a1dc5c4df37eee522bf66d969cc980e00e8711f9" + integrity sha512-PWoF9Keq6laYdIRwwCdhTPl60xRqAloYNMQLiyUnG42VjT53oW07BXIRM+NK7eQjzXjAk2gUvX9caRxlnF9TAA== + dependencies: + punycode "2.1.0" + ieee754@^1.1.13, ieee754@^1.1.4, ieee754@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" @@ -4141,6 +4850,19 @@ io-ts@1.10.4: dependencies: fp-ts "^1.0.0" +ipaddr.js@1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" + integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== + +is-arguments@^1.0.4: + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" + integrity sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + is-array-buffer@^3.0.1, is-array-buffer@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.2.tgz#f2653ced8412081638ecb0ebbd0c41c6e0aecbbe" @@ -4221,6 +4943,18 @@ is-fullwidth-code-point@^3.0.0: resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== +is-function@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-function/-/is-function-1.0.2.tgz#4f097f30abf6efadac9833b17ca5dc03f8144e08" + integrity sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ== + +is-generator-function@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.10.tgz#f1558baf1ac17e0deea7c0415c438351ff2b3c72" + integrity sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A== + dependencies: + has-tostringtag "^1.0.0" + is-glob@^4.0.0, is-glob@^4.0.1, is-glob@~4.0.1: version "4.0.3" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" @@ -4295,7 +5029,14 @@ is-typed-array@^1.1.10, is-typed-array@^1.1.9: gopd "^1.0.1" has-tostringtag "^1.0.0" -is-typedarray@~1.0.0: +is-typed-array@^1.1.3: + version "1.1.13" + resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.13.tgz#d6c5ca56df62334959322d7d7dd1cca50debe229" + integrity sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw== + dependencies: + which-typed-array "^1.1.14" + +is-typedarray@^1.0.0, is-typedarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" integrity sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA== @@ -4355,7 +5096,7 @@ js-sdsl@^4.1.4: resolved "https://registry.yarnpkg.com/js-sdsl/-/js-sdsl-4.4.1.tgz#9e3c7b566d8d9a7e1fe8fc26d00b5ab0f8918ab3" integrity sha512-6Gsx8R0RucyePbWqPssR8DyfuXmLBooYN5cZFZKjHGnQuaf7pEzhtpceagJxVu4LqhYY5EYA7nko3FmeHZ1KbA== -js-sha3@0.5.7: +js-sha3@0.5.7, js-sha3@^0.5.7: version "0.5.7" resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.5.7.tgz#0d4ffd8002d5333aabaf4a23eed2f6374c9f28e7" integrity sha512-GII20kjaPX0zJ8wzkTbNDYMY7msuZcTWk8S5UOh6806Jq/wz1J8/bnr8uGU0DAUmYDjj2Mr4X1cW8v/GLYnR+g== @@ -4405,6 +5146,11 @@ json-bigint@^1.0.0: dependencies: bignumber.js "^9.0.0" +json-buffer@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" + integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== + json-parse-better-errors@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" @@ -4514,6 +5260,13 @@ keccak@^3.0.0, keccak@^3.0.2: node-gyp-build "^4.2.0" readable-stream "^3.6.0" +keyv@^4.0.0: + version "4.5.4" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" + integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== + dependencies: + json-buffer "3.0.1" + kind-of@^6.0.2: version "6.0.3" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" @@ -4732,6 +5485,16 @@ loupe@^2.3.1: dependencies: get-func-name "^2.0.0" +lowercase-keys@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479" + integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA== + +lowercase-keys@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-3.0.0.tgz#c5e7d442e37ead247ae9db117a9d0a467c89d4f2" + integrity sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ== + lru-cache@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" @@ -4780,6 +5543,11 @@ md5.js@^1.3.4: inherits "^2.0.1" safe-buffer "^5.1.2" +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ== + memdown@^5.0.0: version "5.1.0" resolved "https://registry.yarnpkg.com/memdown/-/memdown-5.1.0.tgz#608e91a9f10f37f5b5fe767667a8674129a833cb" @@ -4806,6 +5574,11 @@ memorystream@^0.3.1: resolved "https://registry.yarnpkg.com/memorystream/-/memorystream-0.3.1.tgz#86d7090b30ce455d63fbae12dda51a47ddcaf9b2" integrity sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw== +merge-descriptors@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + integrity sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w== + merge2@^1.2.3, merge2@^1.3.0: version "1.4.1" resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" @@ -4823,6 +5596,16 @@ merkle-patricia-tree@^4.2.2, merkle-patricia-tree@^4.2.4: readable-stream "^3.6.0" semaphore-async-await "^1.5.1" +methods@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== + +micro-ftch@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/micro-ftch/-/micro-ftch-0.3.1.tgz#6cb83388de4c1f279a034fb0cf96dfc050853c5f" + integrity sha512-/0LLxhzP0tfiR5hcQebtudP56gUurs2CLkGarnCiB/OqEyUFQ6U3paQi/tgLv0hBJYt2rnr9MNpxz4fiiugstg== + micromatch@^4.0.4: version "4.0.5" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" @@ -4844,18 +5627,40 @@ mime-db@1.52.0: resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== -mime-types@^2.1.12, mime-types@~2.1.19: +mime-types@^2.1.12, mime-types@^2.1.16, mime-types@~2.1.19, mime-types@~2.1.24, mime-types@~2.1.34: version "2.1.35" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== dependencies: mime-db "1.52.0" +mime@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== + mimic-fn@^1.0.0: version "1.2.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ== +mimic-response@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" + integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== + +mimic-response@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-3.1.0.tgz#2d1d59af9c1b129815accc2c46a022a5ce1fa3c9" + integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ== + +min-document@^2.19.0: + version "2.19.0" + resolved "https://registry.yarnpkg.com/min-document/-/min-document-2.19.0.tgz#7bd282e3f5842ed295bb748cdd9f1ffa2c824685" + integrity sha512-9Wy1B3m3f66bPPmU5hdA4DR4PB2OfDU/+GS3yAB7IQozE3tqXaVv2zOjgla7MEGSRv95+ILmOuvhLkOK6wJtCQ== + dependencies: + dom-walk "^0.1.0" + minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" @@ -4899,6 +5704,33 @@ minimist@^1.2.5, minimist@^1.2.6: resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== +minipass@^2.6.0, minipass@^2.9.0: + version "2.9.0" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.9.0.tgz#e713762e7d3e32fed803115cf93e04bca9fcc9a6" + integrity sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg== + dependencies: + safe-buffer "^5.1.2" + yallist "^3.0.0" + +minizlib@^1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.3.3.tgz#2290de96818a34c29551c8a8d301216bd65a861d" + integrity sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q== + dependencies: + minipass "^2.9.0" + +mkdirp-promise@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/mkdirp-promise/-/mkdirp-promise-5.0.1.tgz#e9b8f68e552c68a9c1713b84883f7a1dd039b8a1" + integrity sha512-Hepn5kb1lJPtVW84RFT40YG1OddBNTOVUZR2bzQUHc+Z03en8/3uX0+060JDhcEzyO08HmipsN9DcnFMxhIL9w== + dependencies: + mkdirp "*" + +mkdirp@*: + version "3.0.1" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-3.0.1.tgz#e44e4c5607fb279c168241713cc6e0fea9adcb50" + integrity sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg== + mkdirp@0.5.5: version "0.5.5" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" @@ -4906,7 +5738,7 @@ mkdirp@0.5.5: dependencies: minimist "^1.2.5" -mkdirp@0.5.x, mkdirp@^0.5.1: +mkdirp@0.5.x, mkdirp@^0.5.1, mkdirp@^0.5.5: version "0.5.6" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6" integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw== @@ -5012,6 +5844,11 @@ mocha@^7.1.1: yargs-parser "13.1.2" yargs-unparser "1.6.0" +mock-fs@^4.1.0: + version "4.14.0" + resolved "https://registry.yarnpkg.com/mock-fs/-/mock-fs-4.14.0.tgz#ce5124d2c601421255985e6e94da80a7357b1b18" + integrity sha512-qYvlv/exQ4+svI3UOvPUpLDF0OMX5euvUH0Ny4N5QyRyhNdgAgUrVH3iUINSzEPLvx0kbo/Bp28GJKIqvE7URw== + module-error@^1.0.1, module-error@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/module-error/-/module-error-1.0.2.tgz#8d1a48897ca883f47a45816d4fb3e3c6ba404d86" @@ -5037,6 +5874,46 @@ ms@2.1.3, ms@^2.1.1: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== +multibase@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/multibase/-/multibase-0.7.0.tgz#1adfc1c50abe05eefeb5091ac0c2728d6b84581b" + integrity sha512-TW8q03O0f6PNFTQDvh3xxH03c8CjGaaYrjkl9UQPG6rz53TQzzxJVCIWVjzcbN/Q5Y53Zd0IBQBMVktVgNx4Fg== + dependencies: + base-x "^3.0.8" + buffer "^5.5.0" + +multibase@~0.6.0: + version "0.6.1" + resolved "https://registry.yarnpkg.com/multibase/-/multibase-0.6.1.tgz#b76df6298536cc17b9f6a6db53ec88f85f8cc12b" + integrity sha512-pFfAwyTjbbQgNc3G7D48JkJxWtoJoBMaR4xQUOuB8RnCgRqaYmWNFeJTTvrJ2w51bjLq2zTby6Rqj9TQ9elSUw== + dependencies: + base-x "^3.0.8" + buffer "^5.5.0" + +multicodec@^0.5.5: + version "0.5.7" + resolved "https://registry.yarnpkg.com/multicodec/-/multicodec-0.5.7.tgz#1fb3f9dd866a10a55d226e194abba2dcc1ee9ffd" + integrity sha512-PscoRxm3f+88fAtELwUnZxGDkduE2HD9Q6GHUOywQLjOGT/HAdhjLDYNZ1e7VR0s0TP0EwZ16LNUTFpoBGivOA== + dependencies: + varint "^5.0.0" + +multicodec@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/multicodec/-/multicodec-1.0.4.tgz#46ac064657c40380c28367c90304d8ed175a714f" + integrity sha512-NDd7FeS3QamVtbgfvu5h7fd1IlbaC4EQ0/pgU4zqE2vdHCmBGsUa0TiM8/TdSeG6BMPC92OOCf8F1ocE/Wkrrg== + dependencies: + buffer "^5.6.0" + varint "^5.0.0" + +multihashes@^0.4.15, multihashes@~0.4.15: + version "0.4.21" + resolved "https://registry.yarnpkg.com/multihashes/-/multihashes-0.4.21.tgz#dc02d525579f334a7909ade8a122dabb58ccfcb5" + integrity sha512-uVSvmeCWf36pU2nB4/1kzYZjsXD9vofZKpgudqkceYY5g2aZZXJ5r9lxuzoRLl1OAp28XljXsEJ/X/85ZsKmKw== + dependencies: + buffer "^5.5.0" + multibase "^0.7.0" + varint "^5.0.0" + murmur-128@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/murmur-128/-/murmur-128-0.2.1.tgz#a9f6568781d2350ecb1bf80c14968cadbeaa4b4d" @@ -5051,6 +5928,11 @@ mute-stream@0.0.7: resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" integrity sha512-r65nCZhrbXXb6dXOACihYApHw2Q6pV0M3V0PSxd74N0+D8nzAdEAITq2oAjA1jVnKI+tGvEBUpqiMh0+rW6zDQ== +nano-json-stream-parser@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/nano-json-stream-parser/-/nano-json-stream-parser-0.1.2.tgz#0cc8f6d0e2b622b479c40d499c46d64b755c6f5f" + integrity sha512-9MqxMH/BSJC7dnLsEMPyfN5Dvoo49IsPFYMcHw3Bcfc2kN0lpHRBSzlMSVx4HGyJ7s9B31CyBTVehWJoQ8Ctew== + nanoid@3.3.3: version "3.3.3" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.3.tgz#fd8e8b7aa761fe807dba2d1b98fb7241bb724a25" @@ -5071,11 +5953,21 @@ natural-compare@^1.4.0: resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== +negotiator@0.6.3: + version "0.6.3" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" + integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== + neo-async@^2.6.0: version "2.6.2" resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== +next-tick@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.1.0.tgz#1836ee30ad56d67ef281b22bd199f709449b35eb" + integrity sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ== + nice-try@^1.0.4: version "1.0.5" resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" @@ -5108,6 +6000,13 @@ node-fetch@^2.6.0, node-fetch@^2.6.1, node-fetch@^2.6.7: dependencies: whatwg-url "^5.0.0" +node-fetch@^2.6.12: + version "2.7.0" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" + integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== + dependencies: + whatwg-url "^5.0.0" + node-gyp-build@4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.3.0.tgz#9f256b03e5826150be39c764bf51e993946d71a3" @@ -5140,6 +6039,11 @@ normalize-path@^3.0.0, normalize-path@~3.0.0: resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== +normalize-url@^6.0.1: + version "6.1.0" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a" + integrity sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A== + number-to-bn@1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/number-to-bn/-/number-to-bn-1.7.0.tgz#bb3623592f7e5f9e0030b1977bd41a0c53fe1ea0" @@ -5153,7 +6057,7 @@ oauth-sign@~0.9.0: resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== -object-assign@^4.1.0: +object-assign@^4, object-assign@^4.1.0, object-assign@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== @@ -5204,7 +6108,21 @@ obliterator@^2.0.0: resolved "https://registry.yarnpkg.com/obliterator/-/obliterator-2.0.4.tgz#fa650e019b2d075d745e44f1effeb13a2adbe816" integrity sha512-lgHwxlxV1qIg1Eap7LgIeoBWIMFibOjbrYPIPJZcI1mmGAI2m3lNYpK12Y+GBdPQ0U1hRwSord7GIaawz962qQ== -once@1.x, once@^1.3.0: +oboe@2.1.5: + version "2.1.5" + resolved "https://registry.yarnpkg.com/oboe/-/oboe-2.1.5.tgz#5554284c543a2266d7a38f17e073821fbde393cd" + integrity sha512-zRFWiF+FoicxEs3jNI/WYUrVEgA7DeET/InK0XQuudGHRg8iIob3cNPrJTKaz4004uaA9Pbe+Dwa8iluhjLZWA== + dependencies: + http-https "^1.0.0" + +on-finished@2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f" + integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== + dependencies: + ee-first "1.1.1" + +once@1.x, once@^1.3.0, once@^1.3.1, once@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== @@ -5247,6 +6165,16 @@ os-tmpdir@~1.0.2: resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" integrity sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g== +p-cancelable@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-2.1.1.tgz#aab7fbd416582fa32a3db49859c122487c5ed2cf" + integrity sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg== + +p-cancelable@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-3.0.0.tgz#63826694b54d61ca1c20ebcb6d3ecf5e14cd8050" + integrity sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw== + p-limit@^1.1.0: version "1.3.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" @@ -5328,6 +6256,11 @@ parse-cache-control@^1.0.1: resolved "https://registry.yarnpkg.com/parse-cache-control/-/parse-cache-control-1.0.1.tgz#8eeab3e54fa56920fe16ba38f77fa21aacc2d74e" integrity sha512-60zvsJReQPX5/QP0Kzfd/VrpjScIQ7SHBW6bFCYfEP+fp0Eppr1SHhIO5nd1PjZtvclzSzES9D/p5nFJurwfWg== +parse-headers@^2.0.0: + version "2.0.5" + resolved "https://registry.yarnpkg.com/parse-headers/-/parse-headers-2.0.5.tgz#069793f9356a54008571eb7f9761153e6c770da9" + integrity sha512-ft3iAoLOB/MlwbNXgzy43SWGP6sQki2jQvAyBg/zDFAgr9bfNWZIUj42Kw2eJIl8kEi4PbgE6U1Zau/HwI75HA== + parse-json@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" @@ -5346,6 +6279,11 @@ parse-json@^5.0.0: json-parse-even-better-errors "^2.3.0" lines-and-columns "^1.1.6" +parseurl@~1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" + integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== + path-browserify@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-1.0.1.tgz#d98454a9c3753d5790860f16f68867b9e46be1fd" @@ -5386,6 +6324,11 @@ path-parse@^1.0.6, path-parse@^1.0.7: resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== +path-to-regexp@0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" + integrity sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ== + path-type@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" @@ -5438,6 +6381,11 @@ pluralize@^8.0.0: resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-8.0.0.tgz#1a6fa16a38d12a1901e0320fa017051c539ce3b1" integrity sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA== +possible-typed-array-names@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz#89bb63c6fada2c3e90adc4a647beeeb39cc7bf8f" + integrity sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q== + prelude-ls@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" @@ -5475,6 +6423,11 @@ process-nextick-args@~2.0.0: resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== +process@^0.11.10: + version "0.11.10" + resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" + integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A== + progress@^2.0.0: version "2.0.3" resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" @@ -5496,6 +6449,14 @@ proper-lockfile@^4.1.1: retry "^0.12.0" signal-exit "^3.0.2" +proxy-addr@~2.0.7: + version "2.0.7" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" + integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== + dependencies: + forwarded "0.2.0" + ipaddr.js "1.9.1" + proxy-from-env@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" @@ -5511,6 +6472,19 @@ psl@^1.1.28: resolved "https://registry.yarnpkg.com/psl/-/psl-1.9.0.tgz#d0df2a137f00794565fcaf3b2c00cd09f8d5a5a7" integrity sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag== +pump@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" + integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +punycode@2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.0.tgz#5f863edc89b96db09074bad7947bf09056ca4e7d" + integrity sha512-Yxz2kRwT90aPiWEMHVYnEf4+rhwF1tBmmZ4KepCP+Wkium9JxtWnUm1nqGwpiAHr/tnTSeHqr3wb++jgSkXjhA== + punycode@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" @@ -5521,6 +6495,13 @@ punycode@^2.1.0, punycode@^2.1.1: resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f" integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA== +qs@6.11.0: + version "6.11.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a" + integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== + dependencies: + side-channel "^1.0.4" + qs@^6.11.0, qs@^6.4.0, qs@^6.7.0, qs@^6.9.4: version "6.11.2" resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.2.tgz#64bea51f12c1f5da1bc01496f48ffcff7c69d7d9" @@ -5533,11 +6514,25 @@ qs@~6.5.2: resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.3.tgz#3aeeffc91967ef6e35c0e488ef46fb296ab76aad" integrity sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA== +query-string@^5.0.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/query-string/-/query-string-5.1.1.tgz#a78c012b71c17e05f2e3fa2319dd330682efb3cb" + integrity sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw== + dependencies: + decode-uri-component "^0.2.0" + object-assign "^4.1.0" + strict-uri-encode "^1.0.0" + queue-microtask@^1.2.2, queue-microtask@^1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== +quick-lru@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932" + integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA== + randombytes@^2.0.1, randombytes@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" @@ -5545,7 +6540,12 @@ randombytes@^2.0.1, randombytes@^2.1.0: dependencies: safe-buffer "^5.1.0" -raw-body@^2.4.1: +range-parser@~1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" + integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== + +raw-body@2.5.2, raw-body@^2.4.1: version "2.5.2" resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.2.tgz#99febd83b90e08975087e8f1f9419a149366b68a" integrity sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA== @@ -5659,7 +6659,7 @@ request-promise-native@^1.0.5: stealthy-require "^1.1.1" tough-cookie "^2.3.3" -request@^2.85.0, request@^2.88.0: +request@^2.79.0, request@^2.85.0, request@^2.88.0: version "2.88.2" resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw== @@ -5700,6 +6700,11 @@ require-main-filename@^2.0.0: resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== +resolve-alpn@^1.0.0, resolve-alpn@^1.2.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/resolve-alpn/-/resolve-alpn-1.2.1.tgz#b7adbdac3546aaaec20b45e7d8265927072726f9" + integrity sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g== + resolve-from@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" @@ -5731,6 +6736,13 @@ resolve@^1.1.6: path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" +responselike@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/responselike/-/responselike-2.0.1.tgz#9a0bc8fdc252f3fb1cca68b016591059ba1422bc" + integrity sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw== + dependencies: + lowercase-keys "^2.0.0" + restore-cursor@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" @@ -5838,7 +6850,7 @@ safe-array-concat@^1.0.0: has-symbols "^1.0.3" isarray "^2.0.5" -safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0: +safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@^5.2.1, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== @@ -5887,7 +6899,7 @@ scrypt-js@2.0.4: resolved "https://registry.yarnpkg.com/scrypt-js/-/scrypt-js-2.0.4.tgz#32f8c5149f0797672e551c07e230f834b6af5f16" integrity sha512-4KsaGcPnuhtCZQCxFxN3GVYIhKFPTdLd8PLC552XwbMndtD0cjRFAhDuuydXQ0h08ZfPgzqe6EKHozpuH74iDw== -scrypt-js@3.0.1, scrypt-js@^3.0.0: +scrypt-js@3.0.1, scrypt-js@^3.0.0, scrypt-js@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/scrypt-js/-/scrypt-js-3.0.1.tgz#d314a57c2aef69d1ad98a138a21fe9eafa9ee312" integrity sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA== @@ -5928,6 +6940,25 @@ semver@^7.2.1, semver@^7.3.4, semver@^7.3.5: dependencies: lru-cache "^6.0.0" +send@0.18.0: + version "0.18.0" + resolved "https://registry.yarnpkg.com/send/-/send-0.18.0.tgz#670167cc654b05f5aa4a767f9113bb371bc706be" + integrity sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg== + dependencies: + debug "2.6.9" + depd "2.0.0" + destroy "1.2.0" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + fresh "0.5.2" + http-errors "2.0.0" + mime "1.6.0" + ms "2.1.3" + on-finished "2.4.1" + range-parser "~1.2.1" + statuses "2.0.1" + serialize-javascript@6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.0.tgz#efae5d88f45d7924141da8b5c3a7a7e663fefeb8" @@ -5935,11 +6966,44 @@ serialize-javascript@6.0.0: dependencies: randombytes "^2.1.0" +serve-static@1.15.0: + version "1.15.0" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.15.0.tgz#faaef08cffe0a1a62f60cad0c4e513cff0ac9540" + integrity sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g== + dependencies: + encodeurl "~1.0.2" + escape-html "~1.0.3" + parseurl "~1.3.3" + send "0.18.0" + +servify@^0.1.12: + version "0.1.12" + resolved "https://registry.yarnpkg.com/servify/-/servify-0.1.12.tgz#142ab7bee1f1d033b66d0707086085b17c06db95" + integrity sha512-/xE6GvsKKqyo1BAY+KxOWXcLpPsUUyji7Qg3bVD7hh1eRze5bR1uYiuDA/k3Gof1s9BTzQZEJK8sNcNGFIzeWw== + dependencies: + body-parser "^1.16.0" + cors "^2.8.1" + express "^4.14.0" + request "^2.79.0" + xhr "^2.3.3" + set-blocking@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw== +set-function-length@^1.2.1: + version "1.2.2" + resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449" + integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg== + dependencies: + define-data-property "^1.1.4" + es-errors "^1.3.0" + function-bind "^1.1.2" + get-intrinsic "^1.2.4" + gopd "^1.0.1" + has-property-descriptors "^1.0.2" + setimmediate@1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.4.tgz#20e81de622d4a02588ce0c8da8973cbcf1d3138f" @@ -6018,6 +7082,20 @@ signal-exit@^3.0.2: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== +simple-concat@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.1.tgz#f46976082ba35c2263f1c8ab5edfe26c41c9552f" + integrity sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q== + +simple-get@^2.7.0: + version "2.8.2" + resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-2.8.2.tgz#5708fb0919d440657326cd5fe7d2599d07705019" + integrity sha512-Ijd/rV5o+mSBBs4F/x9oDPtTx9Zb6X9brmnXvMW4J7IR15ngi9q5xxqWBKU744jTZiaXtxaPL7uHG6vtN8kUkw== + dependencies: + decompress-response "^3.3.0" + once "^1.3.1" + simple-concat "^1.0.0" + slash@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" @@ -6212,6 +7290,16 @@ sshpk@^1.7.0: safer-buffer "^2.0.2" tweetnacl "~0.14.0" +"ssv-scanner@github:bloxapp/ssv-scanner": + version "1.0.3" + resolved "https://codeload.github.com/bloxapp/ssv-scanner/tar.gz/b508efe18acb5ae1b94d13eae993d5dcaccf000b" + dependencies: + "@types/figlet" "^1.5.4" + argparse "^2.0.1" + cli-progress "^3.11.2" + figlet "^1.5.2" + web3 "^1.10.0" + stacktrace-parser@^0.1.10: version "0.1.10" resolved "https://registry.yarnpkg.com/stacktrace-parser/-/stacktrace-parser-0.1.10.tgz#29fb0cae4e0d0b85155879402857a1639eb6051a" @@ -6234,6 +7322,11 @@ streamsearch@^1.1.0: resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-1.1.0.tgz#404dd1e2247ca94af554e841a8ef0eaa238da764" integrity sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg== +strict-uri-encode@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" + integrity sha512-R3f198pcvnB+5IpnBlRkphuE9n46WyVl8I39W/ZUTZLz4nqSP/oLYUrcnJrw462Ds8he4YKMov2efsTIw1BDGQ== + string-format@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/string-format/-/string-format-2.0.0.tgz#f2df2e7097440d3b65de31b6d40d54c96eaffb9b" @@ -6384,6 +7477,23 @@ supports-preserve-symlinks-flag@^1.0.0: resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== +swarm-js@^0.1.40: + version "0.1.42" + resolved "https://registry.yarnpkg.com/swarm-js/-/swarm-js-0.1.42.tgz#497995c62df6696f6e22372f457120e43e727979" + integrity sha512-BV7c/dVlA3R6ya1lMlSSNPLYrntt0LUq4YMgy3iwpCIc6rZnS5W2wUoctarZ5pXlpKtxDDf9hNziEkcfrxdhqQ== + dependencies: + bluebird "^3.5.0" + buffer "^5.0.5" + eth-lib "^0.1.26" + fs-extra "^4.0.2" + got "^11.8.5" + mime-types "^2.1.16" + mkdirp-promise "^5.0.1" + mock-fs "^4.1.0" + setimmediate "^1.0.5" + tar "^4.0.2" + xhr-request "^1.0.1" + sync-fetch@^0.5.2: version "0.5.2" resolved "https://registry.yarnpkg.com/sync-fetch/-/sync-fetch-0.5.2.tgz#65e7ae1133219938dc92eb19aa21d5eb79ebadec" @@ -6438,6 +7548,19 @@ table@^6.0.9, table@^6.8.0, table@^6.8.1: string-width "^4.2.3" strip-ansi "^6.0.1" +tar@^4.0.2: + version "4.4.19" + resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.19.tgz#2e4d7263df26f2b914dee10c825ab132123742f3" + integrity sha512-a20gEsvHnWe0ygBY8JbxoM4w3SJdhc7ZAuxkLqh+nvNQN2IOt0B5lLgM490X5Hl8FF0dl0tOf2ewFYAlIFgzVA== + dependencies: + chownr "^1.1.4" + fs-minipass "^1.2.7" + minipass "^2.9.0" + minizlib "^1.3.3" + mkdirp "^0.5.5" + safe-buffer "^5.2.1" + yallist "^3.1.1" + text-table@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" @@ -6465,6 +7588,11 @@ through@^2.3.6: resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== +timed-out@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" + integrity sha512-G7r3AhovYtr5YKOWQkta8RKAPb+J9IsO4uVmzjl8AZwfhs8UcUwTiD6gcJYSgOtzyjvQKrKYn41syHbUWMkafA== + tmp@0.0.33, tmp@^0.0.33: version "0.0.33" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" @@ -6583,6 +7711,19 @@ type-fest@^0.7.1: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.7.1.tgz#8dda65feaf03ed78f0a3f9678f1869147f7c5c48" integrity sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg== +type-is@~1.6.18: + version "1.6.18" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" + integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== + dependencies: + media-typer "0.3.0" + mime-types "~2.1.24" + +type@^2.7.2: + version "2.7.2" + resolved "https://registry.yarnpkg.com/type/-/type-2.7.2.tgz#2376a15a3a28b1efa0f5350dcf72d24df6ef98d0" + integrity sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw== + typechain@^8.0.0: version "8.2.0" resolved "https://registry.yarnpkg.com/typechain/-/typechain-8.2.0.tgz#bd4fc8f111d4405e36858bae6f744604617b60f3" @@ -6608,6 +7749,13 @@ typed-array-length@^1.0.4: for-each "^0.3.3" is-typed-array "^1.1.9" +typedarray-to-buffer@^3.1.5: + version "3.1.5" + resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" + integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q== + dependencies: + is-typedarray "^1.0.0" + typedarray@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" @@ -6628,6 +7776,11 @@ uglify-js@^3.1.4: resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.17.4.tgz#61678cf5fa3f5b7eb789bb345df29afb8257c22c" integrity sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g== +ultron@~1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.1.1.tgz#9fe1536a10a664a65266a1e3ccf85fd36302bc9c" + integrity sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og== + unbox-primitive@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz#29032021057d5e6cdbd08c5129c226dff8ed6f9e" @@ -6660,7 +7813,7 @@ universalify@^2.0.0: resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== -unpipe@1.0.0: +unpipe@1.0.0, unpipe@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== @@ -6672,6 +7825,11 @@ uri-js@^4.2.2: dependencies: punycode "^2.1.0" +url-set-query@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/url-set-query/-/url-set-query-1.0.0.tgz#016e8cfd7c20ee05cafe7795e892bd0702faa339" + integrity sha512-3AChu4NiXquPfeckE5R5cGdiHCMWJx1dwCWOmWIL4KHAziJNOFIYJlpGFeKDvwLPHovZRCxK3cYlwzqI9Vp+Gg== + url@^0.11.0: version "0.11.1" resolved "https://registry.yarnpkg.com/url/-/url-0.11.1.tgz#26f90f615427eca1b9f4d6a28288c147e2302a32" @@ -6687,6 +7845,13 @@ utf-8-validate@5.0.7: dependencies: node-gyp-build "^4.3.0" +utf-8-validate@^5.0.2: + version "5.0.10" + resolved "https://registry.yarnpkg.com/utf-8-validate/-/utf-8-validate-5.0.10.tgz#d7d10ea39318171ca982718b6b96a8d2442571a2" + integrity sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ== + dependencies: + node-gyp-build "^4.3.0" + utf8@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/utf8/-/utf8-3.0.0.tgz#f052eed1364d696e769ef058b183df88c87f69d1" @@ -6697,6 +7862,22 @@ util-deprecate@^1.0.1, util-deprecate@~1.0.1: resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== +util@^0.12.5: + version "0.12.5" + resolved "https://registry.yarnpkg.com/util/-/util-0.12.5.tgz#5f17a6059b73db61a875668781a1c2b136bd6fbc" + integrity sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA== + dependencies: + inherits "^2.0.3" + is-arguments "^1.0.4" + is-generator-function "^1.0.7" + is-typed-array "^1.1.3" + which-typed-array "^1.1.2" + +utils-merge@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" + integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== + uuid@2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/uuid/-/uuid-2.0.1.tgz#c2a30dedb3e535d72ccf82e343941a50ba8533ac" @@ -6712,11 +7893,26 @@ uuid@^8.3.2: resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== +uuid@^9.0.0: + version "9.0.1" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30" + integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA== + v8-compile-cache@^2.0.3: version "2.3.0" resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== +varint@^5.0.0: + version "5.0.2" + resolved "https://registry.yarnpkg.com/varint/-/varint-5.0.2.tgz#5b47f8a947eb668b848e034dcfa87d0ff8a7f7a4" + integrity sha512-lKxKYG6H03yCZUpAGOPOsMcGxd1RHCu1iKvEHYDPmTyq2HueGhD73ssNBqqQWfvYs04G9iUFRvmAVLW20Jw6ow== + +vary@^1, vary@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== + verror@1.10.0: version "1.10.0" resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" @@ -6726,6 +7922,223 @@ verror@1.10.0: core-util-is "1.0.2" extsprintf "^1.2.0" +web3-bzz@1.10.4: + version "1.10.4" + resolved "https://registry.yarnpkg.com/web3-bzz/-/web3-bzz-1.10.4.tgz#dcc787970767d9004c73d11d0eeef774ce16b880" + integrity sha512-ZZ/X4sJ0Uh2teU9lAGNS8EjveEppoHNQiKlOXAjedsrdWuaMErBPdLQjXfcrYvN6WM6Su9PMsAxf3FXXZ+HwQw== + dependencies: + "@types/node" "^12.12.6" + got "12.1.0" + swarm-js "^0.1.40" + +web3-core-helpers@1.10.4: + version "1.10.4" + resolved "https://registry.yarnpkg.com/web3-core-helpers/-/web3-core-helpers-1.10.4.tgz#bd2b4140df2016d5dd3bb2b925fc29ad8678677c" + integrity sha512-r+L5ylA17JlD1vwS8rjhWr0qg7zVoVMDvWhajWA5r5+USdh91jRUYosp19Kd1m2vE034v7Dfqe1xYRoH2zvG0g== + dependencies: + web3-eth-iban "1.10.4" + web3-utils "1.10.4" + +web3-core-method@1.10.4: + version "1.10.4" + resolved "https://registry.yarnpkg.com/web3-core-method/-/web3-core-method-1.10.4.tgz#566b52f006d3cbb13b21b72b8d2108999bf5d6bf" + integrity sha512-uZTb7flr+Xl6LaDsyTeE2L1TylokCJwTDrIVfIfnrGmnwLc6bmTWCCrm71sSrQ0hqs6vp/MKbQYIYqUN0J8WyA== + dependencies: + "@ethersproject/transactions" "^5.6.2" + web3-core-helpers "1.10.4" + web3-core-promievent "1.10.4" + web3-core-subscriptions "1.10.4" + web3-utils "1.10.4" + +web3-core-promievent@1.10.4: + version "1.10.4" + resolved "https://registry.yarnpkg.com/web3-core-promievent/-/web3-core-promievent-1.10.4.tgz#629b970b7934430b03c5033c79f3bb3893027e22" + integrity sha512-2de5WnJQ72YcIhYwV/jHLc4/cWJnznuoGTJGD29ncFQHAfwW/MItHFSVKPPA5v8AhJe+r6y4Y12EKvZKjQVBvQ== + dependencies: + eventemitter3 "4.0.4" + +web3-core-requestmanager@1.10.4: + version "1.10.4" + resolved "https://registry.yarnpkg.com/web3-core-requestmanager/-/web3-core-requestmanager-1.10.4.tgz#eb1f147e6b9df84e3a37e602162f8925bdb4bb9a" + integrity sha512-vqP6pKH8RrhT/2MoaU+DY/OsYK9h7HmEBNCdoMj+4ZwujQtw/Mq2JifjwsJ7gits7Q+HWJwx8q6WmQoVZAWugg== + dependencies: + util "^0.12.5" + web3-core-helpers "1.10.4" + web3-providers-http "1.10.4" + web3-providers-ipc "1.10.4" + web3-providers-ws "1.10.4" + +web3-core-subscriptions@1.10.4: + version "1.10.4" + resolved "https://registry.yarnpkg.com/web3-core-subscriptions/-/web3-core-subscriptions-1.10.4.tgz#2f4dcb404237e92802a563265d11a33934dc38e6" + integrity sha512-o0lSQo/N/f7/L76C0HV63+S54loXiE9fUPfHFcTtpJRQNDBVsSDdWRdePbWwR206XlsBqD5VHApck1//jEafTw== + dependencies: + eventemitter3 "4.0.4" + web3-core-helpers "1.10.4" + +web3-core@1.10.4: + version "1.10.4" + resolved "https://registry.yarnpkg.com/web3-core/-/web3-core-1.10.4.tgz#639de68b8b9871d2dc8892e0dd4e380cb1361a98" + integrity sha512-B6elffYm81MYZDTrat7aEhnhdtVE3lDBUZft16Z8awYMZYJDbnykEbJVS+l3mnA7AQTnSDr/1MjWofGDLBJPww== + dependencies: + "@types/bn.js" "^5.1.1" + "@types/node" "^12.12.6" + bignumber.js "^9.0.0" + web3-core-helpers "1.10.4" + web3-core-method "1.10.4" + web3-core-requestmanager "1.10.4" + web3-utils "1.10.4" + +web3-eth-abi@1.10.4: + version "1.10.4" + resolved "https://registry.yarnpkg.com/web3-eth-abi/-/web3-eth-abi-1.10.4.tgz#16c19d0bde0aaf8c1a56cb7743a83156d148d798" + integrity sha512-cZ0q65eJIkd/jyOlQPDjr8X4fU6CRL1eWgdLwbWEpo++MPU/2P4PFk5ZLAdye9T5Sdp+MomePPJ/gHjLMj2VfQ== + dependencies: + "@ethersproject/abi" "^5.6.3" + web3-utils "1.10.4" + +web3-eth-accounts@1.10.4: + version "1.10.4" + resolved "https://registry.yarnpkg.com/web3-eth-accounts/-/web3-eth-accounts-1.10.4.tgz#df30e85a7cd70e475f8cf52361befba408829e34" + integrity sha512-ysy5sVTg9snYS7tJjxVoQAH6DTOTkRGR8emEVCWNGLGiB9txj+qDvSeT0izjurS/g7D5xlMAgrEHLK1Vi6I3yg== + dependencies: + "@ethereumjs/common" "2.6.5" + "@ethereumjs/tx" "3.5.2" + "@ethereumjs/util" "^8.1.0" + eth-lib "0.2.8" + scrypt-js "^3.0.1" + uuid "^9.0.0" + web3-core "1.10.4" + web3-core-helpers "1.10.4" + web3-core-method "1.10.4" + web3-utils "1.10.4" + +web3-eth-contract@1.10.4: + version "1.10.4" + resolved "https://registry.yarnpkg.com/web3-eth-contract/-/web3-eth-contract-1.10.4.tgz#22d39f04e11d9ff4e726e8025a56d78e843a2c3d" + integrity sha512-Q8PfolOJ4eV9TvnTj1TGdZ4RarpSLmHnUnzVxZ/6/NiTfe4maJz99R0ISgwZkntLhLRtw0C7LRJuklzGYCNN3A== + dependencies: + "@types/bn.js" "^5.1.1" + web3-core "1.10.4" + web3-core-helpers "1.10.4" + web3-core-method "1.10.4" + web3-core-promievent "1.10.4" + web3-core-subscriptions "1.10.4" + web3-eth-abi "1.10.4" + web3-utils "1.10.4" + +web3-eth-ens@1.10.4: + version "1.10.4" + resolved "https://registry.yarnpkg.com/web3-eth-ens/-/web3-eth-ens-1.10.4.tgz#3d991adac52bc8e598f1f1b8528337fa6291004c" + integrity sha512-LLrvxuFeVooRVZ9e5T6OWKVflHPFgrVjJ/jtisRWcmI7KN/b64+D/wJzXqgmp6CNsMQcE7rpmf4CQmJCrTdsgg== + dependencies: + content-hash "^2.5.2" + eth-ens-namehash "2.0.8" + web3-core "1.10.4" + web3-core-helpers "1.10.4" + web3-core-promievent "1.10.4" + web3-eth-abi "1.10.4" + web3-eth-contract "1.10.4" + web3-utils "1.10.4" + +web3-eth-iban@1.10.4: + version "1.10.4" + resolved "https://registry.yarnpkg.com/web3-eth-iban/-/web3-eth-iban-1.10.4.tgz#bc61b4a1930d19b1df8762c606d669902558e54d" + integrity sha512-0gE5iNmOkmtBmbKH2aTodeompnNE8jEyvwFJ6s/AF6jkw9ky9Op9cqfzS56AYAbrqEFuClsqB/AoRves7LDELw== + dependencies: + bn.js "^5.2.1" + web3-utils "1.10.4" + +web3-eth-personal@1.10.4: + version "1.10.4" + resolved "https://registry.yarnpkg.com/web3-eth-personal/-/web3-eth-personal-1.10.4.tgz#e2ee920f47e84848288e03442659cdbb2c4deea2" + integrity sha512-BRa/hs6jU1hKHz+AC/YkM71RP3f0Yci1dPk4paOic53R4ZZG4MgwKRkJhgt3/GPuPliwS46f/i5A7fEGBT4F9w== + dependencies: + "@types/node" "^12.12.6" + web3-core "1.10.4" + web3-core-helpers "1.10.4" + web3-core-method "1.10.4" + web3-net "1.10.4" + web3-utils "1.10.4" + +web3-eth@1.10.4: + version "1.10.4" + resolved "https://registry.yarnpkg.com/web3-eth/-/web3-eth-1.10.4.tgz#3a908c635cb5d935bd30473e452f3bd7f2ee66a5" + integrity sha512-Sql2kYKmgt+T/cgvg7b9ce24uLS7xbFrxE4kuuor1zSCGrjhTJ5rRNG8gTJUkAJGKJc7KgnWmgW+cOfMBPUDSA== + dependencies: + web3-core "1.10.4" + web3-core-helpers "1.10.4" + web3-core-method "1.10.4" + web3-core-subscriptions "1.10.4" + web3-eth-abi "1.10.4" + web3-eth-accounts "1.10.4" + web3-eth-contract "1.10.4" + web3-eth-ens "1.10.4" + web3-eth-iban "1.10.4" + web3-eth-personal "1.10.4" + web3-net "1.10.4" + web3-utils "1.10.4" + +web3-net@1.10.4: + version "1.10.4" + resolved "https://registry.yarnpkg.com/web3-net/-/web3-net-1.10.4.tgz#20e12c60e4477d4298979d8d5d66b9abf8e66a09" + integrity sha512-mKINnhOOnZ4koA+yV2OT5s5ztVjIx7IY9a03w6s+yao/BUn+Luuty0/keNemZxTr1E8Ehvtn28vbOtW7Ids+Ow== + dependencies: + web3-core "1.10.4" + web3-core-method "1.10.4" + web3-utils "1.10.4" + +web3-providers-http@1.10.4: + version "1.10.4" + resolved "https://registry.yarnpkg.com/web3-providers-http/-/web3-providers-http-1.10.4.tgz#ca7aa58aeaf8123500c24ffe0595896319f830e8" + integrity sha512-m2P5Idc8hdiO0l60O6DSCPw0kw64Zgi0pMjbEFRmxKIck2Py57RQMu4bxvkxJwkF06SlGaEQF8rFZBmuX7aagQ== + dependencies: + abortcontroller-polyfill "^1.7.5" + cross-fetch "^4.0.0" + es6-promise "^4.2.8" + web3-core-helpers "1.10.4" + +web3-providers-ipc@1.10.4: + version "1.10.4" + resolved "https://registry.yarnpkg.com/web3-providers-ipc/-/web3-providers-ipc-1.10.4.tgz#2e03437909e4e7771d646ff05518efae44b783c3" + integrity sha512-YRF/bpQk9z3WwjT+A6FI/GmWRCASgd+gC0si7f9zbBWLXjwzYAKG73bQBaFRAHex1hl4CVcM5WUMaQXf3Opeuw== + dependencies: + oboe "2.1.5" + web3-core-helpers "1.10.4" + +web3-providers-ws@1.10.4: + version "1.10.4" + resolved "https://registry.yarnpkg.com/web3-providers-ws/-/web3-providers-ws-1.10.4.tgz#55d0c3ba36c6a79d105f02e20a707eb3978e7f82" + integrity sha512-j3FBMifyuFFmUIPVQR4pj+t5ILhAexAui0opgcpu9R5LxQrLRUZxHSnU+YO25UycSOa/NAX8A+qkqZNpcFAlxA== + dependencies: + eventemitter3 "4.0.4" + web3-core-helpers "1.10.4" + websocket "^1.0.32" + +web3-shh@1.10.4: + version "1.10.4" + resolved "https://registry.yarnpkg.com/web3-shh/-/web3-shh-1.10.4.tgz#9852d6f3d05678e31e49235a60fea10ca7a9e21d" + integrity sha512-cOH6iFFM71lCNwSQrC3niqDXagMqrdfFW85hC9PFUrAr3PUrIem8TNstTc3xna2bwZeWG6OBy99xSIhBvyIACw== + dependencies: + web3-core "1.10.4" + web3-core-method "1.10.4" + web3-core-subscriptions "1.10.4" + web3-net "1.10.4" + +web3-utils@1.10.4: + version "1.10.4" + resolved "https://registry.yarnpkg.com/web3-utils/-/web3-utils-1.10.4.tgz#0daee7d6841641655d8b3726baf33b08eda1cbec" + integrity sha512-tsu8FiKJLk2PzhDl9fXbGUWTkkVXYhtTA+SmEFkKft+9BgwLxfCRpU96sWv7ICC8zixBNd3JURVoiR3dUXgP8A== + dependencies: + "@ethereumjs/util" "^8.1.0" + bn.js "^5.2.1" + ethereum-bloom-filters "^1.0.6" + ethereum-cryptography "^2.1.2" + ethjs-unit "0.1.6" + number-to-bn "1.7.0" + randombytes "^2.1.0" + utf8 "3.0.0" + web3-utils@^1.3.6, web3-utils@^1.5.2: version "1.10.0" resolved "https://registry.yarnpkg.com/web3-utils/-/web3-utils-1.10.0.tgz#ca4c1b431a765c14ac7f773e92e0fd9377ccf578" @@ -6739,11 +8152,36 @@ web3-utils@^1.3.6, web3-utils@^1.5.2: randombytes "^2.1.0" utf8 "3.0.0" +web3@^1.10.0: + version "1.10.4" + resolved "https://registry.yarnpkg.com/web3/-/web3-1.10.4.tgz#5d5e59b976eaf758b060fe1a296da5fe87bdc79c" + integrity sha512-kgJvQZjkmjOEKimx/tJQsqWfRDPTTcBfYPa9XletxuHLpHcXdx67w8EFn5AW3eVxCutE9dTVHgGa9VYe8vgsEA== + dependencies: + web3-bzz "1.10.4" + web3-core "1.10.4" + web3-eth "1.10.4" + web3-eth-personal "1.10.4" + web3-net "1.10.4" + web3-shh "1.10.4" + web3-utils "1.10.4" + webidl-conversions@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== +websocket@^1.0.32: + version "1.0.34" + resolved "https://registry.yarnpkg.com/websocket/-/websocket-1.0.34.tgz#2bdc2602c08bf2c82253b730655c0ef7dcab3111" + integrity sha512-PRDso2sGwF6kM75QykIesBijKSVceR6jL2G8NGYyq2XrItNC2P5/qL5XeR056GhA+Ly7JMFvJb9I312mJfmqnQ== + dependencies: + bufferutil "^4.0.1" + debug "^2.2.0" + es5-ext "^0.10.50" + typedarray-to-buffer "^3.1.5" + utf-8-validate "^5.0.2" + yaeti "^0.0.6" + whatwg-url@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" @@ -6768,6 +8206,17 @@ which-module@^2.0.0: resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.1.tgz#776b1fe35d90aebe99e8ac15eb24093389a4a409" integrity sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ== +which-typed-array@^1.1.14, which-typed-array@^1.1.2: + version "1.1.15" + resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.15.tgz#264859e9b11a649b388bfaaf4f767df1f779b38d" + integrity sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA== + dependencies: + available-typed-arrays "^1.0.7" + call-bind "^1.0.7" + for-each "^0.3.3" + gopd "^1.0.1" + has-tostringtag "^1.0.2" + which-typed-array@^1.1.9: version "1.1.9" resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.9.tgz#307cf898025848cf995e795e8423c7f337efbde6" @@ -6859,17 +8308,56 @@ ws@7.4.6: resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.6.tgz#5654ca8ecdeee47c33a9a4bf6d28e2be2980377c" integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A== +ws@^3.0.0: + version "3.3.3" + resolved "https://registry.yarnpkg.com/ws/-/ws-3.3.3.tgz#f1cf84fe2d5e901ebce94efaece785f187a228f2" + integrity sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA== + dependencies: + async-limiter "~1.0.0" + safe-buffer "~5.1.0" + ultron "~1.1.0" + ws@^7.4.6: version "7.5.9" resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.9.tgz#54fa7db29f4c7cec68b1ddd3a89de099942bb591" integrity sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q== +xhr-request-promise@^0.1.2: + version "0.1.3" + resolved "https://registry.yarnpkg.com/xhr-request-promise/-/xhr-request-promise-0.1.3.tgz#2d5f4b16d8c6c893be97f1a62b0ed4cf3ca5f96c" + integrity sha512-YUBytBsuwgitWtdRzXDDkWAXzhdGB8bYm0sSzMPZT7Z2MBjMSTHFsyCT1yCRATY+XC69DUrQraRAEgcoCRaIPg== + dependencies: + xhr-request "^1.1.0" + +xhr-request@^1.0.1, xhr-request@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/xhr-request/-/xhr-request-1.1.0.tgz#f4a7c1868b9f198723444d82dcae317643f2e2ed" + integrity sha512-Y7qzEaR3FDtL3fP30k9wO/e+FBnBByZeybKOhASsGP30NIkRAAkKD/sCnLvgEfAIEC1rcmK7YG8f4oEnIrrWzA== + dependencies: + buffer-to-arraybuffer "^0.0.5" + object-assign "^4.1.1" + query-string "^5.0.1" + simple-get "^2.7.0" + timed-out "^4.0.1" + url-set-query "^1.0.0" + xhr "^2.0.4" + +xhr@^2.0.4, xhr@^2.3.3: + version "2.6.0" + resolved "https://registry.yarnpkg.com/xhr/-/xhr-2.6.0.tgz#b69d4395e792b4173d6b7df077f0fc5e4e2b249d" + integrity sha512-/eCGLb5rxjx5e3mF1A7s+pLlR6CGyqWN91fv1JgER5mVWg1MZmlhBvy9kjcsOdRk8RrIujotWyJamfyrp+WIcA== + dependencies: + global "~4.4.0" + is-function "^1.0.1" + parse-headers "^2.0.0" + xtend "^4.0.0" + xmlhttprequest@1.8.0: version "1.8.0" resolved "https://registry.yarnpkg.com/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz#67fe075c5c24fef39f9d65f5f7b7fe75171968fc" integrity sha512-58Im/U0mlVBLM38NdZjHyhuMtCqa61469k2YP/AaPbvCoV9aQGUpbJBj1QRm2ytRiVQBD/fsw7L2bJGDVQswBA== -xtend@^4.0.1, xtend@^4.0.2, xtend@~4.0.0: +xtend@^4.0.0, xtend@^4.0.1, xtend@^4.0.2, xtend@~4.0.0: version "4.0.2" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== @@ -6884,7 +8372,12 @@ y18n@^5.0.5: resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== -yallist@^3.0.2: +yaeti@^0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/yaeti/-/yaeti-0.0.6.tgz#f26f484d72684cf42bedfb76970aa1608fbf9577" + integrity sha512-MvQa//+KcZCUkBTIC9blM+CU9J2GzuTytsOUwf2lidtvkx/6gnEp1QvJv34t9vdjhFmha/mUiNDbN0D0mJWdug== + +yallist@^3.0.0, yallist@^3.0.2, yallist@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== From 6179cb1f661327c05b7fa8c83154855b40780f17 Mon Sep 17 00:00:00 2001 From: Nick Addison Date: Tue, 30 Apr 2024 00:28:36 +1000 Subject: [PATCH 022/273] manuallyFixAccounting changes (#2034) * manuallyFixAccounting now uses delta values and only callable by the strategist manuallyFixAccounting calls doAccounting to check the fuse is still not blown Removed accountingGovernor * Added pauseOnFail param to internal _doAccounting Increased the allowed delta values of manuallyFixAccounting * ran prettier --- .../NativeStaking/ValidatorAccountant.sol | 126 +++--- .../NativeStaking/ValidatorRegistrator.sol | 2 +- .../deploy/mainnet/091_native_ssv_staking.js | 6 - .../NativeStakingSSVStrategyHierarchy.svg | 16 +- .../docs/NativeStakingSSVStrategySquashed.svg | 243 ++++++------ .../docs/NativeStakingSSVStrategyStorage.svg | 152 ++++---- contracts/test/_fixture.js | 3 - contracts/test/strategies/nativeSSVStaking.js | 358 +++++++++++------- 8 files changed, 480 insertions(+), 426 deletions(-) diff --git a/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol b/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol index 2f1843ee56..6edcf44f69 100644 --- a/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol +++ b/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol @@ -22,8 +22,6 @@ abstract contract ValidatorAccountant is ValidatorRegistrator { uint256 public fuseIntervalStart = 0; /// @notice end of fuse interval uint256 public fuseIntervalEnd = 0; - /// @notice Governor that can manually correct the accounting - address public accountingGovernor; uint256[50] private __gap; @@ -37,27 +35,14 @@ abstract contract ValidatorAccountant is ValidatorRegistrator { uint256 remainingValidators, uint256 wethSentToVault ); - event AccountingGovernorChanged(address newAddress); event AccountingConsensusRewards(uint256 amount); event AccountingManuallyFixed( - uint256 oldActiveDepositedValidators, - uint256 activeDepositedValidators, - uint256 oldBeaconChainRewards, - uint256 beaconChainRewards, - uint256 ethToWeth, - uint256 wethToBeSentToVault + int256 validatorsDelta, + int256 consensusRewardsDelta, + uint256 wethToVault ); - /// @dev Throws if called by any account other than the Accounting Governor - modifier onlyAccountingGovernor() { - require( - msg.sender == accountingGovernor, - "Caller is not the Accounting Governor" - ); - _; - } - /// @param _wethAddress Address of the Erc20 WETH Token contract /// @param _vaultAddress Address of the Vault /// @param _beaconChainDepositContract Address of the beacon chain deposit contract @@ -76,11 +61,6 @@ abstract contract ValidatorAccountant is ValidatorRegistrator { ) {} - function setAccountingGovernor(address _address) external onlyGovernor { - emit AccountingGovernorChanged(_address); - accountingGovernor = _address; - } - /// @notice set fuse interval values function setFuseInterval( uint256 _fuseIntervalStart, @@ -111,16 +91,28 @@ abstract contract ValidatorAccountant is ValidatorRegistrator { /// accounting is valid and fuse isn't "blown". Returns false when fuse is blown. /// @dev This function could in theory be permission-less but lets allow only the Registrator (Defender Action) to call it /// for now. + /// @return accountingValid true if accounting was successful, false if fuse is blown /* solhint-enable max-line-length */ function doAccounting() external onlyRegistrator whenNotPaused returns (bool accountingValid) + { + // pause the accounting on failure + accountingValid = _doAccounting(true); + } + + function _doAccounting(bool pauseOnFail) + internal + returns (bool accountingValid) { if (address(this).balance < consensusRewards) { - // pause and fail the accounting - _pause(); + // pause if not already + if (pauseOnFail) { + _pause(); + } + // fail the accounting return false; } @@ -170,66 +162,66 @@ abstract contract ValidatorAccountant is ValidatorRegistrator { ethRemaining ); } - // Oh no... Fuse is blown. The governor (Multisig not OGV Governor) needs to set the - // record straight by manually set the accounting values. + // Oh no... Fuse is blown. The Strategist needs to adjust the accounting values. else { - // will emit a paused event - _pause(); + // pause if not already + if (pauseOnFail) { + _pause(); + } + // fail the accounting accountingValid = false; } } - /// @dev allow the accounting governor to fix the accounting of this strategy and unpause - /// @param _activeDepositedValidators the override value of activeDepositedValidators - /// @param _ethToWeth the amount of ETH to be converted to WETH - /// @param _wethToBeSentToVault the amount of WETH to be sent to the Vault - /// @param _consensusRewards the override value for consensusRewards - /// @param _ethThresholdCheck maximum allowed ETH balance on the contract for the function to run - /// @param _wethThresholdCheck maximum allowed WETH balance on the contract for the function to run - /// the above 2 checks are done so transaction doesn't get front run and cause - /// unexpected behaviour + /// @notice Allow the Strategist to fix the accounting of this strategy and unpause. + /// @param _validatorsDelta adjust the active validators by plus one, minus one or unchanged with zero + /// @param _wethToVaultAmount the amount of WETH to be sent to the Vault + /// @param _consensusRewardsDelta adjust the accounted for consensus rewards up or down function manuallyFixAccounting( - uint256 _activeDepositedValidators, - uint256 _ethToWeth, - uint256 _wethToBeSentToVault, - uint256 _consensusRewards, - uint256 _ethThresholdCheck, - uint256 _wethThresholdCheck - ) external onlyAccountingGovernor whenPaused { - uint256 ethBalance = address(this).balance; - uint256 wethBalance = IWETH9(WETH_TOKEN_ADDRESS).balanceOf( - address(this) + int256 _validatorsDelta, + int256 _consensusRewardsDelta, + uint256 _wethToVaultAmount + ) external onlyStrategist whenPaused { + require( + _validatorsDelta >= -3 && + _validatorsDelta <= 3 && + // new value must be positive + int256(activeDepositedValidators) + _validatorsDelta >= 0, + "invalid validatorsDelta" ); - require( - ethBalance <= _ethThresholdCheck && - wethBalance <= _wethThresholdCheck, - "over accounting threshold" + _consensusRewardsDelta >= -332 ether && + _consensusRewardsDelta <= 332 ether && + // new value must be positive + int256(consensusRewards) + _consensusRewardsDelta >= 0, + "invalid consensusRewardsDelta" ); + require(_wethToVaultAmount <= 32 ether, "invalid wethToVaultAmount"); emit AccountingManuallyFixed( - activeDepositedValidators, - _activeDepositedValidators, - consensusRewards, - _consensusRewards, - _ethToWeth, - _wethToBeSentToVault + _validatorsDelta, + _consensusRewardsDelta, + _wethToVaultAmount ); - activeDepositedValidators = _activeDepositedValidators; - consensusRewards = _consensusRewards; - if (_ethToWeth > 0) { - require(_ethToWeth <= ethBalance, "insufficient ETH"); - - IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: _ethToWeth }(); - } - if (_wethToBeSentToVault > 0) { + activeDepositedValidators = uint256( + int256(activeDepositedValidators) + _validatorsDelta + ); + consensusRewards = uint256( + int256(consensusRewards) + _consensusRewardsDelta + ); + if (_wethToVaultAmount > 0) { IWETH9(WETH_TOKEN_ADDRESS).transfer( VAULT_ADDRESS, - _wethToBeSentToVault + _wethToVaultAmount ); } + // rerun the accounting to see if it has now been fixed. + // Do not pause the accounting on failure as it is already paused + require(_doAccounting(false), "fuse still blown"); + + // unpause since doAccounting was successful _unpause(); } } diff --git a/contracts/contracts/strategies/NativeStaking/ValidatorRegistrator.sol b/contracts/contracts/strategies/NativeStaking/ValidatorRegistrator.sol index 30270331f4..b6f61eecd2 100644 --- a/contracts/contracts/strategies/NativeStaking/ValidatorRegistrator.sol +++ b/contracts/contracts/strategies/NativeStaking/ValidatorRegistrator.sol @@ -34,7 +34,7 @@ abstract contract ValidatorRegistrator is Governable, Pausable { /// @notice The number of validators that have 32 (!) ETH actively deposited. When a new deposit /// to a validator happens this number increases, when a validator exit is detected this number /// decreases. - uint256 activeDepositedValidators; + uint256 public activeDepositedValidators; /// @notice State of the validators keccak256(pubKey) => state mapping(bytes32 => VALIDATOR_STATE) public validatorsStates; diff --git a/contracts/deploy/mainnet/091_native_ssv_staking.js b/contracts/deploy/mainnet/091_native_ssv_staking.js index 77cb1135e8..817a620993 100644 --- a/contracts/deploy/mainnet/091_native_ssv_staking.js +++ b/contracts/deploy/mainnet/091_native_ssv_staking.js @@ -152,12 +152,6 @@ module.exports = deploymentWithGovernanceProposal( ethers.utils.parseEther("25.6"), ], }, - // 5. configure the accounting governor - { - contract: cStrategy, - signature: "setAccountingGovernor(address)", - args: [deployerAddr], // TODO: change this to the defender action - }, ], }; } diff --git a/contracts/docs/NativeStakingSSVStrategyHierarchy.svg b/contracts/docs/NativeStakingSSVStrategyHierarchy.svg index 3007a5a443..0686fa8c78 100644 --- a/contracts/docs/NativeStakingSSVStrategyHierarchy.svg +++ b/contracts/docs/NativeStakingSSVStrategyHierarchy.svg @@ -90,17 +90,17 @@ - + -336 +340 <<Abstract>> Pausable ../node_modules/@openzeppelin/contracts/security/Pausable.sol - + -283->336 +283->340 @@ -124,17 +124,17 @@ - + -341 +345 <<Abstract>> Context ../node_modules/@openzeppelin/contracts/utils/Context.sol - + -336->341 +340->345 diff --git a/contracts/docs/NativeStakingSSVStrategySquashed.svg b/contracts/docs/NativeStakingSSVStrategySquashed.svg index 392788f64f..e66ffdaf08 100644 --- a/contracts/docs/NativeStakingSSVStrategySquashed.svg +++ b/contracts/docs/NativeStakingSSVStrategySquashed.svg @@ -4,133 +4,130 @@ - - + + UmlClassDiagram - + 280 - -NativeStakingSSVStrategy -../contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol - -Private: -   governorPosition: bytes32 <<Governable>> -   pendingGovernorPosition: bytes32 <<Governable>> -   reentryStatusPosition: bytes32 <<Governable>> -   _paused: bool <<Pausable>> -   __gap: uint256[50] <<ValidatorRegistrator>> -   __gap: uint256[50] <<ValidatorAccountant>> -   initialized: bool <<Initializable>> -   initializing: bool <<Initializable>> -   ______gap: uint256[50] <<Initializable>> -   _deprecated_platformAddress: address <<InitializableAbstractStrategy>> -   _deprecated_vaultAddress: address <<InitializableAbstractStrategy>> -   _deprecated_rewardTokenAddress: address <<InitializableAbstractStrategy>> -   _deprecated_rewardLiquidationThreshold: uint256 <<InitializableAbstractStrategy>> -   _reserved: int256[98] <<InitializableAbstractStrategy>> -   __gap: uint256[50] <<NativeStakingSSVStrategy>> -Internal: -   assetsMapped: address[] <<InitializableAbstractStrategy>> -Public: -   _NOT_ENTERED: uint256 <<Governable>> -   _ENTERED: uint256 <<Governable>> -   WETH_TOKEN_ADDRESS: address <<ValidatorRegistrator>> -   BEACON_CHAIN_DEPOSIT_CONTRACT: address <<ValidatorRegistrator>> -   SSV_NETWORK_ADDRESS: address <<ValidatorRegistrator>> -   VAULT_ADDRESS: address <<ValidatorRegistrator>> -   validatorRegistrator: address <<ValidatorRegistrator>> -   activeDepositedValidators: uint256 <<ValidatorRegistrator>> -   validatorsStates: mapping(bytes32=>VALIDATOR_STATE) <<ValidatorRegistrator>> -   MAX_STAKE: uint256 <<ValidatorAccountant>> -   consensusRewards: uint256 <<ValidatorAccountant>> -   fuseIntervalStart: uint256 <<ValidatorAccountant>> -   fuseIntervalEnd: uint256 <<ValidatorAccountant>> -   accountingGovernor: address <<ValidatorAccountant>> -   platformAddress: address <<InitializableAbstractStrategy>> -   vaultAddress: address <<InitializableAbstractStrategy>> -   assetToPToken: mapping(address=>address) <<InitializableAbstractStrategy>> -   harvesterAddress: address <<InitializableAbstractStrategy>> -   rewardTokenAddresses: address[] <<InitializableAbstractStrategy>> -   SSV_TOKEN_ADDRESS: address <<NativeStakingSSVStrategy>> -   FEE_ACCUMULATOR_ADDRESS: address <<NativeStakingSSVStrategy>> - -Internal: -    _governor(): (governorOut: address) <<Governable>> -    _pendingGovernor(): (pendingGovernor: address) <<Governable>> -    _setGovernor(newGovernor: address) <<Governable>> -    _setPendingGovernor(newGovernor: address) <<Governable>> -    _changeGovernor(_newGovernor: address) <<Governable>> -    _msgSender(): address <<Context>> -    _msgData(): bytes <<Context>> -    _pause() <<whenNotPaused>> <<Pausable>> -    _unpause() <<whenPaused>> <<Pausable>> -    _initialize(_rewardTokenAddresses: address[], _assets: address[], _pTokens: address[]) <<InitializableAbstractStrategy>> -    _collectRewardTokens() <<whenNotPaused>> <<NativeStakingSSVStrategy>> -    _setPTokenAddress(_asset: address, _pToken: address) <<InitializableAbstractStrategy>> -    _abstractSetPToken(_asset: address, address) <<NativeStakingSSVStrategy>> -    _deposit(_asset: address, _amount: uint256) <<NativeStakingSSVStrategy>> -    _withdraw(_recipient: address, _asset: address, _amount: uint256) <<NativeStakingSSVStrategy>> -External: -    <<payable>> null() <<NativeStakingSSVStrategy>> -    transferGovernance(_newGovernor: address) <<onlyGovernor>> <<Governable>> -    claimGovernance() <<Governable>> -    setRegistrator(_address: address) <<onlyGovernor>> <<ValidatorRegistrator>> -    stakeEth(validators: ValidatorStakeData[]) <<onlyRegistrator, whenNotPaused>> <<ValidatorRegistrator>> -    registerSsvValidator(publicKey: bytes, operatorIds: uint64[], sharesData: bytes, amount: uint256, cluster: Cluster) <<onlyRegistrator, whenNotPaused>> <<ValidatorRegistrator>> -    exitSsvValidator(publicKey: bytes, operatorIds: uint64[]) <<onlyRegistrator, whenNotPaused>> <<ValidatorRegistrator>> -    removeSsvValidator(publicKey: bytes, operatorIds: uint64[], cluster: Cluster) <<onlyRegistrator, whenNotPaused>> <<ValidatorRegistrator>> -    depositSSV(operatorIds: uint64[], amount: uint256, cluster: Cluster) <<onlyStrategist>> <<ValidatorRegistrator>> -    setAccountingGovernor(_address: address) <<onlyGovernor>> <<ValidatorAccountant>> -    setFuseInterval(_fuseIntervalStart: uint256, _fuseIntervalEnd: uint256) <<onlyGovernor>> <<ValidatorAccountant>> -    doAccounting(): (accountingValid: bool) <<onlyRegistrator, whenNotPaused>> <<ValidatorAccountant>> -    manuallyFixAccounting(_activeDepositedValidators: uint256, _ethToWeth: uint256, _wethToBeSentToVault: uint256, _consensusRewards: uint256, _ethThresholdCheck: uint256, _wethThresholdCheck: uint256) <<onlyAccountingGovernor, whenPaused>> <<ValidatorAccountant>> -    collectRewardTokens() <<onlyHarvester, nonReentrant>> <<InitializableAbstractStrategy>> -    setRewardTokenAddresses(_rewardTokenAddresses: address[]) <<onlyGovernor>> <<InitializableAbstractStrategy>> -    getRewardTokenAddresses(): address[] <<InitializableAbstractStrategy>> -    setPTokenAddress(_asset: address, _pToken: address) <<onlyGovernor>> <<InitializableAbstractStrategy>> -    removePToken(_assetIndex: uint256) <<onlyGovernor>> <<InitializableAbstractStrategy>> -    setHarvesterAddress(_harvesterAddress: address) <<onlyGovernor>> <<InitializableAbstractStrategy>> -    safeApproveAllTokens() <<NativeStakingSSVStrategy>> -    deposit(_asset: address, _amount: uint256) <<onlyVault, nonReentrant>> <<NativeStakingSSVStrategy>> -    depositAll() <<onlyVault, nonReentrant>> <<NativeStakingSSVStrategy>> -    withdraw(_recipient: address, _asset: address, _amount: uint256) <<onlyVault, nonReentrant>> <<NativeStakingSSVStrategy>> -    withdrawAll() <<onlyVaultOrGovernor, nonReentrant>> <<NativeStakingSSVStrategy>> -    checkBalance(_asset: address): (balance: uint256) <<NativeStakingSSVStrategy>> -    initialize(_rewardTokenAddresses: address[], _assets: address[], _pTokens: address[]) <<onlyGovernor, initializer>> <<NativeStakingSSVStrategy>> -    pause() <<onlyStrategist>> <<NativeStakingSSVStrategy>> -Public: -    <<event>> PendingGovernorshipTransfer(previousGovernor: address, newGovernor: address) <<Governable>> -    <<event>> GovernorshipTransferred(previousGovernor: address, newGovernor: address) <<Governable>> -    <<event>> Paused(account: address) <<Pausable>> -    <<event>> Unpaused(account: address) <<Pausable>> -    <<event>> RegistratorChanged(newAddress: address) <<ValidatorRegistrator>> -    <<event>> ETHStaked(pubkey: bytes, amount: uint256, withdrawal_credentials: bytes) <<ValidatorRegistrator>> -    <<event>> SSVValidatorRegistered(pubkey: bytes, operatorIds: uint64[]) <<ValidatorRegistrator>> -    <<event>> SSVValidatorExitInitiated(pubkey: bytes, operatorIds: uint64[]) <<ValidatorRegistrator>> -    <<event>> SSVValidatorExitCompleted(pubkey: bytes, operatorIds: uint64[]) <<ValidatorRegistrator>> -    <<event>> FuseIntervalUpdated(start: uint256, end: uint256) <<ValidatorAccountant>> -    <<event>> AccountingFullyWithdrawnValidator(noOfValidators: uint256, remainingValidators: uint256, wethSentToVault: uint256) <<ValidatorAccountant>> -    <<event>> AccountingValidatorSlashed(remainingValidators: uint256, wethSentToVault: uint256) <<ValidatorAccountant>> -    <<event>> AccountingGovernorChanged(newAddress: address) <<ValidatorAccountant>> -    <<event>> AccountingConsensusRewards(amount: uint256) <<ValidatorAccountant>> -    <<event>> AccountingManuallyFixed(oldActiveDepositedValidators: uint256, activeDepositedValidators: uint256, oldBeaconChainRewards: uint256, beaconChainRewards: uint256, ethToWeth: uint256, wethToBeSentToVault: uint256) <<ValidatorAccountant>> -    <<event>> PTokenAdded(_asset: address, _pToken: address) <<InitializableAbstractStrategy>> -    <<event>> PTokenRemoved(_asset: address, _pToken: address) <<InitializableAbstractStrategy>> -    <<event>> Deposit(_asset: address, _pToken: address, _amount: uint256) <<InitializableAbstractStrategy>> -    <<event>> Withdrawal(_asset: address, _pToken: address, _amount: uint256) <<InitializableAbstractStrategy>> -    <<event>> RewardTokenCollected(recipient: address, rewardToken: address, amount: uint256) <<InitializableAbstractStrategy>> -    <<event>> RewardTokenAddressesUpdated(_oldAddresses: address[], _newAddresses: address[]) <<InitializableAbstractStrategy>> -    <<event>> HarvesterAddressesUpdated(_oldHarvesterAddress: address, _newHarvesterAddress: address) <<InitializableAbstractStrategy>> -    <<modifier>> onlyGovernor() <<Governable>> -    <<modifier>> nonReentrant() <<Governable>> -    <<modifier>> whenNotPaused() <<Pausable>> -    <<modifier>> whenPaused() <<Pausable>> -    <<modifier>> onlyRegistrator() <<ValidatorRegistrator>> -    <<modifier>> onlyStrategist() <<ValidatorRegistrator>> -    <<modifier>> onlyAccountingGovernor() <<ValidatorAccountant>> + +NativeStakingSSVStrategy +../contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol + +Private: +   governorPosition: bytes32 <<Governable>> +   pendingGovernorPosition: bytes32 <<Governable>> +   reentryStatusPosition: bytes32 <<Governable>> +   _paused: bool <<Pausable>> +   __gap: uint256[50] <<ValidatorRegistrator>> +   __gap: uint256[50] <<ValidatorAccountant>> +   initialized: bool <<Initializable>> +   initializing: bool <<Initializable>> +   ______gap: uint256[50] <<Initializable>> +   _deprecated_platformAddress: address <<InitializableAbstractStrategy>> +   _deprecated_vaultAddress: address <<InitializableAbstractStrategy>> +   _deprecated_rewardTokenAddress: address <<InitializableAbstractStrategy>> +   _deprecated_rewardLiquidationThreshold: uint256 <<InitializableAbstractStrategy>> +   _reserved: int256[98] <<InitializableAbstractStrategy>> +   __gap: uint256[50] <<NativeStakingSSVStrategy>> +Internal: +   assetsMapped: address[] <<InitializableAbstractStrategy>> +Public: +   _NOT_ENTERED: uint256 <<Governable>> +   _ENTERED: uint256 <<Governable>> +   WETH_TOKEN_ADDRESS: address <<ValidatorRegistrator>> +   BEACON_CHAIN_DEPOSIT_CONTRACT: address <<ValidatorRegistrator>> +   SSV_NETWORK_ADDRESS: address <<ValidatorRegistrator>> +   VAULT_ADDRESS: address <<ValidatorRegistrator>> +   validatorRegistrator: address <<ValidatorRegistrator>> +   activeDepositedValidators: uint256 <<ValidatorRegistrator>> +   validatorsStates: mapping(bytes32=>VALIDATOR_STATE) <<ValidatorRegistrator>> +   MAX_STAKE: uint256 <<ValidatorAccountant>> +   consensusRewards: uint256 <<ValidatorAccountant>> +   fuseIntervalStart: uint256 <<ValidatorAccountant>> +   fuseIntervalEnd: uint256 <<ValidatorAccountant>> +   platformAddress: address <<InitializableAbstractStrategy>> +   vaultAddress: address <<InitializableAbstractStrategy>> +   assetToPToken: mapping(address=>address) <<InitializableAbstractStrategy>> +   harvesterAddress: address <<InitializableAbstractStrategy>> +   rewardTokenAddresses: address[] <<InitializableAbstractStrategy>> +   SSV_TOKEN_ADDRESS: address <<NativeStakingSSVStrategy>> +   FEE_ACCUMULATOR_ADDRESS: address <<NativeStakingSSVStrategy>> + +Internal: +    _governor(): (governorOut: address) <<Governable>> +    _pendingGovernor(): (pendingGovernor: address) <<Governable>> +    _setGovernor(newGovernor: address) <<Governable>> +    _setPendingGovernor(newGovernor: address) <<Governable>> +    _changeGovernor(_newGovernor: address) <<Governable>> +    _msgSender(): address <<Context>> +    _msgData(): bytes <<Context>> +    _pause() <<whenNotPaused>> <<Pausable>> +    _unpause() <<whenPaused>> <<Pausable>> +    _doAccounting(pauseOnFail: bool): (accountingValid: bool) <<ValidatorAccountant>> +    _initialize(_rewardTokenAddresses: address[], _assets: address[], _pTokens: address[]) <<InitializableAbstractStrategy>> +    _collectRewardTokens() <<whenNotPaused>> <<NativeStakingSSVStrategy>> +    _setPTokenAddress(_asset: address, _pToken: address) <<InitializableAbstractStrategy>> +    _abstractSetPToken(_asset: address, address) <<NativeStakingSSVStrategy>> +    _deposit(_asset: address, _amount: uint256) <<NativeStakingSSVStrategy>> +    _withdraw(_recipient: address, _asset: address, _amount: uint256) <<NativeStakingSSVStrategy>> +External: +    <<payable>> null() <<NativeStakingSSVStrategy>> +    transferGovernance(_newGovernor: address) <<onlyGovernor>> <<Governable>> +    claimGovernance() <<Governable>> +    setRegistrator(_address: address) <<onlyGovernor>> <<ValidatorRegistrator>> +    stakeEth(validators: ValidatorStakeData[]) <<onlyRegistrator, whenNotPaused>> <<ValidatorRegistrator>> +    registerSsvValidator(publicKey: bytes, operatorIds: uint64[], sharesData: bytes, amount: uint256, cluster: Cluster) <<onlyRegistrator, whenNotPaused>> <<ValidatorRegistrator>> +    exitSsvValidator(publicKey: bytes, operatorIds: uint64[]) <<onlyRegistrator, whenNotPaused>> <<ValidatorRegistrator>> +    removeSsvValidator(publicKey: bytes, operatorIds: uint64[], cluster: Cluster) <<onlyRegistrator, whenNotPaused>> <<ValidatorRegistrator>> +    depositSSV(operatorIds: uint64[], amount: uint256, cluster: Cluster) <<onlyStrategist>> <<ValidatorRegistrator>> +    setFuseInterval(_fuseIntervalStart: uint256, _fuseIntervalEnd: uint256) <<onlyGovernor>> <<ValidatorAccountant>> +    doAccounting(): (accountingValid: bool) <<onlyRegistrator, whenNotPaused>> <<ValidatorAccountant>> +    manuallyFixAccounting(_validatorsDelta: int256, _consensusRewardsDelta: int256, _wethToVaultAmount: uint256) <<onlyStrategist, whenPaused>> <<ValidatorAccountant>> +    collectRewardTokens() <<onlyHarvester, nonReentrant>> <<InitializableAbstractStrategy>> +    setRewardTokenAddresses(_rewardTokenAddresses: address[]) <<onlyGovernor>> <<InitializableAbstractStrategy>> +    getRewardTokenAddresses(): address[] <<InitializableAbstractStrategy>> +    setPTokenAddress(_asset: address, _pToken: address) <<onlyGovernor>> <<InitializableAbstractStrategy>> +    removePToken(_assetIndex: uint256) <<onlyGovernor>> <<InitializableAbstractStrategy>> +    setHarvesterAddress(_harvesterAddress: address) <<onlyGovernor>> <<InitializableAbstractStrategy>> +    safeApproveAllTokens() <<NativeStakingSSVStrategy>> +    deposit(_asset: address, _amount: uint256) <<onlyVault, nonReentrant>> <<NativeStakingSSVStrategy>> +    depositAll() <<onlyVault, nonReentrant>> <<NativeStakingSSVStrategy>> +    withdraw(_recipient: address, _asset: address, _amount: uint256) <<onlyVault, nonReentrant>> <<NativeStakingSSVStrategy>> +    withdrawAll() <<onlyVaultOrGovernor, nonReentrant>> <<NativeStakingSSVStrategy>> +    checkBalance(_asset: address): (balance: uint256) <<NativeStakingSSVStrategy>> +    initialize(_rewardTokenAddresses: address[], _assets: address[], _pTokens: address[]) <<onlyGovernor, initializer>> <<NativeStakingSSVStrategy>> +    pause() <<onlyStrategist>> <<NativeStakingSSVStrategy>> +Public: +    <<event>> PendingGovernorshipTransfer(previousGovernor: address, newGovernor: address) <<Governable>> +    <<event>> GovernorshipTransferred(previousGovernor: address, newGovernor: address) <<Governable>> +    <<event>> Paused(account: address) <<Pausable>> +    <<event>> Unpaused(account: address) <<Pausable>> +    <<event>> RegistratorChanged(newAddress: address) <<ValidatorRegistrator>> +    <<event>> ETHStaked(pubkey: bytes, amount: uint256, withdrawal_credentials: bytes) <<ValidatorRegistrator>> +    <<event>> SSVValidatorRegistered(pubkey: bytes, operatorIds: uint64[]) <<ValidatorRegistrator>> +    <<event>> SSVValidatorExitInitiated(pubkey: bytes, operatorIds: uint64[]) <<ValidatorRegistrator>> +    <<event>> SSVValidatorExitCompleted(pubkey: bytes, operatorIds: uint64[]) <<ValidatorRegistrator>> +    <<event>> FuseIntervalUpdated(start: uint256, end: uint256) <<ValidatorAccountant>> +    <<event>> AccountingFullyWithdrawnValidator(noOfValidators: uint256, remainingValidators: uint256, wethSentToVault: uint256) <<ValidatorAccountant>> +    <<event>> AccountingValidatorSlashed(remainingValidators: uint256, wethSentToVault: uint256) <<ValidatorAccountant>> +    <<event>> AccountingConsensusRewards(amount: uint256) <<ValidatorAccountant>> +    <<event>> AccountingManuallyFixed(validatorsDelta: int256, consensusRewardsDelta: int256, wethToVault: uint256) <<ValidatorAccountant>> +    <<event>> PTokenAdded(_asset: address, _pToken: address) <<InitializableAbstractStrategy>> +    <<event>> PTokenRemoved(_asset: address, _pToken: address) <<InitializableAbstractStrategy>> +    <<event>> Deposit(_asset: address, _pToken: address, _amount: uint256) <<InitializableAbstractStrategy>> +    <<event>> Withdrawal(_asset: address, _pToken: address, _amount: uint256) <<InitializableAbstractStrategy>> +    <<event>> RewardTokenCollected(recipient: address, rewardToken: address, amount: uint256) <<InitializableAbstractStrategy>> +    <<event>> RewardTokenAddressesUpdated(_oldAddresses: address[], _newAddresses: address[]) <<InitializableAbstractStrategy>> +    <<event>> HarvesterAddressesUpdated(_oldHarvesterAddress: address, _newHarvesterAddress: address) <<InitializableAbstractStrategy>> +    <<modifier>> onlyGovernor() <<Governable>> +    <<modifier>> nonReentrant() <<Governable>> +    <<modifier>> whenNotPaused() <<Pausable>> +    <<modifier>> whenPaused() <<Pausable>> +    <<modifier>> onlyRegistrator() <<ValidatorRegistrator>> +    <<modifier>> onlyStrategist() <<ValidatorRegistrator>>    <<modifier>> initializer() <<Initializable>>    <<modifier>> onlyVault() <<InitializableAbstractStrategy>>    <<modifier>> onlyHarvester() <<InitializableAbstractStrategy>> diff --git a/contracts/docs/NativeStakingSSVStrategyStorage.svg b/contracts/docs/NativeStakingSSVStrategyStorage.svg index 058cea8538..e5aad7e6a1 100644 --- a/contracts/docs/NativeStakingSSVStrategyStorage.svg +++ b/contracts/docs/NativeStakingSSVStrategyStorage.svg @@ -4,84 +4,78 @@ - - + + StorageDiagram - + 3 - -NativeStakingSSVStrategy <<Contract>> - -slot - -0 + +NativeStakingSSVStrategy <<Contract>> + +slot -1 +0 -2 +1 -3-52 +2 -53 +3-52 -54 +53 -55 +54 -56 +55 -57-106 +56-105 -107 +106 -108-157 +107-156 -158 +157 -159 +158 -160 +159 -161 +160 -162 +161 -163 +162 -164 +163 -165 +164 -166-263 +165-262 -264-313 - -type: <inherited contract>.variable (bytes) - -unallocated (11) - -address: ValidatorRegistrator.validatorRegistrator (20) - -bool: Pausable._paused (1) +263-312 + +type: <inherited contract>.variable (bytes) -uint256: ValidatorRegistrator.activeDepositedValidators (32) +unallocated (11) + +address: ValidatorRegistrator.validatorRegistrator (20) + +bool: Pausable._paused (1) -mapping(bytes32=>VALIDATOR_STATE): ValidatorRegistrator.validatorsStates (32) +uint256: ValidatorRegistrator.activeDepositedValidators (32) -uint256[50]: ValidatorRegistrator.__gap (1600) +mapping(bytes32=>VALIDATOR_STATE): ValidatorRegistrator.validatorsStates (32) -uint256: ValidatorAccountant.consensusRewards (32) +uint256[50]: ValidatorRegistrator.__gap (1600) -uint256: ValidatorAccountant.fuseIntervalStart (32) +uint256: ValidatorAccountant.consensusRewards (32) -uint256: ValidatorAccountant.fuseIntervalEnd (32) +uint256: ValidatorAccountant.fuseIntervalStart (32) -unallocated (12) - -address: ValidatorAccountant.accountingGovernor (20) +uint256: ValidatorAccountant.fuseIntervalEnd (32) uint256[50]: ValidatorAccountant.__gap (1600) @@ -124,48 +118,48 @@ 1 - -address[]: assetsMapped <<Array>> -0xaadc37b8ba5645e62f4546802db221593a94729ccbfc5a97d01365a88f649878 - -offset - -0 - -type: variable (bytes) - -unallocated (12) - -address (20) + +address[]: assetsMapped <<Array>> +0x78fdc8d422c49ced035a9edf18d00d3c6a8d81df210f3e5e448e045e77b41e88 + +offset + +0 + +type: variable (bytes) + +unallocated (12) + +address (20) -3:18->1 - - +3:17->1 + + 2 - -address[]: rewardTokenAddresses <<Array>> -0xb29a2b3b6f2ff1b765777a231725941da5072cc4fcc30ac4a2ce09706e8ddeff - -offset - -0 - -type: variable (bytes) - -unallocated (12) - -address (20) + +address[]: rewardTokenAddresses <<Array>> +0xe434dc35da084cf8d7e8186688ea2dacb53db7003d427af3abf351bd9d0a4e8d + +offset + +0 + +type: variable (bytes) + +unallocated (12) + +address (20) -3:23->2 - - +3:22->2 + + diff --git a/contracts/test/_fixture.js b/contracts/test/_fixture.js index 93c71a49bd..30d342bac3 100644 --- a/contracts/test/_fixture.js +++ b/contracts/test/_fixture.js @@ -1583,9 +1583,6 @@ async function nativeStakingSSVStrategyFixture() { .connect(sGovernor) .setRegistrator(governorAddr); - await nativeStakingSSVStrategy - .connect(sGovernor) - .setAccountingGovernor(governorAddr); } return fixture; diff --git a/contracts/test/strategies/nativeSSVStaking.js b/contracts/test/strategies/nativeSSVStaking.js index c176d3fea3..1fd21a0ae6 100644 --- a/contracts/test/strategies/nativeSSVStaking.js +++ b/contracts/test/strategies/nativeSSVStaking.js @@ -1,7 +1,10 @@ const { expect } = require("chai"); const { BigNumber } = require("ethers"); const { parseEther } = require("ethers").utils; -const { setBalance } = require("@nomicfoundation/hardhat-network-helpers"); +const { + setBalance, + setStorageAt, +} = require("@nomicfoundation/hardhat-network-helpers"); const { isCI } = require("../helpers"); const { shouldBehaveLikeGovernable } = require("../behaviour/governable"); @@ -57,7 +60,7 @@ describe("Unit test: Native SSV Staking Strategy", function () { ); const tx = { to: nativeStakingSSVStrategy.address, - value: parseEther("2", "ether"), + value: parseEther("2"), }; await expect(signer.sendTransaction(tx)).to.be.revertedWith( @@ -153,30 +156,6 @@ describe("Unit test: Native SSV Staking Strategy", function () { .to.emit(nativeStakingSSVStrategy, "FuseIntervalUpdated") .withArgs(fuseStartBn, fuseEndBn); }); - - it("Only accounting governor can call accounting", async () => {}); - - it("Only governor can change the accounting governor", async () => { - const { nativeStakingSSVStrategy, strategist } = fixture; - - await expect( - nativeStakingSSVStrategy - .connect(strategist) - .setAccountingGovernor(strategist.address) - ).to.be.revertedWith("Caller is not the Governor"); - }); - - it("Change the accounting governor", async () => { - const { nativeStakingSSVStrategy, governor, strategist } = fixture; - - const tx = await nativeStakingSSVStrategy - .connect(governor) - .setAccountingGovernor(strategist.address); - - await expect(tx) - .to.emit(nativeStakingSSVStrategy, "AccountingGovernorChanged") - .withArgs(strategist.address); - }); }); describe("Accounting", function () { @@ -466,24 +445,18 @@ describe("Unit test: Native SSV Staking Strategy", function () { } consensus rewards, ${expectedValidatorsFullWithdrawals} withdraws${ fuseBlown ? ", fuse blown" : "" }${slashDetected ? ", slash detected" : ""}.`, async () => { - const { nativeStakingSSVStrategy, governor, strategist } = fixture; + const { nativeStakingSSVStrategy, governor } = fixture; // setup state if (ethBalance.gt(0)) { await setBalance(nativeStakingSSVStrategy.address, ethBalance); } - // pause, so manuallyFixAccounting can be called - await nativeStakingSSVStrategy.connect(strategist).pause(); - await nativeStakingSSVStrategy - .connect(governor) - .manuallyFixAccounting( - 30, // activeDepositedValidators - 0, //_ethToWeth - 0, //_wethToBeSentToVault - previousConsensusRewards, //_consensusRewards - parseEther("3000"), //_ethThresholdCheck - parseEther("3000") //_wethThresholdCheck - ); + + await setActiveDepositedValidators(30, nativeStakingSSVStrategy); + await setConsensusRewards( + previousConsensusRewards, + nativeStakingSSVStrategy + ); // check accounting values const tx = await nativeStakingSSVStrategy @@ -541,124 +514,214 @@ describe("Unit test: Native SSV Staking Strategy", function () { } }); - it("Only accounting governor is allowed to manually fix accounting", async () => { - const { nativeStakingSSVStrategy, strategist } = fixture; + it("Only strategist is allowed to manually fix accounting", async () => { + const { nativeStakingSSVStrategy, strategist, governor } = fixture; await nativeStakingSSVStrategy.connect(strategist).pause(); // unit test fixture sets OUSD governor as accounting governor await expect( - nativeStakingSSVStrategy.connect(strategist).manuallyFixAccounting( - 10, //_activeDepositedValidators - parseEther("2", "ether"), //_ethToWeth - parseEther("2", "ether"), //_wethToBeSentToVault - parseEther("2", "ether"), //_consensusRewards - parseEther("0", "ether"), //_ethThresholdCheck - parseEther("0", "ether") //_wethThresholdCheck + nativeStakingSSVStrategy.connect(governor).manuallyFixAccounting( + 1, //_validatorsDelta + parseEther("2"), //_consensusRewardsDelta + parseEther("2") //_wethToVault ) - ).to.be.revertedWith("Caller is not the Accounting Governor"); + ).to.be.revertedWith("Caller is not the Strategist"); }); it("Accounting needs to be paused in order to call fix accounting function", async () => { - const { nativeStakingSSVStrategy, governor } = fixture; + const { nativeStakingSSVStrategy, strategist } = fixture; // unit test fixture sets OUSD governor as accounting governor await expect( - nativeStakingSSVStrategy.connect(governor).manuallyFixAccounting( - 10, //_activeDepositedValidators - parseEther("2", "ether"), //_ethToWeth - parseEther("2", "ether"), //_wethToBeSentToVault - parseEther("2", "ether"), //_beaconChainRewardWETH - parseEther("1", "ether"), //_ethThresholdCheck - parseEther("0", "ether") //_wethThresholdCheck + nativeStakingSSVStrategy.connect(strategist).manuallyFixAccounting( + 1, //_validatorsDelta + parseEther("2"), //_consensusRewardsDelta + parseEther("2") //_wethToVault ) ).to.be.revertedWith("Pausable: not paused"); }); - it("Should not execute manual recovery if eth threshold reached", async () => { - const { nativeStakingSSVStrategy, strategist, governor, josh, weth } = - fixture; - - await setBalance( - nativeStakingSSVStrategy.address, - parseEther("6", "ether") - ); - await weth - .connect(josh) - .transfer(nativeStakingSSVStrategy.address, parseEther("5", "ether")); + it("Validators delta should not be <-4 or >4 for fix accounting function", async () => { + const { nativeStakingSSVStrategy, strategist } = fixture; await nativeStakingSSVStrategy.connect(strategist).pause(); + await expect( - nativeStakingSSVStrategy.connect(governor).manuallyFixAccounting( - 10, //_activeDepositedValidators - parseEther("2", "ether"), //_ethToWeth - parseEther("2", "ether"), //_wethToBeSentToVault - parseEther("2", "ether"), //_beaconChainRewardWETH - parseEther("5", "ether"), //_ethThresholdCheck - parseEther("5", "ether") //_wethThresholdCheck + nativeStakingSSVStrategy.connect(strategist).manuallyFixAccounting( + -4, //_validatorsDelta + 0, //_consensusRewardsDelta + 0 //_wethToVault ) - ).to.be.revertedWith("over accounting threshold"); + ).to.be.revertedWith("invalid validatorsDelta"); + + await expect( + nativeStakingSSVStrategy.connect(strategist).manuallyFixAccounting( + 4, //_validatorsDelta + 0, //_consensusRewardsDelta + 0 //_wethToVault + ) + ).to.be.revertedWith("invalid validatorsDelta"); }); - it("Should not execute manual recovery if weth threshold reached", async () => { - const { nativeStakingSSVStrategy, strategist, governor, josh, weth } = - fixture; + it("Consensus rewards delta should not be <-333> and >333 for fix accounting function", async () => { + const { nativeStakingSSVStrategy, strategist } = fixture; - await setBalance( - nativeStakingSSVStrategy.address, - parseEther("5", "ether") - ); - await weth - .connect(josh) - .transfer(nativeStakingSSVStrategy.address, parseEther("6", "ether")); + await nativeStakingSSVStrategy.connect(strategist).pause(); + + await expect( + nativeStakingSSVStrategy.connect(strategist).manuallyFixAccounting( + 0, //_validatorsDelta + parseEther("-333"), //_consensusRewardsDelta + 0 //_wethToVault + ) + ).to.be.revertedWith("invalid consensusRewardsDelta"); + + await expect( + nativeStakingSSVStrategy.connect(strategist).manuallyFixAccounting( + 0, //_validatorsDelta + parseEther("333"), //_consensusRewardsDelta + 0 //_wethToVault + ) + ).to.be.revertedWith("invalid consensusRewardsDelta"); + }); + + it("WETH to Vault amount should not be >32 for fix accounting function", async () => { + const { nativeStakingSSVStrategy, strategist } = fixture; await nativeStakingSSVStrategy.connect(strategist).pause(); + await expect( - nativeStakingSSVStrategy.connect(governor).manuallyFixAccounting( - 10, //_activeDepositedValidators - parseEther("2", "ether"), //_ethToWeth - parseEther("2", "ether"), //_wethToBeSentToVault - parseEther("2", "ether"), //_beaconChainRewardWETH - parseEther("5", "ether"), //_ethThresholdCheck - parseEther("5", "ether") //_wethThresholdCheck + nativeStakingSSVStrategy.connect(strategist).manuallyFixAccounting( + 0, //_validatorsDelta + 0, //_consensusRewardsDelta + parseEther("33") //_wethToVault ) - ).to.be.revertedWith("over accounting threshold"); + ).to.be.revertedWith("invalid wethToVaultAmount"); }); - it("Should allow 5/8 governor to recover paused contract and correct the accounting state", async () => { - const { nativeStakingSSVStrategy, strategist, governor, josh, weth } = - fixture; + describe("Should allow strategist to recover paused contract", async () => { + for (const validatorsDelta of [-3, -2, -1, 0, 1, 2, 3]) { + it(`by changing validators by ${validatorsDelta}`, async () => { + const { nativeStakingSSVStrategy, strategist } = fixture; - await setBalance( - nativeStakingSSVStrategy.address, - parseEther("5", "ether") - ); - await weth - .connect(josh) - .transfer(nativeStakingSSVStrategy.address, parseEther("5", "ether")); + await setActiveDepositedValidators(10, nativeStakingSSVStrategy); - await nativeStakingSSVStrategy.connect(strategist).pause(); - // unit test fixture sets OUSD governor as accounting governor - const tx = await nativeStakingSSVStrategy - .connect(governor) - .manuallyFixAccounting( - 3, //_activeDepositedValidators - parseEther("2.1", "ether"), //_ethToWeth - parseEther("2.2", "ether"), //_wethToBeSentToVault - parseEther("2.3", "ether"), //_beaconChainRewardWETH - parseEther("5", "ether"), //_ethThresholdCheck - parseEther("5", "ether") //_wethThresholdCheck - ); + await nativeStakingSSVStrategy.connect(strategist).pause(); + const activeDepositedValidatorsBefore = + await nativeStakingSSVStrategy.activeDepositedValidators(); - expect(tx) - .to.emit(nativeStakingSSVStrategy, "AccountingManuallyFixed") - .withArgs( - 0, // oldActiveDepositedValidators - 3, // activeDepositedValidators - 0, // oldBeaconChainRewardWETH - parseEther("2.3"), // beaconChainRewardWETH - parseEther("2.1"), // ethToWeth - parseEther("2.2") // wethToBeSentToVault - ); + const tx = await nativeStakingSSVStrategy + .connect(strategist) + .manuallyFixAccounting(validatorsDelta, 0, 0); + + expect(tx) + .to.emit(nativeStakingSSVStrategy, "AccountingManuallyFixed") + .withArgs(validatorsDelta, 0, 0); + + expect( + await nativeStakingSSVStrategy.activeDepositedValidators() + ).to.equal( + activeDepositedValidatorsBefore.add(validatorsDelta), + "active deposited validators not updated" + ); + }); + } + + for (const delta of [-332, -320, -1, 0, 1, 320, 332]) { + it(`by changing consensus rewards by ${delta}`, async () => { + const { nativeStakingSSVStrategy, strategist } = fixture; + + await setBalance(nativeStakingSSVStrategy.address, parseEther("670")); + await setConsensusRewards( + parseEther("336"), + nativeStakingSSVStrategy + ); + await setActiveDepositedValidators(10000, nativeStakingSSVStrategy); + + await nativeStakingSSVStrategy.connect(strategist).pause(); + const consensusRewardsDelta = parseEther(delta.toString()); + + const tx = await nativeStakingSSVStrategy + .connect(strategist) + .manuallyFixAccounting(0, consensusRewardsDelta, 0); + + expect(tx) + .to.emit(nativeStakingSSVStrategy, "AccountingManuallyFixed") + .withArgs(0, consensusRewardsDelta, 0); + + expect(await nativeStakingSSVStrategy.consensusRewards()).to.equal( + await nativeStakingSSVStrategy.provider.getBalance( + nativeStakingSSVStrategy.address + ), + "consensus rewards matches eth balance" + ); + }); + } + + it("by sending WETH to vault", async () => { + const { nativeStakingSSVStrategy, strategist, josh, weth } = fixture; + + await weth + .connect(josh) + .transfer(nativeStakingSSVStrategy.address, parseEther("100")); + + for (const wethInEthers of [0, 1, 26, 32]) { + await nativeStakingSSVStrategy.connect(strategist).pause(); + const wethBefore = await weth.balanceOf( + nativeStakingSSVStrategy.address + ); + const wethToVault = parseEther(wethInEthers.toString()); + + const tx = await nativeStakingSSVStrategy + .connect(strategist) + .manuallyFixAccounting(0, 0, wethToVault); + + expect(tx) + .to.emit(nativeStakingSSVStrategy, "AccountingManuallyFixed") + .withArgs(0, 0, wethToVault); + + expect( + await weth.balanceOf(nativeStakingSSVStrategy.address) + ).to.equal( + wethBefore.sub(wethToVault), + "consensus rewards not updated" + ); + + expect(await nativeStakingSSVStrategy.consensusRewards()).to.equal( + await nativeStakingSSVStrategy.provider.getBalance( + nativeStakingSSVStrategy.address + ), + "consensus rewards matches eth balance" + ); + } + }); + + it("by changing all three manuallyFixAccounting delta values", async () => { + const { nativeStakingSSVStrategy, strategist, josh, weth } = fixture; + + await setBalance(nativeStakingSSVStrategy.address, parseEther("5")); + await weth + .connect(josh) + .transfer(nativeStakingSSVStrategy.address, parseEther("5")); + + await nativeStakingSSVStrategy.connect(strategist).pause(); + // unit test fixture sets OUSD governor as accounting governor + const tx = await nativeStakingSSVStrategy + .connect(strategist) + .manuallyFixAccounting( + 1, //_validatorsDelta + parseEther("2.3"), //_consensusRewardsDeltaDelta + parseEther("2.2") //_wethToVault + ); + + expect(tx) + .to.emit(nativeStakingSSVStrategy, "AccountingManuallyFixed") + .withArgs( + 1, // validatorsDelta + parseEther("2.3"), // consensusRewards + parseEther("2.2") // wethToVault + ); + }); }); }); @@ -747,8 +810,7 @@ describe("Unit test: Native SSV Staking Strategy", function () { describe(`given ${testCase.feeAccumulatorEth} execution rewards, ${testCase.consensusRewards} consensus rewards, ${testCase.deposits} deposits and ${nrOfActiveDepositedValidators} validators`, () => { beforeEach(async () => { - const { nativeStakingSSVStrategy, governor, strategist, weth, josh } = - fixture; + const { nativeStakingSSVStrategy, governor, weth, josh } = fixture; const feeAccumulatorAddress = await nativeStakingSSVStrategy.FEE_ACCUMULATOR_ADDRESS(); @@ -772,17 +834,11 @@ describe("Unit test: Native SSV Staking Strategy", function () { } // set the correct amount of staked validators - await nativeStakingSSVStrategy.connect(strategist).pause(); - await nativeStakingSSVStrategy - .connect(governor) - .manuallyFixAccounting( - nrOfActiveDepositedValidators, // activeDepositedValidators - parseEther("0"), //_ethToWeth - parseEther("0"), //_wethToBeSentToVault - consensusRewards, //_consensusRewards - parseEther("3000"), //_ethThresholdCheck - parseEther("3000") //_wethThresholdCheck - ); + await setActiveDepositedValidators( + nrOfActiveDepositedValidators, + nativeStakingSSVStrategy + ); + await setConsensusRewards(consensusRewards, nativeStakingSSVStrategy); // run the accounting await nativeStakingSSVStrategy.connect(governor).doAccounting(); @@ -827,3 +883,27 @@ describe("Unit test: Native SSV Staking Strategy", function () { } }); }); + +const setActiveDepositedValidators = async ( + validators, + nativeStakingSSVStrategy +) => { + await setStorageAt(nativeStakingSSVStrategy.address, 52, validators); + + expect(await nativeStakingSSVStrategy.activeDepositedValidators()).to.equal( + validators, + "validators no set properly" + ); +}; + +const setConsensusRewards = async ( + consensusRewards, + nativeStakingSSVStrategy +) => { + await setStorageAt(nativeStakingSSVStrategy.address, 104, consensusRewards); + + expect(await nativeStakingSSVStrategy.consensusRewards()).to.equal( + consensusRewards, + "consensusRewards no set properly" + ); +}; From da6a7b55c10a9f1d7d8aad82f858b9e08547e845 Mon Sep 17 00:00:00 2001 From: Domen Grabec Date: Mon, 29 Apr 2024 23:56:14 +0200 Subject: [PATCH 023/273] fix fork tests --- contracts/hardhat.config.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/hardhat.config.js b/contracts/hardhat.config.js index 3e571382d4..c09b01ee34 100644 --- a/contracts/hardhat.config.js +++ b/contracts/hardhat.config.js @@ -180,13 +180,13 @@ module.exports = { process.env.FORK === "true" ? isHoleskyFork ? HOLESKY_DEPLOYER - : MAINNET_DEPLOYER + : MAINNET_GOVERNOR : 1, hardhat: process.env.FORK === "true" ? isHoleskyFork ? HOLESKY_DEPLOYER - : MAINNET_DEPLOYER + : MAINNET_GOVERNOR : 1, mainnet: MAINNET_GOVERNOR, holesky: HOLESKY_DEPLOYER, // on Holesky the deployer is also the governor From 8f7d3d534392956b60a0d421c3acac1c4ddd022e Mon Sep 17 00:00:00 2001 From: Domen Grabec Date: Mon, 6 May 2024 14:29:08 +0200 Subject: [PATCH 024/273] prettier --- contracts/test/_fixture.js | 1 - 1 file changed, 1 deletion(-) diff --git a/contracts/test/_fixture.js b/contracts/test/_fixture.js index aaa3bfea13..4e3f722398 100644 --- a/contracts/test/_fixture.js +++ b/contracts/test/_fixture.js @@ -1612,7 +1612,6 @@ async function nativeStakingSSVStrategyFixture() { await nativeStakingSSVStrategy .connect(sGovernor) .setRegistrator(governorAddr); - } return fixture; From 967fe497fb554143b592656a65338198ba59ac63 Mon Sep 17 00:00:00 2001 From: Domen Grabec Date: Mon, 6 May 2024 14:29:13 +0200 Subject: [PATCH 025/273] fix unit test --- contracts/test/strategies/nativeSSVStaking.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/test/strategies/nativeSSVStaking.js b/contracts/test/strategies/nativeSSVStaking.js index 1fd21a0ae6..7eccc686c2 100644 --- a/contracts/test/strategies/nativeSSVStaking.js +++ b/contracts/test/strategies/nativeSSVStaking.js @@ -64,7 +64,7 @@ describe("Unit test: Native SSV Staking Strategy", function () { }; await expect(signer.sendTransaction(tx)).to.be.revertedWith( - "eth not sent from Fee Accumulator" + "eth not from allowed contracts" ); }); From 1af324dc0049e9b650c8f208d2c0a6aa1cc5583d Mon Sep 17 00:00:00 2001 From: Nick Addison Date: Tue, 7 May 2024 22:09:26 +1000 Subject: [PATCH 026/273] mainnet native staking fork tests (#2037) * manuallyFixAccounting now uses delta values and only callable by the strategist manuallyFixAccounting calls doAccounting to check the fuse is still not blown Removed accountingGovernor * Added pauseOnFail param to internal _doAccounting Increased the allowed delta values of manuallyFixAccounting * ran prettier * Added Defender Relayer for validator registrator Added ssv utils to get cluster data Added native staking fork tests * Removed now redundant IWETH9 import * moved more logic into native staking fixture * Removed unused imports * fix native staking unit tests * Fail accounting if activeDepositedValidators < fullyWithdrawnValidators Changed Harvester to transfer WETH to dripper Added more mainnet fork tests for native staking * Updated the OETH value flows * Added governable Hardhat tasks Created a resolveContract util * deconstruct params for Hardhat tasks * WIP Hardhat tasks for validator registration * Added depositSSV HH task * Updated OETH contract dependency diagram * Update to diagrams * mini fixes * fix bug and minor test improvement * update yarn fulie * unify the holesky and the mainnet fork tests * prettier * re-deploy holesky native staking strategy (#2046) * test updates * also re-deploy the harvester * upgrade harvester as well * fix test * fix upgrade script and correct the bug in deploy actions * Deployed new Native Staking strategy including the proxy * Added Hardhat tasks for generic strategy functions * remove nativeStakingSSVStrategyProxy from js addresses file --------- Co-authored-by: Domen Grabec --- contracts/.eslintrc.js | 4 +- contracts/contracts/harvest/BaseHarvester.sol | 25 +- .../NativeStakingSSVStrategy.sol | 2 - .../strategies/NativeStaking/README.md | 4 + .../NativeStaking/ValidatorAccountant.sol | 31 +- contracts/deploy/deployActions.js | 34 +- .../deploy/holesky/004_upgrade_strategy.js | 41 + contracts/deploy/holesky/005_new_harvester.js | 61 ++ .../deploy/mainnet/091_native_ssv_staking.js | 24 + .../deployments/holesky/.migrations.json | 4 +- .../deployments/holesky/FeeAccumulator.json | 34 +- .../NativeStakingFeeAccumulatorProxy.json | 32 +- .../holesky/NativeStakingSSVStrategy.json | 243 ++--- .../NativeStakingSSVStrategyProxy.json | 32 +- .../deployments/holesky/OETHHarvester.json | 44 +- .../5e7101910c63b5cb160cf1f36fa86058.json | 44 + .../66dbdc9fbde8f1c7cc59f29d272eb661.json | 674 +++++++++++++ contracts/docs/FeeAccumulatorHierarchy.svg | 33 + contracts/docs/generate.sh | 3 +- contracts/docs/plantuml/oethContracts.png | Bin 59071 -> 79801 bytes contracts/docs/plantuml/oethContracts.puml | 204 ++-- .../oethValueFlows-native-staking.png | Bin 0 -> 179573 bytes contracts/docs/plantuml/oethValueFlows.png | Bin 547985 -> 491809 bytes contracts/docs/plantuml/oethValueFlows.puml | 276 ++---- contracts/fork-test.sh | 2 +- contracts/hardhat.config.js | 3 - contracts/package.json | 2 + .../deploy/verifySimpleOETHDeployment.sh | 4 +- contracts/tasks/curve.js | 2 +- contracts/tasks/governable.js | 45 + contracts/tasks/proxy.js | 4 +- contracts/tasks/ssv.js | 56 +- contracts/tasks/strategy.js | 55 ++ contracts/tasks/tasks.js | 107 +- contracts/tasks/tokens.js | 17 +- contracts/tasks/validator.js | 542 ++++++++++ contracts/tasks/vault.js | 38 +- contracts/test/_fixture.js | 35 +- contracts/test/_global-hooks.js | 5 +- contracts/test/behaviour/ssvStrategy.js | 432 ++++++++ contracts/test/helpers.js | 7 +- contracts/test/strategies/nativeSSVStaking.js | 2 +- .../strategies/nativeSsvStaking.fork-test.js | 35 + .../nativeSsvStaking.holesky-fork-test.js | 42 + .../nativeSsvStaking.holesky.fork-test.js | 147 --- .../test/vault/collateral-swaps.fork-test.js | 2 +- contracts/utils/addresses.js | 11 +- contracts/utils/assets.js | 37 - contracts/utils/resolvers.js | 84 ++ contracts/utils/signers.js | 4 +- contracts/utils/ssv.js | 172 ++++ contracts/yarn.lock | 922 +++++++++++++++++- 52 files changed, 3826 insertions(+), 837 deletions(-) create mode 100644 contracts/deploy/holesky/004_upgrade_strategy.js create mode 100644 contracts/deploy/holesky/005_new_harvester.js create mode 100644 contracts/deployments/holesky/solcInputs/5e7101910c63b5cb160cf1f36fa86058.json create mode 100644 contracts/deployments/holesky/solcInputs/66dbdc9fbde8f1c7cc59f29d272eb661.json create mode 100644 contracts/docs/FeeAccumulatorHierarchy.svg create mode 100644 contracts/docs/plantuml/oethValueFlows-native-staking.png mode change 100644 => 100755 contracts/scripts/deploy/verifySimpleOETHDeployment.sh create mode 100644 contracts/tasks/governable.js create mode 100644 contracts/tasks/strategy.js create mode 100644 contracts/tasks/validator.js create mode 100644 contracts/test/behaviour/ssvStrategy.js create mode 100644 contracts/test/strategies/nativeSsvStaking.fork-test.js create mode 100644 contracts/test/strategies/nativeSsvStaking.holesky-fork-test.js delete mode 100644 contracts/test/strategies/nativeSsvStaking.holesky.fork-test.js delete mode 100644 contracts/utils/assets.js create mode 100644 contracts/utils/resolvers.js create mode 100644 contracts/utils/ssv.js diff --git a/contracts/.eslintrc.js b/contracts/.eslintrc.js index 854b6ac0f7..d4d47d89a3 100644 --- a/contracts/.eslintrc.js +++ b/contracts/.eslintrc.js @@ -18,5 +18,7 @@ module.exports = { getNamedAccounts: "readable", hre: "readable", }, - rules: {}, + rules: { + "no-constant-condition": ["error", { checkLoops: false }], + }, }; diff --git a/contracts/contracts/harvest/BaseHarvester.sol b/contracts/contracts/harvest/BaseHarvester.sol index c14ab2df0f..ebd804be1c 100644 --- a/contracts/contracts/harvest/BaseHarvester.sol +++ b/contracts/contracts/harvest/BaseHarvester.sol @@ -477,6 +477,23 @@ abstract contract BaseHarvester is Governable { address _rewardTo, IOracle _priceProvider ) internal virtual { + uint256 balance = IERC20(_swapToken).balanceOf(address(this)); + + // No need to swap if the reward token is the base token. eg USDT or WETH. + // There is also no limit on the transfer. Everything in the harvester will be transferred + // to the Dripper regardless of the liquidationLimit config. + if (_swapToken == baseTokenAddress) { + IERC20(_swapToken).safeTransfer(rewardProceedsAddress, balance); + // currently not paying the farmer any rewards as there is no swap + emit RewardProceedsTransferred( + baseTokenAddress, + address(0), + balance, + 0 + ); + return; + } + RewardTokenConfig memory tokenConfig = rewardTokenConfigs[_swapToken]; /* This will trigger a return when reward token configuration has not yet been set @@ -487,8 +504,6 @@ abstract contract BaseHarvester is Governable { return; } - uint256 balance = IERC20(_swapToken).balanceOf(address(this)); - if (balance == 0) { return; } @@ -548,14 +563,14 @@ abstract contract BaseHarvester is Governable { tokenConfig.harvestRewardBps, 1e4 ); - uint256 protcolYield = baseTokenBalance - farmerFee; + uint256 protocolYield = baseTokenBalance - farmerFee; - baseToken.safeTransfer(rewardProceedsAddress, protcolYield); + baseToken.safeTransfer(rewardProceedsAddress, protocolYield); baseToken.safeTransfer(_rewardTo, farmerFee); emit RewardProceedsTransferred( baseTokenAddress, _rewardTo, - protcolYield, + protocolYield, farmerFee ); } diff --git a/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol b/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol index 79629473cd..55ec51a306 100644 --- a/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol +++ b/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol @@ -5,11 +5,9 @@ import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import { InitializableAbstractStrategy } from "../../utils/InitializableAbstractStrategy.sol"; -import { ISSVNetwork, Cluster } from "../../interfaces/ISSVNetwork.sol"; import { IWETH9 } from "../../interfaces/IWETH9.sol"; import { FeeAccumulator } from "./FeeAccumulator.sol"; import { ValidatorAccountant } from "./ValidatorAccountant.sol"; -import { Cluster } from "../../interfaces/ISSVNetwork.sol"; struct ValidatorStakeData { bytes pubkey; diff --git a/contracts/contracts/strategies/NativeStaking/README.md b/contracts/contracts/strategies/NativeStaking/README.md index 13e280eb9b..00c9a7bd9b 100644 --- a/contracts/contracts/strategies/NativeStaking/README.md +++ b/contracts/contracts/strategies/NativeStaking/README.md @@ -16,6 +16,10 @@ ## Fee Accumulator +### Hierarchy + +![Fee Accumulator Hierarchy](../../../docs/FeeAccumulatorHierarchy.svg) + ### Squashed ![Fee Accumulator Squashed](../../../docs/FeeAccumulatorSquashed.svg) diff --git a/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol b/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol index 6edcf44f69..b94d3d8942 100644 --- a/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol +++ b/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol @@ -1,7 +1,6 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import { Pausable } from "@openzeppelin/contracts/security/Pausable.sol"; import { ValidatorRegistrator } from "./ValidatorRegistrator.sol"; import { IWETH9 } from "../../interfaces/IWETH9.sol"; @@ -108,12 +107,7 @@ abstract contract ValidatorAccountant is ValidatorRegistrator { returns (bool accountingValid) { if (address(this).balance < consensusRewards) { - // pause if not already - if (pauseOnFail) { - _pause(); - } - // fail the accounting - return false; + return _failAccounting(pauseOnFail); } // Calculate all the new ETH that has been swept to the contract since the last accounting @@ -123,6 +117,9 @@ abstract contract ValidatorAccountant is ValidatorRegistrator { // send the ETH that is from fully withdrawn validators to the Vault if (newSweptETH >= MAX_STAKE) { uint256 fullyWithdrawnValidators = newSweptETH / MAX_STAKE; + if (activeDepositedValidators < fullyWithdrawnValidators) { + return _failAccounting(pauseOnFail); + } activeDepositedValidators -= fullyWithdrawnValidators; uint256 wethToVault = MAX_STAKE * fullyWithdrawnValidators; @@ -164,13 +161,21 @@ abstract contract ValidatorAccountant is ValidatorRegistrator { } // Oh no... Fuse is blown. The Strategist needs to adjust the accounting values. else { - // pause if not already - if (pauseOnFail) { - _pause(); - } - // fail the accounting - accountingValid = false; + return _failAccounting(pauseOnFail); + } + } + + /// @dev pause any further accounting if required and return false + function _failAccounting(bool pauseOnFail) + internal + returns (bool accountingValid) + { + // pause if not already + if (pauseOnFail) { + _pause(); } + // fail the accounting + accountingValid = false; } /// @notice Allow the Strategist to fix the accounting of this strategy and unpause. diff --git a/contracts/deploy/deployActions.js b/contracts/deploy/deployActions.js index 88dab9238c..625f4c1840 100644 --- a/contracts/deploy/deployActions.js +++ b/contracts/deploy/deployActions.js @@ -543,11 +543,26 @@ const deployOUSDHarvester = async (ousdDripper) => { return dHarvesterProxy; }; +const upgradeOETHHarvester = async () => { + const assetAddresses = await getAssetAddresses(deployments); + const cOETHVaultProxy = await ethers.getContract("OETHVaultProxy"); + const cOETHHarvesterProxy = await ethers.getContract("OETHHarvesterProxy"); + + const dOETHHarvester = await deployWithConfirmation("OETHHarvester", [ + cOETHVaultProxy.address, + assetAddresses.WETH, + ]); + + await withConfirmation(cOETHHarvesterProxy.upgradeTo(dOETHHarvester.address)); + + log("Upgraded OETHHarvesterProxy"); + return cOETHHarvesterProxy; +}; + const deployOETHHarvester = async (oethDripper) => { const assetAddresses = await getAssetAddresses(deployments); const { governorAddr } = await getNamedAccounts(); const sGovernor = await ethers.provider.getSigner(governorAddr); - const cVaultProxy = await ethers.getContract("VaultProxy"); const cOETHVaultProxy = await ethers.getContract("OETHVaultProxy"); const dOETHHarvesterProxy = await deployWithConfirmation( @@ -568,11 +583,13 @@ const deployOETHHarvester = async (oethDripper) => { ); await withConfirmation( - cOETHHarvesterProxy["initialize(address,address,bytes)"]( - dOETHHarvester.address, - governorAddr, - [] - ) + // prettier-ignore + cOETHHarvesterProxy + .connect(sGovernor)["initialize(address,address,bytes)"]( + dOETHHarvester.address, + governorAddr, + [] + ) ); log("Initialized OETHHarvesterProxy"); @@ -581,11 +598,11 @@ const deployOETHHarvester = async (oethDripper) => { cOETHHarvester .connect(sGovernor) .setRewardProceedsAddress( - isMainnet || isHolesky ? oethDripper.address : cVaultProxy.address + isMainnet || isHolesky ? oethDripper.address : cOETHVaultProxy.address ) ); - return dOETHHarvesterProxy; + return cOETHHarvester; }; /** @@ -1509,6 +1526,7 @@ module.exports = { deployHarvesters, deployOETHHarvester, deployOUSDHarvester, + upgradeOETHHarvester, configureVault, configureOETHVault, configureStrategies, diff --git a/contracts/deploy/holesky/004_upgrade_strategy.js b/contracts/deploy/holesky/004_upgrade_strategy.js new file mode 100644 index 0000000000..2636023947 --- /dev/null +++ b/contracts/deploy/holesky/004_upgrade_strategy.js @@ -0,0 +1,41 @@ +const { + upgradeNativeStakingSSVStrategy, + upgradeOETHHarvester, +} = require("../deployActions"); +const { withConfirmation } = require("../../utils/deploy"); + +const mainExport = async () => { + console.log("Running 004 deployment on Holesky..."); + + console.log("Upgrading native staking strategy"); + await upgradeNativeStakingSSVStrategy(); + + console.log("deploying harvester"); + const cOETHDripperProxy = await ethers.getContract("OETHDripperProxy"); + const cOETHHarvester = await upgradeOETHHarvester(cOETHDripperProxy.address); + + const strategyProxy = await ethers.getContract( + "NativeStakingSSVStrategyProxy" + ); + const cStrategy = await ethers.getContractAt( + "NativeStakingSSVStrategy", + strategyProxy.address + ); + + console.log("configuring harvester and the strategy"); + await withConfirmation( + cOETHHarvester.setSupportedStrategy(strategyProxy.address, true) + ); + + await withConfirmation(cStrategy.setHarvesterAddress(cOETHHarvester.address)); + + console.log("Running 004 deployment done"); + return true; +}; + +mainExport.id = "004_upgrade_strategy"; +mainExport.tags = []; +mainExport.dependencies = []; +mainExport.skip = () => false; + +module.exports = mainExport; diff --git a/contracts/deploy/holesky/005_new_harvester.js b/contracts/deploy/holesky/005_new_harvester.js new file mode 100644 index 0000000000..0793c46ec2 --- /dev/null +++ b/contracts/deploy/holesky/005_new_harvester.js @@ -0,0 +1,61 @@ +const { parseEther } = require("ethers/lib/utils"); + +const { deployNativeStakingSSVStrategy } = require("../deployActions"); +const { withConfirmation } = require("../../utils/deploy"); +const { resolveContract } = require("../../utils/resolvers"); + +const mainExport = async () => { + console.log("Running 005 deployment on Holesky..."); + + console.log("Deploying a new Native Staking strategy and proxy"); + + console.log("Deploying Native Staking"); + const nativeStakingSSVStrategy = await deployNativeStakingSSVStrategy(); + + const { governorAddr } = await getNamedAccounts(); + const sGovernor = await ethers.provider.getSigner(governorAddr); + + const cOETHHarvester = await resolveContract( + "OETHHarvesterProxy", + "OETHHarvester" + ); + const cVault = await resolveContract("OETHVaultProxy", "VaultAdmin"); + + await withConfirmation( + nativeStakingSSVStrategy + .connect(sGovernor) + .setHarvesterAddress(cOETHHarvester.address) + ); + + console.log("configuring harvester and the strategy"); + await withConfirmation( + cOETHHarvester + .connect(sGovernor) + .setSupportedStrategy(nativeStakingSSVStrategy.address, true) + ); + + await withConfirmation( + cVault.connect(sGovernor).approveStrategy(nativeStakingSSVStrategy.address) + ); + + await withConfirmation( + nativeStakingSSVStrategy.connect(sGovernor).setRegistrator(governorAddr) + ); + + const fuseStartBn = parseEther("21.6"); + const fuseEndBn = parseEther("25.6"); + + await nativeStakingSSVStrategy + .connect(sGovernor) + .setFuseInterval(fuseStartBn, fuseEndBn); + + console.log("Running 005 deployment done"); + return true; +}; + +mainExport.id = "005_deploy_new_harvester"; +mainExport.tags = []; +mainExport.dependencies = []; +mainExport.skip = () => false; + +module.exports = mainExport; diff --git a/contracts/deploy/mainnet/091_native_ssv_staking.js b/contracts/deploy/mainnet/091_native_ssv_staking.js index 817a620993..689853af98 100644 --- a/contracts/deploy/mainnet/091_native_ssv_staking.js +++ b/contracts/deploy/mainnet/091_native_ssv_staking.js @@ -114,11 +114,23 @@ module.exports = deploymentWithGovernanceProposal( // 7. Safe approve SSV token spending await cStrategy.connect(sDeployer).safeApproveAllTokens(); + // 8. Deploy Harvester + const cOETHHarvesterProxy = await ethers.getContract("OETHHarvesterProxy"); + await deployWithConfirmation("OETHHarvester", [ + cVaultProxy.address, + addresses.mainnet.WETH, + ]); + const dOETHHarvesterImpl = await ethers.getContract("OETHHarvester"); + console.log( "Native Staking SSV Strategy address: ", cStrategyProxy.address ); console.log("Fee accumulator address: ", cFeeAccumulator.address); + console.log( + "New OETHHarvester implementation address: ", + dOETHHarvesterImpl.address + ); // Governance Actions // ---------------- @@ -152,6 +164,18 @@ module.exports = deploymentWithGovernanceProposal( ethers.utils.parseEther("25.6"), ], }, + // 5. set validator registrator + { + contract: cStrategy, + signature: "setRegistrator(address)", + args: [addresses.mainnet.validatorRegistrator], + }, + // 6. Upgrade the OETH Harvester + { + contract: cOETHHarvesterProxy, + signature: "upgradeTo(address)", + args: [dOETHHarvesterImpl.address], + }, ], }; } diff --git a/contracts/deployments/holesky/.migrations.json b/contracts/deployments/holesky/.migrations.json index d45ad24364..7e8f3cdbad 100644 --- a/contracts/deployments/holesky/.migrations.json +++ b/contracts/deployments/holesky/.migrations.json @@ -1,5 +1,7 @@ { "001_core": 1714168010, "002_upgrade_strategy": 1714233842, - "003_deposit_to_native_strategy": 1714307581 + "003_deposit_to_native_strategy": 1714307581, + "004_upgrade_strategy": 1714944723, + "005_deploy_new_harvester": 1714998707 } \ No newline at end of file diff --git a/contracts/deployments/holesky/FeeAccumulator.json b/contracts/deployments/holesky/FeeAccumulator.json index 863cc1ba96..dbee10dcb3 100644 --- a/contracts/deployments/holesky/FeeAccumulator.json +++ b/contracts/deployments/holesky/FeeAccumulator.json @@ -1,5 +1,5 @@ { - "address": "0x79681d3f14a0068479420eE5fDdF59B62301f810", + "address": "0xa3f54f30cDefaBd9527FF11ad51Ba20c3b77ffDD", "abi": [ { "inputs": [ @@ -123,42 +123,42 @@ "type": "function" } ], - "transactionHash": "0x19762cf6f04f946ee9af7a2b33ef576781afc364bf031afe6319b03d0c531a6d", + "transactionHash": "0xa7a9c1f0210822c01adc6baec616c8b15880fa006bfb44e2fd11e8eed5c4d79e", "receipt": { "to": null, "from": "0x1b94CA50D3Ad9f8368851F8526132272d1a5028C", - "contractAddress": "0x79681d3f14a0068479420eE5fDdF59B62301f810", - "transactionIndex": 63, + "contractAddress": "0xa3f54f30cDefaBd9527FF11ad51Ba20c3b77ffDD", + "transactionIndex": 41, "gasUsed": "405585", - "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000008000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000000004000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000010000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000080000000000000000", - "blockHash": "0xc40d7f3894c751ce39361b41360973e012fccc0bcc8770bcbb6a926d9474a899", - "transactionHash": "0x19762cf6f04f946ee9af7a2b33ef576781afc364bf031afe6319b03d0c531a6d", + "logsBloom": "0x00000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000000004000000000100002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000010000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0xeb75a4f4e090ead69abb76fa8002957b1d721ef4121f27dd6b32b784c7ac347c", + "transactionHash": "0xa7a9c1f0210822c01adc6baec616c8b15880fa006bfb44e2fd11e8eed5c4d79e", "logs": [ { - "transactionIndex": 63, - "blockNumber": 1405126, - "transactionHash": "0x19762cf6f04f946ee9af7a2b33ef576781afc364bf031afe6319b03d0c531a6d", - "address": "0x79681d3f14a0068479420eE5fDdF59B62301f810", + "transactionIndex": 41, + "blockNumber": 1489385, + "transactionHash": "0xa7a9c1f0210822c01adc6baec616c8b15880fa006bfb44e2fd11e8eed5c4d79e", + "address": "0xa3f54f30cDefaBd9527FF11ad51Ba20c3b77ffDD", "topics": [ "0xc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000001b94ca50d3ad9f8368851f8526132272d1a5028c" ], "data": "0x", - "logIndex": 69, - "blockHash": "0xc40d7f3894c751ce39361b41360973e012fccc0bcc8770bcbb6a926d9474a899" + "logIndex": 567, + "blockHash": "0xeb75a4f4e090ead69abb76fa8002957b1d721ef4121f27dd6b32b784c7ac347c" } ], - "blockNumber": 1405126, - "cumulativeGasUsed": "7055269", + "blockNumber": 1489385, + "cumulativeGasUsed": "21569388", "status": 1, "byzantium": true }, "args": [ - "0x4Eac8847c7AE50e3A3551B1Aa4FF7Cc162151410" + "0xcf4a9e80Ddb173cc17128A361B98B9A140e3932E" ], "numDeployments": 1, - "solcInputHash": "0213c8dc30149ba5fb281c6d46803d0b", + "solcInputHash": "66dbdc9fbde8f1c7cc59f29d272eb661", "metadata": "{\"compiler\":{\"version\":\"0.8.7+commit.e28d00a7\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_strategy\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"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\":true,\"internalType\":\"address\",\"name\":\"previousGovernor\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newGovernor\",\"type\":\"address\"}],\"name\":\"PendingGovernorshipTransfer\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"STRATEGY\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"claimGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"collect\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"eth\",\"type\":\"uint256\"}],\"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\":[{\"internalType\":\"address\",\"name\":\"_newGovernor\",\"type\":\"address\"}],\"name\":\"transferGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"author\":\"Origin Protocol Inc\",\"kind\":\"dev\",\"methods\":{\"collect()\":{\"returns\":{\"eth\":\"The amount of execution rewards that were sent to the Native Staking Strategy\"}},\"constructor\":{\"params\":{\"_strategy\":\"Address of the Native Staking Strategy\"}},\"transferGovernance(address)\":{\"params\":{\"_newGovernor\":\"Address of the new Governor\"}}},\"title\":\"Fee Accumulator for Native Staking SSV Strategy\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"STRATEGY()\":{\"notice\":\"The address of the Native Staking Strategy\"},\"claimGovernance()\":{\"notice\":\"Claim Governance of the contract to a new account (`newGovernor`). Can only be called by the new Governor.\"},\"collect()\":{\"notice\":\"sends all ETH in this FeeAccumulator contract to the Native Staking Strategy.\"},\"governor()\":{\"notice\":\"Returns the address of the current Governor.\"},\"isGovernor()\":{\"notice\":\"Returns true if the caller is the current Governor.\"},\"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\"}},\"notice\":\"Receives execution rewards which includes tx fees and MEV rewards like tx priority and tx ordering. It does NOT include swept ETH from beacon chain consensus rewards or full validator withdrawals.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/strategies/NativeStaking/FeeAccumulator.sol\":\"FeeAccumulator\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@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\"},\"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/strategies/NativeStaking/FeeAccumulator.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport { Address } from \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\n\\nimport { Governable } from \\\"../../governance/Governable.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 is Governable {\\n /// @notice The address of the Native Staking Strategy\\n address public immutable STRATEGY;\\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 }\\n}\\n\",\"keccak256\":\"0xf47bcc46ce70f649f061bec3d2303f376a15700ba18fe471fba823f60bdfed8b\",\"license\":\"MIT\"}},\"version\":1}", "bytecode": "0x60a060405234801561001057600080fd5b506040516106fe3803806106fe83398101604081905261002f916100a1565b610045336000805160206106de83398151915255565b6000805160206106de833981519152546040516001600160a01b03909116906000907fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a908290a360601b6001600160601b0319166080526100d1565b6000602082840312156100b357600080fd5b81516001600160a01b03811681146100ca57600080fd5b9392505050565b60805160601c6105e26100fc600039600081816091015281816102d8015261035201526105e26000f3fe608060405234801561001057600080fd5b50600436106100625760003560e01c80630c340a2414610067578063185025ef1461008c5780635d36b190146100b3578063c7af3352146100bd578063d38bfff4146100d5578063e5225381146100e8575b600080fd5b61006f6100fe565b6040516001600160a01b0390911681526020015b60405180910390f35b61006f7f000000000000000000000000000000000000000000000000000000000000000081565b6100bb61011b565b005b6100c56101c6565b6040519015158152602001610083565b6100bb6100e336600461055c565b6101f7565b6100f06102cb565b604051908152602001610083565b600061011660008051602061058d8339815191525490565b905090565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b0316146101bb5760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b60648201526084015b60405180910390fd5b6101c43361037a565b565b60006101de60008051602061058d8339815191525490565b6001600160a01b0316336001600160a01b031614905090565b6101ff6101c6565b61024b5760405162461bcd60e51b815260206004820152601a60248201527f43616c6c6572206973206e6f742074686520476f7665726e6f7200000000000060448201526064016101b2565b610273817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b031661029360008051602061058d8339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b6000336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146103455760405162461bcd60e51b815260206004820152601a60248201527f43616c6c6572206973206e6f742074686520537472617465677900000000000060448201526064016101b2565b50478015610377576103777f00000000000000000000000000000000000000000000000000000000000000008261043e565b90565b6001600160a01b0381166103d05760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f72206973206164647265737328302900000000000060448201526064016101b2565b806001600160a01b03166103f060008051602061058d8339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a361043b8160008051602061058d83398151915255565b50565b8047101561048e5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e636500000060448201526064016101b2565b6000826001600160a01b03168260405160006040518083038185875af1925050503d80600081146104db576040519150601f19603f3d011682016040523d82523d6000602084013e6104e0565b606091505b50509050806105575760405162461bcd60e51b815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d6179206861766520726576657274656400000000000060648201526084016101b2565b505050565b60006020828403121561056e57600080fd5b81356001600160a01b038116811461058557600080fd5b939250505056fe7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa26469706673582212200be77de36795d09032129c2625dac1fb5df5aa816a58c269aa5090717764a41664736f6c634300080700337bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a", "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106100625760003560e01c80630c340a2414610067578063185025ef1461008c5780635d36b190146100b3578063c7af3352146100bd578063d38bfff4146100d5578063e5225381146100e8575b600080fd5b61006f6100fe565b6040516001600160a01b0390911681526020015b60405180910390f35b61006f7f000000000000000000000000000000000000000000000000000000000000000081565b6100bb61011b565b005b6100c56101c6565b6040519015158152602001610083565b6100bb6100e336600461055c565b6101f7565b6100f06102cb565b604051908152602001610083565b600061011660008051602061058d8339815191525490565b905090565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b0316146101bb5760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b60648201526084015b60405180910390fd5b6101c43361037a565b565b60006101de60008051602061058d8339815191525490565b6001600160a01b0316336001600160a01b031614905090565b6101ff6101c6565b61024b5760405162461bcd60e51b815260206004820152601a60248201527f43616c6c6572206973206e6f742074686520476f7665726e6f7200000000000060448201526064016101b2565b610273817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b031661029360008051602061058d8339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b6000336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146103455760405162461bcd60e51b815260206004820152601a60248201527f43616c6c6572206973206e6f742074686520537472617465677900000000000060448201526064016101b2565b50478015610377576103777f00000000000000000000000000000000000000000000000000000000000000008261043e565b90565b6001600160a01b0381166103d05760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f72206973206164647265737328302900000000000060448201526064016101b2565b806001600160a01b03166103f060008051602061058d8339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a361043b8160008051602061058d83398151915255565b50565b8047101561048e5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e636500000060448201526064016101b2565b6000826001600160a01b03168260405160006040518083038185875af1925050503d80600081146104db576040519150601f19603f3d011682016040523d82523d6000602084013e6104e0565b606091505b50509050806105575760405162461bcd60e51b815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d6179206861766520726576657274656400000000000060648201526084016101b2565b505050565b60006020828403121561056e57600080fd5b81356001600160a01b038116811461058557600080fd5b939250505056fe7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa26469706673582212200be77de36795d09032129c2625dac1fb5df5aa816a58c269aa5090717764a41664736f6c63430008070033", diff --git a/contracts/deployments/holesky/NativeStakingFeeAccumulatorProxy.json b/contracts/deployments/holesky/NativeStakingFeeAccumulatorProxy.json index 613ebfdf20..b28a9bcbce 100644 --- a/contracts/deployments/holesky/NativeStakingFeeAccumulatorProxy.json +++ b/contracts/deployments/holesky/NativeStakingFeeAccumulatorProxy.json @@ -1,5 +1,5 @@ { - "address": "0x590B781b511e953dbFC49e7E7864A6E787aFBDCc", + "address": "0x65a289f4BF934c964C942eFF6E6F83b6481BE550", "abi": [ { "anonymous": false, @@ -183,40 +183,40 @@ "type": "function" } ], - "transactionHash": "0xe18ea4add8d4b624520b0d846ca2cd46ce529dbfe4b1cd3d0021af17f101976c", + "transactionHash": "0xdf546fcd8f123530eeb172e7b0300f7ec025708e8dc7bf7f81c10ed1bfc27390", "receipt": { "to": null, "from": "0x1b94CA50D3Ad9f8368851F8526132272d1a5028C", - "contractAddress": "0x590B781b511e953dbFC49e7E7864A6E787aFBDCc", - "transactionIndex": 27, + "contractAddress": "0x65a289f4BF934c964C942eFF6E6F83b6481BE550", + "transactionIndex": 5, "gasUsed": "580428", - "logsBloom": "0x00000000000000000000000000000000000000004000000000000000000000000000000000000100000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000000004000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000010000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000400000000", - "blockHash": "0x5b923d8e846ac85cdb6738b81eb0c4497e0bae72d3df76486bafd0c5370abe94", - "transactionHash": "0xe18ea4add8d4b624520b0d846ca2cd46ce529dbfe4b1cd3d0021af17f101976c", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000020000000000000000000800000000000000000000000000000000000004000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000010000000000000000000000000000000001000000020000000000000000000000000000000000000000008000000000000000000000000", + "blockHash": "0x815557d68a9f6f68b373786e2f16e3e037531c823e74be7e8a66e62d600c9ef0", + "transactionHash": "0xdf546fcd8f123530eeb172e7b0300f7ec025708e8dc7bf7f81c10ed1bfc27390", "logs": [ { - "transactionIndex": 27, - "blockNumber": 1405107, - "transactionHash": "0xe18ea4add8d4b624520b0d846ca2cd46ce529dbfe4b1cd3d0021af17f101976c", - "address": "0x590B781b511e953dbFC49e7E7864A6E787aFBDCc", + "transactionIndex": 5, + "blockNumber": 1489367, + "transactionHash": "0xdf546fcd8f123530eeb172e7b0300f7ec025708e8dc7bf7f81c10ed1bfc27390", + "address": "0x65a289f4BF934c964C942eFF6E6F83b6481BE550", "topics": [ "0xc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000001b94ca50d3ad9f8368851f8526132272d1a5028c" ], "data": "0x", - "logIndex": 35, - "blockHash": "0x5b923d8e846ac85cdb6738b81eb0c4497e0bae72d3df76486bafd0c5370abe94" + "logIndex": 8, + "blockHash": "0x815557d68a9f6f68b373786e2f16e3e037531c823e74be7e8a66e62d600c9ef0" } ], - "blockNumber": 1405107, - "cumulativeGasUsed": "3056739", + "blockNumber": 1489367, + "cumulativeGasUsed": "1072707", "status": 1, "byzantium": true }, "args": [], "numDeployments": 1, - "solcInputHash": "da4c2bc4af0be4b969e54f8b43895033", + "solcInputHash": "5e7101910c63b5cb160cf1f36fa86058", "metadata": "{\"compiler\":{\"version\":\"0.8.7+commit.e28d00a7\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"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\":true,\"internalType\":\"address\",\"name\":\"previousGovernor\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newGovernor\",\"type\":\"address\"}],\"name\":\"PendingGovernorshipTransfer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"implementation\",\"type\":\"address\"}],\"name\":\"Upgraded\",\"type\":\"event\"},{\"stateMutability\":\"payable\",\"type\":\"fallback\"},{\"inputs\":[],\"name\":\"admin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"claimGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"governor\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"implementation\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_logic\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_initGovernor\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isGovernor\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_newGovernor\",\"type\":\"address\"}],\"name\":\"transferGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newImplementation\",\"type\":\"address\"}],\"name\":\"upgradeTo\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newImplementation\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"upgradeToAndCall\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"admin()\":{\"returns\":{\"_0\":\"The address of the proxy admin/it's also the governor.\"}},\"implementation()\":{\"returns\":{\"_0\":\"The address of the implementation.\"}},\"initialize(address,address,bytes)\":{\"details\":\"Contract initializer with Governor enforcement\",\"params\":{\"_data\":\"Data to send as msg.data to the implementation to initialize the proxied contract. It should include the signature and the parameters of the function to be called, as described in https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding. This parameter is optional, if no data is given the initialization call to proxied contract will be skipped.\",\"_initGovernor\":\"Address of the initial Governor.\",\"_logic\":\"Address of the initial implementation.\"}},\"transferGovernance(address)\":{\"params\":{\"_newGovernor\":\"Address of the new Governor\"}},\"upgradeTo(address)\":{\"details\":\"Upgrade the backing implementation of the proxy. Only the admin can call this function.\",\"params\":{\"newImplementation\":\"Address of the new implementation.\"}},\"upgradeToAndCall(address,bytes)\":{\"details\":\"Upgrade the backing implementation of the proxy and call a function on the new implementation. This is useful to initialize the proxied contract.\",\"params\":{\"data\":\"Data to send as msg.data in the low level call. It should include the signature and the parameters of the function to be called, as described in https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.\",\"newImplementation\":\"Address of the new implementation.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"claimGovernance()\":{\"notice\":\"Claim Governance of the contract to a new account (`newGovernor`). Can only be called by the new Governor.\"},\"governor()\":{\"notice\":\"Returns the address of the current Governor.\"},\"isGovernor()\":{\"notice\":\"Returns true if the caller is the current Governor.\"},\"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\"}},\"notice\":\"NativeStakingFeeAccumulatorProxy delegates calls to NativeStakingFeeCollector implementation\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/proxies/Proxies.sol\":\"NativeStakingFeeAccumulatorProxy\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@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\"},\"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/proxies/InitializeGovernedUpgradeabilityProxy.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport { Address } from \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\n\\nimport { Governable } from \\\"../governance/Governable.sol\\\";\\n\\n/**\\n * @title BaseGovernedUpgradeabilityProxy\\n * @dev This contract combines an upgradeability proxy with our governor system.\\n * It is based on an older version of OpenZeppelins BaseUpgradeabilityProxy\\n * with Solidity ^0.8.0.\\n * @author Origin Protocol Inc\\n */\\ncontract InitializeGovernedUpgradeabilityProxy is Governable {\\n /**\\n * @dev Emitted when the implementation is upgraded.\\n * @param implementation Address of the new implementation.\\n */\\n event Upgraded(address indexed implementation);\\n\\n /**\\n * @dev Contract initializer with Governor enforcement\\n * @param _logic Address of the initial implementation.\\n * @param _initGovernor Address of the initial Governor.\\n * @param _data Data to send as msg.data to the implementation to initialize\\n * the proxied contract.\\n * It should include the signature and the parameters of the function to be\\n * called, as described in\\n * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.\\n * This parameter is optional, if no data is given the initialization call\\n * to proxied contract will be skipped.\\n */\\n function initialize(\\n address _logic,\\n address _initGovernor,\\n bytes calldata _data\\n ) public payable onlyGovernor {\\n require(_implementation() == address(0));\\n assert(\\n IMPLEMENTATION_SLOT ==\\n bytes32(uint256(keccak256(\\\"eip1967.proxy.implementation\\\")) - 1)\\n );\\n _setImplementation(_logic);\\n if (_data.length > 0) {\\n (bool success, ) = _logic.delegatecall(_data);\\n require(success);\\n }\\n _changeGovernor(_initGovernor);\\n }\\n\\n /**\\n * @return The address of the proxy admin/it's also the governor.\\n */\\n function admin() external view returns (address) {\\n return _governor();\\n }\\n\\n /**\\n * @return The address of the implementation.\\n */\\n function implementation() external view returns (address) {\\n return _implementation();\\n }\\n\\n /**\\n * @dev Upgrade the backing implementation of the proxy.\\n * Only the admin can call this function.\\n * @param newImplementation Address of the new implementation.\\n */\\n function upgradeTo(address newImplementation) external onlyGovernor {\\n _upgradeTo(newImplementation);\\n }\\n\\n /**\\n * @dev Upgrade the backing implementation of the proxy and call a function\\n * on the new implementation.\\n * This is useful to initialize the proxied contract.\\n * @param newImplementation Address of the new implementation.\\n * @param data Data to send as msg.data in the low level call.\\n * It should include the signature and the parameters of the function to be called, as described in\\n * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.\\n */\\n function upgradeToAndCall(address newImplementation, bytes calldata data)\\n external\\n payable\\n onlyGovernor\\n {\\n _upgradeTo(newImplementation);\\n (bool success, ) = newImplementation.delegatecall(data);\\n require(success);\\n }\\n\\n /**\\n * @dev Fallback function.\\n * Implemented entirely in `_fallback`.\\n */\\n fallback() external payable {\\n _fallback();\\n }\\n\\n /**\\n * @dev Delegates execution to an implementation contract.\\n * This is a low level function that doesn't return to its internal call site.\\n * It will return to the external caller whatever the implementation returns.\\n * @param _impl Address to delegate.\\n */\\n function _delegate(address _impl) internal {\\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(gas(), _impl, 0, calldatasize(), 0, 0)\\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 /**\\n * @dev Function that is run as the first thing in the fallback function.\\n * Can be redefined in derived contracts to add functionality.\\n * Redefinitions must call super._willFallback().\\n */\\n function _willFallback() internal {}\\n\\n /**\\n * @dev fallback implementation.\\n * Extracted to enable manual triggering.\\n */\\n function _fallback() internal {\\n _willFallback();\\n _delegate(_implementation());\\n }\\n\\n /**\\n * @dev Storage slot with the address of the current implementation.\\n * This is the keccak-256 hash of \\\"eip1967.proxy.implementation\\\" subtracted by 1, and is\\n * validated in the constructor.\\n */\\n bytes32 internal constant IMPLEMENTATION_SLOT =\\n 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\\n\\n /**\\n * @dev Returns the current implementation.\\n * @return impl Address of the current implementation\\n */\\n function _implementation() internal view returns (address impl) {\\n bytes32 slot = IMPLEMENTATION_SLOT;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n impl := sload(slot)\\n }\\n }\\n\\n /**\\n * @dev Upgrades the proxy to a new implementation.\\n * @param newImplementation Address of the new implementation.\\n */\\n function _upgradeTo(address newImplementation) internal {\\n _setImplementation(newImplementation);\\n emit Upgraded(newImplementation);\\n }\\n\\n /**\\n * @dev Sets the implementation address of the proxy.\\n * @param newImplementation Address of the new implementation.\\n */\\n function _setImplementation(address newImplementation) internal {\\n require(\\n Address.isContract(newImplementation),\\n \\\"Cannot set a proxy implementation to a non-contract address\\\"\\n );\\n\\n bytes32 slot = IMPLEMENTATION_SLOT;\\n\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n sstore(slot, newImplementation)\\n }\\n }\\n}\\n\",\"keccak256\":\"0xcf9bc33957fa41a745726edb6461a4bddca875a038c848286a059f0f22b7f184\",\"license\":\"MIT\"},\"contracts/proxies/Proxies.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport { InitializeGovernedUpgradeabilityProxy } from \\\"./InitializeGovernedUpgradeabilityProxy.sol\\\";\\n\\n/**\\n * @notice OUSDProxy delegates calls to an OUSD implementation\\n */\\ncontract OUSDProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice WrappedOUSDProxy delegates calls to a WrappedOUSD implementation\\n */\\ncontract WrappedOUSDProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice VaultProxy delegates calls to a Vault implementation\\n */\\ncontract VaultProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice CompoundStrategyProxy delegates calls to a CompoundStrategy implementation\\n */\\ncontract CompoundStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice AaveStrategyProxy delegates calls to a AaveStrategy implementation\\n */\\ncontract AaveStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice ThreePoolStrategyProxy delegates calls to a ThreePoolStrategy implementation\\n */\\ncontract ThreePoolStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice ConvexStrategyProxy delegates calls to a ConvexStrategy implementation\\n */\\ncontract ConvexStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice HarvesterProxy delegates calls to a Harvester implementation\\n */\\ncontract HarvesterProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice DripperProxy delegates calls to a Dripper implementation\\n */\\ncontract DripperProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice MorphoCompoundStrategyProxy delegates calls to a MorphoCompoundStrategy implementation\\n */\\ncontract MorphoCompoundStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice ConvexOUSDMetaStrategyProxy delegates calls to a ConvexOUSDMetaStrategy implementation\\n */\\ncontract ConvexOUSDMetaStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice ConvexLUSDMetaStrategyProxy delegates calls to a ConvexalGeneralizedMetaStrategy implementation\\n */\\ncontract ConvexLUSDMetaStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice MorphoAaveStrategyProxy delegates calls to a MorphoCompoundStrategy implementation\\n */\\ncontract MorphoAaveStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice OETHProxy delegates calls to nowhere for now\\n */\\ncontract OETHProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice WOETHProxy delegates calls to nowhere for now\\n */\\ncontract WOETHProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice OETHVaultProxy delegates calls to a Vault implementation\\n */\\ncontract OETHVaultProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice OETHDripperProxy delegates calls to a OETHDripper implementation\\n */\\ncontract OETHDripperProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice OETHHarvesterProxy delegates calls to a Harvester implementation\\n */\\ncontract OETHHarvesterProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice FraxETHStrategyProxy delegates calls to a FraxETHStrategy implementation\\n */\\ncontract FraxETHStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice CurveEthStrategyProxy delegates calls to a CurveEthStrategy implementation\\n */\\ncontract ConvexEthMetaStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice BuybackProxy delegates calls to Buyback implementation\\n */\\ncontract BuybackProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice OETHMorphoAaveStrategyProxy delegates calls to a MorphoAaveStrategy implementation\\n */\\ncontract OETHMorphoAaveStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice OETHBalancerMetaPoolrEthStrategyProxy delegates calls to a BalancerMetaPoolStrategy implementation\\n */\\ncontract OETHBalancerMetaPoolrEthStrategyProxy is\\n InitializeGovernedUpgradeabilityProxy\\n{\\n\\n}\\n\\n/**\\n * @notice OETHBalancerMetaPoolwstEthStrategyProxy delegates calls to a BalancerMetaPoolStrategy implementation\\n */\\ncontract OETHBalancerMetaPoolwstEthStrategyProxy is\\n InitializeGovernedUpgradeabilityProxy\\n{\\n\\n}\\n\\n/**\\n * @notice FluxStrategyProxy delegates calls to a CompoundStrategy implementation\\n */\\ncontract FluxStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice MakerDsrStrategyProxy delegates calls to a Generalized4626Strategy implementation\\n */\\ncontract MakerDsrStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice FrxEthRedeemStrategyProxy delegates calls to a FrxEthRedeemStrategy implementation\\n */\\ncontract FrxEthRedeemStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice OETHBuybackProxy delegates calls to Buyback implementation\\n */\\ncontract OETHBuybackProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice BridgedWOETHProxy delegates calls to BridgedWOETH implementation\\n */\\ncontract BridgedWOETHProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice NativeStakingSSVStrategyProxy delegates calls to NativeStakingSSVStrategy implementation\\n */\\ncontract NativeStakingSSVStrategyProxy is\\n InitializeGovernedUpgradeabilityProxy\\n{\\n\\n}\\n\\n/**\\n * @notice NativeStakingFeeAccumulatorProxy delegates calls to NativeStakingFeeCollector implementation\\n */\\ncontract NativeStakingFeeAccumulatorProxy is\\n InitializeGovernedUpgradeabilityProxy\\n{\\n\\n}\\n\",\"keccak256\":\"0x2e294507edd91494e1020a2a1c43502d2f5cba01266c228406562ecde7a2d872\",\"license\":\"MIT\"}},\"version\":1}", "bytecode": "0x608060405234801561001057600080fd5b506100273360008051602061099083398151915255565b600080516020610990833981519152546040516001600160a01b03909116906000907fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a908290a36109138061007d6000396000f3fe6080604052600436106100865760003560e01c80635d36b190116100595780635d36b1901461010a578063c7af33521461011f578063cf7a1d7714610144578063d38bfff414610157578063f851a4401461009057610086565b80630c340a24146100905780633659cfe6146100c25780634f1ef286146100e25780635c60da1b146100f5575b61008e610177565b005b34801561009c57600080fd5b506100a5610197565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156100ce57600080fd5b5061008e6100dd366004610745565b6101b4565b61008e6100f03660046107c8565b6101ed565b34801561010157600080fd5b506100a561028a565b34801561011657600080fd5b5061008e6102a2565b34801561012b57600080fd5b50610134610346565b60405190151581526020016100b9565b61008e610152366004610767565b610377565b34801561016357600080fd5b5061008e610172366004610745565b610491565b61019561019060008051602061089e8339815191525490565b610535565b565b60006101af6000805160206108be8339815191525490565b905090565b6101bc610346565b6101e15760405162461bcd60e51b81526004016101d89061082b565b60405180910390fd5b6101ea81610559565b50565b6101f5610346565b6102115760405162461bcd60e51b81526004016101d89061082b565b61021a83610559565b6000836001600160a01b0316838360405161023692919061081b565b600060405180830381855af49150503d8060008114610271576040519150601f19603f3d011682016040523d82523d6000602084013e610276565b606091505b505090508061028457600080fd5b50505050565b60006101af60008051602061089e8339815191525490565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b03161461033d5760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b60648201526084016101d8565b61019533610599565b600061035e6000805160206108be8339815191525490565b6001600160a01b0316336001600160a01b031614905090565b61037f610346565b61039b5760405162461bcd60e51b81526004016101d89061082b565b60006103b360008051602061089e8339815191525490565b6001600160a01b0316146103c657600080fd5b6103f160017f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbd610862565b60008051602061089e8339815191521461040d5761040d610887565b6104168461065a565b8015610488576000846001600160a01b0316838360405161043892919061081b565b600060405180830381855af49150503d8060008114610473576040519150601f19603f3d011682016040523d82523d6000602084013e610478565b606091505b505090508061048657600080fd5b505b61028483610599565b610499610346565b6104b55760405162461bcd60e51b81526004016101d89061082b565b6104dd817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b03166104fd6000805160206108be8339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b3660008037600080366000845af43d6000803e808015610554573d6000f35b3d6000fd5b6105628161065a565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b6001600160a01b0381166105ef5760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f72206973206164647265737328302900000000000060448201526064016101d8565b806001600160a01b031661060f6000805160206108be8339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a36101ea816000805160206108be83398151915255565b803b6106ce5760405162461bcd60e51b815260206004820152603b60248201527f43616e6e6f742073657420612070726f787920696d706c656d656e746174696f60448201527f6e20746f2061206e6f6e2d636f6e74726163742061646472657373000000000060648201526084016101d8565b60008051602061089e83398151915255565b80356001600160a01b03811681146106f757600080fd5b919050565b60008083601f84011261070e57600080fd5b50813567ffffffffffffffff81111561072657600080fd5b60208301915083602082850101111561073e57600080fd5b9250929050565b60006020828403121561075757600080fd5b610760826106e0565b9392505050565b6000806000806060858703121561077d57600080fd5b610786856106e0565b9350610794602086016106e0565b9250604085013567ffffffffffffffff8111156107b057600080fd5b6107bc878288016106fc565b95989497509550505050565b6000806000604084860312156107dd57600080fd5b6107e6846106e0565b9250602084013567ffffffffffffffff81111561080257600080fd5b61080e868287016106fc565b9497909650939450505050565b8183823760009101908152919050565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b60008282101561088257634e487b7160e01b600052601160045260246000fd5b500390565b634e487b7160e01b600052600160045260246000fdfe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa26469706673582212205970f4615c7f37182e1f488c42ecbeb496eeeae3e15b9d0b344a6c7530953ff364736f6c634300080700337bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a", "deployedBytecode": "0x6080604052600436106100865760003560e01c80635d36b190116100595780635d36b1901461010a578063c7af33521461011f578063cf7a1d7714610144578063d38bfff414610157578063f851a4401461009057610086565b80630c340a24146100905780633659cfe6146100c25780634f1ef286146100e25780635c60da1b146100f5575b61008e610177565b005b34801561009c57600080fd5b506100a5610197565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156100ce57600080fd5b5061008e6100dd366004610745565b6101b4565b61008e6100f03660046107c8565b6101ed565b34801561010157600080fd5b506100a561028a565b34801561011657600080fd5b5061008e6102a2565b34801561012b57600080fd5b50610134610346565b60405190151581526020016100b9565b61008e610152366004610767565b610377565b34801561016357600080fd5b5061008e610172366004610745565b610491565b61019561019060008051602061089e8339815191525490565b610535565b565b60006101af6000805160206108be8339815191525490565b905090565b6101bc610346565b6101e15760405162461bcd60e51b81526004016101d89061082b565b60405180910390fd5b6101ea81610559565b50565b6101f5610346565b6102115760405162461bcd60e51b81526004016101d89061082b565b61021a83610559565b6000836001600160a01b0316838360405161023692919061081b565b600060405180830381855af49150503d8060008114610271576040519150601f19603f3d011682016040523d82523d6000602084013e610276565b606091505b505090508061028457600080fd5b50505050565b60006101af60008051602061089e8339815191525490565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b03161461033d5760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b60648201526084016101d8565b61019533610599565b600061035e6000805160206108be8339815191525490565b6001600160a01b0316336001600160a01b031614905090565b61037f610346565b61039b5760405162461bcd60e51b81526004016101d89061082b565b60006103b360008051602061089e8339815191525490565b6001600160a01b0316146103c657600080fd5b6103f160017f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbd610862565b60008051602061089e8339815191521461040d5761040d610887565b6104168461065a565b8015610488576000846001600160a01b0316838360405161043892919061081b565b600060405180830381855af49150503d8060008114610473576040519150601f19603f3d011682016040523d82523d6000602084013e610478565b606091505b505090508061048657600080fd5b505b61028483610599565b610499610346565b6104b55760405162461bcd60e51b81526004016101d89061082b565b6104dd817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b03166104fd6000805160206108be8339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b3660008037600080366000845af43d6000803e808015610554573d6000f35b3d6000fd5b6105628161065a565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b6001600160a01b0381166105ef5760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f72206973206164647265737328302900000000000060448201526064016101d8565b806001600160a01b031661060f6000805160206108be8339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a36101ea816000805160206108be83398151915255565b803b6106ce5760405162461bcd60e51b815260206004820152603b60248201527f43616e6e6f742073657420612070726f787920696d706c656d656e746174696f60448201527f6e20746f2061206e6f6e2d636f6e74726163742061646472657373000000000060648201526084016101d8565b60008051602061089e83398151915255565b80356001600160a01b03811681146106f757600080fd5b919050565b60008083601f84011261070e57600080fd5b50813567ffffffffffffffff81111561072657600080fd5b60208301915083602082850101111561073e57600080fd5b9250929050565b60006020828403121561075757600080fd5b610760826106e0565b9392505050565b6000806000806060858703121561077d57600080fd5b610786856106e0565b9350610794602086016106e0565b9250604085013567ffffffffffffffff8111156107b057600080fd5b6107bc878288016106fc565b95989497509550505050565b6000806000604084860312156107dd57600080fd5b6107e6846106e0565b9250602084013567ffffffffffffffff81111561080257600080fd5b61080e868287016106fc565b9497909650939450505050565b8183823760009101908152919050565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b60008282101561088257634e487b7160e01b600052601160045260246000fd5b500390565b634e487b7160e01b600052600160045260246000fdfe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa26469706673582212205970f4615c7f37182e1f488c42ecbeb496eeeae3e15b9d0b344a6c7530953ff364736f6c63430008070033", diff --git a/contracts/deployments/holesky/NativeStakingSSVStrategy.json b/contracts/deployments/holesky/NativeStakingSSVStrategy.json index 260cfb1a33..fc66b58e4c 100644 --- a/contracts/deployments/holesky/NativeStakingSSVStrategy.json +++ b/contracts/deployments/holesky/NativeStakingSSVStrategy.json @@ -1,5 +1,5 @@ { - "address": "0x4aEAcdb5D84eDf02Dd85f3DFC1645b89D7579d62", + "address": "0xaf3fCA5376354c8a51dc3cB02D586530Cc61d164", "abi": [ { "inputs": [ @@ -92,51 +92,20 @@ "inputs": [ { "indexed": false, - "internalType": "address", - "name": "newAddress", - "type": "address" - } - ], - "name": "AccountingGovernorChanged", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "oldActiveDepositedValidators", - "type": "uint256" + "internalType": "int256", + "name": "validatorsDelta", + "type": "int256" }, { "indexed": false, - "internalType": "uint256", - "name": "activeDepositedValidators", - "type": "uint256" + "internalType": "int256", + "name": "consensusRewardsDelta", + "type": "int256" }, { "indexed": false, "internalType": "uint256", - "name": "oldBeaconChainRewards", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "beaconChainRewards", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "ethToWeth", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "wethToBeSentToVault", + "name": "wethToVault", "type": "uint256" } ], @@ -584,12 +553,12 @@ }, { "inputs": [], - "name": "accountingGovernor", + "name": "activeDepositedValidators", "outputs": [ { - "internalType": "address", + "internalType": "uint256", "name": "", - "type": "address" + "type": "uint256" } ], "stateMutability": "view", @@ -870,33 +839,18 @@ { "inputs": [ { - "internalType": "uint256", - "name": "_activeDepositedValidators", - "type": "uint256" + "internalType": "int256", + "name": "_validatorsDelta", + "type": "int256" }, { - "internalType": "uint256", - "name": "_ethToWeth", - "type": "uint256" + "internalType": "int256", + "name": "_consensusRewardsDelta", + "type": "int256" }, { "internalType": "uint256", - "name": "_wethToBeSentToVault", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "_consensusRewards", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "_ethThresholdCheck", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "_wethThresholdCheck", + "name": "_wethToVaultAmount", "type": "uint256" } ], @@ -1087,19 +1041,6 @@ "stateMutability": "nonpayable", "type": "function" }, - { - "inputs": [ - { - "internalType": "address", - "name": "_address", - "type": "address" - } - ], - "name": "setAccountingGovernor", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, { "inputs": [ { @@ -1335,34 +1276,34 @@ "type": "receive" } ], - "transactionHash": "0x32a95bad479c439018f11c6c93e19fc7fd7edc0fdbcdc15009a32231d7967c5c", + "transactionHash": "0xddb5a6d8ad3f95e324b44bfe1d2cb508bcf734deb36c3f6dfb2f29e44f36e797", "receipt": { "to": null, "from": "0x1b94CA50D3Ad9f8368851F8526132272d1a5028C", - "contractAddress": "0x4aEAcdb5D84eDf02Dd85f3DFC1645b89D7579d62", - "transactionIndex": 26, - "gasUsed": "4123386", - "logsBloom": "0x00000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000000004000000000000002000000000000000000040000001000000000000000000000000000000000000000000000000000000000000000000000000000000000200000010000000000010000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000", - "blockHash": "0x7accf851e0f53d2da70bb20741170ae10a24b9724ad337e6e7ec6f032a75da32", - "transactionHash": "0x32a95bad479c439018f11c6c93e19fc7fd7edc0fdbcdc15009a32231d7967c5c", + "contractAddress": "0xaf3fCA5376354c8a51dc3cB02D586530Cc61d164", + "transactionIndex": 9, + "gasUsed": "4109268", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000020000000000000000000800000000000000000000000000000000000004000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000010000000000000000000000000000000000000000020000400000000000000000000000000000000000000000000000000000000000001", + "blockHash": "0x95040d373bc67c18914c67055beff42c69ea4eab3fae944856d9e458a49bfac7", + "transactionHash": "0xddb5a6d8ad3f95e324b44bfe1d2cb508bcf734deb36c3f6dfb2f29e44f36e797", "logs": [ { - "transactionIndex": 26, - "blockNumber": 1429889, - "transactionHash": "0x32a95bad479c439018f11c6c93e19fc7fd7edc0fdbcdc15009a32231d7967c5c", - "address": "0x4aEAcdb5D84eDf02Dd85f3DFC1645b89D7579d62", + "transactionIndex": 9, + "blockNumber": 1489371, + "transactionHash": "0xddb5a6d8ad3f95e324b44bfe1d2cb508bcf734deb36c3f6dfb2f29e44f36e797", + "address": "0xaf3fCA5376354c8a51dc3cB02D586530Cc61d164", "topics": [ "0xc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000001b94ca50d3ad9f8368851f8526132272d1a5028c" ], "data": "0x", - "logIndex": 38, - "blockHash": "0x7accf851e0f53d2da70bb20741170ae10a24b9724ad337e6e7ec6f032a75da32" + "logIndex": 400, + "blockHash": "0x95040d373bc67c18914c67055beff42c69ea4eab3fae944856d9e458a49bfac7" } ], - "blockNumber": 1429889, - "cumulativeGasUsed": "6291081", + "blockNumber": 1489371, + "cumulativeGasUsed": "20992246", "status": 1, "byzantium": true }, @@ -1374,14 +1315,14 @@ "0x94373a4919B3240D86eA41593D5eBa789FEF3848", "0xad45A78180961079BFaeEe349704F411dfF947C6", "0x38A4794cCEd47d3baf7370CcC43B560D3a1beEFA", - "0x590B781b511e953dbFC49e7E7864A6E787aFBDCc", + "0x65a289f4BF934c964C942eFF6E6F83b6481BE550", "0x4242424242424242424242424242424242424242" ], - "numDeployments": 2, - "solcInputHash": "46be8b80ad6bb26f70e58a31071e073e", - "metadata": "{\"compiler\":{\"version\":\"0.8.7+commit.e28d00a7\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"platformAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"vaultAddress\",\"type\":\"address\"}],\"internalType\":\"struct InitializableAbstractStrategy.BaseStrategyConfig\",\"name\":\"_baseConfig\",\"type\":\"tuple\"},{\"internalType\":\"address\",\"name\":\"_wethAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_ssvToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_ssvNetwork\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_feeAccumulator\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_beaconChainDepositContract\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"AccountingConsensusRewards\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"noOfValidators\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"remainingValidators\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"wethSentToVault\",\"type\":\"uint256\"}],\"name\":\"AccountingFullyWithdrawnValidator\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newAddress\",\"type\":\"address\"}],\"name\":\"AccountingGovernorChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldActiveDepositedValidators\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"activeDepositedValidators\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldBeaconChainRewards\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"beaconChainRewards\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"ethToWeth\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"wethToBeSentToVault\",\"type\":\"uint256\"}],\"name\":\"AccountingManuallyFixed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"remainingValidators\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"wethSentToVault\",\"type\":\"uint256\"}],\"name\":\"AccountingValidatorSlashed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"Deposit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"pubkey\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"withdrawal_credentials\",\"type\":\"bytes\"}],\"name\":\"ETHStaked\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"start\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"end\",\"type\":\"uint256\"}],\"name\":\"FuseIntervalUpdated\",\"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\":\"address\",\"name\":\"_oldHarvesterAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_newHarvesterAddress\",\"type\":\"address\"}],\"name\":\"HarvesterAddressesUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"}],\"name\":\"PTokenAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"}],\"name\":\"PTokenRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Paused\",\"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\":\"newAddress\",\"type\":\"address\"}],\"name\":\"RegistratorChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"_oldAddresses\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"_newAddresses\",\"type\":\"address[]\"}],\"name\":\"RewardTokenAddressesUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"rewardToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"RewardTokenCollected\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"pubkey\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"}],\"name\":\"SSVValidatorExitCompleted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"pubkey\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"}],\"name\":\"SSVValidatorExitInitiated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"pubkey\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"}],\"name\":\"SSVValidatorRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Unpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"Withdrawal\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"BEACON_CHAIN_DEPOSIT_CONTRACT\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_ACCUMULATOR_ADDRESS\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MAX_STAKE\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"SSV_NETWORK_ADDRESS\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"SSV_TOKEN_ADDRESS\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"VAULT_ADDRESS\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"WETH_TOKEN_ADDRESS\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"accountingGovernor\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"assetToPToken\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"}],\"name\":\"checkBalance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"claimGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"collectRewardTokens\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"consensusRewards\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"depositAll\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"validatorCount\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"networkFeeIndex\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"index\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"active\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"internalType\":\"struct Cluster\",\"name\":\"cluster\",\"type\":\"tuple\"}],\"name\":\"depositSSV\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"doAccounting\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"accountingValid\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"publicKey\",\"type\":\"bytes\"},{\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"}],\"name\":\"exitSsvValidator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fuseIntervalEnd\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fuseIntervalStart\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRewardTokenAddresses\",\"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\":\"harvesterAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"_rewardTokenAddresses\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"_assets\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"_pTokens\",\"type\":\"address[]\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isGovernor\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_activeDepositedValidators\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_ethToWeth\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_wethToBeSentToVault\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_consensusRewards\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_ethThresholdCheck\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_wethThresholdCheck\",\"type\":\"uint256\"}],\"name\":\"manuallyFixAccounting\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"paused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"platformAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"publicKey\",\"type\":\"bytes\"},{\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"},{\"internalType\":\"bytes\",\"name\":\"sharesData\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"validatorCount\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"networkFeeIndex\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"index\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"active\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"internalType\":\"struct Cluster\",\"name\":\"cluster\",\"type\":\"tuple\"}],\"name\":\"registerSsvValidator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_assetIndex\",\"type\":\"uint256\"}],\"name\":\"removePToken\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"publicKey\",\"type\":\"bytes\"},{\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"validatorCount\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"networkFeeIndex\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"index\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"active\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"internalType\":\"struct Cluster\",\"name\":\"cluster\",\"type\":\"tuple\"}],\"name\":\"removeSsvValidator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"rewardTokenAddresses\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"safeApproveAllTokens\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"setAccountingGovernor\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_fuseIntervalStart\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_fuseIntervalEnd\",\"type\":\"uint256\"}],\"name\":\"setFuseInterval\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_harvesterAddress\",\"type\":\"address\"}],\"name\":\"setHarvesterAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"}],\"name\":\"setPTokenAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"setRegistrator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"_rewardTokenAddresses\",\"type\":\"address[]\"}],\"name\":\"setRewardTokenAddresses\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"pubkey\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"depositDataRoot\",\"type\":\"bytes32\"}],\"internalType\":\"struct ValidatorStakeData[]\",\"name\":\"validators\",\"type\":\"tuple[]\"}],\"name\":\"stakeEth\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"}],\"name\":\"supportsAsset\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"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\":\"validatorRegistrator\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"validatorsStates\",\"outputs\":[{\"internalType\":\"enum ValidatorRegistrator.VALIDATOR_STATE\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"vaultAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"withdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdrawAll\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"author\":\"Origin Protocol Inc\",\"kind\":\"dev\",\"methods\":{\"checkBalance(address)\":{\"params\":{\"_asset\":\"Address of weth asset\"},\"returns\":{\"balance\":\" Total value of (W)ETH\"}},\"constructor\":{\"params\":{\"_baseConfig\":\"Base strategy config with platformAddress (ERC-4626 Vault contract), eg sfrxETH or sDAI, and vaultAddress (OToken Vault contract), eg VaultProxy or OETHVaultProxy\",\"_beaconChainDepositContract\":\"Address of the beacon chain deposit contract\",\"_feeAccumulator\":\"Address of the fee accumulator receiving execution layer validator rewards\",\"_ssvNetwork\":\"Address of the SSV Network contract\",\"_ssvToken\":\"Address of the Erc20 SSV Token contract\",\"_wethAddress\":\"Address of the Erc20 WETH Token contract\"}},\"deposit(address,uint256)\":{\"params\":{\"_amount\":\"Amount of assets that were transferred to the strategy by the vault.\",\"_asset\":\"Address of asset to deposit. Has to be WETH.\"}},\"depositSSV(uint64[],uint256,(uint32,uint64,uint64,bool,uint256))\":{\"details\":\"A SSV cluster is defined by the SSVOwnerAddress and the set of operatorIds. uses \\\"onlyStrategist\\\" modifier so continuous front-running can't DOS our maintenance service that tries to top up SSV tokens.\",\"params\":{\"cluster\":\"The SSV cluster details that must be derived from emitted events from the SSVNetwork contract.\"}},\"doAccounting()\":{\"details\":\"This function could in theory be permission-less but lets allow only the Registrator (Defender Action) to call it for now.\"},\"getRewardTokenAddresses()\":{\"returns\":{\"_0\":\"address[] the reward token addresses.\"}},\"initialize(address[],address[],address[])\":{\"params\":{\"_assets\":\"Addresses of initial supported assets\",\"_pTokens\":\"Platform Token corresponding addresses\",\"_rewardTokenAddresses\":\"Address of reward token for platform\"}},\"manuallyFixAccounting(uint256,uint256,uint256,uint256,uint256,uint256)\":{\"details\":\"allow the accounting governor to fix the accounting of this strategy and unpause\",\"params\":{\"_activeDepositedValidators\":\"the override value of activeDepositedValidators\",\"_consensusRewards\":\"the override value for consensusRewards\",\"_ethThresholdCheck\":\"maximum allowed ETH balance on the contract for the function to run\",\"_ethToWeth\":\"the amount of ETH to be converted to WETH\",\"_wethThresholdCheck\":\"maximum allowed WETH balance on the contract for the function to run the above 2 checks are done so transaction doesn't get front run and cause unexpected behaviour\",\"_wethToBeSentToVault\":\"the amount of WETH to be sent to the Vault\"}},\"paused()\":{\"details\":\"Returns true if the contract is paused, and false otherwise.\"},\"removePToken(uint256)\":{\"params\":{\"_assetIndex\":\"Index of the asset to be removed\"}},\"setHarvesterAddress(address)\":{\"params\":{\"_harvesterAddress\":\"Address of the harvester contract.\"}},\"setPTokenAddress(address,address)\":{\"params\":{\"_asset\":\"Address for the asset\",\"_pToken\":\"Address for the corresponding platform token\"}},\"setRewardTokenAddresses(address[])\":{\"params\":{\"_rewardTokenAddresses\":\"Array of reward token addresses\"}},\"stakeEth((bytes,bytes,bytes32)[])\":{\"params\":{\"validators\":\"A list of validator data needed to stake. The `ValidatorStakeData` struct contains the pubkey, signature and depositDataRoot. Only the registrator can call this function.\"}},\"supportsAsset(address)\":{\"params\":{\"_asset\":\"The address of the asset token.\"}},\"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\"}},\"withdraw(address,address,uint256)\":{\"params\":{\"_amount\":\"Amount of WETH to withdraw\",\"_asset\":\"WETH to withdraw\",\"_recipient\":\"Address to receive withdrawn assets\"}}},\"stateVariables\":{\"FEE_ACCUMULATOR_ADDRESS\":{\"details\":\"this address will receive Execution layer rewards - These are rewards earned for executing transactions on the Ethereum network as part of block proposals. They include priority fees (fees paid by users for their transactions to be included) and MEV rewards (rewards for arranging transactions in a way that benefits the validator).\"}},\"title\":\"Native Staking SSV Strategy\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"BEACON_CHAIN_DEPOSIT_CONTRACT()\":{\"notice\":\"The address of the beacon chain deposit contract\"},\"FEE_ACCUMULATOR_ADDRESS()\":{\"notice\":\"Fee collector address\"},\"MAX_STAKE()\":{\"notice\":\"The maximum amount of ETH that can be staked by a validator\"},\"SSV_NETWORK_ADDRESS()\":{\"notice\":\"The address of the SSV Network contract used to interface with\"},\"SSV_TOKEN_ADDRESS()\":{\"notice\":\"SSV ERC20 token that serves as a payment for operating SSV validators\"},\"VAULT_ADDRESS()\":{\"notice\":\"Address of the OETH Vault proxy contract\"},\"WETH_TOKEN_ADDRESS()\":{\"notice\":\"The address of the Wrapped ETH (WETH) token contract\"},\"accountingGovernor()\":{\"notice\":\"Governor that can manually correct the accounting\"},\"assetToPToken(address)\":{\"notice\":\"asset => pToken (Platform Specific Token Address)\"},\"checkBalance(address)\":{\"notice\":\"Returns the total value of (W)ETH that is staked to the validators and WETH deposits that are still to be staked. This does not include ETH from consensus rewards sitting in this strategy or ETH from MEV rewards in the FeeAccumulator. These rewards are harvested and sent to the Dripper so will eventually be sent to the Vault as WETH.\"},\"claimGovernance()\":{\"notice\":\"Claim Governance of the contract to a new account (`newGovernor`). Can only be called by the new Governor.\"},\"collectRewardTokens()\":{\"notice\":\"Collect accumulated reward token and send to Vault.\"},\"consensusRewards()\":{\"notice\":\"Keeps track of the total consensus rewards swept from the beacon chain\"},\"deposit(address,uint256)\":{\"notice\":\"Unlike other strategies, this does not deposit assets into the underlying platform. It just checks the asset is WETH and emits the Deposit event. To deposit WETH into validators `registerSsvValidator` and `stakeEth` must be used. Will NOT revert if the strategy is paused from an accounting failure.\"},\"depositAll()\":{\"notice\":\"Unlike other strategies, this does not deposit assets into the underlying platform. It just emits the Deposit event. To deposit WETH into validators `registerSsvValidator` and `stakeEth` must be used. Will NOT revert if the strategy is paused from an accounting failure.\"},\"depositSSV(uint64[],uint256,(uint32,uint64,uint64,bool,uint256))\":{\"notice\":\"Deposits more SSV Tokens to the SSV Network contract which is used to pay the SSV Operators.\"},\"doAccounting()\":{\"notice\":\"This notion page offers a good explanation of how the accounting functions https://www.notion.so/originprotocol/Limited-simplified-native-staking-accounting-67a217c8420d40678eb943b9da0ee77d In short, after dividing by 32, if the ETH remaining on the contract falls between 0 and fuseIntervalStart, the accounting function will treat that ETH as Beacon chain consensus rewards. On the contrary, if after dividing by 32, the ETH remaining on the contract falls between fuseIntervalEnd and 32, the accounting function will treat that as a validator slashing.Perform the accounting attributing beacon chain ETH to either full or partial withdrawals. Returns true when accounting is valid and fuse isn't \\\"blown\\\". Returns false when fuse is blown.\"},\"exitSsvValidator(bytes,uint64[])\":{\"notice\":\"Exit a validator from the Beacon chain. The staked ETH will eventually swept to this native staking strategy. Only the registrator can call this function.\"},\"fuseIntervalEnd()\":{\"notice\":\"end of fuse interval\"},\"fuseIntervalStart()\":{\"notice\":\"start of fuse interval\"},\"getRewardTokenAddresses()\":{\"notice\":\"Get the reward token addresses.\"},\"governor()\":{\"notice\":\"Returns the address of the current Governor.\"},\"harvesterAddress()\":{\"notice\":\"Address of the Harvester contract allowed to collect reward tokens\"},\"initialize(address[],address[],address[])\":{\"notice\":\"initialize function, to set up initial internal state\"},\"isGovernor()\":{\"notice\":\"Returns true if the caller is the current Governor.\"},\"platformAddress()\":{\"notice\":\"Address of the underlying platform\"},\"registerSsvValidator(bytes,uint64[],bytes,uint256,(uint32,uint64,uint64,bool,uint256))\":{\"notice\":\"Registers a new validator in the SSV Cluster. Only the registrator can call this function.\"},\"removePToken(uint256)\":{\"notice\":\"Remove a supported asset by passing its index. This method can only be called by the system Governor\"},\"removeSsvValidator(bytes,uint64[],(uint32,uint64,uint64,bool,uint256))\":{\"notice\":\"Remove a validator from the SSV Cluster. Make sure `exitSsvValidator` is called before and the validate has exited the Beacon chain. If removed before the validator has exited the beacon chain will result in the validator being slashed. Only the registrator can call this function.\"},\"rewardTokenAddresses(uint256)\":{\"notice\":\"Address of the reward tokens. eg CRV, BAL, CVX, AURA\"},\"safeApproveAllTokens()\":{\"notice\":\"Approves the SSV Network contract to transfer SSV tokens for deposits\"},\"setFuseInterval(uint256,uint256)\":{\"notice\":\"set fuse interval values\"},\"setHarvesterAddress(address)\":{\"notice\":\"Set the Harvester contract that can collect rewards.\"},\"setPTokenAddress(address,address)\":{\"notice\":\"Provide support for asset by passing its pToken address. This method can only be called by the system Governor\"},\"setRegistrator(address)\":{\"notice\":\"Set the address of the registrator which can register, exit and remove validators\"},\"setRewardTokenAddresses(address[])\":{\"notice\":\"Set the reward token addresses. Any old addresses will be overwritten.\"},\"stakeEth((bytes,bytes,bytes32)[])\":{\"notice\":\"Stakes WETH to the node validators\"},\"supportsAsset(address)\":{\"notice\":\"Returns bool indicating whether asset is supported by strategy.\"},\"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 strategy contracts, i.e. mistaken sends.\"},\"validatorRegistrator()\":{\"notice\":\"Address of the registrator - allowed to register, exit and remove validators\"},\"validatorsStates(bytes32)\":{\"notice\":\"State of the validators keccak256(pubKey) => state\"},\"vaultAddress()\":{\"notice\":\"Address of the OToken vault\"},\"withdraw(address,address,uint256)\":{\"notice\":\"Withdraw WETH from this contract. Used only if some WETH for is lingering on the contract. That can happen when: - the deposit was not a multiple of 32 WETH - someone sent WETH directly to this contract Will NOT revert if the strategy is paused from an accounting failure.\"},\"withdrawAll()\":{\"notice\":\"transfer all WETH deposits back to the vault. This does not withdraw from the validators. That has to be done separately with the `exitSsvValidator` and `removeSsvValidator` operations. This does not withdraw any execution rewards from the FeeAccumulator or consensus rewards in this strategy. Any ETH in this strategy that was swept from a full validator withdrawal will not be withdrawn. ETH from full validator withdrawals is sent to the Vault using `doAccounting`. Will NOT revert if the strategy is paused from an accounting failure.\"}},\"notice\":\"Strategy to deploy funds into DVT validators powered by the SSV Network\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol\":\"NativeStakingSSVStrategy\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"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\",\"keccak256\":\"0xe68ed7fb8766ed1e888291f881e36b616037f852b37d96877045319ad298ba87\",\"license\":\"MIT\"},\"@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/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\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"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/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\",\"keccak256\":\"0x598f90bdbc854250bbd5991426bfb43367207e64e33109c41aa8b54323fd8d8e\",\"license\":\"MIT\"},\"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 error ApprovalNotWithinTimeframe();\\n error CallerNotOwner();\\n error CallerNotWhitelisted();\\n error ClusterAlreadyEnabled();\\n error ClusterDoesNotExists();\\n error ClusterIsLiquidated();\\n error ClusterNotLiquidatable();\\n error ExceedValidatorLimit();\\n error FeeExceedsIncreaseLimit();\\n error FeeIncreaseNotAllowed();\\n error FeeTooHigh();\\n error FeeTooLow();\\n error IncorrectClusterState();\\n error IncorrectValidatorState();\\n error InsufficientBalance();\\n error InvalidOperatorIdsLength();\\n error InvalidPublicKeyLength();\\n error MaxValueExceeded();\\n error NewBlockPeriodIsBelowMinimum();\\n error NoFeeDeclared();\\n error NotAuthorized();\\n error OperatorAlreadyExists();\\n error OperatorDoesNotExist();\\n error OperatorsListNotUnique();\\n error SameFeeChangeNotAllowed();\\n error TargetModuleDoesNotExist();\\n error TokenTransferFailed();\\n error UnsortedOperatorsList();\\n error ValidatorAlreadyExists();\\n error ValidatorDoesNotExist();\\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 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 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 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\",\"keccak256\":\"0x76e2c5148727b72752939b06fee7abc1f732c18970b8c7db7fe7cdfe74629d36\",\"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/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/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\",\"keccak256\":\"0x05b7dce6c24d3cd4e48b5c6346d86e5e40ecc3291bcdf3f3ef091c98fc826519\",\"license\":\"MIT\"},\"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\\nimport { Governable } from \\\"../../governance/Governable.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 is Governable {\\n /// @notice The address of the Native Staking Strategy\\n address public immutable STRATEGY;\\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 }\\n}\\n\",\"keccak256\":\"0xf47bcc46ce70f649f061bec3d2303f376a15700ba18fe471fba823f60bdfed8b\",\"license\":\"MIT\"},\"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\\\";\\n\\nimport { InitializableAbstractStrategy } from \\\"../../utils/InitializableAbstractStrategy.sol\\\";\\nimport { ISSVNetwork, Cluster } from \\\"../../interfaces/ISSVNetwork.sol\\\";\\nimport { IWETH9 } from \\\"../../interfaces/IWETH9.sol\\\";\\nimport { FeeAccumulator } from \\\"./FeeAccumulator.sol\\\";\\nimport { ValidatorAccountant } from \\\"./ValidatorAccountant.sol\\\";\\nimport { Cluster } from \\\"../../interfaces/ISSVNetwork.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\\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_ADDRESS;\\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 public immutable FEE_ACCUMULATOR_ADDRESS;\\n\\n // For future use\\n uint256[50] 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 _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 address _feeAccumulator,\\n address _beaconChainDepositContract\\n )\\n InitializableAbstractStrategy(_baseConfig)\\n ValidatorAccountant(\\n _wethAddress,\\n _baseConfig.vaultAddress,\\n _beaconChainDepositContract,\\n _ssvNetwork\\n )\\n {\\n SSV_TOKEN_ADDRESS = _ssvToken;\\n FEE_ACCUMULATOR_ADDRESS = _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 /// @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_TOKEN_ADDRESS).deposit{ value: ethRewards }();\\n\\n emit RewardTokenCollected(\\n harvesterAddress,\\n WETH_TOKEN_ADDRESS,\\n ethRewards\\n );\\n IERC20(WETH_TOKEN_ADDRESS).safeTransfer(\\n harvesterAddress,\\n ethRewards\\n );\\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_TOKEN_ADDRESS, \\\"Unsupported asset\\\");\\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_TOKEN_ADDRESS).balanceOf(\\n address(this)\\n );\\n if (wethBalance > 0) {\\n _deposit(WETH_TOKEN_ADDRESS, wethBalance);\\n }\\n }\\n\\n /// @notice Withdraw WETH from this contract. Used only if some WETH for is lingering on the contract. That\\n /// can happen when:\\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 _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 emit Withdrawal(_asset, address(0), _amount);\\n IERC20(_asset).safeTransfer(_recipient, _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_TOKEN_ADDRESS).balanceOf(\\n address(this)\\n );\\n if (wethBalance > 0) {\\n _withdraw(vaultAddress, WETH_TOKEN_ADDRESS, wethBalance);\\n }\\n }\\n\\n function _abstractSetPToken(address _asset, address) internal override {}\\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_TOKEN_ADDRESS, \\\"Unsupported asset\\\");\\n\\n balance =\\n // add the ETH that has been staked in validators\\n activeDepositedValidators *\\n 32 ether +\\n // add the WETH in the strategy from deposits that are still to be staked\\n IERC20(WETH_TOKEN_ADDRESS).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_TOKEN_ADDRESS;\\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_ADDRESS).approve(\\n SSV_NETWORK_ADDRESS,\\n type(uint256).max\\n );\\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_TOKEN_ADDRESS,\\n \\\"eth not from allowed contracts\\\"\\n );\\n }\\n}\\n\",\"keccak256\":\"0xf591c47516bc68b9b0a220b7d7c6b96f87315b03ea8636b47ca5c6540e59fb85\",\"license\":\"MIT\"},\"contracts/strategies/NativeStaking/ValidatorAccountant.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport { Pausable } from \\\"@openzeppelin/contracts/security/Pausable.sol\\\";\\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 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 MAX_STAKE = 32 ether;\\n\\n /// @notice Keeps track of the total consensus rewards swept from the beacon chain\\n uint256 public consensusRewards = 0;\\n\\n /// @notice start of fuse interval\\n uint256 public fuseIntervalStart = 0;\\n /// @notice end of fuse interval\\n uint256 public fuseIntervalEnd = 0;\\n /// @notice Governor that can manually correct the accounting\\n address public accountingGovernor;\\n\\n uint256[50] 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 AccountingGovernorChanged(address newAddress);\\n event AccountingConsensusRewards(uint256 amount);\\n\\n event AccountingManuallyFixed(\\n uint256 oldActiveDepositedValidators,\\n uint256 activeDepositedValidators,\\n uint256 oldBeaconChainRewards,\\n uint256 beaconChainRewards,\\n uint256 ethToWeth,\\n uint256 wethToBeSentToVault\\n );\\n\\n /// @dev Throws if called by any account other than the Accounting Governor\\n modifier onlyAccountingGovernor() {\\n require(\\n msg.sender == accountingGovernor,\\n \\\"Caller is not the Accounting Governor\\\"\\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 constructor(\\n address _wethAddress,\\n address _vaultAddress,\\n address _beaconChainDepositContract,\\n address _ssvNetwork\\n )\\n ValidatorRegistrator(\\n _wethAddress,\\n _vaultAddress,\\n _beaconChainDepositContract,\\n _ssvNetwork\\n )\\n {}\\n\\n function setAccountingGovernor(address _address) external onlyGovernor {\\n emit AccountingGovernorChanged(_address);\\n accountingGovernor = _address;\\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 _fuseIntervalStart < 32 ether &&\\n _fuseIntervalEnd < 32 ether &&\\n _fuseIntervalEnd - _fuseIntervalStart >= 4 ether,\\n \\\"incorrect fuse interval\\\"\\n );\\n\\n emit FuseIntervalUpdated(_fuseIntervalStart, _fuseIntervalEnd);\\n\\n fuseIntervalStart = _fuseIntervalStart;\\n fuseIntervalEnd = _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 /* solhint-enable max-line-length */\\n function doAccounting()\\n external\\n onlyRegistrator\\n whenNotPaused\\n returns (bool accountingValid)\\n {\\n if (address(this).balance < consensusRewards) {\\n // pause and fail the accounting\\n _pause();\\n return false;\\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 >= MAX_STAKE) {\\n uint256 fullyWithdrawnValidators = newSweptETH / MAX_STAKE;\\n activeDepositedValidators -= fullyWithdrawnValidators;\\n\\n uint256 wethToVault = MAX_STAKE * fullyWithdrawnValidators;\\n IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: wethToVault }();\\n IWETH9(WETH_TOKEN_ADDRESS).transfer(VAULT_ADDRESS, 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 < 32 ether, \\\"unexpected accounting\\\");\\n\\n // If no Beacon chain consensus rewards swept\\n if (ethRemaining == 0) {\\n // do nothing\\n return accountingValid;\\n }\\n // Beacon chain consensus rewards swept (partial validator withdrawals)\\n else if (ethRemaining < fuseIntervalStart) {\\n // solhint-disable-next-line reentrancy\\n consensusRewards += ethRemaining;\\n emit AccountingConsensusRewards(ethRemaining);\\n }\\n // Beacon chain consensus rewards swept but also a slashed validator fully exited\\n else if (ethRemaining > fuseIntervalEnd) {\\n IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: ethRemaining }();\\n IWETH9(WETH_TOKEN_ADDRESS).transfer(VAULT_ADDRESS, ethRemaining);\\n activeDepositedValidators -= 1;\\n\\n emit AccountingValidatorSlashed(\\n activeDepositedValidators,\\n ethRemaining\\n );\\n }\\n // Oh no... Fuse is blown. The governor (Multisig not OGV Governor) needs to set the\\n // record straight by manually set the accounting values.\\n else {\\n // will emit a paused event\\n _pause();\\n accountingValid = false;\\n }\\n }\\n\\n /// @dev allow the accounting governor to fix the accounting of this strategy and unpause\\n /// @param _activeDepositedValidators the override value of activeDepositedValidators\\n /// @param _ethToWeth the amount of ETH to be converted to WETH\\n /// @param _wethToBeSentToVault the amount of WETH to be sent to the Vault\\n /// @param _consensusRewards the override value for consensusRewards\\n /// @param _ethThresholdCheck maximum allowed ETH balance on the contract for the function to run\\n /// @param _wethThresholdCheck maximum allowed WETH balance on the contract for the function to run\\n /// the above 2 checks are done so transaction doesn't get front run and cause\\n /// unexpected behaviour\\n function manuallyFixAccounting(\\n uint256 _activeDepositedValidators,\\n uint256 _ethToWeth,\\n uint256 _wethToBeSentToVault,\\n uint256 _consensusRewards,\\n uint256 _ethThresholdCheck,\\n uint256 _wethThresholdCheck\\n ) external onlyAccountingGovernor whenPaused {\\n uint256 ethBalance = address(this).balance;\\n uint256 wethBalance = IWETH9(WETH_TOKEN_ADDRESS).balanceOf(\\n address(this)\\n );\\n\\n require(\\n ethBalance <= _ethThresholdCheck &&\\n wethBalance <= _wethThresholdCheck,\\n \\\"over accounting threshold\\\"\\n );\\n\\n emit AccountingManuallyFixed(\\n activeDepositedValidators,\\n _activeDepositedValidators,\\n consensusRewards,\\n _consensusRewards,\\n _ethToWeth,\\n _wethToBeSentToVault\\n );\\n\\n activeDepositedValidators = _activeDepositedValidators;\\n consensusRewards = _consensusRewards;\\n if (_ethToWeth > 0) {\\n require(_ethToWeth <= ethBalance, \\\"insufficient ETH\\\");\\n\\n IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: _ethToWeth }();\\n }\\n if (_wethToBeSentToVault > 0) {\\n IWETH9(WETH_TOKEN_ADDRESS).transfer(\\n VAULT_ADDRESS,\\n _wethToBeSentToVault\\n );\\n }\\n\\n _unpause();\\n }\\n}\\n\",\"keccak256\":\"0x44a1fc3a3e324b3ae63b39d2c5ae0a3e8a1b71b8dbf7e604b70d81ef5b170754\",\"license\":\"MIT\"},\"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 address of the Wrapped ETH (WETH) token contract\\n address public immutable WETH_TOKEN_ADDRESS;\\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_ADDRESS;\\n /// @notice Address of the OETH Vault proxy contract\\n address public immutable VAULT_ADDRESS;\\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 activeDepositedValidators;\\n /// @notice State of the validators keccak256(pubKey) => state\\n mapping(bytes32 => VALIDATOR_STATE) public validatorsStates;\\n\\n // For future use\\n uint256[50] private __gap;\\n\\n enum VALIDATOR_STATE {\\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 newAddress);\\n event ETHStaked(bytes pubkey, uint256 amount, bytes withdrawal_credentials);\\n event SSVValidatorRegistered(bytes pubkey, uint64[] operatorIds);\\n event SSVValidatorExitInitiated(bytes pubkey, uint64[] operatorIds);\\n event SSVValidatorExitCompleted(bytes pubkey, uint64[] operatorIds);\\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 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 constructor(\\n address _wethAddress,\\n address _vaultAddress,\\n address _beaconChainDepositContract,\\n address _ssvNetwork\\n ) {\\n WETH_TOKEN_ADDRESS = _wethAddress;\\n BEACON_CHAIN_DEPOSIT_CONTRACT = _beaconChainDepositContract;\\n SSV_NETWORK_ADDRESS = _ssvNetwork;\\n VAULT_ADDRESS = _vaultAddress;\\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 emit RegistratorChanged(_address);\\n validatorRegistrator = _address;\\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 function stakeEth(ValidatorStakeData[] calldata validators)\\n external\\n onlyRegistrator\\n whenNotPaused\\n {\\n uint256 requiredETH = validators.length * 32 ether;\\n\\n // Check there is enough WETH from the deposits sitting in this strategy contract\\n require(\\n requiredETH <= IWETH9(WETH_TOKEN_ADDRESS).balanceOf(address(this)),\\n \\\"insufficient WETH\\\"\\n );\\n\\n // Convert required ETH from WETH\\n IWETH9(WETH_TOKEN_ADDRESS).withdraw(requiredETH);\\n\\n // For each validator\\n for (uint256 i = 0; i < validators.length; ) {\\n bytes32 pubkeyHash = keccak256(validators[i].pubkey);\\n VALIDATOR_STATE currentState = validatorsStates[pubkeyHash];\\n\\n require(\\n currentState == VALIDATOR_STATE.REGISTERED,\\n \\\"Validator not registered\\\"\\n );\\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 withdrawal_credentials = abi.encodePacked(\\n bytes1(0x01),\\n bytes11(0),\\n address(this)\\n );\\n IDepositContract(BEACON_CHAIN_DEPOSIT_CONTRACT).deposit(\\n validators[i].pubkey,\\n withdrawal_credentials,\\n validators[i].signature,\\n validators[i].depositDataRoot\\n );\\n\\n activeDepositedValidators += 1;\\n emit ETHStaked(\\n validators[i].pubkey,\\n 32 ether,\\n withdrawal_credentials\\n );\\n\\n validatorsStates[pubkeyHash] = VALIDATOR_STATE.STAKED;\\n\\n unchecked {\\n ++i;\\n }\\n }\\n }\\n\\n /// @notice Registers a new validator in the SSV Cluster.\\n /// Only the registrator can call this function.\\n function registerSsvValidator(\\n bytes calldata publicKey,\\n uint64[] calldata operatorIds,\\n bytes calldata sharesData,\\n uint256 amount,\\n Cluster calldata cluster\\n ) external onlyRegistrator whenNotPaused {\\n ISSVNetwork(SSV_NETWORK_ADDRESS).registerValidator(\\n publicKey,\\n operatorIds,\\n sharesData,\\n amount,\\n cluster\\n );\\n validatorsStates[keccak256(publicKey)] = VALIDATOR_STATE.REGISTERED;\\n emit SSVValidatorRegistered(publicKey, operatorIds);\\n }\\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 function exitSsvValidator(\\n bytes calldata publicKey,\\n uint64[] calldata operatorIds\\n ) external onlyRegistrator whenNotPaused {\\n VALIDATOR_STATE currentState = validatorsStates[keccak256(publicKey)];\\n require(currentState == VALIDATOR_STATE.STAKED, \\\"Validator not staked\\\");\\n\\n ISSVNetwork(SSV_NETWORK_ADDRESS).exitValidator(publicKey, operatorIds);\\n emit SSVValidatorExitInitiated(publicKey, operatorIds);\\n\\n validatorsStates[keccak256(publicKey)] = VALIDATOR_STATE.EXITING;\\n }\\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 function removeSsvValidator(\\n bytes calldata publicKey,\\n uint64[] calldata operatorIds,\\n Cluster calldata cluster\\n ) external onlyRegistrator whenNotPaused {\\n VALIDATOR_STATE currentState = validatorsStates[keccak256(publicKey)];\\n require(\\n currentState == VALIDATOR_STATE.EXITING,\\n \\\"Validator not exiting\\\"\\n );\\n\\n ISSVNetwork(SSV_NETWORK_ADDRESS).removeValidator(\\n publicKey,\\n operatorIds,\\n cluster\\n );\\n emit SSVValidatorExitCompleted(publicKey, operatorIds);\\n\\n validatorsStates[keccak256(publicKey)] = VALIDATOR_STATE.EXIT_COMPLETE;\\n }\\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 cluster The SSV cluster details that must be derived from emitted events from the SSVNetwork contract.\\n function depositSSV(\\n uint64[] memory operatorIds,\\n uint256 amount,\\n Cluster memory cluster\\n ) external onlyStrategist {\\n ISSVNetwork(SSV_NETWORK_ADDRESS).deposit(\\n address(this),\\n operatorIds,\\n amount,\\n cluster\\n );\\n }\\n}\\n\",\"keccak256\":\"0x3caea29d952f616674ae0c9c80a161cc5d07b956b2dd219f8674119e41141c53\",\"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/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\",\"keccak256\":\"0x5e17bb3db9f9e1014b7c5c836547f8fa81e02af7568c0bb8f2a2e0e7c2192db4\",\"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/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": "0x610180604052600060685560006069556000606a553480156200002157600080fd5b5060405162004ce338038062004ce3833981016040819052620000449162000147565b8585876020015183868383838362000062336200011760201b60201c565b60008051602062004cc3833981519152546040516001600160a01b03909116906000907fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a908290a36033805460ff191690556001600160601b0319606094851b811660805291841b821660a052831b811660c05290821b811660e0528651821b811661010052602090960151811b86166101205298891b851661014052505050509190931b1661016052506200022292505050565b60008051602062004cc383398151915255565b80516001600160a01b03811681146200014257600080fd5b919050565b60008060008060008086880360e08112156200016257600080fd5b60408112156200017157600080fd5b50604080519081016001600160401b0381118282101715620001a357634e487b7160e01b600052604160045260246000fd5b604052620001b1886200012a565b8152620001c1602089016200012a565b60208201529550620001d6604088016200012a565b9450620001e6606088016200012a565b9350620001f6608088016200012a565b92506200020660a088016200012a565b91506200021660c088016200012a565b90509295509295509295565b60805160601c60a05160601c60c05160601c60e05160601c6101005160601c6101205160601c6101405160601c6101605160601c614904620003bf600039600081816102c2015281816109b301526132ee01526000818161059801526127ba01526000818161046c01528181610db601528181611d0301528181611e7c01528181612b9b0152612e230152600061097f0152600081816106f101528181610b4e01528181611b4001528181611c010152818161231601526125650152600081816109fc01528181610c540152818161172b0152818161278a015281816128a20152612d190152600081816108cb015261147c0152600081816102f4015281816104f6015281816107c201528181610ab501528181610e2b01528181610ffa01528181611082015281816112310152818161130c0152818161192201528181611ab001528181611b6f01528181611ded01528181611e9d0152818161229001528181612345015281816124df0152818161259401528181612eae01528181612f3d015281816133f30152818161347801526134ec01526149046000f3fe6080604052600436106102b25760003560e01c8063853828b611610175578063c2e1e3f4116100dc578063d9caed1211610095578063dd505df61161006f578063dd505df6146109a1578063de5f6268146109d5578063f1188e40146109ea578063f6ca71b014610a1e57600080fd5b8063d9caed121461092d578063d9f00ec71461094d578063dbe55e561461096d57600080fd5b8063c2e1e3f414610867578063c7af335214610887578063c98517c51461089c578063cceab750146108b9578063d38bfff4146108ed578063d5c360f61461090d57600080fd5b8063a4f98af41161012e578063a4f98af414610790578063aa388af6146107a5578063ab12edf5146107f2578063ad1728cb14610812578063af37dcbe14610827578063bb1b918d1461084757600080fd5b8063853828b6146106a557806387bae867146106ba5780639092c31c146106df5780639136616a1461071357806396d538bb146107335780639da0e4621461075357600080fd5b80635c975abb116102195780636ef38795116101d25780636ef38795146105fa57806371a735f31461061a5780637b2d9b2c1461063a5780637e20fffa1461065a578063842f5c461461067a5780638456cb591461069057600080fd5b80635c975abb1461052d5780635d36b190146105515780635f515226146105665780636093d3801461058657806367c7066c146105ba5780636e811d38146105da57600080fd5b8063430bf08a1161026b578063430bf08a1461045a578063435356d11461048e57806347e7ef24146104ae578063484be812146104ce578063579a7e1a146104e45780635a063f631461051857600080fd5b80630c340a241461036e5780630ed57b3a146103a05780630fc3b4c4146103c05780631072cbea146103f657806322495dc8146104165780633c8649591461043657600080fd5b3661036957336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614806103165750336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016145b6103675760405162461bcd60e51b815260206004820152601e60248201527f657468206e6f742066726f6d20616c6c6f77656420636f6e747261637473000060448201526064015b60405180910390fd5b005b600080fd5b34801561037a57600080fd5b50610383610a40565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156103ac57600080fd5b506103676103bb366004613ce6565b610a5d565b3480156103cc57600080fd5b506103836103db366004613cac565b60a0602052600090815260409020546001600160a01b031681565b34801561040257600080fd5b50610367610411366004613d60565b610a8f565b34801561042257600080fd5b50610367610431366004613e54565b610b4c565b34801561044257600080fd5b5061044c60695481565b604051908152602001610397565b34801561046657600080fd5b506103837f000000000000000000000000000000000000000000000000000000000000000081565b34801561049a57600080fd5b506103676104a9366004613dcd565b610cc6565b3480156104ba57600080fd5b506103676104c9366004613d60565b610dab565b3480156104da57600080fd5b5061044c606a5481565b3480156104f057600080fd5b506103837f000000000000000000000000000000000000000000000000000000000000000081565b34801561052457600080fd5b50610367610eb1565b34801561053957600080fd5b5060335460ff165b6040519015158152602001610397565b34801561055d57600080fd5b50610367610f50565b34801561057257600080fd5b5061044c610581366004613cac565b610ff6565b34801561059257600080fd5b506103837f000000000000000000000000000000000000000000000000000000000000000081565b3480156105c657600080fd5b5060a454610383906001600160a01b031681565b3480156105e657600080fd5b506103676105f5366004613cac565b61112a565b34801561060657600080fd5b50610367610615366004613d8c565b6111b2565b34801561062657600080fd5b50610367610635366004614062565b611634565b34801561064657600080fd5b50610383610655366004613f2a565b61182d565b34801561066657600080fd5b5061036761067536600461411e565b611857565b34801561068657600080fd5b5061044c60685481565b34801561069c57600080fd5b50610367611bff565b3480156106b157600080fd5b50610367611cf8565b3480156106c657600080fd5b506033546103839061010090046001600160a01b031681565b3480156106eb57600080fd5b506103837f000000000000000000000000000000000000000000000000000000000000000081565b34801561071f57600080fd5b5061036761072e366004613f2a565b611eca565b34801561073f57600080fd5b5061036761074e366004613d8c565b612095565b34801561075f57600080fd5b5061078361076e366004613f2a565b60356020526000908152604090205460ff1681565b6040516103979190614565565b34801561079c57600080fd5b506105416121b5565b3480156107b157600080fd5b506105416107c0366004613cac565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0390811691161490565b3480156107fe57600080fd5b5061036761080d3660046140fc565b612677565b34801561081e57600080fd5b50610367612773565b34801561083357600080fd5b50606b54610383906001600160a01b031681565b34801561085357600080fd5b50610367610862366004613fae565b612839565b34801561087357600080fd5b50610367610882366004613cac565b6129ac565b34801561089357600080fd5b50610541612a39565b3480156108a857600080fd5b5061044c6801bc16d674ec80000081565b3480156108c557600080fd5b506103837f000000000000000000000000000000000000000000000000000000000000000081565b3480156108f957600080fd5b50610367610908366004613cac565b612a6a565b34801561091957600080fd5b50610367610928366004613cac565b612b0e565b34801561093957600080fd5b50610367610948366004613d1f565b612b90565b34801561095957600080fd5b50610367610968366004613f43565b612c23565b34801561097957600080fd5b506103837f000000000000000000000000000000000000000000000000000000000000000081565b3480156109ad57600080fd5b506103837f000000000000000000000000000000000000000000000000000000000000000081565b3480156109e157600080fd5b50610367612e18565b3480156109f657600080fd5b506103837f000000000000000000000000000000000000000000000000000000000000000081565b348015610a2a57600080fd5b50610a33612f62565b604051610397919061433b565b6000610a586000805160206148af8339815191525490565b905090565b610a65612a39565b610a815760405162461bcd60e51b815260040161035e906145d7565b610a8b8282612fc4565b5050565b610a97612a39565b610ab35760405162461bcd60e51b815260040161035e906145d7565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b039081169083161415610b305760405162461bcd60e51b815260206004820152601f60248201527f43616e6e6f74207472616e7366657220737570706f7274656420617373657400604482015260640161035e565b610a8b610b3b610a40565b6001600160a01b0384169083613123565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b158015610ba557600080fd5b505afa158015610bb9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bdd9190613cc9565b6001600160a01b0316336001600160a01b031614610c3d5760405162461bcd60e51b815260206004820152601c60248201527f43616c6c6572206973206e6f7420746865205374726174656769737400000000604482015260640161035e565b60405163bc26e7e560e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063bc26e7e590610c8f90309087908790879060040161428b565b600060405180830381600087803b158015610ca957600080fd5b505af1158015610cbd573d6000803e3d6000fd5b50505050505050565b610cce612a39565b610cea5760405162461bcd60e51b815260040161035e906145d7565b600054610100900460ff1680610d03575060005460ff16155b610d665760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840161035e565b600054610100900460ff16158015610d88576000805461ffff19166101011790555b610d9384848461317a565b8015610da5576000805461ff00191690555b50505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610df35760405162461bcd60e51b815260040161035e906145a0565b60008051602061488f83398151915280546002811415610e255760405162461bcd60e51b815260040161035e9061466f565b600282557f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316846001600160a01b031614610e9e5760405162461bcd60e51b8152602060048201526011602482015270155b9cdd5c1c1bdc9d195908185cdcd95d607a1b604482015260640161035e565b610ea88484613235565b50600190555050565b60a4546001600160a01b03163314610f0b5760405162461bcd60e51b815260206004820152601b60248201527f43616c6c6572206973206e6f7420746865204861727665737465720000000000604482015260640161035e565b60008051602061488f83398151915280546002811415610f3d5760405162461bcd60e51b815260040161035e9061466f565b60028255610f496132c7565b5060019055565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b031614610feb5760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b606482015260840161035e565b610ff433613515565b565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b03161461106d5760405162461bcd60e51b8152602060048201526011602482015270155b9cdd5c1c1bdc9d195908185cdcd95d607a1b604482015260640161035e565b6040516370a0823160e01b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b1580156110cc57600080fd5b505afa1580156110e0573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061110491906140e3565b60345461111a906801bc16d674ec800000614780565b6111249190614746565b92915050565b611132612a39565b61114e5760405162461bcd60e51b815260040161035e906145d7565b6040516001600160a01b03821681527f83f29c79feb71f8fba9d0fbc4ba5f0982a28b6b1e868b3fc50e6400d100bca0f9060200160405180910390a1603380546001600160a01b0390921661010002610100600160a81b0319909216919091179055565b60335461010090046001600160a01b031633146111e15760405162461bcd60e51b815260040161035e90614638565b60335460ff16156112045760405162461bcd60e51b815260040161035e9061460e565b6000611219826801bc16d674ec800000614780565b6040516370a0823160e01b81523060048201529091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b15801561127b57600080fd5b505afa15801561128f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112b391906140e3565b8111156112f65760405162461bcd60e51b81526020600482015260116024820152700d2dce6eaccccd2c6d2cadce840ae8aa89607b1b604482015260640161035e565b604051632e1a7d4d60e01b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561135857600080fd5b505af115801561136c573d6000803e3d6000fd5b5050505060005b82811015610da557600084848381811061138f5761138f61483f565b90506020028101906113a191906146dd565b6113ab9080614697565b6040516113b992919061425f565b6040805191829003909120600081815260356020529182205490925060ff16908160038111156113eb576113eb614813565b146114385760405162461bcd60e51b815260206004820152601860248201527f56616c696461746f72206e6f7420726567697374657265640000000000000000604482015260640161035e565b60408051600160f81b60208201526000602182018190526bffffffffffffffffffffffff193060601b16602c830152910160405160208183030381529060405290507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663228951188888878181106114bb576114bb61483f565b90506020028101906114cd91906146dd565b6114d79080614697565b848b8b8a8181106114ea576114ea61483f565b90506020028101906114fc91906146dd565b61150a906020810190614697565b8d8d8c81811061151c5761151c61483f565b905060200281019061152e91906146dd565b604001356040518763ffffffff1660e01b8152600401611553969594939291906144ea565b600060405180830381600087803b15801561156d57600080fd5b505af1158015611581573d6000803e3d6000fd5b505050506001603460008282546115989190614746565b909155507ffeb31a79d38edb1b090d516e4df3e273651179c6f2c2ec53a9a22ae015b70ba990508787868181106115d1576115d161483f565b90506020028101906115e391906146dd565b6115ed9080614697565b6801bc16d674ec800000846040516116089493929190614539565b60405180910390a150506000908152603560205260409020805460ff1916600190811790915501611373565b60335461010090046001600160a01b031633146116635760405162461bcd60e51b815260040161035e90614638565b60335460ff16156116865760405162461bcd60e51b815260040161035e9061460e565b600060356000878760405161169c92919061425f565b604080519182900390912082526020820192909252016000205460ff16905060028160038111156116cf576116cf614813565b146117145760405162461bcd60e51b815260206004820152601560248201527456616c696461746f72206e6f742065786974696e6760581b604482015260640161035e565b6040516312b3fc1960e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906312b3fc199061176890899089908990899089906004016144a9565b600060405180830381600087803b15801561178257600080fd5b505af1158015611796573d6000803e3d6000fd5b505050507ff72821b8777f002ccdf6326f1242d9e0f762eb077668b67bebe640535378066d868686866040516117cf9493929190614420565b60405180910390a160036035600088886040516117ed92919061425f565b60408051918290039091208252602082019290925201600020805460ff1916600183600381111561182057611820614813565b0217905550505050505050565b60a5818154811061183d57600080fd5b6000918252602090912001546001600160a01b0316905081565b606b546001600160a01b031633146118bf5760405162461bcd60e51b815260206004820152602560248201527f43616c6c6572206973206e6f7420746865204163636f756e74696e6720476f7660448201526432b93737b960d91b606482015260840161035e565b60335460ff166119085760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b604482015260640161035e565b6040516370a0823160e01b815230600482015247906000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b15801561196c57600080fd5b505afa158015611980573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119a491906140e3565b90508382111580156119b65750828111155b611a025760405162461bcd60e51b815260206004820152601960248201527f6f766572206163636f756e74696e67207468726573686f6c6400000000000000604482015260640161035e565b60345460685460408051928352602083018b9052820152606081018690526080810188905260a081018790527fb2c41d2aedabd456081f30f3b116ce88de1c795a7d4ca787fef373a393f3c5db9060c00160405180910390a1603488905560688590558615611b235781871115611aae5760405162461bcd60e51b815260206004820152601060248201526f0d2dce6eaccccd2c6d2cadce8408aa8960831b604482015260640161035e565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0886040518263ffffffff1660e01b81526004016000604051808303818588803b158015611b0957600080fd5b505af1158015611b1d573d6000803e3d6000fd5b50505050505b8515611bed5760405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018890527f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb90604401602060405180830381600087803b158015611bb357600080fd5b505af1158015611bc7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611beb9190613f0d565b505b611bf56135d6565b5050505050505050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b158015611c5857600080fd5b505afa158015611c6c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c909190613cc9565b6001600160a01b0316336001600160a01b031614611cf05760405162461bcd60e51b815260206004820152601c60248201527f43616c6c6572206973206e6f7420746865205374726174656769737400000000604482015260640161035e565b610ff4613669565b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161480611d475750611d32610a40565b6001600160a01b0316336001600160a01b0316145b611d9f5760405162461bcd60e51b815260206004820152602360248201527f43616c6c6572206973206e6f7420746865205661756c74206f7220476f7665726044820152623737b960e91b606482015260840161035e565b60008051602061488f83398151915280546002811415611dd15760405162461bcd60e51b815260040161035e9061466f565b600282556040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b158015611e3757600080fd5b505afa158015611e4b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e6f91906140e3565b90508015611ec257611ec27f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000836136c1565b505060019055565b611ed2612a39565b611eee5760405162461bcd60e51b815260040161035e906145d7565b60a1548110611f2f5760405162461bcd60e51b815260206004820152600d60248201526c092dcecc2d8d2c840d2dcc8caf609b1b604482015260640161035e565b600060a18281548110611f4457611f4461483f565b60009182526020808320909101546001600160a01b0390811680845260a090925260409092205460a15491935090911690611f819060019061479f565b8310156120035760a18054611f989060019061479f565b81548110611fa857611fa861483f565b60009182526020909120015460a180546001600160a01b039092169185908110611fd457611fd461483f565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505b60a180548061201457612014614829565b60008281526020808220600019908401810180546001600160a01b031990811690915593019093556001600160a01b0385811680835260a0855260409283902080549094169093559051908416815290917f16b7600acff27e39a8a96056b3d533045298de927507f5c1d97e4accde60488c910160405180910390a2505050565b61209d612a39565b6120b95760405162461bcd60e51b815260040161035e906145d7565b8060005b8181101561216c5760008484838181106120d9576120d961483f565b90506020020160208101906120ee9190613cac565b6001600160a01b0316141561215c5760405162461bcd60e51b815260206004820152602e60248201527f43616e206e6f742073657420616e20656d70747920616464726573732061732060448201526d30903932bbb0b932103a37b5b2b760911b606482015260840161035e565b612165816147e2565b90506120bd565b507f04c0b9649497d316554306e53678d5f5f5dbc3a06f97dec13ff4cfe98b986bbc60a584846040516121a193929190614388565b60405180910390a1610da560a58484613a05565b60335460009061010090046001600160a01b031633146121e75760405162461bcd60e51b815260040161035e90614638565b60335460ff161561220a5760405162461bcd60e51b815260040161035e9061460e565b6068544710156122225761221c613669565b50600090565b600060685447612232919061479f565b9050600191506801bc16d674ec800000811061240d57600061225d6801bc16d674ec8000008361475e565b90508060346000828254612271919061479f565b909155506000905061228c826801bc16d674ec800000614780565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b1580156122e957600080fd5b505af11580156122fd573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb92506044019050602060405180830381600087803b15801561238d57600080fd5b505af11580156123a1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123c59190613f0d565b5060345460408051848152602081019290925281018290527fbe7040030ff7b347853214bf49820c6d455fedf58f3815f85c7bc5216993682b9060600160405180910390a150505b60006068544761241d919061479f565b90506801bc16d674ec800000811061246f5760405162461bcd60e51b8152602060048201526015602482015274756e6578706563746564206163636f756e74696e6760581b604482015260640161035e565b8061247957505090565b6069548110156124d35780606860008282546124959190614746565b90915550506040518181527f7a745a2c63a535068f52ceca27debd5297bbad5f7f37ec53d044a59d0362445d906020015b60405180910390a1505090565b606a54811115612666577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b15801561253857600080fd5b505af115801561254c573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb92506044019050602060405180830381600087803b1580156125dc57600080fd5b505af11580156125f0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126149190613f0d565b50600160346000828254612628919061479f565b909155505060345460408051918252602082018390527f6aa7e30787b26429ced603a7aba8b19c4b5d5bcf29a3257da953c8d53bcaa3a691016124c6565b61266e613669565b60009250505090565b61267f612a39565b61269b5760405162461bcd60e51b815260040161035e906145d7565b80821080156126b257506801bc16d674ec80000082105b80156126c657506801bc16d674ec80000081105b80156126e35750673782dace9d9000006126e0838361479f565b10155b61272f5760405162461bcd60e51b815260206004820152601760248201527f696e636f7272656374206675736520696e74657276616c000000000000000000604482015260640161035e565b60408051838152602081018390527fcb8d24e46eb3c402bf344ee60a6576cba9ef2f59ea1af3b311520704924e901a910160405180910390a1606991909155606a55565b60405163095ea7b360e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015260001960248301527f0000000000000000000000000000000000000000000000000000000000000000169063095ea7b390604401602060405180830381600087803b1580156127fe57600080fd5b505af1158015612812573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128369190613f0d565b50565b60335461010090046001600160a01b031633146128685760405162461bcd60e51b815260040161035e90614638565b60335460ff161561288b5760405162461bcd60e51b815260040161035e9061460e565b6040516301ba3ee760e21b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906306e8fb9c906128e5908b908b908b908b908b908b908b908b90600401614447565b600060405180830381600087803b1580156128ff57600080fd5b505af1158015612913573d6000803e3d6000fd5b505050506000603560008a8a60405161292d92919061425f565b60408051918290039091208252602082019290925201600020805460ff1916600183600381111561296057612960614813565b02179055507f75c4a66b2c6c28cf46db7131182a812e4fbbb2f0591377aa83a737909a9b68c38888888860405161299a9493929190614420565b60405180910390a15050505050505050565b6129b4612a39565b6129d05760405162461bcd60e51b815260040161035e906145d7565b60a454604080516001600160a01b03928316815291831660208301527fe48386b84419f4d36e0f96c10cc3510b6fb1a33795620c5098b22472bbe90796910160405180910390a160a480546001600160a01b0319166001600160a01b0392909216919091179055565b6000612a516000805160206148af8339815191525490565b6001600160a01b0316336001600160a01b031614905090565b612a72612a39565b612a8e5760405162461bcd60e51b815260040161035e906145d7565b612ab6817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b0316612ad66000805160206148af8339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b612b16612a39565b612b325760405162461bcd60e51b815260040161035e906145d7565b6040516001600160a01b03821681527ff3dd2b598e2a94dd3f46b414f7c960f8e10a0b0efd00df97d27cdd0fee5c87539060200160405180910390a1606b80546001600160a01b0319166001600160a01b0392909216919091179055565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614612bd85760405162461bcd60e51b815260040161035e906145a0565b60008051602061488f83398151915280546002811415612c0a5760405162461bcd60e51b815260040161035e9061466f565b60028255612c198585856136c1565b5060019055505050565b60335461010090046001600160a01b03163314612c525760405162461bcd60e51b815260040161035e90614638565b60335460ff1615612c755760405162461bcd60e51b815260040161035e9061460e565b6000603560008686604051612c8b92919061425f565b604080519182900390912082526020820192909252016000205460ff1690506001816003811115612cbe57612cbe614813565b14612d025760405162461bcd60e51b815260206004820152601460248201527315985b1a59185d1bdc881b9bdd081cdd185ad95960621b604482015260640161035e565b604051633877322b60e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690633877322b90612d54908890889088908890600401614420565b600060405180830381600087803b158015612d6e57600080fd5b505af1158015612d82573d6000803e3d6000fd5b505050507ff8821da16f5ed966b41e0343c3eff9903af782d74f99f1689dd9d4562b6545b385858585604051612dbb9493929190614420565b60405180910390a16002603560008787604051612dd992919061425f565b60408051918290039091208252602082019290925201600020805460ff19166001836003811115612e0c57612e0c614813565b02179055505050505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614612e605760405162461bcd60e51b815260040161035e906145a0565b60008051602061488f83398151915280546002811415612e925760405162461bcd60e51b815260040161035e9061466f565b600282556040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b158015612ef857600080fd5b505afa158015612f0c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f3091906140e3565b90508015611ec257611ec27f000000000000000000000000000000000000000000000000000000000000000082613235565b606060a5805480602002602001604051908101604052809291908181526020018280548015612fba57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612f9c575b5050505050905090565b6001600160a01b03828116600090815260a0602052604090205416156130215760405162461bcd60e51b81526020600482015260126024820152711c151bdad95b88185b1c9958591e481cd95d60721b604482015260640161035e565b6001600160a01b0382161580159061304157506001600160a01b03811615155b6130815760405162461bcd60e51b8152602060048201526011602482015270496e76616c69642061646472657373657360781b604482015260640161035e565b6001600160a01b03828116600081815260a06020908152604080832080549587166001600160a01b0319968716811790915560a1805460018101825594527faadc37b8ba5645e62f4546802db221593a94729ccbfc5a97d01365a88f64987890930180549095168417909455925190815290917fef6485b84315f9b1483beffa32aae9a0596890395e3d7521f1c5fbb51790e765910160405180910390a25050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b1790526131759084906137b9565b505050565b825161318d9060a5906020860190613a68565b508151815181146131d75760405162461bcd60e51b8152602060048201526014602482015273496e76616c696420696e7075742061727261797360601b604482015260640161035e565b60005b8181101561322e5761321e8482815181106131f7576131f761483f565b60200260200101518483815181106132115761321161483f565b6020026020010151612fc4565b613227816147e2565b90506131da565b5050505050565b6000811161327e5760405162461bcd60e51b81526020600482015260166024820152754d757374206465706f73697420736f6d657468696e6760501b604482015260640161035e565b6040805160008152602081018390526001600160a01b038416917f5548c837ab068cf56a2c2479df0882a4922fd203edb7517321831d95078c5f62910160405180910390a25050565b60335460ff16156132ea5760405162461bcd60e51b815260040161035e9061460e565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663e52253816040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561334757600080fd5b505af115801561335b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061337f91906140e3565b90506000606854826133919190614746565b9050804710156133e35760405162461bcd60e51b815260206004820152601860248201527f696e73756666696369656e74206574682062616c616e63650000000000000000604482015260640161035e565b8015610a8b5760006068819055507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b15801561344c57600080fd5b505af1158015613460573d6000803e3d6000fd5b505060a454604080516001600160a01b0392831681527f0000000000000000000000000000000000000000000000000000000000000000909216602083015281018590527ff6c07a063ed4e63808eb8da7112d46dbcd38de2b40a73dbcc9353c5a94c72353935060600191506134d39050565b60405180910390a160a454610a8b906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116911683613123565b6001600160a01b03811661356b5760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f722069732061646472657373283029000000000000604482015260640161035e565b806001600160a01b031661358b6000805160206148af8339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a3612836816000805160206148af83398151915255565b60335460ff1661361f5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b604482015260640161035e565b6033805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b60335460ff161561368c5760405162461bcd60e51b815260040161035e9061460e565b6033805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25861364c3390565b600081116137115760405162461bcd60e51b815260206004820152601760248201527f4d75737420776974686472617720736f6d657468696e67000000000000000000604482015260640161035e565b6001600160a01b0383166137605760405162461bcd60e51b8152602060048201526016602482015275135d5cdd081cdc1958da599e481c9958da5c1a595b9d60521b604482015260640161035e565b6040805160008152602081018390526001600160a01b038416917f2717ead6b9200dd235aad468c9809ea400fe33ac69b5bfaa6d3e90fc922b6398910160405180910390a26131756001600160a01b0383168483613123565b600061380e826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661388b9092919063ffffffff16565b805190915015613175578080602001905181019061382c9190613f0d565b6131755760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840161035e565b606061389a84846000856138a4565b90505b9392505050565b6060824710156139055760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840161035e565b843b6139535760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161035e565b600080866001600160a01b0316858760405161396f919061426f565b60006040518083038185875af1925050503d80600081146139ac576040519150601f19603f3d011682016040523d82523d6000602084013e6139b1565b606091505b50915091506139c18282866139cc565b979650505050505050565b606083156139db57508161389d565b8251156139eb5782518084602001fd5b8160405162461bcd60e51b815260040161035e919061458d565b828054828255906000526020600020908101928215613a58579160200282015b82811115613a585781546001600160a01b0319166001600160a01b03843516178255602090920191600190910190613a25565b50613a64929150613abd565b5090565b828054828255906000526020600020908101928215613a58579160200282015b82811115613a5857825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190613a88565b5b80821115613a645760008155600101613abe565b60008083601f840112613ae457600080fd5b5081356001600160401b03811115613afb57600080fd5b6020830191508360208260051b8501011115613b1657600080fd5b9250929050565b600082601f830112613b2e57600080fd5b81356020613b43613b3e83614723565b6146f3565b80838252828201915082860187848660051b8901011115613b6357600080fd5b60005b85811015613b8b578135613b798161486b565b84529284019290840190600101613b66565b5090979650505050505050565b60008083601f840112613baa57600080fd5b5081356001600160401b03811115613bc157600080fd5b602083019150836020828501011115613b1657600080fd5b600060a08284031215613beb57600080fd5b50919050565b600060a08284031215613c0357600080fd5b60405160a081018181106001600160401b0382111715613c2557613c25614855565b604052905080613c3483613c7c565b8152613c4260208401613c95565b6020820152613c5360408401613c95565b60408201526060830135613c6681614880565b6060820152608092830135920191909152919050565b803563ffffffff81168114613c9057600080fd5b919050565b80356001600160401b0381168114613c9057600080fd5b600060208284031215613cbe57600080fd5b813561389d8161486b565b600060208284031215613cdb57600080fd5b815161389d8161486b565b60008060408385031215613cf957600080fd5b8235613d048161486b565b91506020830135613d148161486b565b809150509250929050565b600080600060608486031215613d3457600080fd5b8335613d3f8161486b565b92506020840135613d4f8161486b565b929592945050506040919091013590565b60008060408385031215613d7357600080fd5b8235613d7e8161486b565b946020939093013593505050565b60008060208385031215613d9f57600080fd5b82356001600160401b03811115613db557600080fd5b613dc185828601613ad2565b90969095509350505050565b600080600060608486031215613de257600080fd5b83356001600160401b0380821115613df957600080fd5b613e0587838801613b1d565b94506020860135915080821115613e1b57600080fd5b613e2787838801613b1d565b93506040860135915080821115613e3d57600080fd5b50613e4a86828701613b1d565b9150509250925092565b600080600060e08486031215613e6957600080fd5b83356001600160401b03811115613e7f57600080fd5b8401601f81018613613e9057600080fd5b80356020613ea0613b3e83614723565b8083825282820191508285018a848660051b8801011115613ec057600080fd5b600095505b84861015613eea57613ed681613c95565b835260019590950194918301918301613ec5565b509650508601359350613f04915086905060408601613bf1565b90509250925092565b600060208284031215613f1f57600080fd5b815161389d81614880565b600060208284031215613f3c57600080fd5b5035919050565b60008060008060408587031215613f5957600080fd5b84356001600160401b0380821115613f7057600080fd5b613f7c88838901613b98565b90965094506020870135915080821115613f9557600080fd5b50613fa287828801613ad2565b95989497509550505050565b600080600080600080600080610120898b031215613fcb57600080fd5b88356001600160401b0380821115613fe257600080fd5b613fee8c838d01613b98565b909a50985060208b013591508082111561400757600080fd5b6140138c838d01613ad2565b909850965060408b013591508082111561402c57600080fd5b506140398b828c01613b98565b909550935050606089013591506140538a60808b01613bd9565b90509295985092959890939650565b600080600080600060e0868803121561407a57600080fd5b85356001600160401b038082111561409157600080fd5b61409d89838a01613b98565b909750955060208801359150808211156140b657600080fd5b506140c388828901613ad2565b90945092506140d790508760408801613bd9565b90509295509295909350565b6000602082840312156140f557600080fd5b5051919050565b6000806040838503121561410f57600080fd5b50508035926020909101359150565b60008060008060008060c0878903121561413757600080fd5b505084359660208601359650604086013595606081013595506080810135945060a0013592509050565b8183526000602080850194508260005b8581101561419d576001600160401b0361418a83613c95565b1687529582019590820190600101614171565b509495945050505050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b600081518084526141e98160208601602086016147b6565b601f01601f19169290920160200192915050565b63ffffffff61420b82613c7c565b16825261421a60208201613c95565b6001600160401b0380821660208501528061423760408501613c95565b1660408501525050606081013561424d81614880565b15156060830152608090810135910152565b8183823760009101908152919050565b600082516142818184602087016147b6565b9190910192915050565b6001600160a01b03851681526101006020808301829052855191830182905260009161012084019187810191845b818110156142de5783516001600160401b0316855293820193928201926001016142b9565b505082935086604086015263ffffffff865116606086015280860151925050506001600160401b0380821660808501528060408601511660a085015250506060830151151560c0830152608083015160e083015295945050505050565b6020808252825182820181905260009190848201906040850190845b8181101561437c5783516001600160a01b031683529284019291840191600101614357565b50909695505050505050565b6000604082016040835280865480835260608501915087600052602092508260002060005b828110156143d25781546001600160a01b0316845292840192600191820191016143ad565b505050838103828501528481528590820160005b868110156144145782356143f98161486b565b6001600160a01b0316825291830191908301906001016143e6565b50979650505050505050565b6040815260006144346040830186886141a8565b82810360208401526139c1818587614161565b600061012080835261445c8184018b8d6141a8565b9050828103602084015261447181898b614161565b905082810360408401526144868187896141a8565b91505083606083015261449c60808301846141fd565b9998505050505050505050565b60e0815260006144bd60e0830187896141a8565b82810360208401526144d0818688614161565b9150506144e060408301846141fd565b9695505050505050565b6080815260006144fe60808301888a6141a8565b828103602084015261451081886141d1565b905082810360408401526145258186886141a8565b915050826060830152979650505050505050565b60608152600061454d6060830186886141a8565b84602084015282810360408401526139c181856141d1565b602081016004831061458757634e487b7160e01b600052602160045260246000fd5b91905290565b60208152600061389d60208301846141d1565b60208082526017908201527f43616c6c6572206973206e6f7420746865205661756c74000000000000000000604082015260600190565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b60208082526010908201526f14185d5cd8589b194e881c185d5cd95960821b604082015260600190565b6020808252601d908201527f43616c6c6572206973206e6f7420746865205265676973747261746f72000000604082015260600190565b6020808252600e908201526d1499595b9d1c985b9d0818d85b1b60921b604082015260600190565b6000808335601e198436030181126146ae57600080fd5b8301803591506001600160401b038211156146c857600080fd5b602001915036819003821315613b1657600080fd5b60008235605e1983360301811261428157600080fd5b604051601f8201601f191681016001600160401b038111828210171561471b5761471b614855565b604052919050565b60006001600160401b0382111561473c5761473c614855565b5060051b60200190565b60008219821115614759576147596147fd565b500190565b60008261477b57634e487b7160e01b600052601260045260246000fd5b500490565b600081600019048311821515161561479a5761479a6147fd565b500290565b6000828210156147b1576147b16147fd565b500390565b60005b838110156147d15781810151838201526020016147b9565b83811115610da55750506000910152565b60006000198214156147f6576147f66147fd565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b038116811461283657600080fd5b801515811461283657600080fdfe53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac45357bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa26469706673582212204292636866460b0a0ebdd872cc7401407e5a3bdd212181fd3cea747a97b6379e64736f6c634300080700337bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a", - "deployedBytecode": "0x6080604052600436106102b25760003560e01c8063853828b611610175578063c2e1e3f4116100dc578063d9caed1211610095578063dd505df61161006f578063dd505df6146109a1578063de5f6268146109d5578063f1188e40146109ea578063f6ca71b014610a1e57600080fd5b8063d9caed121461092d578063d9f00ec71461094d578063dbe55e561461096d57600080fd5b8063c2e1e3f414610867578063c7af335214610887578063c98517c51461089c578063cceab750146108b9578063d38bfff4146108ed578063d5c360f61461090d57600080fd5b8063a4f98af41161012e578063a4f98af414610790578063aa388af6146107a5578063ab12edf5146107f2578063ad1728cb14610812578063af37dcbe14610827578063bb1b918d1461084757600080fd5b8063853828b6146106a557806387bae867146106ba5780639092c31c146106df5780639136616a1461071357806396d538bb146107335780639da0e4621461075357600080fd5b80635c975abb116102195780636ef38795116101d25780636ef38795146105fa57806371a735f31461061a5780637b2d9b2c1461063a5780637e20fffa1461065a578063842f5c461461067a5780638456cb591461069057600080fd5b80635c975abb1461052d5780635d36b190146105515780635f515226146105665780636093d3801461058657806367c7066c146105ba5780636e811d38146105da57600080fd5b8063430bf08a1161026b578063430bf08a1461045a578063435356d11461048e57806347e7ef24146104ae578063484be812146104ce578063579a7e1a146104e45780635a063f631461051857600080fd5b80630c340a241461036e5780630ed57b3a146103a05780630fc3b4c4146103c05780631072cbea146103f657806322495dc8146104165780633c8649591461043657600080fd5b3661036957336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614806103165750336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016145b6103675760405162461bcd60e51b815260206004820152601e60248201527f657468206e6f742066726f6d20616c6c6f77656420636f6e747261637473000060448201526064015b60405180910390fd5b005b600080fd5b34801561037a57600080fd5b50610383610a40565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156103ac57600080fd5b506103676103bb366004613ce6565b610a5d565b3480156103cc57600080fd5b506103836103db366004613cac565b60a0602052600090815260409020546001600160a01b031681565b34801561040257600080fd5b50610367610411366004613d60565b610a8f565b34801561042257600080fd5b50610367610431366004613e54565b610b4c565b34801561044257600080fd5b5061044c60695481565b604051908152602001610397565b34801561046657600080fd5b506103837f000000000000000000000000000000000000000000000000000000000000000081565b34801561049a57600080fd5b506103676104a9366004613dcd565b610cc6565b3480156104ba57600080fd5b506103676104c9366004613d60565b610dab565b3480156104da57600080fd5b5061044c606a5481565b3480156104f057600080fd5b506103837f000000000000000000000000000000000000000000000000000000000000000081565b34801561052457600080fd5b50610367610eb1565b34801561053957600080fd5b5060335460ff165b6040519015158152602001610397565b34801561055d57600080fd5b50610367610f50565b34801561057257600080fd5b5061044c610581366004613cac565b610ff6565b34801561059257600080fd5b506103837f000000000000000000000000000000000000000000000000000000000000000081565b3480156105c657600080fd5b5060a454610383906001600160a01b031681565b3480156105e657600080fd5b506103676105f5366004613cac565b61112a565b34801561060657600080fd5b50610367610615366004613d8c565b6111b2565b34801561062657600080fd5b50610367610635366004614062565b611634565b34801561064657600080fd5b50610383610655366004613f2a565b61182d565b34801561066657600080fd5b5061036761067536600461411e565b611857565b34801561068657600080fd5b5061044c60685481565b34801561069c57600080fd5b50610367611bff565b3480156106b157600080fd5b50610367611cf8565b3480156106c657600080fd5b506033546103839061010090046001600160a01b031681565b3480156106eb57600080fd5b506103837f000000000000000000000000000000000000000000000000000000000000000081565b34801561071f57600080fd5b5061036761072e366004613f2a565b611eca565b34801561073f57600080fd5b5061036761074e366004613d8c565b612095565b34801561075f57600080fd5b5061078361076e366004613f2a565b60356020526000908152604090205460ff1681565b6040516103979190614565565b34801561079c57600080fd5b506105416121b5565b3480156107b157600080fd5b506105416107c0366004613cac565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0390811691161490565b3480156107fe57600080fd5b5061036761080d3660046140fc565b612677565b34801561081e57600080fd5b50610367612773565b34801561083357600080fd5b50606b54610383906001600160a01b031681565b34801561085357600080fd5b50610367610862366004613fae565b612839565b34801561087357600080fd5b50610367610882366004613cac565b6129ac565b34801561089357600080fd5b50610541612a39565b3480156108a857600080fd5b5061044c6801bc16d674ec80000081565b3480156108c557600080fd5b506103837f000000000000000000000000000000000000000000000000000000000000000081565b3480156108f957600080fd5b50610367610908366004613cac565b612a6a565b34801561091957600080fd5b50610367610928366004613cac565b612b0e565b34801561093957600080fd5b50610367610948366004613d1f565b612b90565b34801561095957600080fd5b50610367610968366004613f43565b612c23565b34801561097957600080fd5b506103837f000000000000000000000000000000000000000000000000000000000000000081565b3480156109ad57600080fd5b506103837f000000000000000000000000000000000000000000000000000000000000000081565b3480156109e157600080fd5b50610367612e18565b3480156109f657600080fd5b506103837f000000000000000000000000000000000000000000000000000000000000000081565b348015610a2a57600080fd5b50610a33612f62565b604051610397919061433b565b6000610a586000805160206148af8339815191525490565b905090565b610a65612a39565b610a815760405162461bcd60e51b815260040161035e906145d7565b610a8b8282612fc4565b5050565b610a97612a39565b610ab35760405162461bcd60e51b815260040161035e906145d7565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b039081169083161415610b305760405162461bcd60e51b815260206004820152601f60248201527f43616e6e6f74207472616e7366657220737570706f7274656420617373657400604482015260640161035e565b610a8b610b3b610a40565b6001600160a01b0384169083613123565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b158015610ba557600080fd5b505afa158015610bb9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bdd9190613cc9565b6001600160a01b0316336001600160a01b031614610c3d5760405162461bcd60e51b815260206004820152601c60248201527f43616c6c6572206973206e6f7420746865205374726174656769737400000000604482015260640161035e565b60405163bc26e7e560e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063bc26e7e590610c8f90309087908790879060040161428b565b600060405180830381600087803b158015610ca957600080fd5b505af1158015610cbd573d6000803e3d6000fd5b50505050505050565b610cce612a39565b610cea5760405162461bcd60e51b815260040161035e906145d7565b600054610100900460ff1680610d03575060005460ff16155b610d665760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840161035e565b600054610100900460ff16158015610d88576000805461ffff19166101011790555b610d9384848461317a565b8015610da5576000805461ff00191690555b50505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610df35760405162461bcd60e51b815260040161035e906145a0565b60008051602061488f83398151915280546002811415610e255760405162461bcd60e51b815260040161035e9061466f565b600282557f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316846001600160a01b031614610e9e5760405162461bcd60e51b8152602060048201526011602482015270155b9cdd5c1c1bdc9d195908185cdcd95d607a1b604482015260640161035e565b610ea88484613235565b50600190555050565b60a4546001600160a01b03163314610f0b5760405162461bcd60e51b815260206004820152601b60248201527f43616c6c6572206973206e6f7420746865204861727665737465720000000000604482015260640161035e565b60008051602061488f83398151915280546002811415610f3d5760405162461bcd60e51b815260040161035e9061466f565b60028255610f496132c7565b5060019055565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b031614610feb5760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b606482015260840161035e565b610ff433613515565b565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b03161461106d5760405162461bcd60e51b8152602060048201526011602482015270155b9cdd5c1c1bdc9d195908185cdcd95d607a1b604482015260640161035e565b6040516370a0823160e01b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b1580156110cc57600080fd5b505afa1580156110e0573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061110491906140e3565b60345461111a906801bc16d674ec800000614780565b6111249190614746565b92915050565b611132612a39565b61114e5760405162461bcd60e51b815260040161035e906145d7565b6040516001600160a01b03821681527f83f29c79feb71f8fba9d0fbc4ba5f0982a28b6b1e868b3fc50e6400d100bca0f9060200160405180910390a1603380546001600160a01b0390921661010002610100600160a81b0319909216919091179055565b60335461010090046001600160a01b031633146111e15760405162461bcd60e51b815260040161035e90614638565b60335460ff16156112045760405162461bcd60e51b815260040161035e9061460e565b6000611219826801bc16d674ec800000614780565b6040516370a0823160e01b81523060048201529091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b15801561127b57600080fd5b505afa15801561128f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112b391906140e3565b8111156112f65760405162461bcd60e51b81526020600482015260116024820152700d2dce6eaccccd2c6d2cadce840ae8aa89607b1b604482015260640161035e565b604051632e1a7d4d60e01b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561135857600080fd5b505af115801561136c573d6000803e3d6000fd5b5050505060005b82811015610da557600084848381811061138f5761138f61483f565b90506020028101906113a191906146dd565b6113ab9080614697565b6040516113b992919061425f565b6040805191829003909120600081815260356020529182205490925060ff16908160038111156113eb576113eb614813565b146114385760405162461bcd60e51b815260206004820152601860248201527f56616c696461746f72206e6f7420726567697374657265640000000000000000604482015260640161035e565b60408051600160f81b60208201526000602182018190526bffffffffffffffffffffffff193060601b16602c830152910160405160208183030381529060405290507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663228951188888878181106114bb576114bb61483f565b90506020028101906114cd91906146dd565b6114d79080614697565b848b8b8a8181106114ea576114ea61483f565b90506020028101906114fc91906146dd565b61150a906020810190614697565b8d8d8c81811061151c5761151c61483f565b905060200281019061152e91906146dd565b604001356040518763ffffffff1660e01b8152600401611553969594939291906144ea565b600060405180830381600087803b15801561156d57600080fd5b505af1158015611581573d6000803e3d6000fd5b505050506001603460008282546115989190614746565b909155507ffeb31a79d38edb1b090d516e4df3e273651179c6f2c2ec53a9a22ae015b70ba990508787868181106115d1576115d161483f565b90506020028101906115e391906146dd565b6115ed9080614697565b6801bc16d674ec800000846040516116089493929190614539565b60405180910390a150506000908152603560205260409020805460ff1916600190811790915501611373565b60335461010090046001600160a01b031633146116635760405162461bcd60e51b815260040161035e90614638565b60335460ff16156116865760405162461bcd60e51b815260040161035e9061460e565b600060356000878760405161169c92919061425f565b604080519182900390912082526020820192909252016000205460ff16905060028160038111156116cf576116cf614813565b146117145760405162461bcd60e51b815260206004820152601560248201527456616c696461746f72206e6f742065786974696e6760581b604482015260640161035e565b6040516312b3fc1960e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906312b3fc199061176890899089908990899089906004016144a9565b600060405180830381600087803b15801561178257600080fd5b505af1158015611796573d6000803e3d6000fd5b505050507ff72821b8777f002ccdf6326f1242d9e0f762eb077668b67bebe640535378066d868686866040516117cf9493929190614420565b60405180910390a160036035600088886040516117ed92919061425f565b60408051918290039091208252602082019290925201600020805460ff1916600183600381111561182057611820614813565b0217905550505050505050565b60a5818154811061183d57600080fd5b6000918252602090912001546001600160a01b0316905081565b606b546001600160a01b031633146118bf5760405162461bcd60e51b815260206004820152602560248201527f43616c6c6572206973206e6f7420746865204163636f756e74696e6720476f7660448201526432b93737b960d91b606482015260840161035e565b60335460ff166119085760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b604482015260640161035e565b6040516370a0823160e01b815230600482015247906000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b15801561196c57600080fd5b505afa158015611980573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119a491906140e3565b90508382111580156119b65750828111155b611a025760405162461bcd60e51b815260206004820152601960248201527f6f766572206163636f756e74696e67207468726573686f6c6400000000000000604482015260640161035e565b60345460685460408051928352602083018b9052820152606081018690526080810188905260a081018790527fb2c41d2aedabd456081f30f3b116ce88de1c795a7d4ca787fef373a393f3c5db9060c00160405180910390a1603488905560688590558615611b235781871115611aae5760405162461bcd60e51b815260206004820152601060248201526f0d2dce6eaccccd2c6d2cadce8408aa8960831b604482015260640161035e565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0886040518263ffffffff1660e01b81526004016000604051808303818588803b158015611b0957600080fd5b505af1158015611b1d573d6000803e3d6000fd5b50505050505b8515611bed5760405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018890527f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb90604401602060405180830381600087803b158015611bb357600080fd5b505af1158015611bc7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611beb9190613f0d565b505b611bf56135d6565b5050505050505050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b158015611c5857600080fd5b505afa158015611c6c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c909190613cc9565b6001600160a01b0316336001600160a01b031614611cf05760405162461bcd60e51b815260206004820152601c60248201527f43616c6c6572206973206e6f7420746865205374726174656769737400000000604482015260640161035e565b610ff4613669565b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161480611d475750611d32610a40565b6001600160a01b0316336001600160a01b0316145b611d9f5760405162461bcd60e51b815260206004820152602360248201527f43616c6c6572206973206e6f7420746865205661756c74206f7220476f7665726044820152623737b960e91b606482015260840161035e565b60008051602061488f83398151915280546002811415611dd15760405162461bcd60e51b815260040161035e9061466f565b600282556040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b158015611e3757600080fd5b505afa158015611e4b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e6f91906140e3565b90508015611ec257611ec27f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000836136c1565b505060019055565b611ed2612a39565b611eee5760405162461bcd60e51b815260040161035e906145d7565b60a1548110611f2f5760405162461bcd60e51b815260206004820152600d60248201526c092dcecc2d8d2c840d2dcc8caf609b1b604482015260640161035e565b600060a18281548110611f4457611f4461483f565b60009182526020808320909101546001600160a01b0390811680845260a090925260409092205460a15491935090911690611f819060019061479f565b8310156120035760a18054611f989060019061479f565b81548110611fa857611fa861483f565b60009182526020909120015460a180546001600160a01b039092169185908110611fd457611fd461483f565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505b60a180548061201457612014614829565b60008281526020808220600019908401810180546001600160a01b031990811690915593019093556001600160a01b0385811680835260a0855260409283902080549094169093559051908416815290917f16b7600acff27e39a8a96056b3d533045298de927507f5c1d97e4accde60488c910160405180910390a2505050565b61209d612a39565b6120b95760405162461bcd60e51b815260040161035e906145d7565b8060005b8181101561216c5760008484838181106120d9576120d961483f565b90506020020160208101906120ee9190613cac565b6001600160a01b0316141561215c5760405162461bcd60e51b815260206004820152602e60248201527f43616e206e6f742073657420616e20656d70747920616464726573732061732060448201526d30903932bbb0b932103a37b5b2b760911b606482015260840161035e565b612165816147e2565b90506120bd565b507f04c0b9649497d316554306e53678d5f5f5dbc3a06f97dec13ff4cfe98b986bbc60a584846040516121a193929190614388565b60405180910390a1610da560a58484613a05565b60335460009061010090046001600160a01b031633146121e75760405162461bcd60e51b815260040161035e90614638565b60335460ff161561220a5760405162461bcd60e51b815260040161035e9061460e565b6068544710156122225761221c613669565b50600090565b600060685447612232919061479f565b9050600191506801bc16d674ec800000811061240d57600061225d6801bc16d674ec8000008361475e565b90508060346000828254612271919061479f565b909155506000905061228c826801bc16d674ec800000614780565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b1580156122e957600080fd5b505af11580156122fd573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb92506044019050602060405180830381600087803b15801561238d57600080fd5b505af11580156123a1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123c59190613f0d565b5060345460408051848152602081019290925281018290527fbe7040030ff7b347853214bf49820c6d455fedf58f3815f85c7bc5216993682b9060600160405180910390a150505b60006068544761241d919061479f565b90506801bc16d674ec800000811061246f5760405162461bcd60e51b8152602060048201526015602482015274756e6578706563746564206163636f756e74696e6760581b604482015260640161035e565b8061247957505090565b6069548110156124d35780606860008282546124959190614746565b90915550506040518181527f7a745a2c63a535068f52ceca27debd5297bbad5f7f37ec53d044a59d0362445d906020015b60405180910390a1505090565b606a54811115612666577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b15801561253857600080fd5b505af115801561254c573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb92506044019050602060405180830381600087803b1580156125dc57600080fd5b505af11580156125f0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126149190613f0d565b50600160346000828254612628919061479f565b909155505060345460408051918252602082018390527f6aa7e30787b26429ced603a7aba8b19c4b5d5bcf29a3257da953c8d53bcaa3a691016124c6565b61266e613669565b60009250505090565b61267f612a39565b61269b5760405162461bcd60e51b815260040161035e906145d7565b80821080156126b257506801bc16d674ec80000082105b80156126c657506801bc16d674ec80000081105b80156126e35750673782dace9d9000006126e0838361479f565b10155b61272f5760405162461bcd60e51b815260206004820152601760248201527f696e636f7272656374206675736520696e74657276616c000000000000000000604482015260640161035e565b60408051838152602081018390527fcb8d24e46eb3c402bf344ee60a6576cba9ef2f59ea1af3b311520704924e901a910160405180910390a1606991909155606a55565b60405163095ea7b360e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015260001960248301527f0000000000000000000000000000000000000000000000000000000000000000169063095ea7b390604401602060405180830381600087803b1580156127fe57600080fd5b505af1158015612812573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128369190613f0d565b50565b60335461010090046001600160a01b031633146128685760405162461bcd60e51b815260040161035e90614638565b60335460ff161561288b5760405162461bcd60e51b815260040161035e9061460e565b6040516301ba3ee760e21b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906306e8fb9c906128e5908b908b908b908b908b908b908b908b90600401614447565b600060405180830381600087803b1580156128ff57600080fd5b505af1158015612913573d6000803e3d6000fd5b505050506000603560008a8a60405161292d92919061425f565b60408051918290039091208252602082019290925201600020805460ff1916600183600381111561296057612960614813565b02179055507f75c4a66b2c6c28cf46db7131182a812e4fbbb2f0591377aa83a737909a9b68c38888888860405161299a9493929190614420565b60405180910390a15050505050505050565b6129b4612a39565b6129d05760405162461bcd60e51b815260040161035e906145d7565b60a454604080516001600160a01b03928316815291831660208301527fe48386b84419f4d36e0f96c10cc3510b6fb1a33795620c5098b22472bbe90796910160405180910390a160a480546001600160a01b0319166001600160a01b0392909216919091179055565b6000612a516000805160206148af8339815191525490565b6001600160a01b0316336001600160a01b031614905090565b612a72612a39565b612a8e5760405162461bcd60e51b815260040161035e906145d7565b612ab6817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b0316612ad66000805160206148af8339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b612b16612a39565b612b325760405162461bcd60e51b815260040161035e906145d7565b6040516001600160a01b03821681527ff3dd2b598e2a94dd3f46b414f7c960f8e10a0b0efd00df97d27cdd0fee5c87539060200160405180910390a1606b80546001600160a01b0319166001600160a01b0392909216919091179055565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614612bd85760405162461bcd60e51b815260040161035e906145a0565b60008051602061488f83398151915280546002811415612c0a5760405162461bcd60e51b815260040161035e9061466f565b60028255612c198585856136c1565b5060019055505050565b60335461010090046001600160a01b03163314612c525760405162461bcd60e51b815260040161035e90614638565b60335460ff1615612c755760405162461bcd60e51b815260040161035e9061460e565b6000603560008686604051612c8b92919061425f565b604080519182900390912082526020820192909252016000205460ff1690506001816003811115612cbe57612cbe614813565b14612d025760405162461bcd60e51b815260206004820152601460248201527315985b1a59185d1bdc881b9bdd081cdd185ad95960621b604482015260640161035e565b604051633877322b60e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690633877322b90612d54908890889088908890600401614420565b600060405180830381600087803b158015612d6e57600080fd5b505af1158015612d82573d6000803e3d6000fd5b505050507ff8821da16f5ed966b41e0343c3eff9903af782d74f99f1689dd9d4562b6545b385858585604051612dbb9493929190614420565b60405180910390a16002603560008787604051612dd992919061425f565b60408051918290039091208252602082019290925201600020805460ff19166001836003811115612e0c57612e0c614813565b02179055505050505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614612e605760405162461bcd60e51b815260040161035e906145a0565b60008051602061488f83398151915280546002811415612e925760405162461bcd60e51b815260040161035e9061466f565b600282556040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b158015612ef857600080fd5b505afa158015612f0c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f3091906140e3565b90508015611ec257611ec27f000000000000000000000000000000000000000000000000000000000000000082613235565b606060a5805480602002602001604051908101604052809291908181526020018280548015612fba57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612f9c575b5050505050905090565b6001600160a01b03828116600090815260a0602052604090205416156130215760405162461bcd60e51b81526020600482015260126024820152711c151bdad95b88185b1c9958591e481cd95d60721b604482015260640161035e565b6001600160a01b0382161580159061304157506001600160a01b03811615155b6130815760405162461bcd60e51b8152602060048201526011602482015270496e76616c69642061646472657373657360781b604482015260640161035e565b6001600160a01b03828116600081815260a06020908152604080832080549587166001600160a01b0319968716811790915560a1805460018101825594527faadc37b8ba5645e62f4546802db221593a94729ccbfc5a97d01365a88f64987890930180549095168417909455925190815290917fef6485b84315f9b1483beffa32aae9a0596890395e3d7521f1c5fbb51790e765910160405180910390a25050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b1790526131759084906137b9565b505050565b825161318d9060a5906020860190613a68565b508151815181146131d75760405162461bcd60e51b8152602060048201526014602482015273496e76616c696420696e7075742061727261797360601b604482015260640161035e565b60005b8181101561322e5761321e8482815181106131f7576131f761483f565b60200260200101518483815181106132115761321161483f565b6020026020010151612fc4565b613227816147e2565b90506131da565b5050505050565b6000811161327e5760405162461bcd60e51b81526020600482015260166024820152754d757374206465706f73697420736f6d657468696e6760501b604482015260640161035e565b6040805160008152602081018390526001600160a01b038416917f5548c837ab068cf56a2c2479df0882a4922fd203edb7517321831d95078c5f62910160405180910390a25050565b60335460ff16156132ea5760405162461bcd60e51b815260040161035e9061460e565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663e52253816040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561334757600080fd5b505af115801561335b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061337f91906140e3565b90506000606854826133919190614746565b9050804710156133e35760405162461bcd60e51b815260206004820152601860248201527f696e73756666696369656e74206574682062616c616e63650000000000000000604482015260640161035e565b8015610a8b5760006068819055507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b15801561344c57600080fd5b505af1158015613460573d6000803e3d6000fd5b505060a454604080516001600160a01b0392831681527f0000000000000000000000000000000000000000000000000000000000000000909216602083015281018590527ff6c07a063ed4e63808eb8da7112d46dbcd38de2b40a73dbcc9353c5a94c72353935060600191506134d39050565b60405180910390a160a454610a8b906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116911683613123565b6001600160a01b03811661356b5760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f722069732061646472657373283029000000000000604482015260640161035e565b806001600160a01b031661358b6000805160206148af8339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a3612836816000805160206148af83398151915255565b60335460ff1661361f5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b604482015260640161035e565b6033805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b60335460ff161561368c5760405162461bcd60e51b815260040161035e9061460e565b6033805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25861364c3390565b600081116137115760405162461bcd60e51b815260206004820152601760248201527f4d75737420776974686472617720736f6d657468696e67000000000000000000604482015260640161035e565b6001600160a01b0383166137605760405162461bcd60e51b8152602060048201526016602482015275135d5cdd081cdc1958da599e481c9958da5c1a595b9d60521b604482015260640161035e565b6040805160008152602081018390526001600160a01b038416917f2717ead6b9200dd235aad468c9809ea400fe33ac69b5bfaa6d3e90fc922b6398910160405180910390a26131756001600160a01b0383168483613123565b600061380e826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661388b9092919063ffffffff16565b805190915015613175578080602001905181019061382c9190613f0d565b6131755760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840161035e565b606061389a84846000856138a4565b90505b9392505050565b6060824710156139055760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840161035e565b843b6139535760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161035e565b600080866001600160a01b0316858760405161396f919061426f565b60006040518083038185875af1925050503d80600081146139ac576040519150601f19603f3d011682016040523d82523d6000602084013e6139b1565b606091505b50915091506139c18282866139cc565b979650505050505050565b606083156139db57508161389d565b8251156139eb5782518084602001fd5b8160405162461bcd60e51b815260040161035e919061458d565b828054828255906000526020600020908101928215613a58579160200282015b82811115613a585781546001600160a01b0319166001600160a01b03843516178255602090920191600190910190613a25565b50613a64929150613abd565b5090565b828054828255906000526020600020908101928215613a58579160200282015b82811115613a5857825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190613a88565b5b80821115613a645760008155600101613abe565b60008083601f840112613ae457600080fd5b5081356001600160401b03811115613afb57600080fd5b6020830191508360208260051b8501011115613b1657600080fd5b9250929050565b600082601f830112613b2e57600080fd5b81356020613b43613b3e83614723565b6146f3565b80838252828201915082860187848660051b8901011115613b6357600080fd5b60005b85811015613b8b578135613b798161486b565b84529284019290840190600101613b66565b5090979650505050505050565b60008083601f840112613baa57600080fd5b5081356001600160401b03811115613bc157600080fd5b602083019150836020828501011115613b1657600080fd5b600060a08284031215613beb57600080fd5b50919050565b600060a08284031215613c0357600080fd5b60405160a081018181106001600160401b0382111715613c2557613c25614855565b604052905080613c3483613c7c565b8152613c4260208401613c95565b6020820152613c5360408401613c95565b60408201526060830135613c6681614880565b6060820152608092830135920191909152919050565b803563ffffffff81168114613c9057600080fd5b919050565b80356001600160401b0381168114613c9057600080fd5b600060208284031215613cbe57600080fd5b813561389d8161486b565b600060208284031215613cdb57600080fd5b815161389d8161486b565b60008060408385031215613cf957600080fd5b8235613d048161486b565b91506020830135613d148161486b565b809150509250929050565b600080600060608486031215613d3457600080fd5b8335613d3f8161486b565b92506020840135613d4f8161486b565b929592945050506040919091013590565b60008060408385031215613d7357600080fd5b8235613d7e8161486b565b946020939093013593505050565b60008060208385031215613d9f57600080fd5b82356001600160401b03811115613db557600080fd5b613dc185828601613ad2565b90969095509350505050565b600080600060608486031215613de257600080fd5b83356001600160401b0380821115613df957600080fd5b613e0587838801613b1d565b94506020860135915080821115613e1b57600080fd5b613e2787838801613b1d565b93506040860135915080821115613e3d57600080fd5b50613e4a86828701613b1d565b9150509250925092565b600080600060e08486031215613e6957600080fd5b83356001600160401b03811115613e7f57600080fd5b8401601f81018613613e9057600080fd5b80356020613ea0613b3e83614723565b8083825282820191508285018a848660051b8801011115613ec057600080fd5b600095505b84861015613eea57613ed681613c95565b835260019590950194918301918301613ec5565b509650508601359350613f04915086905060408601613bf1565b90509250925092565b600060208284031215613f1f57600080fd5b815161389d81614880565b600060208284031215613f3c57600080fd5b5035919050565b60008060008060408587031215613f5957600080fd5b84356001600160401b0380821115613f7057600080fd5b613f7c88838901613b98565b90965094506020870135915080821115613f9557600080fd5b50613fa287828801613ad2565b95989497509550505050565b600080600080600080600080610120898b031215613fcb57600080fd5b88356001600160401b0380821115613fe257600080fd5b613fee8c838d01613b98565b909a50985060208b013591508082111561400757600080fd5b6140138c838d01613ad2565b909850965060408b013591508082111561402c57600080fd5b506140398b828c01613b98565b909550935050606089013591506140538a60808b01613bd9565b90509295985092959890939650565b600080600080600060e0868803121561407a57600080fd5b85356001600160401b038082111561409157600080fd5b61409d89838a01613b98565b909750955060208801359150808211156140b657600080fd5b506140c388828901613ad2565b90945092506140d790508760408801613bd9565b90509295509295909350565b6000602082840312156140f557600080fd5b5051919050565b6000806040838503121561410f57600080fd5b50508035926020909101359150565b60008060008060008060c0878903121561413757600080fd5b505084359660208601359650604086013595606081013595506080810135945060a0013592509050565b8183526000602080850194508260005b8581101561419d576001600160401b0361418a83613c95565b1687529582019590820190600101614171565b509495945050505050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b600081518084526141e98160208601602086016147b6565b601f01601f19169290920160200192915050565b63ffffffff61420b82613c7c565b16825261421a60208201613c95565b6001600160401b0380821660208501528061423760408501613c95565b1660408501525050606081013561424d81614880565b15156060830152608090810135910152565b8183823760009101908152919050565b600082516142818184602087016147b6565b9190910192915050565b6001600160a01b03851681526101006020808301829052855191830182905260009161012084019187810191845b818110156142de5783516001600160401b0316855293820193928201926001016142b9565b505082935086604086015263ffffffff865116606086015280860151925050506001600160401b0380821660808501528060408601511660a085015250506060830151151560c0830152608083015160e083015295945050505050565b6020808252825182820181905260009190848201906040850190845b8181101561437c5783516001600160a01b031683529284019291840191600101614357565b50909695505050505050565b6000604082016040835280865480835260608501915087600052602092508260002060005b828110156143d25781546001600160a01b0316845292840192600191820191016143ad565b505050838103828501528481528590820160005b868110156144145782356143f98161486b565b6001600160a01b0316825291830191908301906001016143e6565b50979650505050505050565b6040815260006144346040830186886141a8565b82810360208401526139c1818587614161565b600061012080835261445c8184018b8d6141a8565b9050828103602084015261447181898b614161565b905082810360408401526144868187896141a8565b91505083606083015261449c60808301846141fd565b9998505050505050505050565b60e0815260006144bd60e0830187896141a8565b82810360208401526144d0818688614161565b9150506144e060408301846141fd565b9695505050505050565b6080815260006144fe60808301888a6141a8565b828103602084015261451081886141d1565b905082810360408401526145258186886141a8565b915050826060830152979650505050505050565b60608152600061454d6060830186886141a8565b84602084015282810360408401526139c181856141d1565b602081016004831061458757634e487b7160e01b600052602160045260246000fd5b91905290565b60208152600061389d60208301846141d1565b60208082526017908201527f43616c6c6572206973206e6f7420746865205661756c74000000000000000000604082015260600190565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b60208082526010908201526f14185d5cd8589b194e881c185d5cd95960821b604082015260600190565b6020808252601d908201527f43616c6c6572206973206e6f7420746865205265676973747261746f72000000604082015260600190565b6020808252600e908201526d1499595b9d1c985b9d0818d85b1b60921b604082015260600190565b6000808335601e198436030181126146ae57600080fd5b8301803591506001600160401b038211156146c857600080fd5b602001915036819003821315613b1657600080fd5b60008235605e1983360301811261428157600080fd5b604051601f8201601f191681016001600160401b038111828210171561471b5761471b614855565b604052919050565b60006001600160401b0382111561473c5761473c614855565b5060051b60200190565b60008219821115614759576147596147fd565b500190565b60008261477b57634e487b7160e01b600052601260045260246000fd5b500490565b600081600019048311821515161561479a5761479a6147fd565b500290565b6000828210156147b1576147b16147fd565b500390565b60005b838110156147d15781810151838201526020016147b9565b83811115610da55750506000910152565b60006000198214156147f6576147f66147fd565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b038116811461283657600080fd5b801515811461283657600080fdfe53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac45357bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa26469706673582212204292636866460b0a0ebdd872cc7401407e5a3bdd212181fd3cea747a97b6379e64736f6c63430008070033", + "numDeployments": 1, + "solcInputHash": "66dbdc9fbde8f1c7cc59f29d272eb661", + "metadata": "{\"compiler\":{\"version\":\"0.8.7+commit.e28d00a7\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"platformAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"vaultAddress\",\"type\":\"address\"}],\"internalType\":\"struct InitializableAbstractStrategy.BaseStrategyConfig\",\"name\":\"_baseConfig\",\"type\":\"tuple\"},{\"internalType\":\"address\",\"name\":\"_wethAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_ssvToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_ssvNetwork\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_feeAccumulator\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_beaconChainDepositContract\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"AccountingConsensusRewards\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"noOfValidators\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"remainingValidators\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"wethSentToVault\",\"type\":\"uint256\"}],\"name\":\"AccountingFullyWithdrawnValidator\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"validatorsDelta\",\"type\":\"int256\"},{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"consensusRewardsDelta\",\"type\":\"int256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"wethToVault\",\"type\":\"uint256\"}],\"name\":\"AccountingManuallyFixed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"remainingValidators\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"wethSentToVault\",\"type\":\"uint256\"}],\"name\":\"AccountingValidatorSlashed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"Deposit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"pubkey\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"withdrawal_credentials\",\"type\":\"bytes\"}],\"name\":\"ETHStaked\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"start\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"end\",\"type\":\"uint256\"}],\"name\":\"FuseIntervalUpdated\",\"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\":\"address\",\"name\":\"_oldHarvesterAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_newHarvesterAddress\",\"type\":\"address\"}],\"name\":\"HarvesterAddressesUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"}],\"name\":\"PTokenAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"}],\"name\":\"PTokenRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Paused\",\"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\":\"newAddress\",\"type\":\"address\"}],\"name\":\"RegistratorChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"_oldAddresses\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"_newAddresses\",\"type\":\"address[]\"}],\"name\":\"RewardTokenAddressesUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"rewardToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"RewardTokenCollected\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"pubkey\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"}],\"name\":\"SSVValidatorExitCompleted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"pubkey\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"}],\"name\":\"SSVValidatorExitInitiated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"pubkey\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"}],\"name\":\"SSVValidatorRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Unpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"Withdrawal\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"BEACON_CHAIN_DEPOSIT_CONTRACT\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_ACCUMULATOR_ADDRESS\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MAX_STAKE\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"SSV_NETWORK_ADDRESS\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"SSV_TOKEN_ADDRESS\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"VAULT_ADDRESS\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"WETH_TOKEN_ADDRESS\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"activeDepositedValidators\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"assetToPToken\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"}],\"name\":\"checkBalance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"claimGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"collectRewardTokens\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"consensusRewards\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"depositAll\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"validatorCount\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"networkFeeIndex\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"index\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"active\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"internalType\":\"struct Cluster\",\"name\":\"cluster\",\"type\":\"tuple\"}],\"name\":\"depositSSV\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"doAccounting\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"accountingValid\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"publicKey\",\"type\":\"bytes\"},{\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"}],\"name\":\"exitSsvValidator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fuseIntervalEnd\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fuseIntervalStart\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRewardTokenAddresses\",\"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\":\"harvesterAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"_rewardTokenAddresses\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"_assets\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"_pTokens\",\"type\":\"address[]\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isGovernor\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"int256\",\"name\":\"_validatorsDelta\",\"type\":\"int256\"},{\"internalType\":\"int256\",\"name\":\"_consensusRewardsDelta\",\"type\":\"int256\"},{\"internalType\":\"uint256\",\"name\":\"_wethToVaultAmount\",\"type\":\"uint256\"}],\"name\":\"manuallyFixAccounting\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"paused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"platformAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"publicKey\",\"type\":\"bytes\"},{\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"},{\"internalType\":\"bytes\",\"name\":\"sharesData\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"validatorCount\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"networkFeeIndex\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"index\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"active\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"internalType\":\"struct Cluster\",\"name\":\"cluster\",\"type\":\"tuple\"}],\"name\":\"registerSsvValidator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_assetIndex\",\"type\":\"uint256\"}],\"name\":\"removePToken\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"publicKey\",\"type\":\"bytes\"},{\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"validatorCount\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"networkFeeIndex\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"index\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"active\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"internalType\":\"struct Cluster\",\"name\":\"cluster\",\"type\":\"tuple\"}],\"name\":\"removeSsvValidator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"rewardTokenAddresses\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"safeApproveAllTokens\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_fuseIntervalStart\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_fuseIntervalEnd\",\"type\":\"uint256\"}],\"name\":\"setFuseInterval\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_harvesterAddress\",\"type\":\"address\"}],\"name\":\"setHarvesterAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"}],\"name\":\"setPTokenAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"setRegistrator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"_rewardTokenAddresses\",\"type\":\"address[]\"}],\"name\":\"setRewardTokenAddresses\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"pubkey\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"depositDataRoot\",\"type\":\"bytes32\"}],\"internalType\":\"struct ValidatorStakeData[]\",\"name\":\"validators\",\"type\":\"tuple[]\"}],\"name\":\"stakeEth\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"}],\"name\":\"supportsAsset\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"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\":\"validatorRegistrator\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"validatorsStates\",\"outputs\":[{\"internalType\":\"enum ValidatorRegistrator.VALIDATOR_STATE\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"vaultAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"withdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdrawAll\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"author\":\"Origin Protocol Inc\",\"kind\":\"dev\",\"methods\":{\"checkBalance(address)\":{\"params\":{\"_asset\":\"Address of weth asset\"},\"returns\":{\"balance\":\" Total value of (W)ETH\"}},\"constructor\":{\"params\":{\"_baseConfig\":\"Base strategy config with platformAddress (ERC-4626 Vault contract), eg sfrxETH or sDAI, and vaultAddress (OToken Vault contract), eg VaultProxy or OETHVaultProxy\",\"_beaconChainDepositContract\":\"Address of the beacon chain deposit contract\",\"_feeAccumulator\":\"Address of the fee accumulator receiving execution layer validator rewards\",\"_ssvNetwork\":\"Address of the SSV Network contract\",\"_ssvToken\":\"Address of the Erc20 SSV Token contract\",\"_wethAddress\":\"Address of the Erc20 WETH Token contract\"}},\"deposit(address,uint256)\":{\"params\":{\"_amount\":\"Amount of assets that were transferred to the strategy by the vault.\",\"_asset\":\"Address of asset to deposit. Has to be WETH.\"}},\"depositSSV(uint64[],uint256,(uint32,uint64,uint64,bool,uint256))\":{\"details\":\"A SSV cluster is defined by the SSVOwnerAddress and the set of operatorIds. uses \\\"onlyStrategist\\\" modifier so continuous front-running can't DOS our maintenance service that tries to top up SSV tokens.\",\"params\":{\"cluster\":\"The SSV cluster details that must be derived from emitted events from the SSVNetwork contract.\"}},\"doAccounting()\":{\"details\":\"This function could in theory be permission-less but lets allow only the Registrator (Defender Action) to call it for now.\",\"returns\":{\"accountingValid\":\"true if accounting was successful, false if fuse is blown\"}},\"getRewardTokenAddresses()\":{\"returns\":{\"_0\":\"address[] the reward token addresses.\"}},\"initialize(address[],address[],address[])\":{\"params\":{\"_assets\":\"Addresses of initial supported assets\",\"_pTokens\":\"Platform Token corresponding addresses\",\"_rewardTokenAddresses\":\"Address of reward token for platform\"}},\"manuallyFixAccounting(int256,int256,uint256)\":{\"params\":{\"_consensusRewardsDelta\":\"adjust the accounted for consensus rewards up or down\",\"_validatorsDelta\":\"adjust the active validators by plus one, minus one or unchanged with zero\",\"_wethToVaultAmount\":\"the amount of WETH to be sent to the Vault\"}},\"paused()\":{\"details\":\"Returns true if the contract is paused, and false otherwise.\"},\"removePToken(uint256)\":{\"params\":{\"_assetIndex\":\"Index of the asset to be removed\"}},\"setHarvesterAddress(address)\":{\"params\":{\"_harvesterAddress\":\"Address of the harvester contract.\"}},\"setPTokenAddress(address,address)\":{\"params\":{\"_asset\":\"Address for the asset\",\"_pToken\":\"Address for the corresponding platform token\"}},\"setRewardTokenAddresses(address[])\":{\"params\":{\"_rewardTokenAddresses\":\"Array of reward token addresses\"}},\"stakeEth((bytes,bytes,bytes32)[])\":{\"params\":{\"validators\":\"A list of validator data needed to stake. The `ValidatorStakeData` struct contains the pubkey, signature and depositDataRoot. Only the registrator can call this function.\"}},\"supportsAsset(address)\":{\"params\":{\"_asset\":\"The address of the asset token.\"}},\"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\"}},\"withdraw(address,address,uint256)\":{\"params\":{\"_amount\":\"Amount of WETH to withdraw\",\"_asset\":\"WETH to withdraw\",\"_recipient\":\"Address to receive withdrawn assets\"}}},\"stateVariables\":{\"FEE_ACCUMULATOR_ADDRESS\":{\"details\":\"this address will receive Execution layer rewards - These are rewards earned for executing transactions on the Ethereum network as part of block proposals. They include priority fees (fees paid by users for their transactions to be included) and MEV rewards (rewards for arranging transactions in a way that benefits the validator).\"}},\"title\":\"Native Staking SSV Strategy\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"BEACON_CHAIN_DEPOSIT_CONTRACT()\":{\"notice\":\"The address of the beacon chain deposit contract\"},\"FEE_ACCUMULATOR_ADDRESS()\":{\"notice\":\"Fee collector address\"},\"MAX_STAKE()\":{\"notice\":\"The maximum amount of ETH that can be staked by a validator\"},\"SSV_NETWORK_ADDRESS()\":{\"notice\":\"The address of the SSV Network contract used to interface with\"},\"SSV_TOKEN_ADDRESS()\":{\"notice\":\"SSV ERC20 token that serves as a payment for operating SSV validators\"},\"VAULT_ADDRESS()\":{\"notice\":\"Address of the OETH Vault proxy contract\"},\"WETH_TOKEN_ADDRESS()\":{\"notice\":\"The address of the Wrapped ETH (WETH) token contract\"},\"activeDepositedValidators()\":{\"notice\":\"The number of validators that have 32 (!) ETH actively deposited. When a new deposit to a validator happens this number increases, when a validator exit is detected this number decreases.\"},\"assetToPToken(address)\":{\"notice\":\"asset => pToken (Platform Specific Token Address)\"},\"checkBalance(address)\":{\"notice\":\"Returns the total value of (W)ETH that is staked to the validators and WETH deposits that are still to be staked. This does not include ETH from consensus rewards sitting in this strategy or ETH from MEV rewards in the FeeAccumulator. These rewards are harvested and sent to the Dripper so will eventually be sent to the Vault as WETH.\"},\"claimGovernance()\":{\"notice\":\"Claim Governance of the contract to a new account (`newGovernor`). Can only be called by the new Governor.\"},\"collectRewardTokens()\":{\"notice\":\"Collect accumulated reward token and send to Vault.\"},\"consensusRewards()\":{\"notice\":\"Keeps track of the total consensus rewards swept from the beacon chain\"},\"deposit(address,uint256)\":{\"notice\":\"Unlike other strategies, this does not deposit assets into the underlying platform. It just checks the asset is WETH and emits the Deposit event. To deposit WETH into validators `registerSsvValidator` and `stakeEth` must be used. Will NOT revert if the strategy is paused from an accounting failure.\"},\"depositAll()\":{\"notice\":\"Unlike other strategies, this does not deposit assets into the underlying platform. It just emits the Deposit event. To deposit WETH into validators `registerSsvValidator` and `stakeEth` must be used. Will NOT revert if the strategy is paused from an accounting failure.\"},\"depositSSV(uint64[],uint256,(uint32,uint64,uint64,bool,uint256))\":{\"notice\":\"Deposits more SSV Tokens to the SSV Network contract which is used to pay the SSV Operators.\"},\"doAccounting()\":{\"notice\":\"This notion page offers a good explanation of how the accounting functions https://www.notion.so/originprotocol/Limited-simplified-native-staking-accounting-67a217c8420d40678eb943b9da0ee77d In short, after dividing by 32, if the ETH remaining on the contract falls between 0 and fuseIntervalStart, the accounting function will treat that ETH as Beacon chain consensus rewards. On the contrary, if after dividing by 32, the ETH remaining on the contract falls between fuseIntervalEnd and 32, the accounting function will treat that as a validator slashing.Perform the accounting attributing beacon chain ETH to either full or partial withdrawals. Returns true when accounting is valid and fuse isn't \\\"blown\\\". Returns false when fuse is blown.\"},\"exitSsvValidator(bytes,uint64[])\":{\"notice\":\"Exit a validator from the Beacon chain. The staked ETH will eventually swept to this native staking strategy. Only the registrator can call this function.\"},\"fuseIntervalEnd()\":{\"notice\":\"end of fuse interval\"},\"fuseIntervalStart()\":{\"notice\":\"start of fuse interval\"},\"getRewardTokenAddresses()\":{\"notice\":\"Get the reward token addresses.\"},\"governor()\":{\"notice\":\"Returns the address of the current Governor.\"},\"harvesterAddress()\":{\"notice\":\"Address of the Harvester contract allowed to collect reward tokens\"},\"initialize(address[],address[],address[])\":{\"notice\":\"initialize function, to set up initial internal state\"},\"isGovernor()\":{\"notice\":\"Returns true if the caller is the current Governor.\"},\"manuallyFixAccounting(int256,int256,uint256)\":{\"notice\":\"Allow the Strategist to fix the accounting of this strategy and unpause.\"},\"platformAddress()\":{\"notice\":\"Address of the underlying platform\"},\"registerSsvValidator(bytes,uint64[],bytes,uint256,(uint32,uint64,uint64,bool,uint256))\":{\"notice\":\"Registers a new validator in the SSV Cluster. Only the registrator can call this function.\"},\"removePToken(uint256)\":{\"notice\":\"Remove a supported asset by passing its index. This method can only be called by the system Governor\"},\"removeSsvValidator(bytes,uint64[],(uint32,uint64,uint64,bool,uint256))\":{\"notice\":\"Remove a validator from the SSV Cluster. Make sure `exitSsvValidator` is called before and the validate has exited the Beacon chain. If removed before the validator has exited the beacon chain will result in the validator being slashed. Only the registrator can call this function.\"},\"rewardTokenAddresses(uint256)\":{\"notice\":\"Address of the reward tokens. eg CRV, BAL, CVX, AURA\"},\"safeApproveAllTokens()\":{\"notice\":\"Approves the SSV Network contract to transfer SSV tokens for deposits\"},\"setFuseInterval(uint256,uint256)\":{\"notice\":\"set fuse interval values\"},\"setHarvesterAddress(address)\":{\"notice\":\"Set the Harvester contract that can collect rewards.\"},\"setPTokenAddress(address,address)\":{\"notice\":\"Provide support for asset by passing its pToken address. This method can only be called by the system Governor\"},\"setRegistrator(address)\":{\"notice\":\"Set the address of the registrator which can register, exit and remove validators\"},\"setRewardTokenAddresses(address[])\":{\"notice\":\"Set the reward token addresses. Any old addresses will be overwritten.\"},\"stakeEth((bytes,bytes,bytes32)[])\":{\"notice\":\"Stakes WETH to the node validators\"},\"supportsAsset(address)\":{\"notice\":\"Returns bool indicating whether asset is supported by strategy.\"},\"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 strategy contracts, i.e. mistaken sends.\"},\"validatorRegistrator()\":{\"notice\":\"Address of the registrator - allowed to register, exit and remove validators\"},\"validatorsStates(bytes32)\":{\"notice\":\"State of the validators keccak256(pubKey) => state\"},\"vaultAddress()\":{\"notice\":\"Address of the OToken vault\"},\"withdraw(address,address,uint256)\":{\"notice\":\"Withdraw WETH from this contract. Used only if some WETH for is lingering on the contract. That can happen when: - the deposit was not a multiple of 32 WETH - someone sent WETH directly to this contract Will NOT revert if the strategy is paused from an accounting failure.\"},\"withdrawAll()\":{\"notice\":\"transfer all WETH deposits back to the vault. This does not withdraw from the validators. That has to be done separately with the `exitSsvValidator` and `removeSsvValidator` operations. This does not withdraw any execution rewards from the FeeAccumulator or consensus rewards in this strategy. Any ETH in this strategy that was swept from a full validator withdrawal will not be withdrawn. ETH from full validator withdrawals is sent to the Vault using `doAccounting`. Will NOT revert if the strategy is paused from an accounting failure.\"}},\"notice\":\"Strategy to deploy funds into DVT validators powered by the SSV Network\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol\":\"NativeStakingSSVStrategy\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"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\",\"keccak256\":\"0xe68ed7fb8766ed1e888291f881e36b616037f852b37d96877045319ad298ba87\",\"license\":\"MIT\"},\"@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/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\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"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/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\",\"keccak256\":\"0x598f90bdbc854250bbd5991426bfb43367207e64e33109c41aa8b54323fd8d8e\",\"license\":\"MIT\"},\"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 error ApprovalNotWithinTimeframe();\\n error CallerNotOwner();\\n error CallerNotWhitelisted();\\n error ClusterAlreadyEnabled();\\n error ClusterDoesNotExists();\\n error ClusterIsLiquidated();\\n error ClusterNotLiquidatable();\\n error ExceedValidatorLimit();\\n error FeeExceedsIncreaseLimit();\\n error FeeIncreaseNotAllowed();\\n error FeeTooHigh();\\n error FeeTooLow();\\n error IncorrectClusterState();\\n error IncorrectValidatorState();\\n error InsufficientBalance();\\n error InvalidOperatorIdsLength();\\n error InvalidPublicKeyLength();\\n error MaxValueExceeded();\\n error NewBlockPeriodIsBelowMinimum();\\n error NoFeeDeclared();\\n error NotAuthorized();\\n error OperatorAlreadyExists();\\n error OperatorDoesNotExist();\\n error OperatorsListNotUnique();\\n error SameFeeChangeNotAllowed();\\n error TargetModuleDoesNotExist();\\n error TokenTransferFailed();\\n error UnsortedOperatorsList();\\n error ValidatorAlreadyExists();\\n error ValidatorDoesNotExist();\\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 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 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 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\",\"keccak256\":\"0x76e2c5148727b72752939b06fee7abc1f732c18970b8c7db7fe7cdfe74629d36\",\"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/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/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\",\"keccak256\":\"0x05b7dce6c24d3cd4e48b5c6346d86e5e40ecc3291bcdf3f3ef091c98fc826519\",\"license\":\"MIT\"},\"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\\nimport { Governable } from \\\"../../governance/Governable.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 is Governable {\\n /// @notice The address of the Native Staking Strategy\\n address public immutable STRATEGY;\\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 }\\n}\\n\",\"keccak256\":\"0xf47bcc46ce70f649f061bec3d2303f376a15700ba18fe471fba823f60bdfed8b\",\"license\":\"MIT\"},\"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\\\";\\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\\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_ADDRESS;\\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 public immutable FEE_ACCUMULATOR_ADDRESS;\\n\\n // For future use\\n uint256[50] 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 _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 address _feeAccumulator,\\n address _beaconChainDepositContract\\n )\\n InitializableAbstractStrategy(_baseConfig)\\n ValidatorAccountant(\\n _wethAddress,\\n _baseConfig.vaultAddress,\\n _beaconChainDepositContract,\\n _ssvNetwork\\n )\\n {\\n SSV_TOKEN_ADDRESS = _ssvToken;\\n FEE_ACCUMULATOR_ADDRESS = _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 /// @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_TOKEN_ADDRESS).deposit{ value: ethRewards }();\\n\\n emit RewardTokenCollected(\\n harvesterAddress,\\n WETH_TOKEN_ADDRESS,\\n ethRewards\\n );\\n IERC20(WETH_TOKEN_ADDRESS).safeTransfer(\\n harvesterAddress,\\n ethRewards\\n );\\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_TOKEN_ADDRESS, \\\"Unsupported asset\\\");\\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_TOKEN_ADDRESS).balanceOf(\\n address(this)\\n );\\n if (wethBalance > 0) {\\n _deposit(WETH_TOKEN_ADDRESS, wethBalance);\\n }\\n }\\n\\n /// @notice Withdraw WETH from this contract. Used only if some WETH for is lingering on the contract. That\\n /// can happen when:\\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 _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 emit Withdrawal(_asset, address(0), _amount);\\n IERC20(_asset).safeTransfer(_recipient, _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_TOKEN_ADDRESS).balanceOf(\\n address(this)\\n );\\n if (wethBalance > 0) {\\n _withdraw(vaultAddress, WETH_TOKEN_ADDRESS, wethBalance);\\n }\\n }\\n\\n function _abstractSetPToken(address _asset, address) internal override {}\\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_TOKEN_ADDRESS, \\\"Unsupported asset\\\");\\n\\n balance =\\n // add the ETH that has been staked in validators\\n activeDepositedValidators *\\n 32 ether +\\n // add the WETH in the strategy from deposits that are still to be staked\\n IERC20(WETH_TOKEN_ADDRESS).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_TOKEN_ADDRESS;\\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_ADDRESS).approve(\\n SSV_NETWORK_ADDRESS,\\n type(uint256).max\\n );\\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 ||\\n msg.sender == WETH_TOKEN_ADDRESS,\\n \\\"eth not from allowed contracts\\\"\\n );\\n }\\n}\\n\",\"keccak256\":\"0x16d14755655e07e98a4758a1328a8117192b3cb8a4c74725b67c2584560fcb2d\",\"license\":\"MIT\"},\"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 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 MAX_STAKE = 32 ether;\\n\\n /// @notice Keeps track of the total consensus rewards swept from the beacon chain\\n uint256 public consensusRewards = 0;\\n\\n /// @notice start of fuse interval\\n uint256 public fuseIntervalStart = 0;\\n /// @notice end of fuse interval\\n uint256 public fuseIntervalEnd = 0;\\n\\n uint256[50] 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 constructor(\\n address _wethAddress,\\n address _vaultAddress,\\n address _beaconChainDepositContract,\\n address _ssvNetwork\\n )\\n ValidatorRegistrator(\\n _wethAddress,\\n _vaultAddress,\\n _beaconChainDepositContract,\\n _ssvNetwork\\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 _fuseIntervalStart < 32 ether &&\\n _fuseIntervalEnd < 32 ether &&\\n _fuseIntervalEnd - _fuseIntervalStart >= 4 ether,\\n \\\"incorrect fuse interval\\\"\\n );\\n\\n emit FuseIntervalUpdated(_fuseIntervalStart, _fuseIntervalEnd);\\n\\n fuseIntervalStart = _fuseIntervalStart;\\n fuseIntervalEnd = _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 returns (bool accountingValid)\\n {\\n // pause the accounting on failure\\n accountingValid = _doAccounting(true);\\n }\\n\\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 >= MAX_STAKE) {\\n uint256 fullyWithdrawnValidators = newSweptETH / MAX_STAKE;\\n if (activeDepositedValidators < fullyWithdrawnValidators) {\\n return _failAccounting(pauseOnFail);\\n }\\n activeDepositedValidators -= fullyWithdrawnValidators;\\n\\n uint256 wethToVault = MAX_STAKE * fullyWithdrawnValidators;\\n IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: wethToVault }();\\n IWETH9(WETH_TOKEN_ADDRESS).transfer(VAULT_ADDRESS, 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 < 32 ether, \\\"unexpected accounting\\\");\\n\\n // If no Beacon chain consensus rewards swept\\n if (ethRemaining == 0) {\\n // do nothing\\n return accountingValid;\\n }\\n // Beacon chain consensus rewards swept (partial validator withdrawals)\\n else if (ethRemaining < fuseIntervalStart) {\\n // solhint-disable-next-line reentrancy\\n consensusRewards += ethRemaining;\\n emit AccountingConsensusRewards(ethRemaining);\\n }\\n // Beacon chain consensus rewards swept but also a slashed validator fully exited\\n else if (ethRemaining > fuseIntervalEnd) {\\n IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: ethRemaining }();\\n IWETH9(WETH_TOKEN_ADDRESS).transfer(VAULT_ADDRESS, ethRemaining);\\n activeDepositedValidators -= 1;\\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 /// @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 plus one, minus one or unchanged with zero\\n /// @param _wethToVaultAmount the amount of WETH to be sent to the Vault\\n /// @param _consensusRewardsDelta adjust the accounted for consensus rewards up or down\\n function manuallyFixAccounting(\\n int256 _validatorsDelta,\\n int256 _consensusRewardsDelta,\\n uint256 _wethToVaultAmount\\n ) external onlyStrategist whenPaused {\\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(_wethToVaultAmount <= 32 ether, \\\"invalid wethToVaultAmount\\\");\\n\\n emit AccountingManuallyFixed(\\n _validatorsDelta,\\n _consensusRewardsDelta,\\n _wethToVaultAmount\\n );\\n\\n activeDepositedValidators = uint256(\\n int256(activeDepositedValidators) + _validatorsDelta\\n );\\n consensusRewards = uint256(\\n int256(consensusRewards) + _consensusRewardsDelta\\n );\\n if (_wethToVaultAmount > 0) {\\n IWETH9(WETH_TOKEN_ADDRESS).transfer(\\n VAULT_ADDRESS,\\n _wethToVaultAmount\\n );\\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\",\"keccak256\":\"0xc6c306bde6b18189944f3d03fc82996b2e0c54b3a2882ee8d0fece0d71949e11\",\"license\":\"MIT\"},\"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 address of the Wrapped ETH (WETH) token contract\\n address public immutable WETH_TOKEN_ADDRESS;\\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_ADDRESS;\\n /// @notice Address of the OETH Vault proxy contract\\n address public immutable VAULT_ADDRESS;\\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\\n // For future use\\n uint256[50] private __gap;\\n\\n enum VALIDATOR_STATE {\\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 newAddress);\\n event ETHStaked(bytes pubkey, uint256 amount, bytes withdrawal_credentials);\\n event SSVValidatorRegistered(bytes pubkey, uint64[] operatorIds);\\n event SSVValidatorExitInitiated(bytes pubkey, uint64[] operatorIds);\\n event SSVValidatorExitCompleted(bytes pubkey, uint64[] operatorIds);\\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 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 constructor(\\n address _wethAddress,\\n address _vaultAddress,\\n address _beaconChainDepositContract,\\n address _ssvNetwork\\n ) {\\n WETH_TOKEN_ADDRESS = _wethAddress;\\n BEACON_CHAIN_DEPOSIT_CONTRACT = _beaconChainDepositContract;\\n SSV_NETWORK_ADDRESS = _ssvNetwork;\\n VAULT_ADDRESS = _vaultAddress;\\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 emit RegistratorChanged(_address);\\n validatorRegistrator = _address;\\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 function stakeEth(ValidatorStakeData[] calldata validators)\\n external\\n onlyRegistrator\\n whenNotPaused\\n {\\n uint256 requiredETH = validators.length * 32 ether;\\n\\n // Check there is enough WETH from the deposits sitting in this strategy contract\\n require(\\n requiredETH <= IWETH9(WETH_TOKEN_ADDRESS).balanceOf(address(this)),\\n \\\"insufficient WETH\\\"\\n );\\n\\n // Convert required ETH from WETH\\n IWETH9(WETH_TOKEN_ADDRESS).withdraw(requiredETH);\\n\\n // For each validator\\n for (uint256 i = 0; i < validators.length; ) {\\n bytes32 pubkeyHash = keccak256(validators[i].pubkey);\\n VALIDATOR_STATE currentState = validatorsStates[pubkeyHash];\\n\\n require(\\n currentState == VALIDATOR_STATE.REGISTERED,\\n \\\"Validator not registered\\\"\\n );\\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 withdrawal_credentials = abi.encodePacked(\\n bytes1(0x01),\\n bytes11(0),\\n address(this)\\n );\\n IDepositContract(BEACON_CHAIN_DEPOSIT_CONTRACT).deposit{\\n value: 32 ether\\n }(\\n validators[i].pubkey,\\n withdrawal_credentials,\\n validators[i].signature,\\n validators[i].depositDataRoot\\n );\\n\\n activeDepositedValidators += 1;\\n emit ETHStaked(\\n validators[i].pubkey,\\n 32 ether,\\n withdrawal_credentials\\n );\\n\\n validatorsStates[pubkeyHash] = VALIDATOR_STATE.STAKED;\\n\\n unchecked {\\n ++i;\\n }\\n }\\n }\\n\\n /// @notice Registers a new validator in the SSV Cluster.\\n /// Only the registrator can call this function.\\n function registerSsvValidator(\\n bytes calldata publicKey,\\n uint64[] calldata operatorIds,\\n bytes calldata sharesData,\\n uint256 amount,\\n Cluster calldata cluster\\n ) external onlyRegistrator whenNotPaused {\\n ISSVNetwork(SSV_NETWORK_ADDRESS).registerValidator(\\n publicKey,\\n operatorIds,\\n sharesData,\\n amount,\\n cluster\\n );\\n validatorsStates[keccak256(publicKey)] = VALIDATOR_STATE.REGISTERED;\\n emit SSVValidatorRegistered(publicKey, operatorIds);\\n }\\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 function exitSsvValidator(\\n bytes calldata publicKey,\\n uint64[] calldata operatorIds\\n ) external onlyRegistrator whenNotPaused {\\n VALIDATOR_STATE currentState = validatorsStates[keccak256(publicKey)];\\n require(currentState == VALIDATOR_STATE.STAKED, \\\"Validator not staked\\\");\\n\\n ISSVNetwork(SSV_NETWORK_ADDRESS).exitValidator(publicKey, operatorIds);\\n emit SSVValidatorExitInitiated(publicKey, operatorIds);\\n\\n validatorsStates[keccak256(publicKey)] = VALIDATOR_STATE.EXITING;\\n }\\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 function removeSsvValidator(\\n bytes calldata publicKey,\\n uint64[] calldata operatorIds,\\n Cluster calldata cluster\\n ) external onlyRegistrator whenNotPaused {\\n VALIDATOR_STATE currentState = validatorsStates[keccak256(publicKey)];\\n require(\\n currentState == VALIDATOR_STATE.EXITING,\\n \\\"Validator not exiting\\\"\\n );\\n\\n ISSVNetwork(SSV_NETWORK_ADDRESS).removeValidator(\\n publicKey,\\n operatorIds,\\n cluster\\n );\\n emit SSVValidatorExitCompleted(publicKey, operatorIds);\\n\\n validatorsStates[keccak256(publicKey)] = VALIDATOR_STATE.EXIT_COMPLETE;\\n }\\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 cluster The SSV cluster details that must be derived from emitted events from the SSVNetwork contract.\\n function depositSSV(\\n uint64[] memory operatorIds,\\n uint256 amount,\\n Cluster memory cluster\\n ) external onlyStrategist {\\n ISSVNetwork(SSV_NETWORK_ADDRESS).deposit(\\n address(this),\\n operatorIds,\\n amount,\\n cluster\\n );\\n }\\n}\\n\",\"keccak256\":\"0x4bc23d19500e2d306fd546c4ab9c4c53292d4ef54392ec4f1ae62dd7601a3d24\",\"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/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\",\"keccak256\":\"0x5e17bb3db9f9e1014b7c5c836547f8fa81e02af7568c0bb8f2a2e0e7c2192db4\",\"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/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": "0x610180604052600060685560006069556000606a553480156200002157600080fd5b5060405162004c9a38038062004c9a833981016040819052620000449162000147565b8585876020015183868383838362000062336200011760201b60201c565b60008051602062004c7a833981519152546040516001600160a01b03909116906000907fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a908290a36033805460ff191690556001600160601b0319606094851b811660805291841b821660a052831b811660c05290821b811660e0528651821b811661010052602090960151811b86166101205298891b851661014052505050509190931b1661016052506200022292505050565b60008051602062004c7a83398151915255565b80516001600160a01b03811681146200014257600080fd5b919050565b60008060008060008086880360e08112156200016257600080fd5b60408112156200017157600080fd5b50604080519081016001600160401b0381118282101715620001a357634e487b7160e01b600052604160045260246000fd5b604052620001b1886200012a565b8152620001c1602089016200012a565b60208201529550620001d6604088016200012a565b9450620001e6606088016200012a565b9350620001f6608088016200012a565b92506200020660a088016200012a565b91506200021660c088016200012a565b90509295509295509295565b60805160601c60a05160601c60c05160601c60e05160601c6101005160601c6101205160601c6101405160601c6101605160601c6148c2620003b8600039600081816102a70152818161096e0152612da901526000818161057d01526122fc01526000818161045101528181610d41015281816118c001528181611a390152818161265b01526128e30152600061093a0152600081816106ec01528181610b09015281816117ee01528181611a8901528181611d6c0152818161332201526135730152600081816109b701528181610bdf015281816116c0015281816122cc015281816123e401526127d90152600081816108a601526114070152600081816102d9015281816104db015281816107bd01528181610a7001528181610db601528181610f850152818161100d015281816111bc01528181611297015281816119aa01528181611a5a01528181611d9b0152818161296e015281816129fd01528181612eae01528181612f3301528181612fa70152818161329c01528181613351015281816134ed01526135a201526148c26000f3fe6080604052600436106102975760003560e01c8063853828b61161015a578063c2e1e3f4116100c1578063d9f00ec71161007a578063d9f00ec714610908578063dbe55e5614610928578063dd505df61461095c578063de5f626814610990578063f1188e40146109a5578063f6ca71b0146109d957600080fd5b8063c2e1e3f414610842578063c7af335214610862578063c98517c514610877578063cceab75014610894578063d38bfff4146108c8578063d9caed12146108e857600080fd5b80639da0e462116101135780639da0e4621461074e578063a4f98af41461078b578063aa388af6146107a0578063ab12edf5146107ed578063ad1728cb1461080d578063bb1b918d1461082257600080fd5b8063853828b61461068057806387bae867146106955780638d7c0e46146106ba5780639092c31c146106da5780639136616a1461070e57806396d538bb1461072e57600080fd5b80635c975abb116101fe5780636e811d38116101b75780636e811d38146105d55780636ef38795146105f557806371a735f3146106155780637b2d9b2c14610635578063842f5c46146106555780638456cb591461066b57600080fd5b80635c975abb146105125780635d36b190146105365780635f5152261461054b5780636093d3801461056b57806366e3667e1461059f57806367c7066c146105b557600080fd5b8063430bf08a11610250578063430bf08a1461043f578063435356d11461047357806347e7ef2414610493578063484be812146104b3578063579a7e1a146104c95780635a063f63146104fd57600080fd5b80630c340a24146103535780630ed57b3a146103855780630fc3b4c4146103a55780631072cbea146103db57806322495dc8146103fb5780633c8649591461041b57600080fd5b3661034e57336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614806102fb5750336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016145b61034c5760405162461bcd60e51b815260206004820152601e60248201527f657468206e6f742066726f6d20616c6c6f77656420636f6e747261637473000060448201526064015b60405180910390fd5b005b600080fd5b34801561035f57600080fd5b506103686109fb565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561039157600080fd5b5061034c6103a0366004613c43565b610a18565b3480156103b157600080fd5b506103686103c0366004613c09565b609f602052600090815260409020546001600160a01b031681565b3480156103e757600080fd5b5061034c6103f6366004613cbd565b610a4a565b34801561040757600080fd5b5061034c610416366004613db1565b610b07565b34801561042757600080fd5b5061043160695481565b60405190815260200161037c565b34801561044b57600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b34801561047f57600080fd5b5061034c61048e366004613d2a565b610c51565b34801561049f57600080fd5b5061034c6104ae366004613cbd565b610d36565b3480156104bf57600080fd5b50610431606a5481565b3480156104d557600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b34801561050957600080fd5b5061034c610e3c565b34801561051e57600080fd5b5060335460ff165b604051901515815260200161037c565b34801561054257600080fd5b5061034c610edb565b34801561055757600080fd5b50610431610566366004613c09565b610f81565b34801561057757600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b3480156105ab57600080fd5b5061043160345481565b3480156105c157600080fd5b5060a354610368906001600160a01b031681565b3480156105e157600080fd5b5061034c6105f0366004613c09565b6110b5565b34801561060157600080fd5b5061034c610610366004613ce9565b61113d565b34801561062157600080fd5b5061034c610630366004613fbf565b6115c9565b34801561064157600080fd5b50610368610650366004613e87565b6117c2565b34801561066157600080fd5b5061043160685481565b34801561067757600080fd5b5061034c6117ec565b34801561068c57600080fd5b5061034c6118b5565b3480156106a157600080fd5b506033546103689061010090046001600160a01b031681565b3480156106c657600080fd5b5061034c6106d5366004614040565b611a87565b3480156106e657600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b34801561071a57600080fd5b5061034c610729366004613e87565b611e6f565b34801561073a57600080fd5b5061034c610749366004613ce9565b61203a565b34801561075a57600080fd5b5061077e610769366004613e87565b60356020526000908152604090205460ff1681565b60405161037c91906144ab565b34801561079757600080fd5b5061052661215a565b3480156107ac57600080fd5b506105266107bb366004613c09565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0390811691161490565b3480156107f957600080fd5b5061034c610808366004614085565b6121b9565b34801561081957600080fd5b5061034c6122b5565b34801561082e57600080fd5b5061034c61083d366004613f0b565b61237b565b34801561084e57600080fd5b5061034c61085d366004613c09565b6124ee565b34801561086e57600080fd5b5061052661257b565b34801561088357600080fd5b506104316801bc16d674ec80000081565b3480156108a057600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b3480156108d457600080fd5b5061034c6108e3366004613c09565b6125ac565b3480156108f457600080fd5b5061034c610903366004613c7c565b612650565b34801561091457600080fd5b5061034c610923366004613ea0565b6126e3565b34801561093457600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b34801561096857600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b34801561099c57600080fd5b5061034c6128d8565b3480156109b157600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b3480156109e557600080fd5b506109ee612a22565b60405161037c9190614281565b6000610a1360008051602061486d8339815191525490565b905090565b610a2061257b565b610a3c5760405162461bcd60e51b81526004016103439061451d565b610a468282612a84565b5050565b610a5261257b565b610a6e5760405162461bcd60e51b81526004016103439061451d565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b039081169083161415610aeb5760405162461bcd60e51b815260206004820152601f60248201527f43616e6e6f74207472616e7366657220737570706f72746564206173736574006044820152606401610343565b610a46610af66109fb565b6001600160a01b0384169083612be3565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b158015610b6057600080fd5b505afa158015610b74573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b989190613c26565b6001600160a01b0316336001600160a01b031614610bc85760405162461bcd60e51b8152600401610343906145dd565b60405163bc26e7e560e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063bc26e7e590610c1a9030908790879087906004016141d1565b600060405180830381600087803b158015610c3457600080fd5b505af1158015610c48573d6000803e3d6000fd5b50505050505050565b610c5961257b565b610c755760405162461bcd60e51b81526004016103439061451d565b600054610100900460ff1680610c8e575060005460ff16155b610cf15760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610343565b600054610100900460ff16158015610d13576000805461ffff19166101011790555b610d1e848484612c35565b8015610d30576000805461ff00191690555b50505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610d7e5760405162461bcd60e51b8152600401610343906144e6565b60008051602061484d83398151915280546002811415610db05760405162461bcd60e51b8152600401610343906145b5565b600282557f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316846001600160a01b031614610e295760405162461bcd60e51b8152602060048201526011602482015270155b9cdd5c1c1bdc9d195908185cdcd95d607a1b6044820152606401610343565b610e338484612cf0565b50600190555050565b60a3546001600160a01b03163314610e965760405162461bcd60e51b815260206004820152601b60248201527f43616c6c6572206973206e6f74207468652048617276657374657200000000006044820152606401610343565b60008051602061484d83398151915280546002811415610ec85760405162461bcd60e51b8152600401610343906145b5565b60028255610ed4612d82565b5060019055565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b031614610f765760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b6064820152608401610343565b610f7f33612fd0565b565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b031614610ff85760405162461bcd60e51b8152602060048201526011602482015270155b9cdd5c1c1bdc9d195908185cdcd95d607a1b6044820152606401610343565b6040516370a0823160e01b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b15801561105757600080fd5b505afa15801561106b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061108f919061406c565b6034546110a5906801bc16d674ec80000061473e565b6110af9190614704565b92915050565b6110bd61257b565b6110d95760405162461bcd60e51b81526004016103439061451d565b6040516001600160a01b03821681527f83f29c79feb71f8fba9d0fbc4ba5f0982a28b6b1e868b3fc50e6400d100bca0f9060200160405180910390a1603380546001600160a01b0390921661010002610100600160a81b0319909216919091179055565b60335461010090046001600160a01b0316331461116c5760405162461bcd60e51b81526004016103439061457e565b60335460ff161561118f5760405162461bcd60e51b815260040161034390614554565b60006111a4826801bc16d674ec80000061473e565b6040516370a0823160e01b81523060048201529091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b15801561120657600080fd5b505afa15801561121a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061123e919061406c565b8111156112815760405162461bcd60e51b81526020600482015260116024820152700d2dce6eaccccd2c6d2cadce840ae8aa89607b1b6044820152606401610343565b604051632e1a7d4d60e01b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b1580156112e357600080fd5b505af11580156112f7573d6000803e3d6000fd5b5050505060005b82811015610d3057600084848381811061131a5761131a6147fd565b905060200281019061132c919061465a565b6113369080614614565b6040516113449291906141a5565b6040805191829003909120600081815260356020529182205490925060ff1690816003811115611376576113766147d1565b146113c35760405162461bcd60e51b815260206004820152601860248201527f56616c696461746f72206e6f74207265676973746572656400000000000000006044820152606401610343565b60408051600160f81b60208201526000602182018190526bffffffffffffffffffffffff193060601b16602c830152910160405160208183030381529060405290507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663228951186801bc16d674ec800000898988818110611450576114506147fd565b9050602002810190611462919061465a565b61146c9080614614565b858c8c8b81811061147f5761147f6147fd565b9050602002810190611491919061465a565b61149f906020810190614614565b8e8e8d8181106114b1576114b16147fd565b90506020028101906114c3919061465a565b604001356040518863ffffffff1660e01b81526004016114e896959493929190614430565b6000604051808303818588803b15801561150157600080fd5b505af1158015611515573d6000803e3d6000fd5b505050505060016034600082825461152d9190614704565b909155507ffeb31a79d38edb1b090d516e4df3e273651179c6f2c2ec53a9a22ae015b70ba99050878786818110611566576115666147fd565b9050602002810190611578919061465a565b6115829080614614565b6801bc16d674ec8000008460405161159d949392919061447f565b60405180910390a150506000908152603560205260409020805460ff19166001908117909155016112fe565b60335461010090046001600160a01b031633146115f85760405162461bcd60e51b81526004016103439061457e565b60335460ff161561161b5760405162461bcd60e51b815260040161034390614554565b60006035600087876040516116319291906141a5565b604080519182900390912082526020820192909252016000205460ff1690506002816003811115611664576116646147d1565b146116a95760405162461bcd60e51b815260206004820152601560248201527456616c696461746f72206e6f742065786974696e6760581b6044820152606401610343565b6040516312b3fc1960e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906312b3fc19906116fd90899089908990899089906004016143ef565b600060405180830381600087803b15801561171757600080fd5b505af115801561172b573d6000803e3d6000fd5b505050507ff72821b8777f002ccdf6326f1242d9e0f762eb077668b67bebe640535378066d868686866040516117649493929190614366565b60405180910390a160036035600088886040516117829291906141a5565b60408051918290039091208252602082019290925201600020805460ff191660018360038111156117b5576117b56147d1565b0217905550505050505050565b60a481815481106117d257600080fd5b6000918252602090912001546001600160a01b0316905081565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b15801561184557600080fd5b505afa158015611859573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061187d9190613c26565b6001600160a01b0316336001600160a01b0316146118ad5760405162461bcd60e51b8152600401610343906145dd565b610f7f613091565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016148061190457506118ef6109fb565b6001600160a01b0316336001600160a01b0316145b61195c5760405162461bcd60e51b815260206004820152602360248201527f43616c6c6572206973206e6f7420746865205661756c74206f7220476f7665726044820152623737b960e91b6064820152608401610343565b60008051602061484d8339815191528054600281141561198e5760405162461bcd60e51b8152600401610343906145b5565b600282556040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b1580156119f457600080fd5b505afa158015611a08573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a2c919061406c565b90508015611a7f57611a7f7f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000083613106565b505060019055565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b158015611ae057600080fd5b505afa158015611af4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b189190613c26565b6001600160a01b0316336001600160a01b031614611b485760405162461bcd60e51b8152600401610343906145dd565b60335460ff16611b915760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610343565b6002198312158015611ba4575060038313155b8015611bbe5750600083603454611bbb91906146c3565b12155b611c0a5760405162461bcd60e51b815260206004820152601760248201527f696e76616c69642076616c696461746f727344656c74610000000000000000006044820152606401610343565b6811ff6cf0fd15afffff198212158015611c2d57506811ff6cf0fd15b000008213155b8015611c475750600082606854611c4491906146c3565b12155b611c935760405162461bcd60e51b815260206004820152601d60248201527f696e76616c696420636f6e73656e7375735265776172647344656c74610000006044820152606401610343565b6801bc16d674ec800000811115611cec5760405162461bcd60e51b815260206004820152601960248201527f696e76616c69642077657468546f5661756c74416d6f756e74000000000000006044820152606401610343565b60408051848152602081018490529081018290527f80d022717ea022455c5886b8dd8a29c037570aae58aeb4d7b136d7a10ec2e4319060600160405180910390a182603454611d3b91906146c3565b603455606854611d4c9083906146c3565b6068558015611e195760405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018390527f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb90604401602060405180830381600087803b158015611ddf57600080fd5b505af1158015611df3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e179190613e6a565b505b611e2360006131fe565b611e625760405162461bcd60e51b815260206004820152601060248201526f333ab9b29039ba34b63610313637bbb760811b6044820152606401610343565b611e6a613684565b505050565b611e7761257b565b611e935760405162461bcd60e51b81526004016103439061451d565b60a0548110611ed45760405162461bcd60e51b815260206004820152600d60248201526c092dcecc2d8d2c840d2dcc8caf609b1b6044820152606401610343565b600060a08281548110611ee957611ee96147fd565b60009182526020808320909101546001600160a01b03908116808452609f90925260409092205460a05491935090911690611f269060019061475d565b831015611fa85760a08054611f3d9060019061475d565b81548110611f4d57611f4d6147fd565b60009182526020909120015460a080546001600160a01b039092169185908110611f7957611f796147fd565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505b60a0805480611fb957611fb96147e7565b60008281526020808220600019908401810180546001600160a01b031990811690915593019093556001600160a01b03858116808352609f855260409283902080549094169093559051908416815290917f16b7600acff27e39a8a96056b3d533045298de927507f5c1d97e4accde60488c910160405180910390a2505050565b61204261257b565b61205e5760405162461bcd60e51b81526004016103439061451d565b8060005b8181101561211157600084848381811061207e5761207e6147fd565b90506020020160208101906120939190613c09565b6001600160a01b031614156121015760405162461bcd60e51b815260206004820152602e60248201527f43616e206e6f742073657420616e20656d70747920616464726573732061732060448201526d30903932bbb0b932103a37b5b2b760911b6064820152608401610343565b61210a816147a0565b9050612062565b507f04c0b9649497d316554306e53678d5f5f5dbc3a06f97dec13ff4cfe98b986bbc60a48484604051612146939291906142ce565b60405180910390a1610d3060a48484613962565b60335460009061010090046001600160a01b0316331461218c5760405162461bcd60e51b81526004016103439061457e565b60335460ff16156121af5760405162461bcd60e51b815260040161034390614554565b610a1360016131fe565b6121c161257b565b6121dd5760405162461bcd60e51b81526004016103439061451d565b80821080156121f457506801bc16d674ec80000082105b801561220857506801bc16d674ec80000081105b80156122255750673782dace9d900000612222838361475d565b10155b6122715760405162461bcd60e51b815260206004820152601760248201527f696e636f7272656374206675736520696e74657276616c0000000000000000006044820152606401610343565b60408051838152602081018390527fcb8d24e46eb3c402bf344ee60a6576cba9ef2f59ea1af3b311520704924e901a910160405180910390a1606991909155606a55565b60405163095ea7b360e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015260001960248301527f0000000000000000000000000000000000000000000000000000000000000000169063095ea7b390604401602060405180830381600087803b15801561234057600080fd5b505af1158015612354573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123789190613e6a565b50565b60335461010090046001600160a01b031633146123aa5760405162461bcd60e51b81526004016103439061457e565b60335460ff16156123cd5760405162461bcd60e51b815260040161034390614554565b6040516301ba3ee760e21b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906306e8fb9c90612427908b908b908b908b908b908b908b908b9060040161438d565b600060405180830381600087803b15801561244157600080fd5b505af1158015612455573d6000803e3d6000fd5b505050506000603560008a8a60405161246f9291906141a5565b60408051918290039091208252602082019290925201600020805460ff191660018360038111156124a2576124a26147d1565b02179055507f75c4a66b2c6c28cf46db7131182a812e4fbbb2f0591377aa83a737909a9b68c3888888886040516124dc9493929190614366565b60405180910390a15050505050505050565b6124f661257b565b6125125760405162461bcd60e51b81526004016103439061451d565b60a354604080516001600160a01b03928316815291831660208301527fe48386b84419f4d36e0f96c10cc3510b6fb1a33795620c5098b22472bbe90796910160405180910390a160a380546001600160a01b0319166001600160a01b0392909216919091179055565b600061259360008051602061486d8339815191525490565b6001600160a01b0316336001600160a01b031614905090565b6125b461257b565b6125d05760405162461bcd60e51b81526004016103439061451d565b6125f8817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b031661261860008051602061486d8339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146126985760405162461bcd60e51b8152600401610343906144e6565b60008051602061484d833981519152805460028114156126ca5760405162461bcd60e51b8152600401610343906145b5565b600282556126d9858585613106565b5060019055505050565b60335461010090046001600160a01b031633146127125760405162461bcd60e51b81526004016103439061457e565b60335460ff16156127355760405162461bcd60e51b815260040161034390614554565b600060356000868660405161274b9291906141a5565b604080519182900390912082526020820192909252016000205460ff169050600181600381111561277e5761277e6147d1565b146127c25760405162461bcd60e51b815260206004820152601460248201527315985b1a59185d1bdc881b9bdd081cdd185ad95960621b6044820152606401610343565b604051633877322b60e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690633877322b90612814908890889088908890600401614366565b600060405180830381600087803b15801561282e57600080fd5b505af1158015612842573d6000803e3d6000fd5b505050507ff8821da16f5ed966b41e0343c3eff9903af782d74f99f1689dd9d4562b6545b38585858560405161287b9493929190614366565b60405180910390a160026035600087876040516128999291906141a5565b60408051918290039091208252602082019290925201600020805460ff191660018360038111156128cc576128cc6147d1565b02179055505050505050565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146129205760405162461bcd60e51b8152600401610343906144e6565b60008051602061484d833981519152805460028114156129525760405162461bcd60e51b8152600401610343906145b5565b600282556040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b1580156129b857600080fd5b505afa1580156129cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129f0919061406c565b90508015611a7f57611a7f7f000000000000000000000000000000000000000000000000000000000000000082612cf0565b606060a4805480602002602001604051908101604052809291908181526020018280548015612a7a57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612a5c575b5050505050905090565b6001600160a01b038281166000908152609f60205260409020541615612ae15760405162461bcd60e51b81526020600482015260126024820152711c151bdad95b88185b1c9958591e481cd95d60721b6044820152606401610343565b6001600160a01b03821615801590612b0157506001600160a01b03811615155b612b415760405162461bcd60e51b8152602060048201526011602482015270496e76616c69642061646472657373657360781b6044820152606401610343565b6001600160a01b038281166000818152609f6020908152604080832080549587166001600160a01b0319968716811790915560a0805460018101825594527f78fdc8d422c49ced035a9edf18d00d3c6a8d81df210f3e5e448e045e77b41e8890930180549095168417909455925190815290917fef6485b84315f9b1483beffa32aae9a0596890395e3d7521f1c5fbb51790e765910160405180910390a25050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052611e6a9084906136fe565b8251612c489060a49060208601906139c5565b50815181518114612c925760405162461bcd60e51b8152602060048201526014602482015273496e76616c696420696e7075742061727261797360601b6044820152606401610343565b60005b81811015612ce957612cd9848281518110612cb257612cb26147fd565b6020026020010151848381518110612ccc57612ccc6147fd565b6020026020010151612a84565b612ce2816147a0565b9050612c95565b5050505050565b60008111612d395760405162461bcd60e51b81526020600482015260166024820152754d757374206465706f73697420736f6d657468696e6760501b6044820152606401610343565b6040805160008152602081018390526001600160a01b038416917f5548c837ab068cf56a2c2479df0882a4922fd203edb7517321831d95078c5f62910160405180910390a25050565b60335460ff1615612da55760405162461bcd60e51b815260040161034390614554565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663e52253816040518163ffffffff1660e01b8152600401602060405180830381600087803b158015612e0257600080fd5b505af1158015612e16573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e3a919061406c565b9050600060685482612e4c9190614704565b905080471015612e9e5760405162461bcd60e51b815260206004820152601860248201527f696e73756666696369656e74206574682062616c616e636500000000000000006044820152606401610343565b8015610a465760006068819055507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b158015612f0757600080fd5b505af1158015612f1b573d6000803e3d6000fd5b505060a354604080516001600160a01b0392831681527f0000000000000000000000000000000000000000000000000000000000000000909216602083015281018590527ff6c07a063ed4e63808eb8da7112d46dbcd38de2b40a73dbcc9353c5a94c7235393506060019150612f8e9050565b60405180910390a160a354610a46906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116911683612be3565b6001600160a01b0381166130265760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f7220697320616464726573732830290000000000006044820152606401610343565b806001600160a01b031661304660008051602061486d8339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a36123788160008051602061486d83398151915255565b60335460ff16156130b45760405162461bcd60e51b815260040161034390614554565b6033805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586130e93390565b6040516001600160a01b03909116815260200160405180910390a1565b600081116131565760405162461bcd60e51b815260206004820152601760248201527f4d75737420776974686472617720736f6d657468696e670000000000000000006044820152606401610343565b6001600160a01b0383166131a55760405162461bcd60e51b8152602060048201526016602482015275135d5cdd081cdc1958da599e481c9958da5c1a595b9d60521b6044820152606401610343565b6040805160008152602081018390526001600160a01b038416917f2717ead6b9200dd235aad468c9809ea400fe33ac69b5bfaa6d3e90fc922b6398910160405180910390a2611e6a6001600160a01b0383168483612be3565b6000606854471015613213576110af826137d0565b600060685447613223919061475d565b9050600191506801bc16d674ec800000811061341957600061324e6801bc16d674ec8000008361471c565b905080603454101561326b57613263846137d0565b949350505050565b806034600082825461327d919061475d565b9091555060009050613298826801bc16d674ec80000061473e565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b1580156132f557600080fd5b505af1158015613309573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb92506044019050602060405180830381600087803b15801561339957600080fd5b505af11580156133ad573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133d19190613e6a565b5060345460408051848152602081019290925281018290527fbe7040030ff7b347853214bf49820c6d455fedf58f3815f85c7bc5216993682b9060600160405180910390a150505b600060685447613429919061475d565b90506801bc16d674ec800000811061347b5760405162461bcd60e51b8152602060048201526015602482015274756e6578706563746564206163636f756e74696e6760581b6044820152606401610343565b80613487575050919050565b6069548110156134e15780606860008282546134a39190614704565b90915550506040518181527f7a745a2c63a535068f52ceca27debd5297bbad5f7f37ec53d044a59d0362445d906020015b60405180910390a161367d565b606a54811115613674577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b15801561354657600080fd5b505af115801561355a573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb92506044019050602060405180830381600087803b1580156135ea57600080fd5b505af11580156135fe573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136229190613e6a565b50600160346000828254613636919061475d565b909155505060345460408051918252602082018390527f6aa7e30787b26429ced603a7aba8b19c4b5d5bcf29a3257da953c8d53bcaa3a691016134d4565b613263846137d0565b5050919050565b60335460ff166136cd5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610343565b6033805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa336130e9565b6000613753826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166137e89092919063ffffffff16565b805190915015611e6a57808060200190518101906137719190613e6a565b611e6a5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610343565b600081156137e0576137e0613091565b506000919050565b60606137f78484600085613801565b90505b9392505050565b6060824710156138625760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610343565b843b6138b05760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610343565b600080866001600160a01b031685876040516138cc91906141b5565b60006040518083038185875af1925050503d8060008114613909576040519150601f19603f3d011682016040523d82523d6000602084013e61390e565b606091505b509150915061391e828286613929565b979650505050505050565b606083156139385750816137fa565b8251156139485782518084602001fd5b8160405162461bcd60e51b815260040161034391906144d3565b8280548282559060005260206000209081019282156139b5579160200282015b828111156139b55781546001600160a01b0319166001600160a01b03843516178255602090920191600190910190613982565b506139c1929150613a1a565b5090565b8280548282559060005260206000209081019282156139b5579160200282015b828111156139b557825182546001600160a01b0319166001600160a01b039091161782556020909201916001909101906139e5565b5b808211156139c15760008155600101613a1b565b60008083601f840112613a4157600080fd5b5081356001600160401b03811115613a5857600080fd5b6020830191508360208260051b8501011115613a7357600080fd5b9250929050565b600082601f830112613a8b57600080fd5b81356020613aa0613a9b836146a0565b614670565b80838252828201915082860187848660051b8901011115613ac057600080fd5b60005b85811015613ae8578135613ad681614829565b84529284019290840190600101613ac3565b5090979650505050505050565b60008083601f840112613b0757600080fd5b5081356001600160401b03811115613b1e57600080fd5b602083019150836020828501011115613a7357600080fd5b600060a08284031215613b4857600080fd5b50919050565b600060a08284031215613b6057600080fd5b60405160a081018181106001600160401b0382111715613b8257613b82614813565b604052905080613b9183613bd9565b8152613b9f60208401613bf2565b6020820152613bb060408401613bf2565b60408201526060830135613bc38161483e565b6060820152608092830135920191909152919050565b803563ffffffff81168114613bed57600080fd5b919050565b80356001600160401b0381168114613bed57600080fd5b600060208284031215613c1b57600080fd5b81356137fa81614829565b600060208284031215613c3857600080fd5b81516137fa81614829565b60008060408385031215613c5657600080fd5b8235613c6181614829565b91506020830135613c7181614829565b809150509250929050565b600080600060608486031215613c9157600080fd5b8335613c9c81614829565b92506020840135613cac81614829565b929592945050506040919091013590565b60008060408385031215613cd057600080fd5b8235613cdb81614829565b946020939093013593505050565b60008060208385031215613cfc57600080fd5b82356001600160401b03811115613d1257600080fd5b613d1e85828601613a2f565b90969095509350505050565b600080600060608486031215613d3f57600080fd5b83356001600160401b0380821115613d5657600080fd5b613d6287838801613a7a565b94506020860135915080821115613d7857600080fd5b613d8487838801613a7a565b93506040860135915080821115613d9a57600080fd5b50613da786828701613a7a565b9150509250925092565b600080600060e08486031215613dc657600080fd5b83356001600160401b03811115613ddc57600080fd5b8401601f81018613613ded57600080fd5b80356020613dfd613a9b836146a0565b8083825282820191508285018a848660051b8801011115613e1d57600080fd5b600095505b84861015613e4757613e3381613bf2565b835260019590950194918301918301613e22565b509650508601359350613e61915086905060408601613b4e565b90509250925092565b600060208284031215613e7c57600080fd5b81516137fa8161483e565b600060208284031215613e9957600080fd5b5035919050565b60008060008060408587031215613eb657600080fd5b84356001600160401b0380821115613ecd57600080fd5b613ed988838901613af5565b90965094506020870135915080821115613ef257600080fd5b50613eff87828801613a2f565b95989497509550505050565b600080600080600080600080610120898b031215613f2857600080fd5b88356001600160401b0380821115613f3f57600080fd5b613f4b8c838d01613af5565b909a50985060208b0135915080821115613f6457600080fd5b613f708c838d01613a2f565b909850965060408b0135915080821115613f8957600080fd5b50613f968b828c01613af5565b90955093505060608901359150613fb08a60808b01613b36565b90509295985092959890939650565b600080600080600060e08688031215613fd757600080fd5b85356001600160401b0380821115613fee57600080fd5b613ffa89838a01613af5565b9097509550602088013591508082111561401357600080fd5b5061402088828901613a2f565b909450925061403490508760408801613b36565b90509295509295909350565b60008060006060848603121561405557600080fd5b505081359360208301359350604090920135919050565b60006020828403121561407e57600080fd5b5051919050565b6000806040838503121561409857600080fd5b50508035926020909101359150565b8183526000602080850194508260005b858110156140e3576001600160401b036140d083613bf2565b16875295820195908201906001016140b7565b509495945050505050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6000815180845261412f816020860160208601614774565b601f01601f19169290920160200192915050565b63ffffffff61415182613bd9565b16825261416060208201613bf2565b6001600160401b0380821660208501528061417d60408501613bf2565b166040850152505060608101356141938161483e565b15156060830152608090810135910152565b8183823760009101908152919050565b600082516141c7818460208701614774565b9190910192915050565b6001600160a01b03851681526101006020808301829052855191830182905260009161012084019187810191845b818110156142245783516001600160401b0316855293820193928201926001016141ff565b505082935086604086015263ffffffff865116606086015280860151925050506001600160401b0380821660808501528060408601511660a085015250506060830151151560c0830152608083015160e083015295945050505050565b6020808252825182820181905260009190848201906040850190845b818110156142c25783516001600160a01b03168352928401929184019160010161429d565b50909695505050505050565b6000604082016040835280865480835260608501915087600052602092508260002060005b828110156143185781546001600160a01b0316845292840192600191820191016142f3565b505050838103828501528481528590820160005b8681101561435a57823561433f81614829565b6001600160a01b03168252918301919083019060010161432c565b50979650505050505050565b60408152600061437a6040830186886140ee565b828103602084015261391e8185876140a7565b60006101208083526143a28184018b8d6140ee565b905082810360208401526143b781898b6140a7565b905082810360408401526143cc8187896140ee565b9150508360608301526143e26080830184614143565b9998505050505050505050565b60e08152600061440360e0830187896140ee565b82810360208401526144168186886140a7565b9150506144266040830184614143565b9695505050505050565b60808152600061444460808301888a6140ee565b82810360208401526144568188614117565b9050828103604084015261446b8186886140ee565b915050826060830152979650505050505050565b6060815260006144936060830186886140ee565b846020840152828103604084015261391e8185614117565b60208101600483106144cd57634e487b7160e01b600052602160045260246000fd5b91905290565b6020815260006137fa6020830184614117565b60208082526017908201527f43616c6c6572206973206e6f7420746865205661756c74000000000000000000604082015260600190565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b60208082526010908201526f14185d5cd8589b194e881c185d5cd95960821b604082015260600190565b6020808252601d908201527f43616c6c6572206973206e6f7420746865205265676973747261746f72000000604082015260600190565b6020808252600e908201526d1499595b9d1c985b9d0818d85b1b60921b604082015260600190565b6020808252601c908201527f43616c6c6572206973206e6f7420746865205374726174656769737400000000604082015260600190565b6000808335601e1984360301811261462b57600080fd5b8301803591506001600160401b0382111561464557600080fd5b602001915036819003821315613a7357600080fd5b60008235605e198336030181126141c757600080fd5b604051601f8201601f191681016001600160401b038111828210171561469857614698614813565b604052919050565b60006001600160401b038211156146b9576146b9614813565b5060051b60200190565b600080821280156001600160ff1b03849003851316156146e5576146e56147bb565b600160ff1b83900384128116156146fe576146fe6147bb565b50500190565b60008219821115614717576147176147bb565b500190565b60008261473957634e487b7160e01b600052601260045260246000fd5b500490565b6000816000190483118215151615614758576147586147bb565b500290565b60008282101561476f5761476f6147bb565b500390565b60005b8381101561478f578181015183820152602001614777565b83811115610d305750506000910152565b60006000198214156147b4576147b46147bb565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b038116811461237857600080fd5b801515811461237857600080fdfe53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac45357bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa264697066735822122002c6785cb55b316b2eea75081179f6e1764ee917e56d0fc72bd1ea4c6b39fa5064736f6c634300080700337bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a", + "deployedBytecode": "0x6080604052600436106102975760003560e01c8063853828b61161015a578063c2e1e3f4116100c1578063d9f00ec71161007a578063d9f00ec714610908578063dbe55e5614610928578063dd505df61461095c578063de5f626814610990578063f1188e40146109a5578063f6ca71b0146109d957600080fd5b8063c2e1e3f414610842578063c7af335214610862578063c98517c514610877578063cceab75014610894578063d38bfff4146108c8578063d9caed12146108e857600080fd5b80639da0e462116101135780639da0e4621461074e578063a4f98af41461078b578063aa388af6146107a0578063ab12edf5146107ed578063ad1728cb1461080d578063bb1b918d1461082257600080fd5b8063853828b61461068057806387bae867146106955780638d7c0e46146106ba5780639092c31c146106da5780639136616a1461070e57806396d538bb1461072e57600080fd5b80635c975abb116101fe5780636e811d38116101b75780636e811d38146105d55780636ef38795146105f557806371a735f3146106155780637b2d9b2c14610635578063842f5c46146106555780638456cb591461066b57600080fd5b80635c975abb146105125780635d36b190146105365780635f5152261461054b5780636093d3801461056b57806366e3667e1461059f57806367c7066c146105b557600080fd5b8063430bf08a11610250578063430bf08a1461043f578063435356d11461047357806347e7ef2414610493578063484be812146104b3578063579a7e1a146104c95780635a063f63146104fd57600080fd5b80630c340a24146103535780630ed57b3a146103855780630fc3b4c4146103a55780631072cbea146103db57806322495dc8146103fb5780633c8649591461041b57600080fd5b3661034e57336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614806102fb5750336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016145b61034c5760405162461bcd60e51b815260206004820152601e60248201527f657468206e6f742066726f6d20616c6c6f77656420636f6e747261637473000060448201526064015b60405180910390fd5b005b600080fd5b34801561035f57600080fd5b506103686109fb565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561039157600080fd5b5061034c6103a0366004613c43565b610a18565b3480156103b157600080fd5b506103686103c0366004613c09565b609f602052600090815260409020546001600160a01b031681565b3480156103e757600080fd5b5061034c6103f6366004613cbd565b610a4a565b34801561040757600080fd5b5061034c610416366004613db1565b610b07565b34801561042757600080fd5b5061043160695481565b60405190815260200161037c565b34801561044b57600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b34801561047f57600080fd5b5061034c61048e366004613d2a565b610c51565b34801561049f57600080fd5b5061034c6104ae366004613cbd565b610d36565b3480156104bf57600080fd5b50610431606a5481565b3480156104d557600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b34801561050957600080fd5b5061034c610e3c565b34801561051e57600080fd5b5060335460ff165b604051901515815260200161037c565b34801561054257600080fd5b5061034c610edb565b34801561055757600080fd5b50610431610566366004613c09565b610f81565b34801561057757600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b3480156105ab57600080fd5b5061043160345481565b3480156105c157600080fd5b5060a354610368906001600160a01b031681565b3480156105e157600080fd5b5061034c6105f0366004613c09565b6110b5565b34801561060157600080fd5b5061034c610610366004613ce9565b61113d565b34801561062157600080fd5b5061034c610630366004613fbf565b6115c9565b34801561064157600080fd5b50610368610650366004613e87565b6117c2565b34801561066157600080fd5b5061043160685481565b34801561067757600080fd5b5061034c6117ec565b34801561068c57600080fd5b5061034c6118b5565b3480156106a157600080fd5b506033546103689061010090046001600160a01b031681565b3480156106c657600080fd5b5061034c6106d5366004614040565b611a87565b3480156106e657600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b34801561071a57600080fd5b5061034c610729366004613e87565b611e6f565b34801561073a57600080fd5b5061034c610749366004613ce9565b61203a565b34801561075a57600080fd5b5061077e610769366004613e87565b60356020526000908152604090205460ff1681565b60405161037c91906144ab565b34801561079757600080fd5b5061052661215a565b3480156107ac57600080fd5b506105266107bb366004613c09565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0390811691161490565b3480156107f957600080fd5b5061034c610808366004614085565b6121b9565b34801561081957600080fd5b5061034c6122b5565b34801561082e57600080fd5b5061034c61083d366004613f0b565b61237b565b34801561084e57600080fd5b5061034c61085d366004613c09565b6124ee565b34801561086e57600080fd5b5061052661257b565b34801561088357600080fd5b506104316801bc16d674ec80000081565b3480156108a057600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b3480156108d457600080fd5b5061034c6108e3366004613c09565b6125ac565b3480156108f457600080fd5b5061034c610903366004613c7c565b612650565b34801561091457600080fd5b5061034c610923366004613ea0565b6126e3565b34801561093457600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b34801561096857600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b34801561099c57600080fd5b5061034c6128d8565b3480156109b157600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b3480156109e557600080fd5b506109ee612a22565b60405161037c9190614281565b6000610a1360008051602061486d8339815191525490565b905090565b610a2061257b565b610a3c5760405162461bcd60e51b81526004016103439061451d565b610a468282612a84565b5050565b610a5261257b565b610a6e5760405162461bcd60e51b81526004016103439061451d565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b039081169083161415610aeb5760405162461bcd60e51b815260206004820152601f60248201527f43616e6e6f74207472616e7366657220737570706f72746564206173736574006044820152606401610343565b610a46610af66109fb565b6001600160a01b0384169083612be3565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b158015610b6057600080fd5b505afa158015610b74573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b989190613c26565b6001600160a01b0316336001600160a01b031614610bc85760405162461bcd60e51b8152600401610343906145dd565b60405163bc26e7e560e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063bc26e7e590610c1a9030908790879087906004016141d1565b600060405180830381600087803b158015610c3457600080fd5b505af1158015610c48573d6000803e3d6000fd5b50505050505050565b610c5961257b565b610c755760405162461bcd60e51b81526004016103439061451d565b600054610100900460ff1680610c8e575060005460ff16155b610cf15760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610343565b600054610100900460ff16158015610d13576000805461ffff19166101011790555b610d1e848484612c35565b8015610d30576000805461ff00191690555b50505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610d7e5760405162461bcd60e51b8152600401610343906144e6565b60008051602061484d83398151915280546002811415610db05760405162461bcd60e51b8152600401610343906145b5565b600282557f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316846001600160a01b031614610e295760405162461bcd60e51b8152602060048201526011602482015270155b9cdd5c1c1bdc9d195908185cdcd95d607a1b6044820152606401610343565b610e338484612cf0565b50600190555050565b60a3546001600160a01b03163314610e965760405162461bcd60e51b815260206004820152601b60248201527f43616c6c6572206973206e6f74207468652048617276657374657200000000006044820152606401610343565b60008051602061484d83398151915280546002811415610ec85760405162461bcd60e51b8152600401610343906145b5565b60028255610ed4612d82565b5060019055565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b031614610f765760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b6064820152608401610343565b610f7f33612fd0565b565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b031614610ff85760405162461bcd60e51b8152602060048201526011602482015270155b9cdd5c1c1bdc9d195908185cdcd95d607a1b6044820152606401610343565b6040516370a0823160e01b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b15801561105757600080fd5b505afa15801561106b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061108f919061406c565b6034546110a5906801bc16d674ec80000061473e565b6110af9190614704565b92915050565b6110bd61257b565b6110d95760405162461bcd60e51b81526004016103439061451d565b6040516001600160a01b03821681527f83f29c79feb71f8fba9d0fbc4ba5f0982a28b6b1e868b3fc50e6400d100bca0f9060200160405180910390a1603380546001600160a01b0390921661010002610100600160a81b0319909216919091179055565b60335461010090046001600160a01b0316331461116c5760405162461bcd60e51b81526004016103439061457e565b60335460ff161561118f5760405162461bcd60e51b815260040161034390614554565b60006111a4826801bc16d674ec80000061473e565b6040516370a0823160e01b81523060048201529091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b15801561120657600080fd5b505afa15801561121a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061123e919061406c565b8111156112815760405162461bcd60e51b81526020600482015260116024820152700d2dce6eaccccd2c6d2cadce840ae8aa89607b1b6044820152606401610343565b604051632e1a7d4d60e01b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b1580156112e357600080fd5b505af11580156112f7573d6000803e3d6000fd5b5050505060005b82811015610d3057600084848381811061131a5761131a6147fd565b905060200281019061132c919061465a565b6113369080614614565b6040516113449291906141a5565b6040805191829003909120600081815260356020529182205490925060ff1690816003811115611376576113766147d1565b146113c35760405162461bcd60e51b815260206004820152601860248201527f56616c696461746f72206e6f74207265676973746572656400000000000000006044820152606401610343565b60408051600160f81b60208201526000602182018190526bffffffffffffffffffffffff193060601b16602c830152910160405160208183030381529060405290507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663228951186801bc16d674ec800000898988818110611450576114506147fd565b9050602002810190611462919061465a565b61146c9080614614565b858c8c8b81811061147f5761147f6147fd565b9050602002810190611491919061465a565b61149f906020810190614614565b8e8e8d8181106114b1576114b16147fd565b90506020028101906114c3919061465a565b604001356040518863ffffffff1660e01b81526004016114e896959493929190614430565b6000604051808303818588803b15801561150157600080fd5b505af1158015611515573d6000803e3d6000fd5b505050505060016034600082825461152d9190614704565b909155507ffeb31a79d38edb1b090d516e4df3e273651179c6f2c2ec53a9a22ae015b70ba99050878786818110611566576115666147fd565b9050602002810190611578919061465a565b6115829080614614565b6801bc16d674ec8000008460405161159d949392919061447f565b60405180910390a150506000908152603560205260409020805460ff19166001908117909155016112fe565b60335461010090046001600160a01b031633146115f85760405162461bcd60e51b81526004016103439061457e565b60335460ff161561161b5760405162461bcd60e51b815260040161034390614554565b60006035600087876040516116319291906141a5565b604080519182900390912082526020820192909252016000205460ff1690506002816003811115611664576116646147d1565b146116a95760405162461bcd60e51b815260206004820152601560248201527456616c696461746f72206e6f742065786974696e6760581b6044820152606401610343565b6040516312b3fc1960e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906312b3fc19906116fd90899089908990899089906004016143ef565b600060405180830381600087803b15801561171757600080fd5b505af115801561172b573d6000803e3d6000fd5b505050507ff72821b8777f002ccdf6326f1242d9e0f762eb077668b67bebe640535378066d868686866040516117649493929190614366565b60405180910390a160036035600088886040516117829291906141a5565b60408051918290039091208252602082019290925201600020805460ff191660018360038111156117b5576117b56147d1565b0217905550505050505050565b60a481815481106117d257600080fd5b6000918252602090912001546001600160a01b0316905081565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b15801561184557600080fd5b505afa158015611859573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061187d9190613c26565b6001600160a01b0316336001600160a01b0316146118ad5760405162461bcd60e51b8152600401610343906145dd565b610f7f613091565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016148061190457506118ef6109fb565b6001600160a01b0316336001600160a01b0316145b61195c5760405162461bcd60e51b815260206004820152602360248201527f43616c6c6572206973206e6f7420746865205661756c74206f7220476f7665726044820152623737b960e91b6064820152608401610343565b60008051602061484d8339815191528054600281141561198e5760405162461bcd60e51b8152600401610343906145b5565b600282556040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b1580156119f457600080fd5b505afa158015611a08573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a2c919061406c565b90508015611a7f57611a7f7f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000083613106565b505060019055565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b158015611ae057600080fd5b505afa158015611af4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b189190613c26565b6001600160a01b0316336001600160a01b031614611b485760405162461bcd60e51b8152600401610343906145dd565b60335460ff16611b915760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610343565b6002198312158015611ba4575060038313155b8015611bbe5750600083603454611bbb91906146c3565b12155b611c0a5760405162461bcd60e51b815260206004820152601760248201527f696e76616c69642076616c696461746f727344656c74610000000000000000006044820152606401610343565b6811ff6cf0fd15afffff198212158015611c2d57506811ff6cf0fd15b000008213155b8015611c475750600082606854611c4491906146c3565b12155b611c935760405162461bcd60e51b815260206004820152601d60248201527f696e76616c696420636f6e73656e7375735265776172647344656c74610000006044820152606401610343565b6801bc16d674ec800000811115611cec5760405162461bcd60e51b815260206004820152601960248201527f696e76616c69642077657468546f5661756c74416d6f756e74000000000000006044820152606401610343565b60408051848152602081018490529081018290527f80d022717ea022455c5886b8dd8a29c037570aae58aeb4d7b136d7a10ec2e4319060600160405180910390a182603454611d3b91906146c3565b603455606854611d4c9083906146c3565b6068558015611e195760405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018390527f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb90604401602060405180830381600087803b158015611ddf57600080fd5b505af1158015611df3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e179190613e6a565b505b611e2360006131fe565b611e625760405162461bcd60e51b815260206004820152601060248201526f333ab9b29039ba34b63610313637bbb760811b6044820152606401610343565b611e6a613684565b505050565b611e7761257b565b611e935760405162461bcd60e51b81526004016103439061451d565b60a0548110611ed45760405162461bcd60e51b815260206004820152600d60248201526c092dcecc2d8d2c840d2dcc8caf609b1b6044820152606401610343565b600060a08281548110611ee957611ee96147fd565b60009182526020808320909101546001600160a01b03908116808452609f90925260409092205460a05491935090911690611f269060019061475d565b831015611fa85760a08054611f3d9060019061475d565b81548110611f4d57611f4d6147fd565b60009182526020909120015460a080546001600160a01b039092169185908110611f7957611f796147fd565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505b60a0805480611fb957611fb96147e7565b60008281526020808220600019908401810180546001600160a01b031990811690915593019093556001600160a01b03858116808352609f855260409283902080549094169093559051908416815290917f16b7600acff27e39a8a96056b3d533045298de927507f5c1d97e4accde60488c910160405180910390a2505050565b61204261257b565b61205e5760405162461bcd60e51b81526004016103439061451d565b8060005b8181101561211157600084848381811061207e5761207e6147fd565b90506020020160208101906120939190613c09565b6001600160a01b031614156121015760405162461bcd60e51b815260206004820152602e60248201527f43616e206e6f742073657420616e20656d70747920616464726573732061732060448201526d30903932bbb0b932103a37b5b2b760911b6064820152608401610343565b61210a816147a0565b9050612062565b507f04c0b9649497d316554306e53678d5f5f5dbc3a06f97dec13ff4cfe98b986bbc60a48484604051612146939291906142ce565b60405180910390a1610d3060a48484613962565b60335460009061010090046001600160a01b0316331461218c5760405162461bcd60e51b81526004016103439061457e565b60335460ff16156121af5760405162461bcd60e51b815260040161034390614554565b610a1360016131fe565b6121c161257b565b6121dd5760405162461bcd60e51b81526004016103439061451d565b80821080156121f457506801bc16d674ec80000082105b801561220857506801bc16d674ec80000081105b80156122255750673782dace9d900000612222838361475d565b10155b6122715760405162461bcd60e51b815260206004820152601760248201527f696e636f7272656374206675736520696e74657276616c0000000000000000006044820152606401610343565b60408051838152602081018390527fcb8d24e46eb3c402bf344ee60a6576cba9ef2f59ea1af3b311520704924e901a910160405180910390a1606991909155606a55565b60405163095ea7b360e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015260001960248301527f0000000000000000000000000000000000000000000000000000000000000000169063095ea7b390604401602060405180830381600087803b15801561234057600080fd5b505af1158015612354573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123789190613e6a565b50565b60335461010090046001600160a01b031633146123aa5760405162461bcd60e51b81526004016103439061457e565b60335460ff16156123cd5760405162461bcd60e51b815260040161034390614554565b6040516301ba3ee760e21b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906306e8fb9c90612427908b908b908b908b908b908b908b908b9060040161438d565b600060405180830381600087803b15801561244157600080fd5b505af1158015612455573d6000803e3d6000fd5b505050506000603560008a8a60405161246f9291906141a5565b60408051918290039091208252602082019290925201600020805460ff191660018360038111156124a2576124a26147d1565b02179055507f75c4a66b2c6c28cf46db7131182a812e4fbbb2f0591377aa83a737909a9b68c3888888886040516124dc9493929190614366565b60405180910390a15050505050505050565b6124f661257b565b6125125760405162461bcd60e51b81526004016103439061451d565b60a354604080516001600160a01b03928316815291831660208301527fe48386b84419f4d36e0f96c10cc3510b6fb1a33795620c5098b22472bbe90796910160405180910390a160a380546001600160a01b0319166001600160a01b0392909216919091179055565b600061259360008051602061486d8339815191525490565b6001600160a01b0316336001600160a01b031614905090565b6125b461257b565b6125d05760405162461bcd60e51b81526004016103439061451d565b6125f8817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b031661261860008051602061486d8339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146126985760405162461bcd60e51b8152600401610343906144e6565b60008051602061484d833981519152805460028114156126ca5760405162461bcd60e51b8152600401610343906145b5565b600282556126d9858585613106565b5060019055505050565b60335461010090046001600160a01b031633146127125760405162461bcd60e51b81526004016103439061457e565b60335460ff16156127355760405162461bcd60e51b815260040161034390614554565b600060356000868660405161274b9291906141a5565b604080519182900390912082526020820192909252016000205460ff169050600181600381111561277e5761277e6147d1565b146127c25760405162461bcd60e51b815260206004820152601460248201527315985b1a59185d1bdc881b9bdd081cdd185ad95960621b6044820152606401610343565b604051633877322b60e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690633877322b90612814908890889088908890600401614366565b600060405180830381600087803b15801561282e57600080fd5b505af1158015612842573d6000803e3d6000fd5b505050507ff8821da16f5ed966b41e0343c3eff9903af782d74f99f1689dd9d4562b6545b38585858560405161287b9493929190614366565b60405180910390a160026035600087876040516128999291906141a5565b60408051918290039091208252602082019290925201600020805460ff191660018360038111156128cc576128cc6147d1565b02179055505050505050565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146129205760405162461bcd60e51b8152600401610343906144e6565b60008051602061484d833981519152805460028114156129525760405162461bcd60e51b8152600401610343906145b5565b600282556040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b1580156129b857600080fd5b505afa1580156129cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129f0919061406c565b90508015611a7f57611a7f7f000000000000000000000000000000000000000000000000000000000000000082612cf0565b606060a4805480602002602001604051908101604052809291908181526020018280548015612a7a57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612a5c575b5050505050905090565b6001600160a01b038281166000908152609f60205260409020541615612ae15760405162461bcd60e51b81526020600482015260126024820152711c151bdad95b88185b1c9958591e481cd95d60721b6044820152606401610343565b6001600160a01b03821615801590612b0157506001600160a01b03811615155b612b415760405162461bcd60e51b8152602060048201526011602482015270496e76616c69642061646472657373657360781b6044820152606401610343565b6001600160a01b038281166000818152609f6020908152604080832080549587166001600160a01b0319968716811790915560a0805460018101825594527f78fdc8d422c49ced035a9edf18d00d3c6a8d81df210f3e5e448e045e77b41e8890930180549095168417909455925190815290917fef6485b84315f9b1483beffa32aae9a0596890395e3d7521f1c5fbb51790e765910160405180910390a25050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052611e6a9084906136fe565b8251612c489060a49060208601906139c5565b50815181518114612c925760405162461bcd60e51b8152602060048201526014602482015273496e76616c696420696e7075742061727261797360601b6044820152606401610343565b60005b81811015612ce957612cd9848281518110612cb257612cb26147fd565b6020026020010151848381518110612ccc57612ccc6147fd565b6020026020010151612a84565b612ce2816147a0565b9050612c95565b5050505050565b60008111612d395760405162461bcd60e51b81526020600482015260166024820152754d757374206465706f73697420736f6d657468696e6760501b6044820152606401610343565b6040805160008152602081018390526001600160a01b038416917f5548c837ab068cf56a2c2479df0882a4922fd203edb7517321831d95078c5f62910160405180910390a25050565b60335460ff1615612da55760405162461bcd60e51b815260040161034390614554565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663e52253816040518163ffffffff1660e01b8152600401602060405180830381600087803b158015612e0257600080fd5b505af1158015612e16573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e3a919061406c565b9050600060685482612e4c9190614704565b905080471015612e9e5760405162461bcd60e51b815260206004820152601860248201527f696e73756666696369656e74206574682062616c616e636500000000000000006044820152606401610343565b8015610a465760006068819055507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b158015612f0757600080fd5b505af1158015612f1b573d6000803e3d6000fd5b505060a354604080516001600160a01b0392831681527f0000000000000000000000000000000000000000000000000000000000000000909216602083015281018590527ff6c07a063ed4e63808eb8da7112d46dbcd38de2b40a73dbcc9353c5a94c7235393506060019150612f8e9050565b60405180910390a160a354610a46906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116911683612be3565b6001600160a01b0381166130265760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f7220697320616464726573732830290000000000006044820152606401610343565b806001600160a01b031661304660008051602061486d8339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a36123788160008051602061486d83398151915255565b60335460ff16156130b45760405162461bcd60e51b815260040161034390614554565b6033805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586130e93390565b6040516001600160a01b03909116815260200160405180910390a1565b600081116131565760405162461bcd60e51b815260206004820152601760248201527f4d75737420776974686472617720736f6d657468696e670000000000000000006044820152606401610343565b6001600160a01b0383166131a55760405162461bcd60e51b8152602060048201526016602482015275135d5cdd081cdc1958da599e481c9958da5c1a595b9d60521b6044820152606401610343565b6040805160008152602081018390526001600160a01b038416917f2717ead6b9200dd235aad468c9809ea400fe33ac69b5bfaa6d3e90fc922b6398910160405180910390a2611e6a6001600160a01b0383168483612be3565b6000606854471015613213576110af826137d0565b600060685447613223919061475d565b9050600191506801bc16d674ec800000811061341957600061324e6801bc16d674ec8000008361471c565b905080603454101561326b57613263846137d0565b949350505050565b806034600082825461327d919061475d565b9091555060009050613298826801bc16d674ec80000061473e565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b1580156132f557600080fd5b505af1158015613309573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb92506044019050602060405180830381600087803b15801561339957600080fd5b505af11580156133ad573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133d19190613e6a565b5060345460408051848152602081019290925281018290527fbe7040030ff7b347853214bf49820c6d455fedf58f3815f85c7bc5216993682b9060600160405180910390a150505b600060685447613429919061475d565b90506801bc16d674ec800000811061347b5760405162461bcd60e51b8152602060048201526015602482015274756e6578706563746564206163636f756e74696e6760581b6044820152606401610343565b80613487575050919050565b6069548110156134e15780606860008282546134a39190614704565b90915550506040518181527f7a745a2c63a535068f52ceca27debd5297bbad5f7f37ec53d044a59d0362445d906020015b60405180910390a161367d565b606a54811115613674577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b15801561354657600080fd5b505af115801561355a573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb92506044019050602060405180830381600087803b1580156135ea57600080fd5b505af11580156135fe573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136229190613e6a565b50600160346000828254613636919061475d565b909155505060345460408051918252602082018390527f6aa7e30787b26429ced603a7aba8b19c4b5d5bcf29a3257da953c8d53bcaa3a691016134d4565b613263846137d0565b5050919050565b60335460ff166136cd5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610343565b6033805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa336130e9565b6000613753826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166137e89092919063ffffffff16565b805190915015611e6a57808060200190518101906137719190613e6a565b611e6a5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610343565b600081156137e0576137e0613091565b506000919050565b60606137f78484600085613801565b90505b9392505050565b6060824710156138625760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610343565b843b6138b05760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610343565b600080866001600160a01b031685876040516138cc91906141b5565b60006040518083038185875af1925050503d8060008114613909576040519150601f19603f3d011682016040523d82523d6000602084013e61390e565b606091505b509150915061391e828286613929565b979650505050505050565b606083156139385750816137fa565b8251156139485782518084602001fd5b8160405162461bcd60e51b815260040161034391906144d3565b8280548282559060005260206000209081019282156139b5579160200282015b828111156139b55781546001600160a01b0319166001600160a01b03843516178255602090920191600190910190613982565b506139c1929150613a1a565b5090565b8280548282559060005260206000209081019282156139b5579160200282015b828111156139b557825182546001600160a01b0319166001600160a01b039091161782556020909201916001909101906139e5565b5b808211156139c15760008155600101613a1b565b60008083601f840112613a4157600080fd5b5081356001600160401b03811115613a5857600080fd5b6020830191508360208260051b8501011115613a7357600080fd5b9250929050565b600082601f830112613a8b57600080fd5b81356020613aa0613a9b836146a0565b614670565b80838252828201915082860187848660051b8901011115613ac057600080fd5b60005b85811015613ae8578135613ad681614829565b84529284019290840190600101613ac3565b5090979650505050505050565b60008083601f840112613b0757600080fd5b5081356001600160401b03811115613b1e57600080fd5b602083019150836020828501011115613a7357600080fd5b600060a08284031215613b4857600080fd5b50919050565b600060a08284031215613b6057600080fd5b60405160a081018181106001600160401b0382111715613b8257613b82614813565b604052905080613b9183613bd9565b8152613b9f60208401613bf2565b6020820152613bb060408401613bf2565b60408201526060830135613bc38161483e565b6060820152608092830135920191909152919050565b803563ffffffff81168114613bed57600080fd5b919050565b80356001600160401b0381168114613bed57600080fd5b600060208284031215613c1b57600080fd5b81356137fa81614829565b600060208284031215613c3857600080fd5b81516137fa81614829565b60008060408385031215613c5657600080fd5b8235613c6181614829565b91506020830135613c7181614829565b809150509250929050565b600080600060608486031215613c9157600080fd5b8335613c9c81614829565b92506020840135613cac81614829565b929592945050506040919091013590565b60008060408385031215613cd057600080fd5b8235613cdb81614829565b946020939093013593505050565b60008060208385031215613cfc57600080fd5b82356001600160401b03811115613d1257600080fd5b613d1e85828601613a2f565b90969095509350505050565b600080600060608486031215613d3f57600080fd5b83356001600160401b0380821115613d5657600080fd5b613d6287838801613a7a565b94506020860135915080821115613d7857600080fd5b613d8487838801613a7a565b93506040860135915080821115613d9a57600080fd5b50613da786828701613a7a565b9150509250925092565b600080600060e08486031215613dc657600080fd5b83356001600160401b03811115613ddc57600080fd5b8401601f81018613613ded57600080fd5b80356020613dfd613a9b836146a0565b8083825282820191508285018a848660051b8801011115613e1d57600080fd5b600095505b84861015613e4757613e3381613bf2565b835260019590950194918301918301613e22565b509650508601359350613e61915086905060408601613b4e565b90509250925092565b600060208284031215613e7c57600080fd5b81516137fa8161483e565b600060208284031215613e9957600080fd5b5035919050565b60008060008060408587031215613eb657600080fd5b84356001600160401b0380821115613ecd57600080fd5b613ed988838901613af5565b90965094506020870135915080821115613ef257600080fd5b50613eff87828801613a2f565b95989497509550505050565b600080600080600080600080610120898b031215613f2857600080fd5b88356001600160401b0380821115613f3f57600080fd5b613f4b8c838d01613af5565b909a50985060208b0135915080821115613f6457600080fd5b613f708c838d01613a2f565b909850965060408b0135915080821115613f8957600080fd5b50613f968b828c01613af5565b90955093505060608901359150613fb08a60808b01613b36565b90509295985092959890939650565b600080600080600060e08688031215613fd757600080fd5b85356001600160401b0380821115613fee57600080fd5b613ffa89838a01613af5565b9097509550602088013591508082111561401357600080fd5b5061402088828901613a2f565b909450925061403490508760408801613b36565b90509295509295909350565b60008060006060848603121561405557600080fd5b505081359360208301359350604090920135919050565b60006020828403121561407e57600080fd5b5051919050565b6000806040838503121561409857600080fd5b50508035926020909101359150565b8183526000602080850194508260005b858110156140e3576001600160401b036140d083613bf2565b16875295820195908201906001016140b7565b509495945050505050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6000815180845261412f816020860160208601614774565b601f01601f19169290920160200192915050565b63ffffffff61415182613bd9565b16825261416060208201613bf2565b6001600160401b0380821660208501528061417d60408501613bf2565b166040850152505060608101356141938161483e565b15156060830152608090810135910152565b8183823760009101908152919050565b600082516141c7818460208701614774565b9190910192915050565b6001600160a01b03851681526101006020808301829052855191830182905260009161012084019187810191845b818110156142245783516001600160401b0316855293820193928201926001016141ff565b505082935086604086015263ffffffff865116606086015280860151925050506001600160401b0380821660808501528060408601511660a085015250506060830151151560c0830152608083015160e083015295945050505050565b6020808252825182820181905260009190848201906040850190845b818110156142c25783516001600160a01b03168352928401929184019160010161429d565b50909695505050505050565b6000604082016040835280865480835260608501915087600052602092508260002060005b828110156143185781546001600160a01b0316845292840192600191820191016142f3565b505050838103828501528481528590820160005b8681101561435a57823561433f81614829565b6001600160a01b03168252918301919083019060010161432c565b50979650505050505050565b60408152600061437a6040830186886140ee565b828103602084015261391e8185876140a7565b60006101208083526143a28184018b8d6140ee565b905082810360208401526143b781898b6140a7565b905082810360408401526143cc8187896140ee565b9150508360608301526143e26080830184614143565b9998505050505050505050565b60e08152600061440360e0830187896140ee565b82810360208401526144168186886140a7565b9150506144266040830184614143565b9695505050505050565b60808152600061444460808301888a6140ee565b82810360208401526144568188614117565b9050828103604084015261446b8186886140ee565b915050826060830152979650505050505050565b6060815260006144936060830186886140ee565b846020840152828103604084015261391e8185614117565b60208101600483106144cd57634e487b7160e01b600052602160045260246000fd5b91905290565b6020815260006137fa6020830184614117565b60208082526017908201527f43616c6c6572206973206e6f7420746865205661756c74000000000000000000604082015260600190565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b60208082526010908201526f14185d5cd8589b194e881c185d5cd95960821b604082015260600190565b6020808252601d908201527f43616c6c6572206973206e6f7420746865205265676973747261746f72000000604082015260600190565b6020808252600e908201526d1499595b9d1c985b9d0818d85b1b60921b604082015260600190565b6020808252601c908201527f43616c6c6572206973206e6f7420746865205374726174656769737400000000604082015260600190565b6000808335601e1984360301811261462b57600080fd5b8301803591506001600160401b0382111561464557600080fd5b602001915036819003821315613a7357600080fd5b60008235605e198336030181126141c757600080fd5b604051601f8201601f191681016001600160401b038111828210171561469857614698614813565b604052919050565b60006001600160401b038211156146b9576146b9614813565b5060051b60200190565b600080821280156001600160ff1b03849003851316156146e5576146e56147bb565b600160ff1b83900384128116156146fe576146fe6147bb565b50500190565b60008219821115614717576147176147bb565b500190565b60008261473957634e487b7160e01b600052601260045260246000fd5b500490565b6000816000190483118215151615614758576147586147bb565b500290565b60008282101561476f5761476f6147bb565b500390565b60005b8381101561478f578181015183820152602001614777565b83811115610d305750506000910152565b60006000198214156147b4576147b46147bb565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b038116811461237857600080fd5b801515811461237857600080fdfe53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac45357bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa264697066735822122002c6785cb55b316b2eea75081179f6e1764ee917e56d0fc72bd1ea4c6b39fa5064736f6c63430008070033", "libraries": {}, "devdoc": { "author": "Origin Protocol Inc", @@ -1418,7 +1359,10 @@ } }, "doAccounting()": { - "details": "This function could in theory be permission-less but lets allow only the Registrator (Defender Action) to call it for now." + "details": "This function could in theory be permission-less but lets allow only the Registrator (Defender Action) to call it for now.", + "returns": { + "accountingValid": "true if accounting was successful, false if fuse is blown" + } }, "getRewardTokenAddresses()": { "returns": { @@ -1432,15 +1376,11 @@ "_rewardTokenAddresses": "Address of reward token for platform" } }, - "manuallyFixAccounting(uint256,uint256,uint256,uint256,uint256,uint256)": { - "details": "allow the accounting governor to fix the accounting of this strategy and unpause", + "manuallyFixAccounting(int256,int256,uint256)": { "params": { - "_activeDepositedValidators": "the override value of activeDepositedValidators", - "_consensusRewards": "the override value for consensusRewards", - "_ethThresholdCheck": "maximum allowed ETH balance on the contract for the function to run", - "_ethToWeth": "the amount of ETH to be converted to WETH", - "_wethThresholdCheck": "maximum allowed WETH balance on the contract for the function to run the above 2 checks are done so transaction doesn't get front run and cause unexpected behaviour", - "_wethToBeSentToVault": "the amount of WETH to be sent to the Vault" + "_consensusRewardsDelta": "adjust the accounted for consensus rewards up or down", + "_validatorsDelta": "adjust the active validators by plus one, minus one or unchanged with zero", + "_wethToVaultAmount": "the amount of WETH to be sent to the Vault" } }, "paused()": { @@ -1528,8 +1468,8 @@ "WETH_TOKEN_ADDRESS()": { "notice": "The address of the Wrapped ETH (WETH) token contract" }, - "accountingGovernor()": { - "notice": "Governor that can manually correct the accounting" + "activeDepositedValidators()": { + "notice": "The number of validators that have 32 (!) ETH actively deposited. When a new deposit to a validator happens this number increases, when a validator exit is detected this number decreases." }, "assetToPToken(address)": { "notice": "asset => pToken (Platform Specific Token Address)" @@ -1582,6 +1522,9 @@ "isGovernor()": { "notice": "Returns true if the caller is the current Governor." }, + "manuallyFixAccounting(int256,int256,uint256)": { + "notice": "Allow the Strategist to fix the accounting of this strategy and unpause." + }, "platformAddress()": { "notice": "Address of the underlying platform" }, @@ -1649,7 +1592,7 @@ "storageLayout": { "storage": [ { - "astId": 5232, + "astId": 41335, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "initialized", "offset": 0, @@ -1657,7 +1600,7 @@ "type": "t_bool" }, { - "astId": 5235, + "astId": 41338, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "initializing", "offset": 1, @@ -1665,7 +1608,7 @@ "type": "t_bool" }, { - "astId": 5275, + "astId": 41378, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "______gap", "offset": 0, @@ -1673,7 +1616,7 @@ "type": "t_array(t_uint256)50_storage" }, { - "astId": 17, + "astId": 549, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "_paused", "offset": 0, @@ -1681,7 +1624,7 @@ "type": "t_bool" }, { - "astId": 3497, + "astId": 34647, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "validatorRegistrator", "offset": 1, @@ -1689,7 +1632,7 @@ "type": "t_address" }, { - "astId": 3500, + "astId": 34650, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "activeDepositedValidators", "offset": 0, @@ -1697,15 +1640,15 @@ "type": "t_uint256" }, { - "astId": 3506, + "astId": 34656, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "validatorsStates", "offset": 0, "slot": "53", - "type": "t_mapping(t_bytes32,t_enum(VALIDATOR_STATE)3515)" + "type": "t_mapping(t_bytes32,t_enum(VALIDATOR_STATE)34665)" }, { - "astId": 3510, + "astId": 34660, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "__gap", "offset": 0, @@ -1713,7 +1656,7 @@ "type": "t_array(t_uint256)50_storage" }, { - "astId": 3042, + "astId": 34184, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "consensusRewards", "offset": 0, @@ -1721,7 +1664,7 @@ "type": "t_uint256" }, { - "astId": 3046, + "astId": 34188, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "fuseIntervalStart", "offset": 0, @@ -1729,7 +1672,7 @@ "type": "t_uint256" }, { - "astId": 3050, + "astId": 34192, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "fuseIntervalEnd", "offset": 0, @@ -1737,99 +1680,91 @@ "type": "t_uint256" }, { - "astId": 3053, - "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", - "label": "accountingGovernor", - "offset": 0, - "slot": "107", - "type": "t_address" - }, - { - "astId": 3057, + "astId": 34196, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "__gap", "offset": 0, - "slot": "108", + "slot": "107", "type": "t_array(t_uint256)50_storage" }, { - "astId": 5355, + "astId": 41458, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "_deprecated_platformAddress", "offset": 0, - "slot": "158", + "slot": "157", "type": "t_address" }, { - "astId": 5358, + "astId": 41461, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "_deprecated_vaultAddress", "offset": 0, - "slot": "159", + "slot": "158", "type": "t_address" }, { - "astId": 5363, + "astId": 41466, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "assetToPToken", "offset": 0, - "slot": "160", + "slot": "159", "type": "t_mapping(t_address,t_address)" }, { - "astId": 5367, + "astId": 41470, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "assetsMapped", "offset": 0, - "slot": "161", + "slot": "160", "type": "t_array(t_address)dyn_storage" }, { - "astId": 5369, + "astId": 41472, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "_deprecated_rewardTokenAddress", "offset": 0, - "slot": "162", + "slot": "161", "type": "t_address" }, { - "astId": 5371, + "astId": 41474, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "_deprecated_rewardLiquidationThreshold", "offset": 0, - "slot": "163", + "slot": "162", "type": "t_uint256" }, { - "astId": 5374, + "astId": 41477, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "harvesterAddress", "offset": 0, - "slot": "164", + "slot": "163", "type": "t_address" }, { - "astId": 5378, + "astId": 41481, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "rewardTokenAddresses", "offset": 0, - "slot": "165", + "slot": "164", "type": "t_array(t_address)dyn_storage" }, { - "astId": 5382, + "astId": 41485, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "_reserved", "offset": 0, - "slot": "166", + "slot": "165", "type": "t_array(t_int256)98_storage" }, { - "astId": 2613, + "astId": 33757, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "__gap", "offset": 0, - "slot": "264", + "slot": "263", "type": "t_array(t_uint256)50_storage" } ], @@ -1867,7 +1802,7 @@ "label": "bytes32", "numberOfBytes": "32" }, - "t_enum(VALIDATOR_STATE)3515": { + "t_enum(VALIDATOR_STATE)34665": { "encoding": "inplace", "label": "enum ValidatorRegistrator.VALIDATOR_STATE", "numberOfBytes": "1" @@ -1884,12 +1819,12 @@ "numberOfBytes": "32", "value": "t_address" }, - "t_mapping(t_bytes32,t_enum(VALIDATOR_STATE)3515)": { + "t_mapping(t_bytes32,t_enum(VALIDATOR_STATE)34665)": { "encoding": "mapping", "key": "t_bytes32", "label": "mapping(bytes32 => enum ValidatorRegistrator.VALIDATOR_STATE)", "numberOfBytes": "32", - "value": "t_enum(VALIDATOR_STATE)3515" + "value": "t_enum(VALIDATOR_STATE)34665" }, "t_uint256": { "encoding": "inplace", diff --git a/contracts/deployments/holesky/NativeStakingSSVStrategyProxy.json b/contracts/deployments/holesky/NativeStakingSSVStrategyProxy.json index e6e3625aba..0972da0b7d 100644 --- a/contracts/deployments/holesky/NativeStakingSSVStrategyProxy.json +++ b/contracts/deployments/holesky/NativeStakingSSVStrategyProxy.json @@ -1,5 +1,5 @@ { - "address": "0x4Eac8847c7AE50e3A3551B1Aa4FF7Cc162151410", + "address": "0xcf4a9e80Ddb173cc17128A361B98B9A140e3932E", "abi": [ { "anonymous": false, @@ -183,40 +183,40 @@ "type": "function" } ], - "transactionHash": "0x8f9577961a6ba3cd743d72c27db2c8f2472a6c26a58fc73150fc25a4cd371ad5", + "transactionHash": "0x25f06b54b637b629c9dda47e609ed96ae2583c17f6368f4b9983f0e7171d6c43", "receipt": { "to": null, "from": "0x1b94CA50D3Ad9f8368851F8526132272d1a5028C", - "contractAddress": "0x4Eac8847c7AE50e3A3551B1Aa4FF7Cc162151410", - "transactionIndex": 46, + "contractAddress": "0xcf4a9e80Ddb173cc17128A361B98B9A140e3932E", + "transactionIndex": 18, "gasUsed": "580428", - "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000020000000004000000000800000000000000000000000000080000000004000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000010000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000", - "blockHash": "0xc04b8dec47c654e4489a465ba27058787f5aeb4496c2d3026f3ca88b9f690e3e", - "transactionHash": "0x8f9577961a6ba3cd743d72c27db2c8f2472a6c26a58fc73150fc25a4cd371ad5", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000000004000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000010200000000000800000000000000000000000000020000000000000000000000000000000000000000000000000000000000000008000", + "blockHash": "0xfa1ddfe7e2895d3ea20b590cbee2013a0622f3f1d06047bda7e0dc9c23edda63", + "transactionHash": "0x25f06b54b637b629c9dda47e609ed96ae2583c17f6368f4b9983f0e7171d6c43", "logs": [ { - "transactionIndex": 46, - "blockNumber": 1405102, - "transactionHash": "0x8f9577961a6ba3cd743d72c27db2c8f2472a6c26a58fc73150fc25a4cd371ad5", - "address": "0x4Eac8847c7AE50e3A3551B1Aa4FF7Cc162151410", + "transactionIndex": 18, + "blockNumber": 1489362, + "transactionHash": "0x25f06b54b637b629c9dda47e609ed96ae2583c17f6368f4b9983f0e7171d6c43", + "address": "0xcf4a9e80Ddb173cc17128A361B98B9A140e3932E", "topics": [ "0xc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000001b94ca50d3ad9f8368851f8526132272d1a5028c" ], "data": "0x", - "logIndex": 56, - "blockHash": "0xc04b8dec47c654e4489a465ba27058787f5aeb4496c2d3026f3ca88b9f690e3e" + "logIndex": 45, + "blockHash": "0xfa1ddfe7e2895d3ea20b590cbee2013a0622f3f1d06047bda7e0dc9c23edda63" } ], - "blockNumber": 1405102, - "cumulativeGasUsed": "6315195", + "blockNumber": 1489362, + "cumulativeGasUsed": "3002183", "status": 1, "byzantium": true }, "args": [], "numDeployments": 1, - "solcInputHash": "da4c2bc4af0be4b969e54f8b43895033", + "solcInputHash": "5e7101910c63b5cb160cf1f36fa86058", "metadata": "{\"compiler\":{\"version\":\"0.8.7+commit.e28d00a7\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"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\":true,\"internalType\":\"address\",\"name\":\"previousGovernor\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newGovernor\",\"type\":\"address\"}],\"name\":\"PendingGovernorshipTransfer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"implementation\",\"type\":\"address\"}],\"name\":\"Upgraded\",\"type\":\"event\"},{\"stateMutability\":\"payable\",\"type\":\"fallback\"},{\"inputs\":[],\"name\":\"admin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"claimGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"governor\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"implementation\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_logic\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_initGovernor\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isGovernor\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_newGovernor\",\"type\":\"address\"}],\"name\":\"transferGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newImplementation\",\"type\":\"address\"}],\"name\":\"upgradeTo\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newImplementation\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"upgradeToAndCall\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"admin()\":{\"returns\":{\"_0\":\"The address of the proxy admin/it's also the governor.\"}},\"implementation()\":{\"returns\":{\"_0\":\"The address of the implementation.\"}},\"initialize(address,address,bytes)\":{\"details\":\"Contract initializer with Governor enforcement\",\"params\":{\"_data\":\"Data to send as msg.data to the implementation to initialize the proxied contract. It should include the signature and the parameters of the function to be called, as described in https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding. This parameter is optional, if no data is given the initialization call to proxied contract will be skipped.\",\"_initGovernor\":\"Address of the initial Governor.\",\"_logic\":\"Address of the initial implementation.\"}},\"transferGovernance(address)\":{\"params\":{\"_newGovernor\":\"Address of the new Governor\"}},\"upgradeTo(address)\":{\"details\":\"Upgrade the backing implementation of the proxy. Only the admin can call this function.\",\"params\":{\"newImplementation\":\"Address of the new implementation.\"}},\"upgradeToAndCall(address,bytes)\":{\"details\":\"Upgrade the backing implementation of the proxy and call a function on the new implementation. This is useful to initialize the proxied contract.\",\"params\":{\"data\":\"Data to send as msg.data in the low level call. It should include the signature and the parameters of the function to be called, as described in https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.\",\"newImplementation\":\"Address of the new implementation.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"claimGovernance()\":{\"notice\":\"Claim Governance of the contract to a new account (`newGovernor`). Can only be called by the new Governor.\"},\"governor()\":{\"notice\":\"Returns the address of the current Governor.\"},\"isGovernor()\":{\"notice\":\"Returns true if the caller is the current Governor.\"},\"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\"}},\"notice\":\"NativeStakingSSVStrategyProxy delegates calls to NativeStakingSSVStrategy implementation\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/proxies/Proxies.sol\":\"NativeStakingSSVStrategyProxy\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@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\"},\"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/proxies/InitializeGovernedUpgradeabilityProxy.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport { Address } from \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\n\\nimport { Governable } from \\\"../governance/Governable.sol\\\";\\n\\n/**\\n * @title BaseGovernedUpgradeabilityProxy\\n * @dev This contract combines an upgradeability proxy with our governor system.\\n * It is based on an older version of OpenZeppelins BaseUpgradeabilityProxy\\n * with Solidity ^0.8.0.\\n * @author Origin Protocol Inc\\n */\\ncontract InitializeGovernedUpgradeabilityProxy is Governable {\\n /**\\n * @dev Emitted when the implementation is upgraded.\\n * @param implementation Address of the new implementation.\\n */\\n event Upgraded(address indexed implementation);\\n\\n /**\\n * @dev Contract initializer with Governor enforcement\\n * @param _logic Address of the initial implementation.\\n * @param _initGovernor Address of the initial Governor.\\n * @param _data Data to send as msg.data to the implementation to initialize\\n * the proxied contract.\\n * It should include the signature and the parameters of the function to be\\n * called, as described in\\n * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.\\n * This parameter is optional, if no data is given the initialization call\\n * to proxied contract will be skipped.\\n */\\n function initialize(\\n address _logic,\\n address _initGovernor,\\n bytes calldata _data\\n ) public payable onlyGovernor {\\n require(_implementation() == address(0));\\n assert(\\n IMPLEMENTATION_SLOT ==\\n bytes32(uint256(keccak256(\\\"eip1967.proxy.implementation\\\")) - 1)\\n );\\n _setImplementation(_logic);\\n if (_data.length > 0) {\\n (bool success, ) = _logic.delegatecall(_data);\\n require(success);\\n }\\n _changeGovernor(_initGovernor);\\n }\\n\\n /**\\n * @return The address of the proxy admin/it's also the governor.\\n */\\n function admin() external view returns (address) {\\n return _governor();\\n }\\n\\n /**\\n * @return The address of the implementation.\\n */\\n function implementation() external view returns (address) {\\n return _implementation();\\n }\\n\\n /**\\n * @dev Upgrade the backing implementation of the proxy.\\n * Only the admin can call this function.\\n * @param newImplementation Address of the new implementation.\\n */\\n function upgradeTo(address newImplementation) external onlyGovernor {\\n _upgradeTo(newImplementation);\\n }\\n\\n /**\\n * @dev Upgrade the backing implementation of the proxy and call a function\\n * on the new implementation.\\n * This is useful to initialize the proxied contract.\\n * @param newImplementation Address of the new implementation.\\n * @param data Data to send as msg.data in the low level call.\\n * It should include the signature and the parameters of the function to be called, as described in\\n * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.\\n */\\n function upgradeToAndCall(address newImplementation, bytes calldata data)\\n external\\n payable\\n onlyGovernor\\n {\\n _upgradeTo(newImplementation);\\n (bool success, ) = newImplementation.delegatecall(data);\\n require(success);\\n }\\n\\n /**\\n * @dev Fallback function.\\n * Implemented entirely in `_fallback`.\\n */\\n fallback() external payable {\\n _fallback();\\n }\\n\\n /**\\n * @dev Delegates execution to an implementation contract.\\n * This is a low level function that doesn't return to its internal call site.\\n * It will return to the external caller whatever the implementation returns.\\n * @param _impl Address to delegate.\\n */\\n function _delegate(address _impl) internal {\\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(gas(), _impl, 0, calldatasize(), 0, 0)\\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 /**\\n * @dev Function that is run as the first thing in the fallback function.\\n * Can be redefined in derived contracts to add functionality.\\n * Redefinitions must call super._willFallback().\\n */\\n function _willFallback() internal {}\\n\\n /**\\n * @dev fallback implementation.\\n * Extracted to enable manual triggering.\\n */\\n function _fallback() internal {\\n _willFallback();\\n _delegate(_implementation());\\n }\\n\\n /**\\n * @dev Storage slot with the address of the current implementation.\\n * This is the keccak-256 hash of \\\"eip1967.proxy.implementation\\\" subtracted by 1, and is\\n * validated in the constructor.\\n */\\n bytes32 internal constant IMPLEMENTATION_SLOT =\\n 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\\n\\n /**\\n * @dev Returns the current implementation.\\n * @return impl Address of the current implementation\\n */\\n function _implementation() internal view returns (address impl) {\\n bytes32 slot = IMPLEMENTATION_SLOT;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n impl := sload(slot)\\n }\\n }\\n\\n /**\\n * @dev Upgrades the proxy to a new implementation.\\n * @param newImplementation Address of the new implementation.\\n */\\n function _upgradeTo(address newImplementation) internal {\\n _setImplementation(newImplementation);\\n emit Upgraded(newImplementation);\\n }\\n\\n /**\\n * @dev Sets the implementation address of the proxy.\\n * @param newImplementation Address of the new implementation.\\n */\\n function _setImplementation(address newImplementation) internal {\\n require(\\n Address.isContract(newImplementation),\\n \\\"Cannot set a proxy implementation to a non-contract address\\\"\\n );\\n\\n bytes32 slot = IMPLEMENTATION_SLOT;\\n\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n sstore(slot, newImplementation)\\n }\\n }\\n}\\n\",\"keccak256\":\"0xcf9bc33957fa41a745726edb6461a4bddca875a038c848286a059f0f22b7f184\",\"license\":\"MIT\"},\"contracts/proxies/Proxies.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport { InitializeGovernedUpgradeabilityProxy } from \\\"./InitializeGovernedUpgradeabilityProxy.sol\\\";\\n\\n/**\\n * @notice OUSDProxy delegates calls to an OUSD implementation\\n */\\ncontract OUSDProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice WrappedOUSDProxy delegates calls to a WrappedOUSD implementation\\n */\\ncontract WrappedOUSDProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice VaultProxy delegates calls to a Vault implementation\\n */\\ncontract VaultProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice CompoundStrategyProxy delegates calls to a CompoundStrategy implementation\\n */\\ncontract CompoundStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice AaveStrategyProxy delegates calls to a AaveStrategy implementation\\n */\\ncontract AaveStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice ThreePoolStrategyProxy delegates calls to a ThreePoolStrategy implementation\\n */\\ncontract ThreePoolStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice ConvexStrategyProxy delegates calls to a ConvexStrategy implementation\\n */\\ncontract ConvexStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice HarvesterProxy delegates calls to a Harvester implementation\\n */\\ncontract HarvesterProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice DripperProxy delegates calls to a Dripper implementation\\n */\\ncontract DripperProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice MorphoCompoundStrategyProxy delegates calls to a MorphoCompoundStrategy implementation\\n */\\ncontract MorphoCompoundStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice ConvexOUSDMetaStrategyProxy delegates calls to a ConvexOUSDMetaStrategy implementation\\n */\\ncontract ConvexOUSDMetaStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice ConvexLUSDMetaStrategyProxy delegates calls to a ConvexalGeneralizedMetaStrategy implementation\\n */\\ncontract ConvexLUSDMetaStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice MorphoAaveStrategyProxy delegates calls to a MorphoCompoundStrategy implementation\\n */\\ncontract MorphoAaveStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice OETHProxy delegates calls to nowhere for now\\n */\\ncontract OETHProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice WOETHProxy delegates calls to nowhere for now\\n */\\ncontract WOETHProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice OETHVaultProxy delegates calls to a Vault implementation\\n */\\ncontract OETHVaultProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice OETHDripperProxy delegates calls to a OETHDripper implementation\\n */\\ncontract OETHDripperProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice OETHHarvesterProxy delegates calls to a Harvester implementation\\n */\\ncontract OETHHarvesterProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice FraxETHStrategyProxy delegates calls to a FraxETHStrategy implementation\\n */\\ncontract FraxETHStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice CurveEthStrategyProxy delegates calls to a CurveEthStrategy implementation\\n */\\ncontract ConvexEthMetaStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice BuybackProxy delegates calls to Buyback implementation\\n */\\ncontract BuybackProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice OETHMorphoAaveStrategyProxy delegates calls to a MorphoAaveStrategy implementation\\n */\\ncontract OETHMorphoAaveStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice OETHBalancerMetaPoolrEthStrategyProxy delegates calls to a BalancerMetaPoolStrategy implementation\\n */\\ncontract OETHBalancerMetaPoolrEthStrategyProxy is\\n InitializeGovernedUpgradeabilityProxy\\n{\\n\\n}\\n\\n/**\\n * @notice OETHBalancerMetaPoolwstEthStrategyProxy delegates calls to a BalancerMetaPoolStrategy implementation\\n */\\ncontract OETHBalancerMetaPoolwstEthStrategyProxy is\\n InitializeGovernedUpgradeabilityProxy\\n{\\n\\n}\\n\\n/**\\n * @notice FluxStrategyProxy delegates calls to a CompoundStrategy implementation\\n */\\ncontract FluxStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice MakerDsrStrategyProxy delegates calls to a Generalized4626Strategy implementation\\n */\\ncontract MakerDsrStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice FrxEthRedeemStrategyProxy delegates calls to a FrxEthRedeemStrategy implementation\\n */\\ncontract FrxEthRedeemStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice OETHBuybackProxy delegates calls to Buyback implementation\\n */\\ncontract OETHBuybackProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice BridgedWOETHProxy delegates calls to BridgedWOETH implementation\\n */\\ncontract BridgedWOETHProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice NativeStakingSSVStrategyProxy delegates calls to NativeStakingSSVStrategy implementation\\n */\\ncontract NativeStakingSSVStrategyProxy is\\n InitializeGovernedUpgradeabilityProxy\\n{\\n\\n}\\n\\n/**\\n * @notice NativeStakingFeeAccumulatorProxy delegates calls to NativeStakingFeeCollector implementation\\n */\\ncontract NativeStakingFeeAccumulatorProxy is\\n InitializeGovernedUpgradeabilityProxy\\n{\\n\\n}\\n\",\"keccak256\":\"0x2e294507edd91494e1020a2a1c43502d2f5cba01266c228406562ecde7a2d872\",\"license\":\"MIT\"}},\"version\":1}", "bytecode": "0x608060405234801561001057600080fd5b506100273360008051602061099083398151915255565b600080516020610990833981519152546040516001600160a01b03909116906000907fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a908290a36109138061007d6000396000f3fe6080604052600436106100865760003560e01c80635d36b190116100595780635d36b1901461010a578063c7af33521461011f578063cf7a1d7714610144578063d38bfff414610157578063f851a4401461009057610086565b80630c340a24146100905780633659cfe6146100c25780634f1ef286146100e25780635c60da1b146100f5575b61008e610177565b005b34801561009c57600080fd5b506100a5610197565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156100ce57600080fd5b5061008e6100dd366004610745565b6101b4565b61008e6100f03660046107c8565b6101ed565b34801561010157600080fd5b506100a561028a565b34801561011657600080fd5b5061008e6102a2565b34801561012b57600080fd5b50610134610346565b60405190151581526020016100b9565b61008e610152366004610767565b610377565b34801561016357600080fd5b5061008e610172366004610745565b610491565b61019561019060008051602061089e8339815191525490565b610535565b565b60006101af6000805160206108be8339815191525490565b905090565b6101bc610346565b6101e15760405162461bcd60e51b81526004016101d89061082b565b60405180910390fd5b6101ea81610559565b50565b6101f5610346565b6102115760405162461bcd60e51b81526004016101d89061082b565b61021a83610559565b6000836001600160a01b0316838360405161023692919061081b565b600060405180830381855af49150503d8060008114610271576040519150601f19603f3d011682016040523d82523d6000602084013e610276565b606091505b505090508061028457600080fd5b50505050565b60006101af60008051602061089e8339815191525490565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b03161461033d5760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b60648201526084016101d8565b61019533610599565b600061035e6000805160206108be8339815191525490565b6001600160a01b0316336001600160a01b031614905090565b61037f610346565b61039b5760405162461bcd60e51b81526004016101d89061082b565b60006103b360008051602061089e8339815191525490565b6001600160a01b0316146103c657600080fd5b6103f160017f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbd610862565b60008051602061089e8339815191521461040d5761040d610887565b6104168461065a565b8015610488576000846001600160a01b0316838360405161043892919061081b565b600060405180830381855af49150503d8060008114610473576040519150601f19603f3d011682016040523d82523d6000602084013e610478565b606091505b505090508061048657600080fd5b505b61028483610599565b610499610346565b6104b55760405162461bcd60e51b81526004016101d89061082b565b6104dd817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b03166104fd6000805160206108be8339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b3660008037600080366000845af43d6000803e808015610554573d6000f35b3d6000fd5b6105628161065a565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b6001600160a01b0381166105ef5760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f72206973206164647265737328302900000000000060448201526064016101d8565b806001600160a01b031661060f6000805160206108be8339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a36101ea816000805160206108be83398151915255565b803b6106ce5760405162461bcd60e51b815260206004820152603b60248201527f43616e6e6f742073657420612070726f787920696d706c656d656e746174696f60448201527f6e20746f2061206e6f6e2d636f6e74726163742061646472657373000000000060648201526084016101d8565b60008051602061089e83398151915255565b80356001600160a01b03811681146106f757600080fd5b919050565b60008083601f84011261070e57600080fd5b50813567ffffffffffffffff81111561072657600080fd5b60208301915083602082850101111561073e57600080fd5b9250929050565b60006020828403121561075757600080fd5b610760826106e0565b9392505050565b6000806000806060858703121561077d57600080fd5b610786856106e0565b9350610794602086016106e0565b9250604085013567ffffffffffffffff8111156107b057600080fd5b6107bc878288016106fc565b95989497509550505050565b6000806000604084860312156107dd57600080fd5b6107e6846106e0565b9250602084013567ffffffffffffffff81111561080257600080fd5b61080e868287016106fc565b9497909650939450505050565b8183823760009101908152919050565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b60008282101561088257634e487b7160e01b600052601160045260246000fd5b500390565b634e487b7160e01b600052600160045260246000fdfe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa26469706673582212203019a79a43f7d4ec89620197adcc99852be5f4965adfb8a6bbb0ad3954812e2c64736f6c634300080700337bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a", "deployedBytecode": "0x6080604052600436106100865760003560e01c80635d36b190116100595780635d36b1901461010a578063c7af33521461011f578063cf7a1d7714610144578063d38bfff414610157578063f851a4401461009057610086565b80630c340a24146100905780633659cfe6146100c25780634f1ef286146100e25780635c60da1b146100f5575b61008e610177565b005b34801561009c57600080fd5b506100a5610197565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156100ce57600080fd5b5061008e6100dd366004610745565b6101b4565b61008e6100f03660046107c8565b6101ed565b34801561010157600080fd5b506100a561028a565b34801561011657600080fd5b5061008e6102a2565b34801561012b57600080fd5b50610134610346565b60405190151581526020016100b9565b61008e610152366004610767565b610377565b34801561016357600080fd5b5061008e610172366004610745565b610491565b61019561019060008051602061089e8339815191525490565b610535565b565b60006101af6000805160206108be8339815191525490565b905090565b6101bc610346565b6101e15760405162461bcd60e51b81526004016101d89061082b565b60405180910390fd5b6101ea81610559565b50565b6101f5610346565b6102115760405162461bcd60e51b81526004016101d89061082b565b61021a83610559565b6000836001600160a01b0316838360405161023692919061081b565b600060405180830381855af49150503d8060008114610271576040519150601f19603f3d011682016040523d82523d6000602084013e610276565b606091505b505090508061028457600080fd5b50505050565b60006101af60008051602061089e8339815191525490565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b03161461033d5760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b60648201526084016101d8565b61019533610599565b600061035e6000805160206108be8339815191525490565b6001600160a01b0316336001600160a01b031614905090565b61037f610346565b61039b5760405162461bcd60e51b81526004016101d89061082b565b60006103b360008051602061089e8339815191525490565b6001600160a01b0316146103c657600080fd5b6103f160017f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbd610862565b60008051602061089e8339815191521461040d5761040d610887565b6104168461065a565b8015610488576000846001600160a01b0316838360405161043892919061081b565b600060405180830381855af49150503d8060008114610473576040519150601f19603f3d011682016040523d82523d6000602084013e610478565b606091505b505090508061048657600080fd5b505b61028483610599565b610499610346565b6104b55760405162461bcd60e51b81526004016101d89061082b565b6104dd817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b03166104fd6000805160206108be8339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b3660008037600080366000845af43d6000803e808015610554573d6000f35b3d6000fd5b6105628161065a565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b6001600160a01b0381166105ef5760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f72206973206164647265737328302900000000000060448201526064016101d8565b806001600160a01b031661060f6000805160206108be8339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a36101ea816000805160206108be83398151915255565b803b6106ce5760405162461bcd60e51b815260206004820152603b60248201527f43616e6e6f742073657420612070726f787920696d706c656d656e746174696f60448201527f6e20746f2061206e6f6e2d636f6e74726163742061646472657373000000000060648201526084016101d8565b60008051602061089e83398151915255565b80356001600160a01b03811681146106f757600080fd5b919050565b60008083601f84011261070e57600080fd5b50813567ffffffffffffffff81111561072657600080fd5b60208301915083602082850101111561073e57600080fd5b9250929050565b60006020828403121561075757600080fd5b610760826106e0565b9392505050565b6000806000806060858703121561077d57600080fd5b610786856106e0565b9350610794602086016106e0565b9250604085013567ffffffffffffffff8111156107b057600080fd5b6107bc878288016106fc565b95989497509550505050565b6000806000604084860312156107dd57600080fd5b6107e6846106e0565b9250602084013567ffffffffffffffff81111561080257600080fd5b61080e868287016106fc565b9497909650939450505050565b8183823760009101908152919050565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b60008282101561088257634e487b7160e01b600052601160045260246000fd5b500390565b634e487b7160e01b600052600160045260246000fdfe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa26469706673582212203019a79a43f7d4ec89620197adcc99852be5f4965adfb8a6bbb0ad3954812e2c64736f6c63430008070033", diff --git a/contracts/deployments/holesky/OETHHarvester.json b/contracts/deployments/holesky/OETHHarvester.json index bfc4c84482..694edc13d3 100644 --- a/contracts/deployments/holesky/OETHHarvester.json +++ b/contracts/deployments/holesky/OETHHarvester.json @@ -1,5 +1,5 @@ { - "address": "0x22b00a89531E199bd90eC162F9810298b9FBC8b3", + "address": "0xBd09F938259AE61e089959d52580235b76C69A83", "abi": [ { "inputs": [ @@ -694,46 +694,46 @@ "type": "function" } ], - "transactionHash": "0x4b3113aba3207e3c1ef50452c3ee4f5c18a1606f38f31864acd0bb872f1c8baf", + "transactionHash": "0xb261b4230c6856c159cd50e1f4005943c06e59ce82bd06eca13608c61940e110", "receipt": { "to": null, "from": "0x1b94CA50D3Ad9f8368851F8526132272d1a5028C", - "contractAddress": "0x22b00a89531E199bd90eC162F9810298b9FBC8b3", - "transactionIndex": 61, - "gasUsed": "2857566", - "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000020000000000000000001800000000000000000000000000000000000004000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000010000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000100000000", - "blockHash": "0x14116552a1bab414922c64f6ccf8f1135e30b3e731c71bce315c90c9c8cb2fc5", - "transactionHash": "0x4b3113aba3207e3c1ef50452c3ee4f5c18a1606f38f31864acd0bb872f1c8baf", + "contractAddress": "0xBd09F938259AE61e089959d52580235b76C69A83", + "transactionIndex": 38, + "gasUsed": "2900119", + "logsBloom": "0x00000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000000004000000000000002000000000000000000040000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000010000000000010000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x8a3dd6f9d1e547a31be3fba7f0ef840ba40a7a921e4e6dc37b5f7f41ae8a9ff4", + "transactionHash": "0xb261b4230c6856c159cd50e1f4005943c06e59ce82bd06eca13608c61940e110", "logs": [ { - "transactionIndex": 61, - "blockNumber": 1405153, - "transactionHash": "0x4b3113aba3207e3c1ef50452c3ee4f5c18a1606f38f31864acd0bb872f1c8baf", - "address": "0x22b00a89531E199bd90eC162F9810298b9FBC8b3", + "transactionIndex": 38, + "blockNumber": 1471485, + "transactionHash": "0xb261b4230c6856c159cd50e1f4005943c06e59ce82bd06eca13608c61940e110", + "address": "0xBd09F938259AE61e089959d52580235b76C69A83", "topics": [ "0xc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000001b94ca50d3ad9f8368851f8526132272d1a5028c" ], "data": "0x", - "logIndex": 495, - "blockHash": "0x14116552a1bab414922c64f6ccf8f1135e30b3e731c71bce315c90c9c8cb2fc5" + "logIndex": 503, + "blockHash": "0x8a3dd6f9d1e547a31be3fba7f0ef840ba40a7a921e4e6dc37b5f7f41ae8a9ff4" } ], - "blockNumber": 1405153, - "cumulativeGasUsed": "24006246", + "blockNumber": 1471485, + "cumulativeGasUsed": "23563856", "status": 1, "byzantium": true }, "args": [ "0x19d2bAaBA949eFfa163bFB9efB53ed8701aA5dD9", - "0x94373a4919b3240d86ea41593d5eba789fef3848" + "0x94373a4919B3240D86eA41593D5eBa789FEF3848" ], - "numDeployments": 1, - "solcInputHash": "da4c2bc4af0be4b969e54f8b43895033", - "metadata": "{\"compiler\":{\"version\":\"0.8.7+commit.e28d00a7\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_vault\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_wethAddress\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"actualBalance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"minExpected\",\"type\":\"uint256\"}],\"name\":\"BalanceMismatchAfterSwap\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"EmptyAddress\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"EmptyBalancerPoolId\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"InvalidCurvePoolAssetIndex\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidHarvestRewardBps\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSlippageBps\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"enum BaseHarvester.SwapPlatform\",\"name\":\"swapPlatform\",\"type\":\"uint8\"}],\"name\":\"InvalidSwapPlatform\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"InvalidTokenInSwapPath\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidUniswapV2PathLength\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"actualBalance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"minExpected\",\"type\":\"uint256\"}],\"name\":\"SlippageError\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"strategyAddress\",\"type\":\"address\"}],\"name\":\"UnsupportedStrategy\",\"type\":\"error\"},{\"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\":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\":\"newProceedsAddress\",\"type\":\"address\"}],\"name\":\"RewardProceedsAddressChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"farmer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"protcolYield\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"farmerFee\",\"type\":\"uint256\"}],\"name\":\"RewardProceedsTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"tokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"allowedSlippageBps\",\"type\":\"uint16\"},{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"harvestRewardBps\",\"type\":\"uint16\"},{\"indexed\":false,\"internalType\":\"enum BaseHarvester.SwapPlatform\",\"name\":\"swapPlatform\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"swapPlatformAddr\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"swapData\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"liquidationLimit\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"doSwapRewardToken\",\"type\":\"bool\"}],\"name\":\"RewardTokenConfigUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"rewardToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"swappedInto\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"enum BaseHarvester.SwapPlatform\",\"name\":\"swapPlatform\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountIn\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountOut\",\"type\":\"uint256\"}],\"name\":\"RewardTokenSwapped\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"strategyAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"isSupported\",\"type\":\"bool\"}],\"name\":\"SupportedStrategyUpdate\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"balancerPoolId\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"baseTokenAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"baseTokenDecimals\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"claimGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"curvePoolIndices\",\"outputs\":[{\"internalType\":\"uint128\",\"name\":\"rewardTokenIndex\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"baseTokenIndex\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"governor\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_strategyAddr\",\"type\":\"address\"}],\"name\":\"harvestAndSwap\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_strategyAddr\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_rewardTo\",\"type\":\"address\"}],\"name\":\"harvestAndSwap\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isGovernor\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rewardProceedsAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"rewardTokenConfigs\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"allowedSlippageBps\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"harvestRewardBps\",\"type\":\"uint16\"},{\"internalType\":\"address\",\"name\":\"swapPlatformAddr\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"doSwapRewardToken\",\"type\":\"bool\"},{\"internalType\":\"enum BaseHarvester.SwapPlatform\",\"name\":\"swapPlatform\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"liquidationLimit\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_rewardProceedsAddress\",\"type\":\"address\"}],\"name\":\"setRewardProceedsAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_tokenAddress\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint16\",\"name\":\"allowedSlippageBps\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"harvestRewardBps\",\"type\":\"uint16\"},{\"internalType\":\"address\",\"name\":\"swapPlatformAddr\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"doSwapRewardToken\",\"type\":\"bool\"},{\"internalType\":\"enum BaseHarvester.SwapPlatform\",\"name\":\"swapPlatform\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"liquidationLimit\",\"type\":\"uint256\"}],\"internalType\":\"struct BaseHarvester.RewardTokenConfig\",\"name\":\"tokenConfig\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"swapData\",\"type\":\"bytes\"}],\"name\":\"setRewardTokenConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_strategyAddress\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"_isSupported\",\"type\":\"bool\"}],\"name\":\"setSupportedStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"supportedStrategies\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"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\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"uniswapV2Path\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"uniswapV3Path\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"vaultAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"harvestAndSwap(address)\":{\"details\":\"Collect reward tokens from a specific strategy and swap them for base token on the configured swap platform. Can be called by anyone. Rewards incentivizing the caller are sent to the caller of this function.\",\"params\":{\"_strategyAddr\":\"Address of the strategy to collect rewards from\"}},\"harvestAndSwap(address,address)\":{\"details\":\"Collect reward tokens from a specific strategy and swap them for base token on the configured swap platform. Can be called by anyone\",\"params\":{\"_rewardTo\":\"Address where to send a share of harvest rewards to as an incentive for executing this function\",\"_strategyAddr\":\"Address of the strategy to collect rewards from\"}},\"setRewardProceedsAddress(address)\":{\"params\":{\"_rewardProceedsAddress\":\"Address of the reward token\"}},\"setRewardTokenConfig(address,(uint16,uint16,address,bool,uint8,uint256),bytes)\":{\"details\":\"Add/update a reward token configuration that holds harvesting config variables\",\"params\":{\"_tokenAddress\":\"Address of the reward token\",\"swapData\":\"Additional data required for swapping\",\"tokenConfig\":\".swapPlatform SwapPlatform to use for Swapping\"}},\"setSupportedStrategy(address,bool)\":{\"details\":\"Flags a strategy as supported or not supported one\",\"params\":{\"_isSupported\":\"Bool marking strategy as supported or not supported\",\"_strategyAddress\":\"Address of the strategy\"}},\"transferGovernance(address)\":{\"params\":{\"_newGovernor\":\"Address of the new Governor\"}},\"transferToken(address,uint256)\":{\"details\":\"Transfer token to governor. Intended for recovering tokens stuck in contract, i.e. mistaken sends.\",\"params\":{\"_amount\":\"Amount of the asset to transfer\",\"_asset\":\"Address for the asset\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"baseTokenAddress()\":{\"notice\":\"All tokens are swapped to this token before it gets transferred to the `rewardProceedsAddress`. USDT for OUSD and WETH for OETH.*\"},\"claimGovernance()\":{\"notice\":\"Claim Governance of the contract to a new account (`newGovernor`). Can only be called by the new Governor.\"},\"governor()\":{\"notice\":\"Returns the address of the current Governor.\"},\"isGovernor()\":{\"notice\":\"Returns true if the caller is the current Governor.\"},\"rewardProceedsAddress()\":{\"notice\":\"Address receiving rewards proceeds. Initially the Vault contract later will possibly be replaced by another contract that eases out rewards distribution.*\"},\"setRewardProceedsAddress(address)\":{\"notice\":\"Set the Address receiving rewards proceeds.\"},\"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\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/harvest/OETHHarvester.sol\":\"OETHHarvester\"},\"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/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\",\"keccak256\":\"0xfaad496c1c944b6259b7dc70b4865eb1775d6402bc0c81b38a0b24d9f525ae37\",\"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/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 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 uint256 balance = IERC20(_swapToken).balanceOf(address(this));\\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 transfering `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 protcolYield = baseTokenBalance - farmerFee;\\n\\n baseToken.safeTransfer(rewardProceedsAddress, protcolYield);\\n baseToken.safeTransfer(_rewardTo, farmerFee);\\n emit RewardProceedsTransferred(\\n baseTokenAddress,\\n _rewardTo,\\n protcolYield,\\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\",\"keccak256\":\"0x909d6fcd5e294f04e1106bc0bedd344f5efc305db053cc678764ac64670df00d\",\"license\":\"MIT\"},\"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\",\"keccak256\":\"0x67255aabc4a8ec5d6650b3ab1daedffa093d8f6c324ee92281581c05990098bc\",\"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/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/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\",\"keccak256\":\"0x597796f9c5b3d174acbec8b520c633695c10d87762f7a0a7fec49b291694d7de\",\"license\":\"MIT\"},\"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\",\"keccak256\":\"0x3fdf2b91880f2b669202cc43bdceaf9d01537a9b955fc7a51159fb04fdbc68d4\",\"license\":\"MIT\"},\"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\",\"keccak256\":\"0xe32b76d23705979a297b164718aefa6b08e0ec3830883c020a5ac68d332a1dd2\",\"license\":\"MIT\"},\"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\",\"keccak256\":\"0x65e40829ff1f51c6c64fe991ed6a536b413ced85b9d9aa852d37fa14966d474c\",\"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/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\",\"keccak256\":\"0x5e17bb3db9f9e1014b7c5c836547f8fa81e02af7568c0bb8f2a2e0e7c2192db4\",\"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/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": "0x60e06040523480156200001157600080fd5b506040516200352f3803806200352f833981016040819052620000349162000215565b81816200004e336000805160206200350f83398151915255565b6000805160206200350f833981519152546040516001600160a01b03909116906000907fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a908290a36001600160a01b038216620000aa57600080fd5b6001600160a01b038116620000be57600080fd5b606082811b6001600160601b03199081166080529082901b1660a052620000f181620000ff602090811b62000d3217901c565b60c052506200027992505050565b600080826001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b1580156200013c57600080fd5b505afa15801562000151573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200017791906200024d565b60ff169050600481101580156200018f575060128111155b620001f25760405162461bcd60e51b815260206004820152602960248201527f546f6b656e206d75737420686176652073756666696369656e7420646563696d604482015268616c20706c6163657360b81b606482015260840160405180910390fd5b92915050565b80516001600160a01b03811681146200021057600080fd5b919050565b600080604083850312156200022957600080fd5b6200023483620001f8565b91506200024460208401620001f8565b90509250929050565b6000602082840312156200026057600080fd5b815160ff811681146200027257600080fd5b9392505050565b60805160601c60a05160601c60c05161320c62000303600039600081816102910152611a8401526000818161026a015281816110630152818161115c0152818161128001528181611486015281816114ca01528181611b3701528181611bbd01528181611cea01526122a70152600081816101a301528181610539015261158b015261320c6000f3fe608060405234801561001057600080fd5b506004361061012c5760003560e01c806382aa1c88116100ad578063d38bfff411610071578063d38bfff414610312578063da70696c14610325578063dac4db4e14610345578063e48d7fc514610358578063ee3be5f5146103ac57600080fd5b806382aa1c881461028c578063a994317f146102c1578063b13dc20a146102d4578063b76e83af146102e7578063c7af3352146102fa57600080fd5b8063548f5ae5116100f4578063548f5ae5146101c5578063587c8440146101d85780635d36b1901461024a57806365f6fa94146102525780637cb374bd1461026557600080fd5b80630c340a24146101315780631072cbea146101565780632579153d1461016b5780632dfbe8311461017e578063430bf08a1461019e575b600080fd5b6101396103cf565b6040516001600160a01b0390911681526020015b60405180910390f35b6101696101643660046126ec565b6103ec565b005b61016961017936600461264f565b610439565b61019161018c3660046125ae565b6108c8565b60405161014d9190612b1f565b6101397f000000000000000000000000000000000000000000000000000000000000000081565b6101696101d33660046125ae565b610962565b6102386101e63660046125ae565b6000602081905290815260409020805460019091015461ffff80831692620100008104909116916001600160a01b036401000000008304169160ff600160c01b8204811692600160c81b909204169086565b60405161014d96959493929190612cb0565b6101696109dd565b610169610260366004612621565b610a83565b6101397f000000000000000000000000000000000000000000000000000000000000000081565b6102b37f000000000000000000000000000000000000000000000000000000000000000081565b60405190815260200161014d565b6101696102cf3660046125e8565b610b0a565b6101696102e23660046125ae565b610b86565b600254610139906001600160a01b031681565b610302610c25565b604051901515815260200161014d565b6101696103203660046125ae565b610c56565b6102b36103333660046125ae565b60056020526000908152604090205481565b6101396103533660046126ec565b610cfa565b61038c6103663660046125ae565b6006602052600090815260409020546001600160801b0380821691600160801b90041682565b604080516001600160801b0393841681529290911660208301520161014d565b6103026103ba3660046125ae565b60016020526000908152604090205460ff1681565b60006103e76000805160206131b78339815191525490565b905090565b6103f4610c25565b6104195760405162461bcd60e51b815260040161041090612b5f565b60405180910390fd5b6104356104246103cf565b6001600160a01b0384169083610e21565b5050565b610441610c25565b61045d5760405162461bcd60e51b815260040161041090612b5f565b6103e861046d60208501856129aa565b61ffff1611156104905760405163faa3445560e01b815260040160405180910390fd5b6103e86104a360408501602086016129aa565b61ffff1611156104c657604051631633c8cd60e31b815260040160405180910390fd5b60006104d860608501604086016125ae565b90506001600160a01b03811661050157604051637138356f60e01b815260040160405180910390fd5b6001600160a01b03808616600090815260208190526040902080546401000000009004909116908590610534828261307b565b9050507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b888879e6040518163ffffffff1660e01b815260040160206040518083038186803b15801561059057600080fd5b505afa1580156105a4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105c891906125cb565b6040516315d5220f60e31b81526001600160a01b038881166004830152919091169063aea910789060240160206040518083038186803b15801561060b57600080fd5b505afa15801561061f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061064391906129c7565b50856001600160a01b0382161580159061066f5750826001600160a01b0316826001600160a01b031614155b15610689576106896001600160a01b038216836000610e89565b826001600160a01b0316826001600160a01b0316146106cd576106b76001600160a01b038216846000610e89565b6106cd6001600160a01b03821684600019610e89565b60006106df60a0880160808901612932565b905060008160038111156106f5576106f561301f565b14156107395761070686868a610fad565b6001600160a01b0389166000908152600360209081526040909120825161073393919291909101906124a4565b50610846565b600181600381111561074d5761074d61301f565b14156107815761075e86868a6110d9565b6001600160a01b038a166000908152600460205260409020610733929091612509565b60028160038111156107955761079561301f565b14156107c5576107a78686868b6111af565b6001600160a01b038916600090815260056020526040902055610846565b60038160038111156107d9576107d961301f565b141561082b576107eb8686868b611311565b6001600160a01b0389166000908152600660209081526040909120825192909101516001600160801b03908116600160801b029216919091179055610846565b806040516336cb1d2160e01b81526004016104109190612b32565b7f5eb6073ba3980477f03b1ce0dccba754d48454bbd65a115dcd42db65ca1fefd28861087560208a018a6129aa565b61088560408b0160208c016129aa565b84888b8b8e60a001358f60600160208101906108a191906128df565b6040516108b699989796959493929190612aa0565b60405180910390a15050505050505050565b600460205260009081526040902080546108e190612fb3565b80601f016020809104026020016040519081016040528092919081815260200182805461090d90612fb3565b801561095a5780601f1061092f5761010080835404028352916020019161095a565b820191906000526020600020905b81548152906001019060200180831161093d57829003601f168201915b505050505081565b7f53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac4535805460028114156109c75760405162461bcd60e51b815260206004820152600e60248201526d1499595b9d1c985b9d0818d85b1b60921b6044820152606401610410565b600282556109d58333611500565b506001905550565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b031614610a785760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b6064820152608401610410565b610a8133611667565b565b610a8b610c25565b610aa75760405162461bcd60e51b815260040161041090612b5f565b6001600160a01b038216600081815260016020908152604091829020805460ff19168515159081179091558251938452908301527f013ed61add17cbfcbbd95bf8543da67c89658c5477d3f3199a1a2d58ecf1913f910160405180910390a15050565b7f53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac453580546002811415610b6f5760405162461bcd60e51b815260206004820152600e60248201526d1499595b9d1c985b9d0818d85b1b60921b6044820152606401610410565b60028255610b7d8484611500565b50600190555050565b610b8e610c25565b610baa5760405162461bcd60e51b815260040161041090612b5f565b6001600160a01b038116610bd157604051637138356f60e01b815260040160405180910390fd5b600280546001600160a01b0319166001600160a01b0383169081179091556040519081527f50f4ca9002119593802480c412cb5e106ae726647a31dcf8a7e7ed4e6794bf5e9060200160405180910390a150565b6000610c3d6000805160206131b78339815191525490565b6001600160a01b0316336001600160a01b031614905090565b610c5e610c25565b610c7a5760405162461bcd60e51b815260040161041090612b5f565b610ca2817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b0316610cc26000805160206131b78339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b60036020528160005260406000208181548110610d1657600080fd5b6000918252602090912001546001600160a01b03169150829050565b600080826001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b158015610d6e57600080fd5b505afa158015610d82573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610da69190612a21565b60ff16905060048110158015610dbd575060128111155b610e1b5760405162461bcd60e51b815260206004820152602960248201527f546f6b656e206d75737420686176652073756666696369656e7420646563696d604482015268616c20706c6163657360b81b6064820152608401610410565b92915050565b6040516001600160a01b038316602482015260448101829052610e8490849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915261172b565b505050565b801580610f125750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e9060440160206040518083038186803b158015610ed857600080fd5b505afa158015610eec573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f1091906129c7565b155b610f7d5760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b6064820152608401610410565b6040516001600160a01b038316602482015260448101829052610e8490849063095ea7b360e01b90606401610e4d565b6060610fbb83850185612718565b80519091506002811015610fe2576040516360fa33db60e11b815260040160405180910390fd5b826001600160a01b031682600081518110610fff57610fff613035565b60200260200101516001600160a01b031614611059578160008151811061102857611028613035565b602002602001015160405163280d94a560e21b815260040161041091906001600160a01b0391909116815260200190565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168261108f600184612f37565b8151811061109f5761109f613035565b60200260200101516001600160a01b0316146110d157816110c1600183612f37565b8151811061102857611028613035565b509392505050565b828260006110ea6014828486612dbe565b6110f391612f4e565b60601c90506001600160a01b038416811461112c5760405163280d94a560e21b81526001600160a01b0382166004820152602401610410565b8585611139601485612f37565b611144928290612dbe565b61114d91612f4e565b60601c90506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001681146111a65760405163280d94a560e21b81526001600160a01b0382166004820152602401610410565b50935093915050565b60006111bd84860186612919565b9050806111dd57604051634bdc2c9560e01b815260040160405180910390fd5b60405163160bf1c960e31b8152600481018290526001600160a01b03838116602483015284919082169063b05f8e489060440160806040518083038186803b15801561122857600080fd5b505afa15801561123c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061126091906129e0565b505060405163160bf1c960e31b8152600481018590526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660248301528416925063b05f8e48915060440160806040518083038186803b1580156112cc57600080fd5b505afa1580156112e0573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061130491906129e0565b5050505050949350505050565b60408051808201909152600080825260208201526113318486018661294f565b805160405163c661065760e01b81526001600160801b03909116600482015290915083906001600160a01b0382169063c66106579060240160206040518083038186803b15801561138157600080fd5b505afa158015611395573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113b991906125cb565b6001600160a01b0316836001600160a01b0316146113f55760405163d658230160e01b81526001600160a01b0384166004820152602401610410565b602082015160405163c661065760e01b81526001600160801b0390911660048201526001600160a01b0382169063c66106579060240160206040518083038186803b15801561144357600080fd5b505afa158015611457573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061147b91906125cb565b6001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316146114f75760405163d658230160e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166004820152602401610410565b50949350505050565b611509826117fd565b60008290506000816001600160a01b031663f6ca71b06040518163ffffffff1660e01b815260040160006040518083038186803b15801561154957600080fd5b505afa15801561155d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261158591908101906127be565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b888879e6040518163ffffffff1660e01b815260040160206040518083038186803b1580156115e257600080fd5b505afa1580156115f6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061161a91906125cb565b825190915060005b8181101561165e5761164e84828151811061163f5761163f613035565b6020026020010151878561189d565b61165781612fee565b9050611622565b50505050505050565b6001600160a01b0381166116bd5760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f7220697320616464726573732830290000000000006044820152606401610410565b806001600160a01b03166116dd6000805160206131b78339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a3611728816000805160206131b783398151915255565b50565b6000611780826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611d489092919063ffffffff16565b805190915015610e84578080602001905181019061179e91906128fc565b610e845760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610410565b6001600160a01b03811660009081526001602052604090205460ff1661184157604051630211444960e11b81526001600160a01b0382166004820152602401610410565b6000819050806001600160a01b0316635a063f636040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561188157600080fd5b505af1158015611895573d6000803e3d6000fd5b505050505050565b6001600160a01b03808416600090815260208181526040808320815160c081018352815461ffff8082168352620100008204169482019490945264010000000084049095169185019190915260ff600160c01b830481161515606086015292939290916080840191600160c81b90910416600381111561191f5761191f61301f565b60038111156119305761193061301f565b81526020016001820154815250509050806060015161194f5750505050565b6040516370a0823160e01b81523060048201526000906001600160a01b038616906370a082319060240160206040518083038186803b15801561199157600080fd5b505afa1580156119a5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119c991906129c7565b9050806119d7575050505050565b60a0820151156119f2576119ef818360a00151611d61565b90505b6040516315d5220f60e31b81526001600160a01b0386811660048301526000919085169063aea910789060240160206040518083038186803b158015611a3757600080fd5b505afa158015611a4b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a6f91906129c7565b90506000670de0b6b3a7640000612710611adb7f0000000000000000000000000000000000000000000000000000000000000000611aac8b610d32565b88518790611abc90612710612f14565b611aca9061ffff168a612ef5565b611ad49190612ef5565b9190611d77565b611ae59190612de8565b611aef9190612de8565b90506000611b08856080015186604001518a8786611dd9565b905081811015611b35576040516302d96fff60e41b81526004810182905260248101839052604401610410565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316886001600160a01b03167fa861903141bc68b536d5048a576afcc645630e1b18a4296ef34cbd4d1407f70987608001518785604051611ba093929190612b40565b60405180910390a36040516370a0823160e01b81523060048201527f0000000000000000000000000000000000000000000000000000000000000000906000906001600160a01b038316906370a082319060240160206040518083038186803b158015611c0c57600080fd5b505afa158015611c20573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c4491906129c7565b905082811015611c715760405163315d50df60e11b81526004810182905260248101849052604401610410565b6020870151600090611c8b90859061ffff16612710611e9d565b90506000611c998284612f37565b600254909150611cb6906001600160a01b03868116911683610e21565b611cca6001600160a01b0385168c84610e21565b604080516001600160a01b038d81168252602082018490529181018490527f0000000000000000000000000000000000000000000000000000000000000000909116907f42e60aae8f000883c46e2f449fa76268e374ce1b962f46ca9360ab98b18f57999060600160405180910390a2505050505050505050505050565b6060611d578484600085611eb6565b90505b9392505050565b6000818310611d705781611d5a565b5090919050565b600081831115611da757611da0611d8e8385612f37565b611d9990600a612e4d565b8590611fde565b9350611dd1565b81831015611dd157611dce611dbc8484612f37565b611dc790600a612e4d565b8590611fea565b93505b509192915050565b600080866003811115611dee57611dee61301f565b1415611e0757611e0085858585611ff6565b9050611e94565b6001866003811115611e1b57611e1b61301f565b1415611e2d57611e0085858585612125565b6002866003811115611e4157611e4161301f565b1415611e5357611e0085858585612270565b6003866003811115611e6757611e6761301f565b1415611e7957611e0085858585612392565b856040516336cb1d2160e01b81526004016104109190612b32565b95945050505050565b600080611eaa8585611fde565b9050611e948184611fea565b606082471015611f175760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610410565b843b611f655760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610410565b600080866001600160a01b03168587604051611f819190612a84565b60006040518083038185875af1925050503d8060008114611fbe576040519150601f19603f3d011682016040523d82523d6000602084013e611fc3565b606091505b5091509150611fd382828661246b565b979650505050505050565b6000611d5a8284612ef5565b6000611d5a8284612de8565b6001600160a01b03831660009081526003602090815260408083208054825181850281018501909352808352849383018282801561205d57602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161203f575b505050505090506000866001600160a01b03166338ed173986868530426040518663ffffffff1660e01b815260040161209a959493929190612cf8565b600060405180830381600087803b1580156120b457600080fd5b505af11580156120c8573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526120f09190810190612853565b905080600182516121019190612f37565b8151811061211157612111613035565b602002602001015192505050949350505050565b6001600160a01b0383166000908152600460205260408120805482919061214b90612fb3565b80601f016020809104026020016040519081016040528092919081815260200182805461217790612fb3565b80156121c45780601f10612199576101008083540402835291602001916121c4565b820191906000526020600020905b8154815290600101906020018083116121a757829003601f168201915b50506040805160a0810182528581523060208201524281830152606081018a905260808101899052905163c04b8d5960e01b8152949550936001600160a01b038b16935063c04b8d59925061221e91508490600401612b96565b602060405180830381600087803b15801561223857600080fd5b505af115801561224c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fd391906129c7565b6001600160a01b03838116600081815260056020908152604080832054815160c081018352818152808401859052808301959095527f0000000000000000000000000000000000000000000000000000000000000000861660608087019190915260808087018a90528351808601855286815260a0880152835190810184523080825294810186905280840194909452830184905290516352bbbe2960e01b81529294909392908916906352bbbe299061233490859085908a904290600401612bee565b602060405180830381600087803b15801561234e57600080fd5b505af1158015612362573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061238691906129c7565b98975050505050505050565b6001600160a01b0383811660009081526006602090815260408083208151808301835290546001600160801b03808216808452600160801b909204169382018490529151630b68372160e31b81526004810192909252602482019290925260448101869052606481018590529192909190871690635b41b90890608401602060405180830381600087803b15801561242957600080fd5b505af115801561243d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061246191906129c7565b9695505050505050565b6060831561247a575081611d5a565b82511561248a5782518084602001fd5b8160405162461bcd60e51b81526004016104109190612b1f565b8280548282559060005260206000209081019282156124f9579160200282015b828111156124f957825182546001600160a01b0319166001600160a01b039091161782556020909201916001909101906124c4565b5061250592915061257d565b5090565b82805461251590612fb3565b90600052602060002090601f01602090048101928261253757600085556124f9565b82601f106125505782800160ff198235161785556124f9565b828001600101855582156124f9579182015b828111156124f9578235825591602001919060010190612562565b5b80821115612505576000815560010161257e565b80356001600160801b03811681146125a957600080fd5b919050565b6000602082840312156125c057600080fd5b8135611d5a81613176565b6000602082840312156125dd57600080fd5b8151611d5a81613176565b600080604083850312156125fb57600080fd5b823561260681613176565b9150602083013561261681613176565b809150509250929050565b6000806040838503121561263457600080fd5b823561263f81613176565b915060208301356126168161318b565b60008060008084860361010081121561266757600080fd5b853561267281613176565b945060c0601f198201121561268657600080fd5b5060208501925060e085013567ffffffffffffffff808211156126a857600080fd5b818701915087601f8301126126bc57600080fd5b8135818111156126cb57600080fd5b8860208285010111156126dd57600080fd5b95989497505060200194505050565b600080604083850312156126ff57600080fd5b823561270a81613176565b946020939093013593505050565b6000602080838503121561272b57600080fd5b823567ffffffffffffffff81111561274257600080fd5b8301601f8101851361275357600080fd5b803561276661276182612d9a565b612d69565b80828252848201915084840188868560051b870101111561278657600080fd5b600094505b838510156127b257803561279e81613176565b83526001949094019391850191850161278b565b50979650505050505050565b600060208083850312156127d157600080fd5b825167ffffffffffffffff8111156127e857600080fd5b8301601f810185136127f957600080fd5b805161280761276182612d9a565b80828252848201915084840188868560051b870101111561282757600080fd5b600094505b838510156127b257805161283f81613176565b83526001949094019391850191850161282c565b6000602080838503121561286657600080fd5b825167ffffffffffffffff81111561287d57600080fd5b8301601f8101851361288e57600080fd5b805161289c61276182612d9a565b80828252848201915084840188868560051b87010111156128bc57600080fd5b600094505b838510156127b25780518352600194909401939185019185016128c1565b6000602082840312156128f157600080fd5b8135611d5a8161318b565b60006020828403121561290e57600080fd5b8151611d5a8161318b565b60006020828403121561292b57600080fd5b5035919050565b60006020828403121561294457600080fd5b8135611d5a81613199565b60006040828403121561296157600080fd5b6040516040810181811067ffffffffffffffff821117156129845761298461304b565b60405261299083612592565b815261299e60208401612592565b60208201529392505050565b6000602082840312156129bc57600080fd5b8135611d5a816131a6565b6000602082840312156129d957600080fd5b5051919050565b600080600080608085870312156129f657600080fd5b8451935060208501519250604085015191506060850151612a1681613176565b939692955090935050565b600060208284031215612a3357600080fd5b815160ff81168114611d5a57600080fd5b60008151808452612a5c816020860160208601612f83565b601f01601f19169290920160200192915050565b60048110612a8057612a8061301f565b9052565b60008251612a96818460208701612f83565b9190910192915050565b6001600160a01b038a8116825261ffff8a811660208401528916604083015260009061010090612ad3606085018b612a70565b8816608084015260a083018190528201859052610120858782850137600083870182015260c08301949094525090151560e0820152601f909201601f1916909101019695505050505050565b602081526000611d5a6020830184612a44565b60208101610e1b8284612a70565b60608101612b4e8286612a70565b602082019390935260400152919050565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b602081526000825160a06020840152612bb260c0840182612a44565b905060018060a01b0360208501511660408401526040840151606084015260608401516080840152608084015160a08401528091505092915050565b60e08152845160e08201526000602086015160028110612c1057612c1061301f565b61010083015260408601516001600160a01b03908116610120840152606087015116610140830152608086015161016083015260a086015160c0610180840152612c5e6101a0840182612a44565b915050612c9e602083018680516001600160a01b039081168352602080830151151590840152604080830151909116908301526060908101511515910152565b60a082019390935260c0015292915050565b61ffff8781168252861660208201526001600160a01b0385166040820152831515606082015260c08101612ce76080830185612a70565b8260a0830152979650505050505050565b600060a082018783526020878185015260a0604085015281875180845260c086019150828901935060005b81811015612d485784516001600160a01b031683529383019391830191600101612d23565b50506001600160a01b03969096166060850152505050608001529392505050565b604051601f8201601f1916810167ffffffffffffffff81118282101715612d9257612d9261304b565b604052919050565b600067ffffffffffffffff821115612db457612db461304b565b5060051b60200190565b60008085851115612dce57600080fd5b83861115612ddb57600080fd5b5050820193919092039150565b600082612e0557634e487b7160e01b600052601260045260246000fd5b500490565b600181815b80851115612e45578160001904821115612e2b57612e2b613009565b80851615612e3857918102915b93841c9390800290612e0f565b509250929050565b6000611d5a8383600082612e6357506001610e1b565b81612e7057506000610e1b565b8160018114612e865760028114612e9057612eac565b6001915050610e1b565b60ff841115612ea157612ea1613009565b50506001821b610e1b565b5060208310610133831016604e8410600b8410161715612ecf575081810a610e1b565b612ed98383612e0a565b8060001904821115612eed57612eed613009565b029392505050565b6000816000190483118215151615612f0f57612f0f613009565b500290565b600061ffff83811690831681811015612f2f57612f2f613009565b039392505050565b600082821015612f4957612f49613009565b500390565b6bffffffffffffffffffffffff198135818116916014851015612f7b5780818660140360031b1b83161692505b505092915050565b60005b83811015612f9e578181015183820152602001612f86565b83811115612fad576000848401525b50505050565b600181811c90821680612fc757607f821691505b60208210811415612fe857634e487b7160e01b600052602260045260246000fd5b50919050565b600060001982141561300257613002613009565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b60008135610e1b8161318b565b60008135610e1b81613199565b8135613086816131a6565b61ffff8116905081548161ffff19821617835560208401356130a7816131a6565b63ffff00008160101b169050808363ffffffff1984161717845560408501356130cf81613176565b6001600160c01b0319929092169092179190911760209190911b640100000000600160c01b031617815561312661310860608401613061565b82805460ff60c01b191691151560c01b60ff60c01b16919091179055565b61313b6131356080840161306e565b82613149565b60a082013560018201555050565b600482106131595761315961301f565b805460ff60c81b191660c89290921b60ff60c81b16919091179055565b6001600160a01b038116811461172857600080fd5b801515811461172857600080fd5b6004811061172857600080fd5b61ffff8116811461172857600080fdfe7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa2646970667358221220a027d837b490da1a267b5f9d265801eb2ba7a5c697f983dfeceefae0e7d2981e64736f6c634300080700337bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a", - "deployedBytecode": "0x608060405234801561001057600080fd5b506004361061012c5760003560e01c806382aa1c88116100ad578063d38bfff411610071578063d38bfff414610312578063da70696c14610325578063dac4db4e14610345578063e48d7fc514610358578063ee3be5f5146103ac57600080fd5b806382aa1c881461028c578063a994317f146102c1578063b13dc20a146102d4578063b76e83af146102e7578063c7af3352146102fa57600080fd5b8063548f5ae5116100f4578063548f5ae5146101c5578063587c8440146101d85780635d36b1901461024a57806365f6fa94146102525780637cb374bd1461026557600080fd5b80630c340a24146101315780631072cbea146101565780632579153d1461016b5780632dfbe8311461017e578063430bf08a1461019e575b600080fd5b6101396103cf565b6040516001600160a01b0390911681526020015b60405180910390f35b6101696101643660046126ec565b6103ec565b005b61016961017936600461264f565b610439565b61019161018c3660046125ae565b6108c8565b60405161014d9190612b1f565b6101397f000000000000000000000000000000000000000000000000000000000000000081565b6101696101d33660046125ae565b610962565b6102386101e63660046125ae565b6000602081905290815260409020805460019091015461ffff80831692620100008104909116916001600160a01b036401000000008304169160ff600160c01b8204811692600160c81b909204169086565b60405161014d96959493929190612cb0565b6101696109dd565b610169610260366004612621565b610a83565b6101397f000000000000000000000000000000000000000000000000000000000000000081565b6102b37f000000000000000000000000000000000000000000000000000000000000000081565b60405190815260200161014d565b6101696102cf3660046125e8565b610b0a565b6101696102e23660046125ae565b610b86565b600254610139906001600160a01b031681565b610302610c25565b604051901515815260200161014d565b6101696103203660046125ae565b610c56565b6102b36103333660046125ae565b60056020526000908152604090205481565b6101396103533660046126ec565b610cfa565b61038c6103663660046125ae565b6006602052600090815260409020546001600160801b0380821691600160801b90041682565b604080516001600160801b0393841681529290911660208301520161014d565b6103026103ba3660046125ae565b60016020526000908152604090205460ff1681565b60006103e76000805160206131b78339815191525490565b905090565b6103f4610c25565b6104195760405162461bcd60e51b815260040161041090612b5f565b60405180910390fd5b6104356104246103cf565b6001600160a01b0384169083610e21565b5050565b610441610c25565b61045d5760405162461bcd60e51b815260040161041090612b5f565b6103e861046d60208501856129aa565b61ffff1611156104905760405163faa3445560e01b815260040160405180910390fd5b6103e86104a360408501602086016129aa565b61ffff1611156104c657604051631633c8cd60e31b815260040160405180910390fd5b60006104d860608501604086016125ae565b90506001600160a01b03811661050157604051637138356f60e01b815260040160405180910390fd5b6001600160a01b03808616600090815260208190526040902080546401000000009004909116908590610534828261307b565b9050507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b888879e6040518163ffffffff1660e01b815260040160206040518083038186803b15801561059057600080fd5b505afa1580156105a4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105c891906125cb565b6040516315d5220f60e31b81526001600160a01b038881166004830152919091169063aea910789060240160206040518083038186803b15801561060b57600080fd5b505afa15801561061f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061064391906129c7565b50856001600160a01b0382161580159061066f5750826001600160a01b0316826001600160a01b031614155b15610689576106896001600160a01b038216836000610e89565b826001600160a01b0316826001600160a01b0316146106cd576106b76001600160a01b038216846000610e89565b6106cd6001600160a01b03821684600019610e89565b60006106df60a0880160808901612932565b905060008160038111156106f5576106f561301f565b14156107395761070686868a610fad565b6001600160a01b0389166000908152600360209081526040909120825161073393919291909101906124a4565b50610846565b600181600381111561074d5761074d61301f565b14156107815761075e86868a6110d9565b6001600160a01b038a166000908152600460205260409020610733929091612509565b60028160038111156107955761079561301f565b14156107c5576107a78686868b6111af565b6001600160a01b038916600090815260056020526040902055610846565b60038160038111156107d9576107d961301f565b141561082b576107eb8686868b611311565b6001600160a01b0389166000908152600660209081526040909120825192909101516001600160801b03908116600160801b029216919091179055610846565b806040516336cb1d2160e01b81526004016104109190612b32565b7f5eb6073ba3980477f03b1ce0dccba754d48454bbd65a115dcd42db65ca1fefd28861087560208a018a6129aa565b61088560408b0160208c016129aa565b84888b8b8e60a001358f60600160208101906108a191906128df565b6040516108b699989796959493929190612aa0565b60405180910390a15050505050505050565b600460205260009081526040902080546108e190612fb3565b80601f016020809104026020016040519081016040528092919081815260200182805461090d90612fb3565b801561095a5780601f1061092f5761010080835404028352916020019161095a565b820191906000526020600020905b81548152906001019060200180831161093d57829003601f168201915b505050505081565b7f53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac4535805460028114156109c75760405162461bcd60e51b815260206004820152600e60248201526d1499595b9d1c985b9d0818d85b1b60921b6044820152606401610410565b600282556109d58333611500565b506001905550565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b031614610a785760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b6064820152608401610410565b610a8133611667565b565b610a8b610c25565b610aa75760405162461bcd60e51b815260040161041090612b5f565b6001600160a01b038216600081815260016020908152604091829020805460ff19168515159081179091558251938452908301527f013ed61add17cbfcbbd95bf8543da67c89658c5477d3f3199a1a2d58ecf1913f910160405180910390a15050565b7f53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac453580546002811415610b6f5760405162461bcd60e51b815260206004820152600e60248201526d1499595b9d1c985b9d0818d85b1b60921b6044820152606401610410565b60028255610b7d8484611500565b50600190555050565b610b8e610c25565b610baa5760405162461bcd60e51b815260040161041090612b5f565b6001600160a01b038116610bd157604051637138356f60e01b815260040160405180910390fd5b600280546001600160a01b0319166001600160a01b0383169081179091556040519081527f50f4ca9002119593802480c412cb5e106ae726647a31dcf8a7e7ed4e6794bf5e9060200160405180910390a150565b6000610c3d6000805160206131b78339815191525490565b6001600160a01b0316336001600160a01b031614905090565b610c5e610c25565b610c7a5760405162461bcd60e51b815260040161041090612b5f565b610ca2817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b0316610cc26000805160206131b78339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b60036020528160005260406000208181548110610d1657600080fd5b6000918252602090912001546001600160a01b03169150829050565b600080826001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b158015610d6e57600080fd5b505afa158015610d82573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610da69190612a21565b60ff16905060048110158015610dbd575060128111155b610e1b5760405162461bcd60e51b815260206004820152602960248201527f546f6b656e206d75737420686176652073756666696369656e7420646563696d604482015268616c20706c6163657360b81b6064820152608401610410565b92915050565b6040516001600160a01b038316602482015260448101829052610e8490849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915261172b565b505050565b801580610f125750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e9060440160206040518083038186803b158015610ed857600080fd5b505afa158015610eec573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f1091906129c7565b155b610f7d5760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b6064820152608401610410565b6040516001600160a01b038316602482015260448101829052610e8490849063095ea7b360e01b90606401610e4d565b6060610fbb83850185612718565b80519091506002811015610fe2576040516360fa33db60e11b815260040160405180910390fd5b826001600160a01b031682600081518110610fff57610fff613035565b60200260200101516001600160a01b031614611059578160008151811061102857611028613035565b602002602001015160405163280d94a560e21b815260040161041091906001600160a01b0391909116815260200190565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168261108f600184612f37565b8151811061109f5761109f613035565b60200260200101516001600160a01b0316146110d157816110c1600183612f37565b8151811061102857611028613035565b509392505050565b828260006110ea6014828486612dbe565b6110f391612f4e565b60601c90506001600160a01b038416811461112c5760405163280d94a560e21b81526001600160a01b0382166004820152602401610410565b8585611139601485612f37565b611144928290612dbe565b61114d91612f4e565b60601c90506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001681146111a65760405163280d94a560e21b81526001600160a01b0382166004820152602401610410565b50935093915050565b60006111bd84860186612919565b9050806111dd57604051634bdc2c9560e01b815260040160405180910390fd5b60405163160bf1c960e31b8152600481018290526001600160a01b03838116602483015284919082169063b05f8e489060440160806040518083038186803b15801561122857600080fd5b505afa15801561123c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061126091906129e0565b505060405163160bf1c960e31b8152600481018590526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660248301528416925063b05f8e48915060440160806040518083038186803b1580156112cc57600080fd5b505afa1580156112e0573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061130491906129e0565b5050505050949350505050565b60408051808201909152600080825260208201526113318486018661294f565b805160405163c661065760e01b81526001600160801b03909116600482015290915083906001600160a01b0382169063c66106579060240160206040518083038186803b15801561138157600080fd5b505afa158015611395573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113b991906125cb565b6001600160a01b0316836001600160a01b0316146113f55760405163d658230160e01b81526001600160a01b0384166004820152602401610410565b602082015160405163c661065760e01b81526001600160801b0390911660048201526001600160a01b0382169063c66106579060240160206040518083038186803b15801561144357600080fd5b505afa158015611457573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061147b91906125cb565b6001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316146114f75760405163d658230160e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166004820152602401610410565b50949350505050565b611509826117fd565b60008290506000816001600160a01b031663f6ca71b06040518163ffffffff1660e01b815260040160006040518083038186803b15801561154957600080fd5b505afa15801561155d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261158591908101906127be565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b888879e6040518163ffffffff1660e01b815260040160206040518083038186803b1580156115e257600080fd5b505afa1580156115f6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061161a91906125cb565b825190915060005b8181101561165e5761164e84828151811061163f5761163f613035565b6020026020010151878561189d565b61165781612fee565b9050611622565b50505050505050565b6001600160a01b0381166116bd5760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f7220697320616464726573732830290000000000006044820152606401610410565b806001600160a01b03166116dd6000805160206131b78339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a3611728816000805160206131b783398151915255565b50565b6000611780826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611d489092919063ffffffff16565b805190915015610e84578080602001905181019061179e91906128fc565b610e845760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610410565b6001600160a01b03811660009081526001602052604090205460ff1661184157604051630211444960e11b81526001600160a01b0382166004820152602401610410565b6000819050806001600160a01b0316635a063f636040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561188157600080fd5b505af1158015611895573d6000803e3d6000fd5b505050505050565b6001600160a01b03808416600090815260208181526040808320815160c081018352815461ffff8082168352620100008204169482019490945264010000000084049095169185019190915260ff600160c01b830481161515606086015292939290916080840191600160c81b90910416600381111561191f5761191f61301f565b60038111156119305761193061301f565b81526020016001820154815250509050806060015161194f5750505050565b6040516370a0823160e01b81523060048201526000906001600160a01b038616906370a082319060240160206040518083038186803b15801561199157600080fd5b505afa1580156119a5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119c991906129c7565b9050806119d7575050505050565b60a0820151156119f2576119ef818360a00151611d61565b90505b6040516315d5220f60e31b81526001600160a01b0386811660048301526000919085169063aea910789060240160206040518083038186803b158015611a3757600080fd5b505afa158015611a4b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a6f91906129c7565b90506000670de0b6b3a7640000612710611adb7f0000000000000000000000000000000000000000000000000000000000000000611aac8b610d32565b88518790611abc90612710612f14565b611aca9061ffff168a612ef5565b611ad49190612ef5565b9190611d77565b611ae59190612de8565b611aef9190612de8565b90506000611b08856080015186604001518a8786611dd9565b905081811015611b35576040516302d96fff60e41b81526004810182905260248101839052604401610410565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316886001600160a01b03167fa861903141bc68b536d5048a576afcc645630e1b18a4296ef34cbd4d1407f70987608001518785604051611ba093929190612b40565b60405180910390a36040516370a0823160e01b81523060048201527f0000000000000000000000000000000000000000000000000000000000000000906000906001600160a01b038316906370a082319060240160206040518083038186803b158015611c0c57600080fd5b505afa158015611c20573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c4491906129c7565b905082811015611c715760405163315d50df60e11b81526004810182905260248101849052604401610410565b6020870151600090611c8b90859061ffff16612710611e9d565b90506000611c998284612f37565b600254909150611cb6906001600160a01b03868116911683610e21565b611cca6001600160a01b0385168c84610e21565b604080516001600160a01b038d81168252602082018490529181018490527f0000000000000000000000000000000000000000000000000000000000000000909116907f42e60aae8f000883c46e2f449fa76268e374ce1b962f46ca9360ab98b18f57999060600160405180910390a2505050505050505050505050565b6060611d578484600085611eb6565b90505b9392505050565b6000818310611d705781611d5a565b5090919050565b600081831115611da757611da0611d8e8385612f37565b611d9990600a612e4d565b8590611fde565b9350611dd1565b81831015611dd157611dce611dbc8484612f37565b611dc790600a612e4d565b8590611fea565b93505b509192915050565b600080866003811115611dee57611dee61301f565b1415611e0757611e0085858585611ff6565b9050611e94565b6001866003811115611e1b57611e1b61301f565b1415611e2d57611e0085858585612125565b6002866003811115611e4157611e4161301f565b1415611e5357611e0085858585612270565b6003866003811115611e6757611e6761301f565b1415611e7957611e0085858585612392565b856040516336cb1d2160e01b81526004016104109190612b32565b95945050505050565b600080611eaa8585611fde565b9050611e948184611fea565b606082471015611f175760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610410565b843b611f655760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610410565b600080866001600160a01b03168587604051611f819190612a84565b60006040518083038185875af1925050503d8060008114611fbe576040519150601f19603f3d011682016040523d82523d6000602084013e611fc3565b606091505b5091509150611fd382828661246b565b979650505050505050565b6000611d5a8284612ef5565b6000611d5a8284612de8565b6001600160a01b03831660009081526003602090815260408083208054825181850281018501909352808352849383018282801561205d57602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161203f575b505050505090506000866001600160a01b03166338ed173986868530426040518663ffffffff1660e01b815260040161209a959493929190612cf8565b600060405180830381600087803b1580156120b457600080fd5b505af11580156120c8573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526120f09190810190612853565b905080600182516121019190612f37565b8151811061211157612111613035565b602002602001015192505050949350505050565b6001600160a01b0383166000908152600460205260408120805482919061214b90612fb3565b80601f016020809104026020016040519081016040528092919081815260200182805461217790612fb3565b80156121c45780601f10612199576101008083540402835291602001916121c4565b820191906000526020600020905b8154815290600101906020018083116121a757829003601f168201915b50506040805160a0810182528581523060208201524281830152606081018a905260808101899052905163c04b8d5960e01b8152949550936001600160a01b038b16935063c04b8d59925061221e91508490600401612b96565b602060405180830381600087803b15801561223857600080fd5b505af115801561224c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fd391906129c7565b6001600160a01b03838116600081815260056020908152604080832054815160c081018352818152808401859052808301959095527f0000000000000000000000000000000000000000000000000000000000000000861660608087019190915260808087018a90528351808601855286815260a0880152835190810184523080825294810186905280840194909452830184905290516352bbbe2960e01b81529294909392908916906352bbbe299061233490859085908a904290600401612bee565b602060405180830381600087803b15801561234e57600080fd5b505af1158015612362573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061238691906129c7565b98975050505050505050565b6001600160a01b0383811660009081526006602090815260408083208151808301835290546001600160801b03808216808452600160801b909204169382018490529151630b68372160e31b81526004810192909252602482019290925260448101869052606481018590529192909190871690635b41b90890608401602060405180830381600087803b15801561242957600080fd5b505af115801561243d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061246191906129c7565b9695505050505050565b6060831561247a575081611d5a565b82511561248a5782518084602001fd5b8160405162461bcd60e51b81526004016104109190612b1f565b8280548282559060005260206000209081019282156124f9579160200282015b828111156124f957825182546001600160a01b0319166001600160a01b039091161782556020909201916001909101906124c4565b5061250592915061257d565b5090565b82805461251590612fb3565b90600052602060002090601f01602090048101928261253757600085556124f9565b82601f106125505782800160ff198235161785556124f9565b828001600101855582156124f9579182015b828111156124f9578235825591602001919060010190612562565b5b80821115612505576000815560010161257e565b80356001600160801b03811681146125a957600080fd5b919050565b6000602082840312156125c057600080fd5b8135611d5a81613176565b6000602082840312156125dd57600080fd5b8151611d5a81613176565b600080604083850312156125fb57600080fd5b823561260681613176565b9150602083013561261681613176565b809150509250929050565b6000806040838503121561263457600080fd5b823561263f81613176565b915060208301356126168161318b565b60008060008084860361010081121561266757600080fd5b853561267281613176565b945060c0601f198201121561268657600080fd5b5060208501925060e085013567ffffffffffffffff808211156126a857600080fd5b818701915087601f8301126126bc57600080fd5b8135818111156126cb57600080fd5b8860208285010111156126dd57600080fd5b95989497505060200194505050565b600080604083850312156126ff57600080fd5b823561270a81613176565b946020939093013593505050565b6000602080838503121561272b57600080fd5b823567ffffffffffffffff81111561274257600080fd5b8301601f8101851361275357600080fd5b803561276661276182612d9a565b612d69565b80828252848201915084840188868560051b870101111561278657600080fd5b600094505b838510156127b257803561279e81613176565b83526001949094019391850191850161278b565b50979650505050505050565b600060208083850312156127d157600080fd5b825167ffffffffffffffff8111156127e857600080fd5b8301601f810185136127f957600080fd5b805161280761276182612d9a565b80828252848201915084840188868560051b870101111561282757600080fd5b600094505b838510156127b257805161283f81613176565b83526001949094019391850191850161282c565b6000602080838503121561286657600080fd5b825167ffffffffffffffff81111561287d57600080fd5b8301601f8101851361288e57600080fd5b805161289c61276182612d9a565b80828252848201915084840188868560051b87010111156128bc57600080fd5b600094505b838510156127b25780518352600194909401939185019185016128c1565b6000602082840312156128f157600080fd5b8135611d5a8161318b565b60006020828403121561290e57600080fd5b8151611d5a8161318b565b60006020828403121561292b57600080fd5b5035919050565b60006020828403121561294457600080fd5b8135611d5a81613199565b60006040828403121561296157600080fd5b6040516040810181811067ffffffffffffffff821117156129845761298461304b565b60405261299083612592565b815261299e60208401612592565b60208201529392505050565b6000602082840312156129bc57600080fd5b8135611d5a816131a6565b6000602082840312156129d957600080fd5b5051919050565b600080600080608085870312156129f657600080fd5b8451935060208501519250604085015191506060850151612a1681613176565b939692955090935050565b600060208284031215612a3357600080fd5b815160ff81168114611d5a57600080fd5b60008151808452612a5c816020860160208601612f83565b601f01601f19169290920160200192915050565b60048110612a8057612a8061301f565b9052565b60008251612a96818460208701612f83565b9190910192915050565b6001600160a01b038a8116825261ffff8a811660208401528916604083015260009061010090612ad3606085018b612a70565b8816608084015260a083018190528201859052610120858782850137600083870182015260c08301949094525090151560e0820152601f909201601f1916909101019695505050505050565b602081526000611d5a6020830184612a44565b60208101610e1b8284612a70565b60608101612b4e8286612a70565b602082019390935260400152919050565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b602081526000825160a06020840152612bb260c0840182612a44565b905060018060a01b0360208501511660408401526040840151606084015260608401516080840152608084015160a08401528091505092915050565b60e08152845160e08201526000602086015160028110612c1057612c1061301f565b61010083015260408601516001600160a01b03908116610120840152606087015116610140830152608086015161016083015260a086015160c0610180840152612c5e6101a0840182612a44565b915050612c9e602083018680516001600160a01b039081168352602080830151151590840152604080830151909116908301526060908101511515910152565b60a082019390935260c0015292915050565b61ffff8781168252861660208201526001600160a01b0385166040820152831515606082015260c08101612ce76080830185612a70565b8260a0830152979650505050505050565b600060a082018783526020878185015260a0604085015281875180845260c086019150828901935060005b81811015612d485784516001600160a01b031683529383019391830191600101612d23565b50506001600160a01b03969096166060850152505050608001529392505050565b604051601f8201601f1916810167ffffffffffffffff81118282101715612d9257612d9261304b565b604052919050565b600067ffffffffffffffff821115612db457612db461304b565b5060051b60200190565b60008085851115612dce57600080fd5b83861115612ddb57600080fd5b5050820193919092039150565b600082612e0557634e487b7160e01b600052601260045260246000fd5b500490565b600181815b80851115612e45578160001904821115612e2b57612e2b613009565b80851615612e3857918102915b93841c9390800290612e0f565b509250929050565b6000611d5a8383600082612e6357506001610e1b565b81612e7057506000610e1b565b8160018114612e865760028114612e9057612eac565b6001915050610e1b565b60ff841115612ea157612ea1613009565b50506001821b610e1b565b5060208310610133831016604e8410600b8410161715612ecf575081810a610e1b565b612ed98383612e0a565b8060001904821115612eed57612eed613009565b029392505050565b6000816000190483118215151615612f0f57612f0f613009565b500290565b600061ffff83811690831681811015612f2f57612f2f613009565b039392505050565b600082821015612f4957612f49613009565b500390565b6bffffffffffffffffffffffff198135818116916014851015612f7b5780818660140360031b1b83161692505b505092915050565b60005b83811015612f9e578181015183820152602001612f86565b83811115612fad576000848401525b50505050565b600181811c90821680612fc757607f821691505b60208210811415612fe857634e487b7160e01b600052602260045260246000fd5b50919050565b600060001982141561300257613002613009565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b60008135610e1b8161318b565b60008135610e1b81613199565b8135613086816131a6565b61ffff8116905081548161ffff19821617835560208401356130a7816131a6565b63ffff00008160101b169050808363ffffffff1984161717845560408501356130cf81613176565b6001600160c01b0319929092169092179190911760209190911b640100000000600160c01b031617815561312661310860608401613061565b82805460ff60c01b191691151560c01b60ff60c01b16919091179055565b61313b6131356080840161306e565b82613149565b60a082013560018201555050565b600482106131595761315961301f565b805460ff60c81b191660c89290921b60ff60c81b16919091179055565b6001600160a01b038116811461172857600080fd5b801515811461172857600080fd5b6004811061172857600080fd5b61ffff8116811461172857600080fdfe7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa2646970667358221220a027d837b490da1a267b5f9d265801eb2ba7a5c697f983dfeceefae0e7d2981e64736f6c63430008070033", + "numDeployments": 2, + "solcInputHash": "66dbdc9fbde8f1c7cc59f29d272eb661", + "metadata": "{\"compiler\":{\"version\":\"0.8.7+commit.e28d00a7\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_vault\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_wethAddress\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"actualBalance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"minExpected\",\"type\":\"uint256\"}],\"name\":\"BalanceMismatchAfterSwap\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"EmptyAddress\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"EmptyBalancerPoolId\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"InvalidCurvePoolAssetIndex\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidHarvestRewardBps\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSlippageBps\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"enum BaseHarvester.SwapPlatform\",\"name\":\"swapPlatform\",\"type\":\"uint8\"}],\"name\":\"InvalidSwapPlatform\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"InvalidTokenInSwapPath\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidUniswapV2PathLength\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"actualBalance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"minExpected\",\"type\":\"uint256\"}],\"name\":\"SlippageError\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"strategyAddress\",\"type\":\"address\"}],\"name\":\"UnsupportedStrategy\",\"type\":\"error\"},{\"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\":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\":\"newProceedsAddress\",\"type\":\"address\"}],\"name\":\"RewardProceedsAddressChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"farmer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"protcolYield\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"farmerFee\",\"type\":\"uint256\"}],\"name\":\"RewardProceedsTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"tokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"allowedSlippageBps\",\"type\":\"uint16\"},{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"harvestRewardBps\",\"type\":\"uint16\"},{\"indexed\":false,\"internalType\":\"enum BaseHarvester.SwapPlatform\",\"name\":\"swapPlatform\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"swapPlatformAddr\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"swapData\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"liquidationLimit\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"doSwapRewardToken\",\"type\":\"bool\"}],\"name\":\"RewardTokenConfigUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"rewardToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"swappedInto\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"enum BaseHarvester.SwapPlatform\",\"name\":\"swapPlatform\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountIn\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountOut\",\"type\":\"uint256\"}],\"name\":\"RewardTokenSwapped\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"strategyAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"isSupported\",\"type\":\"bool\"}],\"name\":\"SupportedStrategyUpdate\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"balancerPoolId\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"baseTokenAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"baseTokenDecimals\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"claimGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"curvePoolIndices\",\"outputs\":[{\"internalType\":\"uint128\",\"name\":\"rewardTokenIndex\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"baseTokenIndex\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"governor\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_strategyAddr\",\"type\":\"address\"}],\"name\":\"harvestAndSwap\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_strategyAddr\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_rewardTo\",\"type\":\"address\"}],\"name\":\"harvestAndSwap\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isGovernor\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rewardProceedsAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"rewardTokenConfigs\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"allowedSlippageBps\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"harvestRewardBps\",\"type\":\"uint16\"},{\"internalType\":\"address\",\"name\":\"swapPlatformAddr\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"doSwapRewardToken\",\"type\":\"bool\"},{\"internalType\":\"enum BaseHarvester.SwapPlatform\",\"name\":\"swapPlatform\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"liquidationLimit\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_rewardProceedsAddress\",\"type\":\"address\"}],\"name\":\"setRewardProceedsAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_tokenAddress\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint16\",\"name\":\"allowedSlippageBps\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"harvestRewardBps\",\"type\":\"uint16\"},{\"internalType\":\"address\",\"name\":\"swapPlatformAddr\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"doSwapRewardToken\",\"type\":\"bool\"},{\"internalType\":\"enum BaseHarvester.SwapPlatform\",\"name\":\"swapPlatform\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"liquidationLimit\",\"type\":\"uint256\"}],\"internalType\":\"struct BaseHarvester.RewardTokenConfig\",\"name\":\"tokenConfig\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"swapData\",\"type\":\"bytes\"}],\"name\":\"setRewardTokenConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_strategyAddress\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"_isSupported\",\"type\":\"bool\"}],\"name\":\"setSupportedStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"supportedStrategies\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"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\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"uniswapV2Path\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"uniswapV3Path\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"vaultAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"harvestAndSwap(address)\":{\"details\":\"Collect reward tokens from a specific strategy and swap them for base token on the configured swap platform. Can be called by anyone. Rewards incentivizing the caller are sent to the caller of this function.\",\"params\":{\"_strategyAddr\":\"Address of the strategy to collect rewards from\"}},\"harvestAndSwap(address,address)\":{\"details\":\"Collect reward tokens from a specific strategy and swap them for base token on the configured swap platform. Can be called by anyone\",\"params\":{\"_rewardTo\":\"Address where to send a share of harvest rewards to as an incentive for executing this function\",\"_strategyAddr\":\"Address of the strategy to collect rewards from\"}},\"setRewardProceedsAddress(address)\":{\"params\":{\"_rewardProceedsAddress\":\"Address of the reward token\"}},\"setRewardTokenConfig(address,(uint16,uint16,address,bool,uint8,uint256),bytes)\":{\"details\":\"Add/update a reward token configuration that holds harvesting config variables\",\"params\":{\"_tokenAddress\":\"Address of the reward token\",\"swapData\":\"Additional data required for swapping\",\"tokenConfig\":\".swapPlatform SwapPlatform to use for Swapping\"}},\"setSupportedStrategy(address,bool)\":{\"details\":\"Flags a strategy as supported or not supported one\",\"params\":{\"_isSupported\":\"Bool marking strategy as supported or not supported\",\"_strategyAddress\":\"Address of the strategy\"}},\"transferGovernance(address)\":{\"params\":{\"_newGovernor\":\"Address of the new Governor\"}},\"transferToken(address,uint256)\":{\"details\":\"Transfer token to governor. Intended for recovering tokens stuck in contract, i.e. mistaken sends.\",\"params\":{\"_amount\":\"Amount of the asset to transfer\",\"_asset\":\"Address for the asset\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"baseTokenAddress()\":{\"notice\":\"All tokens are swapped to this token before it gets transferred to the `rewardProceedsAddress`. USDT for OUSD and WETH for OETH.*\"},\"claimGovernance()\":{\"notice\":\"Claim Governance of the contract to a new account (`newGovernor`). Can only be called by the new Governor.\"},\"governor()\":{\"notice\":\"Returns the address of the current Governor.\"},\"isGovernor()\":{\"notice\":\"Returns true if the caller is the current Governor.\"},\"rewardProceedsAddress()\":{\"notice\":\"Address receiving rewards proceeds. Initially the Vault contract later will possibly be replaced by another contract that eases out rewards distribution.*\"},\"setRewardProceedsAddress(address)\":{\"notice\":\"Set the Address receiving rewards proceeds.\"},\"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\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/harvest/OETHHarvester.sol\":\"OETHHarvester\"},\"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/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\",\"keccak256\":\"0xfaad496c1c944b6259b7dc70b4865eb1775d6402bc0c81b38a0b24d9f525ae37\",\"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/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 transfering `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\",\"keccak256\":\"0x9d6a3756c5f35f48cb9e16dbeff2cd6f3024ef0c4e0be385cc230b47b5745c9a\",\"license\":\"MIT\"},\"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\",\"keccak256\":\"0x67255aabc4a8ec5d6650b3ab1daedffa093d8f6c324ee92281581c05990098bc\",\"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/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/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\",\"keccak256\":\"0x597796f9c5b3d174acbec8b520c633695c10d87762f7a0a7fec49b291694d7de\",\"license\":\"MIT\"},\"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\",\"keccak256\":\"0x3fdf2b91880f2b669202cc43bdceaf9d01537a9b955fc7a51159fb04fdbc68d4\",\"license\":\"MIT\"},\"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\",\"keccak256\":\"0xe32b76d23705979a297b164718aefa6b08e0ec3830883c020a5ac68d332a1dd2\",\"license\":\"MIT\"},\"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\",\"keccak256\":\"0x65e40829ff1f51c6c64fe991ed6a536b413ced85b9d9aa852d37fa14966d474c\",\"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/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\",\"keccak256\":\"0x5e17bb3db9f9e1014b7c5c836547f8fa81e02af7568c0bb8f2a2e0e7c2192db4\",\"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/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": "0x60e06040523480156200001157600080fd5b506040516200360438038062003604833981016040819052620000349162000215565b81816200004e33600080516020620035e483398151915255565b600080516020620035e4833981519152546040516001600160a01b03909116906000907fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a908290a36001600160a01b038216620000aa57600080fd5b6001600160a01b038116620000be57600080fd5b606082811b6001600160601b03199081166080529082901b1660a052620000f181620000ff602090811b62000d3217901c565b60c052506200027992505050565b600080826001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b1580156200013c57600080fd5b505afa15801562000151573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200017791906200024d565b60ff169050600481101580156200018f575060128111155b620001f25760405162461bcd60e51b815260206004820152602960248201527f546f6b656e206d75737420686176652073756666696369656e7420646563696d604482015268616c20706c6163657360b81b606482015260840160405180910390fd5b92915050565b80516001600160a01b03811681146200021057600080fd5b919050565b600080604083850312156200022957600080fd5b6200023483620001f8565b91506200024460208401620001f8565b90509250929050565b6000602082840312156200026057600080fd5b815160ff811681146200027257600080fd5b9392505050565b60805160601c60a05160601c60c0516132d362000311600039600081816102910152611b4b01526000818161026a015281816110630152818161115c0152818161128001528181611486015281816114ca0152818161191b0152818161198501528181611bfe01528181611c8401528181611db1015261236e0152600081816101a301528181610539015261158b01526132d36000f3fe608060405234801561001057600080fd5b506004361061012c5760003560e01c806382aa1c88116100ad578063d38bfff411610071578063d38bfff414610312578063da70696c14610325578063dac4db4e14610345578063e48d7fc514610358578063ee3be5f5146103ac57600080fd5b806382aa1c881461028c578063a994317f146102c1578063b13dc20a146102d4578063b76e83af146102e7578063c7af3352146102fa57600080fd5b8063548f5ae5116100f4578063548f5ae5146101c5578063587c8440146101d85780635d36b1901461024a57806365f6fa94146102525780637cb374bd1461026557600080fd5b80630c340a24146101315780631072cbea146101565780632579153d1461016b5780632dfbe8311461017e578063430bf08a1461019e575b600080fd5b6101396103cf565b6040516001600160a01b0390911681526020015b60405180910390f35b6101696101643660046127b3565b6103ec565b005b610169610179366004612716565b610439565b61019161018c366004612675565b6108c8565b60405161014d9190612be6565b6101397f000000000000000000000000000000000000000000000000000000000000000081565b6101696101d3366004612675565b610962565b6102386101e6366004612675565b6000602081905290815260409020805460019091015461ffff80831692620100008104909116916001600160a01b036401000000008304169160ff600160c01b8204811692600160c81b909204169086565b60405161014d96959493929190612d77565b6101696109dd565b6101696102603660046126e8565b610a83565b6101397f000000000000000000000000000000000000000000000000000000000000000081565b6102b37f000000000000000000000000000000000000000000000000000000000000000081565b60405190815260200161014d565b6101696102cf3660046126af565b610b0a565b6101696102e2366004612675565b610b86565b600254610139906001600160a01b031681565b610302610c25565b604051901515815260200161014d565b610169610320366004612675565b610c56565b6102b3610333366004612675565b60056020526000908152604090205481565b6101396103533660046127b3565b610cfa565b61038c610366366004612675565b6006602052600090815260409020546001600160801b0380821691600160801b90041682565b604080516001600160801b0393841681529290911660208301520161014d565b6103026103ba366004612675565b60016020526000908152604090205460ff1681565b60006103e760008051602061327e8339815191525490565b905090565b6103f4610c25565b6104195760405162461bcd60e51b815260040161041090612c26565b60405180910390fd5b6104356104246103cf565b6001600160a01b0384169083610e21565b5050565b610441610c25565b61045d5760405162461bcd60e51b815260040161041090612c26565b6103e861046d6020850185612a71565b61ffff1611156104905760405163faa3445560e01b815260040160405180910390fd5b6103e86104a36040850160208601612a71565b61ffff1611156104c657604051631633c8cd60e31b815260040160405180910390fd5b60006104d86060850160408601612675565b90506001600160a01b03811661050157604051637138356f60e01b815260040160405180910390fd5b6001600160a01b038086166000908152602081905260409020805464010000000090049091169085906105348282613142565b9050507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b888879e6040518163ffffffff1660e01b815260040160206040518083038186803b15801561059057600080fd5b505afa1580156105a4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105c89190612692565b6040516315d5220f60e31b81526001600160a01b038881166004830152919091169063aea910789060240160206040518083038186803b15801561060b57600080fd5b505afa15801561061f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106439190612a8e565b50856001600160a01b0382161580159061066f5750826001600160a01b0316826001600160a01b031614155b15610689576106896001600160a01b038216836000610e89565b826001600160a01b0316826001600160a01b0316146106cd576106b76001600160a01b038216846000610e89565b6106cd6001600160a01b03821684600019610e89565b60006106df60a08801608089016129f9565b905060008160038111156106f5576106f56130e6565b14156107395761070686868a610fad565b6001600160a01b03891660009081526003602090815260409091208251610733939192919091019061256b565b50610846565b600181600381111561074d5761074d6130e6565b14156107815761075e86868a6110d9565b6001600160a01b038a1660009081526004602052604090206107339290916125d0565b6002816003811115610795576107956130e6565b14156107c5576107a78686868b6111af565b6001600160a01b038916600090815260056020526040902055610846565b60038160038111156107d9576107d96130e6565b141561082b576107eb8686868b611311565b6001600160a01b0389166000908152600660209081526040909120825192909101516001600160801b03908116600160801b029216919091179055610846565b806040516336cb1d2160e01b81526004016104109190612bf9565b7f5eb6073ba3980477f03b1ce0dccba754d48454bbd65a115dcd42db65ca1fefd28861087560208a018a612a71565b61088560408b0160208c01612a71565b84888b8b8e60a001358f60600160208101906108a191906129a6565b6040516108b699989796959493929190612b67565b60405180910390a15050505050505050565b600460205260009081526040902080546108e19061307a565b80601f016020809104026020016040519081016040528092919081815260200182805461090d9061307a565b801561095a5780601f1061092f5761010080835404028352916020019161095a565b820191906000526020600020905b81548152906001019060200180831161093d57829003601f168201915b505050505081565b7f53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac4535805460028114156109c75760405162461bcd60e51b815260206004820152600e60248201526d1499595b9d1c985b9d0818d85b1b60921b6044820152606401610410565b600282556109d58333611500565b506001905550565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b031614610a785760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b6064820152608401610410565b610a8133611667565b565b610a8b610c25565b610aa75760405162461bcd60e51b815260040161041090612c26565b6001600160a01b038216600081815260016020908152604091829020805460ff19168515159081179091558251938452908301527f013ed61add17cbfcbbd95bf8543da67c89658c5477d3f3199a1a2d58ecf1913f910160405180910390a15050565b7f53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac453580546002811415610b6f5760405162461bcd60e51b815260206004820152600e60248201526d1499595b9d1c985b9d0818d85b1b60921b6044820152606401610410565b60028255610b7d8484611500565b50600190555050565b610b8e610c25565b610baa5760405162461bcd60e51b815260040161041090612c26565b6001600160a01b038116610bd157604051637138356f60e01b815260040160405180910390fd5b600280546001600160a01b0319166001600160a01b0383169081179091556040519081527f50f4ca9002119593802480c412cb5e106ae726647a31dcf8a7e7ed4e6794bf5e9060200160405180910390a150565b6000610c3d60008051602061327e8339815191525490565b6001600160a01b0316336001600160a01b031614905090565b610c5e610c25565b610c7a5760405162461bcd60e51b815260040161041090612c26565b610ca2817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b0316610cc260008051602061327e8339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b60036020528160005260406000208181548110610d1657600080fd5b6000918252602090912001546001600160a01b03169150829050565b600080826001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b158015610d6e57600080fd5b505afa158015610d82573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610da69190612ae8565b60ff16905060048110158015610dbd575060128111155b610e1b5760405162461bcd60e51b815260206004820152602960248201527f546f6b656e206d75737420686176652073756666696369656e7420646563696d604482015268616c20706c6163657360b81b6064820152608401610410565b92915050565b6040516001600160a01b038316602482015260448101829052610e8490849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915261172b565b505050565b801580610f125750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e9060440160206040518083038186803b158015610ed857600080fd5b505afa158015610eec573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f109190612a8e565b155b610f7d5760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b6064820152608401610410565b6040516001600160a01b038316602482015260448101829052610e8490849063095ea7b360e01b90606401610e4d565b6060610fbb838501856127df565b80519091506002811015610fe2576040516360fa33db60e11b815260040160405180910390fd5b826001600160a01b031682600081518110610fff57610fff6130fc565b60200260200101516001600160a01b0316146110595781600081518110611028576110286130fc565b602002602001015160405163280d94a560e21b815260040161041091906001600160a01b0391909116815260200190565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168261108f600184612ffe565b8151811061109f5761109f6130fc565b60200260200101516001600160a01b0316146110d157816110c1600183612ffe565b81518110611028576110286130fc565b509392505050565b828260006110ea6014828486612e85565b6110f391613015565b60601c90506001600160a01b038416811461112c5760405163280d94a560e21b81526001600160a01b0382166004820152602401610410565b8585611139601485612ffe565b611144928290612e85565b61114d91613015565b60601c90506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001681146111a65760405163280d94a560e21b81526001600160a01b0382166004820152602401610410565b50935093915050565b60006111bd848601866129e0565b9050806111dd57604051634bdc2c9560e01b815260040160405180910390fd5b60405163160bf1c960e31b8152600481018290526001600160a01b03838116602483015284919082169063b05f8e489060440160806040518083038186803b15801561122857600080fd5b505afa15801561123c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112609190612aa7565b505060405163160bf1c960e31b8152600481018590526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660248301528416925063b05f8e48915060440160806040518083038186803b1580156112cc57600080fd5b505afa1580156112e0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113049190612aa7565b5050505050949350505050565b604080518082019091526000808252602082015261133184860186612a16565b805160405163c661065760e01b81526001600160801b03909116600482015290915083906001600160a01b0382169063c66106579060240160206040518083038186803b15801561138157600080fd5b505afa158015611395573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113b99190612692565b6001600160a01b0316836001600160a01b0316146113f55760405163d658230160e01b81526001600160a01b0384166004820152602401610410565b602082015160405163c661065760e01b81526001600160801b0390911660048201526001600160a01b0382169063c66106579060240160206040518083038186803b15801561144357600080fd5b505afa158015611457573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061147b9190612692565b6001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316146114f75760405163d658230160e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166004820152602401610410565b50949350505050565b611509826117fd565b60008290506000816001600160a01b031663f6ca71b06040518163ffffffff1660e01b815260040160006040518083038186803b15801561154957600080fd5b505afa15801561155d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526115859190810190612885565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b888879e6040518163ffffffff1660e01b815260040160206040518083038186803b1580156115e257600080fd5b505afa1580156115f6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061161a9190612692565b825190915060005b8181101561165e5761164e84828151811061163f5761163f6130fc565b6020026020010151878561189d565b611657816130b5565b9050611622565b50505050505050565b6001600160a01b0381166116bd5760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f7220697320616464726573732830290000000000006044820152606401610410565b806001600160a01b03166116dd60008051602061327e8339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a36117288160008051602061327e83398151915255565b50565b6000611780826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611e0f9092919063ffffffff16565b805190915015610e84578080602001905181019061179e91906129c3565b610e845760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610410565b6001600160a01b03811660009081526001602052604090205460ff1661184157604051630211444960e11b81526001600160a01b0382166004820152602401610410565b6000819050806001600160a01b0316635a063f636040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561188157600080fd5b505af1158015611895573d6000803e3d6000fd5b505050505050565b6040516370a0823160e01b81523060048201526000906001600160a01b038516906370a082319060240160206040518083038186803b1580156118df57600080fd5b505afa1580156118f3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119179190612a8e565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316846001600160a01b031614156119df5760025461196d906001600160a01b03868116911683610e21565b604080516000808252602082018490528183015290517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316917f42e60aae8f000883c46e2f449fa76268e374ce1b962f46ca9360ab98b18f5799919081900360600190a250505050565b6001600160a01b03808516600090815260208181526040808320815160c081018352815461ffff8082168352620100008204169482019490945264010000000084049095169185019190915260ff600160c01b830481161515606086015292939290916080840191600160c81b909104166003811115611a6157611a616130e6565b6003811115611a7257611a726130e6565b815260200160018201548152505090508060600151611a92575050505050565b81611a9e575050505050565b60a081015115611ab957611ab6828260a00151611e28565b91505b6040516315d5220f60e31b81526001600160a01b0386811660048301526000919085169063aea910789060240160206040518083038186803b158015611afe57600080fd5b505afa158015611b12573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b369190612a8e565b90506000670de0b6b3a7640000612710611ba27f0000000000000000000000000000000000000000000000000000000000000000611b738b610d32565b87518790611b8390612710612fdb565b611b919061ffff168b612fbc565b611b9b9190612fbc565b9190611e3e565b611bac9190612eaf565b611bb69190612eaf565b90506000611bcf846080015185604001518a8886611ea0565b905081811015611bfc576040516302d96fff60e41b81526004810182905260248101839052604401610410565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316886001600160a01b03167fa861903141bc68b536d5048a576afcc645630e1b18a4296ef34cbd4d1407f70986608001518885604051611c6793929190612c07565b60405180910390a36040516370a0823160e01b81523060048201527f0000000000000000000000000000000000000000000000000000000000000000906000906001600160a01b038316906370a082319060240160206040518083038186803b158015611cd357600080fd5b505afa158015611ce7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d0b9190612a8e565b905082811015611d385760405163315d50df60e11b81526004810182905260248101849052604401610410565b6020860151600090611d5290859061ffff16612710611f64565b90506000611d608284612ffe565b600254909150611d7d906001600160a01b03868116911683610e21565b611d916001600160a01b0385168c84610e21565b604080516001600160a01b038d81168252602082018490529181018490527f0000000000000000000000000000000000000000000000000000000000000000909116907f42e60aae8f000883c46e2f449fa76268e374ce1b962f46ca9360ab98b18f57999060600160405180910390a2505050505050505050505050565b6060611e1e8484600085611f7d565b90505b9392505050565b6000818310611e375781611e21565b5090919050565b600081831115611e6e57611e67611e558385612ffe565b611e6090600a612f14565b85906120a5565b9350611e98565b81831015611e9857611e95611e838484612ffe565b611e8e90600a612f14565b85906120b1565b93505b509192915050565b600080866003811115611eb557611eb56130e6565b1415611ece57611ec7858585856120bd565b9050611f5b565b6001866003811115611ee257611ee26130e6565b1415611ef457611ec7858585856121ec565b6002866003811115611f0857611f086130e6565b1415611f1a57611ec785858585612337565b6003866003811115611f2e57611f2e6130e6565b1415611f4057611ec785858585612459565b856040516336cb1d2160e01b81526004016104109190612bf9565b95945050505050565b600080611f7185856120a5565b9050611f5b81846120b1565b606082471015611fde5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610410565b843b61202c5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610410565b600080866001600160a01b031685876040516120489190612b4b565b60006040518083038185875af1925050503d8060008114612085576040519150601f19603f3d011682016040523d82523d6000602084013e61208a565b606091505b509150915061209a828286612532565b979650505050505050565b6000611e218284612fbc565b6000611e218284612eaf565b6001600160a01b03831660009081526003602090815260408083208054825181850281018501909352808352849383018282801561212457602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612106575b505050505090506000866001600160a01b03166338ed173986868530426040518663ffffffff1660e01b8152600401612161959493929190612dbf565b600060405180830381600087803b15801561217b57600080fd5b505af115801561218f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526121b7919081019061291a565b905080600182516121c89190612ffe565b815181106121d8576121d86130fc565b602002602001015192505050949350505050565b6001600160a01b038316600090815260046020526040812080548291906122129061307a565b80601f016020809104026020016040519081016040528092919081815260200182805461223e9061307a565b801561228b5780601f106122605761010080835404028352916020019161228b565b820191906000526020600020905b81548152906001019060200180831161226e57829003601f168201915b50506040805160a0810182528581523060208201524281830152606081018a905260808101899052905163c04b8d5960e01b8152949550936001600160a01b038b16935063c04b8d5992506122e591508490600401612c5d565b602060405180830381600087803b1580156122ff57600080fd5b505af1158015612313573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061209a9190612a8e565b6001600160a01b03838116600081815260056020908152604080832054815160c081018352818152808401859052808301959095527f0000000000000000000000000000000000000000000000000000000000000000861660608087019190915260808087018a90528351808601855286815260a0880152835190810184523080825294810186905280840194909452830184905290516352bbbe2960e01b81529294909392908916906352bbbe29906123fb90859085908a904290600401612cb5565b602060405180830381600087803b15801561241557600080fd5b505af1158015612429573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061244d9190612a8e565b98975050505050505050565b6001600160a01b0383811660009081526006602090815260408083208151808301835290546001600160801b03808216808452600160801b909204169382018490529151630b68372160e31b81526004810192909252602482019290925260448101869052606481018590529192909190871690635b41b90890608401602060405180830381600087803b1580156124f057600080fd5b505af1158015612504573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125289190612a8e565b9695505050505050565b60608315612541575081611e21565b8251156125515782518084602001fd5b8160405162461bcd60e51b81526004016104109190612be6565b8280548282559060005260206000209081019282156125c0579160200282015b828111156125c057825182546001600160a01b0319166001600160a01b0390911617825560209092019160019091019061258b565b506125cc929150612644565b5090565b8280546125dc9061307a565b90600052602060002090601f0160209004810192826125fe57600085556125c0565b82601f106126175782800160ff198235161785556125c0565b828001600101855582156125c0579182015b828111156125c0578235825591602001919060010190612629565b5b808211156125cc5760008155600101612645565b80356001600160801b038116811461267057600080fd5b919050565b60006020828403121561268757600080fd5b8135611e218161323d565b6000602082840312156126a457600080fd5b8151611e218161323d565b600080604083850312156126c257600080fd5b82356126cd8161323d565b915060208301356126dd8161323d565b809150509250929050565b600080604083850312156126fb57600080fd5b82356127068161323d565b915060208301356126dd81613252565b60008060008084860361010081121561272e57600080fd5b85356127398161323d565b945060c0601f198201121561274d57600080fd5b5060208501925060e085013567ffffffffffffffff8082111561276f57600080fd5b818701915087601f83011261278357600080fd5b81358181111561279257600080fd5b8860208285010111156127a457600080fd5b95989497505060200194505050565b600080604083850312156127c657600080fd5b82356127d18161323d565b946020939093013593505050565b600060208083850312156127f257600080fd5b823567ffffffffffffffff81111561280957600080fd5b8301601f8101851361281a57600080fd5b803561282d61282882612e61565b612e30565b80828252848201915084840188868560051b870101111561284d57600080fd5b600094505b838510156128795780356128658161323d565b835260019490940193918501918501612852565b50979650505050505050565b6000602080838503121561289857600080fd5b825167ffffffffffffffff8111156128af57600080fd5b8301601f810185136128c057600080fd5b80516128ce61282882612e61565b80828252848201915084840188868560051b87010111156128ee57600080fd5b600094505b838510156128795780516129068161323d565b8352600194909401939185019185016128f3565b6000602080838503121561292d57600080fd5b825167ffffffffffffffff81111561294457600080fd5b8301601f8101851361295557600080fd5b805161296361282882612e61565b80828252848201915084840188868560051b870101111561298357600080fd5b600094505b83851015612879578051835260019490940193918501918501612988565b6000602082840312156129b857600080fd5b8135611e2181613252565b6000602082840312156129d557600080fd5b8151611e2181613252565b6000602082840312156129f257600080fd5b5035919050565b600060208284031215612a0b57600080fd5b8135611e2181613260565b600060408284031215612a2857600080fd5b6040516040810181811067ffffffffffffffff82111715612a4b57612a4b613112565b604052612a5783612659565b8152612a6560208401612659565b60208201529392505050565b600060208284031215612a8357600080fd5b8135611e218161326d565b600060208284031215612aa057600080fd5b5051919050565b60008060008060808587031215612abd57600080fd5b8451935060208501519250604085015191506060850151612add8161323d565b939692955090935050565b600060208284031215612afa57600080fd5b815160ff81168114611e2157600080fd5b60008151808452612b2381602086016020860161304a565b601f01601f19169290920160200192915050565b60048110612b4757612b476130e6565b9052565b60008251612b5d81846020870161304a565b9190910192915050565b6001600160a01b038a8116825261ffff8a811660208401528916604083015260009061010090612b9a606085018b612b37565b8816608084015260a083018190528201859052610120858782850137600083870182015260c08301949094525090151560e0820152601f909201601f1916909101019695505050505050565b602081526000611e216020830184612b0b565b60208101610e1b8284612b37565b60608101612c158286612b37565b602082019390935260400152919050565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b602081526000825160a06020840152612c7960c0840182612b0b565b905060018060a01b0360208501511660408401526040840151606084015260608401516080840152608084015160a08401528091505092915050565b60e08152845160e08201526000602086015160028110612cd757612cd76130e6565b61010083015260408601516001600160a01b03908116610120840152606087015116610140830152608086015161016083015260a086015160c0610180840152612d256101a0840182612b0b565b915050612d65602083018680516001600160a01b039081168352602080830151151590840152604080830151909116908301526060908101511515910152565b60a082019390935260c0015292915050565b61ffff8781168252861660208201526001600160a01b0385166040820152831515606082015260c08101612dae6080830185612b37565b8260a0830152979650505050505050565b600060a082018783526020878185015260a0604085015281875180845260c086019150828901935060005b81811015612e0f5784516001600160a01b031683529383019391830191600101612dea565b50506001600160a01b03969096166060850152505050608001529392505050565b604051601f8201601f1916810167ffffffffffffffff81118282101715612e5957612e59613112565b604052919050565b600067ffffffffffffffff821115612e7b57612e7b613112565b5060051b60200190565b60008085851115612e9557600080fd5b83861115612ea257600080fd5b5050820193919092039150565b600082612ecc57634e487b7160e01b600052601260045260246000fd5b500490565b600181815b80851115612f0c578160001904821115612ef257612ef26130d0565b80851615612eff57918102915b93841c9390800290612ed6565b509250929050565b6000611e218383600082612f2a57506001610e1b565b81612f3757506000610e1b565b8160018114612f4d5760028114612f5757612f73565b6001915050610e1b565b60ff841115612f6857612f686130d0565b50506001821b610e1b565b5060208310610133831016604e8410600b8410161715612f96575081810a610e1b565b612fa08383612ed1565b8060001904821115612fb457612fb46130d0565b029392505050565b6000816000190483118215151615612fd657612fd66130d0565b500290565b600061ffff83811690831681811015612ff657612ff66130d0565b039392505050565b600082821015613010576130106130d0565b500390565b6bffffffffffffffffffffffff1981358181169160148510156130425780818660140360031b1b83161692505b505092915050565b60005b8381101561306557818101518382015260200161304d565b83811115613074576000848401525b50505050565b600181811c9082168061308e57607f821691505b602082108114156130af57634e487b7160e01b600052602260045260246000fd5b50919050565b60006000198214156130c9576130c96130d0565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b60008135610e1b81613252565b60008135610e1b81613260565b813561314d8161326d565b61ffff8116905081548161ffff198216178355602084013561316e8161326d565b63ffff00008160101b169050808363ffffffff1984161717845560408501356131968161323d565b6001600160c01b0319929092169092179190911760209190911b640100000000600160c01b03161781556131ed6131cf60608401613128565b82805460ff60c01b191691151560c01b60ff60c01b16919091179055565b6132026131fc60808401613135565b82613210565b60a082013560018201555050565b60048210613220576132206130e6565b805460ff60c81b191660c89290921b60ff60c81b16919091179055565b6001600160a01b038116811461172857600080fd5b801515811461172857600080fd5b6004811061172857600080fd5b61ffff8116811461172857600080fdfe7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa264697066735822122083162c271976c91ebc3c0a0e8199fc7a19f20127f4ebdb1a7c35bf3e390a9c0f64736f6c634300080700337bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a", + "deployedBytecode": "0x608060405234801561001057600080fd5b506004361061012c5760003560e01c806382aa1c88116100ad578063d38bfff411610071578063d38bfff414610312578063da70696c14610325578063dac4db4e14610345578063e48d7fc514610358578063ee3be5f5146103ac57600080fd5b806382aa1c881461028c578063a994317f146102c1578063b13dc20a146102d4578063b76e83af146102e7578063c7af3352146102fa57600080fd5b8063548f5ae5116100f4578063548f5ae5146101c5578063587c8440146101d85780635d36b1901461024a57806365f6fa94146102525780637cb374bd1461026557600080fd5b80630c340a24146101315780631072cbea146101565780632579153d1461016b5780632dfbe8311461017e578063430bf08a1461019e575b600080fd5b6101396103cf565b6040516001600160a01b0390911681526020015b60405180910390f35b6101696101643660046127b3565b6103ec565b005b610169610179366004612716565b610439565b61019161018c366004612675565b6108c8565b60405161014d9190612be6565b6101397f000000000000000000000000000000000000000000000000000000000000000081565b6101696101d3366004612675565b610962565b6102386101e6366004612675565b6000602081905290815260409020805460019091015461ffff80831692620100008104909116916001600160a01b036401000000008304169160ff600160c01b8204811692600160c81b909204169086565b60405161014d96959493929190612d77565b6101696109dd565b6101696102603660046126e8565b610a83565b6101397f000000000000000000000000000000000000000000000000000000000000000081565b6102b37f000000000000000000000000000000000000000000000000000000000000000081565b60405190815260200161014d565b6101696102cf3660046126af565b610b0a565b6101696102e2366004612675565b610b86565b600254610139906001600160a01b031681565b610302610c25565b604051901515815260200161014d565b610169610320366004612675565b610c56565b6102b3610333366004612675565b60056020526000908152604090205481565b6101396103533660046127b3565b610cfa565b61038c610366366004612675565b6006602052600090815260409020546001600160801b0380821691600160801b90041682565b604080516001600160801b0393841681529290911660208301520161014d565b6103026103ba366004612675565b60016020526000908152604090205460ff1681565b60006103e760008051602061327e8339815191525490565b905090565b6103f4610c25565b6104195760405162461bcd60e51b815260040161041090612c26565b60405180910390fd5b6104356104246103cf565b6001600160a01b0384169083610e21565b5050565b610441610c25565b61045d5760405162461bcd60e51b815260040161041090612c26565b6103e861046d6020850185612a71565b61ffff1611156104905760405163faa3445560e01b815260040160405180910390fd5b6103e86104a36040850160208601612a71565b61ffff1611156104c657604051631633c8cd60e31b815260040160405180910390fd5b60006104d86060850160408601612675565b90506001600160a01b03811661050157604051637138356f60e01b815260040160405180910390fd5b6001600160a01b038086166000908152602081905260409020805464010000000090049091169085906105348282613142565b9050507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b888879e6040518163ffffffff1660e01b815260040160206040518083038186803b15801561059057600080fd5b505afa1580156105a4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105c89190612692565b6040516315d5220f60e31b81526001600160a01b038881166004830152919091169063aea910789060240160206040518083038186803b15801561060b57600080fd5b505afa15801561061f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106439190612a8e565b50856001600160a01b0382161580159061066f5750826001600160a01b0316826001600160a01b031614155b15610689576106896001600160a01b038216836000610e89565b826001600160a01b0316826001600160a01b0316146106cd576106b76001600160a01b038216846000610e89565b6106cd6001600160a01b03821684600019610e89565b60006106df60a08801608089016129f9565b905060008160038111156106f5576106f56130e6565b14156107395761070686868a610fad565b6001600160a01b03891660009081526003602090815260409091208251610733939192919091019061256b565b50610846565b600181600381111561074d5761074d6130e6565b14156107815761075e86868a6110d9565b6001600160a01b038a1660009081526004602052604090206107339290916125d0565b6002816003811115610795576107956130e6565b14156107c5576107a78686868b6111af565b6001600160a01b038916600090815260056020526040902055610846565b60038160038111156107d9576107d96130e6565b141561082b576107eb8686868b611311565b6001600160a01b0389166000908152600660209081526040909120825192909101516001600160801b03908116600160801b029216919091179055610846565b806040516336cb1d2160e01b81526004016104109190612bf9565b7f5eb6073ba3980477f03b1ce0dccba754d48454bbd65a115dcd42db65ca1fefd28861087560208a018a612a71565b61088560408b0160208c01612a71565b84888b8b8e60a001358f60600160208101906108a191906129a6565b6040516108b699989796959493929190612b67565b60405180910390a15050505050505050565b600460205260009081526040902080546108e19061307a565b80601f016020809104026020016040519081016040528092919081815260200182805461090d9061307a565b801561095a5780601f1061092f5761010080835404028352916020019161095a565b820191906000526020600020905b81548152906001019060200180831161093d57829003601f168201915b505050505081565b7f53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac4535805460028114156109c75760405162461bcd60e51b815260206004820152600e60248201526d1499595b9d1c985b9d0818d85b1b60921b6044820152606401610410565b600282556109d58333611500565b506001905550565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b031614610a785760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b6064820152608401610410565b610a8133611667565b565b610a8b610c25565b610aa75760405162461bcd60e51b815260040161041090612c26565b6001600160a01b038216600081815260016020908152604091829020805460ff19168515159081179091558251938452908301527f013ed61add17cbfcbbd95bf8543da67c89658c5477d3f3199a1a2d58ecf1913f910160405180910390a15050565b7f53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac453580546002811415610b6f5760405162461bcd60e51b815260206004820152600e60248201526d1499595b9d1c985b9d0818d85b1b60921b6044820152606401610410565b60028255610b7d8484611500565b50600190555050565b610b8e610c25565b610baa5760405162461bcd60e51b815260040161041090612c26565b6001600160a01b038116610bd157604051637138356f60e01b815260040160405180910390fd5b600280546001600160a01b0319166001600160a01b0383169081179091556040519081527f50f4ca9002119593802480c412cb5e106ae726647a31dcf8a7e7ed4e6794bf5e9060200160405180910390a150565b6000610c3d60008051602061327e8339815191525490565b6001600160a01b0316336001600160a01b031614905090565b610c5e610c25565b610c7a5760405162461bcd60e51b815260040161041090612c26565b610ca2817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b0316610cc260008051602061327e8339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b60036020528160005260406000208181548110610d1657600080fd5b6000918252602090912001546001600160a01b03169150829050565b600080826001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b158015610d6e57600080fd5b505afa158015610d82573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610da69190612ae8565b60ff16905060048110158015610dbd575060128111155b610e1b5760405162461bcd60e51b815260206004820152602960248201527f546f6b656e206d75737420686176652073756666696369656e7420646563696d604482015268616c20706c6163657360b81b6064820152608401610410565b92915050565b6040516001600160a01b038316602482015260448101829052610e8490849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915261172b565b505050565b801580610f125750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e9060440160206040518083038186803b158015610ed857600080fd5b505afa158015610eec573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f109190612a8e565b155b610f7d5760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b6064820152608401610410565b6040516001600160a01b038316602482015260448101829052610e8490849063095ea7b360e01b90606401610e4d565b6060610fbb838501856127df565b80519091506002811015610fe2576040516360fa33db60e11b815260040160405180910390fd5b826001600160a01b031682600081518110610fff57610fff6130fc565b60200260200101516001600160a01b0316146110595781600081518110611028576110286130fc565b602002602001015160405163280d94a560e21b815260040161041091906001600160a01b0391909116815260200190565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168261108f600184612ffe565b8151811061109f5761109f6130fc565b60200260200101516001600160a01b0316146110d157816110c1600183612ffe565b81518110611028576110286130fc565b509392505050565b828260006110ea6014828486612e85565b6110f391613015565b60601c90506001600160a01b038416811461112c5760405163280d94a560e21b81526001600160a01b0382166004820152602401610410565b8585611139601485612ffe565b611144928290612e85565b61114d91613015565b60601c90506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001681146111a65760405163280d94a560e21b81526001600160a01b0382166004820152602401610410565b50935093915050565b60006111bd848601866129e0565b9050806111dd57604051634bdc2c9560e01b815260040160405180910390fd5b60405163160bf1c960e31b8152600481018290526001600160a01b03838116602483015284919082169063b05f8e489060440160806040518083038186803b15801561122857600080fd5b505afa15801561123c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112609190612aa7565b505060405163160bf1c960e31b8152600481018590526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660248301528416925063b05f8e48915060440160806040518083038186803b1580156112cc57600080fd5b505afa1580156112e0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113049190612aa7565b5050505050949350505050565b604080518082019091526000808252602082015261133184860186612a16565b805160405163c661065760e01b81526001600160801b03909116600482015290915083906001600160a01b0382169063c66106579060240160206040518083038186803b15801561138157600080fd5b505afa158015611395573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113b99190612692565b6001600160a01b0316836001600160a01b0316146113f55760405163d658230160e01b81526001600160a01b0384166004820152602401610410565b602082015160405163c661065760e01b81526001600160801b0390911660048201526001600160a01b0382169063c66106579060240160206040518083038186803b15801561144357600080fd5b505afa158015611457573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061147b9190612692565b6001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316146114f75760405163d658230160e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166004820152602401610410565b50949350505050565b611509826117fd565b60008290506000816001600160a01b031663f6ca71b06040518163ffffffff1660e01b815260040160006040518083038186803b15801561154957600080fd5b505afa15801561155d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526115859190810190612885565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b888879e6040518163ffffffff1660e01b815260040160206040518083038186803b1580156115e257600080fd5b505afa1580156115f6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061161a9190612692565b825190915060005b8181101561165e5761164e84828151811061163f5761163f6130fc565b6020026020010151878561189d565b611657816130b5565b9050611622565b50505050505050565b6001600160a01b0381166116bd5760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f7220697320616464726573732830290000000000006044820152606401610410565b806001600160a01b03166116dd60008051602061327e8339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a36117288160008051602061327e83398151915255565b50565b6000611780826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611e0f9092919063ffffffff16565b805190915015610e84578080602001905181019061179e91906129c3565b610e845760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610410565b6001600160a01b03811660009081526001602052604090205460ff1661184157604051630211444960e11b81526001600160a01b0382166004820152602401610410565b6000819050806001600160a01b0316635a063f636040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561188157600080fd5b505af1158015611895573d6000803e3d6000fd5b505050505050565b6040516370a0823160e01b81523060048201526000906001600160a01b038516906370a082319060240160206040518083038186803b1580156118df57600080fd5b505afa1580156118f3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119179190612a8e565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316846001600160a01b031614156119df5760025461196d906001600160a01b03868116911683610e21565b604080516000808252602082018490528183015290517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316917f42e60aae8f000883c46e2f449fa76268e374ce1b962f46ca9360ab98b18f5799919081900360600190a250505050565b6001600160a01b03808516600090815260208181526040808320815160c081018352815461ffff8082168352620100008204169482019490945264010000000084049095169185019190915260ff600160c01b830481161515606086015292939290916080840191600160c81b909104166003811115611a6157611a616130e6565b6003811115611a7257611a726130e6565b815260200160018201548152505090508060600151611a92575050505050565b81611a9e575050505050565b60a081015115611ab957611ab6828260a00151611e28565b91505b6040516315d5220f60e31b81526001600160a01b0386811660048301526000919085169063aea910789060240160206040518083038186803b158015611afe57600080fd5b505afa158015611b12573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b369190612a8e565b90506000670de0b6b3a7640000612710611ba27f0000000000000000000000000000000000000000000000000000000000000000611b738b610d32565b87518790611b8390612710612fdb565b611b919061ffff168b612fbc565b611b9b9190612fbc565b9190611e3e565b611bac9190612eaf565b611bb69190612eaf565b90506000611bcf846080015185604001518a8886611ea0565b905081811015611bfc576040516302d96fff60e41b81526004810182905260248101839052604401610410565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316886001600160a01b03167fa861903141bc68b536d5048a576afcc645630e1b18a4296ef34cbd4d1407f70986608001518885604051611c6793929190612c07565b60405180910390a36040516370a0823160e01b81523060048201527f0000000000000000000000000000000000000000000000000000000000000000906000906001600160a01b038316906370a082319060240160206040518083038186803b158015611cd357600080fd5b505afa158015611ce7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d0b9190612a8e565b905082811015611d385760405163315d50df60e11b81526004810182905260248101849052604401610410565b6020860151600090611d5290859061ffff16612710611f64565b90506000611d608284612ffe565b600254909150611d7d906001600160a01b03868116911683610e21565b611d916001600160a01b0385168c84610e21565b604080516001600160a01b038d81168252602082018490529181018490527f0000000000000000000000000000000000000000000000000000000000000000909116907f42e60aae8f000883c46e2f449fa76268e374ce1b962f46ca9360ab98b18f57999060600160405180910390a2505050505050505050505050565b6060611e1e8484600085611f7d565b90505b9392505050565b6000818310611e375781611e21565b5090919050565b600081831115611e6e57611e67611e558385612ffe565b611e6090600a612f14565b85906120a5565b9350611e98565b81831015611e9857611e95611e838484612ffe565b611e8e90600a612f14565b85906120b1565b93505b509192915050565b600080866003811115611eb557611eb56130e6565b1415611ece57611ec7858585856120bd565b9050611f5b565b6001866003811115611ee257611ee26130e6565b1415611ef457611ec7858585856121ec565b6002866003811115611f0857611f086130e6565b1415611f1a57611ec785858585612337565b6003866003811115611f2e57611f2e6130e6565b1415611f4057611ec785858585612459565b856040516336cb1d2160e01b81526004016104109190612bf9565b95945050505050565b600080611f7185856120a5565b9050611f5b81846120b1565b606082471015611fde5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610410565b843b61202c5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610410565b600080866001600160a01b031685876040516120489190612b4b565b60006040518083038185875af1925050503d8060008114612085576040519150601f19603f3d011682016040523d82523d6000602084013e61208a565b606091505b509150915061209a828286612532565b979650505050505050565b6000611e218284612fbc565b6000611e218284612eaf565b6001600160a01b03831660009081526003602090815260408083208054825181850281018501909352808352849383018282801561212457602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612106575b505050505090506000866001600160a01b03166338ed173986868530426040518663ffffffff1660e01b8152600401612161959493929190612dbf565b600060405180830381600087803b15801561217b57600080fd5b505af115801561218f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526121b7919081019061291a565b905080600182516121c89190612ffe565b815181106121d8576121d86130fc565b602002602001015192505050949350505050565b6001600160a01b038316600090815260046020526040812080548291906122129061307a565b80601f016020809104026020016040519081016040528092919081815260200182805461223e9061307a565b801561228b5780601f106122605761010080835404028352916020019161228b565b820191906000526020600020905b81548152906001019060200180831161226e57829003601f168201915b50506040805160a0810182528581523060208201524281830152606081018a905260808101899052905163c04b8d5960e01b8152949550936001600160a01b038b16935063c04b8d5992506122e591508490600401612c5d565b602060405180830381600087803b1580156122ff57600080fd5b505af1158015612313573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061209a9190612a8e565b6001600160a01b03838116600081815260056020908152604080832054815160c081018352818152808401859052808301959095527f0000000000000000000000000000000000000000000000000000000000000000861660608087019190915260808087018a90528351808601855286815260a0880152835190810184523080825294810186905280840194909452830184905290516352bbbe2960e01b81529294909392908916906352bbbe29906123fb90859085908a904290600401612cb5565b602060405180830381600087803b15801561241557600080fd5b505af1158015612429573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061244d9190612a8e565b98975050505050505050565b6001600160a01b0383811660009081526006602090815260408083208151808301835290546001600160801b03808216808452600160801b909204169382018490529151630b68372160e31b81526004810192909252602482019290925260448101869052606481018590529192909190871690635b41b90890608401602060405180830381600087803b1580156124f057600080fd5b505af1158015612504573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125289190612a8e565b9695505050505050565b60608315612541575081611e21565b8251156125515782518084602001fd5b8160405162461bcd60e51b81526004016104109190612be6565b8280548282559060005260206000209081019282156125c0579160200282015b828111156125c057825182546001600160a01b0319166001600160a01b0390911617825560209092019160019091019061258b565b506125cc929150612644565b5090565b8280546125dc9061307a565b90600052602060002090601f0160209004810192826125fe57600085556125c0565b82601f106126175782800160ff198235161785556125c0565b828001600101855582156125c0579182015b828111156125c0578235825591602001919060010190612629565b5b808211156125cc5760008155600101612645565b80356001600160801b038116811461267057600080fd5b919050565b60006020828403121561268757600080fd5b8135611e218161323d565b6000602082840312156126a457600080fd5b8151611e218161323d565b600080604083850312156126c257600080fd5b82356126cd8161323d565b915060208301356126dd8161323d565b809150509250929050565b600080604083850312156126fb57600080fd5b82356127068161323d565b915060208301356126dd81613252565b60008060008084860361010081121561272e57600080fd5b85356127398161323d565b945060c0601f198201121561274d57600080fd5b5060208501925060e085013567ffffffffffffffff8082111561276f57600080fd5b818701915087601f83011261278357600080fd5b81358181111561279257600080fd5b8860208285010111156127a457600080fd5b95989497505060200194505050565b600080604083850312156127c657600080fd5b82356127d18161323d565b946020939093013593505050565b600060208083850312156127f257600080fd5b823567ffffffffffffffff81111561280957600080fd5b8301601f8101851361281a57600080fd5b803561282d61282882612e61565b612e30565b80828252848201915084840188868560051b870101111561284d57600080fd5b600094505b838510156128795780356128658161323d565b835260019490940193918501918501612852565b50979650505050505050565b6000602080838503121561289857600080fd5b825167ffffffffffffffff8111156128af57600080fd5b8301601f810185136128c057600080fd5b80516128ce61282882612e61565b80828252848201915084840188868560051b87010111156128ee57600080fd5b600094505b838510156128795780516129068161323d565b8352600194909401939185019185016128f3565b6000602080838503121561292d57600080fd5b825167ffffffffffffffff81111561294457600080fd5b8301601f8101851361295557600080fd5b805161296361282882612e61565b80828252848201915084840188868560051b870101111561298357600080fd5b600094505b83851015612879578051835260019490940193918501918501612988565b6000602082840312156129b857600080fd5b8135611e2181613252565b6000602082840312156129d557600080fd5b8151611e2181613252565b6000602082840312156129f257600080fd5b5035919050565b600060208284031215612a0b57600080fd5b8135611e2181613260565b600060408284031215612a2857600080fd5b6040516040810181811067ffffffffffffffff82111715612a4b57612a4b613112565b604052612a5783612659565b8152612a6560208401612659565b60208201529392505050565b600060208284031215612a8357600080fd5b8135611e218161326d565b600060208284031215612aa057600080fd5b5051919050565b60008060008060808587031215612abd57600080fd5b8451935060208501519250604085015191506060850151612add8161323d565b939692955090935050565b600060208284031215612afa57600080fd5b815160ff81168114611e2157600080fd5b60008151808452612b2381602086016020860161304a565b601f01601f19169290920160200192915050565b60048110612b4757612b476130e6565b9052565b60008251612b5d81846020870161304a565b9190910192915050565b6001600160a01b038a8116825261ffff8a811660208401528916604083015260009061010090612b9a606085018b612b37565b8816608084015260a083018190528201859052610120858782850137600083870182015260c08301949094525090151560e0820152601f909201601f1916909101019695505050505050565b602081526000611e216020830184612b0b565b60208101610e1b8284612b37565b60608101612c158286612b37565b602082019390935260400152919050565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b602081526000825160a06020840152612c7960c0840182612b0b565b905060018060a01b0360208501511660408401526040840151606084015260608401516080840152608084015160a08401528091505092915050565b60e08152845160e08201526000602086015160028110612cd757612cd76130e6565b61010083015260408601516001600160a01b03908116610120840152606087015116610140830152608086015161016083015260a086015160c0610180840152612d256101a0840182612b0b565b915050612d65602083018680516001600160a01b039081168352602080830151151590840152604080830151909116908301526060908101511515910152565b60a082019390935260c0015292915050565b61ffff8781168252861660208201526001600160a01b0385166040820152831515606082015260c08101612dae6080830185612b37565b8260a0830152979650505050505050565b600060a082018783526020878185015260a0604085015281875180845260c086019150828901935060005b81811015612e0f5784516001600160a01b031683529383019391830191600101612dea565b50506001600160a01b03969096166060850152505050608001529392505050565b604051601f8201601f1916810167ffffffffffffffff81118282101715612e5957612e59613112565b604052919050565b600067ffffffffffffffff821115612e7b57612e7b613112565b5060051b60200190565b60008085851115612e9557600080fd5b83861115612ea257600080fd5b5050820193919092039150565b600082612ecc57634e487b7160e01b600052601260045260246000fd5b500490565b600181815b80851115612f0c578160001904821115612ef257612ef26130d0565b80851615612eff57918102915b93841c9390800290612ed6565b509250929050565b6000611e218383600082612f2a57506001610e1b565b81612f3757506000610e1b565b8160018114612f4d5760028114612f5757612f73565b6001915050610e1b565b60ff841115612f6857612f686130d0565b50506001821b610e1b565b5060208310610133831016604e8410600b8410161715612f96575081810a610e1b565b612fa08383612ed1565b8060001904821115612fb457612fb46130d0565b029392505050565b6000816000190483118215151615612fd657612fd66130d0565b500290565b600061ffff83811690831681811015612ff657612ff66130d0565b039392505050565b600082821015613010576130106130d0565b500390565b6bffffffffffffffffffffffff1981358181169160148510156130425780818660140360031b1b83161692505b505092915050565b60005b8381101561306557818101518382015260200161304d565b83811115613074576000848401525b50505050565b600181811c9082168061308e57607f821691505b602082108114156130af57634e487b7160e01b600052602260045260246000fd5b50919050565b60006000198214156130c9576130c96130d0565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b60008135610e1b81613252565b60008135610e1b81613260565b813561314d8161326d565b61ffff8116905081548161ffff198216178355602084013561316e8161326d565b63ffff00008160101b169050808363ffffffff1984161717845560408501356131968161323d565b6001600160c01b0319929092169092179190911760209190911b640100000000600160c01b03161781556131ed6131cf60608401613128565b82805460ff60c01b191691151560c01b60ff60c01b16919091179055565b6132026131fc60808401613135565b82613210565b60a082013560018201555050565b60048210613220576132206130e6565b805460ff60c81b191660c89290921b60ff60c81b16919091179055565b6001600160a01b038116811461172857600080fd5b801515811461172857600080fd5b6004811061172857600080fd5b61ffff8116811461172857600080fdfe7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa264697066735822122083162c271976c91ebc3c0a0e8199fc7a19f20127f4ebdb1a7c35bf3e390a9c0f64736f6c63430008070033", "libraries": {}, "devdoc": { "kind": "dev", diff --git a/contracts/deployments/holesky/solcInputs/5e7101910c63b5cb160cf1f36fa86058.json b/contracts/deployments/holesky/solcInputs/5e7101910c63b5cb160cf1f36fa86058.json new file mode 100644 index 0000000000..8b8b49dee9 --- /dev/null +++ b/contracts/deployments/holesky/solcInputs/5e7101910c63b5cb160cf1f36fa86058.json @@ -0,0 +1,44 @@ +{ + "language": "Solidity", + "sources": { + "@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" + }, + "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/proxies/InitializeGovernedUpgradeabilityProxy.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { Address } from \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport { Governable } from \"../governance/Governable.sol\";\n\n/**\n * @title BaseGovernedUpgradeabilityProxy\n * @dev This contract combines an upgradeability proxy with our governor system.\n * It is based on an older version of OpenZeppelins BaseUpgradeabilityProxy\n * with Solidity ^0.8.0.\n * @author Origin Protocol Inc\n */\ncontract InitializeGovernedUpgradeabilityProxy is Governable {\n /**\n * @dev Emitted when the implementation is upgraded.\n * @param implementation Address of the new implementation.\n */\n event Upgraded(address indexed implementation);\n\n /**\n * @dev Contract initializer with Governor enforcement\n * @param _logic Address of the initial implementation.\n * @param _initGovernor Address of the initial Governor.\n * @param _data Data to send as msg.data to the implementation to initialize\n * the proxied contract.\n * It should include the signature and the parameters of the function to be\n * called, as described in\n * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.\n * This parameter is optional, if no data is given the initialization call\n * to proxied contract will be skipped.\n */\n function initialize(\n address _logic,\n address _initGovernor,\n bytes calldata _data\n ) public payable onlyGovernor {\n require(_implementation() == address(0));\n assert(\n IMPLEMENTATION_SLOT ==\n bytes32(uint256(keccak256(\"eip1967.proxy.implementation\")) - 1)\n );\n _setImplementation(_logic);\n if (_data.length > 0) {\n (bool success, ) = _logic.delegatecall(_data);\n require(success);\n }\n _changeGovernor(_initGovernor);\n }\n\n /**\n * @return The address of the proxy admin/it's also the governor.\n */\n function admin() external view returns (address) {\n return _governor();\n }\n\n /**\n * @return The address of the implementation.\n */\n function implementation() external view returns (address) {\n return _implementation();\n }\n\n /**\n * @dev Upgrade the backing implementation of the proxy.\n * Only the admin can call this function.\n * @param newImplementation Address of the new implementation.\n */\n function upgradeTo(address newImplementation) external onlyGovernor {\n _upgradeTo(newImplementation);\n }\n\n /**\n * @dev Upgrade the backing implementation of the proxy and call a function\n * on the new implementation.\n * This is useful to initialize the proxied contract.\n * @param newImplementation Address of the new implementation.\n * @param data Data to send as msg.data in the low level call.\n * It should include the signature and the parameters of the function to be called, as described in\n * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.\n */\n function upgradeToAndCall(address newImplementation, bytes calldata data)\n external\n payable\n onlyGovernor\n {\n _upgradeTo(newImplementation);\n (bool success, ) = newImplementation.delegatecall(data);\n require(success);\n }\n\n /**\n * @dev Fallback function.\n * Implemented entirely in `_fallback`.\n */\n fallback() external payable {\n _fallback();\n }\n\n /**\n * @dev Delegates execution to an implementation contract.\n * This is a low level function that doesn't return to its internal call site.\n * It will return to the external caller whatever the implementation returns.\n * @param _impl Address to delegate.\n */\n function _delegate(address _impl) internal {\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(gas(), _impl, 0, calldatasize(), 0, 0)\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 /**\n * @dev Function that is run as the first thing in the fallback function.\n * Can be redefined in derived contracts to add functionality.\n * Redefinitions must call super._willFallback().\n */\n function _willFallback() internal {}\n\n /**\n * @dev fallback implementation.\n * Extracted to enable manual triggering.\n */\n function _fallback() internal {\n _willFallback();\n _delegate(_implementation());\n }\n\n /**\n * @dev Storage slot with the address of the current implementation.\n * This is the keccak-256 hash of \"eip1967.proxy.implementation\" subtracted by 1, and is\n * validated in the constructor.\n */\n bytes32 internal constant IMPLEMENTATION_SLOT =\n 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\n\n /**\n * @dev Returns the current implementation.\n * @return impl Address of the current implementation\n */\n function _implementation() internal view returns (address impl) {\n bytes32 slot = IMPLEMENTATION_SLOT;\n // solhint-disable-next-line no-inline-assembly\n assembly {\n impl := sload(slot)\n }\n }\n\n /**\n * @dev Upgrades the proxy to a new implementation.\n * @param newImplementation Address of the new implementation.\n */\n function _upgradeTo(address newImplementation) internal {\n _setImplementation(newImplementation);\n emit Upgraded(newImplementation);\n }\n\n /**\n * @dev Sets the implementation address of the proxy.\n * @param newImplementation Address of the new implementation.\n */\n function _setImplementation(address newImplementation) internal {\n require(\n Address.isContract(newImplementation),\n \"Cannot set a proxy implementation to a non-contract address\"\n );\n\n bytes32 slot = IMPLEMENTATION_SLOT;\n\n // solhint-disable-next-line no-inline-assembly\n assembly {\n sstore(slot, newImplementation)\n }\n }\n}\n" + }, + "contracts/proxies/Proxies.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { InitializeGovernedUpgradeabilityProxy } from \"./InitializeGovernedUpgradeabilityProxy.sol\";\n\n/**\n * @notice OUSDProxy delegates calls to an OUSD implementation\n */\ncontract OUSDProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice WrappedOUSDProxy delegates calls to a WrappedOUSD implementation\n */\ncontract WrappedOUSDProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice VaultProxy delegates calls to a Vault implementation\n */\ncontract VaultProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice CompoundStrategyProxy delegates calls to a CompoundStrategy implementation\n */\ncontract CompoundStrategyProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice AaveStrategyProxy delegates calls to a AaveStrategy implementation\n */\ncontract AaveStrategyProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice ThreePoolStrategyProxy delegates calls to a ThreePoolStrategy implementation\n */\ncontract ThreePoolStrategyProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice ConvexStrategyProxy delegates calls to a ConvexStrategy implementation\n */\ncontract ConvexStrategyProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice HarvesterProxy delegates calls to a Harvester implementation\n */\ncontract HarvesterProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice DripperProxy delegates calls to a Dripper implementation\n */\ncontract DripperProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice MorphoCompoundStrategyProxy delegates calls to a MorphoCompoundStrategy implementation\n */\ncontract MorphoCompoundStrategyProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice ConvexOUSDMetaStrategyProxy delegates calls to a ConvexOUSDMetaStrategy implementation\n */\ncontract ConvexOUSDMetaStrategyProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice ConvexLUSDMetaStrategyProxy delegates calls to a ConvexalGeneralizedMetaStrategy implementation\n */\ncontract ConvexLUSDMetaStrategyProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice MorphoAaveStrategyProxy delegates calls to a MorphoCompoundStrategy implementation\n */\ncontract MorphoAaveStrategyProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice OETHProxy delegates calls to nowhere for now\n */\ncontract OETHProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice WOETHProxy delegates calls to nowhere for now\n */\ncontract WOETHProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice OETHVaultProxy delegates calls to a Vault implementation\n */\ncontract OETHVaultProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice OETHDripperProxy delegates calls to a OETHDripper implementation\n */\ncontract OETHDripperProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice OETHHarvesterProxy delegates calls to a Harvester implementation\n */\ncontract OETHHarvesterProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice FraxETHStrategyProxy delegates calls to a FraxETHStrategy implementation\n */\ncontract FraxETHStrategyProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice CurveEthStrategyProxy delegates calls to a CurveEthStrategy implementation\n */\ncontract ConvexEthMetaStrategyProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice BuybackProxy delegates calls to Buyback implementation\n */\ncontract BuybackProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice OETHMorphoAaveStrategyProxy delegates calls to a MorphoAaveStrategy implementation\n */\ncontract OETHMorphoAaveStrategyProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice OETHBalancerMetaPoolrEthStrategyProxy delegates calls to a BalancerMetaPoolStrategy implementation\n */\ncontract OETHBalancerMetaPoolrEthStrategyProxy is\n InitializeGovernedUpgradeabilityProxy\n{\n\n}\n\n/**\n * @notice OETHBalancerMetaPoolwstEthStrategyProxy delegates calls to a BalancerMetaPoolStrategy implementation\n */\ncontract OETHBalancerMetaPoolwstEthStrategyProxy is\n InitializeGovernedUpgradeabilityProxy\n{\n\n}\n\n/**\n * @notice FluxStrategyProxy delegates calls to a CompoundStrategy implementation\n */\ncontract FluxStrategyProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice MakerDsrStrategyProxy delegates calls to a Generalized4626Strategy implementation\n */\ncontract MakerDsrStrategyProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice FrxEthRedeemStrategyProxy delegates calls to a FrxEthRedeemStrategy implementation\n */\ncontract FrxEthRedeemStrategyProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice OETHBuybackProxy delegates calls to Buyback implementation\n */\ncontract OETHBuybackProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice BridgedWOETHProxy delegates calls to BridgedWOETH implementation\n */\ncontract BridgedWOETHProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice NativeStakingSSVStrategyProxy delegates calls to NativeStakingSSVStrategy implementation\n */\ncontract NativeStakingSSVStrategyProxy is\n InitializeGovernedUpgradeabilityProxy\n{\n\n}\n\n/**\n * @notice NativeStakingFeeAccumulatorProxy delegates calls to NativeStakingFeeCollector implementation\n */\ncontract NativeStakingFeeAccumulatorProxy is\n InitializeGovernedUpgradeabilityProxy\n{\n\n}\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/66dbdc9fbde8f1c7cc59f29d272eb661.json b/contracts/deployments/holesky/solcInputs/66dbdc9fbde8f1c7cc59f29d272eb661.json new file mode 100644 index 0000000000..7c4a288f05 --- /dev/null +++ b/contracts/deployments/holesky/solcInputs/66dbdc9fbde8f1c7cc59f29d272eb661.json @@ -0,0 +1,674 @@ +{ + "language": "Solidity", + "sources": { + "@openzeppelin/contracts/access/AccessControl.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/AccessControl.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IAccessControl.sol\";\nimport \"../utils/Context.sol\";\nimport \"../utils/Strings.sol\";\nimport \"../utils/introspection/ERC165.sol\";\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address => bool) members;\n bytes32 adminRole;\n }\n\n mapping(bytes32 => RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with a standardized message including the required role.\n *\n * The format of the revert reason is given by the following regular expression:\n *\n * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/\n *\n * _Available since v4.1._\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role, _msgSender());\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view override returns (bool) {\n return _roles[role].members[account];\n }\n\n /**\n * @dev Revert with a standard message if `account` is missing `role`.\n *\n * The format of the revert reason is given by the following regular expression:\n *\n * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/\n */\n function _checkRole(bytes32 role, address account) internal view {\n if (!hasRole(role, account)) {\n revert(\n string(\n abi.encodePacked(\n \"AccessControl: account \",\n Strings.toHexString(uint160(account), 20),\n \" is missing role \",\n Strings.toHexString(uint256(role), 32)\n )\n )\n );\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view override returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `account`.\n */\n function renounceRole(bytes32 role, address account) public virtual override {\n require(account == _msgSender(), \"AccessControl: can only renounce roles for self\");\n\n _revokeRole(role, account);\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event. Note that unlike {grantRole}, this function doesn't perform any\n * checks on the calling account.\n *\n * [WARNING]\n * ====\n * This function should only be called from the constructor when setting\n * up the initial roles for the system.\n *\n * Using this function in any other way is effectively circumventing the admin\n * system imposed by {AccessControl}.\n * ====\n *\n * NOTE: This function is deprecated in favor of {_grantRole}.\n */\n function _setupRole(bytes32 role, address account) internal virtual {\n _grantRole(role, account);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * Internal function without access restriction.\n */\n function _grantRole(bytes32 role, address account) internal virtual {\n if (!hasRole(role, account)) {\n _roles[role].members[account] = true;\n emit RoleGranted(role, account, _msgSender());\n }\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * Internal function without access restriction.\n */\n function _revokeRole(bytes32 role, address account) internal virtual {\n if (hasRole(role, account)) {\n _roles[role].members[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n }\n }\n}\n" + }, + "@openzeppelin/contracts/access/AccessControlEnumerable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/AccessControlEnumerable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IAccessControlEnumerable.sol\";\nimport \"./AccessControl.sol\";\nimport \"../utils/structs/EnumerableSet.sol\";\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 => EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view override returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view override returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override {\n super._grantRole(role, account);\n _roleMembers[role].add(account);\n }\n\n /**\n * @dev Overload {_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override {\n super._revokeRole(role, account);\n _roleMembers[role].remove(account);\n }\n}\n" + }, + "@openzeppelin/contracts/access/IAccessControl.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n *\n * _Available since v3.1._\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `account`.\n */\n function renounceRole(bytes32 role, address account) external;\n}\n" + }, + "@openzeppelin/contracts/access/IAccessControlEnumerable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/IAccessControlEnumerable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IAccessControl.sol\";\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n" + }, + "@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/introspection/ERC165.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC165.sol\";\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n *\n * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n" + }, + "@openzeppelin/contracts/utils/introspection/IERC165.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\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" + }, + "@openzeppelin/contracts/utils/structs/EnumerableSet.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/structs/EnumerableSet.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position of the value in the `values` array, plus 1 because index 0\n // means a value is not in the set.\n mapping(bytes32 => uint256) _indexes;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._indexes[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We read and store the value's index to prevent multiple reads from the same storage slot\n uint256 valueIndex = set._indexes[value];\n\n if (valueIndex != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 toDeleteIndex = valueIndex - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (lastIndex != toDeleteIndex) {\n bytes32 lastvalue = set._values[lastIndex];\n\n // Move the last value to the index where the value to delete is\n set._values[toDeleteIndex] = lastvalue;\n // Update the index for the moved value\n set._indexes[lastvalue] = valueIndex; // Replace lastvalue's index to valueIndex\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the index for the deleted slot\n delete set._indexes[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._indexes[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n return _values(set._inner);\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n assembly {\n result := store\n }\n\n return result;\n }\n}\n" + }, + "contracts/buyback/BaseBuyback.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { Strategizable } from \"../governance/Strategizable.sol\";\nimport \"../interfaces/chainlink/AggregatorV3Interface.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { ICVXLocker } from \"../interfaces/ICVXLocker.sol\";\nimport { ISwapper } from \"../interfaces/ISwapper.sol\";\n\nimport { Initializable } from \"../utils/Initializable.sol\";\n\nabstract contract BaseBuyback is Initializable, Strategizable {\n using SafeERC20 for IERC20;\n\n event SwapRouterUpdated(address indexed _address);\n\n event RewardsSourceUpdated(address indexed _address);\n event TreasuryManagerUpdated(address indexed _address);\n event CVXShareBpsUpdated(uint256 bps);\n\n // Emitted whenever OUSD/OETH is swapped for OGV/CVX or any other token\n event OTokenBuyback(\n address indexed oToken,\n address indexed swappedFor,\n uint256 swapAmountIn,\n uint256 minExpected\n );\n\n // Address of 1-inch Swap Router\n address public swapRouter;\n\n // slither-disable-next-line constable-states\n address private __deprecated_ousd;\n // slither-disable-next-line constable-states\n address private __deprecated_ogv;\n // slither-disable-next-line constable-states\n address private __deprecated_usdt;\n // slither-disable-next-line constable-states\n address private __deprecated_weth9;\n\n // Address that receives OGV after swaps\n address public rewardsSource;\n\n // Address that receives all other tokens after swaps\n address public treasuryManager;\n\n // slither-disable-next-line constable-states\n uint256 private __deprecated_treasuryBps;\n\n address public immutable oToken;\n address public immutable ogv;\n address public immutable cvx;\n address public immutable cvxLocker;\n\n // Amount of `oToken` balance to use for OGV buyback\n uint256 public balanceForOGV;\n\n // Amount of `oToken` balance to use for CVX buyback\n uint256 public balanceForCVX;\n\n // Percentage of `oToken` balance to be used for CVX\n uint256 public cvxShareBps; // 10000 = 100%\n\n constructor(\n address _oToken,\n address _ogv,\n address _cvx,\n address _cvxLocker\n ) {\n // Make sure nobody owns the implementation contract\n _setGovernor(address(0));\n\n oToken = _oToken;\n ogv = _ogv;\n cvx = _cvx;\n cvxLocker = _cvxLocker;\n }\n\n /**\n * @param _swapRouter Address of Uniswap V3 Router\n * @param _strategistAddr Address of Strategist multi-sig wallet\n * @param _treasuryManagerAddr Address that receives the treasury's share of OUSD\n * @param _rewardsSource Address of RewardsSource contract\n * @param _cvxShareBps Percentage of balance to use for CVX\n */\n function initialize(\n address _swapRouter,\n address _strategistAddr,\n address _treasuryManagerAddr,\n address _rewardsSource,\n uint256 _cvxShareBps\n ) external onlyGovernor initializer {\n _setStrategistAddr(_strategistAddr);\n\n _setSwapRouter(_swapRouter);\n _setRewardsSource(_rewardsSource);\n\n _setTreasuryManager(_treasuryManagerAddr);\n\n _setCVXShareBps(_cvxShareBps);\n }\n\n /**\n * @dev Set address of Uniswap Universal Router for performing liquidation\n * of platform fee tokens. Setting to 0x0 will pause swaps.\n *\n * @param _router Address of the Uniswap Universal router\n */\n function setSwapRouter(address _router) external onlyGovernor {\n _setSwapRouter(_router);\n }\n\n function _setSwapRouter(address _router) internal {\n address oldRouter = swapRouter;\n swapRouter = _router;\n\n if (oldRouter != address(0)) {\n // Remove allowance of old router, if any\n\n if (IERC20(ogv).allowance(address(this), oldRouter) != 0) {\n // slither-disable-next-line unused-return\n IERC20(ogv).safeApprove(oldRouter, 0);\n }\n\n if (IERC20(cvx).allowance(address(this), oldRouter) != 0) {\n // slither-disable-next-line unused-return\n IERC20(cvx).safeApprove(oldRouter, 0);\n }\n }\n\n emit SwapRouterUpdated(_router);\n }\n\n /**\n * @dev Sets the address that receives the OGV buyback rewards\n * @param _address Address\n */\n function setRewardsSource(address _address) external onlyGovernor {\n _setRewardsSource(_address);\n }\n\n function _setRewardsSource(address _address) internal {\n require(_address != address(0), \"Address not set\");\n rewardsSource = _address;\n emit RewardsSourceUpdated(_address);\n }\n\n /**\n * @dev Sets the address that can receive and manage the funds for Treasury\n * @param _address Address\n */\n function setTreasuryManager(address _address) external onlyGovernor {\n _setTreasuryManager(_address);\n }\n\n function _setTreasuryManager(address _address) internal {\n require(_address != address(0), \"Address not set\");\n treasuryManager = _address;\n emit TreasuryManagerUpdated(_address);\n }\n\n /**\n * @dev Sets the percentage of oToken to use for Flywheel tokens\n * @param _bps BPS, 10000 to 100%\n */\n function setCVXShareBps(uint256 _bps) external onlyGovernor {\n _setCVXShareBps(_bps);\n }\n\n function _setCVXShareBps(uint256 _bps) internal {\n require(_bps <= 10000, \"Invalid bps value\");\n cvxShareBps = _bps;\n emit CVXShareBpsUpdated(_bps);\n }\n\n /**\n * @dev Computes the split of oToken balance that can be\n * used for OGV and CVX buybacks.\n */\n function _updateBuybackSplits()\n internal\n returns (uint256 _balanceForOGV, uint256 _balanceForCVX)\n {\n _balanceForOGV = balanceForOGV;\n _balanceForCVX = balanceForCVX;\n\n uint256 totalBalance = IERC20(oToken).balanceOf(address(this));\n uint256 unsplitBalance = totalBalance - _balanceForOGV - _balanceForCVX;\n\n // Check if all balance is accounted for\n if (unsplitBalance != 0) {\n // If not, split unaccounted balance based on `cvxShareBps`\n uint256 addToCVX = (unsplitBalance * cvxShareBps) / 10000;\n _balanceForCVX = _balanceForCVX + addToCVX;\n _balanceForOGV = _balanceForOGV + unsplitBalance - addToCVX;\n\n // Update storage\n balanceForOGV = _balanceForOGV;\n balanceForCVX = _balanceForCVX;\n }\n }\n\n function updateBuybackSplits() external onlyGovernor {\n // slither-disable-next-line unused-return\n _updateBuybackSplits();\n }\n\n function _swapToken(\n address tokenOut,\n uint256 oTokenAmount,\n uint256 minAmountOut,\n bytes calldata swapData\n ) internal returns (uint256 amountOut) {\n require(oTokenAmount > 0, \"Invalid Swap Amount\");\n require(swapRouter != address(0), \"Swap Router not set\");\n require(minAmountOut > 0, \"Invalid minAmount\");\n\n // Transfer OToken to Swapper for swapping\n // slither-disable-next-line unchecked-transfer unused-return\n IERC20(oToken).transfer(swapRouter, oTokenAmount);\n\n // Swap\n amountOut = ISwapper(swapRouter).swap(\n oToken,\n tokenOut,\n oTokenAmount,\n minAmountOut,\n swapData\n );\n\n require(amountOut >= minAmountOut, \"Higher Slippage\");\n\n emit OTokenBuyback(oToken, tokenOut, minAmountOut, amountOut);\n }\n\n /**\n * @dev Swaps `oTokenAmount` to OGV\n * @param oTokenAmount Amount of OUSD/OETH to swap\n * @param minOGV Minimum OGV to receive for oTokenAmount\n * @param swapData 1inch Swap Data\n */\n function swapForOGV(\n uint256 oTokenAmount,\n uint256 minOGV,\n bytes calldata swapData\n ) external onlyGovernorOrStrategist nonReentrant {\n (uint256 _amountForOGV, ) = _updateBuybackSplits();\n require(_amountForOGV >= oTokenAmount, \"Balance underflow\");\n require(rewardsSource != address(0), \"RewardsSource contract not set\");\n\n unchecked {\n // Subtract the amount to swap from net balance\n balanceForOGV = _amountForOGV - oTokenAmount;\n }\n\n uint256 ogvReceived = _swapToken(ogv, oTokenAmount, minOGV, swapData);\n\n // Transfer OGV received to RewardsSource contract\n // slither-disable-next-line unchecked-transfer unused-return\n IERC20(ogv).transfer(rewardsSource, ogvReceived);\n }\n\n /**\n * @dev Swaps `oTokenAmount` to CVX\n * @param oTokenAmount Amount of OUSD/OETH to swap\n * @param minCVX Minimum CVX to receive for oTokenAmount\n * @param swapData 1inch Swap Data\n */\n function swapForCVX(\n uint256 oTokenAmount,\n uint256 minCVX,\n bytes calldata swapData\n ) external onlyGovernorOrStrategist nonReentrant {\n (, uint256 _amountForCVX) = _updateBuybackSplits();\n require(_amountForCVX >= oTokenAmount, \"Balance underflow\");\n\n unchecked {\n // Subtract the amount to swap from net balance\n balanceForCVX = _amountForCVX - oTokenAmount;\n }\n\n uint256 cvxReceived = _swapToken(cvx, oTokenAmount, minCVX, swapData);\n\n // Lock all CVX\n _lockAllCVX(cvxReceived);\n }\n\n /**\n * @dev Locks all CVX held by the contract on behalf of the Treasury Manager\n */\n function lockAllCVX() external onlyGovernorOrStrategist {\n _lockAllCVX(IERC20(cvx).balanceOf(address(this)));\n }\n\n function _lockAllCVX(uint256 cvxAmount) internal {\n require(\n treasuryManager != address(0),\n \"Treasury manager address not set\"\n );\n\n // Lock all available CVX on behalf of `treasuryManager`\n ICVXLocker(cvxLocker).lock(treasuryManager, cvxAmount, 0);\n }\n\n /**\n * @dev Approve CVX Locker to move CVX held by this contract\n */\n function safeApproveAllTokens() external onlyGovernorOrStrategist {\n IERC20(cvx).safeApprove(cvxLocker, type(uint256).max);\n }\n\n /**\n * @notice Owner function to withdraw a specific amount of a token\n * @param token token to be transferered\n * @param amount amount of the token to be transferred\n */\n function transferToken(address token, uint256 amount)\n external\n onlyGovernor\n nonReentrant\n {\n IERC20(token).safeTransfer(_governor(), amount);\n }\n}\n" + }, + "contracts/buyback/OETHBuyback.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { BaseBuyback } from \"./BaseBuyback.sol\";\n\ncontract OETHBuyback is BaseBuyback {\n constructor(\n address _oToken,\n address _ogv,\n address _cvx,\n address _cvxLocker\n ) BaseBuyback(_oToken, _ogv, _cvx, _cvxLocker) {}\n}\n" + }, + "contracts/buyback/OUSDBuyback.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { BaseBuyback } from \"./BaseBuyback.sol\";\n\ncontract OUSDBuyback is BaseBuyback {\n constructor(\n address _oToken,\n address _ogv,\n address _cvx,\n address _cvxLocker\n ) BaseBuyback(_oToken, _ogv, _cvx, _cvxLocker) {}\n}\n" + }, + "contracts/compensation/CompensationClaims.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\";\n\nimport { Initializable } from \"../utils/Initializable.sol\";\nimport { Governable } from \"../governance/Governable.sol\";\n\n/**\n * @title Compensation Claims\n * @author Origin Protocol Inc\n * @dev Airdrop for ERC20 tokens.\n *\n * Provides a coin airdrop with a verification period in which everyone\n * can check that all claims are correct before any actual funds are moved\n * to the contract.\n *\n * - Users can claim funds during the claim period.\n *\n * - The adjuster can set the amount of each user's claim,\n * but only when unlocked, and not during the claim period.\n *\n * - The governor can unlock and lock the adjuster, outside the claim period.\n * - The governor can start the claim period, if it's not started.\n * - The governor can collect any remaining funds after the claim period is over.\n *\n * Intended use sequence:\n *\n * 1. Governor unlocks the adjuster\n * 2. Adjuster uploads claims\n * 3. Governor locks the adjuster\n * 4. Everyone verifies that the claim amounts and totals are correct\n * 5. Payout funds are moved to the contract\n * 6. The claim period starts\n * 7. Users claim funds\n * 8. The claim period ends\n * 9. Governor can collect any remaing funds\n *\n */\ncontract CompensationClaims is Governable {\n address public adjuster;\n address public token;\n uint256 public end;\n uint256 public totalClaims;\n mapping(address => uint256) claims;\n bool public isAdjusterLocked;\n\n using SafeMath for uint256;\n\n event Claim(address indexed recipient, uint256 amount);\n event ClaimSet(address indexed recipient, uint256 amount);\n event Start(uint256 end);\n event Lock();\n event Unlock();\n event Collect(address indexed coin, uint256 amount);\n\n constructor(address _token, address _adjuster) onlyGovernor {\n token = _token;\n adjuster = _adjuster;\n isAdjusterLocked = true;\n }\n\n function balanceOf(address _account) external view returns (uint256) {\n return claims[_account];\n }\n\n function decimals() external view returns (uint8) {\n return IERC20Decimals(token).decimals();\n }\n\n /* -- User -- */\n\n function claim(address _recipient) external onlyInClaimPeriod nonReentrant {\n uint256 amount = claims[_recipient];\n require(amount > 0, \"Amount must be greater than 0\");\n claims[_recipient] = 0;\n totalClaims = totalClaims.sub(amount);\n SafeERC20.safeTransfer(IERC20(token), _recipient, amount);\n emit Claim(_recipient, amount);\n }\n\n /* -- Adjustor -- */\n\n function setClaims(\n address[] calldata _addresses,\n uint256[] calldata _amounts\n ) external notInClaimPeriod onlyUnlockedAdjuster {\n require(\n _addresses.length == _amounts.length,\n \"Addresses and amounts must match\"\n );\n uint256 len = _addresses.length;\n for (uint256 i = 0; i < len; i++) {\n address recipient = _addresses[i];\n uint256 newAmount = _amounts[i];\n uint256 oldAmount = claims[recipient];\n claims[recipient] = newAmount;\n totalClaims = totalClaims.add(newAmount).sub(oldAmount);\n emit ClaimSet(recipient, newAmount);\n }\n }\n\n /* -- Governor -- */\n\n function lockAdjuster() external onlyGovernor notInClaimPeriod {\n _lockAdjuster();\n }\n\n function _lockAdjuster() internal {\n isAdjusterLocked = true;\n emit Lock();\n }\n\n function unlockAdjuster() external onlyGovernor notInClaimPeriod {\n isAdjusterLocked = false;\n emit Unlock();\n }\n\n function start(uint256 _seconds)\n external\n onlyGovernor\n notInClaimPeriod\n nonReentrant\n {\n require(totalClaims > 0, \"No claims\");\n uint256 funding = IERC20(token).balanceOf(address(this));\n require(funding >= totalClaims, \"Insufficient funds for all claims\");\n _lockAdjuster();\n end = block.timestamp.add(_seconds);\n require(end.sub(block.timestamp) < 31622400, \"Duration too long\"); // 31622400 = 366*24*60*60\n emit Start(end);\n }\n\n function collect(address _coin)\n external\n onlyGovernor\n notInClaimPeriod\n nonReentrant\n {\n uint256 amount = IERC20(_coin).balanceOf(address(this));\n SafeERC20.safeTransfer(IERC20(_coin), address(governor()), amount);\n emit Collect(_coin, amount);\n }\n\n /* -- modifiers -- */\n\n modifier onlyInClaimPeriod() {\n require(block.timestamp <= end, \"Should be in claim period\");\n _;\n }\n\n modifier notInClaimPeriod() {\n require(block.timestamp > end, \"Should not be in claim period\");\n _;\n }\n\n modifier onlyUnlockedAdjuster() {\n require(isAdjusterLocked == false, \"Adjuster must be unlocked\");\n require(msg.sender == adjuster, \"Must be adjuster\");\n _;\n }\n}\n\ninterface IERC20Decimals {\n function decimals() external view returns (uint8);\n}\n" + }, + "contracts/echidna/Debugger.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nlibrary Debugger {\n event Debug(string debugString);\n event Debug(string description, string data);\n event Debug(string prefix, string description, string data);\n event Debug(string description, bytes32 data);\n event Debug(string prefix, string description, bytes32 data);\n event Debug(string description, uint256 data);\n event Debug(string prefix, string description, uint256 data);\n event Debug(string description, int256 data);\n event Debug(string prefix, string description, int256 data);\n event Debug(string description, address data);\n event Debug(string prefix, string description, address data);\n event Debug(string description, bool data);\n event Debug(string prefix, string description, bool data);\n\n function log(string memory debugString) internal {\n emit Debug(debugString);\n }\n\n function log(string memory description, string memory data) internal {\n emit Debug(description, data);\n }\n\n function log(\n string memory prefix,\n string memory description,\n string memory data\n ) internal {\n emit Debug(prefix, description, data);\n }\n\n function log(string memory description, bytes32 data) internal {\n emit Debug(description, data);\n }\n\n function log(\n string memory prefix,\n string memory description,\n bytes32 data\n ) internal {\n emit Debug(prefix, description, data);\n }\n\n function log(string memory description, uint256 data) internal {\n emit Debug(description, data);\n }\n\n function log(\n string memory prefix,\n string memory description,\n uint256 data\n ) internal {\n emit Debug(prefix, description, data);\n }\n\n function log(string memory description, int256 data) internal {\n emit Debug(description, data);\n }\n\n function log(\n string memory prefix,\n string memory description,\n int256 data\n ) internal {\n emit Debug(prefix, description, data);\n }\n\n function log(string memory description, address data) internal {\n emit Debug(description, data);\n }\n\n function log(\n string memory prefix,\n string memory description,\n address data\n ) internal {\n emit Debug(prefix, description, data);\n }\n\n function log(string memory description, bool data) internal {\n emit Debug(description, data);\n }\n\n function log(\n string memory prefix,\n string memory description,\n bool data\n ) internal {\n emit Debug(prefix, description, data);\n }\n}\n" + }, + "contracts/echidna/Echidna.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./EchidnaTestApproval.sol\";\n\n/**\n * @title Echidna test contract for OUSD\n * @notice Target contract to be tested, containing all mixins\n * @author Rappie\n */\ncontract Echidna is EchidnaTestApproval {\n\n}\n" + }, + "contracts/echidna/EchidnaConfig.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @title Top-level mixin for configuring the desired fuzzing setup\n * @author Rappie\n */\ncontract EchidnaConfig {\n address internal constant ADDRESS_VAULT = address(0x10000);\n address internal constant ADDRESS_OUTSIDER_USER = address(0x20000);\n\n address internal constant ADDRESS_USER0 = address(0x30000);\n address internal constant ADDRESS_USER1 = address(0x40000);\n\n // Will be set in EchidnaSetup constructor\n address internal ADDRESS_OUTSIDER_CONTRACT;\n address internal ADDRESS_CONTRACT0;\n address internal ADDRESS_CONTRACT1;\n\n // Toggle known issues\n //\n // This can be used to skip tests that are known to fail. This is useful\n // when debugging a specific issue, but should be disabled when running\n // the full test suite.\n //\n // True => skip tests that are known to fail\n // False => run all tests\n //\n bool internal constant TOGGLE_KNOWN_ISSUES = false;\n\n // Toggle known issues within limits\n //\n // Same as TOGGLE_KNOWN_ISSUES, but also skip tests that are known to fail\n // within limits set by the variables below.\n //\n bool internal constant TOGGLE_KNOWN_ISSUES_WITHIN_LIMITS = true;\n\n // Starting balance\n //\n // Gives OUSD a non-zero starting supply, which can be useful to ignore\n // certain edge cases.\n //\n // The starting balance is given to outsider accounts that are not used as\n // accounts while fuzzing.\n //\n bool internal constant TOGGLE_STARTING_BALANCE = true;\n uint256 internal constant STARTING_BALANCE = 1_000_000e18;\n\n // Change supply\n //\n // Set a limit to the amount of change per rebase, which can be useful to\n // ignore certain edge cases.\n //\n // True => limit the amount of change to a percentage of total supply\n // False => no limit\n //\n bool internal constant TOGGLE_CHANGESUPPLY_LIMIT = true;\n uint256 internal constant CHANGESUPPLY_DIVISOR = 10; // 10% of total supply\n\n // Mint limit\n //\n // Set a limit the the amount minted per mint, which can be useful to\n // ignore certain edge cases.\n //\n // True => limit the amount of minted tokens\n // False => no limit\n //\n bool internal constant TOGGLE_MINT_LIMIT = true;\n uint256 internal constant MINT_MODULO = 1_000_000_000_000e18;\n\n // Known rounding errors\n uint256 internal constant TRANSFER_ROUNDING_ERROR = 1e18 - 1;\n uint256 internal constant OPT_IN_ROUNDING_ERROR = 1e18 - 1;\n uint256 internal constant MINT_ROUNDING_ERROR = 1e18 - 1;\n\n /**\n * @notice Modifier to skip tests that are known to fail\n * @dev see TOGGLE_KNOWN_ISSUES for more information\n */\n modifier hasKnownIssue() {\n if (TOGGLE_KNOWN_ISSUES) return;\n _;\n }\n\n /**\n * @notice Modifier to skip tests that are known to fail within limits\n * @dev see TOGGLE_KNOWN_ISSUES_WITHIN_LIMITS for more information\n */\n modifier hasKnownIssueWithinLimits() {\n if (TOGGLE_KNOWN_ISSUES_WITHIN_LIMITS) return;\n _;\n }\n\n /**\n * @notice Translate an account ID to an address\n * @param accountId The ID of the account\n * @return account The address of the account\n */\n function getAccount(uint8 accountId)\n internal\n view\n returns (address account)\n {\n accountId = accountId / 64;\n if (accountId == 0) return account = ADDRESS_USER0;\n if (accountId == 1) return account = ADDRESS_USER1;\n if (accountId == 2) return account = ADDRESS_CONTRACT0;\n if (accountId == 3) return account = ADDRESS_CONTRACT1;\n require(false, \"Unknown account ID\");\n }\n}\n" + }, + "contracts/echidna/EchidnaDebug.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { Address } from \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport \"./EchidnaHelper.sol\";\nimport \"./Debugger.sol\";\n\nimport \"../token/OUSD.sol\";\n\n/**\n * @title Room for random debugging functions\n * @author Rappie\n */\ncontract EchidnaDebug is EchidnaHelper {\n function debugOUSD() public pure {\n // assert(ousd.balanceOf(ADDRESS_USER0) == 1000);\n // assert(ousd.rebaseState(ADDRESS_USER0) != OUSD.RebaseOptions.OptIn);\n // assert(Address.isContract(ADDRESS_CONTRACT0));\n // Debugger.log(\"nonRebasingSupply\", ousd.nonRebasingSupply());\n // assert(false);\n }\n}\n" + }, + "contracts/echidna/EchidnaHelper.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./EchidnaSetup.sol\";\nimport \"./Debugger.sol\";\n\n/**\n * @title Mixin containing helper functions\n * @author Rappie\n */\ncontract EchidnaHelper is EchidnaSetup {\n /**\n * @notice Mint tokens to an account\n * @param toAcc Account to mint to\n * @param amount Amount to mint\n * @return Amount minted (in case of capped mint with modulo)\n */\n function mint(uint8 toAcc, uint256 amount) public returns (uint256) {\n address to = getAccount(toAcc);\n\n if (TOGGLE_MINT_LIMIT) {\n amount = amount % MINT_MODULO;\n }\n\n hevm.prank(ADDRESS_VAULT);\n ousd.mint(to, amount);\n\n return amount;\n }\n\n /**\n * @notice Burn tokens from an account\n * @param fromAcc Account to burn from\n * @param amount Amount to burn\n */\n function burn(uint8 fromAcc, uint256 amount) public {\n address from = getAccount(fromAcc);\n hevm.prank(ADDRESS_VAULT);\n ousd.burn(from, amount);\n }\n\n /**\n * @notice Change the total supply of OUSD (rebase)\n * @param amount New total supply\n */\n function changeSupply(uint256 amount) public {\n if (TOGGLE_CHANGESUPPLY_LIMIT) {\n amount =\n ousd.totalSupply() +\n (amount % (ousd.totalSupply() / CHANGESUPPLY_DIVISOR));\n }\n\n hevm.prank(ADDRESS_VAULT);\n ousd.changeSupply(amount);\n }\n\n /**\n * @notice Transfer tokens between accounts\n * @param fromAcc Account to transfer from\n * @param toAcc Account to transfer to\n * @param amount Amount to transfer\n */\n function transfer(\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public {\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n hevm.prank(from);\n // slither-disable-next-line unchecked-transfer\n ousd.transfer(to, amount);\n }\n\n /**\n * @notice Transfer approved tokens between accounts\n * @param authorizedAcc Account that is authorized to transfer\n * @param fromAcc Account to transfer from\n * @param toAcc Account to transfer to\n * @param amount Amount to transfer\n */\n function transferFrom(\n uint8 authorizedAcc,\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public {\n address authorized = getAccount(authorizedAcc);\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n hevm.prank(authorized);\n // slither-disable-next-line unchecked-transfer\n ousd.transferFrom(from, to, amount);\n }\n\n /**\n * @notice Opt in to rebasing\n * @param targetAcc Account to opt in\n */\n function optIn(uint8 targetAcc) public {\n address target = getAccount(targetAcc);\n hevm.prank(target);\n ousd.rebaseOptIn();\n }\n\n /**\n * @notice Opt out of rebasing\n * @param targetAcc Account to opt out\n */\n function optOut(uint8 targetAcc) public {\n address target = getAccount(targetAcc);\n hevm.prank(target);\n ousd.rebaseOptOut();\n }\n\n /**\n * @notice Approve an account to spend OUSD\n * @param ownerAcc Account that owns the OUSD\n * @param spenderAcc Account that is approved to spend the OUSD\n * @param amount Amount to approve\n */\n function approve(\n uint8 ownerAcc,\n uint8 spenderAcc,\n uint256 amount\n ) public {\n address owner = getAccount(ownerAcc);\n address spender = getAccount(spenderAcc);\n hevm.prank(owner);\n // slither-disable-next-line unused-return\n ousd.approve(spender, amount);\n }\n\n /**\n * @notice Increase the allowance of an account to spend OUSD\n * @param ownerAcc Account that owns the OUSD\n * @param spenderAcc Account that is approved to spend the OUSD\n * @param amount Amount to increase the allowance by\n */\n function increaseAllowance(\n uint8 ownerAcc,\n uint8 spenderAcc,\n uint256 amount\n ) public {\n address owner = getAccount(ownerAcc);\n address spender = getAccount(spenderAcc);\n hevm.prank(owner);\n // slither-disable-next-line unused-return\n ousd.increaseAllowance(spender, amount);\n }\n\n /**\n * @notice Decrease the allowance of an account to spend OUSD\n * @param ownerAcc Account that owns the OUSD\n * @param spenderAcc Account that is approved to spend the OUSD\n * @param amount Amount to decrease the allowance by\n */\n function decreaseAllowance(\n uint8 ownerAcc,\n uint8 spenderAcc,\n uint256 amount\n ) public {\n address owner = getAccount(ownerAcc);\n address spender = getAccount(spenderAcc);\n hevm.prank(owner);\n // slither-disable-next-line unused-return\n ousd.decreaseAllowance(spender, amount);\n }\n\n /**\n * @notice Get the sum of all OUSD balances\n * @return total Total balance\n */\n function getTotalBalance() public view returns (uint256 total) {\n total += ousd.balanceOf(ADDRESS_VAULT);\n total += ousd.balanceOf(ADDRESS_OUTSIDER_USER);\n total += ousd.balanceOf(ADDRESS_OUTSIDER_CONTRACT);\n total += ousd.balanceOf(ADDRESS_USER0);\n total += ousd.balanceOf(ADDRESS_USER1);\n total += ousd.balanceOf(ADDRESS_CONTRACT0);\n total += ousd.balanceOf(ADDRESS_CONTRACT1);\n }\n\n /**\n * @notice Get the sum of all non-rebasing OUSD balances\n * @return total Total balance\n */\n function getTotalNonRebasingBalance() public returns (uint256 total) {\n total += ousd._isNonRebasingAccountEchidna(ADDRESS_VAULT)\n ? ousd.balanceOf(ADDRESS_VAULT)\n : 0;\n total += ousd._isNonRebasingAccountEchidna(ADDRESS_OUTSIDER_USER)\n ? ousd.balanceOf(ADDRESS_OUTSIDER_USER)\n : 0;\n total += ousd._isNonRebasingAccountEchidna(ADDRESS_OUTSIDER_CONTRACT)\n ? ousd.balanceOf(ADDRESS_OUTSIDER_CONTRACT)\n : 0;\n total += ousd._isNonRebasingAccountEchidna(ADDRESS_USER0)\n ? ousd.balanceOf(ADDRESS_USER0)\n : 0;\n total += ousd._isNonRebasingAccountEchidna(ADDRESS_USER1)\n ? ousd.balanceOf(ADDRESS_USER1)\n : 0;\n total += ousd._isNonRebasingAccountEchidna(ADDRESS_CONTRACT0)\n ? ousd.balanceOf(ADDRESS_CONTRACT0)\n : 0;\n total += ousd._isNonRebasingAccountEchidna(ADDRESS_CONTRACT1)\n ? ousd.balanceOf(ADDRESS_CONTRACT1)\n : 0;\n }\n}\n" + }, + "contracts/echidna/EchidnaSetup.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./IHevm.sol\";\nimport \"./EchidnaConfig.sol\";\nimport \"./OUSDEchidna.sol\";\n\ncontract Dummy {}\n\n/**\n * @title Mixin for setup and deployment\n * @author Rappie\n */\ncontract EchidnaSetup is EchidnaConfig {\n IHevm hevm = IHevm(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D);\n OUSDEchidna ousd = new OUSDEchidna();\n\n /**\n * @notice Deploy the OUSD contract and set up initial state\n */\n constructor() {\n ousd.initialize(\"Origin Dollar\", \"OUSD\", ADDRESS_VAULT, 1e18);\n\n // Deploy dummny contracts as users\n Dummy outsider = new Dummy();\n ADDRESS_OUTSIDER_CONTRACT = address(outsider);\n Dummy dummy0 = new Dummy();\n ADDRESS_CONTRACT0 = address(dummy0);\n Dummy dummy1 = new Dummy();\n ADDRESS_CONTRACT1 = address(dummy1);\n\n // Start out with a reasonable amount of OUSD\n if (TOGGLE_STARTING_BALANCE) {\n // Rebasing tokens\n hevm.prank(ADDRESS_VAULT);\n ousd.mint(ADDRESS_OUTSIDER_USER, STARTING_BALANCE / 2);\n\n // Non-rebasing tokens\n hevm.prank(ADDRESS_VAULT);\n ousd.mint(ADDRESS_OUTSIDER_CONTRACT, STARTING_BALANCE / 2);\n }\n }\n}\n" + }, + "contracts/echidna/EchidnaTestAccounting.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./EchidnaDebug.sol\";\nimport \"./EchidnaTestSupply.sol\";\n\n/**\n * @title Mixin for testing accounting functions\n * @author Rappie\n */\ncontract EchidnaTestAccounting is EchidnaTestSupply {\n /**\n * @notice After opting in, balance should not increase. (Ok to lose rounding funds doing this)\n * @param targetAcc Account to opt in\n */\n function testOptInBalance(uint8 targetAcc) public {\n address target = getAccount(targetAcc);\n\n uint256 balanceBefore = ousd.balanceOf(target);\n optIn(targetAcc);\n uint256 balanceAfter = ousd.balanceOf(target);\n\n assert(balanceAfter <= balanceBefore);\n }\n\n /**\n * @notice After opting out, balance should remain the same\n * @param targetAcc Account to opt out\n */\n function testOptOutBalance(uint8 targetAcc) public {\n address target = getAccount(targetAcc);\n\n uint256 balanceBefore = ousd.balanceOf(target);\n optOut(targetAcc);\n uint256 balanceAfter = ousd.balanceOf(target);\n\n assert(balanceAfter == balanceBefore);\n }\n\n /**\n * @notice Account balance should remain the same after opting in minus rounding error\n * @param targetAcc Account to opt in\n */\n function testOptInBalanceRounding(uint8 targetAcc) public {\n address target = getAccount(targetAcc);\n\n uint256 balanceBefore = ousd.balanceOf(target);\n optIn(targetAcc);\n uint256 balanceAfter = ousd.balanceOf(target);\n\n int256 delta = int256(balanceAfter) - int256(balanceBefore);\n Debugger.log(\"delta\", delta);\n\n // slither-disable-next-line tautology\n assert(-1 * delta >= 0);\n assert(-1 * delta <= int256(OPT_IN_ROUNDING_ERROR));\n }\n\n /**\n * @notice After opting in, total supply should remain the same\n * @param targetAcc Account to opt in\n */\n function testOptInTotalSupply(uint8 targetAcc) public {\n uint256 totalSupplyBefore = ousd.totalSupply();\n optIn(targetAcc);\n uint256 totalSupplyAfter = ousd.totalSupply();\n\n assert(totalSupplyAfter == totalSupplyBefore);\n }\n\n /**\n * @notice After opting out, total supply should remain the same\n * @param targetAcc Account to opt out\n */\n function testOptOutTotalSupply(uint8 targetAcc) public {\n uint256 totalSupplyBefore = ousd.totalSupply();\n optOut(targetAcc);\n uint256 totalSupplyAfter = ousd.totalSupply();\n\n assert(totalSupplyAfter == totalSupplyBefore);\n }\n\n /**\n * @notice Account balance should remain the same when a smart contract auto converts\n * @param targetAcc Account to auto convert\n */\n function testAutoConvertBalance(uint8 targetAcc) public {\n address target = getAccount(targetAcc);\n\n uint256 balanceBefore = ousd.balanceOf(target);\n // slither-disable-next-line unused-return\n ousd._isNonRebasingAccountEchidna(target);\n uint256 balanceAfter = ousd.balanceOf(target);\n\n assert(balanceAfter == balanceBefore);\n }\n\n /**\n * @notice The `balanceOf` function should never revert\n * @param targetAcc Account to check balance of\n */\n function testBalanceOfShouldNotRevert(uint8 targetAcc) public {\n address target = getAccount(targetAcc);\n\n // slither-disable-next-line unused-return\n try ousd.balanceOf(target) {\n assert(true);\n } catch {\n assert(false);\n }\n }\n}\n" + }, + "contracts/echidna/EchidnaTestApproval.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./EchidnaTestMintBurn.sol\";\nimport \"./Debugger.sol\";\n\n/**\n * @title Mixin for testing approval related functions\n * @author Rappie\n */\ncontract EchidnaTestApproval is EchidnaTestMintBurn {\n /**\n * @notice Performing `transferFrom` with an amount inside the allowance should not revert\n * @param authorizedAcc The account that is authorized to transfer\n * @param fromAcc The account that is transferring\n * @param toAcc The account that is receiving\n * @param amount The amount to transfer\n */\n function testTransferFromShouldNotRevert(\n uint8 authorizedAcc,\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public {\n address authorized = getAccount(authorizedAcc);\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n\n require(amount <= ousd.balanceOf(from));\n require(amount <= ousd.allowance(from, authorized));\n\n hevm.prank(authorized);\n // slither-disable-next-line unchecked-transfer\n try ousd.transferFrom(from, to, amount) {\n // pass\n } catch {\n assert(false);\n }\n }\n\n /**\n * @notice Performing `transferFrom` with an amount outside the allowance should revert\n * @param authorizedAcc The account that is authorized to transfer\n * @param fromAcc The account that is transferring\n * @param toAcc The account that is receiving\n * @param amount The amount to transfer\n */\n function testTransferFromShouldRevert(\n uint8 authorizedAcc,\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public {\n address authorized = getAccount(authorizedAcc);\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n\n require(amount > 0);\n require(\n !(amount <= ousd.balanceOf(from) &&\n amount <= ousd.allowance(from, authorized))\n );\n\n hevm.prank(authorized);\n // slither-disable-next-line unchecked-transfer\n try ousd.transferFrom(from, to, amount) {\n assert(false);\n } catch {\n // pass\n }\n }\n\n /**\n * @notice Approving an amount should update the allowance and overwrite any previous allowance\n * @param ownerAcc The account that is approving\n * @param spenderAcc The account that is being approved\n * @param amount The amount to approve\n */\n function testApprove(\n uint8 ownerAcc,\n uint8 spenderAcc,\n uint256 amount\n ) public {\n address owner = getAccount(ownerAcc);\n address spender = getAccount(spenderAcc);\n\n approve(ownerAcc, spenderAcc, amount);\n uint256 allowanceAfter1 = ousd.allowance(owner, spender);\n\n assert(allowanceAfter1 == amount);\n\n approve(ownerAcc, spenderAcc, amount / 2);\n uint256 allowanceAfter2 = ousd.allowance(owner, spender);\n\n assert(allowanceAfter2 == amount / 2);\n }\n\n /**\n * @notice Increasing the allowance should raise it by the amount provided\n * @param ownerAcc The account that is approving\n * @param spenderAcc The account that is being approved\n * @param amount The amount to approve\n */\n function testIncreaseAllowance(\n uint8 ownerAcc,\n uint8 spenderAcc,\n uint256 amount\n ) public {\n address owner = getAccount(ownerAcc);\n address spender = getAccount(spenderAcc);\n\n uint256 allowanceBefore = ousd.allowance(owner, spender);\n increaseAllowance(ownerAcc, spenderAcc, amount);\n uint256 allowanceAfter = ousd.allowance(owner, spender);\n\n assert(allowanceAfter == allowanceBefore + amount);\n }\n\n /**\n * @notice Decreasing the allowance should lower it by the amount provided\n * @param ownerAcc The account that is approving\n * @param spenderAcc The account that is being approved\n * @param amount The amount to approve\n */\n function testDecreaseAllowance(\n uint8 ownerAcc,\n uint8 spenderAcc,\n uint256 amount\n ) public {\n address owner = getAccount(ownerAcc);\n address spender = getAccount(spenderAcc);\n\n uint256 allowanceBefore = ousd.allowance(owner, spender);\n decreaseAllowance(ownerAcc, spenderAcc, amount);\n uint256 allowanceAfter = ousd.allowance(owner, spender);\n\n assert(allowanceAfter == allowanceBefore - amount);\n }\n}\n" + }, + "contracts/echidna/EchidnaTestMintBurn.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./EchidnaDebug.sol\";\nimport \"./EchidnaTestAccounting.sol\";\n\n/**\n * @title Mixin for testing Mint and Burn functions\n * @author Rappie\n */\ncontract EchidnaTestMintBurn is EchidnaTestAccounting {\n /**\n * @notice Minting 0 tokens should not affect account balance\n * @param targetAcc Account to mint to\n */\n function testMintZeroBalance(uint8 targetAcc) public {\n address target = getAccount(targetAcc);\n\n uint256 balanceBefore = ousd.balanceOf(target);\n mint(targetAcc, 0);\n uint256 balanceAfter = ousd.balanceOf(target);\n\n assert(balanceAfter == balanceBefore);\n }\n\n /**\n * @notice Burning 0 tokens should not affect account balance\n * @param targetAcc Account to burn from\n */\n function testBurnZeroBalance(uint8 targetAcc) public {\n address target = getAccount(targetAcc);\n\n uint256 balanceBefore = ousd.balanceOf(target);\n burn(targetAcc, 0);\n uint256 balanceAfter = ousd.balanceOf(target);\n\n assert(balanceAfter == balanceBefore);\n }\n\n /**\n * @notice Minting tokens must increase the account balance by at least amount\n * @param targetAcc Account to mint to\n * @param amount Amount to mint\n * @custom:error testMintBalance(uint8,uint256): failed!💥\n * Call sequence:\n * changeSupply(1)\n * testMintBalance(0,1)\n * Event sequence:\n * Debug(«balanceBefore», 0)\n * Debug(«balanceAfter», 0)\n */\n function testMintBalance(uint8 targetAcc, uint256 amount)\n public\n hasKnownIssue\n hasKnownIssueWithinLimits\n {\n address target = getAccount(targetAcc);\n\n uint256 balanceBefore = ousd.balanceOf(target);\n uint256 amountMinted = mint(targetAcc, amount);\n uint256 balanceAfter = ousd.balanceOf(target);\n\n Debugger.log(\"amountMinted\", amountMinted);\n Debugger.log(\"balanceBefore\", balanceBefore);\n Debugger.log(\"balanceAfter\", balanceAfter);\n\n assert(balanceAfter >= balanceBefore + amountMinted);\n }\n\n /**\n * @notice Burning tokens must decrease the account balance by at least amount\n * @param targetAcc Account to burn from\n * @param amount Amount to burn\n * @custom:error testBurnBalance(uint8,uint256): failed!💥\n * Call sequence:\n * changeSupply(1)\n * mint(0,3)\n * testBurnBalance(0,1)\n * Event sequence:\n * Debug(«balanceBefore», 2)\n * Debug(«balanceAfter», 2)\n */\n function testBurnBalance(uint8 targetAcc, uint256 amount)\n public\n hasKnownIssue\n hasKnownIssueWithinLimits\n {\n address target = getAccount(targetAcc);\n\n uint256 balanceBefore = ousd.balanceOf(target);\n burn(targetAcc, amount);\n uint256 balanceAfter = ousd.balanceOf(target);\n\n Debugger.log(\"balanceBefore\", balanceBefore);\n Debugger.log(\"balanceAfter\", balanceAfter);\n\n assert(balanceAfter <= balanceBefore - amount);\n }\n\n /**\n * @notice Minting tokens should not increase the account balance by less than rounding error above amount\n * @param targetAcc Account to mint to\n * @param amount Amount to mint\n */\n function testMintBalanceRounding(uint8 targetAcc, uint256 amount) public {\n address target = getAccount(targetAcc);\n\n uint256 balanceBefore = ousd.balanceOf(target);\n uint256 amountMinted = mint(targetAcc, amount);\n uint256 balanceAfter = ousd.balanceOf(target);\n\n int256 delta = int256(balanceAfter) - int256(balanceBefore);\n\n // delta == amount, if no error\n // delta < amount, if too little is minted\n // delta > amount, if too much is minted\n int256 error = int256(amountMinted) - delta;\n\n assert(error >= 0);\n assert(error <= int256(MINT_ROUNDING_ERROR));\n }\n\n /**\n * @notice A burn of an account balance must result in a zero balance\n * @param targetAcc Account to burn from\n */\n function testBurnAllBalanceToZero(uint8 targetAcc) public hasKnownIssue {\n address target = getAccount(targetAcc);\n\n burn(targetAcc, ousd.balanceOf(target));\n assert(ousd.balanceOf(target) == 0);\n }\n\n /**\n * @notice You should always be able to burn an account's balance\n * @param targetAcc Account to burn from\n */\n function testBurnAllBalanceShouldNotRevert(uint8 targetAcc)\n public\n hasKnownIssue\n {\n address target = getAccount(targetAcc);\n uint256 balance = ousd.balanceOf(target);\n\n hevm.prank(ADDRESS_VAULT);\n try ousd.burn(target, balance) {\n assert(true);\n } catch {\n assert(false);\n }\n }\n}\n" + }, + "contracts/echidna/EchidnaTestSupply.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./EchidnaDebug.sol\";\nimport \"./EchidnaTestTransfer.sol\";\n\nimport { StableMath } from \"../utils/StableMath.sol\";\n\n/**\n * @title Mixin for testing supply related functions\n * @author Rappie\n */\ncontract EchidnaTestSupply is EchidnaTestTransfer {\n using StableMath for uint256;\n\n uint256 prevRebasingCreditsPerToken = type(uint256).max;\n\n /**\n * @notice After a `changeSupply`, the total supply should exactly\n * match the target total supply. (This is needed to ensure successive\n * rebases are correct).\n * @param supply New total supply\n * @custom:error testChangeSupply(uint256): failed!💥\n * Call sequence:\n * testChangeSupply(1044505275072865171609)\n * Event sequence:\n * TotalSupplyUpdatedHighres(1044505275072865171610, 1000000000000000000000000, 957391048054055578595)\n */\n function testChangeSupply(uint256 supply)\n public\n hasKnownIssue\n hasKnownIssueWithinLimits\n {\n hevm.prank(ADDRESS_VAULT);\n ousd.changeSupply(supply);\n\n assert(ousd.totalSupply() == supply);\n }\n\n /**\n * @notice The total supply must not be less than the sum of account balances.\n * (The difference will go into future rebases)\n * @custom:error testTotalSupplyLessThanTotalBalance(): failed!💥\n * Call sequence:\n * mint(0,1)\n * changeSupply(1)\n * optOut(64)\n * transfer(0,64,1)\n * testTotalSupplyLessThanTotalBalance()\n * Event sequence:\n * Debug(«totalSupply», 1000000000000000001000001)\n * Debug(«totalBalance», 1000000000000000001000002)\n */\n function testTotalSupplyLessThanTotalBalance()\n public\n hasKnownIssue\n hasKnownIssueWithinLimits\n {\n uint256 totalSupply = ousd.totalSupply();\n uint256 totalBalance = getTotalBalance();\n\n Debugger.log(\"totalSupply\", totalSupply);\n Debugger.log(\"totalBalance\", totalBalance);\n\n assert(totalSupply >= totalBalance);\n }\n\n /**\n * @notice Non-rebasing supply should not be larger than total supply\n * @custom:error testNonRebasingSupplyVsTotalSupply(): failed!💥\n * Call sequence:\n * mint(0,2)\n * changeSupply(3)\n * burn(0,1)\n * optOut(0)\n * testNonRebasingSupplyVsTotalSupply()\n */\n function testNonRebasingSupplyVsTotalSupply() public hasKnownIssue {\n uint256 nonRebasingSupply = ousd.nonRebasingSupply();\n uint256 totalSupply = ousd.totalSupply();\n\n assert(nonRebasingSupply <= totalSupply);\n }\n\n /**\n * @notice Global `rebasingCreditsPerToken` should never increase\n * @custom:error testRebasingCreditsPerTokenNotIncreased(): failed!💥\n * Call sequence:\n * testRebasingCreditsPerTokenNotIncreased()\n * changeSupply(1)\n * testRebasingCreditsPerTokenNotIncreased()\n */\n function testRebasingCreditsPerTokenNotIncreased() public hasKnownIssue {\n uint256 curRebasingCreditsPerToken = ousd\n .rebasingCreditsPerTokenHighres();\n\n Debugger.log(\n \"prevRebasingCreditsPerToken\",\n prevRebasingCreditsPerToken\n );\n Debugger.log(\"curRebasingCreditsPerToken\", curRebasingCreditsPerToken);\n\n assert(curRebasingCreditsPerToken <= prevRebasingCreditsPerToken);\n\n prevRebasingCreditsPerToken = curRebasingCreditsPerToken;\n }\n\n /**\n * @notice The rebasing credits per token ratio must greater than zero\n */\n function testRebasingCreditsPerTokenAboveZero() public {\n assert(ousd.rebasingCreditsPerTokenHighres() > 0);\n }\n\n /**\n * @notice The sum of all non-rebasing balances should not be larger than\n * non-rebasing supply\n * @custom:error testTotalNonRebasingSupplyLessThanTotalBalance(): failed!💥\n * Call sequence\n * mint(0,2)\n * changeSupply(1)\n * optOut(0)\n * burn(0,1)\n * testTotalNonRebasingSupplyLessThanTotalBalance()\n * Event sequence:\n * Debug(«totalNonRebasingSupply», 500000000000000000000001)\n * Debug(«totalNonRebasingBalance», 500000000000000000000002)\n */\n function testTotalNonRebasingSupplyLessThanTotalBalance()\n public\n hasKnownIssue\n hasKnownIssueWithinLimits\n {\n uint256 totalNonRebasingSupply = ousd.nonRebasingSupply();\n uint256 totalNonRebasingBalance = getTotalNonRebasingBalance();\n\n Debugger.log(\"totalNonRebasingSupply\", totalNonRebasingSupply);\n Debugger.log(\"totalNonRebasingBalance\", totalNonRebasingBalance);\n\n assert(totalNonRebasingSupply >= totalNonRebasingBalance);\n }\n\n /**\n * @notice An accounts credits / credits per token should not be larger it's balance\n * @param targetAcc The account to check\n */\n function testCreditsPerTokenVsBalance(uint8 targetAcc) public {\n address target = getAccount(targetAcc);\n\n (uint256 credits, uint256 creditsPerToken, ) = ousd\n .creditsBalanceOfHighres(target);\n uint256 expectedBalance = credits.divPrecisely(creditsPerToken);\n\n uint256 balance = ousd.balanceOf(target);\n\n Debugger.log(\"credits\", credits);\n Debugger.log(\"creditsPerToken\", creditsPerToken);\n Debugger.log(\"expectedBalance\", expectedBalance);\n Debugger.log(\"balance\", balance);\n\n assert(expectedBalance == balance);\n }\n}\n" + }, + "contracts/echidna/EchidnaTestTransfer.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./EchidnaDebug.sol\";\nimport \"./Debugger.sol\";\n\n/**\n * @title Mixin for testing transfer related functions\n * @author Rappie\n */\ncontract EchidnaTestTransfer is EchidnaDebug {\n /**\n * @notice The receiving account's balance after a transfer must not increase by\n * less than the amount transferred\n * @param fromAcc Account to transfer from\n * @param toAcc Account to transfer to\n * @param amount Amount to transfer\n * @custom:error testTransferBalanceReceivedLess(uint8,uint8,uint256): failed!💥\n * Call sequence:\n * changeSupply(1)\n * mint(64,2)\n * testTransferBalanceReceivedLess(64,0,1)\n * Event sequence:\n * Debug(«totalSupply», 1000000000000000000500002)\n * Debug(«toBalBefore», 0)\n * Debug(«toBalAfter», 0)\n */\n function testTransferBalanceReceivedLess(\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public hasKnownIssue hasKnownIssueWithinLimits {\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n\n require(from != to);\n\n uint256 toBalBefore = ousd.balanceOf(to);\n transfer(fromAcc, toAcc, amount);\n uint256 toBalAfter = ousd.balanceOf(to);\n\n Debugger.log(\"totalSupply\", ousd.totalSupply());\n Debugger.log(\"toBalBefore\", toBalBefore);\n Debugger.log(\"toBalAfter\", toBalAfter);\n\n assert(toBalAfter >= toBalBefore + amount);\n }\n\n /**\n * @notice The receiving account's balance after a transfer must not\n * increase by more than the amount transferred\n * @param fromAcc Account to transfer from\n * @param toAcc Account to transfer to\n * @param amount Amount to transfer\n */\n function testTransferBalanceReceivedMore(\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public {\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n\n require(from != to);\n\n uint256 toBalBefore = ousd.balanceOf(to);\n transfer(fromAcc, toAcc, amount);\n uint256 toBalAfter = ousd.balanceOf(to);\n\n Debugger.log(\"totalSupply\", ousd.totalSupply());\n Debugger.log(\"toBalBefore\", toBalBefore);\n Debugger.log(\"toBalAfter\", toBalAfter);\n\n assert(toBalAfter <= toBalBefore + amount);\n }\n\n /**\n * @notice The sending account's balance after a transfer must not\n * decrease by less than the amount transferred\n * @param fromAcc Account to transfer from\n * @param toAcc Account to transfer to\n * @param amount Amount to transfer\n * @custom:error testTransferBalanceSentLess(uint8,uint8,uint256): failed!💥\n * Call sequence:\n * mint(0,1)\n * changeSupply(1)\n * testTransferBalanceSentLess(0,64,1)\n * Event sequence:\n * Debug(«totalSupply», 1000000000000000000500001)\n * Debug(«fromBalBefore», 1)\n * Debug(«fromBalAfter», 1)\n */\n function testTransferBalanceSentLess(\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public hasKnownIssue hasKnownIssueWithinLimits {\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n\n require(from != to);\n\n uint256 fromBalBefore = ousd.balanceOf(from);\n transfer(fromAcc, toAcc, amount);\n uint256 fromBalAfter = ousd.balanceOf(from);\n\n Debugger.log(\"totalSupply\", ousd.totalSupply());\n Debugger.log(\"fromBalBefore\", fromBalBefore);\n Debugger.log(\"fromBalAfter\", fromBalAfter);\n\n assert(fromBalAfter <= fromBalBefore - amount);\n }\n\n /**\n * @notice The sending account's balance after a transfer must not\n * decrease by more than the amount transferred\n * @param fromAcc Account to transfer from\n * @param toAcc Account to transfer to\n * @param amount Amount to transfer\n */\n function testTransferBalanceSentMore(\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public {\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n\n require(from != to);\n\n uint256 fromBalBefore = ousd.balanceOf(from);\n transfer(fromAcc, toAcc, amount);\n uint256 fromBalAfter = ousd.balanceOf(from);\n\n Debugger.log(\"totalSupply\", ousd.totalSupply());\n Debugger.log(\"fromBalBefore\", fromBalBefore);\n Debugger.log(\"fromBalAfter\", fromBalAfter);\n\n assert(fromBalAfter >= fromBalBefore - amount);\n }\n\n /**\n * @notice The receiving account's balance after a transfer must not\n * increase by less than the amount transferred (minus rounding error)\n * @param fromAcc Account to transfer from\n * @param toAcc Account to transfer to\n * @param amount Amount to transfer\n */\n function testTransferBalanceReceivedLessRounding(\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public {\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n\n require(from != to);\n\n uint256 toBalBefore = ousd.balanceOf(to);\n transfer(fromAcc, toAcc, amount);\n uint256 toBalAfter = ousd.balanceOf(to);\n\n int256 toDelta = int256(toBalAfter) - int256(toBalBefore);\n\n // delta == amount, if no error\n // delta < amount, if too little is sent\n // delta > amount, if too much is sent\n int256 error = int256(amount) - toDelta;\n\n Debugger.log(\"totalSupply\", ousd.totalSupply());\n Debugger.log(\"toBalBefore\", toBalBefore);\n Debugger.log(\"toBalAfter\", toBalAfter);\n Debugger.log(\"toDelta\", toDelta);\n Debugger.log(\"error\", error);\n\n assert(error >= 0);\n assert(error <= int256(TRANSFER_ROUNDING_ERROR));\n }\n\n /**\n * @notice The sending account's balance after a transfer must\n * not decrease by less than the amount transferred (minus rounding error)\n * @param fromAcc Account to transfer from\n * @param toAcc Account to transfer to\n * @param amount Amount to transfer\n */\n function testTransferBalanceSentLessRounding(\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public {\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n\n require(from != to);\n\n uint256 fromBalBefore = ousd.balanceOf(from);\n transfer(fromAcc, toAcc, amount);\n uint256 fromBalAfter = ousd.balanceOf(from);\n\n int256 fromDelta = int256(fromBalAfter) - int256(fromBalBefore);\n\n // delta == -amount, if no error\n // delta < -amount, if too much is sent\n // delta > -amount, if too little is sent\n int256 error = int256(amount) + fromDelta;\n\n Debugger.log(\"totalSupply\", ousd.totalSupply());\n Debugger.log(\"fromBalBefore\", fromBalBefore);\n Debugger.log(\"fromBalAfter\", fromBalAfter);\n Debugger.log(\"fromDelta\", fromDelta);\n Debugger.log(\"error\", error);\n\n assert(error >= 0);\n assert(error <= int256(TRANSFER_ROUNDING_ERROR));\n }\n\n /**\n * @notice An account should always be able to successfully transfer\n * an amount within its balance.\n * @param fromAcc Account to transfer from\n * @param toAcc Account to transfer to\n * @param amount Amount to transfer\n * @custom:error testTransferWithinBalanceDoesNotRevert(uint8,uint8,uint8): failed!💥\n * Call sequence:\n * mint(0,1)\n * changeSupply(3)\n * optOut(0)\n * testTransferWithinBalanceDoesNotRevert(0,128,2)\n * optIn(0)\n * testTransferWithinBalanceDoesNotRevert(128,0,1)\n * Event sequence:\n * error Revert Panic(17): SafeMath over-/under-flows\n */\n function testTransferWithinBalanceDoesNotRevert(\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public hasKnownIssue {\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n\n require(amount > 0);\n amount = amount % ousd.balanceOf(from);\n\n Debugger.log(\"Total supply\", ousd.totalSupply());\n\n hevm.prank(from);\n // slither-disable-next-line unchecked-transfer\n try ousd.transfer(to, amount) {\n assert(true);\n } catch {\n assert(false);\n }\n }\n\n /**\n * @notice An account should never be able to successfully transfer\n * an amount greater than their balance.\n * @param fromAcc Account to transfer from\n * @param toAcc Account to transfer to\n * @param amount Amount to transfer\n */\n function testTransferExceedingBalanceReverts(\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public {\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n\n amount = ousd.balanceOf(from) + 1 + amount;\n\n hevm.prank(from);\n // slither-disable-next-line unchecked-transfer\n try ousd.transfer(to, amount) {\n assert(false);\n } catch {\n assert(true);\n }\n }\n\n /**\n * @notice A transfer to the same account should not change that account's balance\n * @param targetAcc Account to transfer to\n * @param amount Amount to transfer\n */\n function testTransferSelf(uint8 targetAcc, uint256 amount) public {\n address target = getAccount(targetAcc);\n\n uint256 balanceBefore = ousd.balanceOf(target);\n transfer(targetAcc, targetAcc, amount);\n uint256 balanceAfter = ousd.balanceOf(target);\n\n assert(balanceBefore == balanceAfter);\n }\n\n /**\n * @notice Transfers to the zero account revert\n * @param fromAcc Account to transfer from\n * @param amount Amount to transfer\n */\n function testTransferToZeroAddress(uint8 fromAcc, uint256 amount) public {\n address from = getAccount(fromAcc);\n\n hevm.prank(from);\n // slither-disable-next-line unchecked-transfer\n try ousd.transfer(address(0), amount) {\n assert(false);\n } catch {\n assert(true);\n }\n }\n}\n" + }, + "contracts/echidna/IHevm.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n// https://github.com/ethereum/hevm/blob/main/doc/src/controlling-the-unit-testing-environment.md#cheat-codes\n\ninterface IHevm {\n function warp(uint256 x) external;\n\n function roll(uint256 x) external;\n\n function store(\n address c,\n bytes32 loc,\n bytes32 val\n ) external;\n\n function load(address c, bytes32 loc) external returns (bytes32 val);\n\n function sign(uint256 sk, bytes32 digest)\n external\n returns (\n uint8 v,\n bytes32 r,\n bytes32 s\n );\n\n function addr(uint256 sk) external returns (address addr);\n\n function ffi(string[] calldata) external returns (bytes memory);\n\n function prank(address sender) external;\n}\n" + }, + "contracts/echidna/OUSDEchidna.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../token/OUSD.sol\";\n\ncontract OUSDEchidna is OUSD {\n constructor() OUSD() {}\n\n function _isNonRebasingAccountEchidna(address _account)\n public\n returns (bool)\n {\n return _isNonRebasingAccount(_account);\n }\n}\n" + }, + "contracts/flipper/Flipper.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../governance/Governable.sol\";\nimport \"../token/OUSD.sol\";\nimport \"../interfaces/Tether.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Contract to exchange usdt, usdc, dai from and to ousd.\n// - 1 to 1. No slippage\n// - Optimized for low gas usage\n// - No guarantee of availability\n\ncontract Flipper is Governable {\n using SafeERC20 for IERC20;\n\n uint256 constant MAXIMUM_PER_TRADE = (25000 * 1e18);\n\n // Settable coin addresses allow easy testing and use of mock currencies.\n IERC20 immutable dai;\n OUSD immutable ousd;\n IERC20 immutable usdc;\n Tether immutable usdt;\n\n // ---------------------\n // Dev constructor\n // ---------------------\n constructor(\n address _dai,\n address _ousd,\n address _usdc,\n address _usdt\n ) {\n require(address(_dai) != address(0));\n require(address(_ousd) != address(0));\n require(address(_usdc) != address(0));\n require(address(_usdt) != address(0));\n dai = IERC20(_dai);\n ousd = OUSD(_ousd);\n usdc = IERC20(_usdc);\n usdt = Tether(_usdt);\n }\n\n // -----------------\n // Trading functions\n // -----------------\n\n /// @notice Purchase OUSD with Dai\n /// @param amount Amount of OUSD to purchase, in 18 fixed decimals.\n function buyOusdWithDai(uint256 amount) external {\n require(amount <= MAXIMUM_PER_TRADE, \"Amount too large\");\n require(\n dai.transferFrom(msg.sender, address(this), amount),\n \"DAI transfer failed\"\n );\n require(ousd.transfer(msg.sender, amount), \"OUSD transfer failed\");\n }\n\n /// @notice Sell OUSD for Dai\n /// @param amount Amount of OUSD to sell, in 18 fixed decimals.\n function sellOusdForDai(uint256 amount) external {\n require(amount <= MAXIMUM_PER_TRADE, \"Amount too large\");\n require(dai.transfer(msg.sender, amount), \"DAI transfer failed\");\n require(\n ousd.transferFrom(msg.sender, address(this), amount),\n \"OUSD transfer failed\"\n );\n }\n\n /// @notice Purchase OUSD with USDC\n /// @param amount Amount of OUSD to purchase, in 18 fixed decimals.\n function buyOusdWithUsdc(uint256 amount) external {\n require(amount <= MAXIMUM_PER_TRADE, \"Amount too large\");\n // Potential rounding error is an intentional trade off\n require(\n usdc.transferFrom(msg.sender, address(this), amount / 1e12),\n \"USDC transfer failed\"\n );\n require(ousd.transfer(msg.sender, amount), \"OUSD transfer failed\");\n }\n\n /// @notice Sell OUSD for USDC\n /// @param amount Amount of OUSD to sell, in 18 fixed decimals.\n function sellOusdForUsdc(uint256 amount) external {\n require(amount <= MAXIMUM_PER_TRADE, \"Amount too large\");\n require(\n usdc.transfer(msg.sender, amount / 1e12),\n \"USDC transfer failed\"\n );\n require(\n ousd.transferFrom(msg.sender, address(this), amount),\n \"OUSD transfer failed\"\n );\n }\n\n /// @notice Purchase OUSD with USDT\n /// @param amount Amount of OUSD to purchase, in 18 fixed decimals.\n function buyOusdWithUsdt(uint256 amount) external {\n require(amount <= MAXIMUM_PER_TRADE, \"Amount too large\");\n // Potential rounding error is an intentional trade off\n // USDT does not return a boolean and reverts,\n // so no need for a require.\n usdt.transferFrom(msg.sender, address(this), amount / 1e12);\n require(ousd.transfer(msg.sender, amount), \"OUSD transfer failed\");\n }\n\n /// @notice Sell OUSD for USDT\n /// @param amount Amount of OUSD to sell, in 18 fixed decimals.\n function sellOusdForUsdt(uint256 amount) external {\n require(amount <= MAXIMUM_PER_TRADE, \"Amount too large\");\n // USDT does not return a boolean and reverts,\n // so no need for a require.\n usdt.transfer(msg.sender, amount / 1e12);\n require(\n ousd.transferFrom(msg.sender, address(this), amount),\n \"OUSD transfer failed\"\n );\n }\n\n // --------------------\n // Governance functions\n // --------------------\n\n /// @dev Opting into yield reduces the gas cost per transfer by about 4K, since\n /// ousd needs to do less accounting and one less storage write.\n function rebaseOptIn() external onlyGovernor nonReentrant {\n ousd.rebaseOptIn();\n }\n\n /// @notice Owner function to withdraw a specific amount of a token\n function withdraw(address token, uint256 amount)\n external\n onlyGovernor\n nonReentrant\n {\n IERC20(token).safeTransfer(_governor(), amount);\n }\n\n /// @notice Owner function to withdraw all tradable tokens\n /// @dev Contract will not perform any swaps until liquidity is provided\n /// again by transferring assets to the contract.\n function withdrawAll() external onlyGovernor nonReentrant {\n IERC20(dai).safeTransfer(_governor(), dai.balanceOf(address(this)));\n IERC20(ousd).safeTransfer(_governor(), ousd.balanceOf(address(this)));\n IERC20(address(usdt)).safeTransfer(\n _governor(),\n usdt.balanceOf(address(this))\n );\n IERC20(usdc).safeTransfer(_governor(), usdc.balanceOf(address(this)));\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/governance/Governor.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./../timelock/Timelock.sol\";\n\n// Modeled off of Compound's Governor Alpha\n// https://github.com/compound-finance/compound-protocol/blob/master/contracts/Governance/GovernorAlpha.sol\ncontract Governor is Timelock {\n // @notice The total number of proposals\n uint256 public proposalCount;\n\n struct Proposal {\n // @notice Unique id for looking up a proposal\n uint256 id;\n // @notice Creator of the proposal\n address proposer;\n // @notice The timestamp that the proposal will be available for\n // execution, set once the vote succeeds\n uint256 eta;\n // @notice the ordered list of target addresses for calls to be made\n address[] targets;\n // @notice The ordered list of function signatures to be called\n string[] signatures;\n // @notice The ordered list of calldata to be passed to each call\n bytes[] calldatas;\n // @notice Flag marking whether the proposal has been executed\n bool executed;\n }\n\n // @notice The official record of all proposals ever proposed\n mapping(uint256 => Proposal) public proposals;\n\n // @notice An event emitted when a new proposal is created\n event ProposalCreated(\n uint256 id,\n address proposer,\n address[] targets,\n string[] signatures,\n bytes[] calldatas,\n string description\n );\n\n // @notice An event emitted when a proposal has been queued in the Timelock\n event ProposalQueued(uint256 id, uint256 eta);\n\n // @notice An event emitted when a proposal has been executed in the Timelock\n event ProposalExecuted(uint256 id);\n\n // @notice An event emitted when a proposal has been cancelled\n event ProposalCancelled(uint256 id);\n\n uint256 public constant MAX_OPERATIONS = 32;\n\n // @notice Possible states that a proposal may be in\n enum ProposalState {\n Pending,\n Queued,\n Expired,\n Executed\n }\n\n constructor(address admin_, uint256 delay_) Timelock(admin_, delay_) {}\n\n /**\n * @notice Propose Governance call(s)\n * @param targets Ordered list of targeted addresses\n * @param signatures Orderd list of function signatures to be called\n * @param calldatas Orderded list of calldata to be passed with each call\n * @param description Description of the governance\n * @return uint256 id of the proposal\n */\n function propose(\n address[] memory targets,\n string[] memory signatures,\n bytes[] memory calldatas,\n string memory description\n ) public returns (uint256) {\n // Allow anyone to propose for now, since only admin can queue the\n // transaction it should be harmless, you just need to pay the gas\n require(\n targets.length == signatures.length &&\n targets.length == calldatas.length,\n \"Governor::propose: proposal function information arity mismatch\"\n );\n require(targets.length != 0, \"Governor::propose: must provide actions\");\n require(\n targets.length <= MAX_OPERATIONS,\n \"Governor::propose: too many actions\"\n );\n\n proposalCount++;\n Proposal memory newProposal = Proposal({\n id: proposalCount,\n proposer: msg.sender,\n eta: 0,\n targets: targets,\n signatures: signatures,\n calldatas: calldatas,\n executed: false\n });\n\n proposals[newProposal.id] = newProposal;\n\n emit ProposalCreated(\n newProposal.id,\n msg.sender,\n targets,\n signatures,\n calldatas,\n description\n );\n return newProposal.id;\n }\n\n /**\n * @notice Queue a proposal for execution\n * @param proposalId id of the proposal to queue\n */\n function queue(uint256 proposalId) public onlyAdmin {\n require(\n state(proposalId) == ProposalState.Pending,\n \"Governor::queue: proposal can only be queued if it is pending\"\n );\n Proposal storage proposal = proposals[proposalId];\n proposal.eta = block.timestamp + delay;\n\n for (uint256 i = 0; i < proposal.targets.length; i++) {\n _queueOrRevert(\n proposal.targets[i],\n proposal.signatures[i],\n proposal.calldatas[i],\n proposal.eta\n );\n }\n\n emit ProposalQueued(proposal.id, proposal.eta);\n }\n\n /**\n * @notice Get the state of a proposal\n * @param proposalId id of the proposal\n * @return ProposalState\n */\n function state(uint256 proposalId) public view returns (ProposalState) {\n require(\n proposalCount >= proposalId && proposalId > 0,\n \"Governor::state: invalid proposal id\"\n );\n Proposal storage proposal = proposals[proposalId];\n if (proposal.executed) {\n return ProposalState.Executed;\n } else if (proposal.eta == 0) {\n return ProposalState.Pending;\n } else if (block.timestamp >= proposal.eta + GRACE_PERIOD) {\n return ProposalState.Expired;\n } else {\n return ProposalState.Queued;\n }\n }\n\n function _queueOrRevert(\n address target,\n string memory signature,\n bytes memory data,\n uint256 eta\n ) internal {\n require(\n !queuedTransactions[\n keccak256(abi.encode(target, signature, keccak256(data), eta))\n ],\n \"Governor::_queueOrRevert: proposal action already queued at eta\"\n );\n require(\n queuedTransactions[queueTransaction(target, signature, data, eta)],\n \"Governor::_queueOrRevert: failed to queue transaction\"\n );\n }\n\n /**\n * @notice Execute a proposal.\n * @param proposalId id of the proposal\n */\n function execute(uint256 proposalId) public {\n require(\n state(proposalId) == ProposalState.Queued,\n \"Governor::execute: proposal can only be executed if it is queued\"\n );\n Proposal storage proposal = proposals[proposalId];\n proposal.executed = true;\n for (uint256 i = 0; i < proposal.targets.length; i++) {\n executeTransaction(\n proposal.targets[i],\n proposal.signatures[i],\n proposal.calldatas[i],\n proposal.eta\n );\n }\n emit ProposalExecuted(proposalId);\n }\n\n /**\n * @notice Cancel a proposal.\n * @param proposalId id of the proposal\n */\n function cancel(uint256 proposalId) public onlyAdmin {\n ProposalState proposalState = state(proposalId);\n\n require(\n proposalState == ProposalState.Queued ||\n proposalState == ProposalState.Pending,\n \"Governor::execute: proposal can only be cancelled if it is queued or pending\"\n );\n Proposal storage proposal = proposals[proposalId];\n proposal.eta = 1; // To mark the proposal as `Expired`\n for (uint256 i = 0; i < proposal.targets.length; i++) {\n cancelTransaction(\n proposal.targets[i],\n proposal.signatures[i],\n proposal.calldatas[i],\n proposal.eta\n );\n }\n emit ProposalCancelled(proposalId);\n }\n\n /**\n * @notice Get the actions that a proposal will take.\n * @param proposalId id of the proposal\n */\n function getActions(uint256 proposalId)\n public\n view\n returns (\n address[] memory targets,\n string[] memory signatures,\n bytes[] memory calldatas\n )\n {\n Proposal storage p = proposals[proposalId];\n return (p.targets, p.signatures, p.calldatas);\n }\n}\n" + }, + "contracts/governance/InitializableGovernable.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @title OUSD InitializableGovernable Contract\n * @author Origin Protocol Inc\n */\nimport { Initializable } from \"../utils/Initializable.sol\";\n\nimport { Governable } from \"./Governable.sol\";\n\ncontract InitializableGovernable is Governable, Initializable {\n function _initialize(address _newGovernor) internal {\n _changeGovernor(_newGovernor);\n }\n}\n" + }, + "contracts/governance/Strategizable.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { Governable } from \"./Governable.sol\";\n\ncontract Strategizable is Governable {\n event StrategistUpdated(address _address);\n\n // Address of strategist\n address public strategistAddr;\n\n // For future use\n uint256[50] private __gap;\n\n /**\n * @dev Verifies that the caller is either 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 * @dev Set address of Strategist\n * @param _address Address of Strategist\n */\n function setStrategistAddr(address _address) external onlyGovernor {\n _setStrategistAddr(_address);\n }\n\n /**\n * @dev Set address of Strategist\n * @param _address Address of Strategist\n */\n function _setStrategistAddr(address _address) internal {\n strategistAddr = _address;\n emit StrategistUpdated(_address);\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 transfering `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/IOracleWeightedPool.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n// The three values that can be queried:\n//\n// - PAIR_PRICE: the price of the tokens in the Pool, expressed as the price of the second token in units of the\n// first token. For example, if token A is worth $2, and token B is worth $4, the pair price will be 2.0.\n// Note that the price is computed *including* the tokens decimals. This means that the pair price of a Pool with\n// DAI and USDC will be close to 1.0, despite DAI having 18 decimals and USDC 6.\n//\n// - BPT_PRICE: the price of the Pool share token (BPT), in units of the first token.\n// Note that the price is computed *including* the tokens decimals. This means that the BPT price of a Pool with\n// USDC in which BPT is worth $5 will be 5.0, despite the BPT having 18 decimals and USDC 6.\n//\n// - INVARIANT: the value of the Pool's invariant, which serves as a measure of its liquidity.\nenum Variable {\n PAIR_PRICE,\n BPT_PRICE,\n INVARIANT\n}\n\n/**\n * @dev Information for a Time Weighted Average query.\n *\n * Each query computes the average over a window of duration `secs` seconds that ended `ago` seconds ago. For\n * example, the average over the past 30 minutes is computed by settings secs to 1800 and ago to 0. If secs is 1800\n * and ago is 1800 as well, the average between 60 and 30 minutes ago is computed instead.\n */\nstruct OracleAverageQuery {\n Variable variable;\n uint256 secs;\n uint256 ago;\n}\n\ninterface IOracleWeightedPool {\n /**\n * @dev Returns the time average weighted price corresponding to each of `queries`. Prices are represented as 18\n * decimal fixed point values.\n */\n function getTimeWeightedAverage(OracleAverageQuery[] memory queries)\n external\n view\n returns (uint256[] memory results);\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/chainlink/AggregatorV3Interface.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface AggregatorV3Interface {\n function decimals() external view returns (uint8);\n\n function description() external view returns (string memory);\n\n function version() external view returns (uint256);\n\n // getRoundData and latestRoundData should both raise \"No data present\"\n // if they do not have data to report, instead of returning unset values\n // which could be misinterpreted as actual reported values.\n function getRoundData(uint80 _roundId)\n external\n view\n returns (\n uint80 roundId,\n int256 answer,\n uint256 startedAt,\n uint256 updatedAt,\n uint80 answeredInRound\n );\n\n function latestRoundData()\n external\n view\n returns (\n uint80 roundId,\n int256 answer,\n uint256 startedAt,\n uint256 updatedAt,\n uint80 answeredInRound\n );\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/IBuyback.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IBuyback {\n function swap() external;\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/ICVXLocker.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface ICVXLocker {\n function lock(\n address _account,\n uint256 _amount,\n uint256 _spendRatio\n ) external;\n\n function lockedBalanceOf(address _account) external view returns (uint256);\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/IEthUsdOracle.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IEthUsdOracle {\n /**\n * @notice Returns ETH price in USD.\n * @return Price in USD with 6 decimal digits.\n */\n function ethUsdPrice() external view returns (uint256);\n\n /**\n * @notice Returns token price in USD.\n * @param symbol. Asset symbol. For ex. \"DAI\".\n * @return Price in USD with 6 decimal digits.\n */\n function tokUsdPrice(string calldata symbol)\n external\n view\n returns (uint256);\n\n /**\n * @notice Returns the asset price in ETH.\n * @param symbol. Asset symbol. For ex. \"DAI\".\n * @return Price in ETH with 8 decimal digits.\n */\n function tokEthPrice(string calldata symbol)\n external\n view\n returns (uint256);\n}\n\ninterface IViewEthUsdOracle {\n /**\n * @notice Returns ETH price in USD.\n * @return Price in USD with 6 decimal digits.\n */\n function ethUsdPrice() external view returns (uint256);\n\n /**\n * @notice Returns token price in USD.\n * @param symbol. Asset symbol. For ex. \"DAI\".\n * @return Price in USD with 6 decimal digits.\n */\n function tokUsdPrice(string calldata symbol)\n external\n view\n returns (uint256);\n\n /**\n * @notice Returns the asset price in ETH.\n * @param symbol. Asset symbol. For ex. \"DAI\".\n * @return Price in ETH with 8 decimal digits.\n */\n function tokEthPrice(string calldata symbol)\n external\n view\n returns (uint256);\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/IMinMaxOracle.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IMinMaxOracle {\n //Assuming 8 decimals\n function priceMin(string calldata symbol) external view returns (uint256);\n\n function priceMax(string calldata symbol) external view returns (uint256);\n}\n" + }, + "contracts/interfaces/IOneInch.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/// 1Inch swap data\nstruct SwapDescription {\n IERC20 srcToken; // contract address of a token to sell\n IERC20 dstToken; // contract address of a token to buy\n address payable srcReceiver;\n address payable dstReceiver; // Receiver of destination currency. default: fromAddress\n uint256 amount;\n uint256 minReturnAmount;\n uint256 flags;\n}\n\n/// @title Interface for making arbitrary calls during swap\ninterface IAggregationExecutor {\n /// @notice propagates information about original msg.sender and executes arbitrary data\n function execute(address msgSender) external payable; // 0x4b64e492\n}\n\ninterface IOneInchRouter {\n /// @notice Performs a swap, delegating all calls encoded in `data` to `executor`.\n function swap(\n IAggregationExecutor executor,\n SwapDescription calldata desc,\n bytes calldata permit,\n bytes calldata data\n ) external returns (uint256 returnAmount, uint256 spentAmount);\n\n /// @notice Performs swap using Uniswap exchange. Wraps and unwraps ETH if required.\n function unoswapTo(\n address payable recipient,\n IERC20 srcToken,\n uint256 amount,\n uint256 minReturn,\n uint256[] calldata pools\n ) external payable returns (uint256 returnAmount);\n\n /// @notice Performs swap using Uniswap V3 exchange. Wraps and unwraps ETH if required.\n function uniswapV3SwapTo(\n address payable recipient,\n uint256 amount,\n uint256 minReturn,\n uint256[] calldata pools\n ) external payable returns (uint256 returnAmount);\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/IPriceOracle.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IPriceOracle {\n /**\n * @dev returns the asset price in USD, 6 decimal digits.\n * Compatible with the Open Price Feed.\n */\n function price(string calldata symbol) external view returns (uint256);\n}\n" + }, + "contracts/interfaces/IRETH.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IRETH {\n function getEthValue(uint256 _rethAmount) external view returns (uint256);\n\n function getRethValue(uint256 _ethAmount) external view returns (uint256);\n\n function getExchangeRate() external view returns (uint256);\n\n function totalSupply() external view returns (uint256);\n\n function balanceOf(address account) external view returns (uint256);\n\n function transfer(address recipient, uint256 amount)\n external\n returns (bool);\n\n function allowance(address owner, address spender)\n external\n view\n returns (uint256);\n\n function approve(address spender, uint256 amount) external returns (bool);\n\n function transferFrom(\n address sender,\n address recipient,\n uint256 amount\n ) external returns (bool);\n\n function name() external view returns (string memory);\n\n function symbol() external view returns (string memory);\n\n function decimals() external view returns (uint8);\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 error ApprovalNotWithinTimeframe();\n error CallerNotOwner();\n error CallerNotWhitelisted();\n error ClusterAlreadyEnabled();\n error ClusterDoesNotExists();\n error ClusterIsLiquidated();\n error ClusterNotLiquidatable();\n error ExceedValidatorLimit();\n error FeeExceedsIncreaseLimit();\n error FeeIncreaseNotAllowed();\n error FeeTooHigh();\n error FeeTooLow();\n error IncorrectClusterState();\n error IncorrectValidatorState();\n error InsufficientBalance();\n error InvalidOperatorIdsLength();\n error InvalidPublicKeyLength();\n error MaxValueExceeded();\n error NewBlockPeriodIsBelowMinimum();\n error NoFeeDeclared();\n error NotAuthorized();\n error OperatorAlreadyExists();\n error OperatorDoesNotExist();\n error OperatorsListNotUnique();\n error SameFeeChangeNotAllowed();\n error TargetModuleDoesNotExist();\n error TokenTransferFailed();\n error UnsortedOperatorsList();\n error ValidatorAlreadyExists();\n error ValidatorDoesNotExist();\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 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 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 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/ITimelock.sol": { + "content": "pragma solidity ^0.8.0;\n\ninterface ITimelock {\n function delay() external view returns (uint256);\n\n function GRACE_PERIOD() external view returns (uint256);\n\n function acceptAdmin() external;\n\n function queuedTransactions(bytes32 hash) external view returns (bool);\n\n function queueTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) external returns (bytes32);\n\n function cancelTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) external;\n\n function executeTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) external payable returns (bytes memory);\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\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" + }, + "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/Tether.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface Tether {\n function transfer(address to, uint256 value) external;\n\n function transferFrom(\n address from,\n address to,\n uint256 value\n ) external;\n\n function balanceOf(address) external returns (uint256);\n}\n" + }, + "contracts/interfaces/uniswap/IUniswapUniversalRouter.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IUniswapUniversalRouter {\n /// @notice Executes encoded commands along with provided inputs. Reverts if deadline has expired.\n /// @param commands A set of concatenated commands, each 1 byte in length\n /// @param inputs An array of byte strings containing abi encoded inputs for each command\n /// @param deadline The deadline by which the transaction must be executed\n function execute(\n bytes calldata commands,\n bytes[] calldata inputs,\n uint256 deadline\n ) external payable;\n\n function execute(bytes calldata commands, bytes[] calldata inputs)\n external\n payable;\n}\n" + }, + "contracts/interfaces/uniswap/IUniswapV2Pair.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IUniswapV2Pair {\n function token0() external view returns (address);\n\n function token1() external view returns (address);\n\n function getReserves()\n external\n view\n returns (\n uint112 reserve0,\n uint112 reserve1,\n uint32 blockTimestampLast\n );\n\n function price0CumulativeLast() external view returns (uint256);\n\n function price1CumulativeLast() external view returns (uint256);\n\n function sync() external;\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/liquidity/LiquidityReward.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { SafeMath } from \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\n\nimport { Initializable } from \"../utils/Initializable.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\nimport { Governable } from \"../governance/Governable.sol\";\n\n//\n// LiquidityReward contract doles out reward for liquidity\n// base off of Sushiswap's MasterChef: https://github.com/sushiswap/sushiswap/blob/master/contracts/MasterChef.sol\n//\ncontract LiquidityReward is Initializable, Governable {\n using SafeMath for uint256;\n using StableMath for uint256;\n using SafeERC20 for IERC20;\n\n // Info of each user.\n struct UserInfo {\n uint256 amount; // How many LP tokens the user has provided.\n int256 rewardDebt; // Reward debt. See explanation below.\n //\n // We do some fancy math here. Basically, any point in time, the amount of Reward Tokens\n // entitled to a user but is pending to be distributed is:\n //\n // pending reward = (user.amount * pool.accRewardPerShare) - user.rewardDebt\n //\n // Whenever a user deposits or withdraws LP tokens to a pool. Here's what happens:\n // 1. The pool's `accRewardPerShare` (and `lastRewardBlock`) gets updated.\n // 2. User receives the pending reward sent to his/her address.\n // 3. User's `amount` gets updated.\n // 4. User's `rewardDebt` gets updated.\n //\n // NOTE: rewardDebt can go negative because we allow withdraws without claiming the reward\n // in that case we owe the account holder some reward.\n }\n\n // Info of each pool.\n struct PoolInfo {\n IERC20 lpToken; // Address of LP token contract.\n uint256 lastRewardBlock; // Last block number that Reward calculation occurs.\n uint256 accRewardPerShare; // Accumulated Reward per share in reward precision. See below.\n }\n\n // The Reward token\n IERC20 public reward;\n\n // Reward tokens created per block in 1e18 precision.\n uint256 public rewardPerBlock;\n\n // Info on the LP.\n PoolInfo public pool;\n // total Reward debt, useful to calculate if we have enough to pay out all rewards\n int256 public totalRewardDebt;\n // total Supply that is accounted for via deposit/withdraw so that our rewards calc are stable\n uint256 public totalSupply;\n // Info of each user that stakes LP tokens.\n mapping(address => UserInfo) public userInfo;\n // The block number when Liquidity rewards ends.\n uint256 public endBlock;\n\n event CampaignStarted(\n uint256 rewardRate,\n uint256 startBlock,\n uint256 endBlock\n );\n event CampaignStopped(uint256 endBlock);\n event Deposit(address indexed user, uint256 amount);\n event Withdraw(address indexed user, uint256 amount);\n event Claim(address indexed user, uint256 amount);\n event DrainExtraReward(address indexed user, uint256 amount);\n event DrainExtraLP(address indexed user, uint256 amount);\n\n /**\n * Initializer for setting up Liquidity Reward internal state.\n * @param _reward Address of the reward token(OGN)\n * @param _lpToken Address of the LP token(Uniswap Pair)\n */\n function initialize(IERC20 _reward, IERC20 _lpToken)\n external\n onlyGovernor\n initializer\n {\n reward = _reward;\n pool.lpToken = _lpToken;\n pool.lastRewardBlock = block.number;\n }\n\n /**\n * @dev start a new reward campaign.\n * This will calculate all rewards up to the current block at the old rate.\n * This ensures that we pay everyone at the promised rate before update to the new rate.\n * @param _rewardPerBlock Amount rewarded per block\n * @param _startBlock Block number that we want to start the rewards at (0 for current block)\n * @param _numBlocks number of blocks that the campaign should last\n */\n function startCampaign(\n uint256 _rewardPerBlock,\n uint256 _startBlock,\n uint256 _numBlocks\n ) external onlyGovernor {\n // Calculate up to the current block at the current rate for everyone.\n updatePool();\n\n // total Pending calculated at the current pool rate\n uint256 totalPending = subDebt(\n pool.accRewardPerShare.mulTruncate(totalSupply),\n totalRewardDebt\n );\n\n require(_numBlocks > 0, \"startCampaign: zero blocks\");\n\n require(\n reward.balanceOf(address(this)) >=\n _rewardPerBlock.mul(_numBlocks).add(totalPending),\n \"startCampaign: insufficient rewards\"\n );\n\n uint256 startBlock = _startBlock;\n if (startBlock == 0) {\n // start block number isn't given so we start at the current\n startBlock = block.number;\n }\n require(\n startBlock >= block.number,\n \"startCampaign: _startBlock can't be in the past\"\n );\n endBlock = startBlock.add(_numBlocks);\n // we don't start accrue until the startBlock\n pool.lastRewardBlock = startBlock;\n // new blocks start at the new reward rate\n rewardPerBlock = _rewardPerBlock;\n emit CampaignStarted(rewardPerBlock, startBlock, endBlock);\n }\n\n function stopCampaign() external onlyGovernor {\n //calculate until current pool\n updatePool();\n //end the block here (the CampaignMultiplier will be zero)\n endBlock = block.number;\n emit CampaignStopped(endBlock);\n }\n\n function drainExtraRewards() external onlyGovernor {\n require(endBlock < block.number, \"drainExtraRewards:Campaign active\");\n updatePool();\n uint256 extraRewards = reward.balanceOf(address(this)).sub(\n subDebt(\n pool.accRewardPerShare.mulTruncate(totalSupply),\n totalRewardDebt\n )\n );\n if (extraRewards > 0) {\n emit DrainExtraReward(msg.sender, extraRewards);\n reward.safeTransfer(msg.sender, extraRewards);\n }\n }\n\n function drainExtraLP() external onlyGovernor {\n uint256 extraLP = pool.lpToken.balanceOf(address(this)).sub(\n totalSupply\n );\n require(extraLP > 0, \"drainExtraLP:no extra\");\n emit DrainExtraLP(msg.sender, extraLP);\n pool.lpToken.safeTransfer(msg.sender, extraLP);\n }\n\n function campaignActive() external view returns (bool) {\n return endBlock > block.number && block.number >= pool.lastRewardBlock;\n }\n\n function balanceOf(address _account) external view returns (uint256) {\n return userInfo[_account].amount;\n }\n\n /**\n * @dev calculate the number of blocks since we last updated\n * within start and end as constraints\n * @param _to Block number of the ending point.\n * @return multiplier Multiplier over the given _from to _to block.\n */\n function getCampaignMultiplier(uint256 _to)\n internal\n view\n returns (uint256)\n {\n uint256 from = pool.lastRewardBlock;\n if (from > endBlock) {\n return 0;\n } else {\n return (_to < endBlock ? _to : endBlock).sub(from);\n }\n }\n\n /**\n * @dev View function to see pending rewards for each account on frontend.\n * @param _user Address of the account we're looking up.\n * @return reward Total rewards owed to this account.\n */\n function pendingRewards(address _user) external view returns (uint256) {\n UserInfo storage user = userInfo[_user];\n return _pendingRewards(user);\n }\n\n function _pendingRewards(UserInfo storage user)\n internal\n view\n returns (uint256)\n {\n uint256 accRewardPerShare = pool.accRewardPerShare;\n if (block.number > pool.lastRewardBlock) {\n if (totalSupply != 0) {\n uint256 multiplier = getCampaignMultiplier(block.number);\n uint256 incReward = multiplier.mul(rewardPerBlock);\n accRewardPerShare = accRewardPerShare.add(\n incReward.divPrecisely(totalSupply)\n );\n }\n }\n return\n subDebt(\n user.amount.mulTruncate(accRewardPerShare),\n user.rewardDebt\n );\n }\n\n /**\n * @dev View function to see total outstanding rewards for the entire contract.\n * This is how much is owed when everyone pulls out.\n * @return reward Total rewards owed to everyone.\n */\n function totalOutstandingRewards() external view returns (uint256) {\n if (block.number > pool.lastRewardBlock && totalSupply != 0) {\n uint256 multiplier = getCampaignMultiplier(block.number);\n uint256 incReward = multiplier.mul(rewardPerBlock);\n uint256 accRewardPerShare = pool.accRewardPerShare;\n accRewardPerShare = accRewardPerShare.add(\n incReward.divPrecisely(totalSupply)\n );\n return\n subDebt(\n accRewardPerShare.mulTruncate(totalSupply),\n totalRewardDebt\n );\n }\n // no supply or not even started\n return 0;\n }\n\n /**\n * @dev External call for updating the pool.\n */\n function doUpdatePool() external {\n // There should be no harm allowing anyone to call this function.\n // It just updates the latest accRewardPerShare for the pool.\n updatePool();\n }\n\n /**\n * @dev Update the Liquidity Pool reward multiplier.\n * This locks in the accRewardPerShare from the last update block number to now.\n * Will fail if we do not have enough to pay everyone.\n * Always call updatePool whenever the balance changes!\n */\n function updatePool() internal {\n if (\n block.number <= pool.lastRewardBlock ||\n endBlock <= pool.lastRewardBlock\n ) {\n return;\n }\n\n if (totalSupply == 0) {\n pool.lastRewardBlock = block.number;\n return;\n }\n\n uint256 incReward = getCampaignMultiplier(block.number).mul(\n rewardPerBlock\n );\n // we are of course assuming lpTokens are in 1e18 precision\n uint256 accRewardPerShare = pool.accRewardPerShare.add(\n incReward.divPrecisely(totalSupply)\n );\n\n pool.accRewardPerShare = accRewardPerShare;\n pool.lastRewardBlock = block.number;\n }\n\n /**\n * @dev Deposit LP tokens into contract, must be preapproved.\n * @param _amount Amount of LPToken to deposit.\n */\n function deposit(uint256 _amount) external {\n UserInfo storage user = userInfo[msg.sender];\n updatePool();\n if (_amount > 0) {\n user.amount = user.amount.add(_amount);\n // newDebt is equal to the change in amount * accRewardPerShare (note accRewardPerShare is historic)\n int256 newDebt = int256(\n _amount.mulTruncate(pool.accRewardPerShare)\n );\n user.rewardDebt += newDebt;\n totalRewardDebt += newDebt;\n totalSupply = totalSupply.add(_amount);\n emit Deposit(msg.sender, _amount);\n pool.lpToken.safeTransferFrom(\n address(msg.sender),\n address(this),\n _amount\n );\n }\n }\n\n /**\n * @dev Exit out of the contract completely, withdraw LP tokens and claim rewards\n */\n function exit() external {\n UserInfo storage user = userInfo[msg.sender];\n // withdraw everything\n _withdraw(user, user.amount, true);\n }\n\n /**\n * @dev Withdraw LP tokens from contract.\n * @param _amount Amount of LPToken to withdraw.\n * @param _claim Boolean do we want to claim our rewards or not\n */\n function withdraw(uint256 _amount, bool _claim) external {\n UserInfo storage user = userInfo[msg.sender];\n _withdraw(user, _amount, _claim);\n }\n\n function _withdraw(\n UserInfo storage user,\n uint256 _amount,\n bool _claim\n ) internal {\n require(user.amount >= _amount, \"withdraw: overflow\");\n updatePool();\n\n // newDebt is equal to the change in amount * accRewardPerShare (note accRewardPerShare is historic)\n int256 newDebt = -int256(_amount.mulTruncate(pool.accRewardPerShare));\n uint256 pending = 0;\n if (_claim) {\n //This is an optimization so we don't modify the storage variable twice\n pending = subDebt(\n user.amount.mulTruncate(pool.accRewardPerShare),\n user.rewardDebt\n );\n\n newDebt += int256(pending);\n }\n\n user.rewardDebt += newDebt;\n totalRewardDebt += newDebt;\n emit Withdraw(msg.sender, _amount);\n // actually make the changes to the amount and debt\n if (_amount > 0) {\n user.amount = user.amount.sub(_amount);\n totalSupply = totalSupply.sub(_amount, \"withdraw: total overflow\");\n }\n //putting this all at the end to avoid reentrancy error\n if (pending > 0) {\n emit Claim(msg.sender, pending);\n reward.safeTransfer(msg.sender, pending);\n }\n if (_amount > 0) {\n pool.lpToken.safeTransfer(address(msg.sender), _amount);\n }\n }\n\n /**\n * @dev Claim all pending rewards up to current block\n */\n function claim() external {\n UserInfo storage user = userInfo[msg.sender];\n uint256 pending = _pendingRewards(user);\n if (pending > 0) {\n emit Claim(msg.sender, pending);\n int256 debtDelta = int256(pending);\n user.rewardDebt += debtDelta;\n totalRewardDebt += debtDelta;\n reward.safeTransfer(msg.sender, pending);\n }\n }\n\n function subDebt(uint256 amount, int256 debt)\n internal\n pure\n returns (uint256 result)\n {\n if (debt < 0) {\n result = amount.add(uint256(-debt));\n } else {\n result = amount.sub(uint256(debt));\n }\n }\n}\n" + }, + "contracts/mocks/BeaconChainDepositContractMock.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ncontract BeaconChainDepositContractMock {\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 // Extended ABI length checks since dynamic types are used.\n require(pubkey.length == 48, \"DepositContract: invalid pubkey length\");\n require(\n withdrawal_credentials.length == 32,\n \"DepositContract: invalid withdrawal_credentials length\"\n );\n require(\n signature.length == 96,\n \"DepositContract: invalid signature length\"\n );\n\n // Check deposit amount\n require(msg.value >= 1 ether, \"DepositContract: deposit value too low\");\n require(\n msg.value % 1 gwei == 0,\n \"DepositContract: deposit value not multiple of gwei\"\n );\n uint256 deposit_amount = msg.value / 1 gwei;\n require(\n deposit_amount <= type(uint64).max,\n \"DepositContract: deposit value too high\"\n );\n require(\n deposit_data_root != 0,\n \"DepositContract: invalid deposit_data_root\"\n );\n }\n}\n" + }, + "contracts/mocks/BurnableERC20.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { ERC20 } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ninterface IBurnableERC20 {\n function burn(uint256 value) external returns (bool);\n\n function burnFrom(address account, uint256 value) external returns (bool);\n}\n\n/**\n * @title BurnableERC20\n * @dev Exposes the burn function of ERC20 for tests\n */\nabstract contract BurnableERC20 is IBurnableERC20, ERC20 {\n /**\n * @dev Function to burn tokens\n * @param value The amount of tokens to burn.\n * @return A boolean that indicates if the operation was successful.\n */\n function burn(uint256 value) public virtual override returns (bool) {\n _burn(msg.sender, value);\n return true;\n }\n\n /**\n * @dev Function to burn tokens from a specific account\n * @param account The address with the tokens to burn.\n * @param value The amount of tokens to burn.\n * @return A boolean that indicates if the operation was successful.\n */\n function burnFrom(address account, uint256 value)\n public\n override\n returns (bool)\n {\n _burn(account, value);\n return true;\n }\n}\n" + }, + "contracts/mocks/curve/Mock3CRV.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { ERC20, MintableERC20 } from \"../MintableERC20.sol\";\nimport { BurnableERC20 } from \"../BurnableERC20.sol\";\n\ncontract Mock3CRV is MintableERC20, BurnableERC20 {\n constructor() ERC20(\"Curve.fi DAI/USDC/USDT\", \"3Crv\") {}\n\n function decimals() public pure override returns (uint8) {\n return 18;\n }\n}\n" + }, + "contracts/mocks/curve/MockBooster.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 { MockRewardPool } from \"./MockRewardPool.sol\";\n\nimport { IRewardStaking } from \"../../strategies/IRewardStaking.sol\";\nimport { IMintableERC20, MintableERC20, ERC20 } from \"../MintableERC20.sol\";\nimport { IBurnableERC20, BurnableERC20 } from \"../BurnableERC20.sol\";\n\ncontract MockDepositToken is MintableERC20, BurnableERC20 {\n constructor() ERC20(\"DCVX\", \"CVX Deposit Token\") {}\n}\n\ncontract MockBooster {\n using SafeERC20 for IERC20;\n\n struct PoolInfo {\n address lptoken;\n address token;\n address crvRewards;\n }\n\n address public minter; // this is CVx for the booster on live\n address public crv; // Curve rewards token\n address public cvx; // Convex rewards token\n mapping(uint256 => PoolInfo) public poolInfo;\n\n constructor(\n address _rewardsMinter,\n address _crv,\n address _cvx\n ) public {\n minter = _rewardsMinter;\n crv = _crv;\n cvx = _cvx;\n }\n\n function setPool(uint256 pid, address _lpToken)\n external\n returns (address rewards)\n {\n address token = address(new MockDepositToken());\n // Deploy a new Convex Rewards Pool\n rewards = address(\n new MockRewardPool(pid, token, crv, cvx, address(this))\n );\n\n poolInfo[pid] = PoolInfo({\n lptoken: _lpToken,\n token: token,\n crvRewards: rewards\n });\n }\n\n function deposit(\n uint256 _pid,\n uint256 _amount,\n bool _stake\n ) public returns (bool) {\n PoolInfo storage pool = poolInfo[_pid];\n\n address lptoken = pool.lptoken;\n\n // hold on to the Curve LP tokens\n IERC20(lptoken).safeTransferFrom(msg.sender, address(this), _amount);\n\n address token = pool.token;\n if (_stake) {\n // mint Convex pool LP tokens and stake in rewards contract on user behalf\n IMintableERC20(token).mint(_amount);\n address rewardContract = pool.crvRewards;\n IERC20(token).safeApprove(rewardContract, 0);\n IERC20(token).safeApprove(rewardContract, _amount);\n IRewardStaking(rewardContract).stakeFor(msg.sender, _amount);\n } else {\n // mint Convex pool LP tokens and send to user\n IMintableERC20(token).mint(_amount);\n IERC20(token).transfer(msg.sender, _amount);\n }\n return true;\n }\n\n // Deposit all Curve LP tokens and stake\n function depositAll(uint256 _pid, bool _stake) external returns (bool) {\n address lptoken = poolInfo[_pid].lptoken;\n uint256 balance = IERC20(lptoken).balanceOf(msg.sender);\n deposit(_pid, balance, _stake);\n return true;\n }\n\n // withdraw Curve LP tokens\n function _withdraw(\n uint256 _pid,\n uint256 _amount,\n address _from,\n address _to\n ) internal {\n PoolInfo storage pool = poolInfo[_pid];\n\n // burn the Convex pool LP tokens\n IBurnableERC20(pool.token).burnFrom(_from, _amount);\n\n // return the Curve LP tokens\n IERC20(pool.lptoken).safeTransfer(_to, _amount);\n }\n\n // withdraw Curve LP tokens\n function withdraw(uint256 _pid, uint256 _amount) public returns (bool) {\n _withdraw(_pid, _amount, msg.sender, msg.sender);\n return true;\n }\n\n // withdraw all Curve LP tokens\n function withdrawAll(uint256 _pid) public returns (bool) {\n address token = poolInfo[_pid].token;\n uint256 userBal = IERC20(token).balanceOf(msg.sender);\n withdraw(_pid, userBal);\n return true;\n }\n\n // allow reward contracts to send here and withdraw to user\n function withdrawTo(\n uint256 _pid,\n uint256 _amount,\n address _to\n ) external returns (bool) {\n address rewardContract = poolInfo[_pid].crvRewards;\n require(msg.sender == rewardContract, \"!auth\");\n\n _withdraw(_pid, _amount, msg.sender, _to);\n return true;\n }\n\n // callback from reward contract when crv is received.\n function rewardClaimed(\n uint256 _pid,\n // solhint-disable-next-line no-unused-vars\n address _address,\n uint256 _amount\n ) external returns (bool) {\n address rewardContract = poolInfo[_pid].crvRewards;\n require(msg.sender == rewardContract, \"!auth\");\n\n //mint reward tokens\n // and transfer it\n IMintableERC20(minter).mint(_amount);\n IERC20(minter).transfer(msg.sender, _amount);\n return true;\n }\n}\n" + }, + "contracts/mocks/curve/MockCRV.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../MintableERC20.sol\";\n\ncontract MockCRV is MintableERC20 {\n constructor() ERC20(\"Curve DAO Token\", \"CRV\") {}\n\n function decimals() public pure override returns (uint8) {\n return 18;\n }\n}\n" + }, + "contracts/mocks/curve/MockCRVMinter.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\nimport { IMintableERC20 } from \"../MintableERC20.sol\";\n\ncontract MockCRVMinter {\n address crv;\n\n constructor(address _crv) {\n crv = _crv;\n }\n\n function mint(address _address) external {\n uint256 amount = 2e18;\n IMintableERC20(crv).mint(amount);\n IERC20(crv).transfer(_address, amount);\n }\n}\n" + }, + "contracts/mocks/curve/MockCurveAbstractMetapool.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\nimport { MintableERC20, IMintableERC20 } from \"../MintableERC20.sol\";\nimport { StableMath } from \"../../utils/StableMath.sol\";\nimport \"../../utils/Helpers.sol\";\n\nabstract contract MockCurveAbstractMetapool is MintableERC20 {\n using StableMath for uint256;\n\n address[] public coins;\n uint256[2] public balances;\n\n // Returns the same amount of LP tokens in 1e18 decimals\n function add_liquidity(uint256[2] calldata _amounts, uint256 _minAmount)\n external\n returns (uint256 lpAmount)\n {\n for (uint256 i = 0; i < _amounts.length; i++) {\n if (_amounts[i] > 0) {\n IERC20(coins[i]).transferFrom(\n msg.sender,\n address(this),\n _amounts[i]\n );\n uint256 assetDecimals = Helpers.getDecimals(coins[i]);\n // Convert to 1e18 and add to sum\n lpAmount += _amounts[i].scaleBy(18, assetDecimals);\n balances[i] = balances[i] + _amounts[i];\n }\n }\n // Hacky way of simulating slippage to check _minAmount\n if (lpAmount == 29000e18) lpAmount = 14500e18;\n require(lpAmount >= _minAmount, \"Slippage ruined your day\");\n // Send LP token to sender, e.g. 3CRV\n _mint(msg.sender, lpAmount);\n }\n\n // Dumb implementation that returns the same amount\n function calc_withdraw_one_coin(uint256 _amount, int128 _index)\n public\n view\n returns (uint256 lpAmount)\n {\n uint256 assetDecimals = Helpers.getDecimals(coins[uint128(_index)]);\n lpAmount = _amount.scaleBy(assetDecimals, 18);\n }\n\n function remove_liquidity_one_coin(\n uint256 _lpAmount,\n int128 _index,\n // solhint-disable-next-line no-unused-vars\n uint256 _minAmount\n ) external returns (uint256 amount) {\n _burn(msg.sender, _lpAmount);\n uint256[] memory amounts = new uint256[](coins.length);\n amounts[uint128(_index)] = _lpAmount;\n amount = calc_withdraw_one_coin(_lpAmount, _index);\n balances[uint128(_index)] -= amount;\n IERC20(coins[uint128(_index)]).transfer(msg.sender, amount);\n }\n\n function get_virtual_price() external pure returns (uint256) {\n return 1e18;\n }\n\n // solhint-disable-next-line no-unused-vars\n function remove_liquidity(uint256 _amount, uint256[2] memory _min_amounts)\n public\n returns (uint256[2] memory amounts)\n {\n _burn(msg.sender, _amount);\n uint256 totalSupply = totalSupply();\n for (uint256 i = 0; i < 2; i++) {\n amounts[i] = totalSupply > 0\n ? (_amount * IERC20(coins[i]).balanceOf(address(this))) /\n totalSupply\n : IERC20(coins[i]).balanceOf(address(this));\n balances[i] -= amounts[i];\n IERC20(coins[i]).transfer(msg.sender, amounts[i]);\n }\n }\n\n function remove_liquidity_imbalance(\n uint256[2] memory _amounts,\n uint256 _max_burned_tokens\n ) public returns (uint256) {\n return\n _remove_liquidity_imbalance(\n _amounts,\n _max_burned_tokens,\n msg.sender\n );\n }\n\n function remove_liquidity_imbalance(\n uint256[2] memory _amounts,\n uint256 _max_burned_tokens,\n address _reveiver\n ) public returns (uint256) {\n return\n _remove_liquidity_imbalance(\n _amounts,\n _max_burned_tokens,\n _reveiver\n );\n }\n\n function _remove_liquidity_imbalance(\n uint256[2] memory _amounts,\n uint256 _max_burned_tokens,\n address _reveiver\n ) internal returns (uint256 lpTokens) {\n lpTokens = _max_burned_tokens;\n _burn(msg.sender, lpTokens);\n for (uint256 i = 0; i < _amounts.length; i++) {\n balances[i] -= _amounts[i];\n if (_amounts[i] > 0) {\n IERC20(coins[i]).transfer(_reveiver, _amounts[i]);\n }\n }\n }\n\n // Dumb implementation that sums the scaled amounts\n function calc_token_amount(uint256[2] memory _amounts, bool)\n public\n view\n returns (uint256 lpTokens)\n {\n for (uint256 i = 0; i < _amounts.length; i++) {\n uint256 assetDecimals = Helpers.getDecimals(coins[i]);\n // Convert to 1e18 and add to lpTokens\n lpTokens += _amounts[i].scaleBy(18, assetDecimals);\n }\n }\n\n /// @notice 0.02% fee\n function fee() external pure returns (uint256) {\n return 2000000;\n }\n\n function decimals() public pure override returns (uint8) {\n return 18;\n }\n\n function burnFrom(address from, uint256 value) public {\n _burn(from, value);\n }\n}\n" + }, + "contracts/mocks/curve/MockCurveGauge.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\nimport { ICurveGauge } from \"../../strategies/ICurveGauge.sol\";\n\ncontract MockCurveGauge is ICurveGauge {\n mapping(address => uint256) private _balances;\n address lpToken;\n\n constructor(address _lpToken) {\n lpToken = _lpToken;\n }\n\n function balanceOf(address account) public view override returns (uint256) {\n return _balances[account];\n }\n\n function deposit(uint256 _value, address _account) external override {\n IERC20(lpToken).transferFrom(msg.sender, address(this), _value);\n _balances[_account] += _value;\n }\n\n function withdraw(uint256 _value) external override {\n IERC20(lpToken).transfer(msg.sender, _value);\n // solhint-disable-next-line reentrancy\n _balances[msg.sender] -= _value;\n }\n}\n" + }, + "contracts/mocks/curve/MockCurveLUSDMetapool.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { MockCurveAbstractMetapool } from \"./MockCurveAbstractMetapool.sol\";\nimport \"../MintableERC20.sol\";\n\ncontract MockCurveLUSDMetapool is MockCurveAbstractMetapool {\n constructor(address[2] memory _coins)\n ERC20(\"Curve.fi Factory USD Metapool: LUSD\", \"LUSD3CRV-f\")\n {\n coins = _coins;\n }\n}\n" + }, + "contracts/mocks/curve/MockCurveMetapool.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { MockCurveAbstractMetapool } from \"./MockCurveAbstractMetapool.sol\";\nimport \"../MintableERC20.sol\";\n\ncontract MockCurveMetapool is MockCurveAbstractMetapool {\n constructor(address[2] memory _coins)\n ERC20(\"Curve.fi 3pool/OUSD metapool\", \"3crv_OUSD\")\n {\n coins = _coins;\n }\n}\n" + }, + "contracts/mocks/curve/MockCurvePool.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { IBurnableERC20 } from \"../BurnableERC20.sol\";\n\nimport { IMintableERC20 } from \"../MintableERC20.sol\";\nimport { ICurvePool } from \"../../strategies/ICurvePool.sol\";\nimport { StableMath } from \"../../utils/StableMath.sol\";\nimport \"../../utils/Helpers.sol\";\n\ncontract MockCurvePool {\n using StableMath for uint256;\n\n address[] public coins;\n uint256[3] public balances;\n address lpToken;\n uint256 public slippage = 1 ether;\n\n constructor(address[3] memory _coins, address _lpToken) {\n coins = _coins;\n lpToken = _lpToken;\n }\n\n function setCoins(address[] memory _coins) external {\n coins = _coins;\n }\n\n // Returns the same amount of LP tokens in 1e18 decimals\n function add_liquidity(uint256[3] calldata _amounts, uint256 _minAmount)\n external\n {\n uint256 sum = 0;\n for (uint256 i = 0; i < _amounts.length; i++) {\n if (_amounts[i] > 0) {\n IERC20(coins[i]).transferFrom(\n msg.sender,\n address(this),\n _amounts[i]\n );\n uint256 assetDecimals = Helpers.getDecimals(coins[i]);\n // Convert to 1e18 and add to sum\n sum += _amounts[i].scaleBy(18, assetDecimals);\n balances[i] = balances[i] + _amounts[i];\n }\n }\n // Hacky way of simulating slippage to check _minAmount\n if (sum == 29000e18) sum = 14500e18;\n require(sum >= _minAmount, \"Slippage ruined your day\");\n // Send LP token to sender, e.g. 3CRV\n IMintableERC20(lpToken).mint(sum);\n IERC20(lpToken).transfer(msg.sender, sum);\n }\n\n // Dumb implementation that returns the same amount\n function calc_withdraw_one_coin(uint256 _amount, int128 _index)\n public\n view\n returns (uint256)\n {\n uint256 assetDecimals = Helpers.getDecimals(coins[uint128(_index)]);\n return _amount.scaleBy(assetDecimals, 18);\n }\n\n function remove_liquidity_one_coin(\n uint256 _amount,\n int128 _index,\n // solhint-disable-next-line no-unused-vars\n uint256 _minAmount\n ) external {\n // Burn the Curve LP tokens\n IBurnableERC20(lpToken).burnFrom(msg.sender, _amount);\n uint256[] memory amounts = new uint256[](coins.length);\n amounts[uint128(_index)] = _amount;\n uint256 coinAmount = calc_withdraw_one_coin(_amount, _index);\n balances[uint128(_index)] -= coinAmount;\n IERC20(coins[uint128(_index)]).transfer(msg.sender, coinAmount);\n }\n\n function get_virtual_price() external pure returns (uint256) {\n return 1e18;\n }\n\n // solhint-disable-next-line no-unused-vars\n function remove_liquidity(uint256 _lpAmount, uint256[3] memory _min_amounts)\n public\n {\n // Burn the Curve LP tokens\n IBurnableERC20(lpToken).burnFrom(msg.sender, _lpAmount);\n uint256 totalSupply = IERC20(lpToken).totalSupply();\n for (uint256 i = 0; i < 3; i++) {\n uint256 coinAmount = totalSupply > 0\n ? (_lpAmount * IERC20(coins[i]).balanceOf(address(this))) /\n totalSupply\n : IERC20(coins[i]).balanceOf(address(this));\n balances[i] -= coinAmount;\n IERC20(coins[i]).transfer(msg.sender, coinAmount);\n }\n }\n\n function remove_liquidity_imbalance(\n uint256[3] memory _amounts,\n uint256 _max_burned_tokens\n ) public {\n // Burn the Curve LP tokens\n IBurnableERC20(lpToken).burnFrom(msg.sender, _max_burned_tokens);\n // For each coin, transfer to the caller\n for (uint256 i = 0; i < _amounts.length; i++) {\n balances[i] -= _amounts[i];\n if (_amounts[i] > 0) {\n IERC20(coins[i]).transfer(msg.sender, _amounts[i]);\n }\n }\n }\n\n // Dumb implementation that sums the scaled amounts\n function calc_token_amount(uint256[3] memory _amounts, bool)\n public\n view\n returns (uint256 lpTokens)\n {\n for (uint256 i = 0; i < _amounts.length; i++) {\n uint256 assetDecimals = Helpers.getDecimals(coins[i]);\n // Convert to 1e18 and add to lpTokens\n lpTokens += _amounts[i].scaleBy(18, assetDecimals);\n }\n }\n\n function fee() external pure returns (uint256) {\n return 1000000;\n }\n\n function exchange(\n uint256 coin0,\n uint256 coin1,\n uint256 amountIn,\n uint256 minAmountOut\n ) external returns (uint256 amountOut) {\n IERC20(coins[coin0]).transferFrom(msg.sender, address(this), amountIn);\n amountOut = (minAmountOut * slippage) / 1 ether;\n require(amountOut >= minAmountOut, \"Slippage error\");\n IMintableERC20(coins[coin1]).mintTo(msg.sender, amountOut);\n }\n\n function setSlippage(uint256 _slippage) external {\n slippage = _slippage;\n }\n}\n" + }, + "contracts/mocks/curve/MockCVX.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../MintableERC20.sol\";\n\ncontract MockCVX is MintableERC20 {\n constructor() ERC20(\"CVX\", \"CVX DAO Token\") {}\n}\n" + }, + "contracts/mocks/curve/MockLUSD.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../MintableERC20.sol\";\n\ncontract MockLUSD is MintableERC20 {\n constructor() ERC20(\"LUSD\", \"Liquity Token\") {}\n}\n" + }, + "contracts/mocks/curve/MockRewardPool.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 { IMintableERC20 } from \"../MintableERC20.sol\";\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\n\ninterface IDeposit {\n function poolInfo(uint256)\n external\n view\n returns (\n address,\n address,\n address,\n address,\n address,\n bool\n );\n\n function rewardClaimed(\n uint256,\n address,\n uint256\n ) external;\n\n function withdrawTo(\n uint256,\n uint256,\n address\n ) external;\n}\n\ncontract MockRewardPool {\n using SafeMath for uint256;\n using SafeERC20 for IERC20;\n\n uint256 public pid;\n address public stakingToken;\n address public rewardTokenA;\n address public rewardTokenB;\n address public operator;\n\n uint256 private _totalSupply;\n\n mapping(address => uint256) private _balances;\n mapping(address => uint256) public rewards;\n\n constructor(\n uint256 _pid,\n address _stakingToken,\n address _rewardTokenA,\n address _rewardTokenB,\n address _operator\n ) public {\n pid = _pid;\n stakingToken = _stakingToken;\n rewardTokenA = _rewardTokenA;\n rewardTokenB = _rewardTokenB;\n operator = _operator;\n }\n\n function totalSupply() public view returns (uint256) {\n return _totalSupply;\n }\n\n function balanceOf(address account) public view returns (uint256) {\n return _balances[account];\n }\n\n function stakeFor(address _for, uint256 _amount) public returns (bool) {\n require(_amount > 0, \"RewardPool : Cannot stake 0\");\n\n //give to _for\n _totalSupply = _totalSupply.add(_amount);\n _balances[_for] = _balances[_for].add(_amount);\n\n //take away from sender\n IERC20(stakingToken).safeTransferFrom(\n msg.sender,\n address(this),\n _amount\n );\n\n return true;\n }\n\n function withdrawAndUnwrap(uint256 amount, bool claim)\n public\n returns (bool)\n {\n _totalSupply = _totalSupply.sub(amount);\n _balances[msg.sender] = _balances[msg.sender].sub(amount);\n\n //tell operator to withdraw from here directly to user\n IDeposit(operator).withdrawTo(pid, amount, msg.sender);\n\n //get rewards too\n if (claim) {\n getReward(msg.sender, true);\n }\n return true;\n }\n\n function withdrawAllAndUnwrap(bool claim) external {\n withdrawAndUnwrap(_balances[msg.sender], claim);\n }\n\n // solhint-disable-next-line no-unused-vars\n function getReward(address _account, bool _claimExtras)\n public\n returns (bool)\n {\n IMintableERC20(rewardTokenA).mint(2 * 1e18);\n IERC20(rewardTokenA).transfer(_account, 2 * 1e18);\n\n IMintableERC20(rewardTokenB).mint(3 * 1e18);\n IERC20(rewardTokenB).transfer(_account, 3 * 1e18);\n\n return true;\n }\n\n function getReward() public returns (bool) {\n getReward(msg.sender, true);\n }\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/Mock1InchSwapRouter.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\";\n\nimport { SwapDescription } from \"../interfaces/IOneInch.sol\";\n\ncontract Mock1InchSwapRouter {\n using SafeERC20 for IERC20;\n\n event MockSwap(address executor, bytes permitData, bytes executorData);\n\n event MockSwapDesc(\n address srcToken,\n address dstToken,\n address srcReceiver,\n address dstReceiver,\n uint256 amount,\n uint256 minReturnAmount,\n uint256 flags\n );\n\n event MockUnoswapTo(\n address recipient,\n address srcToken,\n uint256 amount,\n uint256 minReturn,\n uint256[] pools\n );\n\n event MockUniswapV3SwapTo(\n address recipient,\n uint256 amount,\n uint256 minReturn,\n uint256[] pools\n );\n\n /**\n * @dev transfers the shource asset and returns the minReturnAmount of the destination asset.\n */\n function swap(\n address executor,\n SwapDescription calldata desc,\n bytes calldata permitData,\n bytes calldata executorData\n ) public returns (uint256 returnAmount, uint256 spentAmount) {\n // Transfer the source tokens to the receiver contract\n IERC20(desc.srcToken).safeTransferFrom(\n msg.sender,\n desc.srcReceiver,\n desc.amount\n );\n\n // Transfer the destination tokens to the recipient\n IERC20(desc.dstToken).safeTransfer(\n desc.dstReceiver,\n desc.minReturnAmount\n );\n\n emit MockSwap(executor, permitData, executorData);\n _swapDesc(desc);\n returnAmount = 0;\n spentAmount = 0;\n }\n\n function _swapDesc(SwapDescription calldata desc) public {\n emit MockSwapDesc(\n address(desc.srcToken),\n address(desc.dstToken),\n desc.srcReceiver,\n desc.dstReceiver,\n desc.amount,\n desc.minReturnAmount,\n desc.flags\n );\n }\n\n /**\n * @dev only transfers the source asset to this contract.\n * Ideally it would return the destination asset but that's encoded in the pools array.\n */\n function unoswapTo(\n address payable recipient,\n address srcToken,\n uint256 amount,\n uint256 minReturn,\n uint256[] calldata pools\n ) public returns (uint256 returnAmount) {\n // transfer the from asset from the caller\n IERC20(srcToken).safeTransferFrom(msg.sender, address(this), amount);\n\n emit MockUnoswapTo(recipient, srcToken, amount, minReturn, pools);\n returnAmount = 0;\n }\n\n /**\n * @dev does not do any transfers. Just emits MockUniswapV3SwapTo.\n */\n function uniswapV3SwapTo(\n address payable recipient,\n uint256 amount,\n uint256 minReturn,\n uint256[] calldata pools\n ) public returns (uint256 returnAmount) {\n emit MockUniswapV3SwapTo(recipient, amount, minReturn, pools);\n returnAmount = 0;\n }\n}\n" + }, + "contracts/mocks/MockAave.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { IERC20, ERC20 } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\nimport { MintableERC20 } from \"./MintableERC20.sol\";\nimport { IAaveLendingPool, ILendingPoolAddressesProvider } from \"../strategies/IAave.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\n\n// 1. User calls 'getLendingPool'\n// 2. User calls 'deposit' (Aave)\n// - Deposit their underlying\n// - Mint aToken to them\n// 3. User calls redeem (aToken)\n// - Retrieve their aToken\n// - Return equal amount of underlying\n\ncontract MockAToken is MintableERC20 {\n address public lendingPool;\n IERC20 public underlyingToken;\n using SafeERC20 for IERC20;\n\n constructor(\n address _lendingPool,\n string memory _name,\n string memory _symbol,\n IERC20 _underlyingToken\n ) ERC20(_name, _symbol) {\n lendingPool = _lendingPool;\n underlyingToken = _underlyingToken;\n // addMinter(_lendingPool);\n }\n\n function decimals() public view override returns (uint8) {\n return ERC20(address(underlyingToken)).decimals();\n }\n\n function poolRedeem(uint256 _amount, address _to) external {\n require(msg.sender == lendingPool, \"pool only\");\n // Redeem these a Tokens\n _burn(_to, _amount);\n // For the underlying\n underlyingToken.safeTransferFrom(lendingPool, _to, _amount);\n }\n}\n\ncontract MockAave is IAaveLendingPool, ILendingPoolAddressesProvider {\n using SafeERC20 for IERC20;\n using StableMath for uint256;\n\n mapping(address => address) reserveToAToken;\n address pool = address(this);\n address payable core = payable(address(this));\n uint256 factor;\n\n function addAToken(address _aToken, address _underlying) public {\n IERC20(_underlying).safeApprove(_aToken, 0);\n IERC20(_underlying).safeApprove(_aToken, type(uint256).max);\n reserveToAToken[_underlying] = _aToken;\n }\n\n // set the reserve factor / basically the interest on deposit\n // in 18 precision\n // so 0.5% would be 5 * 10 ^ 15\n function setFactor(uint256 factor_) public {\n factor = factor_;\n }\n\n function deposit(\n address _reserve,\n uint256 _amount,\n address _to,\n uint16 /*_referralCode*/\n ) external override {\n uint256 previousBal = IERC20(reserveToAToken[_reserve]).balanceOf(\n msg.sender\n );\n uint256 interest = previousBal.mulTruncate(factor);\n MintableERC20(reserveToAToken[_reserve]).mintTo(msg.sender, interest);\n // Take their reserve\n IERC20(_reserve).safeTransferFrom(msg.sender, address(this), _amount);\n // Credit them with aToken\n MintableERC20(reserveToAToken[_reserve]).mintTo(_to, _amount);\n }\n\n function withdraw(\n address asset,\n uint256 amount,\n address to\n ) external override returns (uint256) {\n MockAToken atoken = MockAToken(reserveToAToken[asset]);\n atoken.poolRedeem(amount, to);\n return amount;\n }\n\n function getLendingPool() external view override returns (address) {\n return pool;\n }\n}\n" + }, + "contracts/mocks/MockAaveIncentivesController.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { MockStkAave } from \"./MockStkAave.sol\";\n\ncontract MockAaveIncentivesController {\n mapping(address => uint256) private rewards;\n MockStkAave public REWARD_TOKEN;\n\n constructor(address _reward_token) {\n REWARD_TOKEN = MockStkAave(_reward_token);\n }\n\n function setRewardsBalance(address user, uint256 amount) external {\n rewards[user] = amount;\n }\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 // solhint-disable-next-line no-unused-vars\n function getRewardsBalance(address[] calldata assets, address user)\n external\n view\n returns (uint256)\n {\n return rewards[user];\n }\n\n /**\n * @dev Claims reward for an user, on all the assets of the lending pool, 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 // solhint-disable-next-line no-unused-vars\n address[] calldata assets,\n uint256 amount,\n address to\n ) external returns (uint256) {\n require(amount > 0);\n require(rewards[to] == amount);\n REWARD_TOKEN.mint(amount);\n require(REWARD_TOKEN.transfer(to, amount));\n // solhint-disable-next-line reentrancy\n rewards[to] = 0;\n return amount;\n }\n}\n" + }, + "contracts/mocks/MockAAVEToken.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./MintableERC20.sol\";\n\ncontract MockAAVEToken is MintableERC20 {\n constructor() ERC20(\"AAVE\", \"AAVE\") {}\n}\n" + }, + "contracts/mocks/MockAura.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./MintableERC20.sol\";\n\ncontract MockAura is MintableERC20 {\n constructor() ERC20(\"Aura\", \"AURA\") {}\n}\n" + }, + "contracts/mocks/MockBAL.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./MintableERC20.sol\";\n\ncontract MockBAL is MintableERC20 {\n constructor() ERC20(\"Balancer\", \"BAL\") {}\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/MockBuyback.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { BaseBuyback } from \"../buyback/BaseBuyback.sol\";\n\ncontract MockBuyback is BaseBuyback {\n constructor(\n address _oToken,\n address _ogv,\n address _cvx,\n address _cvxLocker\n ) BaseBuyback(_oToken, _ogv, _cvx, _cvxLocker) {}\n}\n" + }, + "contracts/mocks/MockChainlinkOracleFeed.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../interfaces/chainlink/AggregatorV3Interface.sol\";\n\ncontract MockChainlinkOracleFeed is AggregatorV3Interface {\n int256 price;\n uint8 numDecimals;\n\n constructor(int256 _price, uint8 _decimals) {\n price = _price;\n numDecimals = _decimals;\n }\n\n function decimals() external view override returns (uint8) {\n return numDecimals;\n }\n\n function description() external pure override returns (string memory) {\n return \"MockOracleEthFeed\";\n }\n\n function version() external pure override returns (uint256) {\n return 1;\n }\n\n function setPrice(int256 _price) public {\n price = _price;\n }\n\n function setDecimals(uint8 _decimals) public {\n numDecimals = _decimals;\n }\n\n // getRoundData and latestRoundData should both raise \"No data present\"\n // if they do not have data to report, instead of returning unset values\n // which could be misinterpreted as actual reported values.\n function getRoundData(uint80 _roundId)\n external\n view\n override\n returns (\n uint80 roundId,\n int256 answer,\n uint256 startedAt,\n uint256 updatedAt,\n uint80 answeredInRound\n )\n {\n roundId = _roundId;\n answer = price;\n startedAt = 0;\n updatedAt = 0;\n answeredInRound = 0;\n }\n\n function latestRoundData()\n external\n view\n override\n returns (\n uint80 roundId,\n int256 answer,\n uint256 startedAt,\n uint256 updatedAt,\n uint80 answeredInRound\n )\n {\n roundId = 0;\n answer = price;\n startedAt = 0;\n updatedAt = block.timestamp;\n answeredInRound = 0;\n }\n}\n" + }, + "contracts/mocks/MockCOMP.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./MintableERC20.sol\";\n\ncontract MockCOMP is MintableERC20 {\n constructor() ERC20(\"COMP\", \"COMP\") {}\n}\n" + }, + "contracts/mocks/MockComptroller.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ncontract MockComptroller {\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" + }, + "contracts/mocks/MockCToken.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { IERC20, ERC20 } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\nimport { ICERC20 } from \"../strategies/ICompound.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\n\ncontract MockCToken is ICERC20, ERC20 {\n using StableMath for uint256;\n\n IERC20 public underlyingToken;\n // underlying = cToken * exchangeRate\n // cToken = underlying / exchangeRate\n uint256 exchangeRate;\n address public override comptroller;\n\n constructor(ERC20 _underlyingToken, address _comptroller)\n ERC20(\"cMock\", \"cMK\")\n {\n uint8 underlyingDecimals = _underlyingToken.decimals();\n // if has 18 dp, exchange rate should be 1e26\n // if has 8 dp, exchange rate should be 1e18\n if (underlyingDecimals > 8) {\n exchangeRate = 10**uint256(18 + underlyingDecimals - 10);\n } else if (underlyingDecimals < 8) {\n // e.g. 18-8+6 = 16\n exchangeRate = 10**uint256(18 - 8 + underlyingDecimals);\n } else {\n exchangeRate = 1e18;\n }\n underlyingToken = _underlyingToken;\n comptroller = _comptroller;\n }\n\n function decimals() public pure override returns (uint8) {\n return 8;\n }\n\n function mint(uint256 mintAmount) public override returns (uint256) {\n // Credit them with cToken\n _mint(msg.sender, mintAmount.divPrecisely(exchangeRate));\n // Take their reserve\n underlyingToken.transferFrom(msg.sender, address(this), mintAmount);\n return 0;\n }\n\n function redeem(uint256 redeemAmount) external override returns (uint256) {\n uint256 tokenAmount = redeemAmount.mulTruncate(exchangeRate);\n // Burn the cToken\n _burn(msg.sender, redeemAmount);\n // Transfer underlying to caller\n underlyingToken.transfer(msg.sender, tokenAmount);\n return 0;\n }\n\n function redeemUnderlying(uint256 redeemAmount)\n external\n override\n returns (uint256)\n {\n uint256 cTokens = redeemAmount.divPrecisely(exchangeRate);\n // Burn the cToken\n _burn(msg.sender, cTokens);\n // Transfer underlying to caller\n underlyingToken.transfer(msg.sender, redeemAmount);\n return 0;\n }\n\n function balanceOfUnderlying(address owner)\n external\n view\n override\n returns (uint256)\n {\n uint256 cTokenBal = this.balanceOf(owner);\n return cTokenBal.mulTruncate(exchangeRate);\n }\n\n function balanceOf(address owner)\n public\n view\n override(ICERC20, ERC20)\n returns (uint256)\n {\n return ERC20.balanceOf(owner);\n }\n\n function updateExchangeRate()\n internal\n view\n returns (uint256 newExchangeRate)\n {\n uint256 factor = 100002 * (10**13); // 0.002%\n newExchangeRate = exchangeRate.mulTruncate(factor);\n }\n\n function exchangeRateStored() external view override returns (uint256) {\n return exchangeRate;\n }\n\n function supplyRatePerBlock() external pure override returns (uint256) {\n return 141 * (10**8);\n }\n}\n" + }, + "contracts/mocks/MockCVXLocker.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { ERC20 } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ncontract MockCVXLocker {\n address public immutable cvx;\n mapping(address => uint256) public lockedBalanceOf;\n\n constructor(address _cvx) {\n cvx = _cvx;\n }\n\n function lock(\n address _account,\n uint256 _amount,\n uint256\n ) external {\n lockedBalanceOf[_account] += _amount;\n ERC20(cvx).transferFrom(msg.sender, address(this), _amount);\n }\n\n function unlockAllTokens(address _account) external {\n lockedBalanceOf[_account] = 0;\n ERC20(cvx).transfer(_account, lockedBalanceOf[_account]);\n }\n}\n" + }, + "contracts/mocks/MockDAI.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./MintableERC20.sol\";\n\ncontract MockDAI is MintableERC20 {\n constructor() ERC20(\"DAI\", \"DAI\") {}\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/MockfrxETH.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./MintableERC20.sol\";\n\ncontract MockfrxETH is MintableERC20 {\n constructor() ERC20(\"frxETH\", \"frxETH\") {}\n}\n" + }, + "contracts/mocks/MockFrxETHMinter.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./MintableERC20.sol\";\n\ncontract MockFrxETHMinter {\n address public immutable frxETH;\n address public immutable sfrxETH;\n\n constructor(address _frxETH, address _sfrxETH) {\n frxETH = _frxETH;\n sfrxETH = _sfrxETH;\n }\n\n function submitAndDeposit(address recipient)\n external\n payable\n returns (uint256 shares)\n {\n IMintableERC20(frxETH).mintTo(sfrxETH, msg.value);\n IMintableERC20(sfrxETH).mintTo(recipient, msg.value);\n shares = msg.value;\n }\n}\n" + }, + "contracts/mocks/MockLimitedWrappedOusd.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { WrappedOusd } from \"../token/WrappedOusd.sol\";\nimport { ERC20 } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ncontract MockLimitedWrappedOusd is WrappedOusd {\n constructor(\n ERC20 underlying_,\n string memory name_,\n string memory symbol_\n ) WrappedOusd(underlying_, name_, symbol_) {}\n\n function maxDeposit(address)\n public\n view\n virtual\n override\n returns (uint256)\n {\n return 1e18;\n }\n}\n" + }, + "contracts/mocks/MockMetadataToken.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n// IERC20Metadata is used in the resolveAsset function in contracts/utils/assets.js\n// We just need to import it here to make its ABI available to Hardhat\nimport { IERC20Metadata } from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\n" + }, + "contracts/mocks/MockMintableUniswapPair.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./MintableERC20.sol\";\nimport \"./MockUniswapPair.sol\";\n\ncontract MockMintableUniswapPair is MockUniswapPair, MintableERC20 {\n constructor(\n address _token0,\n address _token1,\n uint112 _reserve0,\n uint112 _reserve1\n )\n MockUniswapPair(_token0, _token1, _reserve0, _reserve1)\n ERC20(\"Uniswap V2\", \"UNI-v2\")\n {}\n\n function decimals() public pure override returns (uint8) {\n return 18;\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/MockNonStandardToken.sol": { + "content": "pragma solidity ^0.8.0;\n\nimport { SafeMath } from \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\n\nimport \"./MintableERC20.sol\";\n\n/**\n * Mock token contract to simulate tokens that don't\n * throw/revert when a transfer/transferFrom call fails\n */\ncontract MockNonStandardToken is MintableERC20 {\n using SafeMath for uint256;\n\n constructor() ERC20(\"NonStandardToken\", \"NonStandardToken\") {}\n\n function decimals() public pure override returns (uint8) {\n return 6;\n }\n\n function transfer(address recipient, uint256 amount)\n public\n override\n returns (bool)\n {\n if (balanceOf(msg.sender) < amount) {\n // Fail silently\n return false;\n }\n\n _transfer(_msgSender(), recipient, amount);\n return true;\n }\n\n function transferFrom(\n address sender,\n address recipient,\n uint256 amount\n ) public override returns (bool) {\n if (balanceOf(sender) < amount) {\n // Fail silently\n return false;\n }\n\n _transfer(sender, recipient, amount);\n _approve(\n sender,\n _msgSender(),\n allowance(sender, _msgSender()).sub(\n amount,\n \"ERC20: transfer amount exceeds allowance\"\n )\n );\n return true;\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/MockOGN.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./BurnableERC20.sol\";\nimport \"./MintableERC20.sol\";\n\n/**\n * @title Origin token (OGN).\n *\n * @dev Token that allows minting and burning.\n * @dev Important note:\n * @dev There is a known race condition in the ERC20 standard on the approve() method.\n * @dev See details: https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n * @dev The Origin token contract implements the increaseApproval() and decreaseApproval() methods.\n * @dev It is strongly recommended to use those methods rather than approve()\n * @dev when updating the token allowance.\n */\ncontract MockOGN is MintableERC20, BurnableERC20 {\n event SetWhitelistExpiration(uint256 expiration);\n event AllowedTransactorAdded(address sender);\n event AllowedTransactorRemoved(address sender);\n event AddCallSpenderWhitelist(address enabler, address spender);\n event RemoveCallSpenderWhitelist(address disabler, address spender);\n\n mapping(address => bool) public callSpenderWhitelist;\n address public owner = msg.sender;\n // UNIX timestamp (in seconds) after which this whitelist no longer applies\n uint256 public whitelistExpiration;\n // While the whitelist is active, either the sender or recipient must be\n // in allowedTransactors.\n mapping(address => bool) public allowedTransactors;\n\n // @dev Constructor that gives msg.sender all initial tokens.\n constructor(uint256 _initialSupply) ERC20(\"OriginToken\", \"OGN\") {\n owner = msg.sender;\n _mint(owner, _initialSupply);\n }\n\n //\n // approveAndCall methods\n //\n\n // @dev Add spender to whitelist of spenders for approveAndCall\n // @param _spender Address to add\n function addCallSpenderWhitelist(address _spender) public onlyOwner {\n callSpenderWhitelist[_spender] = true;\n emit AddCallSpenderWhitelist(msg.sender, _spender);\n }\n\n // @dev Remove spender from whitelist of spenders for approveAndCall\n // @param _spender Address to remove\n function removeCallSpenderWhitelist(address _spender) public onlyOwner {\n delete callSpenderWhitelist[_spender];\n emit RemoveCallSpenderWhitelist(msg.sender, _spender);\n }\n\n // @dev Approve transfer of tokens and make a contract call in a single\n // @dev transaction. This allows a DApp to avoid requiring two MetaMask\n // @dev approvals for a single logical action, such as creating a listing,\n // @dev which requires the seller to approve a token transfer and the\n // @dev marketplace contract to transfer tokens from the seller.\n //\n // @dev This is based on the ERC827 function approveAndCall and avoids\n // @dev security issues by only working with a whitelisted set of _spender\n // @dev addresses. The other difference is that the combination of this\n // @dev function ensures that the proxied function call receives the\n // @dev msg.sender for this function as its first parameter.\n //\n // @param _spender The address that will spend the funds.\n // @param _value The amount of tokens to be spent.\n // @param _selector Function selector for function to be called.\n // @param _callParams Packed, encoded parameters, omitting the first parameter which is always msg.sender\n function approveAndCallWithSender(\n address _spender,\n uint256 _value,\n bytes4 _selector,\n bytes memory _callParams\n ) public payable returns (bool) {\n require(_spender != address(this), \"token contract can't be approved\");\n require(callSpenderWhitelist[_spender], \"spender not in whitelist\");\n\n require(super.approve(_spender, _value), \"approve failed\");\n\n bytes memory callData = abi.encodePacked(\n _selector,\n uint256(uint160(msg.sender)),\n _callParams\n );\n // solium-disable-next-line security/no-call-value\n (bool success, ) = _spender.call{ value: msg.value }(callData);\n require(success, \"proxied call failed\");\n return true;\n }\n\n //\n // Functions for maintaining whitelist\n //\n\n modifier onlyOwner() {\n require(msg.sender == owner);\n _;\n }\n modifier allowedTransfer(address _from, address _to) {\n require(\n // solium-disable-next-line operator-whitespace\n !whitelistActive() ||\n allowedTransactors[_from] ||\n allowedTransactors[_to],\n \"neither sender nor recipient are allowed\"\n );\n _;\n }\n\n function whitelistActive() public view returns (bool) {\n return block.timestamp < whitelistExpiration;\n }\n\n function addAllowedTransactor(address _transactor) public onlyOwner {\n emit AllowedTransactorAdded(_transactor);\n allowedTransactors[_transactor] = true;\n }\n\n function removeAllowedTransactor(address _transactor) public onlyOwner {\n emit AllowedTransactorRemoved(_transactor);\n delete allowedTransactors[_transactor];\n }\n\n /**\n * @dev Set the whitelist expiration, after which the whitelist no longer\n * applies.\n */\n function setWhitelistExpiration(uint256 _expiration) public onlyOwner {\n // allow only if whitelist expiration hasn't yet been set, or if the\n // whitelist expiration hasn't passed yet\n require(\n whitelistExpiration == 0 || whitelistActive(),\n \"an expired whitelist cannot be extended\"\n );\n // prevent possible mistakes in calling this function\n require(\n _expiration >= block.timestamp + 1 days,\n \"whitelist expiration not far enough into the future\"\n );\n emit SetWhitelistExpiration(_expiration);\n whitelistExpiration = _expiration;\n }\n\n //\n // ERC20 transfer functions that have been overridden to enforce the\n // whitelist.\n //\n\n function transfer(address _to, uint256 _value)\n public\n override\n allowedTransfer(msg.sender, _to)\n returns (bool)\n {\n return super.transfer(_to, _value);\n }\n\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n ) public override allowedTransfer(_from, _to) returns (bool) {\n return super.transferFrom(_from, _to, _value);\n }\n}\n" + }, + "contracts/mocks/MockOGV.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./MintableERC20.sol\";\n\ncontract MockOGV is MintableERC20 {\n constructor() ERC20(\"OGV\", \"OGV\") {}\n}\n" + }, + "contracts/mocks/MockOracle.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../interfaces/IPriceOracle.sol\";\nimport \"../interfaces/IMinMaxOracle.sol\";\n\n/**\n * Mock of both price Oracle and min max oracles\n */\ncontract MockOracle is IPriceOracle, IMinMaxOracle {\n mapping(bytes32 => uint256) prices;\n mapping(bytes32 => uint256[]) pricesMinMax;\n uint256 ethMin;\n uint256 ethMax;\n\n /**\n * @dev returns the asset price in USD, 6 decimal digits.\n * Compatible with the Open Price Feed.\n */\n function price(string calldata symbol)\n external\n view\n override\n returns (uint256)\n {\n return prices[keccak256(abi.encodePacked(symbol))];\n }\n\n /**\n * @dev sets the price of the asset in USD, 6 decimal digits\n *\n */\n function setPrice(string calldata symbol, uint256 _price) external {\n prices[keccak256(abi.encodePacked(symbol))] = _price;\n }\n\n /**\n * @dev sets the min and max price of ETH in USD, 6 decimal digits\n *\n */\n function setEthPriceMinMax(uint256 _min, uint256 _max) external {\n ethMin = _min;\n ethMax = _max;\n }\n\n /**\n * @dev sets the prices Min Max for a specific symbol in ETH, 8 decimal digits\n *\n */\n function setTokPriceMinMax(\n string calldata symbol,\n uint256 _min,\n uint256 _max\n ) external {\n pricesMinMax[keccak256(abi.encodePacked(symbol))] = [_min, _max];\n }\n\n /**\n * @dev get the price of asset in ETH, 8 decimal digits.\n */\n function priceMin(string calldata symbol)\n external\n view\n override\n returns (uint256)\n {\n uint256[] storage pMinMax = pricesMinMax[\n keccak256(abi.encodePacked(symbol))\n ];\n return (pMinMax[0] * ethMin) / 1e6;\n }\n\n /**\n * @dev get the price of asset in USD, 8 decimal digits.\n * Not needed for now\n */\n function priceMax(string calldata symbol)\n external\n view\n override\n returns (uint256)\n {\n uint256[] storage pMinMax = pricesMinMax[\n keccak256(abi.encodePacked(symbol))\n ];\n return (pMinMax[1] * ethMax) / 1e6;\n }\n}\n" + }, + "contracts/mocks/MockOracleRouter.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../interfaces/chainlink/AggregatorV3Interface.sol\";\nimport { IOracle } from \"../interfaces/IOracle.sol\";\nimport { Helpers } from \"../utils/Helpers.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\nimport { SafeCast } from \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\nimport { OracleRouterBase } from \"../oracle/OracleRouterBase.sol\";\n\n// @notice Oracle Router required for testing environment\ncontract MockOracleRouter is OracleRouterBase {\n struct FeedMetadata {\n address feedAddress;\n uint256 maxStaleness;\n }\n\n mapping(address => FeedMetadata) public assetToFeedMetadata;\n\n /* @dev Override feed and maxStaleness information for a particular asset\n * @param _asset the asset to override feed for\n * @param _feed new feed\n * @param _maxStaleness new maximum time allowed for feed data to be stale\n */\n function setFeed(\n address _asset,\n address _feed,\n uint256 _maxStaleness\n ) external {\n assetToFeedMetadata[_asset] = FeedMetadata(_feed, _maxStaleness);\n }\n\n /*\n * The dev version of the Oracle doesn't need to gas optimize and cache the decimals\n */\n function getDecimals(address _feed) internal view override returns (uint8) {\n require(_feed != address(0), \"Asset not available\");\n require(_feed != FIXED_PRICE, \"Fixed price feeds not supported\");\n\n return AggregatorV3Interface(_feed).decimals();\n }\n\n /**\n * @dev The price feed contract to use for a particular asset along with\n * maximum data staleness\n * @param asset address of the asset\n * @return feedAddress address of the price feed for the asset\n * @return maxStaleness maximum acceptable data staleness duration\n */\n function feedMetadata(address asset)\n internal\n view\n override\n returns (address feedAddress, uint256 maxStaleness)\n {\n FeedMetadata storage fm = assetToFeedMetadata[asset];\n feedAddress = fm.feedAddress;\n maxStaleness = fm.maxStaleness;\n }\n}\n" + }, + "contracts/mocks/MockOracleRouterNoStale.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../interfaces/chainlink/AggregatorV3Interface.sol\";\nimport { IOracle } from \"../interfaces/IOracle.sol\";\nimport { Helpers } from \"../utils/Helpers.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\nimport { SafeCast } from \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\nimport { OracleRouter } from \"../oracle/OracleRouter.sol\";\nimport { OETHOracleRouter } from \"../oracle/OETHOracleRouter.sol\";\n\n// @notice Oracle Router used to bypass staleness\ncontract MockOracleRouterNoStale is OracleRouter {\n function feedMetadata(address asset)\n internal\n pure\n virtual\n override\n returns (address feedAddress, uint256 maxStaleness)\n {\n (feedAddress, ) = super.feedMetadata(asset);\n maxStaleness = 365 days;\n }\n}\n\n// @notice Oracle Router used to bypass staleness\ncontract MockOETHOracleRouterNoStale is OETHOracleRouter {\n constructor(address auraPriceFeed) OETHOracleRouter(auraPriceFeed) {}\n\n function feedMetadata(address asset)\n internal\n view\n virtual\n override\n returns (address feedAddress, uint256 maxStaleness)\n {\n (feedAddress, ) = super.feedMetadata(asset);\n maxStaleness = 365 days;\n }\n}\n" + }, + "contracts/mocks/MockOracleWeightedPool.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { Variable, OracleAverageQuery, IOracleWeightedPool } from \"../interfaces/balancer/IOracleWeightedPool.sol\";\n\ncontract MockOracleWeightedPool is IOracleWeightedPool {\n uint256[] public nextResults;\n\n constructor() {\n nextResults = [1 ether, 1 ether];\n }\n\n function getTimeWeightedAverage(OracleAverageQuery[] memory)\n external\n view\n override\n returns (uint256[] memory results)\n {\n return nextResults;\n }\n\n function setNextResults(uint256[] calldata results) external {\n nextResults = results;\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/MockRETH.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./MintableERC20.sol\";\nimport \"../interfaces/IGetExchangeRateToken.sol\";\n\ncontract MockRETH is MintableERC20, IGetExchangeRateToken {\n uint256 private exchangeRate = 12e17;\n\n constructor() ERC20(\"Rocket Pool ETH\", \"rETH\") {}\n\n function getExchangeRate() external view override returns (uint256) {\n return exchangeRate;\n }\n\n function setExchangeRate(uint256 _rate) external {\n exchangeRate = _rate;\n }\n}\n" + }, + "contracts/mocks/MocksfrxETH.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./MintableERC20.sol\";\n\ncontract MocksfrxETH is MintableERC20 {\n address public frxETH;\n\n constructor(address _frxETH) ERC20(\"sfrxETH\", \"sfrxETH\") {\n frxETH = _frxETH;\n }\n\n function setMockfrxETHAddress(address _frxETH) external {\n frxETH = _frxETH;\n }\n\n function deposit(uint256 assets, address receiver)\n external\n returns (uint256 shares)\n {\n ERC20(frxETH).transferFrom(msg.sender, address(this), assets);\n\n _mint(receiver, assets);\n\n return assets;\n }\n\n function maxWithdraw(address owner) external view returns (uint256) {\n return balanceOf(owner);\n }\n\n function setMaxWithdrawableBalance(address owner, uint256 balance)\n external\n {\n uint256 currentBalance = balanceOf(owner);\n if (currentBalance > balance) {\n _burn(owner, currentBalance - balance);\n } else if (balance > currentBalance) {\n _mint(owner, balance - currentBalance);\n }\n }\n\n function redeem(\n uint256 shares,\n address receiver,\n address owner\n ) external returns (uint256 assets) {\n _burn(owner, shares);\n\n ERC20(frxETH).transfer(receiver, shares);\n\n assets = shares;\n }\n\n function withdraw(\n uint256 assets,\n address receiver,\n address owner\n ) external returns (uint256 shares) {\n _burn(owner, assets);\n\n ERC20(frxETH).transfer(receiver, assets);\n\n shares = assets;\n }\n\n function submitAndDeposit(address recipient)\n external\n payable\n returns (uint256 shares)\n {\n _mint(recipient, msg.value);\n shares = msg.value;\n }\n}\n" + }, + "contracts/mocks/MockSSV.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./MintableERC20.sol\";\n\ncontract MockSSV is MintableERC20 {\n constructor() ERC20(\"SSV Token\", \"SSV\") {}\n}\n" + }, + "contracts/mocks/MockSSVNetwork.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ncontract MockSSVNetwork {\n constructor() {}\n}\n" + }, + "contracts/mocks/MockstETH.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./MintableERC20.sol\";\n\ncontract MockstETH is MintableERC20 {\n constructor() ERC20(\"stETH\", \"stETH\") {}\n}\n" + }, + "contracts/mocks/MockStkAave.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 \"./MintableERC20.sol\";\n\ncontract MockStkAave is MintableERC20 {\n uint256 public COOLDOWN_SECONDS = 864000;\n uint256 public UNSTAKE_WINDOW = 172800;\n address public STAKED_TOKEN;\n\n mapping(address => uint256) public stakerRewardsToClaim;\n mapping(address => uint256) public stakersCooldowns;\n\n using SafeERC20 for IERC20;\n\n constructor(address _stakedToken) ERC20(\"Staked Aave\", \"stkAAVE\") {\n STAKED_TOKEN = _stakedToken;\n }\n\n function decimals() public pure override returns (uint8) {\n return 18;\n }\n\n function setStakedToken(address _stakedToken) external {\n STAKED_TOKEN = _stakedToken;\n }\n\n /**\n * @dev Redeems staked tokens, and stop earning rewards\n * @param to Address to redeem to\n * @param amount Amount to redeem\n **/\n function redeem(address to, uint256 amount) external {\n uint256 cooldownStartTimestamp = stakersCooldowns[msg.sender];\n uint256 windowStart = cooldownStartTimestamp + COOLDOWN_SECONDS;\n require(amount != 0, \"INVALID_ZERO_AMOUNT\");\n require(block.timestamp > windowStart, \"INSUFFICIENT_COOLDOWN\");\n require(\n block.timestamp - windowStart <= UNSTAKE_WINDOW,\n \"UNSTAKE_WINDOW_FINISHED\"\n );\n uint256 balanceOfMessageSender = balanceOf(msg.sender);\n uint256 amountToRedeem = (amount > balanceOfMessageSender)\n ? balanceOfMessageSender\n : amount;\n\n stakersCooldowns[msg.sender] = 0;\n _burn(msg.sender, amountToRedeem);\n IERC20(STAKED_TOKEN).safeTransfer(to, amountToRedeem);\n }\n\n /**\n * @dev Activates the cooldown period to unstake\n * - It can't be called if the user is not staking\n **/\n function cooldown() external {\n require(balanceOf(msg.sender) != 0, \"INVALID_BALANCE_ON_COOLDOWN\");\n stakersCooldowns[msg.sender] = block.timestamp;\n }\n\n /**\n * @dev Test helper function to allow changing the cooldown\n **/\n function setCooldown(address account, uint256 _cooldown) external {\n stakersCooldowns[account] = _cooldown;\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 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 require(false, \"Not implemented\");\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" + }, + "contracts/mocks/MockSwapper.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { IMintableERC20 } from \"./MintableERC20.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\ncontract MockSwapper {\n uint256 public nextOutAmount;\n\n function swap(\n // solhint-disable-next-line no-unused-vars\n address _fromAsset,\n address _toAsset,\n // solhint-disable-next-line no-unused-vars\n uint256 _fromAssetAmount,\n uint256 _minToAssetAmount,\n // solhint-disable-next-line no-unused-vars\n bytes calldata _data\n ) external returns (uint256 toAssetAmount) {\n toAssetAmount = (nextOutAmount > 0) ? nextOutAmount : _minToAssetAmount;\n nextOutAmount = 0;\n IMintableERC20(_toAsset).mint(toAssetAmount);\n IERC20(_toAsset).transfer(msg.sender, toAssetAmount);\n }\n\n function setNextOutAmount(uint256 _nextOutAmount) public {\n nextOutAmount = _nextOutAmount;\n }\n}\n" + }, + "contracts/mocks/MockTUSD.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./MintableERC20.sol\";\n\ncontract MockTUSD is MintableERC20 {\n constructor() ERC20(\"TrueUSD\", \"TUSD\") {}\n\n function decimals() public pure override returns (uint8) {\n return 18;\n }\n}\n" + }, + "contracts/mocks/MockUniswapPair.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { IUniswapV2Pair } from \"../interfaces/uniswap/IUniswapV2Pair.sol\";\n\ncontract MockUniswapPair is IUniswapV2Pair {\n address tok0;\n address tok1;\n uint112 reserve0;\n uint112 reserve1;\n uint256 blockTimestampLast;\n\n bool public hasSynced = false;\n\n constructor(\n address _token0,\n address _token1,\n uint112 _reserve0,\n uint112 _reserve1\n ) {\n tok0 = _token0;\n tok1 = _token1;\n reserve0 = _reserve0;\n reserve1 = _reserve1;\n blockTimestampLast = block.timestamp;\n }\n\n function token0() external view override returns (address) {\n return tok0;\n }\n\n function token1() external view override returns (address) {\n return tok1;\n }\n\n function getReserves()\n external\n view\n override\n returns (\n uint112,\n uint112,\n uint32\n )\n {\n return (reserve0, reserve1, uint32(blockTimestampLast));\n }\n\n function setReserves(uint112 _reserve0, uint112 _reserve1) public {\n reserve0 = _reserve0;\n reserve1 = _reserve1;\n blockTimestampLast = block.timestamp;\n }\n\n // CAUTION This will not work if you setReserves multiple times over\n // multiple different blocks because then it wouldn't be a continuous\n // reserve factor over that blockTimestamp, this assumes an even reserve\n // ratio all the way through\n function price0CumulativeLast() external view override returns (uint256) {\n return\n uint256(FixedPoint.fraction(reserve1, reserve0)._x) *\n blockTimestampLast;\n }\n\n function price1CumulativeLast() external view override returns (uint256) {\n return\n uint256(FixedPoint.fraction(reserve0, reserve1)._x) *\n blockTimestampLast;\n }\n\n function sync() external override {\n hasSynced = true;\n }\n\n function checkHasSynced() external view {\n require(hasSynced, \"Not synced\");\n }\n}\n\n// a library for handling binary fixed point numbers (https://en.wikipedia.org/wiki/Q_(number_format))\nlibrary FixedPoint {\n // range: [0, 2**112 - 1]\n // resolution: 1 / 2**112\n struct uq112x112 {\n uint224 _x;\n }\n\n // returns a uq112x112 which represents the ratio of the numerator to the denominator\n // equivalent to encode(numerator).div(denominator)\n function fraction(uint112 numerator, uint112 denominator)\n internal\n pure\n returns (uq112x112 memory)\n {\n require(denominator > 0, \"FixedPoint: DIV_BY_ZERO\");\n return uq112x112((uint224(numerator) << 112) / denominator);\n }\n}\n" + }, + "contracts/mocks/MockUniswapRouter.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { MintableERC20 } from \"./MintableERC20.sol\";\nimport { IUniswapV2Router } from \"../interfaces/uniswap/IUniswapV2Router02.sol\";\nimport { Helpers } from \"../utils/Helpers.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\n\ncontract MockUniswapRouter is IUniswapV2Router {\n using StableMath for uint256;\n\n mapping(address => address) public pairMaps;\n uint256 public slippage = 1 ether;\n\n function initialize(\n address[] calldata _0tokens,\n address[] calldata _1tokens\n ) public {\n require(\n _0tokens.length == _1tokens.length,\n \"Mock token pairs should be of the same length\"\n );\n for (uint256 i = 0; i < _0tokens.length; i++) {\n pairMaps[_0tokens[i]] = _1tokens[i];\n }\n }\n\n function setSlippage(uint256 _slippage) external {\n slippage = _slippage;\n }\n\n function swapExactTokensForTokens(\n uint256 amountIn,\n uint256 amountOutMin,\n address[] calldata path,\n address to,\n // solhint-disable-next-line no-unused-vars\n uint256\n ) external override returns (uint256[] memory amountsOut) {\n address tok0 = path[0];\n address tok1 = path[path.length - 1];\n\n uint256 amountOut = (amountOutMin * slippage) / 1 ether;\n require(amountOut >= amountOutMin, \"Slippage error\");\n\n IERC20(tok0).transferFrom(msg.sender, address(this), amountIn);\n MintableERC20(tok1).mintTo(to, amountOut);\n\n amountsOut = new uint256[](path.length);\n amountsOut[path.length - 1] = amountOut;\n }\n\n struct ExactInputParams {\n bytes path;\n address recipient;\n uint256 deadline;\n uint256 amountIn;\n uint256 amountOutMinimum;\n }\n\n function exactInput(ExactInputParams calldata params)\n external\n payable\n returns (uint256 amountOut)\n {\n (address tok0, address tok1) = _getFirstAndLastToken(params.path);\n\n amountOut = (params.amountOutMinimum * slippage) / 1 ether;\n\n IERC20(tok0).transferFrom(msg.sender, address(this), params.amountIn);\n MintableERC20(tok1).mintTo(params.recipient, amountOut);\n\n require(\n amountOut >= params.amountOutMinimum,\n \"UniswapMock: amountOut less than amountOutMinimum\"\n );\n return amountOut;\n }\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 override\n returns (\n uint256 amountA,\n uint256 amountB,\n uint256 liquidity\n )\n {\n // this is needed to make this contract whole else it'd be just virtual\n }\n\n function WETH() external pure override returns (address) {\n return address(0);\n }\n\n // Universal router mock\n function execute(\n bytes calldata,\n bytes[] calldata inputs,\n uint256\n ) external payable {\n uint256 inLen = inputs.length;\n for (uint256 i = 0; i < inLen; ++i) {\n (\n address recipient,\n ,\n uint256 amountOutMinimum,\n bytes memory path,\n\n ) = abi.decode(inputs[i], (address, uint256, uint256, bytes, bool));\n\n (address token0, address token1) = _getFirstAndLastToken(path);\n\n amountOutMinimum = amountOutMinimum.scaleBy(\n Helpers.getDecimals(token0),\n Helpers.getDecimals(token1)\n );\n\n MintableERC20(token1).mintTo(recipient, amountOutMinimum);\n }\n }\n\n function _getFirstAndLastToken(bytes memory path)\n internal\n view\n returns (address token0, address token1)\n {\n bytes memory tok0Bytes = new bytes(20);\n for (uint256 j = 0; j < 20; ++j) {\n tok0Bytes[j] = path[j];\n }\n token0 = address(bytes20(tok0Bytes));\n\n if (pairMaps[token0] != address(0)) {\n token0 = pairMaps[token0];\n }\n\n bytes memory tok1Bytes = new bytes(20);\n uint256 tok1Offset = path.length - 20;\n for (uint256 j = 0; j < 20; ++j) {\n tok1Bytes[j] = path[j + tok1Offset];\n }\n token1 = address(bytes20(tok1Bytes));\n\n if (pairMaps[token1] != address(0)) {\n token1 = pairMaps[token1];\n }\n }\n}\n" + }, + "contracts/mocks/MockUSDC.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./MintableERC20.sol\";\n\ncontract MockUSDC is MintableERC20 {\n constructor() ERC20(\"USDC Coin\", \"USDC\") {}\n\n function decimals() public pure override returns (uint8) {\n return 6;\n }\n}\n" + }, + "contracts/mocks/MockUSDT.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./MintableERC20.sol\";\n\ncontract MockUSDT is MintableERC20 {\n constructor() ERC20(\"USDT Coin\", \"USDT\") {}\n\n function decimals() public pure override returns (uint8) {\n return 6;\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/mocks/MockWETH.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./MintableERC20.sol\";\n\ncontract MockWETH is MintableERC20 {\n constructor() ERC20(\"WETH\", \"WETH\") {}\n\n function deposit() external payable {\n _mint(msg.sender, msg.value);\n }\n\n function withdraw(uint256 wad) external {\n _burn(msg.sender, wad);\n payable(msg.sender).transfer(wad);\n }\n}\n" + }, + "contracts/oracle/AuraWETHPriceFeed.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { Variable, OracleAverageQuery, IOracleWeightedPool } from \"../interfaces/balancer/IOracleWeightedPool.sol\";\nimport { Strategizable } from \"../governance/Strategizable.sol\";\nimport { AggregatorV3Interface } from \"../interfaces/chainlink/AggregatorV3Interface.sol\";\nimport { SafeCast } from \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\n\ncontract AuraWETHPriceFeed is AggregatorV3Interface, Strategizable {\n using SafeCast for uint256;\n using SafeCast for int256;\n\n event PriceFeedPaused();\n event PriceFeedUnpaused();\n event ToleranceChanged(uint256 oldTolerance, uint256 newTolerance);\n\n error PriceFeedPausedError();\n error PriceFeedUnpausedError();\n error InvalidToleranceBps();\n error HighPriceVolatility(uint256 deviation);\n\n bool public paused;\n uint256 public tolerance = 0.02 ether; // 2% by default\n\n // Fields to make it compatible with `AggregatorV3Interface`\n uint8 public constant override decimals = 18;\n string public constant override description = \"\";\n uint256 public constant override version = 1;\n\n IOracleWeightedPool public immutable auraOracleWeightedPool;\n\n constructor(address _auraOracleWeightedPool, address _governor) {\n _setGovernor(_governor);\n auraOracleWeightedPool = IOracleWeightedPool(_auraOracleWeightedPool);\n }\n\n /**\n * @dev Queries the OracleWeightedPool for TWAP of two intervals\n * (1h data from 5m ago and the recent 5m data) and ensures that\n * the price hasn't deviated too much and returns the most recent\n * TWAP price.\n *\n * @return price The price scaled to 18 decimals\n **/\n function price() external view returns (int256) {\n return _price();\n }\n\n function _price() internal view returns (int256) {\n if (paused) {\n revert PriceFeedPausedError();\n }\n OracleAverageQuery[] memory queries = new OracleAverageQuery[](2);\n\n queries[0] = OracleAverageQuery({\n variable: Variable.PAIR_PRICE,\n secs: 3600, // Get 1h data\n ago: 300 // From 5min ago\n });\n queries[1] = OracleAverageQuery({\n variable: Variable.PAIR_PRICE,\n secs: 300, // Get 5min data\n ago: 0 // From now\n });\n\n uint256[] memory prices = auraOracleWeightedPool.getTimeWeightedAverage(\n queries\n );\n int256 price_1h = prices[0].toInt256();\n int256 price_5m = prices[1].toInt256();\n\n int256 diff = (1e18 * (price_1h - price_5m)) /\n ((price_1h + price_5m) / 2);\n uint256 absDiff = diff >= 0 ? diff.toUint256() : (-diff).toUint256();\n\n // Ensure the price hasn't moved too much (2% tolerance)\n // between now and the past hour\n if (absDiff > tolerance) {\n revert HighPriceVolatility(absDiff);\n }\n\n // Return the recent price\n return price_5m;\n }\n\n /**\n * Pauses the price feed. Callable by Strategist as well.\n **/\n function pause() external onlyGovernorOrStrategist {\n if (paused) {\n revert PriceFeedPausedError();\n }\n paused = true;\n emit PriceFeedPaused();\n }\n\n /**\n * Unpauses the price feed. Only Governor can call it\n **/\n function unpause() external onlyGovernor {\n if (!paused) {\n revert PriceFeedUnpausedError();\n }\n paused = false;\n emit PriceFeedUnpaused();\n }\n\n /**\n * Set the max amount of tolerance acceptable between\n * two different price points.\n *\n * @param _tolerance New tolerance value\n **/\n function setTolerance(uint256 _tolerance) external onlyGovernor {\n if (_tolerance > 0.1 ether) {\n revert InvalidToleranceBps();\n }\n emit ToleranceChanged(tolerance, _tolerance);\n tolerance = _tolerance;\n }\n\n /**\n * @dev This function exists to make the contract compatible\n * with AggregatorV3Interface (which OETHOracleRouter uses to\n * get the price).\n *\n * The `answer` returned by this is same as what `price()` would return.\n *\n * It doesn't return any data about rounds (since those doesn't exist).\n **/\n function latestRoundData()\n external\n view\n override\n returns (\n uint80,\n int256 answer,\n uint256,\n uint256 updatedAt,\n uint80\n )\n {\n answer = _price();\n updatedAt = block.timestamp;\n }\n\n /**\n * @dev This function exists to make the contract compatible\n * with AggregatorV3Interface.\n *\n * Always reverts since there're no round data in this contract.\n **/\n function getRoundData(uint80)\n external\n pure\n override\n returns (\n uint80,\n int256,\n uint256,\n uint256,\n uint80\n )\n {\n revert(\"No data present\");\n }\n}\n" + }, + "contracts/oracle/OETHFixedOracle.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { OETHOracleRouter } from \"./OETHOracleRouter.sol\";\n\n// @notice Oracle Router that returns 1e18 for all prices\n// used solely for deployment to testnets\ncontract OETHFixedOracle is OETHOracleRouter {\n constructor(address _auraPriceFeed) OETHOracleRouter(_auraPriceFeed) {}\n\n /**\n * @dev The price feed contract to use for a particular asset along with\n * maximum data staleness\n * @param asset address of the asset\n * @return feedAddress address of the price feed for the asset\n * @return maxStaleness maximum acceptable data staleness duration\n */\n // solhint-disable-next-line no-unused-vars\n function feedMetadata(address asset)\n internal\n view\n virtual\n override\n returns (address feedAddress, uint256 maxStaleness)\n {\n // fixes price for all of the assets\n feedAddress = FIXED_PRICE;\n maxStaleness = 0;\n }\n}\n" + }, + "contracts/oracle/OETHOracleRouter.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../interfaces/chainlink/AggregatorV3Interface.sol\";\nimport { OracleRouterBase } from \"./OracleRouterBase.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\n\n// @notice Oracle Router that denominates all prices in ETH\ncontract OETHOracleRouter is OracleRouterBase {\n using StableMath for uint256;\n\n address public immutable auraPriceFeed;\n\n constructor(address _auraPriceFeed) {\n auraPriceFeed = _auraPriceFeed;\n }\n\n /**\n * @notice Returns the total price in 18 digit units for a given asset.\n * This implementation does not (!) do range checks as the\n * parent OracleRouter does.\n * @param asset address of the asset\n * @return uint256 unit price for 1 asset unit, in 18 decimal fixed\n */\n function price(address asset)\n external\n view\n virtual\n override\n returns (uint256)\n {\n (address _feed, uint256 maxStaleness) = feedMetadata(asset);\n if (_feed == FIXED_PRICE) {\n return 1e18;\n }\n require(_feed != address(0), \"Asset not available\");\n\n // slither-disable-next-line unused-return\n (, int256 _iprice, , uint256 updatedAt, ) = AggregatorV3Interface(_feed)\n .latestRoundData();\n\n require(\n updatedAt + maxStaleness >= block.timestamp,\n \"Oracle price too old\"\n );\n\n uint8 decimals = getDecimals(_feed);\n uint256 _price = uint256(_iprice).scaleBy(18, decimals);\n return _price;\n }\n\n /**\n * @dev The price feed contract to use for a particular asset along with\n * maximum data staleness\n * @param asset address of the asset\n * @return feedAddress address of the price feed for the asset\n * @return maxStaleness maximum acceptable data staleness duration\n */\n function feedMetadata(address asset)\n internal\n view\n virtual\n override\n returns (address feedAddress, uint256 maxStaleness)\n {\n if (asset == 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2) {\n // FIXED_PRICE: WETH/ETH\n feedAddress = FIXED_PRICE;\n maxStaleness = 0;\n } else if (asset == 0x5E8422345238F34275888049021821E8E08CAa1f) {\n // frxETH/ETH\n feedAddress = 0xC58F3385FBc1C8AD2c0C9a061D7c13b141D7A5Df;\n maxStaleness = 18 hours + STALENESS_BUFFER;\n } else if (asset == 0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84) {\n // https://data.chain.link/ethereum/mainnet/crypto-eth/steth-eth\n // Chainlink: stETH/ETH\n feedAddress = 0x86392dC19c0b719886221c78AB11eb8Cf5c52812;\n maxStaleness = 1 days + STALENESS_BUFFER;\n } else if (asset == 0xae78736Cd615f374D3085123A210448E74Fc6393) {\n // https://data.chain.link/ethereum/mainnet/crypto-eth/reth-eth\n // Chainlink: rETH/ETH\n feedAddress = 0x536218f9E9Eb48863970252233c8F271f554C2d0;\n maxStaleness = 1 days + STALENESS_BUFFER;\n } else if (asset == 0xD533a949740bb3306d119CC777fa900bA034cd52) {\n // https://data.chain.link/ethereum/mainnet/crypto-eth/crv-eth\n // Chainlink: CRV/ETH\n feedAddress = 0x8a12Be339B0cD1829b91Adc01977caa5E9ac121e;\n maxStaleness = 1 days + STALENESS_BUFFER;\n } else if (asset == 0x4e3FBD56CD56c3e72c1403e103b45Db9da5B9D2B) {\n // https://data.chain.link/ethereum/mainnet/crypto-eth/cvx-eth\n // Chainlink: CVX/ETH\n feedAddress = 0xC9CbF687f43176B302F03f5e58470b77D07c61c6;\n maxStaleness = 1 days + STALENESS_BUFFER;\n } else if (asset == 0xBe9895146f7AF43049ca1c1AE358B0541Ea49704) {\n // https://data.chain.link/ethereum/mainnet/crypto-eth/cbeth-eth\n // Chainlink: cbETH/ETH\n feedAddress = 0xF017fcB346A1885194689bA23Eff2fE6fA5C483b;\n maxStaleness = 1 days + STALENESS_BUFFER;\n } else if (asset == 0xba100000625a3754423978a60c9317c58a424e3D) {\n // https://data.chain.link/ethereum/mainnet/crypto-eth/bal-eth\n // Chainlink: BAL/ETH\n feedAddress = 0xC1438AA3823A6Ba0C159CfA8D98dF5A994bA120b;\n maxStaleness = 1 days + STALENESS_BUFFER;\n } else if (asset == 0xC0c293ce456fF0ED870ADd98a0828Dd4d2903DBF) {\n // AURA/ETH\n feedAddress = auraPriceFeed;\n maxStaleness = 0;\n } else {\n revert(\"Asset not available\");\n }\n }\n}\n" + }, + "contracts/oracle/OracleRouter.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../interfaces/chainlink/AggregatorV3Interface.sol\";\nimport { OracleRouterBase } from \"./OracleRouterBase.sol\";\n\n// @notice Oracle Router that denominates all prices in USD\ncontract OracleRouter is OracleRouterBase {\n /**\n * @dev The price feed contract to use for a particular asset along with\n * maximum data staleness\n * @param asset address of the asset\n * @return feedAddress address of the price feed for the asset\n * @return maxStaleness maximum acceptable data staleness duration\n */\n function feedMetadata(address asset)\n internal\n pure\n virtual\n override\n returns (address feedAddress, uint256 maxStaleness)\n {\n /* + STALENESS_BUFFER is added in case Oracle for some reason doesn't\n * update on heartbeat and we add a generous buffer amount.\n */\n if (asset == 0x6B175474E89094C44Da98b954EedeAC495271d0F) {\n // https://data.chain.link/ethereum/mainnet/stablecoins/dai-usd\n // Chainlink: DAI/USD\n feedAddress = 0xAed0c38402a5d19df6E4c03F4E2DceD6e29c1ee9;\n maxStaleness = 1 hours + STALENESS_BUFFER;\n } else if (asset == 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48) {\n // https://data.chain.link/ethereum/mainnet/stablecoins/usdc-usd\n // Chainlink: USDC/USD\n feedAddress = 0x8fFfFfd4AfB6115b954Bd326cbe7B4BA576818f6;\n maxStaleness = 1 days + STALENESS_BUFFER;\n } else if (asset == 0xdAC17F958D2ee523a2206206994597C13D831ec7) {\n // https://data.chain.link/ethereum/mainnet/stablecoins/usdt-usd\n // Chainlink: USDT/USD\n feedAddress = 0x3E7d1eAB13ad0104d2750B8863b489D65364e32D;\n maxStaleness = 1 days + STALENESS_BUFFER;\n } else if (asset == 0xc00e94Cb662C3520282E6f5717214004A7f26888) {\n // https://data.chain.link/ethereum/mainnet/crypto-usd/comp-usd\n // Chainlink: COMP/USD\n feedAddress = 0xdbd020CAeF83eFd542f4De03e3cF0C28A4428bd5;\n maxStaleness = 1 hours + STALENESS_BUFFER;\n } else if (asset == 0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9) {\n // https://data.chain.link/ethereum/mainnet/crypto-usd/aave-usd\n // Chainlink: AAVE/USD\n feedAddress = 0x547a514d5e3769680Ce22B2361c10Ea13619e8a9;\n maxStaleness = 1 hours + STALENESS_BUFFER;\n } else if (asset == 0xD533a949740bb3306d119CC777fa900bA034cd52) {\n // https://data.chain.link/ethereum/mainnet/crypto-usd/crv-usd\n // Chainlink: CRV/USD\n feedAddress = 0xCd627aA160A6fA45Eb793D19Ef54f5062F20f33f;\n maxStaleness = 1 days + STALENESS_BUFFER;\n } else if (asset == 0x4e3FBD56CD56c3e72c1403e103b45Db9da5B9D2B) {\n // Chainlink: CVX/USD\n feedAddress = 0xd962fC30A72A84cE50161031391756Bf2876Af5D;\n maxStaleness = 1 days + STALENESS_BUFFER;\n } else {\n revert(\"Asset not available\");\n }\n }\n}\n" + }, + "contracts/oracle/OracleRouterBase.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../interfaces/chainlink/AggregatorV3Interface.sol\";\nimport { IOracle } from \"../interfaces/IOracle.sol\";\nimport { Helpers } from \"../utils/Helpers.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\nimport { SafeCast } from \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\n\n// @notice Abstract functionality that is shared between various Oracle Routers\nabstract contract OracleRouterBase is IOracle {\n using StableMath for uint256;\n using SafeCast for int256;\n\n uint256 internal constant MIN_DRIFT = 0.7e18;\n uint256 internal constant MAX_DRIFT = 1.3e18;\n address internal constant FIXED_PRICE =\n 0x0000000000000000000000000000000000000001;\n // Maximum allowed staleness buffer above normal Oracle maximum staleness\n uint256 internal constant STALENESS_BUFFER = 1 days;\n mapping(address => uint8) internal decimalsCache;\n\n /**\n * @dev The price feed contract to use for a particular asset along with\n * maximum data staleness\n * @param asset address of the asset\n * @return feedAddress address of the price feed for the asset\n * @return maxStaleness maximum acceptable data staleness duration\n */\n function feedMetadata(address asset)\n internal\n view\n virtual\n returns (address feedAddress, uint256 maxStaleness);\n\n /**\n * @notice Returns the total price in 18 digit unit for a given asset.\n * @param asset address of the asset\n * @return uint256 unit price for 1 asset unit, in 18 decimal fixed\n */\n function price(address asset)\n external\n view\n virtual\n override\n returns (uint256)\n {\n (address _feed, uint256 maxStaleness) = feedMetadata(asset);\n require(_feed != address(0), \"Asset not available\");\n require(_feed != FIXED_PRICE, \"Fixed price feeds not supported\");\n\n // slither-disable-next-line unused-return\n (, int256 _iprice, , uint256 updatedAt, ) = AggregatorV3Interface(_feed)\n .latestRoundData();\n\n require(\n updatedAt + maxStaleness >= block.timestamp,\n \"Oracle price too old\"\n );\n\n uint8 decimals = getDecimals(_feed);\n\n uint256 _price = _iprice.toUint256().scaleBy(18, decimals);\n if (shouldBePegged(asset)) {\n require(_price <= MAX_DRIFT, \"Oracle: Price exceeds max\");\n require(_price >= MIN_DRIFT, \"Oracle: Price under min\");\n }\n return _price;\n }\n\n function getDecimals(address _feed) internal view virtual returns (uint8) {\n uint8 decimals = decimalsCache[_feed];\n require(decimals > 0, \"Oracle: Decimals not cached\");\n return decimals;\n }\n\n /**\n * @notice Before an asset/feed price is fetches for the first time the\n * decimals need to be cached. This is a gas optimization\n * @param asset address of the asset\n * @return uint8 corresponding asset decimals\n */\n function cacheDecimals(address asset) external returns (uint8) {\n (address _feed, ) = feedMetadata(asset);\n require(_feed != address(0), \"Asset not available\");\n require(_feed != FIXED_PRICE, \"Fixed price feeds not supported\");\n\n uint8 decimals = AggregatorV3Interface(_feed).decimals();\n decimalsCache[_feed] = decimals;\n return decimals;\n }\n\n function shouldBePegged(address _asset) internal view returns (bool) {\n string memory symbol = Helpers.getSymbol(_asset);\n bytes32 symbolHash = keccak256(abi.encodePacked(symbol));\n return\n symbolHash == keccak256(abi.encodePacked(\"DAI\")) ||\n symbolHash == keccak256(abi.encodePacked(\"USDC\")) ||\n symbolHash == keccak256(abi.encodePacked(\"USDT\"));\n }\n}\n" + }, + "contracts/proxies/InitializeGovernedUpgradeabilityProxy.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { Address } from \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport { Governable } from \"../governance/Governable.sol\";\n\n/**\n * @title BaseGovernedUpgradeabilityProxy\n * @dev This contract combines an upgradeability proxy with our governor system.\n * It is based on an older version of OpenZeppelins BaseUpgradeabilityProxy\n * with Solidity ^0.8.0.\n * @author Origin Protocol Inc\n */\ncontract InitializeGovernedUpgradeabilityProxy is Governable {\n /**\n * @dev Emitted when the implementation is upgraded.\n * @param implementation Address of the new implementation.\n */\n event Upgraded(address indexed implementation);\n\n /**\n * @dev Contract initializer with Governor enforcement\n * @param _logic Address of the initial implementation.\n * @param _initGovernor Address of the initial Governor.\n * @param _data Data to send as msg.data to the implementation to initialize\n * the proxied contract.\n * It should include the signature and the parameters of the function to be\n * called, as described in\n * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.\n * This parameter is optional, if no data is given the initialization call\n * to proxied contract will be skipped.\n */\n function initialize(\n address _logic,\n address _initGovernor,\n bytes calldata _data\n ) public payable onlyGovernor {\n require(_implementation() == address(0));\n assert(\n IMPLEMENTATION_SLOT ==\n bytes32(uint256(keccak256(\"eip1967.proxy.implementation\")) - 1)\n );\n _setImplementation(_logic);\n if (_data.length > 0) {\n (bool success, ) = _logic.delegatecall(_data);\n require(success);\n }\n _changeGovernor(_initGovernor);\n }\n\n /**\n * @return The address of the proxy admin/it's also the governor.\n */\n function admin() external view returns (address) {\n return _governor();\n }\n\n /**\n * @return The address of the implementation.\n */\n function implementation() external view returns (address) {\n return _implementation();\n }\n\n /**\n * @dev Upgrade the backing implementation of the proxy.\n * Only the admin can call this function.\n * @param newImplementation Address of the new implementation.\n */\n function upgradeTo(address newImplementation) external onlyGovernor {\n _upgradeTo(newImplementation);\n }\n\n /**\n * @dev Upgrade the backing implementation of the proxy and call a function\n * on the new implementation.\n * This is useful to initialize the proxied contract.\n * @param newImplementation Address of the new implementation.\n * @param data Data to send as msg.data in the low level call.\n * It should include the signature and the parameters of the function to be called, as described in\n * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.\n */\n function upgradeToAndCall(address newImplementation, bytes calldata data)\n external\n payable\n onlyGovernor\n {\n _upgradeTo(newImplementation);\n (bool success, ) = newImplementation.delegatecall(data);\n require(success);\n }\n\n /**\n * @dev Fallback function.\n * Implemented entirely in `_fallback`.\n */\n fallback() external payable {\n _fallback();\n }\n\n /**\n * @dev Delegates execution to an implementation contract.\n * This is a low level function that doesn't return to its internal call site.\n * It will return to the external caller whatever the implementation returns.\n * @param _impl Address to delegate.\n */\n function _delegate(address _impl) internal {\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(gas(), _impl, 0, calldatasize(), 0, 0)\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 /**\n * @dev Function that is run as the first thing in the fallback function.\n * Can be redefined in derived contracts to add functionality.\n * Redefinitions must call super._willFallback().\n */\n function _willFallback() internal {}\n\n /**\n * @dev fallback implementation.\n * Extracted to enable manual triggering.\n */\n function _fallback() internal {\n _willFallback();\n _delegate(_implementation());\n }\n\n /**\n * @dev Storage slot with the address of the current implementation.\n * This is the keccak-256 hash of \"eip1967.proxy.implementation\" subtracted by 1, and is\n * validated in the constructor.\n */\n bytes32 internal constant IMPLEMENTATION_SLOT =\n 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\n\n /**\n * @dev Returns the current implementation.\n * @return impl Address of the current implementation\n */\n function _implementation() internal view returns (address impl) {\n bytes32 slot = IMPLEMENTATION_SLOT;\n // solhint-disable-next-line no-inline-assembly\n assembly {\n impl := sload(slot)\n }\n }\n\n /**\n * @dev Upgrades the proxy to a new implementation.\n * @param newImplementation Address of the new implementation.\n */\n function _upgradeTo(address newImplementation) internal {\n _setImplementation(newImplementation);\n emit Upgraded(newImplementation);\n }\n\n /**\n * @dev Sets the implementation address of the proxy.\n * @param newImplementation Address of the new implementation.\n */\n function _setImplementation(address newImplementation) internal {\n require(\n Address.isContract(newImplementation),\n \"Cannot set a proxy implementation to a non-contract address\"\n );\n\n bytes32 slot = IMPLEMENTATION_SLOT;\n\n // solhint-disable-next-line no-inline-assembly\n assembly {\n sstore(slot, newImplementation)\n }\n }\n}\n" + }, + "contracts/proxies/Proxies.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { InitializeGovernedUpgradeabilityProxy } from \"./InitializeGovernedUpgradeabilityProxy.sol\";\n\n/**\n * @notice OUSDProxy delegates calls to an OUSD implementation\n */\ncontract OUSDProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice WrappedOUSDProxy delegates calls to a WrappedOUSD implementation\n */\ncontract WrappedOUSDProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice VaultProxy delegates calls to a Vault implementation\n */\ncontract VaultProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice CompoundStrategyProxy delegates calls to a CompoundStrategy implementation\n */\ncontract CompoundStrategyProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice AaveStrategyProxy delegates calls to a AaveStrategy implementation\n */\ncontract AaveStrategyProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice ThreePoolStrategyProxy delegates calls to a ThreePoolStrategy implementation\n */\ncontract ThreePoolStrategyProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice ConvexStrategyProxy delegates calls to a ConvexStrategy implementation\n */\ncontract ConvexStrategyProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice HarvesterProxy delegates calls to a Harvester implementation\n */\ncontract HarvesterProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice DripperProxy delegates calls to a Dripper implementation\n */\ncontract DripperProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice MorphoCompoundStrategyProxy delegates calls to a MorphoCompoundStrategy implementation\n */\ncontract MorphoCompoundStrategyProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice ConvexOUSDMetaStrategyProxy delegates calls to a ConvexOUSDMetaStrategy implementation\n */\ncontract ConvexOUSDMetaStrategyProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice ConvexLUSDMetaStrategyProxy delegates calls to a ConvexalGeneralizedMetaStrategy implementation\n */\ncontract ConvexLUSDMetaStrategyProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice MorphoAaveStrategyProxy delegates calls to a MorphoCompoundStrategy implementation\n */\ncontract MorphoAaveStrategyProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice OETHProxy delegates calls to nowhere for now\n */\ncontract OETHProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice WOETHProxy delegates calls to nowhere for now\n */\ncontract WOETHProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice OETHVaultProxy delegates calls to a Vault implementation\n */\ncontract OETHVaultProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice OETHDripperProxy delegates calls to a OETHDripper implementation\n */\ncontract OETHDripperProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice OETHHarvesterProxy delegates calls to a Harvester implementation\n */\ncontract OETHHarvesterProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice FraxETHStrategyProxy delegates calls to a FraxETHStrategy implementation\n */\ncontract FraxETHStrategyProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice CurveEthStrategyProxy delegates calls to a CurveEthStrategy implementation\n */\ncontract ConvexEthMetaStrategyProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice BuybackProxy delegates calls to Buyback implementation\n */\ncontract BuybackProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice OETHMorphoAaveStrategyProxy delegates calls to a MorphoAaveStrategy implementation\n */\ncontract OETHMorphoAaveStrategyProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice OETHBalancerMetaPoolrEthStrategyProxy delegates calls to a BalancerMetaPoolStrategy implementation\n */\ncontract OETHBalancerMetaPoolrEthStrategyProxy is\n InitializeGovernedUpgradeabilityProxy\n{\n\n}\n\n/**\n * @notice OETHBalancerMetaPoolwstEthStrategyProxy delegates calls to a BalancerMetaPoolStrategy implementation\n */\ncontract OETHBalancerMetaPoolwstEthStrategyProxy is\n InitializeGovernedUpgradeabilityProxy\n{\n\n}\n\n/**\n * @notice FluxStrategyProxy delegates calls to a CompoundStrategy implementation\n */\ncontract FluxStrategyProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice MakerDsrStrategyProxy delegates calls to a Generalized4626Strategy implementation\n */\ncontract MakerDsrStrategyProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice FrxEthRedeemStrategyProxy delegates calls to a FrxEthRedeemStrategy implementation\n */\ncontract FrxEthRedeemStrategyProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice OETHBuybackProxy delegates calls to Buyback implementation\n */\ncontract OETHBuybackProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice BridgedWOETHProxy delegates calls to BridgedWOETH implementation\n */\ncontract BridgedWOETHProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice NativeStakingSSVStrategyProxy delegates calls to NativeStakingSSVStrategy implementation\n */\ncontract NativeStakingSSVStrategyProxy is\n InitializeGovernedUpgradeabilityProxy\n{\n\n}\n\n/**\n * @notice NativeStakingFeeAccumulatorProxy delegates calls to NativeStakingFeeCollector implementation\n */\ncontract NativeStakingFeeAccumulatorProxy is\n InitializeGovernedUpgradeabilityProxy\n{\n\n}\n" + }, + "contracts/staking/SingleAssetStaking.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeMath } from \"@openzeppelin/contracts/utils/math/SafeMath.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 { StableMath } from \"../utils/StableMath.sol\";\n\ncontract SingleAssetStaking is Initializable, Governable {\n using SafeMath for uint256;\n using StableMath for uint256;\n using SafeERC20 for IERC20;\n\n /* ========== STATE VARIABLES ========== */\n\n IERC20 public stakingToken; // this is both the staking and rewards\n\n struct Stake {\n uint256 amount; // amount to stake\n uint256 end; // when does the staking period end\n uint256 duration; // the duration of the stake\n uint240 rate; // rate to charge use 248 to reserve 8 bits for the bool\n bool paid;\n uint8 stakeType;\n }\n\n struct DropRoot {\n bytes32 hash;\n uint256 depth;\n }\n\n uint256[] public durations; // allowed durations\n uint256[] public rates; // rates that correspond with the allowed durations\n\n uint256 public totalOutstanding;\n bool public paused;\n\n mapping(address => Stake[]) public userStakes;\n\n mapping(uint8 => DropRoot) public dropRoots;\n\n // type 0 is reserved for stakes done by the user, all other types will be drop/preApproved stakes\n uint8 constant USER_STAKE_TYPE = 0;\n uint256 constant MAX_STAKES = 256;\n\n address public transferAgent;\n\n /* ========== Initialize ========== */\n\n /**\n * @dev Initialize the contracts, sets up durations, rates, and preApprover\n * for preApproved contracts can only be called once\n * @param _stakingToken Address of the token that we are staking\n * @param _durations Array of allowed durations in seconds\n * @param _rates Array of rates(0.3 is 30%) that correspond to the allowed\n * durations in 1e18 precision\n */\n function initialize(\n address _stakingToken,\n uint256[] calldata _durations,\n uint256[] calldata _rates\n ) external onlyGovernor initializer {\n stakingToken = IERC20(_stakingToken);\n _setDurationRates(_durations, _rates);\n }\n\n /* ========= Internal helper functions ======== */\n\n /**\n * @dev Validate and set the duration and corresponding rates, will emit\n * events NewRate and NewDurations\n */\n function _setDurationRates(\n uint256[] memory _durations,\n uint256[] memory _rates\n ) internal {\n require(\n _rates.length == _durations.length,\n \"Mismatch durations and rates\"\n );\n\n for (uint256 i = 0; i < _rates.length; i++) {\n require(_rates[i] < type(uint240).max, \"Max rate exceeded\");\n }\n\n rates = _rates;\n durations = _durations;\n\n emit NewRates(msg.sender, rates);\n emit NewDurations(msg.sender, durations);\n }\n\n function _totalExpectedRewards(Stake[] storage stakes)\n internal\n view\n returns (uint256 total)\n {\n for (uint256 i = 0; i < stakes.length; i++) {\n Stake storage stake = stakes[i];\n if (!stake.paid) {\n total = total.add(stake.amount.mulTruncate(stake.rate));\n }\n }\n }\n\n function _totalExpected(Stake storage _stake)\n internal\n view\n returns (uint256)\n {\n return _stake.amount.add(_stake.amount.mulTruncate(_stake.rate));\n }\n\n function _airDroppedStakeClaimed(address account, uint8 stakeType)\n internal\n view\n returns (bool)\n {\n Stake[] storage stakes = userStakes[account];\n for (uint256 i = 0; i < stakes.length; i++) {\n if (stakes[i].stakeType == stakeType) {\n return true;\n }\n }\n return false;\n }\n\n function _findDurationRate(uint256 duration)\n internal\n view\n returns (uint240)\n {\n for (uint256 i = 0; i < durations.length; i++) {\n if (duration == durations[i]) {\n return uint240(rates[i]);\n }\n }\n return 0;\n }\n\n /**\n * @dev Internal staking function\n * will insert the stake into the stakes array and verify we have\n * enough to pay off stake + reward\n * @param staker Address of the staker\n * @param stakeType Number that represent the type of the stake, 0 is user\n * initiated all else is currently preApproved\n * @param duration Number of seconds this stake will be held for\n * @param rate Rate(0.3 is 30%) of reward for this stake in 1e18, uint240 =\n * to fit the bool and type in struct Stake\n * @param amount Number of tokens to stake in 1e18\n */\n function _stake(\n address staker,\n uint8 stakeType,\n uint256 duration,\n uint240 rate,\n uint256 amount\n ) internal {\n require(!paused, \"Staking paused\");\n\n Stake[] storage stakes = userStakes[staker];\n\n uint256 end = block.timestamp.add(duration);\n\n uint256 i = stakes.length; // start at the end of the current array\n\n require(i < MAX_STAKES, \"Max stakes\");\n\n stakes.push(); // grow the array\n // find the spot where we can insert the current stake\n // this should make an increasing list sorted by end\n while (i != 0 && stakes[i - 1].end > end) {\n // shift it back one\n stakes[i] = stakes[i - 1];\n i -= 1;\n }\n\n // insert the stake\n Stake storage newStake = stakes[i];\n newStake.rate = rate;\n newStake.stakeType = stakeType;\n newStake.end = end;\n newStake.duration = duration;\n newStake.amount = amount;\n\n totalOutstanding = totalOutstanding.add(_totalExpected(newStake));\n\n emit Staked(staker, amount, duration, rate);\n }\n\n function _stakeWithChecks(\n address staker,\n uint256 amount,\n uint256 duration\n ) internal {\n require(amount > 0, \"Cannot stake 0\");\n\n uint240 rewardRate = _findDurationRate(duration);\n require(rewardRate > 0, \"Invalid duration\"); // we couldn't find the rate that correspond to the passed duration\n\n _stake(staker, USER_STAKE_TYPE, duration, rewardRate, amount);\n // transfer in the token so that we can stake the correct amount\n stakingToken.safeTransferFrom(staker, address(this), amount);\n }\n\n modifier requireLiquidity() {\n // we need to have enough balance to cover the rewards after the operation is complete\n _;\n require(\n stakingToken.balanceOf(address(this)) >= totalOutstanding,\n \"Insufficient rewards\"\n );\n }\n\n /* ========== VIEWS ========== */\n\n function getAllDurations() external view returns (uint256[] memory) {\n return durations;\n }\n\n function getAllRates() external view returns (uint256[] memory) {\n return rates;\n }\n\n /**\n * @dev Return all the stakes paid and unpaid for a given user\n * @param account Address of the account that we want to look up\n */\n function getAllStakes(address account)\n external\n view\n returns (Stake[] memory)\n {\n return userStakes[account];\n }\n\n /**\n * @dev Find the rate that corresponds to a given duration\n * @param _duration Number of seconds\n */\n function durationRewardRate(uint256 _duration)\n external\n view\n returns (uint256)\n {\n return _findDurationRate(_duration);\n }\n\n /**\n * @dev Has the airdropped stake already been claimed\n */\n function airDroppedStakeClaimed(address account, uint8 stakeType)\n external\n view\n returns (bool)\n {\n return _airDroppedStakeClaimed(account, stakeType);\n }\n\n /**\n * @dev Calculate all the staked value a user has put into the contract,\n * rewards not included\n * @param account Address of the account that we want to look up\n */\n function totalStaked(address account)\n external\n view\n returns (uint256 total)\n {\n Stake[] storage stakes = userStakes[account];\n\n for (uint256 i = 0; i < stakes.length; i++) {\n if (!stakes[i].paid) {\n total = total.add(stakes[i].amount);\n }\n }\n }\n\n /**\n * @dev Calculate all the rewards a user can expect to receive.\n * @param account Address of the account that we want to look up\n */\n function totalExpectedRewards(address account)\n external\n view\n returns (uint256)\n {\n return _totalExpectedRewards(userStakes[account]);\n }\n\n /**\n * @dev Calculate all current holdings of a user: staked value + prorated rewards\n * @param account Address of the account that we want to look up\n */\n function totalCurrentHoldings(address account)\n external\n view\n returns (uint256 total)\n {\n Stake[] storage stakes = userStakes[account];\n\n for (uint256 i = 0; i < stakes.length; i++) {\n Stake storage stake = stakes[i];\n if (stake.paid) {\n continue;\n } else if (stake.end < block.timestamp) {\n total = total.add(_totalExpected(stake));\n } else {\n //calcualte the precentage accrued in term of rewards\n total = total.add(\n stake.amount.add(\n stake.amount.mulTruncate(stake.rate).mulTruncate(\n stake\n .duration\n .sub(stake.end.sub(block.timestamp))\n .divPrecisely(stake.duration)\n )\n )\n );\n }\n }\n }\n\n /* ========== MUTATIVE FUNCTIONS ========== */\n\n /**\n * @dev Make a preapproved stake for the user, this is a presigned voucher that the user can redeem either from\n * an airdrop or a compensation program.\n * Only 1 of each type is allowed per user. The proof must match the root hash\n * @param index Number that is zero base index of the stake in the payout entry\n * @param stakeType Number that represent the type of the stake, must not be 0 which is user stake\n * @param duration Number of seconds this stake will be held for\n * @param rate Rate(0.3 is 30%) of reward for this stake in 1e18, uint240 to fit the bool and type in struct Stake\n * @param amount Number of tokens to stake in 1e18\n * @param merkleProof Array of proofs for that amount\n */\n function airDroppedStake(\n uint256 index,\n uint8 stakeType,\n uint256 duration,\n uint256 rate,\n uint256 amount,\n bytes32[] calldata merkleProof\n ) external requireLiquidity {\n require(stakeType != USER_STAKE_TYPE, \"Cannot be normal staking\");\n require(rate < type(uint240).max, \"Max rate exceeded\");\n require(index < 2**merkleProof.length, \"Invalid index\");\n DropRoot storage dropRoot = dropRoots[stakeType];\n require(merkleProof.length == dropRoot.depth, \"Invalid proof\");\n\n // Compute the merkle root\n bytes32 node = keccak256(\n abi.encodePacked(\n index,\n stakeType,\n address(this),\n msg.sender,\n duration,\n rate,\n amount\n )\n );\n uint256 path = index;\n for (uint16 i = 0; i < merkleProof.length; i++) {\n if ((path & 0x01) == 1) {\n node = keccak256(abi.encodePacked(merkleProof[i], node));\n } else {\n node = keccak256(abi.encodePacked(node, merkleProof[i]));\n }\n path /= 2;\n }\n\n // Check the merkle proof\n require(node == dropRoot.hash, \"Stake not approved\");\n\n // verify that we haven't already staked\n require(\n !_airDroppedStakeClaimed(msg.sender, stakeType),\n \"Already staked\"\n );\n\n _stake(msg.sender, stakeType, duration, uint240(rate), amount);\n }\n\n /**\n * @dev Stake an approved amount of staking token into the contract.\n * User must have already approved the contract for specified amount.\n * @param amount Number of tokens to stake in 1e18\n * @param duration Number of seconds this stake will be held for\n */\n function stake(uint256 amount, uint256 duration) external requireLiquidity {\n // no checks are performed in this function since those are already present in _stakeWithChecks\n _stakeWithChecks(msg.sender, amount, duration);\n }\n\n /**\n * @dev Stake an approved amount of staking token into the contract. This function\n * can only be called by OGN token contract.\n * @param staker Address of the account that is creating the stake\n * @param amount Number of tokens to stake in 1e18\n * @param duration Number of seconds this stake will be held for\n */\n function stakeWithSender(\n address staker,\n uint256 amount,\n uint256 duration\n ) external requireLiquidity returns (bool) {\n require(\n msg.sender == address(stakingToken),\n \"Only token contract can make this call\"\n );\n\n _stakeWithChecks(staker, amount, duration);\n return true;\n }\n\n /**\n * @dev Exit out of all possible stakes\n */\n function exit() external requireLiquidity {\n Stake[] storage stakes = userStakes[msg.sender];\n require(stakes.length > 0, \"Nothing staked\");\n\n uint256 totalWithdraw = 0;\n uint256 stakedAmount = 0;\n uint256 l = stakes.length;\n do {\n Stake storage exitStake = stakes[l - 1];\n // stop on the first ended stake that's already been paid\n if (exitStake.end < block.timestamp && exitStake.paid) {\n break;\n }\n //might not be ended\n if (exitStake.end < block.timestamp) {\n //we are paying out the stake\n exitStake.paid = true;\n totalWithdraw = totalWithdraw.add(_totalExpected(exitStake));\n stakedAmount = stakedAmount.add(exitStake.amount);\n }\n l--;\n } while (l > 0);\n require(totalWithdraw > 0, \"All stakes in lock-up\");\n\n totalOutstanding = totalOutstanding.sub(totalWithdraw);\n emit Withdrawn(msg.sender, totalWithdraw, stakedAmount);\n stakingToken.safeTransfer(msg.sender, totalWithdraw);\n }\n\n /**\n * @dev Use to transfer all the stakes of an account in the case that the account is compromised\n * Requires access to both the account itself and the transfer agent\n * @param _frmAccount the address to transfer from\n * @param _dstAccount the address to transfer to(must be a clean address with no stakes)\n * @param r r portion of the signature by the transfer agent\n * @param s s portion of the signature\n * @param v v portion of the signature\n */\n function transferStakes(\n address _frmAccount,\n address _dstAccount,\n bytes32 r,\n bytes32 s,\n uint8 v\n ) external {\n require(transferAgent == msg.sender, \"must be transfer agent\");\n Stake[] storage dstStakes = userStakes[_dstAccount];\n require(dstStakes.length == 0, \"Dest stakes must be empty\");\n require(_frmAccount != address(0), \"from account not set\");\n Stake[] storage stakes = userStakes[_frmAccount];\n require(stakes.length > 0, \"Nothing to transfer\");\n\n // matches ethers.signMsg(ethers.utils.solidityPack([string(4), address, adddress, address]))\n bytes32 hash = keccak256(\n abi.encodePacked(\n \"\\x19Ethereum Signed Message:\\n64\",\n abi.encodePacked(\n \"tran\",\n address(this),\n _frmAccount,\n _dstAccount\n )\n )\n );\n require(ecrecover(hash, v, r, s) == _frmAccount, \"Transfer not authed\");\n\n // copy the stakes into the dstAccount array and delete the old one\n userStakes[_dstAccount] = stakes;\n delete userStakes[_frmAccount];\n emit StakesTransfered(_frmAccount, _dstAccount, stakes.length);\n }\n\n /* ========== MODIFIERS ========== */\n\n function setPaused(bool _paused) external onlyGovernor {\n paused = _paused;\n emit Paused(msg.sender, paused);\n }\n\n /**\n * @dev Set new durations and rates will not effect existing stakes\n * @param _durations Array of durations in seconds\n * @param _rates Array of rates that corresponds to the durations (0.01 is 1%) in 1e18\n */\n function setDurationRates(\n uint256[] calldata _durations,\n uint256[] calldata _rates\n ) external onlyGovernor {\n _setDurationRates(_durations, _rates);\n }\n\n /**\n * @dev Set the agent that will authorize transfers\n * @param _agent Address of agent\n */\n function setTransferAgent(address _agent) external onlyGovernor {\n transferAgent = _agent;\n }\n\n /**\n * @dev Set air drop root for a specific stake type\n * @param _stakeType Type of staking must be greater than 0\n * @param _rootHash Root hash of the Merkle Tree\n * @param _proofDepth Depth of the Merklke Tree\n */\n function setAirDropRoot(\n uint8 _stakeType,\n bytes32 _rootHash,\n uint256 _proofDepth\n ) external onlyGovernor {\n require(_stakeType != USER_STAKE_TYPE, \"Cannot be normal staking\");\n dropRoots[_stakeType].hash = _rootHash;\n dropRoots[_stakeType].depth = _proofDepth;\n emit NewAirDropRootHash(_stakeType, _rootHash, _proofDepth);\n }\n\n /* ========== EVENTS ========== */\n\n event Staked(\n address indexed user,\n uint256 amount,\n uint256 duration,\n uint256 rate\n );\n event Withdrawn(address indexed user, uint256 amount, uint256 stakedAmount);\n event Paused(address indexed user, bool yes);\n event NewDurations(address indexed user, uint256[] durations);\n event NewRates(address indexed user, uint256[] rates);\n event NewAirDropRootHash(\n uint8 stakeType,\n bytes32 rootHash,\n uint256 proofDepth\n );\n event StakesTransfered(\n address indexed fromUser,\n address toUser,\n uint256 numStakes\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 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/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\nimport { Governable } from \"../../governance/Governable.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 is Governable {\n /// @notice The address of the Native Staking Strategy\n address public immutable STRATEGY;\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 }\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\";\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\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_ADDRESS;\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 public immutable FEE_ACCUMULATOR_ADDRESS;\n\n // For future use\n uint256[50] 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 _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 address _feeAccumulator,\n address _beaconChainDepositContract\n )\n InitializableAbstractStrategy(_baseConfig)\n ValidatorAccountant(\n _wethAddress,\n _baseConfig.vaultAddress,\n _beaconChainDepositContract,\n _ssvNetwork\n )\n {\n SSV_TOKEN_ADDRESS = _ssvToken;\n FEE_ACCUMULATOR_ADDRESS = _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 /// @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_TOKEN_ADDRESS).deposit{ value: ethRewards }();\n\n emit RewardTokenCollected(\n harvesterAddress,\n WETH_TOKEN_ADDRESS,\n ethRewards\n );\n IERC20(WETH_TOKEN_ADDRESS).safeTransfer(\n harvesterAddress,\n ethRewards\n );\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_TOKEN_ADDRESS, \"Unsupported asset\");\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_TOKEN_ADDRESS).balanceOf(\n address(this)\n );\n if (wethBalance > 0) {\n _deposit(WETH_TOKEN_ADDRESS, wethBalance);\n }\n }\n\n /// @notice Withdraw WETH from this contract. Used only if some WETH for is lingering on the contract. That\n /// can happen when:\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 _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 emit Withdrawal(_asset, address(0), _amount);\n IERC20(_asset).safeTransfer(_recipient, _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_TOKEN_ADDRESS).balanceOf(\n address(this)\n );\n if (wethBalance > 0) {\n _withdraw(vaultAddress, WETH_TOKEN_ADDRESS, wethBalance);\n }\n }\n\n function _abstractSetPToken(address _asset, address) internal override {}\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_TOKEN_ADDRESS, \"Unsupported asset\");\n\n balance =\n // add the ETH that has been staked in validators\n activeDepositedValidators *\n 32 ether +\n // add the WETH in the strategy from deposits that are still to be staked\n IERC20(WETH_TOKEN_ADDRESS).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_TOKEN_ADDRESS;\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_ADDRESS).approve(\n SSV_NETWORK_ADDRESS,\n type(uint256).max\n );\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 ||\n msg.sender == WETH_TOKEN_ADDRESS,\n \"eth not from allowed contracts\"\n );\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 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 MAX_STAKE = 32 ether;\n\n /// @notice Keeps track of the total consensus rewards swept from the beacon chain\n uint256 public consensusRewards = 0;\n\n /// @notice start of fuse interval\n uint256 public fuseIntervalStart = 0;\n /// @notice end of fuse interval\n uint256 public fuseIntervalEnd = 0;\n\n uint256[50] 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 constructor(\n address _wethAddress,\n address _vaultAddress,\n address _beaconChainDepositContract,\n address _ssvNetwork\n )\n ValidatorRegistrator(\n _wethAddress,\n _vaultAddress,\n _beaconChainDepositContract,\n _ssvNetwork\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 _fuseIntervalStart < 32 ether &&\n _fuseIntervalEnd < 32 ether &&\n _fuseIntervalEnd - _fuseIntervalStart >= 4 ether,\n \"incorrect fuse interval\"\n );\n\n emit FuseIntervalUpdated(_fuseIntervalStart, _fuseIntervalEnd);\n\n fuseIntervalStart = _fuseIntervalStart;\n fuseIntervalEnd = _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 returns (bool accountingValid)\n {\n // pause the accounting on failure\n accountingValid = _doAccounting(true);\n }\n\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 >= MAX_STAKE) {\n uint256 fullyWithdrawnValidators = newSweptETH / MAX_STAKE;\n if (activeDepositedValidators < fullyWithdrawnValidators) {\n return _failAccounting(pauseOnFail);\n }\n activeDepositedValidators -= fullyWithdrawnValidators;\n\n uint256 wethToVault = MAX_STAKE * fullyWithdrawnValidators;\n IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: wethToVault }();\n IWETH9(WETH_TOKEN_ADDRESS).transfer(VAULT_ADDRESS, 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 < 32 ether, \"unexpected accounting\");\n\n // If no Beacon chain consensus rewards swept\n if (ethRemaining == 0) {\n // do nothing\n return accountingValid;\n }\n // Beacon chain consensus rewards swept (partial validator withdrawals)\n else if (ethRemaining < fuseIntervalStart) {\n // solhint-disable-next-line reentrancy\n consensusRewards += ethRemaining;\n emit AccountingConsensusRewards(ethRemaining);\n }\n // Beacon chain consensus rewards swept but also a slashed validator fully exited\n else if (ethRemaining > fuseIntervalEnd) {\n IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: ethRemaining }();\n IWETH9(WETH_TOKEN_ADDRESS).transfer(VAULT_ADDRESS, ethRemaining);\n activeDepositedValidators -= 1;\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 /// @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 plus one, minus one or unchanged with zero\n /// @param _wethToVaultAmount the amount of WETH to be sent to the Vault\n /// @param _consensusRewardsDelta adjust the accounted for consensus rewards up or down\n function manuallyFixAccounting(\n int256 _validatorsDelta,\n int256 _consensusRewardsDelta,\n uint256 _wethToVaultAmount\n ) external onlyStrategist whenPaused {\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(_wethToVaultAmount <= 32 ether, \"invalid wethToVaultAmount\");\n\n emit AccountingManuallyFixed(\n _validatorsDelta,\n _consensusRewardsDelta,\n _wethToVaultAmount\n );\n\n activeDepositedValidators = uint256(\n int256(activeDepositedValidators) + _validatorsDelta\n );\n consensusRewards = uint256(\n int256(consensusRewards) + _consensusRewardsDelta\n );\n if (_wethToVaultAmount > 0) {\n IWETH9(WETH_TOKEN_ADDRESS).transfer(\n VAULT_ADDRESS,\n _wethToVaultAmount\n );\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" + }, + "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 address of the Wrapped ETH (WETH) token contract\n address public immutable WETH_TOKEN_ADDRESS;\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_ADDRESS;\n /// @notice Address of the OETH Vault proxy contract\n address public immutable VAULT_ADDRESS;\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\n // For future use\n uint256[50] private __gap;\n\n enum VALIDATOR_STATE {\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 newAddress);\n event ETHStaked(bytes pubkey, uint256 amount, bytes withdrawal_credentials);\n event SSVValidatorRegistered(bytes pubkey, uint64[] operatorIds);\n event SSVValidatorExitInitiated(bytes pubkey, uint64[] operatorIds);\n event SSVValidatorExitCompleted(bytes pubkey, uint64[] operatorIds);\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 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 constructor(\n address _wethAddress,\n address _vaultAddress,\n address _beaconChainDepositContract,\n address _ssvNetwork\n ) {\n WETH_TOKEN_ADDRESS = _wethAddress;\n BEACON_CHAIN_DEPOSIT_CONTRACT = _beaconChainDepositContract;\n SSV_NETWORK_ADDRESS = _ssvNetwork;\n VAULT_ADDRESS = _vaultAddress;\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 emit RegistratorChanged(_address);\n validatorRegistrator = _address;\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 function stakeEth(ValidatorStakeData[] calldata validators)\n external\n onlyRegistrator\n whenNotPaused\n {\n uint256 requiredETH = validators.length * 32 ether;\n\n // Check there is enough WETH from the deposits sitting in this strategy contract\n require(\n requiredETH <= IWETH9(WETH_TOKEN_ADDRESS).balanceOf(address(this)),\n \"insufficient WETH\"\n );\n\n // Convert required ETH from WETH\n IWETH9(WETH_TOKEN_ADDRESS).withdraw(requiredETH);\n\n // For each validator\n for (uint256 i = 0; i < validators.length; ) {\n bytes32 pubkeyHash = keccak256(validators[i].pubkey);\n VALIDATOR_STATE currentState = validatorsStates[pubkeyHash];\n\n require(\n currentState == VALIDATOR_STATE.REGISTERED,\n \"Validator not registered\"\n );\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 withdrawal_credentials = abi.encodePacked(\n bytes1(0x01),\n bytes11(0),\n address(this)\n );\n IDepositContract(BEACON_CHAIN_DEPOSIT_CONTRACT).deposit{\n value: 32 ether\n }(\n validators[i].pubkey,\n withdrawal_credentials,\n validators[i].signature,\n validators[i].depositDataRoot\n );\n\n activeDepositedValidators += 1;\n emit ETHStaked(\n validators[i].pubkey,\n 32 ether,\n withdrawal_credentials\n );\n\n validatorsStates[pubkeyHash] = VALIDATOR_STATE.STAKED;\n\n unchecked {\n ++i;\n }\n }\n }\n\n /// @notice Registers a new validator in the SSV Cluster.\n /// Only the registrator can call this function.\n function registerSsvValidator(\n bytes calldata publicKey,\n uint64[] calldata operatorIds,\n bytes calldata sharesData,\n uint256 amount,\n Cluster calldata cluster\n ) external onlyRegistrator whenNotPaused {\n ISSVNetwork(SSV_NETWORK_ADDRESS).registerValidator(\n publicKey,\n operatorIds,\n sharesData,\n amount,\n cluster\n );\n validatorsStates[keccak256(publicKey)] = VALIDATOR_STATE.REGISTERED;\n emit SSVValidatorRegistered(publicKey, operatorIds);\n }\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 function exitSsvValidator(\n bytes calldata publicKey,\n uint64[] calldata operatorIds\n ) external onlyRegistrator whenNotPaused {\n VALIDATOR_STATE currentState = validatorsStates[keccak256(publicKey)];\n require(currentState == VALIDATOR_STATE.STAKED, \"Validator not staked\");\n\n ISSVNetwork(SSV_NETWORK_ADDRESS).exitValidator(publicKey, operatorIds);\n emit SSVValidatorExitInitiated(publicKey, operatorIds);\n\n validatorsStates[keccak256(publicKey)] = VALIDATOR_STATE.EXITING;\n }\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 function removeSsvValidator(\n bytes calldata publicKey,\n uint64[] calldata operatorIds,\n Cluster calldata cluster\n ) external onlyRegistrator whenNotPaused {\n VALIDATOR_STATE currentState = validatorsStates[keccak256(publicKey)];\n require(\n currentState == VALIDATOR_STATE.EXITING,\n \"Validator not exiting\"\n );\n\n ISSVNetwork(SSV_NETWORK_ADDRESS).removeValidator(\n publicKey,\n operatorIds,\n cluster\n );\n emit SSVValidatorExitCompleted(publicKey, operatorIds);\n\n validatorsStates[keccak256(publicKey)] = VALIDATOR_STATE.EXIT_COMPLETE;\n }\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 cluster The SSV cluster details that must be derived from emitted events from the SSVNetwork contract.\n function depositSSV(\n uint64[] memory operatorIds,\n uint256 amount,\n Cluster memory cluster\n ) external onlyStrategist {\n ISSVNetwork(SSV_NETWORK_ADDRESS).deposit(\n address(this),\n operatorIds,\n amount,\n cluster\n );\n }\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/swapper/Swapper1InchV5.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @notice 1Inch Pathfinder V5 implementation of the general ISwapper interface.\n * @author Origin Protocol Inc\n * @dev It is possible that dust token amounts are left in this contract after a swap.\n * This can happen with some tokens that don't send the full transfer amount.\n * These dust amounts can build up over time and be used by anyone who calls the `swap` function.\n */\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nimport { IAggregationExecutor, IOneInchRouter, SwapDescription } from \"../interfaces/IOneInch.sol\";\nimport { ISwapper } from \"../interfaces/ISwapper.sol\";\n\ncontract Swapper1InchV5 is ISwapper {\n using SafeERC20 for IERC20;\n\n /// @notice 1Inch router contract to give allowance to perform swaps\n address public constant SWAP_ROUTER =\n 0x1111111254EEB25477B68fb85Ed929f73A960582;\n\n // swap(address,(address,address,address,address,uint256,uint256,uint256),bytes,bytes)\n bytes4 internal constant SWAP_SELECTOR = 0x12aa3caf;\n // unoswapTo(address,address,uint256,uint256,uint256[])\n bytes4 internal constant UNISWAP_SELECTOR = 0xf78dc253;\n // uniswapV3SwapTo(address,uint256,uint256,uint256[])\n bytes4 internal constant UNISWAPV3_SELECTOR = 0xbc80f1a8;\n\n /**\n * @notice Strategist swaps assets sitting in the contract of the `assetHolder`.\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 RLP encoded executer address and bytes data. This is re-encoded tx.data from 1Inch swap API\n */\n function swap(\n address _fromAsset,\n address _toAsset,\n uint256 _fromAssetAmount,\n uint256 _minToAssetAmount,\n bytes calldata _data\n ) external override returns (uint256 toAssetAmount) {\n // Decode the function selector from the RLP encoded _data param\n bytes4 swapSelector = bytes4(_data[:4]);\n\n if (swapSelector == SWAP_SELECTOR) {\n // Decode the executer address and data from the RLP encoded _data param\n (, address executer, bytes memory executerData) = abi.decode(\n _data,\n (bytes4, address, bytes)\n );\n SwapDescription memory swapDesc = SwapDescription({\n srcToken: IERC20(_fromAsset),\n dstToken: IERC20(_toAsset),\n srcReceiver: payable(executer),\n dstReceiver: payable(msg.sender),\n amount: _fromAssetAmount,\n minReturnAmount: _minToAssetAmount,\n flags: 4 // 1st bit _PARTIAL_FILL, 2nd bit _REQUIRES_EXTRA_ETH, 3rd bit _SHOULD_CLAIM\n });\n (toAssetAmount, ) = IOneInchRouter(SWAP_ROUTER).swap(\n IAggregationExecutor(executer),\n swapDesc,\n hex\"\",\n executerData\n );\n } else if (swapSelector == UNISWAP_SELECTOR) {\n // Need to get the Uniswap pools data from the _data param\n (, uint256[] memory pools) = abi.decode(_data, (bytes4, uint256[]));\n toAssetAmount = IOneInchRouter(SWAP_ROUTER).unoswapTo(\n payable(msg.sender),\n IERC20(_fromAsset),\n _fromAssetAmount,\n _minToAssetAmount,\n pools\n );\n } else if (swapSelector == UNISWAPV3_SELECTOR) {\n // Need to get the Uniswap pools data from the _data param\n // slither-disable-next-line uninitialized-storage\n (, uint256[] memory pools) = abi.decode(_data, (bytes4, uint256[]));\n toAssetAmount = IOneInchRouter(SWAP_ROUTER).uniswapV3SwapTo(\n payable(msg.sender),\n _fromAssetAmount,\n _minToAssetAmount,\n pools\n );\n } else {\n revert(\"Unsupported swap function\");\n }\n }\n\n /**\n * @notice Approve assets for swapping.\n * @param _assets Array of token addresses to approve.\n * @dev unlimited approval is used as no tokens sit in this contract outside a transaction.\n */\n function approveAssets(address[] memory _assets) external {\n for (uint256 i = 0; i < _assets.length; ++i) {\n // Give the 1Inch router approval to transfer unlimited assets\n IERC20(_assets[i]).safeApprove(SWAP_ROUTER, type(uint256).max);\n }\n }\n}\n" + }, + "contracts/timelock/Timelock.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @title OUSD Timelock Contract\n * @author Origin Protocol Inc\n */\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\n\ninterface CapitalPausable {\n function pauseCapital() external;\n\n function unpauseCapital() external;\n}\n\ncontract Timelock {\n using SafeMath for uint256;\n\n event NewAdmin(address indexed newAdmin);\n event NewPendingAdmin(address indexed newPendingAdmin);\n event NewDelay(uint256 indexed newDelay);\n event CancelTransaction(\n bytes32 indexed txHash,\n address indexed target,\n string signature,\n bytes data,\n uint256 eta\n );\n event ExecuteTransaction(\n bytes32 indexed txHash,\n address indexed target,\n string signature,\n bytes data,\n uint256 eta\n );\n event QueueTransaction(\n bytes32 indexed txHash,\n address indexed target,\n string signature,\n bytes data,\n uint256 eta\n );\n\n uint256 public constant GRACE_PERIOD = 3 days;\n uint256 public constant MINIMUM_DELAY = 1 minutes;\n uint256 public constant MAXIMUM_DELAY = 2 days;\n\n address public admin;\n address public pendingAdmin;\n uint256 public delay;\n\n mapping(bytes32 => bool) public queuedTransactions;\n\n /**\n * @dev Throws if called by any account other than the Admin.\n */\n modifier onlyAdmin() {\n require(msg.sender == admin, \"Caller is not the admin\");\n _;\n }\n\n constructor(address admin_, uint256 delay_) {\n require(\n delay_ >= MINIMUM_DELAY,\n \"Timelock::constructor: Delay must exceed minimum delay.\"\n );\n require(\n delay_ <= MAXIMUM_DELAY,\n \"Timelock::setDelay: Delay must not exceed maximum delay.\"\n );\n\n admin = admin_;\n delay = delay_;\n }\n\n function setDelay(uint256 delay_) public {\n require(\n msg.sender == address(this),\n \"Timelock::setDelay: Call must come from Timelock.\"\n );\n require(\n delay_ >= MINIMUM_DELAY,\n \"Timelock::setDelay: Delay must exceed minimum delay.\"\n );\n require(\n delay_ <= MAXIMUM_DELAY,\n \"Timelock::setDelay: Delay must not exceed maximum delay.\"\n );\n delay = delay_;\n\n emit NewDelay(delay);\n }\n\n function acceptAdmin() public {\n require(\n msg.sender == pendingAdmin,\n \"Timelock::acceptAdmin: Call must come from pendingAdmin.\"\n );\n admin = msg.sender;\n pendingAdmin = address(0);\n\n emit NewAdmin(admin);\n }\n\n function setPendingAdmin(address pendingAdmin_) public onlyAdmin {\n pendingAdmin = pendingAdmin_;\n\n emit NewPendingAdmin(pendingAdmin);\n }\n\n function queueTransaction(\n address target,\n string memory signature,\n bytes memory data,\n uint256 eta\n ) internal returns (bytes32) {\n require(\n msg.sender == admin,\n \"Timelock::queueTransaction: Call must come from admin.\"\n );\n require(\n eta >= getBlockTimestamp().add(delay),\n \"Timelock::queueTransaction: Estimated execution block must satisfy delay.\"\n );\n\n bytes32 txHash = keccak256(\n abi.encode(target, signature, keccak256(data), eta)\n );\n queuedTransactions[txHash] = true;\n\n emit QueueTransaction(txHash, target, signature, data, eta);\n return txHash;\n }\n\n function cancelTransaction(\n address target,\n string memory signature,\n bytes memory data,\n uint256 eta\n ) internal {\n require(\n msg.sender == admin,\n \"Timelock::cancelTransaction: Call must come from admin.\"\n );\n\n bytes32 txHash = keccak256(\n abi.encode(target, signature, keccak256(data), eta)\n );\n queuedTransactions[txHash] = false;\n\n emit CancelTransaction(txHash, target, signature, data, eta);\n }\n\n function _getRevertMsg(bytes memory _returnData)\n internal\n pure\n returns (string memory)\n {\n // If the _res length is less than 68, then the transaction failed\n // silently (without a revert message)\n if (_returnData.length < 68) return \"Transaction reverted silently\";\n\n // solhint-disable-next-line no-inline-assembly\n assembly {\n // Slice the sighash.\n _returnData := add(_returnData, 0x04)\n }\n return abi.decode(_returnData, (string));\n }\n\n function executeTransaction(\n address target,\n string memory signature,\n bytes memory data,\n uint256 eta\n ) internal returns (bytes memory) {\n require(\n msg.sender == admin,\n \"Timelock::executeTransaction: Call must come from admin.\"\n );\n\n bytes32 txHash = keccak256(\n abi.encode(target, signature, keccak256(data), eta)\n );\n require(\n queuedTransactions[txHash],\n \"Timelock::executeTransaction: Transaction hasn't been queued.\"\n );\n require(\n getBlockTimestamp() >= eta,\n \"Timelock::executeTransaction: Transaction hasn't surpassed time lock.\"\n );\n require(\n getBlockTimestamp() <= eta.add(GRACE_PERIOD),\n \"Timelock::executeTransaction: Transaction is stale.\"\n );\n\n queuedTransactions[txHash] = false;\n\n bytes memory callData;\n\n if (bytes(signature).length == 0) {\n callData = data;\n } else {\n callData = abi.encodePacked(\n bytes4(keccak256(bytes(signature))),\n data\n );\n }\n\n (bool success, bytes memory returnData) = target.call(callData);\n\n if (!success) {\n revert(_getRevertMsg(returnData));\n }\n\n emit ExecuteTransaction(txHash, target, signature, data, eta);\n\n return returnData;\n }\n\n function getBlockTimestamp() internal view returns (uint256) {\n // solium-disable-next-line security/no-block-members\n return block.timestamp;\n }\n\n function pauseCapital(address target) external {\n require(\n msg.sender == admin,\n \"Timelock::pauseCapital: Call must come from admin.\"\n );\n CapitalPausable(target).pauseCapital();\n }\n\n function unpauseCapital(address target) external {\n require(\n msg.sender == admin,\n \"Timelock::unpauseCapital: Call must come from admin.\"\n );\n CapitalPausable(target).unpauseCapital();\n }\n}\n" + }, + "contracts/token/BridgedWOETH.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { ERC20 } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport { AccessControlEnumerable } from \"@openzeppelin/contracts/access/AccessControlEnumerable.sol\";\nimport { Governable } from \"../governance/Governable.sol\";\nimport { Initializable } from \"../utils/Initializable.sol\";\n\ncontract BridgedWOETH is\n Governable,\n AccessControlEnumerable,\n Initializable,\n ERC20\n{\n bytes32 public constant MINTER_ROLE = keccak256(\"MINTER_ROLE\");\n bytes32 public constant BURNER_ROLE = keccak256(\"BURNER_ROLE\");\n\n constructor() ERC20(\"Wrapped OETH\", \"WOETH\") {\n // Nobody owns the implementation\n _setGovernor(address(0));\n }\n\n /**\n * @dev Initialize the proxy and set the Governor\n */\n function initialize() external initializer {\n // Governor can grant Minter/Burner roles\n _setupRole(DEFAULT_ADMIN_ROLE, _governor());\n }\n\n /**\n * @dev Mint tokens for `account`\n * @param account Address to mint tokens for\n * @param amount Amount of tokens to mint\n */\n function mint(address account, uint256 amount)\n external\n onlyRole(MINTER_ROLE)\n nonReentrant\n {\n _mint(account, amount);\n }\n\n /**\n * @dev Burns tokens from `account`\n * @param account Address to burn tokens from\n * @param amount Amount of tokens to burn\n */\n function burn(address account, uint256 amount)\n external\n onlyRole(BURNER_ROLE)\n nonReentrant\n {\n _burn(account, amount);\n }\n\n /**\n * @dev Burns tokens from `msg.sender`\n * @param amount Amount of tokens to burn\n */\n function burn(uint256 amount) external onlyRole(BURNER_ROLE) nonReentrant {\n _burn(msg.sender, amount);\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual override returns (string memory) {\n return \"Wrapped OETH\";\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 \"WOETH\";\n }\n\n /**\n * @dev Returns the decimals of the token\n */\n function decimals() public view virtual override returns (uint8) {\n return 18;\n }\n}\n" + }, + "contracts/token/OETH.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { OUSD } from \"./OUSD.sol\";\n\n/**\n * @title OETH Token Contract\n * @author Origin Protocol Inc\n */\ncontract OETH is 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/token/OUSDResolutionUpgrade.sol": { + "content": "pragma solidity ^0.8.0;\n\ncontract OUSDResolutionUpgrade {\n enum RebaseOptions {\n NotSet,\n OptOut,\n OptIn\n }\n\n // From Initializable\n bool private initialized;\n bool private initializing;\n uint256[50] private ______igap;\n\n // From InitializableERC20Detailed\n uint256[100] private _____ugap;\n string private _name;\n string private _symbol;\n uint8 private _decimals;\n\n // From OUSD\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 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 /**\n * @return High resolution rebasingCreditsPerToken\n */\n function rebasingCreditsPerToken() public view returns (uint256) {\n return _rebasingCreditsPerToken / RESOLUTION_INCREASE;\n }\n\n /**\n * @return High 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 function upgradeGlobals() external {\n require(isUpgraded[address(0)] == 0, \"Globals already upgraded\");\n require(_rebasingCredits > 0, \"Sanity _rebasingCredits\");\n require(\n _rebasingCreditsPerToken > 0,\n \"Sanity _rebasingCreditsPerToken\"\n );\n isUpgraded[address(0)] = 1;\n _rebasingCredits = _rebasingCredits * RESOLUTION_INCREASE;\n _rebasingCreditsPerToken =\n _rebasingCreditsPerToken *\n RESOLUTION_INCREASE;\n }\n\n function upgradeAccounts(address[] calldata accounts) external {\n for (uint256 i = 0; i < accounts.length; i++) {\n address account = accounts[i];\n require(account != address(0), \"Reserved\");\n require(isUpgraded[account] == 0, \"Account already upgraded\");\n isUpgraded[account] = 1;\n\n // Handle special for non-rebasing accounts\n uint256 nrc = nonRebasingCreditsPerToken[account];\n if (nrc > 0) {\n require(nrc < 1e18, \"Account already highres\");\n nonRebasingCreditsPerToken[account] = nrc * RESOLUTION_INCREASE;\n }\n // Upgrade balance\n uint256 balance = _creditBalances[account];\n require(balance > 0, \"Will not upgrade zero balance\");\n _creditBalances[account] = balance * RESOLUTION_INCREASE;\n }\n }\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 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" + }, + "contracts/token/WOETH.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { ERC4626 } from \"../../lib/openzeppelin/contracts/token/ERC20/extensions/ERC4626.sol\";\nimport { ERC20 } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nimport { Governable } from \"../governance/Governable.sol\";\nimport { Initializable } from \"../utils/Initializable.sol\";\nimport { OETH } from \"./OETH.sol\";\n\n/**\n * @title OETH Token Contract\n * @author Origin Protocol Inc\n */\n\ncontract WOETH is ERC4626, Governable, Initializable {\n using SafeERC20 for IERC20;\n\n constructor(\n ERC20 underlying_,\n string memory name_,\n string memory symbol_\n ) ERC20(name_, symbol_) ERC4626(underlying_) Governable() {}\n\n /**\n * @notice Enable OETH rebasing for this contract\n */\n function initialize() external onlyGovernor initializer {\n OETH(address(asset())).rebaseOptIn();\n }\n\n function name() public view override returns (string memory) {\n return \"Wrapped OETH\";\n }\n\n function symbol() public view override returns (string memory) {\n return \"WOETH\";\n }\n\n /**\n * @notice Transfer token to governor. Intended for recovering tokens stuck in\n * contract, i.e. mistaken sends. Cannot transfer OETH\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(asset_ != address(asset()), \"Cannot collect OETH\");\n IERC20(asset_).safeTransfer(governor(), amount_);\n }\n}\n" + }, + "contracts/token/WrappedOusd.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { ERC4626 } from \"../../lib/openzeppelin/contracts/token/ERC20/extensions/ERC4626.sol\";\nimport { ERC20 } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nimport { Governable } from \"../governance/Governable.sol\";\nimport { Initializable } from \"../utils/Initializable.sol\";\nimport { OUSD } from \"./OUSD.sol\";\n\ncontract WrappedOusd is ERC4626, Governable, Initializable {\n using SafeERC20 for IERC20;\n\n constructor(\n ERC20 underlying_,\n string memory name_,\n string memory symbol_\n ) ERC20(name_, symbol_) ERC4626(underlying_) Governable() {}\n\n /**\n * @notice Enable OUSD rebasing for this contract\n */\n function initialize() external onlyGovernor initializer {\n OUSD(address(asset())).rebaseOptIn();\n }\n\n function name() public view override returns (string memory) {\n return \"Wrapped OUSD\";\n }\n\n function symbol() public view override returns (string memory) {\n return \"WOUSD\";\n }\n\n /**\n * @notice Transfer token to governor. Intended for recovering tokens stuck in\n * contract, i.e. mistaken sends. Cannot transfer OUSD\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(asset_ != address(asset()), \"Cannot collect OUSD\");\n IERC20(asset_).safeTransfer(governor(), amount_);\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 { VaultAdmin } from \"./VaultAdmin.sol\";\n\n/**\n * @title OETH VaultAdmin Contract\n * @author Origin Protocol Inc\n */\ncontract OETHVaultAdmin is VaultAdmin {\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\";\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" + }, + "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 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" + }, + "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" + }, + "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 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" + }, + "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/contracts/token/ERC20/extensions/ERC4626.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\nimport { IERC4626 } from \"../../../../interfaces/IERC4626.sol\";\nimport { ERC20 } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { IERC20Metadata } from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\n\n// From Open Zeppelin draft PR commit:\n// fac43034dca85ff539db3fc8aa2a7084b843d454\n// https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3171\n\nabstract contract ERC4626 is ERC20, IERC4626 {\n IERC20Metadata private immutable _asset;\n\n constructor(IERC20Metadata __asset) {\n _asset = __asset;\n }\n\n /** @dev See {IERC4262-asset} */\n function asset() public view virtual override returns (address) {\n return address(_asset);\n }\n\n /** @dev See {IERC4262-totalAssets} */\n function totalAssets() public view virtual override returns (uint256) {\n return _asset.balanceOf(address(this));\n }\n\n /**\n * @dev See {IERC4262-convertToShares}\n *\n * Will revert if asserts > 0, totalSupply > 0 and totalAssets = 0. That corresponds to a case where any asset\n * would represent an infinite amout of shares.\n */\n function convertToShares(uint256 assets) public view virtual override returns (uint256 shares) {\n uint256 supply = totalSupply();\n\n return\n (assets == 0 || supply == 0)\n ? (assets * 10**decimals()) / 10**_asset.decimals()\n : (assets * supply) / totalAssets();\n }\n\n /** @dev See {IERC4262-convertToAssets} */\n function convertToAssets(uint256 shares) public view virtual override returns (uint256 assets) {\n uint256 supply = totalSupply();\n\n return (supply == 0) ? (shares * 10**_asset.decimals()) / 10**decimals() : (shares * totalAssets()) / supply;\n }\n\n /** @dev See {IERC4262-maxDeposit} */\n function maxDeposit(address) public view virtual override returns (uint256) {\n return type(uint256).max;\n }\n\n /** @dev See {IERC4262-maxMint} */\n function maxMint(address) public view virtual override returns (uint256) {\n return type(uint256).max;\n }\n\n /** @dev See {IERC4262-maxWithdraw} */\n function maxWithdraw(address owner) public view virtual override returns (uint256) {\n return convertToAssets(balanceOf(owner));\n }\n\n /** @dev See {IERC4262-maxRedeem} */\n function maxRedeem(address owner) public view virtual override returns (uint256) {\n return balanceOf(owner);\n }\n\n /** @dev See {IERC4262-previewDeposit} */\n function previewDeposit(uint256 assets) public view virtual override returns (uint256) {\n return convertToShares(assets);\n }\n\n /** @dev See {IERC4262-previewMint} */\n function previewMint(uint256 shares) public view virtual override returns (uint256) {\n uint256 assets = convertToAssets(shares);\n return assets + (convertToShares(assets) < shares ? 1 : 0);\n }\n\n /** @dev See {IERC4262-previewWithdraw} */\n function previewWithdraw(uint256 assets) public view virtual override returns (uint256) {\n uint256 shares = convertToShares(assets);\n return shares + (convertToAssets(shares) < assets ? 1 : 0);\n }\n\n /** @dev See {IERC4262-previewRedeem} */\n function previewRedeem(uint256 shares) public view virtual override returns (uint256) {\n return convertToAssets(shares);\n }\n\n /** @dev See {IERC4262-deposit} */\n function deposit(uint256 assets, address receiver) public virtual override returns (uint256) {\n require(assets <= maxDeposit(receiver), \"ERC4626: deposit more then max\");\n\n address caller = _msgSender();\n uint256 shares = previewDeposit(assets);\n\n // if _asset is ERC777, transferFrom can call reenter BEFORE the transfer happens through\n // the tokensToSend hook, so we need to transfer before we mint to keep the invariants.\n SafeERC20.safeTransferFrom(_asset, caller, address(this), assets);\n _mint(receiver, shares);\n\n emit Deposit(caller, receiver, assets, shares);\n\n return shares;\n }\n\n /** @dev See {IERC4262-mint} */\n function mint(uint256 shares, address receiver) public virtual override returns (uint256) {\n require(shares <= maxMint(receiver), \"ERC4626: mint more then max\");\n\n address caller = _msgSender();\n uint256 assets = previewMint(shares);\n\n // if _asset is ERC777, transferFrom can call reenter BEFORE the transfer happens through\n // the tokensToSend hook, so we need to transfer before we mint to keep the invariants.\n SafeERC20.safeTransferFrom(_asset, caller, address(this), assets);\n _mint(receiver, shares);\n\n emit Deposit(caller, receiver, assets, shares);\n\n return assets;\n }\n\n /** @dev See {IERC4262-withdraw} */\n function withdraw(\n uint256 assets,\n address receiver,\n address owner\n ) public virtual override returns (uint256) {\n require(assets <= maxWithdraw(owner), \"ERC4626: withdraw more then max\");\n\n address caller = _msgSender();\n uint256 shares = previewWithdraw(assets);\n\n if (caller != owner) {\n _spendAllowance(owner, caller, shares);\n }\n\n // if _asset is ERC777, transfer can call reenter AFTER the transfer happens through\n // the tokensReceived hook, so we need to transfer after we burn to keep the invariants.\n _burn(owner, shares);\n SafeERC20.safeTransfer(_asset, receiver, assets);\n\n emit Withdraw(caller, receiver, owner, assets, shares);\n\n return shares;\n }\n\n /** @dev See {IERC4262-redeem} */\n function redeem(\n uint256 shares,\n address receiver,\n address owner\n ) public virtual override returns (uint256) {\n require(shares <= maxRedeem(owner), \"ERC4626: redeem more then max\");\n\n address caller = _msgSender();\n uint256 assets = previewRedeem(shares);\n\n if (caller != owner) {\n _spendAllowance(owner, caller, shares);\n }\n\n // if _asset is ERC777, transfer can call reenter AFTER the transfer happens through\n // the tokensReceived hook, so we need to transfer after we burn to keep the invariants.\n _burn(owner, shares);\n SafeERC20.safeTransfer(_asset, receiver, assets);\n\n emit Withdraw(caller, receiver, owner, assets, shares);\n\n return assets;\n }\n\n // Included here, since this method was not yet present in\n // the version of Open Zeppelin ERC20 code we use.\n function _spendAllowance(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n uint256 currentAllowance = allowance(owner, spender);\n if (currentAllowance != type(uint256).max) {\n require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n unchecked {\n _approve(owner, spender, currentAllowance - amount);\n }\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/docs/FeeAccumulatorHierarchy.svg b/contracts/docs/FeeAccumulatorHierarchy.svg new file mode 100644 index 0000000000..3ddcdb22a3 --- /dev/null +++ b/contracts/docs/FeeAccumulatorHierarchy.svg @@ -0,0 +1,33 @@ + + + + + + +UmlClassDiagram + + + +20 + +Governable +../contracts/governance/Governable.sol + + + +279 + +FeeAccumulator +../contracts/strategies/NativeStaking/FeeAccumulator.sol + + + +279->20 + + + + + diff --git a/contracts/docs/generate.sh b/contracts/docs/generate.sh index 69ab22c21c..ed02d52347 100644 --- a/contracts/docs/generate.sh +++ b/contracts/docs/generate.sh @@ -84,8 +84,9 @@ sol2uml storage .. -c Generalized4626Strategy -o Generalized4626StrategyStorage. sol2uml .. -v -hv -hf -he -hs -hl -hi -b NativeStakingSSVStrategy -o NativeStakingSSVStrategyHierarchy.svg sol2uml .. -s -d 0 -b NativeStakingSSVStrategy -o NativeStakingSSVStrategySquashed.svg -sol2uml .. -s -d 0 -b FeeAccumulator -o FeeAccumulatorSquashed.svg sol2uml storage .. -c NativeStakingSSVStrategy -o NativeStakingSSVStrategyStorage.svg --hideExpand __gap,______gap,_reserved +sol2uml .. -v -hv -hf -he -hs -hl -hi -b FeeAccumulator -o FeeAccumulatorHierarchy.svg +sol2uml .. -s -d 0 -b FeeAccumulator -o FeeAccumulatorSquashed.svg sol2uml .. -v -hv -hf -he -hs -hl -hi -b MorphoAaveStrategy -o MorphoAaveStrategyHierarchy.svg sol2uml .. -s -d 0 -b MorphoAaveStrategy -o MorphoAaveStrategySquashed.svg diff --git a/contracts/docs/plantuml/oethContracts.png b/contracts/docs/plantuml/oethContracts.png index db3e35d8bf87727e53a1614e42df9ab24234a86b..e7df706f4537dd9d58c1e15ca283a72d1ebd4f75 100644 GIT binary patch literal 79801 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 literal 59071 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 #DeepSkyBlue { - assets: ETH, sfrxETH +object "OETHZapper" as zap <> #$originColor { + assets: ETH } -object "OETHDripper" as drip <><> #DeepSkyBlue { +object "OETHDripper" as drip <><> #$originColor { asset: WETH } -object "OETHVaultValueChecker" as checker <> #DeepSkyBlue { -} +' object "OETHVaultValueChecker" as checker <> #$originColor { +' } -object "WOETH" as woeth <><> #DeepSkyBlue { +object "WOETH" as woeth <><> #$originColor { asset: OETH symbol: WOETH name: Wrapped OETH } -object "OETH" as oeth <><> #DeepSkyBlue { +object "OETH" as oeth <><> #$originColor { symbol: OETH name: Origin Ether } -object "OETH Vault" as oethv <><> #DeepSkyBlue { -assets: - WETH - frxETH - stETH - rETH -} - -object "Swapper1InchV5" as swap <> #DeepSkyBlue { - asset: any +object "OETH Vault" as oethv <><> #$originColor { +asset: WETH } -object "OETHHarvester" as harv <><> #DeepSkyBlue { - rewards: CRV, CVX, BAL, AURA +object "OETHHarvester" as harv <><> #$originColor { + rewards: CRV, CVX } ' Strategies -object "FraxETHStrategy" as frxethstrat <><> #DeepSkyBlue { - asset: frxETH, WETH - vault: sfrxETH -} -object "ConvexEthMetaStrategy" as cvxStrat <><> #DeepSkyBlue { +object "ConvexEthMetaStrategy" as cvxStrat <><> #$originColor { asset: WETH Curve metapool: OETHCRV-f Convex pool: cvxOETHCRV-f Rewards: CRV, CVX } -object "MorphoAaveStrategy" as morphAaveStrat <><> #DeepSkyBlue { - asset: WETH - Aave token: aWETH -} -object "BalancerMetaPoolStrategy" as balancerStrat <><> #DeepSkyBlue { - asset: rETH, WETH - Balancer Pool Token: B-rETH-STABLE - Rewards: BAL, AURA +object "NativeStakingStrategy" as nativeStrat <><> #$originColor { + assets: WETH, ETH + Rewards: ETH, SSV } -' Oracle -object "OETHOracleRouter" as oracle <> #DeepSkyBlue { -pairs: - frxETH/ETH - stETH/ETH - rETH/ETH - CRV/ETH - CVX/ETH +object "FeeAccumulator" as feeAcc <><> #$originColor { + assets: ETH } -' object "EACAggregatorProxy" as chain <> { -' prices: CVX/ETH, CRV/ETH,\nrETH/ETH, stETH/ETH, frxETH/ETH,\nWETH/ETH +' ' Oracle +' object "OETHOracleRouter" as oracle <> #$originColor { +' pairs: +' CRV/ETH +' CVX/ETH ' } ' ' SushiSwap @@ -81,70 +74,43 @@ pairs: ' pairs: CRV/ETH, CVX/ETH ' } -' ' Curve -' object "Gauge" as gauge <> { -' asset: OETHCRV-f -' symbol: OETHCRV-f-gauge -' name: Curve.fi OETHCRV-f Gauge Deposit -' } -' object "StableSwap" as crvPool <> { -' assets: [ETH, OETH] -' symbol: OETHCRV-f -' name: Curve.fi Factory Pool: OETH -' } -' ' Convex -' ' object "Booster" as cvxBoost <> { -' ' } -' object "BaseRewardPool" as cvxPool <> { -' } +' Curve +object "Gauge" as gauge <> { + asset: OETHCRV-f + symbol: OETHCRV-f-gauge + name: Curve.fi OETHCRV-f Gauge Deposit +} +object "StableSwap" as crvPool <> { + assets: [ETH, OETH] + symbol: OETHCRV-f + name: Curve.fi Factory Pool: OETH +} +' Convex +object "Booster" as cvxBoost <> { +} +object "BaseRewardPool" as cvxPool <> { +} ' object "DepositToken" as cvxPoolLp <> { ' symbol: cvxOUSD3CRV-f ' name: Origin Dollar Convex Deposit ' } -' ' Aave Morpho -' object "Morpho\nAave V2" as morphoV2 <> { -' } -' object "Morpho\nLens" as morphoLens <> { -' } - -' object "aWETH" as aweth <> { -' symbol: aWETH -' name: Aave interest bearing WETH -' } -' object "variableDebtWETH" as vdweth <> { -' symbol: variableDebtWETH -' name: Aave variable debt bearing WETH -' } - -' ' Assets +' SSV +object "SSV Network" as ssvNet <> #$thirdPartyColor { +assets: ETH, SSV +} -' object "sfrxETH" as sfrxeth <> { -' asset: frxETH -' symbol: sfrxETH -' name: Staked Frax Ether -' } +object "Deposit" as bDep <> #$thirdPartyColor { +assets: ETH +} -' object "frxETH" as frxeth <> { -' symbol: frxETH -' name: Frax Ether -' } +' ' Assets ' object "WETH9" as weth <> { ' symbol: WETH ' name: Wrapped Ether ' } -' object "RocketTokenRETH" as reth <> { -' symbol: rETH -' name: Rocket Pool ETH -' } - -' object "Lido" as steth <><> { -' symbol: stETH -' name: Liquid staked Ether 2.0 -' } - ' ' Rewards ' object "ConvexToken" as cvx <> { ' symbol: CVX @@ -158,15 +124,13 @@ pairs: zap ..> oeth zap ..> oethv -' zap ....> sfrxeth -' zap .....> frxeth ' zap .....> weth ' drip .....> weth oethv <. drip -checker ..> oeth -checker ..> oethv +' checker ..> oeth +' checker ..> oethv oethv <.. harv drip <.. harv @@ -176,51 +140,35 @@ drip <.. harv woeth ..> oeth oeth <.> oethv -oethv ..> oracle -oethv .> swap +' oethv ..> oracle ' oracle ...> chain -' Staked FRAX ETH Strategy -oethv ...> frxethstrat -' frxethstrat ..> sfrxeth - ' Convex ETH Metapool Strategy harv <..> cvxStrat oethv <...> cvxStrat oeth <... cvxStrat -' cvxStrat ..> crvPool -' cvxStrat ..> cvxPool +harv <..> nativeStrat +oethv <...> nativeStrat +nativeStrat <.> feeAcc +nativeStrat ..> ssvNet +nativeStrat ..> bDep + +cvxStrat ..> crvPool +cvxStrat ...> cvxPool ' cvxStrat ...> weth ' cvxStrat ...> cvx ' cvxStrat ...> crv ' cvxPool ..> cvxPoolLp ' cvxPool ..> crv -' cvxPool .> gauge -' gauge .> crvPool -' oeth <... crvPool - -' Morpho Aave Strategy -oethv <...> morphAaveStrat -oeth <... morphAaveStrat -' morphAaveStrat ..> morphoV2 -' morphAaveStrat ..> morphoLens -' morphoLens .> morphoV2 -' morphoV2 ..> aweth -' morphoV2 ..> vdweth - -' Balancer Strategy -oethv <...> balancerStrat -oeth <... balancerStrat -harv <..> balancerStrat +gauge <. cvxPool +crvPool <.. gauge +oeth <... crvPool +cvxStrat ..> cvxBoost +cvxBoost ..> cvxPool ' ' Vault to Assets -' oethv .....> frxeth -' oethv .....> weth -' oethv .....> reth -' oethv .....> steth - -' sfrxeth ..> frxeth +' oethv ....> weth @enduml \ No newline at end of file diff --git a/contracts/docs/plantuml/oethValueFlows-native-staking.png b/contracts/docs/plantuml/oethValueFlows-native-staking.png new file mode 100644 index 0000000000000000000000000000000000000000..9042fa5f33bea1a619db13f9e5183602d5d71ab2 GIT binary patch literal 179573 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Χ-oj=oUMlK;|xX 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
g1R{@I7nFradYh1f_a6ffcH7| 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

2$ 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

n?2E*aVkHb! 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

;P@86$Hl+z>}GI(c9 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 literal 547985 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 jgTz_e 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%0AyJ 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

>z`M*e}KbcXCunV8!Rxr_=tEnTlnt%gbI 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�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 z%0D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

m- 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%0AvwA3eN(wHZ=19ER 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 diff --git a/contracts/docs/plantuml/oethValueFlows.puml b/contracts/docs/plantuml/oethValueFlows.puml index c2bf22c805..bf3cfab347 100644 --- a/contracts/docs/plantuml/oethValueFlows.puml +++ b/contracts/docs/plantuml/oethValueFlows.puml @@ -7,15 +7,12 @@ actor "Anyone" as anyone actor "Trustee" as trust <> #DeepSkyBlue participant "Zapper" as zap <> #DeepSkyBlue participant "OETH\nVault" as vault <> #DeepSkyBlue -participant "Harvester" as harv <> #DeepSkyBlue -participant "Dripper" as drip <> #DeepSkyBlue -participant "Swapper" as swapper <> #DeepSkyBlue -participant "OGV\nRewards" as ogvRewards <> #DeepSkyBlue -participant "Buyback" as buyBack <> #DeepSkyBlue -participant "FRAX\nStrategy" as frxStrat <> #DeepSkyBlue -participant "FRAX ETH" as frxETH <><> -participant "Staked\nFRAX ETH" as sfrxETH <><> +participant "Native ETH\nStrategy" as nativeStrat <> #DeepSkyBlue +participant "Native ETH\nFee Accumulator" as feeAcc <> #DeepSkyBlue +participant "SSV Network" as ssvNetwork <> +participant "Deposit" as dep <> +participant "Validator" as val <> participant "Curve AMO\nStrategy" as crvStrat <> #DeepSkyBlue participant "OETH-ETH\nMetapool" as oethCrv <> @@ -23,16 +20,6 @@ participant "OETH-ETH\nPool" as oethCvx <> participant "Rewards\nPool" as cvxRewards <> participant "Locked\nCVX" as icvx <> -participant "rETH/WETH\nBalancer\nMetaStable\nStrategy" as balMetaStrat <> #DeepSkyBlue -participant "Balancer\nVault" as balVault <> -participant "rETH\nMetaStable\nPool" as balMetaPool <> -participant "rETH\nRewards\nPool" as auraRewards <> - -participant "Morpho Aave\nStrategy" as morphAaveStrat <> #DeepSkyBlue -participant "Morpho\nAave V2" as morpho <> -participant "interst\nbearing\nWETH" as aweth <><> -participant "variable\ndebt WETH" as vdweth <><> - participant "TriCrv\ncrvUSD/ETH/CRV" as triCrv <> participant "cvxeth\nCVX/ETH" as cvxeth <> participant "Universal\nRouter" as uniRouter <> @@ -41,8 +28,11 @@ participant "OGV/ETH\nV3 Pool" as uniOgv <> participant "CVX/ETH\nV3 Pool" as uniCvx <> participant "Wrapped ETH" as weth <><> - -participant "1Inch\nRouter" as 1r <<1Inch>> +participant "Harvester" as harv <> #DeepSkyBlue +participant "Dripper" as drip <> #DeepSkyBlue +participant "Swapper" as swapper <> #DeepSkyBlue +participant "OGV\nRewards" as ogvRewards <> #DeepSkyBlue +participant "Buyback" as buyBack <> #DeepSkyBlue ' Deposit ETH via Zapper group User deposit ETH [> 10 OETH] @@ -64,70 +54,20 @@ vault o-> user : OETH note left : mint OETH\nto match ETH end -' Deposit sfrxETH via Zapper -group User deposit sfrxETH [> 10 OETH] -note over zap : User approves Zapper to transfer their sfrxETH - -user -x sfrxETH : sfrxETH -note left : redeem sfrxETH for frxETH -sfrxETH -> zap : frxETH - -vault o-> trust : OETH -note left : 20% performance\nfee from rebase - -zap -> vault : frxETH - -group FRAX Strategy -vault -> frxStrat : frxETH -note left: > 10 ETH worth so allocate\nto default frxETH strategy -frxStrat -> sfrxETH : frxETH -note left : deposit frxETH -sfrxETH o-> frxStrat : sfrxETH -note left : get sfrxETH shares -end - -vault o-> user : OETH -note left : mint OETH to match\nETH value of frxETH -end - ' Mint group User mint [< 10 OETH] vault o-> trust : OETH note left : 20% performance\nfee from rebase -user -> vault : frxETH, stETH, rETH or WETH +user -> vault : WETH note left: Only to vault,\nnot strategy as <10 ETH vault o-> user : OETH note left : mint OETH to\nETH value of deposit end -' Allocate -group Vault allocate [anyone can call] - -' FRAX Strategy for frxETH -group Deposit frxETH to FRAX Strategy [unallocated frxETH in vault] -vault -> frxStrat : frxETH -frxStrat -> sfrxETH : frxETH -note left : deposit frxETH -sfrxETH o-> frxStrat : sfrxETH -note left : get sfrxETH shares -end - -' FRAX Strategy for WETH -group Deposit WETH to FRAX Strategy [unallocated WETH in vault] -vault -> frxStrat : WETH -frxStrat -x weth : WETH -note left : withdraw ETH from WETH -weth -> frxStrat : ETH -frxStrat -> frxETH : ETH -note left : Deposit and stake ETH for sfrxETH -frxETH -> sfrxETH : frxETH -sfrxETH o-> frxStrat : sfrxETH -end - ' Curve AMO Strategy -group Deposit to Curve AMO Strategy [unallocated WETH in vault] +group Strategist deposits to Curve AMO Strategy [unallocated WETH in vault] vault -> crvStrat : WETH note left : Vault transfers\nWETH to strategy crvStrat -x weth : WETH @@ -148,63 +88,91 @@ oethCvx o-> cvxRewards : cvxOETHCRV-f note left : stake Convex LP tokens end -' Balancer MetaPool Strategy -group Deposit rETH and WETH to Balancer MetaStable Strategy [unallocated rETH and WETH in vault] -vault -> balMetaStrat : rETH and WETH -note left : Vault transfers\nrETH and WETH to strategy -balMetaStrat -> balVault : rETH and WETH -note left : join Balancer pool -balMetaPool o-> balMetaStrat : B-rETH-STABLE -balMetaStrat -> auraRewards : B-rETH-STABLE -note left : deposit BPT to Aura -auraRewards o-> balMetaStrat : auraB-rETH-STABLE-vault +' Native staking strategy +group Strategist deposits to Native Staking Strategy [unallocated WETH in vault] -end +... deposit to strategy ... + +vault -> nativeStrat : WETH +note left : Vault transfers\nWETH to strategy + +... register SSV validator ... + +nativeStrat -> ssvNetwork : SSV +note left : deposit SSV to SSV Cluster to pay SSV Operators + +... stake to validator ... + +nativeStrat -x weth : WETH +note left : WETH is burned +weth -> nativeStrat : ETH +note left : ETH is withdrawn + +nativeStrat -> dep : 32 ETH +note left : deposit 32 ETH to\nSSV Beacon Chain + +... 1024 execution blocks (~4 hours) ... +... 32 consensus epochs (~3.5 hours) ... + +dep -> val : 32 ETH + +note over val : Pending Activation + +... four validators are activated each epoch from the Validator Queue (0.5-10 days) ... + +note over val : Active -' Morpho Aave Strategy -group Deposit to Morpho Aave Strategy [unallocated WETH in vault] -vault -> morphAaveStrat : WETH -morphAaveStrat -> morpho : WETH -morpho -> aweth : WETH - -alt Morpho has more borrows than deposits -morpho -x vdweth : varDebtWETH -note left : repay borrowed WETH from Aave -else Morpho has more deposits than borrows -aweth o-> morpho : aWETH -note left : deposit WETH to Aave end + + +group Native staking rewards + +... partial withdraw from Beacon chain very 8-10 days ... + +val -> nativeStrat : ETH +note right : Beacon chain\nconsensus rewards + +... when a validator produces a block (~4 times a year) ... + +val -> feeAcc : ETH +note right : execution rewards\nincluding MEV + end +group Validator registrator exits a validator + +... validator exit ... + +... wait until validator has exited.\nmin four epochs (~25 min), currently 1.5 hours but can take a number of days depending on the number of validators in the exit queue ... + +... wait for the validator to be swept on the Beacon chain\ncurrent time is every 8-10 days ... + +val -> nativeStrat : ETH +note right : Beacon chain sweeps ETH\nto the Native Staking strategy + +... validator registrator does accounting ... + +nativeStrat -> weth : ETH +note left : deposit ETH into Wrapped ETH +weth o-> nativeStrat : WETH +note left : mint WETH to Native Staking Strategy + +nativeStrat -> vault : WETH +note right : transfer WETH to Vault + end +group Strategist withdraw from Native Staking Strategy [WETH in strategy from deposits] -' Redeem -group User redeem OETH -vault o-> trust : OETH -note left : 20% performance\nfee from rebase +nativeStrat -> vault : WETH +note right : transfer WETH to Vault -user -x vault : OETH -note left : burn User's OETH +note over nativeStrat : Once WETH has been staked in a validator, the exist validator process must be used. -note over vault : 0.5% fee applied to redeemed assets.\nThis adds to the yield in the next rebase. - -' FRAX Strategy -group Withdraw from FRAX Strategy [not enough frxETH in vault] -note over frxStrat -can only redeem frxETH. -depositted WETH is removed as frxETH. -end note -frxStrat -x sfrxETH : sfrxETH -note left : redeem sfrxETH shares -sfrxETH -> user : frxETH -note left : transfer directly to user -' sfrxETH -> vault : frxETH -' note left : transfer to vault end ' Curve AMO Strategy -group Withdraw from Curve AMO Strategy [not enough WETH in vault] +group Strategist withdraw from Curve AMO Strategy [not enough WETH in vault] cvxRewards -x oethCvx : cvxOETHCRV-f note left : unstake and burn Convex LP tokens oethCvx -> crvStrat : OETHCRV-f @@ -226,27 +194,20 @@ note left : transfer directly to user ' note left : transfer to vault end -' Morpho Aave Strategy -group Withdraw from Morpho Aave Strategy [not enough WETH in vault] -alt Morpho has more borrows than deposits -vdweth o-> morpho : varDebtWETH -note left : borrow WETH from Aave -else Morpho has more deposits than borrows -morpho -x aweth : aWETH -note left : withdraw WETH deposit from Aave -end -aweth -> morpho : WETH -morpho -> morphAaveStrat : WETH -' morphAaveStrat -> vault : WETH -morphAaveStrat -> user : WETH -note left : transfer directly to user -end +' Redeem +group User redeem OETH +vault o-> trust : OETH +note left : 20% performance\nfee from rebase + +user -x vault : OETH +note left : burn User's OETH + +vault -> user : WETH +note right : 0.1% fee applied to redeemed assets.\nThis adds to the yield in the next rebase. -note over vault : no strategy so comes from vault -vault -> user : stETH -vault -> user : rETH end + ' Curve AMO Strategy - mint and add oTokens group Strategist mints and adds oTokens to Metapool [too much ETH in Metapool] vault o-> crvStrat : OETH @@ -299,6 +260,17 @@ end ' Harvest and swap Convex AMO group Harvest and swap Convex AMO rewards [can be called by anyone] +feeAcc -> nativeStrat : ETH +note left : transfer execution rewards to Native Staking Strategy +nativeStrat -> weth : ETH +note left : deposit ETH from execution and consensus rewards into Wrapped ETH +weth o-> nativeStrat : WETH +note left : mint WETH to Native Staking Strategy +nativeStrat -> harv : WETH +note left : transfer WETH to Harvester +harv -> drip : 100% WETH +note left : 100% of WETH to Dripper + cvxRewards -> crvStrat : CVX & CRV note left : collect Convex rewards crvStrat -> harv : CVX & CRV @@ -327,32 +299,6 @@ harv -> anyone : 2% WETH note left : 2% of WETH\nto Harvest caller end -' Harvest and swap Balancer -group Harvest and swap Balancer rewards [can be called by anyone] - -balMetaPool -> balMetaStrat : BAL -note left : collect Balancer rewards -auraRewards -> balMetaStrat : AURA -note left : collect Aura rewards -balMetaStrat -> harv : BAL & AURA -note left : transfer rewards to Harvester -harv -> balVault : BAL -note left : swap BAL for WETH\nmax 1,000 BAL -balVault -> harv : WETH -harv -> drip : WETH -note left : 98% of WETH to Dripper -harv -> anyone : WETH -note left : 2% of WETH\nto Harvest caller -harv -> balVault : AURA -note left : swap AURA for WETH\nmax 4,000 BAL -balVault -> harv : WETH -harv -> drip : WETH -note left : 98% of WETH to Dripper -harv -> anyone : WETH -note left : 2% of WETH\nto Harvest caller - -end - ' Collect and Rebase group Collect and Rebase [can be called by anyone] @@ -368,7 +314,7 @@ note left : 20% of rebase\nto trustee as\nperformance fee end end -group Trustee OETH rewards +group OETH rewards group OGV buyback for OGV stakers trust -> uniRouter : OETH @@ -395,12 +341,4 @@ end end -' Swap vault collateral assets -group Trustee swaps collateral assets [WETH for rETH] -vault -> swapper : WETH -note left : swap WETH for rETH -swapper -> 1r : WETH -1r -> vault : rETH -end - @enduml diff --git a/contracts/fork-test.sh b/contracts/fork-test.sh index 3a499dd53a..c4d94009f3 100755 --- a/contracts/fork-test.sh +++ b/contracts/fork-test.sh @@ -74,7 +74,7 @@ main() if [[ $FORK_NETWORK_NAME == "holesky" ]]; then # Run all files with `.holesky.fork-test.js` suffix when no file name param is given # pass all other params along - params+="test/**/*.holesky.fork-test.js" + params+="test/**/*.holesky-fork-test.js" else # Run all files with `.fork-test.js` suffix when no file name param is given # pass all other params along diff --git a/contracts/hardhat.config.js b/contracts/hardhat.config.js index c09b01ee34..32de4c1a18 100644 --- a/contracts/hardhat.config.js +++ b/contracts/hardhat.config.js @@ -1,14 +1,11 @@ const ethers = require("ethers"); const { task } = require("hardhat/config"); const { - isFork, isArbitrumFork, isHoleskyFork, isHolesky, isForkTest, - isArbForkTest, isHoleskyForkTest, - providerUrl, arbitrumProviderUrl, holeskyProviderUrl, adjustTheForkBlockNumber, diff --git a/contracts/package.json b/contracts/package.json index 5abce09f9e..a45dee4888 100644 --- a/contracts/package.json +++ b/contracts/package.json @@ -75,8 +75,10 @@ "solhint": "^3.4.1", "solidifier": "^2.2.3", "solidity-coverage": "^0.8.2", + "ssv-keys": "^1.1.0", "ssv-scanner": "github:bloxapp/ssv-scanner", "sync-fetch": "^0.5.2", + "uuid": "^9.0.1", "web3-utils": "^1.5.2" }, "husky": { diff --git a/contracts/scripts/deploy/verifySimpleOETHDeployment.sh b/contracts/scripts/deploy/verifySimpleOETHDeployment.sh old mode 100644 new mode 100755 index 1dbdc7bc0c..7fc14add36 --- a/contracts/scripts/deploy/verifySimpleOETHDeployment.sh +++ b/contracts/scripts/deploy/verifySimpleOETHDeployment.sh @@ -10,10 +10,10 @@ export FEE_ACC=0x79681d3f14a0068479420eE5fDdF59B62301f810 export FEE_ACC_PROXY=0x590B781b511e953dbFC49e7E7864A6E787aFBDCc export OETH_DRIPPER=0x3833C32826A7f2a93C48D50ae44D45F45Ab17B7F export OETH_DRIPPER_PROXY=0xaFF1E6263F4004C95Ae611DEb2ADaC049B5aD121 -export OETH_HARVESTER=0x22b00a89531E199bd90eC162F9810298b9FBC8b3 +export OETH_HARVESTER=0xBd09F938259AE61e089959d52580235b76C69A83 export OETH_HARVESTER_PROXY=0xB7491cdf36367C89001cc41312F22f63A3a17931 export OETH_ORACLE_ROUTER=0x7e2bf9A89180f20591EcFA42C0dd7e52b2C546E3 -export NATIVE_STAKING=0x33Eeb0996f6981ff7d11F643630734856BEc09f5 +export NATIVE_STAKING=0x51766Fd366D6C9121F6Aeec20267ecA87c2c9793 export NATIVE_STAKING_PROXY=0x4Eac8847c7AE50e3A3551B1Aa4FF7Cc162151410 export WETH=0x94373a4919b3240d86ea41593d5eba789fef3848 export ZERO=0x0000000000000000000000000000000000000000 diff --git a/contracts/tasks/curve.js b/contracts/tasks/curve.js index 23bf6493cb..ffeae9621a 100644 --- a/contracts/tasks/curve.js +++ b/contracts/tasks/curve.js @@ -4,7 +4,7 @@ const { formatUnits, parseUnits } = require("ethers/lib/utils"); const ousdPoolAbi = require("../test/abi/ousdMetapool.json"); const oethPoolAbi = require("../test/abi/oethMetapool.json"); const addresses = require("../utils/addresses"); -const { resolveAsset } = require("../utils/assets"); +const { resolveAsset } = require("../utils/resolvers"); const { getDiffBlocks } = require("./block"); const { getSigner } = require("../utils/signers"); diff --git a/contracts/tasks/governable.js b/contracts/tasks/governable.js new file mode 100644 index 0000000000..b8eef6465a --- /dev/null +++ b/contracts/tasks/governable.js @@ -0,0 +1,45 @@ +const { resolveContract } = require("../utils/resolvers"); +const { ethereumAddress } = require("../utils/regex"); +const { getSigner } = require("../utils/signers"); +const { logTxDetails } = require("../utils/txLogger"); + +const log = require("../utils/logger")("task:governable"); + +async function governor({ proxy }) { + const signer = await getSigner(); + + const contract = await resolveContract(proxy, "Governable"); + + const governor = await contract.connect(signer).governor(); + console.log(`Governor for ${proxy} is ${governor}`); +} + +async function transferGovernance({ proxy, governor }) { + const signer = await getSigner(); + + const contract = await resolveContract(proxy, "Governable"); + + if (!governor.match(ethereumAddress)) { + throw new Error(`Invalid governor address: ${governor}`); + } + + log(`About to transfer governance for ${proxy} to ${governor}`); + const tx = await contract.connect(signer).transferGovernance(governor); + await logTxDetails(tx, "transferGovernance"); +} + +async function claimGovernance({ proxy }) { + const signer = await getSigner(); + + const governable = await resolveContract(proxy, "Governable"); + + log(`About to claim governance for ${proxy}`); + const tx = await governable.connect(signer).claimGovernance(); + await logTxDetails(tx, "claimGovernance"); +} + +module.exports = { + transferGovernance, + claimGovernance, + governor, +}; diff --git a/contracts/tasks/proxy.js b/contracts/tasks/proxy.js index 1977bcb3f7..f42f502d9b 100644 --- a/contracts/tasks/proxy.js +++ b/contracts/tasks/proxy.js @@ -3,9 +3,7 @@ const { getSigner } = require("../utils/signers"); const log = require("../utils/logger")("task:proxy"); -async function proxyUpgrades(taskArguments, hre) { - const { contract, from, to } = taskArguments; - +async function proxyUpgrades({ contract, from, to }, hre) { const toBlockNumber = to || (await hre.ethers.provider.getBlockNumber()); log(`Searching for Upgraded events from ${from} to ${toBlockNumber}`); diff --git a/contracts/tasks/ssv.js b/contracts/tasks/ssv.js index 539ef986cc..c156f76ad1 100644 --- a/contracts/tasks/ssv.js +++ b/contracts/tasks/ssv.js @@ -1,6 +1,21 @@ +const { parseUnits, formatUnits } = require("ethers/lib/utils"); const { ClusterScanner, NonceScanner } = require("ssv-scanner"); + +const addresses = require("../utils/addresses"); +const { resolveContract } = require("../utils/resolvers"); +const { getSigner } = require("../utils/signers"); +const { logTxDetails } = require("../utils/txLogger"); + const log = require("../utils/logger")("task:ssv"); +const printClusterInfo = async (options) => { + const cluster = await getClusterInfo(options); + const nextNonce = await getClusterNonce(options); + console.log(`block ${cluster.block}`); + console.log(`Cluster: ${JSON.stringify(cluster.snapshot, null, " ")}`); + console.log("Next Nonce:", nextNonce); +}; + const getClusterInfo = async ({ ownerAddress, operatorids, @@ -69,15 +84,44 @@ const getClusterNonce = async ({ return nextNonce; }; -const printClusterInfo = async (options) => { - const cluster = await getClusterInfo(options); - const nextNonce = await getClusterNonce(options); - console.log(`block ${cluster.block}`); - console.log(`Cluster: ${JSON.stringify(cluster.snapshot, null, " ")}`); - console.log("Next Nonce:", nextNonce); +const depositSSV = async ({ amount, operatorids }, hre) => { + const amountBN = parseUnits(amount.toString(), 18); + log(`Splitting operator IDs ${operatorids}`); + const operatorIds = operatorids.split(".").map((id) => parseInt(id)); + + const signer = await getSigner(); + + const strategy = await resolveContract( + "NativeStakingSSVStrategyProxy", + "NativeStakingSSVStrategy" + ); + const ssvNetworkAddress = addresses[hre.network.name].SSVNetwork; + const ssvNetwork = await resolveContract(ssvNetworkAddress, "ISSVNetwork"); + + // Cluster details + const clusterInfo = await getClusterInfo({ + chainId: hre.network.config.chainId, + ssvNetwork: ssvNetwork.address, + operatorIds, + ownerAddress: strategy.address, + }); + + log( + `About to deposit ${formatUnits( + amountBN + )} SSV tokens to the SSV Network for native staking strategy ${ + strategy.address + } with operator IDs ${operatorIds}` + ); + log(`Cluster: ${JSON.stringify(clusterInfo.snapshot)}`); + const tx = await strategy + .connect(signer) + .depositSSV(operatorIds, amountBN, clusterInfo.cluster); + await logTxDetails(tx, "depositSSV"); }; module.exports = { printClusterInfo, getClusterInfo, + depositSSV, }; diff --git a/contracts/tasks/strategy.js b/contracts/tasks/strategy.js new file mode 100644 index 0000000000..682357353f --- /dev/null +++ b/contracts/tasks/strategy.js @@ -0,0 +1,55 @@ +const { formatUnits } = require("ethers/lib/utils"); +const { resolveContract, resolveAsset } = require("../utils/resolvers"); +const { getSigner } = require("../utils/signers"); +const { logTxDetails } = require("../utils/txLogger"); + +const log = require("../utils/logger")("task:strategy"); + +async function checkBalance({ proxy, symbol }) { + const signer = await getSigner(); + + const asset = await resolveAsset(symbol); + const strategy = await resolveContract( + proxy, + "InitializableAbstractStrategy" + ); + + const balance = await strategy.connect(signer).checkBalance(asset.address); + console.log(`Strategy balance: ${formatUnits(balance)}`); +} + +async function getRewardTokenAddresses({ proxy }) { + const signer = await getSigner(); + + const strategy = await resolveContract( + proxy, + "InitializableAbstractStrategy" + ); + + const rewardTokens = await strategy.connect(signer).getRewardTokenAddresses(); + console.log(`Strategy reward tokens for ${proxy} are: ${rewardTokens}`); +} + +async function setRewardTokenAddresses({ proxy, symbol }) { + const signer = await getSigner(); + + const asset = await resolveAsset(symbol); + const strategy = await resolveContract( + proxy, + "InitializableAbstractStrategy" + ); + + log( + `About to set the reward tokens for the strategy ${proxy} to [${symbol}] ${asset.address}` + ); + const tx = await strategy + .connect(signer) + .setRewardTokenAddresses([asset.address]); + await logTxDetails(tx, "setRewardTokenAddresses"); +} + +module.exports = { + getRewardTokenAddresses, + setRewardTokenAddresses, + checkBalance, +}; diff --git a/contracts/tasks/tasks.js b/contracts/tasks/tasks.js index 6a6e08518d..d922fdf25f 100644 --- a/contracts/tasks/tasks.js +++ b/contracts/tasks/tasks.js @@ -48,7 +48,7 @@ const { curveSwapTask, curvePoolTask, } = require("./curve"); -const { printClusterInfo } = require("./ssv"); +const { depositSSV, printClusterInfo } = require("./ssv"); const { amoStrategyTask, mintAndAddOTokensTask, @@ -56,6 +56,17 @@ const { removeOnlyAssetsTask, } = require("./amoStrategy"); const { proxyUpgrades } = require("./proxy"); +const { + governor, + transferGovernance, + claimGovernance, +} = require("./governable"); +const { + getRewardTokenAddresses, + setRewardTokenAddresses, + checkBalance, +} = require("./strategy"); + const log = require("../utils/logger")("tasks"); // Environment tasks. @@ -744,6 +755,84 @@ task("proxyUpgrades", "Lists all proxy implementation changes") ) .setAction(proxyUpgrades); +// Governable + +task("governor", "Gets the governor of a Governable contract") + .addParam( + "proxy", + "Name of the proxy contract or contract name if no proxy. eg OETHVaultProxy or OETHZapper", + undefined, + types.string + ) + .setAction(governor); + +task( + "transferGovernance", + "Start transfer of governance for a Governable contract" +) + .addParam( + "proxy", + "Name of the proxy contract or contract name if no proxy. eg OETHVaultProxy or OETHZapper", + undefined, + types.string + ) + .setAction(transferGovernance); + +task( + "claimGovernance", + "Complete the transfer of governance for a Governable contract" +) + .addParam( + "proxy", + "Name of the proxy contract or contract name if no proxy. eg OETHVaultProxy or OETHZapper", + undefined, + types.string + ) + .setAction(claimGovernance); + +// Strategy + +task("checkBalance", "Gets the asset balance of a strategy") + .addParam( + "proxy", + "Name of the proxy contract or contract name if no proxy. eg OETHVaultProxy or OETHZapper", + undefined, + types.string + ) + .addParam( + "symbol", + "Symbol of the token. eg WETH, CRV, CVX, BAL or AURA", + undefined, + types.string + ) + .setAction(checkBalance); + +task("getRewardTokenAddresses", "Gets the reward tokens of a strategy") + .addParam( + "proxy", + "Name of the proxy contract or contract name if no proxy. eg OETHVaultProxy or OETHZapper", + undefined, + types.string + ) + .setAction(getRewardTokenAddresses); + +task("setRewardTokenAddresses", "Sets the reward token of a strategy") + .addParam( + "proxy", + "Name of the proxy contract or contract name if no proxy. eg OETHVaultProxy or OETHZapper", + undefined, + types.string + ) + .addParam( + "symbol", + "Symbol of the token. eg WETH, CRV, CVX, BAL or AURA", + undefined, + types.string + ) + .setAction(setRewardTokenAddresses); + +// SSV + subtask("getClusterInfo", "Print out information regarding SSV cluster") .addParam( "operatorids", @@ -774,3 +863,19 @@ subtask("getClusterInfo", "Print out information regarding SSV cluster") task("getClusterInfo").setAction(async (_, __, runSuper) => { return runSuper(); }); + +subtask( + "depositSSV", + "Deposit SSV tokens from the native staking strategy into an SSV Cluster" +) + .addParam("amount", "Amount of SSV tokens to deposit", undefined, types.float) + .addParam( + "operatorids", + "4 operator ids separated with a dot: same as IP format. E.g. 60.79.220.349", + undefined, + types.string + ) + .setAction(depositSSV); +task("depositSSV").setAction(async (_, __, runSuper) => { + return runSuper(); +}); diff --git a/contracts/tasks/tokens.js b/contracts/tasks/tokens.js index aa6d2f70b1..d12bae8eb0 100644 --- a/contracts/tasks/tokens.js +++ b/contracts/tasks/tokens.js @@ -1,6 +1,6 @@ const { parseUnits, formatUnits } = require("ethers/lib/utils"); -const { resolveAsset } = require("../utils/assets"); +const { resolveAsset } = require("../utils/resolvers"); const { getSigner } = require("../utils/signers"); const { logTxDetails } = require("../utils/txLogger"); const { ethereumAddress } = require("../utils/regex"); @@ -8,8 +8,7 @@ const { getBlock } = require("./block"); const log = require("../utils/logger")("task:tokens"); -async function tokenBalance(taskArguments) { - const { account, block, symbol } = taskArguments; +async function tokenBalance({ account, block, symbol }) { const signer = await getSigner(); const asset = await resolveAsset(symbol); @@ -24,8 +23,7 @@ async function tokenBalance(taskArguments) { const decimals = await asset.decimals(); console.log(`${accountAddr} has ${formatUnits(balance, decimals)} ${symbol}`); } -async function tokenAllowance(taskArguments) { - const { block, owner, spender, symbol } = taskArguments; +async function tokenAllowance({ block, owner, spender, symbol }) { const signer = await getSigner(); const asset = await resolveAsset(symbol); @@ -46,8 +44,7 @@ async function tokenAllowance(taskArguments) { ); } -async function tokenApprove(taskArguments) { - const { amount, symbol, spender } = taskArguments; +async function tokenApprove({ amount, symbol, spender }) { const signer = await getSigner(); if (!spender.match(ethereumAddress)) { @@ -62,8 +59,7 @@ async function tokenApprove(taskArguments) { await logTxDetails(tx, "approve"); } -async function tokenTransfer(taskArguments) { - const { amount, symbol, to } = taskArguments; +async function tokenTransfer({ amount, symbol, to }) { const signer = await getSigner(); if (!to.match(ethereumAddress)) { @@ -90,8 +86,7 @@ async function tokenTransfer(taskArguments) { await logTxDetails(tx, "transfer"); } -async function tokenTransferFrom(taskArguments) { - const { amount, symbol, from, to } = taskArguments; +async function tokenTransferFrom({ amount, symbol, from, to }) { const signer = await getSigner(); if (!from.match(ethereumAddress)) { diff --git a/contracts/tasks/validator.js b/contracts/tasks/validator.js new file mode 100644 index 0000000000..566dbef27c --- /dev/null +++ b/contracts/tasks/validator.js @@ -0,0 +1,542 @@ +const fetch = require("node-fetch"); +const { defaultAbiCoder, formatUnits, hexDataSlice, parseEther } = + require("ethers").utils; +const { v4: uuidv4 } = require("uuid"); + +const { resolveContract } = require("../utils/resolvers"); +const { getSigner } = require("../utils/signers"); +const { getClusterInfo } = require("../utils/ssv"); +const { sleep } = require("../utils/time"); +const { logTxDetails } = require("../utils/txLogger"); + +const log = require("../utils/logger")("task:p2p"); + +/* When same UUID experiences and error threshold amount of times it is + * discarded. + */ +const ERROR_THRESHOLD = 5; +/* + * Spawns and maintains the required amount of validators throughout + * their setup cycle which consists of: + * - check balance of (W)ETH and crate P2P SSV cluster creation request + * - wait for the cluster to become operational + * - batch register the cluster on the SSV network + * - verify the complete cluster has been registered + * - batch stake the ETH to each of the validators + * + * Needs to also handle: + * - if anytime in the spawn cycle the number of (W)ETH falls below the + * required stake amount (withdrawal from Node Operator), mark the spawn + * process as failed + * - if spawn process gets stuck at any of the above steps and is not able to + * recover in X amount of times (e.g. 5 times). Mark the process as failed + * and start over. + */ +const operateValidators = async ({ store, signer, contracts, config }) => { + const { + clear, + eigenPodAddress, + p2p_api_key, + validatorSpawnOperationalPeriodInDays, + p2p_base_url, + stake, + } = config; + + let currentState = await getState(store); + log("currentState", currentState); + + if (clear && currentState?.uuid) { + await clearState(currentState.uuid, store); + currentState = undefined; + } + + if (!(await nodeDelegatorHas32Eth(contracts))) { + log(`Node delegator doesn't have enough ETH, exiting`); + return; + } + + const executeOperateLoop = async () => { + while (true) { + if (!currentState) { + await createValidatorRequest( + p2p_api_key, // api key + p2p_base_url, + contracts.nodeDelegator.address, // node delegator address + eigenPodAddress, // eigenPod address + validatorSpawnOperationalPeriodInDays, + store + ); + currentState = await getState(store); + } + + if (currentState.state === "validator_creation_issued") { + await confirmValidatorCreatedRequest( + p2p_api_key, + p2p_base_url, + currentState.uuid, + store + ); + currentState = await getState(store); + } + + if (currentState.state === "validator_creation_confirmed") { + await broadcastRegisterValidator( + signer, + store, + currentState.uuid, + currentState.metadata, + contracts.nodeDelegator + ); + currentState = await getState(store); + } + + if (currentState.state === "register_transaction_broadcast") { + await waitForTransactionAndUpdateStateOnSuccess( + store, + currentState.uuid, + contracts.nodeDelegator.provider, + currentState.metadata.validatorRegistrationTx, + "registerSsvValidator", // name of transaction we are waiting for + "validator_registered" // new state when transaction confirmed + ); + currentState = await getState(store); + } + + if (!stake) break; + + if (currentState.state === "validator_registered") { + await depositEth( + signer, + store, + currentState.uuid, + contracts.nodeDelegator, + currentState.metadata.depositData + ); + currentState = await getState(store); + } + + if (currentState.state === "deposit_transaction_broadcast") { + await waitForTransactionAndUpdateStateOnSuccess( + store, + currentState.uuid, + contracts.nodeDelegator.provider, + currentState.metadata.depositTx, + "stakeEth", // name of transaction we are waiting for + "deposit_confirmed" // new state when transaction confirmed + ); + + currentState = await getState(store); + } + + if (currentState.state === "deposit_confirmed") { + await clearState(currentState.uuid, store); + break; + } + await sleep(1000); + } + }; + + try { + if ((await getErrorCount(store)) >= ERROR_THRESHOLD) { + await clearState( + currentState.uuid, + store, + `Errors have reached the threshold(${ERROR_THRESHOLD}) discarding attempt` + ); + return; + } + await executeOperateLoop(); + } catch (e) { + await increaseErrorCount(currentState ? currentState.uuid : "", store, e); + throw e; + } +}; + +const getErrorCount = async (store) => { + const existingRequest = await getState(store); + return existingRequest && existingRequest.errorCount + ? existingRequest.errorCount + : 0; +}; + +const increaseErrorCount = async (requestUUID, store, error) => { + if (!requestUUID) { + return; + } + + const existingRequest = await getState(store); + const existingErrorCount = existingRequest.errorCount + ? existingRequest.errorCount + : 0; + const newErrorCount = existingErrorCount + 1; + + await store.put( + "currentRequest", + JSON.stringify({ + ...existingRequest, + errorCount: newErrorCount, + }) + ); + log( + `Operate validators loop uuid: ${requestUUID} encountered an error ${newErrorCount} times. Error: `, + error + ); +}; + +/* Each P2P request has a life cycle that results in the following states stored + * in the shared Defender key-value storage memory. + * - "validator_creation_issued" the create request that creates a validator issued + * - "validator_creation_confirmed" confirmation that the validator has been created + * - "register_transaction_broadcast" the transaction to register the validator on + * the SSV network has been broadcast to the Ethereum network + * - "validator_registered" the register transaction has been confirmed + * - "deposit_transaction_broadcast" the stake transaction staking 32 ETH has been + * broadcast to the Ethereum network + * - "deposit_confirmed" transaction to stake 32 ETH has been confirmed + */ +const updateState = async (requestUUID, state, store, metadata = {}) => { + if ( + ![ + "validator_creation_issued", + "validator_creation_confirmed", + "register_transaction_broadcast", + "validator_registered", + "deposit_transaction_broadcast", + "deposit_confirmed", + ].includes(state) + ) { + throw new Error(`Unexpected state: ${state}`); + } + + const existingRequest = await getState(store); + const existingMetadata = + existingRequest && existingRequest.metadata ? existingRequest.metadata : {}; + + await store.put( + "currentRequest", + JSON.stringify({ + uuid: requestUUID, + state: state, + metadata: { ...existingMetadata, ...metadata }, + }) + ); +}; + +const clearState = async (uuid, store, error = false) => { + if (error) { + log( + `Clearing state tracking of ${uuid} request because of an error: ${error}` + ); + } else { + log( + `Clearing state tracking of ${uuid} request as it has completed its spawn cycle` + ); + } + await store.del("currentRequest"); +}; + +/* Fetches the state of the current/ongoing cluster creation if there is any + * returns either: + * - false if there is no cluster + * - + */ +const getState = async (store) => { + const currentState = await store.get("currentRequest"); + if (!currentState) { + return currentState; + } + + return JSON.parse(await store.get("currentRequest")); +}; + +const nodeDelegatorHas32Eth = async (contracts) => { + const address = contracts.nodeDelegator.address; + const wethBalance = await contracts.WETH.balanceOf(address); + const ethBalance = await contracts.nodeDelegator.provider.getBalance(address); + const totalBalance = wethBalance.add(ethBalance); + + log(`Node delegator has ${formatUnits(totalBalance, 18)} ETH in total`); + return totalBalance.gte(parseEther("32")); +}; + +/* Make a GET or POST request to P2P service + * @param api_key: p2p service api key + * @param method: http method that can either be POST or GET + * @param body: body object in case of a POST request + */ +const p2pRequest = async (url, api_key, method, body) => { + const headers = { + Accept: "application/json", + Authorization: `Bearer ${api_key}`, + }; + + if (method === "POST") { + headers["Content-Type"] = "application/json"; + } + + const bodyString = JSON.stringify(body); + log( + `Creating a P2P ${method} request with ${url} `, + body != undefined ? ` and body: ${bodyString}` : "" + ); + + const rawResponse = await fetch(url, { + method, + headers, + body: bodyString, + }); + + const response = await rawResponse.json(); + if (response.error != null) { + log("Request to P2P service failed with an error:", response); + throw new Error( + `Call to P2P has failed: ${JSON.stringify(response.error)}` + ); + } else { + log("Request to P2P service succeeded: ", response); + } + + return response; +}; + +const createValidatorRequest = async ( + p2p_api_key, + p2p_base_url, + nodeDelegatorAddress, + eigenPodAddress, + validatorSpawnOperationalPeriodInDays, + store +) => { + const uuid = uuidv4(); + await p2pRequest( + `https://${p2p_base_url}/api/v1/eth/staking/ssv/request/create`, + p2p_api_key, + "POST", + { + validatorsCount: 1, + id: uuid, + withdrawalAddress: eigenPodAddress, + feeRecipientAddress: nodeDelegatorAddress, + ssvOwnerAddress: nodeDelegatorAddress, + type: "without-encrypt-key", + operationPeriodInDays: validatorSpawnOperationalPeriodInDays, + } + ); + + await updateState(uuid, "validator_creation_issued", store); +}; + +const waitForTransactionAndUpdateStateOnSuccess = async ( + store, + uuid, + provider, + txHash, + methodName, + newState +) => { + log( + `Waiting for transaction with hash "${txHash}" method "${methodName}" and uuid "${uuid}" to be mined...` + ); + const tx = await provider.waitForTransaction(txHash); + if (!tx) { + throw Error( + `Transaction with hash "${txHash}" not found for method "${methodName}" and uuid "${uuid}"` + ); + } + await updateState(uuid, newState, store); +}; + +const depositEth = async (signer, store, uuid, nodeDelegator, depositData) => { + const { pubkey, signature, depositDataRoot } = depositData; + try { + log(`About to stake ETH with:`); + log(`pubkey: ${pubkey}`); + log(`signature: ${signature}`); + log(`depositDataRoot: ${depositDataRoot}`); + const tx = await nodeDelegator.connect(signer).stakeEth([ + { + pubkey, + signature, + depositDataRoot, + }, + ]); + + log(`Transaction to stake ETH has been broadcast with hash: ${tx.hash}`); + + await updateState(uuid, "deposit_transaction_broadcast", store, { + depositTx: tx.hash, + }); + } catch (e) { + log(`Submitting transaction failed with: `, e); + //await clearState(uuid, store, `Transaction to deposit to validator fails`) + throw e; + } +}; + +const broadcastRegisterValidator = async ( + signer, + store, + uuid, + metadata, + nodeDelegator +) => { + const registerTransactionParams = defaultAbiCoder.decode( + [ + "bytes", + "uint64[]", + "bytes", + "uint256", + "tuple(uint32, uint64, uint64, bool, uint256)", + ], + hexDataSlice(metadata.registerValidatorData, 4) + ); + // the publicKey and sharesData params are not encoded correctly by P2P so we will ignore them + const [, operatorIds, , amount, cluster] = registerTransactionParams; + // get publicKey and sharesData state storage + const publicKey = metadata.depositData.pubkey; + if (!publicKey) { + throw Error( + `pubkey not found in metadata.depositData: ${metadata?.depositData}` + ); + } + const { sharesData } = metadata; + if (!sharesData) { + throw Error(`sharesData not found in metadata: ${metadata}`); + } + + log(`About to register validator with:`); + log(`publicKey: ${publicKey}`); + log(`operatorIds: ${operatorIds}`); + log(`sharesData: ${sharesData}`); + log(`amount: ${amount}`); + log(`cluster: ${cluster}`); + + try { + const tx = await nodeDelegator + .connect(signer) + .registerSsvValidator( + publicKey, + operatorIds, + sharesData, + amount, + cluster + ); + + log( + `Transaction to register SSV Validator has been broadcast with hash: ${tx.hash}` + ); + + await updateState(uuid, "register_transaction_broadcast", store, { + validatorRegistrationTx: tx.hash, + }); + } catch (e) { + log(`Submitting transaction failed with: `, e); + //await clearState(uuid, store, `Transaction to register SSV Validator fails`) + throw e; + } +}; + +const confirmValidatorCreatedRequest = async ( + p2p_api_key, + p2p_base_url, + uuid, + store +) => { + const doConfirmation = async () => { + const response = await p2pRequest( + `https://${p2p_base_url}/api/v1/eth/staking/ssv/request/status/${uuid}`, + p2p_api_key, + "GET" + ); + if (response.error != null) { + log(`Error processing request uuid: ${uuid} error: ${response}`); + } else if (response.result.status === "ready") { + const registerValidatorData = + response.result.validatorRegistrationTxs[0].data; + const depositData = response.result.depositData[0]; + const sharesData = response.result.encryptedShares[0].sharesData; + await updateState(uuid, "validator_creation_confirmed", store, { + registerValidatorData, + depositData, + sharesData, + }); + log(`Validator created using uuid: ${uuid} is ready`); + log(`Primary key: ${depositData.pubkey}`); + log(`signature: ${depositData.signature}`); + log(`depositDataRoot: ${depositData.depositDataRoot}`); + log(`sharesData: ${sharesData}`); + return true; + } else { + log( + `Validator created using uuid: ${uuid} not yet ready. State: ${response.result.status}` + ); + return false; + } + }; + + let counter = 0; + const attempts = 20; + while (true) { + if (await doConfirmation()) { + break; + } + counter++; + + if (counter > attempts) { + log( + `Tried validating the validator formation with ${attempts} but failed` + ); + await clearState( + uuid, + store, + `Too may attempts(${attempts}) to waiting for validator to be ready.` + ); + break; + } + await sleep(3000); + } +}; + +async function exitValidator({ publicKey, operatorIds }) { + const signer = await getSigner(); + + const strategy = await resolveContract( + "NativeStakingSSVStrategyProxy", + "NativeStakingSSVStrategy" + ); + + log(`About to exit validator`); + const tx = await strategy + .connect(signer) + .exitSsvValidator(publicKey, operatorIds); + await logTxDetails(tx, "exitSsvValidator"); +} + +async function removeValidator({ publicKey, operatorIds }) { + const signer = await getSigner(); + + const strategy = await resolveContract( + "NativeStakingSSVStrategyProxy", + "NativeStakingSSVStrategy" + ); + + // Cluster details + const { cluster } = await getClusterInfo({ + chainId: hre.network.config.chainId, + ssvNetwork: hre.network.name.toUpperCase(), + operatorIds, + ownerAddress: strategy.address, + }); + + log(`About to exit validator`); + const tx = await strategy + .connect(signer) + .removeSsvValidator(publicKey, operatorIds, cluster); + await logTxDetails(tx, "removeSsvValidator"); +} + +module.exports = { + operateValidators, + removeValidator, + exitValidator, +}; diff --git a/contracts/tasks/vault.js b/contracts/tasks/vault.js index 0c8788727c..f31db84369 100644 --- a/contracts/tasks/vault.js +++ b/contracts/tasks/vault.js @@ -1,7 +1,7 @@ const { parseUnits } = require("ethers/lib/utils"); const addresses = require("../utils/addresses"); -const { resolveAsset } = require("../utils/assets"); +const { resolveAsset } = require("../utils/resolvers"); const { getSigner } = require("../utils/signers"); const { logTxDetails } = require("../utils/txLogger"); const { ethereumAddress } = require("../utils/regex"); @@ -26,8 +26,7 @@ async function getContract(hre, symbol) { }; } -async function allocate(taskArguments, hre) { - const symbol = taskArguments.symbol; +async function allocate({ symbol }, hre) { const signer = await getSigner(); const { vault } = await getContract(hre, symbol); @@ -39,8 +38,7 @@ async function allocate(taskArguments, hre) { await logTxDetails(tx, "allocate"); } -async function rebase(taskArguments, hre) { - const symbol = taskArguments.symbol; +async function rebase({ symbol }, hre) { const signer = await getSigner(); const { vault } = await getContract(hre, symbol); @@ -55,7 +53,7 @@ async function rebase(taskArguments, hre) { /** * Artificially generate yield on the vault by sending it USDT. */ -async function yieldTask(taskArguments, hre) { +async function yieldTask(_, hre) { const usdtAbi = require("../test/abi/usdt.json").abi; const { ousdUnitsFormat, @@ -106,12 +104,10 @@ async function yieldTask(taskArguments, hre) { /** * Call the Vault's admin pauseCapital method. */ -async function capital(taskArguments, hre) { - const symbol = taskArguments.symbol; +async function capital({ symbol, pause }, hre) { const { isMainnet } = require("../test/helpers"); const { proposeArgs } = require("../utils/governor"); - const pause = taskArguments.pause; log("Setting Vault capitalPause to", pause); const sGovernor = await getSigner(); @@ -137,8 +133,7 @@ async function capital(taskArguments, hre) { } } -async function mint(taskArguments, hre) { - const { amount, asset, symbol, min } = taskArguments; +async function mint({ amount, asset, symbol, min }, hre) { const signer = await getSigner(); const { vault } = await getContract(hre, symbol); @@ -156,8 +151,7 @@ async function mint(taskArguments, hre) { await logTxDetails(tx, "mint"); } -async function redeem(taskArguments, hre) { - const { amount, min, symbol } = taskArguments; +async function redeem({ amount, min, symbol }, hre) { const signer = await getSigner(); const { vault } = await getContract(hre, symbol); @@ -170,8 +164,7 @@ async function redeem(taskArguments, hre) { await logTxDetails(tx, "redeem"); } -async function redeemAll(taskArguments, hre) { - const { min, symbol } = taskArguments; +async function redeemAll({ min, symbol }, hre) { const signer = await getSigner(); const { vault } = await getContract(hre, symbol); @@ -231,8 +224,7 @@ async function resolveAmounts(amounts, assetContracts) { return amountUnits; } -async function depositToStrategy(taskArguments, hre) { - const { amounts, assets, symbol, strategy } = taskArguments; +async function depositToStrategy({ amounts, assets, symbol, strategy }, hre) { const signer = await getSigner(); const { vault } = await getContract(hre, symbol); @@ -252,8 +244,10 @@ async function depositToStrategy(taskArguments, hre) { await logTxDetails(tx, "depositToStrategy"); } -async function withdrawFromStrategy(taskArguments, hre) { - const { amounts, assets, symbol, strategy } = taskArguments; +async function withdrawFromStrategy( + { amounts, assets, symbol, strategy }, + hre +) { const signer = await getSigner(); const { vault } = await getContract(hre, symbol); @@ -273,8 +267,7 @@ async function withdrawFromStrategy(taskArguments, hre) { await logTxDetails(tx, "withdrawFromStrategy"); } -async function withdrawAllFromStrategy(taskArguments, hre) { - const { symbol, strategy } = taskArguments; +async function withdrawAllFromStrategy({ symbol, strategy }, hre) { const signer = await getSigner(); const { vault } = await getContract(hre, symbol); @@ -286,8 +279,7 @@ async function withdrawAllFromStrategy(taskArguments, hre) { await logTxDetails(tx, "withdrawAllFromStrategy"); } -async function withdrawAllFromStrategies(taskArguments, hre) { - const { symbol } = taskArguments; +async function withdrawAllFromStrategies({ symbol }, hre) { const signer = await getSigner(); const { vault } = await getContract(hre, symbol); diff --git a/contracts/test/_fixture.js b/contracts/test/_fixture.js index 4e3f722398..5b4881458c 100644 --- a/contracts/test/_fixture.js +++ b/contracts/test/_fixture.js @@ -99,8 +99,6 @@ const simpleOETHFixture = deployments.createFixture(async () => { addressContext = addresses.holesky; } - console.log("addressContext.WETH", addressContext.WETH); - weth = await ethers.getContractAt("IWETH9", addressContext.WETH); ssv = await ethers.getContractAt(erc20Abi, addressContext.SSV); @@ -362,6 +360,7 @@ const defaultFixture = deployments.createFixture(async () => { convexEthMetaStrategy, fluxStrategy, nativeStakingSSVStrategy, + nativeStakingFeeAccumulator, vaultValueChecker, oethVaultValueChecker; @@ -506,6 +505,14 @@ const defaultFixture = deployments.createFixture(async () => { nativeStakingStrategyProxy.address ); + const nativeStakingFeeAccumulatorProxy = await ethers.getContract( + "NativeStakingFeeAccumulatorProxy" + ); + nativeStakingFeeAccumulator = await ethers.getContractAt( + "FeeAccumulator", + nativeStakingFeeAccumulatorProxy.address + ); + vaultValueChecker = await ethers.getContract("VaultValueChecker"); oethVaultValueChecker = await ethers.getContract("OETHVaultValueChecker"); } else { @@ -760,6 +767,7 @@ const defaultFixture = deployments.createFixture(async () => { sDAI, fraxEthStrategy, nativeStakingSSVStrategy, + nativeStakingFeeAccumulator, frxEthRedeemStrategy, balancerREthStrategy, oethMorphoAaveStrategy, @@ -1581,10 +1589,29 @@ async function nativeStakingSSVStrategyFixture() { }); if (isFork) { - const { oethVault, weth, nativeStakingSSVStrategy, timelock } = fixture; + const { oethVault, weth, nativeStakingSSVStrategy, ssv, timelock } = + fixture; await oethVault .connect(timelock) .setAssetDefaultStrategy(weth.address, nativeStakingSSVStrategy.address); + + // The Defender Relayer + fixture.validatorRegistrator = await impersonateAndFund( + addresses.mainnet.validatorRegistrator + ); + + // Fund some SSV to the native staking strategy + const ssvWhale = await impersonateAndFund( + "0xf977814e90da44bfa03b6295a0616a897441acec" // Binance 8 + ); + await ssv + .connect(ssvWhale) + .transfer(nativeStakingSSVStrategy.address, oethUnits("100")); + + fixture.ssvNetwork = await ethers.getContractAt( + "ISSVNetwork", + addresses.mainnet.SSVNetwork + ); } else { const { governorAddr } = await getNamedAccounts(); const { oethVault, weth, nativeStakingSSVStrategy } = fixture; @@ -1595,8 +1622,6 @@ async function nativeStakingSSVStrategyFixture() { .connect(sGovernor) .approveStrategy(nativeStakingSSVStrategy.address); - log("nativeStakingSSVStrategy.address", nativeStakingSSVStrategy.address); - const fuseStartBn = ethers.utils.parseEther("21.6"); const fuseEndBn = ethers.utils.parseEther("25.6"); diff --git a/contracts/test/_global-hooks.js b/contracts/test/_global-hooks.js index 2c49a1b821..0ad9877e84 100644 --- a/contracts/test/_global-hooks.js +++ b/contracts/test/_global-hooks.js @@ -1,6 +1,6 @@ const mocha = require("mocha"); -const { isForkTest, isArbFork } = require("./helpers"); +const { isForkTest, isArbFork, isHoleskyFork } = require("./helpers"); const _chunkId = Number(process.env.CHUNK_ID); const _maxChunks = Number(process.env.MAX_CHUNKS); @@ -36,7 +36,8 @@ mocha.before(function () { // For fork tests, scrape out all unit tests. root.suites = root.suites.filter( (s) => - s.file.endsWith(".fork-test.js") == isForkTest && + s.file.endsWith(".fork-test.js") == isForkTest || + s.file.endsWith(".holesky-fork-test.js") == isHoleskyFork || s.file.endsWith(".arb.fork-test.js") == isArbFork ); diff --git a/contracts/test/behaviour/ssvStrategy.js b/contracts/test/behaviour/ssvStrategy.js new file mode 100644 index 0000000000..5aeec4864e --- /dev/null +++ b/contracts/test/behaviour/ssvStrategy.js @@ -0,0 +1,432 @@ +const { expect } = require("chai"); +const { AddressZero } = require("@ethersproject/constants"); +const { + setBalance, + setStorageAt, +} = require("@nomicfoundation/hardhat-network-helpers"); + +const { oethUnits } = require("../helpers"); +const addresses = require("../../utils/addresses"); +const { impersonateAndFund } = require("../../utils/signers"); +const { getClusterInfo } = require("../../utils/ssv"); +const { parseEther } = require("ethers/lib/utils"); + +/** + * + * @param {*} context a function that returns a fixture with the additional properties: + * @example + shouldBehaveLikeAnSsvStrategy(() => ({ + ...fixture, + addresses: [addresses.holesky|addresses.mainnet], + validatorRegistrator: await impersonateAndFund( + addresses.holesky.validatorRegistrator + ), + ssvNetwork: await ethers.getContractAt( + "ISSVNetwork", + addresses.holesky.SSVNetwork + ), + nativeStakingFeeAccumulator: await ethers.getContractAt( + "FeeAccumulator", + await fixture.nativeStakingSSVStrategy.FEE_ACCUMULATOR_ADDRESS() + ), + testValidator: { + publicKey: + "0xb279166b18ca9ced3e0a83385799ae33b27c6cd2ad2083b9b7c33c555d091933a09b1af9fb65c6c4d51c40ca931447a9", + operatorIds: [111, 119, 230, 252], + sharesData: + "0xb1edfddfdf70c8c56cfba3f00ae09815db2383c4faa328733df73dd4616492a58648d543642078c72e2bad60a22322d70ea44cc953c05aa0404681fb57498daa9cbd5c8cc98f736c75a8bf908f0eb98d6448b6778f35b1ce724fee8a1bb53f9ab60f29c5fc7c53e1577a27581b8aff689ac2fdeda72e9620f6991edb7779acef68ed2e6ea4ccfaecd00ccac09b7ed8b7abc72ea5c5469e1b5603c73fe3d054e074c88446c4e31abbc34ee309022524da5aacecb4aa83bf0ac658931813a402e4a4b1d9f83d54404b730e04e61dc82e872fa397e3a9ea249715c861ef0d4b309fdba762cd07f0506925a7a4e3e52d2c0e8f07ae01b8bb393df14c17648340c55e3a82564efb943de4033308d197d562c8bf377a589c87e4c7757afe5964ec92a616622138797c4a647dda550e3b94e3a6152cdda20d4a7b491218ab7df46a2eb9c3963811bf0555b272bf4ef5a8c0c2496e133d1cc34b01c7a5cb40d379e607d0bd7f0d8fcb965ab8d5c7634d80dbd3fac67227b53ec6fbd1a5207bfea8cb202ac88fef732328a2b717b6284af9f34a251e5ecf5eb744a4cf4df35abb423ca02556df957cd8bc645b83d497235b92f310996748c54a89106937cfcf182744ad423b104ca0a61a351d15aa9ae98093f64de31e14a7203304021ebbe2ee0e3f91e1641ff7da84396a83643101cfe67640c05467ffa8de458ebb4db0fcffe9210b72c50f8835cb636e1f5e7356092f15b29fb11761ce36a6601d599eb02d82aa02ce300a7e6c538ca72133036e5f3634c29b27c66964f65086e3f725d535f5e7d92f6a0b589a71caa7d0ca572c5192fe6ef5a4b44ad05cbb8c214a444a399b035263a1d2853bfe43b457873e700be599d3ff03532df1f52be09f6607acfc466f8bb4c4d98d74908c7394d516b738a6143a5456dc43a45f1f00a6515e11b5efc6f4dabfb3d967941ac159a8b6f7c464760c4770082b1d97600cabb1dc286d20c321e6bcb36138507915c399d8639d8a66143bff1f5a6d6cb63d0a8b560134dab42e9d23100c05e51104e068c0c76ecb5382d04e34375efea6467dfb096f6dc12b67609ea1d8310044ab8e80f75341b4aa3eb8dd5f465a3dc6b3f1dea8f25c77cdc34f0eb04247c1ac73bde467c8048cc4d57afefcb33de7520048baeaa9401fc175061881d5c60c89a4fe71cf6af8ed7ba3f6b5da42ef2ee5454f422ecf0b02d09f1ba77d35b56240232237810ffe4ff8e49c4a40a9aab7880ea91472440f30b22797f97d90a68e7904513a4267af47d988d96a17c5a2e90c4ad7c6fb56de8ba7e5488cfc16d1015963e2778e2b3def5ffdda1439cf8750b5823e31f4ba59f1eaf17c7ee98a69495a3c38c177175554b343c21f91a708c6313f146bbdde18b1fcead4e0d0274c8c1010c96f79b81060b850ab5c1da001fc908e45b84d57837fbbd272a4349261e500ce56560939cba45a58f2d0bdba3c6631e52d4e0b7a29ea50f14ed36c1ccb5fca6fdc45f881764b3ee39949ef5df255d9afdedfdf390409dadd31df7540d25174cf21a33dce1a2fd6097967be67267aa7e9353db71821bd89db0b3887eebc01cb64a4116edefac323fdde618a34d91545bab38f920e8e6f38b22a3a243b261fd56f0ec1ff6187b3ed42ddeeadf2c7a78c154d44ab332e293ca2b03e77ae1fe628378e336bc73149df4d7cbc86df73d04b9d35a9fe6a87a865f92337a8df10d5a5cf4dcc6cfba73bdd9b13d3b671acfc829b87f869ed42a48ced74099f92ac79721a79ac93d7c4d5e9be780fe1a78f807fd6a222fac05c3c8b9cd4182cb84617abaa72815b5dceec1d58b1278bf90498e4be3a456428866170046c", + signature: + "0xa450d596551c7fb7aca201e9a075b034d8da1ec7bf8806740ca53c0e8653465ed9cd26d6ce10290581586676eb0dd896022a243dc42179337c9c4c2a60969a11bb9e4a2dcf57a783daf880999f6db34d1e42163cb96287b3bb91b03361942b80", + depositDataRoot: + "0x3f327f69bb527386ff4c2f820e6e375fcc632b1b7ee826bd53d4d2807cfd6769", + }, + })); + */ + +const shouldBehaveLikeAnSsvStrategy = (context) => { + describe("Initial setup", function () { + it("Should verify the initial state", async () => { + const { nativeStakingSSVStrategy, addresses } = await context(); + await expect( + await nativeStakingSSVStrategy.WETH_TOKEN_ADDRESS() + ).to.equal(addresses.WETH, "Incorrect WETH address set"); + await expect(await nativeStakingSSVStrategy.SSV_TOKEN_ADDRESS()).to.equal( + addresses.SSV, + "Incorrect SSV Token address" + ); + await expect( + await nativeStakingSSVStrategy.SSV_NETWORK_ADDRESS() + ).to.equal(addresses.SSVNetwork, "Incorrect SSV Network address"); + await expect( + await nativeStakingSSVStrategy.BEACON_CHAIN_DEPOSIT_CONTRACT() + ).to.equal( + addresses.beaconChainDepositContract, + "Incorrect Beacon deposit contract" + ); + await expect(await nativeStakingSSVStrategy.VAULT_ADDRESS()).to.equal( + addresses.OETHVaultProxy, + "Incorrect OETH Vault address" + ); + await expect(await nativeStakingSSVStrategy.fuseIntervalStart()).to.equal( + oethUnits("21.6"), + "Incorrect fuse start" + ); + await expect(await nativeStakingSSVStrategy.fuseIntervalEnd()).to.equal( + oethUnits("25.6"), + "Incorrect fuse end" + ); + await expect( + await nativeStakingSSVStrategy.validatorRegistrator() + ).to.equal( + addresses.validatorRegistrator, + "Incorrect validator registrator" + ); + }); + }); + + describe("Deposit/Allocation", function () { + it("Should accept and handle WETH allocation", async () => { + const { oethVault, weth, domen, nativeStakingSSVStrategy } = + await context(); + const fakeVaultSigner = await impersonateAndFund(oethVault.address); + + const depositAmount = oethUnits("32"); + const wethBalanceBefore = await weth.balanceOf( + nativeStakingSSVStrategy.address + ); + const strategyBalanceBefore = await nativeStakingSSVStrategy.checkBalance( + weth.address + ); + + // Transfer some WETH to strategy + await weth + .connect(domen) + .transfer(nativeStakingSSVStrategy.address, depositAmount); + + // Call deposit by impersonating the Vault + const tx = await nativeStakingSSVStrategy + .connect(fakeVaultSigner) + .deposit(weth.address, depositAmount); + + expect(tx) + .to.emit(nativeStakingSSVStrategy, "Deposit") + .withArgs(weth.address, AddressZero, depositAmount); + + expect(await weth.balanceOf(nativeStakingSSVStrategy.address)).to.equal( + wethBalanceBefore.add(depositAmount), + "WETH not transferred" + ); + expect( + await nativeStakingSSVStrategy.checkBalance(weth.address) + ).to.equal( + strategyBalanceBefore.add(depositAmount), + "strategy checkBalance not increased" + ); + }); + }); + + describe("Validator operations", function () { + beforeEach(async () => { + const { weth, domen, nativeStakingSSVStrategy } = await context(); + + // Add 32 WETH to the strategy so it can be staked + await weth + .connect(domen) + .transfer(nativeStakingSSVStrategy.address, oethUnits("32")); + }); + + it("Should register and staked 32 ETH by validator registrator", async () => { + const { + weth, + nativeStakingSSVStrategy, + validatorRegistrator, + testValidator, + } = await context(); + + const strategyWethBalanceBefore = await weth.balanceOf( + nativeStakingSSVStrategy.address + ); + + const { cluster } = await getClusterInfo({ + ownerAddress: nativeStakingSSVStrategy.address, + operatorIds: testValidator.operatorIds, + chainId: 1, + ssvNetwork: addresses.SSVNetwork, + }); + + const stakeAmount = oethUnits("32"); + + // Register a new validator with the SSV Network + const regTx = await nativeStakingSSVStrategy + .connect(validatorRegistrator) + .registerSsvValidator( + testValidator.publicKey, + testValidator.operatorIds, + testValidator.sharesData, + stakeAmount, + cluster + ); + await expect(regTx) + .to.emit(nativeStakingSSVStrategy, "SSVValidatorRegistered") + .withArgs(testValidator.publicKey, testValidator.operatorIds); + + // Stake 32 ETH to the new validator + const stakeTx = await nativeStakingSSVStrategy + .connect(validatorRegistrator) + .stakeEth([ + { + pubkey: testValidator.publicKey, + signature: testValidator.signature, + depositDataRoot: testValidator.depositDataRoot, + }, + ]); + + await expect(stakeTx) + .to.emit(nativeStakingSSVStrategy, "ETHStaked") + .withNamedArgs({ + pubkey: testValidator.publicKey, + amount: stakeAmount, + }); + + expect(await weth.balanceOf(nativeStakingSSVStrategy.address)).to.equal( + strategyWethBalanceBefore.sub( + stakeAmount, + "strategy WETH not decreased" + ) + ); + }); + + it("Should exit and remove validator by validator registrator", async () => { + const { + nativeStakingSSVStrategy, + ssvNetwork, + validatorRegistrator, + addresses, + testValidator, + } = await context(); + + const { cluster } = await getClusterInfo({ + ownerAddress: nativeStakingSSVStrategy.address, + operatorIds: testValidator.operatorIds, + chainId: 1, + ssvNetwork: addresses.SSVNetwork, + }); + + const stakeAmount = oethUnits("32"); + + // Register a new validator with the SSV network + const regTx = await nativeStakingSSVStrategy + .connect(validatorRegistrator) + .registerSsvValidator( + testValidator.publicKey, + testValidator.operatorIds, + testValidator.sharesData, + stakeAmount, + cluster + ); + const regReceipt = await regTx.wait(); + const ValidatorAddedRawEvent = regReceipt.events.find( + (e) => e.address.toLowerCase() == ssvNetwork.address.toLowerCase() + ); + const ValidatorAddedEvent = ssvNetwork.interface.parseLog( + ValidatorAddedRawEvent + ); + const { cluster: newCluster } = ValidatorAddedEvent.args; + + // Stake 32 ETH to the new validator + await nativeStakingSSVStrategy.connect(validatorRegistrator).stakeEth([ + { + pubkey: testValidator.publicKey, + signature: testValidator.signature, + depositDataRoot: testValidator.depositDataRoot, + }, + ]); + + // exit validator from SSV network + const exitTx = await nativeStakingSSVStrategy + .connect(validatorRegistrator) + .exitSsvValidator(testValidator.publicKey, testValidator.operatorIds); + + await expect(exitTx) + .to.emit(nativeStakingSSVStrategy, "SSVValidatorExitInitiated") + .withArgs(testValidator.publicKey, testValidator.operatorIds); + + const removeTx = await nativeStakingSSVStrategy + .connect(validatorRegistrator) + .removeSsvValidator( + testValidator.publicKey, + testValidator.operatorIds, + newCluster + ); + + await expect(removeTx) + .to.emit(nativeStakingSSVStrategy, "SSVValidatorExitCompleted") + .withArgs(testValidator.publicKey, testValidator.operatorIds); + }); + }); + + describe("Accounting for ETH", function () { + let strategyBalanceBefore; + let consensusRewardsBefore; + let activeDepositedValidatorsBefore = 30000; + beforeEach(async () => { + const { nativeStakingSSVStrategy, validatorRegistrator, weth } = + await context(); + + // clear any ETH sitting in the strategy + await nativeStakingSSVStrategy + .connect(validatorRegistrator) + .doAccounting(); + + // Set the number validators to a high number + await setStorageAt( + nativeStakingSSVStrategy.address, + 52, // the storage slot + activeDepositedValidatorsBefore + ); + + strategyBalanceBefore = await nativeStakingSSVStrategy.checkBalance( + weth.address + ); + consensusRewardsBefore = + await nativeStakingSSVStrategy.consensusRewards(); + }); + + it("Should account for new consensus rewards", async () => { + const { nativeStakingSSVStrategy, validatorRegistrator, weth } = + await context(); + + const rewards = oethUnits("2"); + + // simulate consensus rewards + await setBalance( + nativeStakingSSVStrategy.address, + consensusRewardsBefore.add(rewards) + ); + + const tx = await nativeStakingSSVStrategy + .connect(validatorRegistrator) + .doAccounting(); + + await expect(tx) + .to.emit(nativeStakingSSVStrategy, "AccountingConsensusRewards") + .withArgs(rewards); + + // check balances after + expect( + await nativeStakingSSVStrategy.checkBalance(weth.address) + ).to.equal(strategyBalanceBefore, "checkBalance should not increase"); + expect(await nativeStakingSSVStrategy.consensusRewards()).to.equal( + consensusRewardsBefore.add(rewards), + "consensusRewards should increase" + ); + }); + it("Should account for withdrawals and consensus rewards", async () => { + const { + oethVault, + nativeStakingSSVStrategy, + validatorRegistrator, + weth, + } = await context(); + + const rewards = oethUnits("3"); + const withdrawals = oethUnits("64"); + const vaultWethBalanceBefore = await weth.balanceOf(oethVault.address); + + // simulate withdraw of 2 validators and consensus rewards + await setBalance( + nativeStakingSSVStrategy.address, + withdrawals.add(rewards) + ); + + const tx = await nativeStakingSSVStrategy + .connect(validatorRegistrator) + .doAccounting(); + + await expect(tx) + .to.emit(nativeStakingSSVStrategy, "AccountingFullyWithdrawnValidator") + .withArgs(2, activeDepositedValidatorsBefore - 2, withdrawals); + + await expect(tx) + .to.emit(nativeStakingSSVStrategy, "AccountingConsensusRewards") + .withArgs(rewards); + + // check balances after + expect( + await nativeStakingSSVStrategy.checkBalance(weth.address) + ).to.equal( + strategyBalanceBefore.sub(withdrawals), + "checkBalance should decrease" + ); + expect(await nativeStakingSSVStrategy.consensusRewards()).to.equal( + consensusRewardsBefore.add(rewards), + "consensusRewards should increase" + ); + expect( + await nativeStakingSSVStrategy.activeDepositedValidators() + ).to.equal( + activeDepositedValidatorsBefore - 2, + "active validators decreases" + ); + expect(await weth.balanceOf(oethVault.address)).to.equal( + vaultWethBalanceBefore.add(withdrawals, "WETH in vault should increase") + ); + }); + }); + + describe("Harvest", async function () { + it("Should account for new execution rewards", async () => { + const { + oethHarvester, + josh, + nativeStakingSSVStrategy, + nativeStakingFeeAccumulator, + oethDripper, + weth, + validatorRegistrator, + } = await context(); + const dripperWethBefore = await weth.balanceOf(oethDripper.address); + + const strategyBalanceBefore = await nativeStakingSSVStrategy.checkBalance( + weth.address + ); + + // add some ETH to the FeeAccumulator to simulate execution rewards + const executionRewards = parseEther("7"); + await setBalance(nativeStakingFeeAccumulator.address, executionRewards); + // simulate consensus rewards + const consensusRewards = parseEther("5"); + await setBalance(nativeStakingSSVStrategy.address, consensusRewards); + // account for the consensus rewards + + await nativeStakingSSVStrategy + .connect(validatorRegistrator) + .doAccounting(); + + // prettier-ignore + const tx = await oethHarvester + .connect(josh)["harvestAndSwap(address)"](nativeStakingSSVStrategy.address); + + await expect(tx) + .to.emit(oethHarvester, "RewardProceedsTransferred") + .withArgs( + weth.address, + AddressZero, + executionRewards.add(consensusRewards), + 0 + ); + + // check balances after + expect( + await nativeStakingSSVStrategy.checkBalance(weth.address) + ).to.equal(strategyBalanceBefore, "checkBalance should not increase"); + + expect(await weth.balanceOf(oethDripper.address)).to.equal( + dripperWethBefore.add(executionRewards).add(consensusRewards), + "Dripper WETH balance should increase" + ); + }); + }); +}; + +module.exports = { shouldBehaveLikeAnSsvStrategy }; diff --git a/contracts/test/helpers.js b/contracts/test/helpers.js index 5db24cc0b0..407d54dd60 100644 --- a/contracts/test/helpers.js +++ b/contracts/test/helpers.js @@ -258,13 +258,15 @@ const isHolesky = hre.network.name == "holesky"; const isExternalNet = isMainnet || isHolesky; const isTest = process.env.IS_TEST === "true"; const isSmokeTest = process.env.SMOKE_TEST === "true"; -const isMainnetOrFork = isMainnet || isFork; +const isMainnetOrFork = + isMainnet || (isFork && process.env.FORK_NETWORK_NAME == "mainnet"); const isForkTest = isFork && isTest; const isForkWithLocalNode = isFork && process.env.LOCAL_PROVIDER_URL; const isArbitrumOne = hre.network.name == "arbitrumOne"; const isTestnetSimplifiedDeploy = isHolesky; const isArbFork = isFork && process.env.FORK_NETWORK_NAME == "arbitrumOne"; const isHoleskyFork = isFork && process.env.FORK_NETWORK_NAME == "holesky"; +const isHoleskyOrFork = isHolesky || isHoleskyFork; const isArbitrumOneOrFork = isArbitrumOne || isArbFork; const isCI = process.env.GITHUB_ACTIONS; @@ -433,7 +435,7 @@ const getAssetAddresses = async (deployments) => { SSVNetwork: addresses.mainnet.SSVNetwork, beaconChainDepositContract: addresses.mainnet.beaconChainDepositContract, }; - } else if (isHolesky) { + } else if (isHoleskyOrFork) { return { WETH: addresses.holesky.WETH, SSV: addresses.holesky.SSV, @@ -793,6 +795,7 @@ module.exports = { isArbitrumOne, isHolesky, isHoleskyFork, + isHoleskyOrFork, isTestnetSimplifiedDeploy, isArbitrumOneOrFork, isArbFork, diff --git a/contracts/test/strategies/nativeSSVStaking.js b/contracts/test/strategies/nativeSSVStaking.js index 7eccc686c2..af6e2b4a3a 100644 --- a/contracts/test/strategies/nativeSSVStaking.js +++ b/contracts/test/strategies/nativeSSVStaking.js @@ -52,7 +52,7 @@ describe("Unit test: Native SSV Staking Strategy", function () { })); describe("Initial setup", function () { - it("Should not allow ETH to be sent to the strategy if not Fee Accumulator", async () => { + it("Should not allow ETH to be sent to the strategy if not FeeAccumulator or WETH", async () => { const { nativeStakingSSVStrategy, strategist } = fixture; const signer = nativeStakingSSVStrategy.provider.getSigner( diff --git a/contracts/test/strategies/nativeSsvStaking.fork-test.js b/contracts/test/strategies/nativeSsvStaking.fork-test.js new file mode 100644 index 0000000000..3652fa8955 --- /dev/null +++ b/contracts/test/strategies/nativeSsvStaking.fork-test.js @@ -0,0 +1,35 @@ +const { + createFixtureLoader, + nativeStakingSSVStrategyFixture, +} = require("./../_fixture"); + +const addresses = require("../../utils/addresses"); +const loadFixture = createFixtureLoader(nativeStakingSSVStrategyFixture); +const { shouldBehaveLikeAnSsvStrategy } = require("../behaviour/ssvStrategy"); + +describe("ForkTest: Native SSV Staking Strategy", function () { + this.timeout(0); + + let fixture; + beforeEach(async () => { + fixture = await loadFixture(); + }); + + shouldBehaveLikeAnSsvStrategy(async () => { + return { + ...fixture, + addresses: addresses.mainnet, + testValidator: { + publicKey: + "0xad9ade40c386259fe4161ec12d7746ab49a098a4760a279c56dc7e26b56fc4d985e74eeecdd2bc5a1decceb5174204f4", + operatorIds: [193, 196, 199, 202], + sharesData: + "0x8308e4b6ad536304f978077a0cd3685a98d5847bb1b05e0a4c5994ddf64ce48daa917f666d86f3125aac139a4fc7b07119ea2c7fc0fe5cfb316a5687dbddf621b0229e55230f0857d426697513ee2556d2c730595268358ebe8e16331bd2dd53acfd93e4e96c5fb510f78dc0f11e5097f83b2609a5711b233fa843935125dbbd90e43dc4f7d181221a42fcc02fe58aeb90fefb6a1d46faad099b6fa8e68351ff21f52d90a96bffeb33d1c0517bf39e413a441f1c290f1289021e9bd47146689ba139bccfaf7d6d1a6fba03c177d9ffca11f347b0f16a1cd8b1808a9b46ec0849ff45562a853ea137dfea3a0ed43ceac5805a993edd6b618cf7aa1441b2deeb2a7a573f0a44d9ed6bffb75573a91e9de2c21e198815d9b133ce7060ff339bf23b12af3c15f566b81842f307066205f09b40b4db045af881f5ca571289d1aa52555002544e8941b854b1b565b5e76c845c4b287a46890d6ad3e01185d2fb5485ecb136814a23378d37ff53244c1420af43db268f74bf0532dd235cb2afd49d1dce7158d1f51650bc32b790f29bdfc2bafc9990a55a15d005139c6ede259a6a9426400d67192ec697a8990c326bc63fe8a809515d0cc311059da2e333cb92331c45ac8b8d2e09a8cc4092016ade9f90a4b1a89a89f9da38818a5a77f84ae2aba340719dc6a01810ddfcd9e9cf9ebfab033363d2a58296cd1ab8e33ea4e04738111a3e2d80d34c601b0b49e95412cdd554a844f02a94f7f239e70cb72247c36218de79b5d0d73a7429cccf1999eca2611b1c486e8148451cac60bc60280764948f54100a39d9290c368a2ace60daa3ff1bf9dd7514afd02397c196b9cee8ef94478619a114cbebdf4475053857f2728c7621c5fb6739cbf8a15727c5d15a354e20ac054f31e51288a4f94a4215d00d23d2e5a82f745f2f15d6b147ecf817165913f2f72f492075de8f339efe54f163311f7de056c36a900949f7f026c17a96770edd29ba0301732bb83d218a0fb28d466858118e7240725ee74a45fd3acf8ca7310cb72f6cb3c6f8517b89984ad622ffeb39dad587d2e944d59fe849841fc5f09e9f1935cc59b10c795446eb18a2f87e6ee1a497fe0bb556164cd2d7b5c7cf5fdb758e8fc26711116bf59a08be68d2ddb9a97300d2ac43055877a0cc3be97c8b82ceb5dd59f6222c23d849dc7620ffca0393d685cb609059e0e8a76500c9c92d7878a3939c346897d10c6707d39bd10d0f546f6506b6b087dea16156478e11d9537d169d582ca26a04dceede25a38b5a4bf2e16db9db97bdb320f198632a0b60af8ebdf3e6a0bda19f34c9ddc7e437d3fef3da021cae41dd99d2898d825db9de51561dee2a5587fa75453609fff5aec3e949a34fd438f00ab6dbca03e385059003936db14c66d4fec38d6ba729051866c336c51c802507dc5b16b591a4905636736a05bbd0d39ba965de131abad34797e3521ff01612b1bd17aca6af61abf8bd24182a1e2848fc41819c0ce7065000747023db82de23eef601ed7cdaffd39b005e8bb8156f4986d9825e62cd2f13f8c0e33e5825e8d81730ef1a63dfd19af6afd08f9f102f403783dca89173456d9e60fb72b2c153bf0bb73bed799a15eb94923f7cadd9c9bc529a86051d8202b1af53ccb161179f9c4609084dd977091082fc14c20ff21efd70bb9ca56b0ea80c7fc16e2f1718c7b306944fa6c7572440c7d6035a22cea8858f64bb3b6d147a05743021ca1b79d71bac87888bb5fd343b1817a28dda336f1d640f8adae159020deba8d3e1e97ae0b9a4ba23112e59d93169a7b875fc878f66f13b2568ed326f9da7ba6c2bd08d37f5b0ef6bfe56febe20e366fa9d", + signature: + "0xadf71438600db72305e4a277554c06359d25e59480e2c4d5ea9d12d132088893d2df141c60a0857c63edc10b9800ac0e0e3e3dcd7b5fdfbcab8fbf377816811becc8be9420c17a725dff9dac6653230b9c5c04fd2ea19f9313fe943e1a562a18", + depositDataRoot: + "0x0d12c28849771f3f946d8d705a1f73683d97add9edaec5e6b30650cc03bc57d5", + }, + }; + }); +}); diff --git a/contracts/test/strategies/nativeSsvStaking.holesky-fork-test.js b/contracts/test/strategies/nativeSsvStaking.holesky-fork-test.js new file mode 100644 index 0000000000..f5447b1dcd --- /dev/null +++ b/contracts/test/strategies/nativeSsvStaking.holesky-fork-test.js @@ -0,0 +1,42 @@ +const { loadSimpleOETHFixture } = require("./../_fixture"); +const { shouldBehaveLikeAnSsvStrategy } = require("../behaviour/ssvStrategy"); +const addresses = require("../../utils/addresses"); +const { impersonateAndFund } = require("../../utils/signers"); + +describe("Holesky ForkTest: Native SSV Staking Strategy", function () { + this.timeout(0); + + let fixture; + beforeEach(async () => { + fixture = await loadSimpleOETHFixture(); + }); + + shouldBehaveLikeAnSsvStrategy(async () => { + return { + ...fixture, + addresses: addresses.holesky, + validatorRegistrator: await impersonateAndFund( + addresses.holesky.validatorRegistrator + ), + ssvNetwork: await ethers.getContractAt( + "ISSVNetwork", + addresses.holesky.SSVNetwork + ), + nativeStakingFeeAccumulator: await ethers.getContractAt( + "FeeAccumulator", + await fixture.nativeStakingSSVStrategy.FEE_ACCUMULATOR_ADDRESS() + ), + testValidator: { + publicKey: + "0xb279166b18ca9ced3e0a83385799ae33b27c6cd2ad2083b9b7c33c555d091933a09b1af9fb65c6c4d51c40ca931447a9", + operatorIds: [111, 119, 230, 252], + sharesData: + "0xb1edfddfdf70c8c56cfba3f00ae09815db2383c4faa328733df73dd4616492a58648d543642078c72e2bad60a22322d70ea44cc953c05aa0404681fb57498daa9cbd5c8cc98f736c75a8bf908f0eb98d6448b6778f35b1ce724fee8a1bb53f9ab60f29c5fc7c53e1577a27581b8aff689ac2fdeda72e9620f6991edb7779acef68ed2e6ea4ccfaecd00ccac09b7ed8b7abc72ea5c5469e1b5603c73fe3d054e074c88446c4e31abbc34ee309022524da5aacecb4aa83bf0ac658931813a402e4a4b1d9f83d54404b730e04e61dc82e872fa397e3a9ea249715c861ef0d4b309fdba762cd07f0506925a7a4e3e52d2c0e8f07ae01b8bb393df14c17648340c55e3a82564efb943de4033308d197d562c8bf377a589c87e4c7757afe5964ec92a616622138797c4a647dda550e3b94e3a6152cdda20d4a7b491218ab7df46a2eb9c3963811bf0555b272bf4ef5a8c0c2496e133d1cc34b01c7a5cb40d379e607d0bd7f0d8fcb965ab8d5c7634d80dbd3fac67227b53ec6fbd1a5207bfea8cb202ac88fef732328a2b717b6284af9f34a251e5ecf5eb744a4cf4df35abb423ca02556df957cd8bc645b83d497235b92f310996748c54a89106937cfcf182744ad423b104ca0a61a351d15aa9ae98093f64de31e14a7203304021ebbe2ee0e3f91e1641ff7da84396a83643101cfe67640c05467ffa8de458ebb4db0fcffe9210b72c50f8835cb636e1f5e7356092f15b29fb11761ce36a6601d599eb02d82aa02ce300a7e6c538ca72133036e5f3634c29b27c66964f65086e3f725d535f5e7d92f6a0b589a71caa7d0ca572c5192fe6ef5a4b44ad05cbb8c214a444a399b035263a1d2853bfe43b457873e700be599d3ff03532df1f52be09f6607acfc466f8bb4c4d98d74908c7394d516b738a6143a5456dc43a45f1f00a6515e11b5efc6f4dabfb3d967941ac159a8b6f7c464760c4770082b1d97600cabb1dc286d20c321e6bcb36138507915c399d8639d8a66143bff1f5a6d6cb63d0a8b560134dab42e9d23100c05e51104e068c0c76ecb5382d04e34375efea6467dfb096f6dc12b67609ea1d8310044ab8e80f75341b4aa3eb8dd5f465a3dc6b3f1dea8f25c77cdc34f0eb04247c1ac73bde467c8048cc4d57afefcb33de7520048baeaa9401fc175061881d5c60c89a4fe71cf6af8ed7ba3f6b5da42ef2ee5454f422ecf0b02d09f1ba77d35b56240232237810ffe4ff8e49c4a40a9aab7880ea91472440f30b22797f97d90a68e7904513a4267af47d988d96a17c5a2e90c4ad7c6fb56de8ba7e5488cfc16d1015963e2778e2b3def5ffdda1439cf8750b5823e31f4ba59f1eaf17c7ee98a69495a3c38c177175554b343c21f91a708c6313f146bbdde18b1fcead4e0d0274c8c1010c96f79b81060b850ab5c1da001fc908e45b84d57837fbbd272a4349261e500ce56560939cba45a58f2d0bdba3c6631e52d4e0b7a29ea50f14ed36c1ccb5fca6fdc45f881764b3ee39949ef5df255d9afdedfdf390409dadd31df7540d25174cf21a33dce1a2fd6097967be67267aa7e9353db71821bd89db0b3887eebc01cb64a4116edefac323fdde618a34d91545bab38f920e8e6f38b22a3a243b261fd56f0ec1ff6187b3ed42ddeeadf2c7a78c154d44ab332e293ca2b03e77ae1fe628378e336bc73149df4d7cbc86df73d04b9d35a9fe6a87a865f92337a8df10d5a5cf4dcc6cfba73bdd9b13d3b671acfc829b87f869ed42a48ced74099f92ac79721a79ac93d7c4d5e9be780fe1a78f807fd6a222fac05c3c8b9cd4182cb84617abaa72815b5dceec1d58b1278bf90498e4be3a456428866170046c", + signature: + "0xa450d596551c7fb7aca201e9a075b034d8da1ec7bf8806740ca53c0e8653465ed9cd26d6ce10290581586676eb0dd896022a243dc42179337c9c4c2a60969a11bb9e4a2dcf57a783daf880999f6db34d1e42163cb96287b3bb91b03361942b80", + depositDataRoot: + "0x3f327f69bb527386ff4c2f820e6e375fcc632b1b7ee826bd53d4d2807cfd6769", + }, + }; + }); +}); diff --git a/contracts/test/strategies/nativeSsvStaking.holesky.fork-test.js b/contracts/test/strategies/nativeSsvStaking.holesky.fork-test.js deleted file mode 100644 index ec838941c6..0000000000 --- a/contracts/test/strategies/nativeSsvStaking.holesky.fork-test.js +++ /dev/null @@ -1,147 +0,0 @@ -const { expect } = require("chai"); -const { utils, BigNumber } = require("ethers"); -const addresses = require("../../utils/addresses"); -const { units, oethUnits } = require("../helpers"); - -const { loadSimpleOETHFixture } = require("./../_fixture"); - -describe("Holesky ForkTest: Native SSV Staking Strategy", function () { - this.timeout(0); - - // Retry up to 3 times on CI - // this.retries(isCI ? 3 : 0); - - let fixture; - beforeEach(async () => { - fixture = await loadSimpleOETHFixture(); - }); - - describe("Initial setup", function () { - it("Should verify the initial state", async () => { - const { nativeStakingSSVStrategy } = fixture; - await expect( - await nativeStakingSSVStrategy.WETH_TOKEN_ADDRESS() - ).to.equal(addresses.holesky.WETH, "Incorrect WETH address set"); - await expect(await nativeStakingSSVStrategy.SSV_TOKEN_ADDRESS()).to.equal( - addresses.holesky.SSV, - "Incorrect SSV Token address" - ); - await expect( - await nativeStakingSSVStrategy.SSV_NETWORK_ADDRESS() - ).to.equal(addresses.holesky.SSVNetwork, "Incorrect SSV Network address"); - }); - - it("Should check that the fuse interval is configured correctly", async () => { - const { nativeStakingSSVStrategy } = fixture; - - await expect(utils.parseEther("21.6")).to.equal( - await nativeStakingSSVStrategy.fuseIntervalStart() - ); - await expect(utils.parseEther("25.6")).to.equal( - await nativeStakingSSVStrategy.fuseIntervalEnd() - ); - }); - }); - - describe("Deposit/Allocation register validators", function () { - it("Should mint using WETH and see balance on the strategy contract", async () => { - const { josh, weth } = fixture; - await mintTest(fixture, josh, weth, "32"); - }); - - it("Should mint using WETH and deposit to a validator", async () => { - const { josh, weth } = fixture; - await mintTest(fixture, josh, weth, "32"); - - await registerAndDepositTest(fixture); - }); - }); - - describe("Withdraw", function () {}); - - describe("Balance/Assets", function () {}); - - const registerAndDepositTest = async (fixture) => { - const { nativeStakingSSVStrategy, strategist } = fixture; - - await nativeStakingSSVStrategy - .connect(strategist) // TODO this will be a Defender relayer - .registerSsvValidator( - // pubkey - "0xb279166b18ca9ced3e0a83385799ae33b27c6cd2ad2083b9b7c33c555d091933a09b1af9fb65c6c4d51c40ca931447a9", - // operator ids - [111, 119, 230, 252], - // shares data - "0xb1edfddfdf70c8c56cfba3f00ae09815db2383c4faa328733df73dd4616492a58648d543642078c72e2bad60a22322d70ea44cc953c05aa0404681fb57498daa9cbd5c8cc98f736c75a8bf908f0eb98d6448b6778f35b1ce724fee8a1bb53f9ab60f29c5fc7c53e1577a27581b8aff689ac2fdeda72e9620f6991edb7779acef68ed2e6ea4ccfaecd00ccac09b7ed8b7abc72ea5c5469e1b5603c73fe3d054e074c88446c4e31abbc34ee309022524da5aacecb4aa83bf0ac658931813a402e4a4b1d9f83d54404b730e04e61dc82e872fa397e3a9ea249715c861ef0d4b309fdba762cd07f0506925a7a4e3e52d2c0e8f07ae01b8bb393df14c17648340c55e3a82564efb943de4033308d197d562c8bf377a589c87e4c7757afe5964ec92a616622138797c4a647dda550e3b94e3a6152cdda20d4a7b491218ab7df46a2eb9c3963811bf0555b272bf4ef5a8c0c2496e133d1cc34b01c7a5cb40d379e607d0bd7f0d8fcb965ab8d5c7634d80dbd3fac67227b53ec6fbd1a5207bfea8cb202ac88fef732328a2b717b6284af9f34a251e5ecf5eb744a4cf4df35abb423ca02556df957cd8bc645b83d497235b92f310996748c54a89106937cfcf182744ad423b104ca0a61a351d15aa9ae98093f64de31e14a7203304021ebbe2ee0e3f91e1641ff7da84396a83643101cfe67640c05467ffa8de458ebb4db0fcffe9210b72c50f8835cb636e1f5e7356092f15b29fb11761ce36a6601d599eb02d82aa02ce300a7e6c538ca72133036e5f3634c29b27c66964f65086e3f725d535f5e7d92f6a0b589a71caa7d0ca572c5192fe6ef5a4b44ad05cbb8c214a444a399b035263a1d2853bfe43b457873e700be599d3ff03532df1f52be09f6607acfc466f8bb4c4d98d74908c7394d516b738a6143a5456dc43a45f1f00a6515e11b5efc6f4dabfb3d967941ac159a8b6f7c464760c4770082b1d97600cabb1dc286d20c321e6bcb36138507915c399d8639d8a66143bff1f5a6d6cb63d0a8b560134dab42e9d23100c05e51104e068c0c76ecb5382d04e34375efea6467dfb096f6dc12b67609ea1d8310044ab8e80f75341b4aa3eb8dd5f465a3dc6b3f1dea8f25c77cdc34f0eb04247c1ac73bde467c8048cc4d57afefcb33de7520048baeaa9401fc175061881d5c60c89a4fe71cf6af8ed7ba3f6b5da42ef2ee5454f422ecf0b02d09f1ba77d35b56240232237810ffe4ff8e49c4a40a9aab7880ea91472440f30b22797f97d90a68e7904513a4267af47d988d96a17c5a2e90c4ad7c6fb56de8ba7e5488cfc16d1015963e2778e2b3def5ffdda1439cf8750b5823e31f4ba59f1eaf17c7ee98a69495a3c38c177175554b343c21f91a708c6313f146bbdde18b1fcead4e0d0274c8c1010c96f79b81060b850ab5c1da001fc908e45b84d57837fbbd272a4349261e500ce56560939cba45a58f2d0bdba3c6631e52d4e0b7a29ea50f14ed36c1ccb5fca6fdc45f881764b3ee39949ef5df255d9afdedfdf390409dadd31df7540d25174cf21a33dce1a2fd6097967be67267aa7e9353db71821bd89db0b3887eebc01cb64a4116edefac323fdde618a34d91545bab38f920e8e6f38b22a3a243b261fd56f0ec1ff6187b3ed42ddeeadf2c7a78c154d44ab332e293ca2b03e77ae1fe628378e336bc73149df4d7cbc86df73d04b9d35a9fe6a87a865f92337a8df10d5a5cf4dcc6cfba73bdd9b13d3b671acfc829b87f869ed42a48ced74099f92ac79721a79ac93d7c4d5e9be780fe1a78f807fd6a222fac05c3c8b9cd4182cb84617abaa72815b5dceec1d58b1278bf90498e4be3a456428866170046c", - // amount - BigNumber.from("1534241968000000000"), - // cluster tuple - [0, 0, 0, true, 0] - ); - - await nativeStakingSSVStrategy - .connect(strategist) // TODO this will be a Defender relayer - .stakeEth([ - [ - //pubkey - "0xb279166b18ca9ced3e0a83385799ae33b27c6cd2ad2083b9b7c33c555d091933a09b1af9fb65c6c4d51c40ca931447a9", - //signature - "0xa450d596551c7fb7aca201e9a075b034d8da1ec7bf8806740ca53c0e8653465ed9cd26d6ce10290581586676eb0dd896022a243dc42179337c9c4c2a60969a11bb9e4a2dcf57a783daf880999f6db34d1e42163cb96287b3bb91b03361942b80", - //depositDataRoot - "0x3f327f69bb527386ff4c2f820e6e375fcc632b1b7ee826bd53d4d2807cfd6769", - ], - ]); - }; - - const mintTest = async (fixture, user, asset, amount = "32") => { - const { oethVault, oeth, weth, nativeStakingSSVStrategy, strategist } = - fixture; - - const unitAmount = await units(amount, asset); - - if (asset.address != weth.address) { - const tx = oethVault.connect(user).mint(asset.address, unitAmount, "0"); - await expect(tx).to.be.revertedWith("Unsupported asset for minting"); - return; - } - - await oethVault.connect(user).allocate(); - await oethVault.connect(user).rebase(); - - const currentSupply = await oeth.totalSupply(); - const currentBalance = await oeth.connect(user).balanceOf(user.address); - const currentStrategyBalance = await nativeStakingSSVStrategy.checkBalance( - weth.address - ); - - // Mint OETH w/ asset - await oethVault.connect(user).mint(asset.address, unitAmount, 0); - - await oethVault - .connect(strategist) - .depositToStrategy( - nativeStakingSSVStrategy.address, - [asset.address], - [unitAmount] - ); - - await oethVault.connect(user).allocate(); - - const newBalance = await oeth.connect(user).balanceOf(user.address); - const newSupply = await oeth.totalSupply(); - const newStrategyBalance = await nativeStakingSSVStrategy.checkBalance( - weth.address - ); - - const balanceDiff = newBalance.sub(currentBalance); - // Ensure user has correct balance (w/ 1% slippage tolerance) - expect(balanceDiff).to.approxEqualTolerance(oethUnits(amount), 2); - - // Supply checks - const supplyDiff = newSupply.sub(currentSupply); - const oethUnitAmount = oethUnits(amount); - expect(supplyDiff).to.approxEqualTolerance(oethUnitAmount, 1); - - expect(unitAmount).to.equal(newStrategyBalance.sub(currentStrategyBalance)); - }; -}); diff --git a/contracts/test/vault/collateral-swaps.fork-test.js b/contracts/test/vault/collateral-swaps.fork-test.js index 85c40b83f3..f9ced0127d 100644 --- a/contracts/test/vault/collateral-swaps.fork-test.js +++ b/contracts/test/vault/collateral-swaps.fork-test.js @@ -10,7 +10,7 @@ const { } = require("../_fixture"); const { getIInchSwapData, recodeSwapData } = require("../../utils/1Inch"); const { decimalsFor, isCI } = require("../helpers"); -const { resolveAsset } = require("../../utils/assets"); +const { resolveAsset } = require("../../utils/resolvers"); const log = require("../../utils/logger")("test:fork:swaps"); diff --git a/contracts/utils/addresses.js b/contracts/utils/addresses.js index 6bba45a601..aa6885e32e 100644 --- a/contracts/utils/addresses.js +++ b/contracts/utils/addresses.js @@ -184,7 +184,7 @@ addresses.mainnet.OldTimelock = "0x72426BA137DEC62657306b12B1E869d43FeC6eC7"; // OETH addresses.mainnet.OETHProxy = "0x856c4Efb76C1D1AE02e20CEB03A2A6a08b0b8dC3"; addresses.mainnet.WOETHProxy = "0xDcEe70654261AF21C44c093C300eD3Bb97b78192"; -addresses.mainnet.OETHVaultProxy = "0x39254033945aa2e4809cc2977e7087bee48bd7ab"; +addresses.mainnet.OETHVaultProxy = "0x39254033945AA2E4809Cc2977E7087BEE48bd7Ab"; addresses.mainnet.OETHZapper = "0x9858e47BCbBe6fBAC040519B02d7cd4B2C470C66"; addresses.mainnet.FraxETHStrategy = "0x3ff8654d633d4ea0fae24c52aec73b4a20d0d0e5"; @@ -251,7 +251,11 @@ addresses.mainnet.CurveCVXPool = "0xB576491F1E6e5E62f1d8F26062Ee822B40B0E0d4"; addresses.mainnet.SSV = "0x9D65fF81a3c488d585bBfb0Bfe3c7707c7917f54"; addresses.mainnet.SSVNetwork = "0xDD9BC35aE942eF0cFa76930954a156B3fF30a4E1"; addresses.mainnet.beaconChainDepositContract = - "0x00000000219ab540356cbb839cbe05303d7705fa"; + "0x00000000219ab540356cBB839Cbe05303d7705Fa"; + +// Native Staking Strategy +addresses.mainnet.validatorRegistrator = + "0x4b91827516f79d6F6a1F292eD99671663b09169a"; // Arbitrum One addresses.arbitrumOne = {}; @@ -266,4 +270,7 @@ addresses.holesky.SSVNetwork = "0x38A4794cCEd47d3baf7370CcC43B560D3a1beEFA"; addresses.holesky.beaconChainDepositContract = "0x4242424242424242424242424242424242424242"; +addresses.holesky.OETHVaultProxy = "0x19d2bAaBA949eFfa163bFB9efB53ed8701aA5dD9"; +addresses.holesky.validatorRegistrator = + "0x1b94CA50D3Ad9f8368851F8526132272d1a5028C"; module.exports = addresses; diff --git a/contracts/utils/assets.js b/contracts/utils/assets.js deleted file mode 100644 index fae2b42c42..0000000000 --- a/contracts/utils/assets.js +++ /dev/null @@ -1,37 +0,0 @@ -const addresses = require("../utils/addresses"); - -const log = require("../utils/logger")("task:assets"); - -/** - * Resolves a token symbol to a ERC20 token contract. - * @param {string} symbol token symbol of the asset. eg OUSD, USDT, stETH, CRV... - */ -const resolveAsset = async (symbol) => { - // dynamically load in function so this function can be used by tasks - // if put outside this function, the following error occurs: - // "Hardhat can't be initialized while its config is being defined" - const hre = require("hardhat"); - const isFork = process.env.FORK === "true"; - const isMainnet = hre.network.name === "mainnet"; - const isMainnetOrFork = isMainnet || isFork; - - if (isMainnetOrFork) { - const assetAddr = - addresses.mainnet[symbol] || addresses.mainnet[symbol + "Proxy"]; - if (!assetAddr) { - throw Error(`Failed to resolve symbol "${symbol}" to an address`); - } - log(`Resolved ${symbol} to ${assetAddr}`); - const asset = await ethers.getContractAt("IERC20Metadata", assetAddr); - return asset; - } - const asset = await ethers.getContract("Mock" + symbol); - if (!asset) { - throw Error(`Failed to resolve symbol "${symbol}" to a mock contract`); - } - return asset; -}; - -module.exports = { - resolveAsset, -}; diff --git a/contracts/utils/resolvers.js b/contracts/utils/resolvers.js new file mode 100644 index 0000000000..e1bc803f06 --- /dev/null +++ b/contracts/utils/resolvers.js @@ -0,0 +1,84 @@ +const addresses = require("./addresses"); +const { ethereumAddress } = require("./regex"); + +const log = require("./logger")("task:assets"); + +/** + * Resolves a token symbol to a ERC20 token contract. + * @param {string} symbol token symbol of the asset. eg OUSD, USDT, stETH, CRV... + */ +const resolveAsset = async (symbol) => { + // dynamically load in function so this function can be used by tasks + // if put outside this function, the following error occurs: + // "Hardhat can't be initialized while its config is being defined" + const hre = require("hardhat"); + + if (hre.network.name != "hardhat") { + const assetAddr = + addresses[hre.network.name][symbol + "Proxy"] || + addresses[hre.network.name][symbol]; + if (!assetAddr) { + throw Error( + `Failed to resolve symbol "${symbol}" to an address on the "${hre.network.name}" network` + ); + } + log(`Resolved ${symbol} to ${assetAddr}`); + const asset = await ethers.getContractAt("IERC20Metadata", assetAddr); + return asset; + } + const asset = await ethers.getContract("Mock" + symbol); + if (!asset) { + throw Error(`Failed to resolve symbol "${symbol}" to a mock contract`); + } + return asset; +}; + +/** + * Returns a contract instance. + * @param {string} proxy Address or name of the proxy contract or contract name if no proxy. eg OETHVaultProxy or OETHZapper + * @param {string} [abiName=proxy] ABI name. Will default to proxy is not used. eg VaultAdmin, VaultCore, Governable or IERC20Metadata + * @returns + */ +const resolveContract = async (proxy, abiName) => { + // dynamically load in function so this function can be used by tasks + // if put outside this function, the following error occurs: + // "Hardhat can't be initialized while its config is being defined" + const hre = require("hardhat"); + + // If proxy is an address + if (proxy.match(ethereumAddress)) { + if (!abiName) { + throw Error(`Must pass an ABI name if the proxy is an address`); + } + const contract = await ethers.getContractAt(abiName, proxy); + if (!contract) { + throw Error(`Failed find ABI for "${abiName}"`); + } + return contract; + } + + const proxyContract = await ethers.getContract(proxy); + if (!proxyContract) { + throw Error( + `Failed find proxy "${proxy}" on the ${hre.network.name} network` + ); + } + log( + `Resolved proxy ${proxy} on the ${hre.network.name} network to ${proxyContract.address}` + ); + + if (abiName) { + const contract = await ethers.getContractAt(abiName, proxyContract.address); + if (!contract) { + throw Error(`Failed find ABI for "${abiName}"`); + } + return contract; + } + + return proxy; +}; + +module.exports = { + resolveAsset, + resolveContract, +}; diff --git a/contracts/utils/signers.js b/contracts/utils/signers.js index dd16417d4b..3ec192d55c 100644 --- a/contracts/utils/signers.js +++ b/contracts/utils/signers.js @@ -1,4 +1,4 @@ -const { Wallet } = require("ethers").utils; +const { Wallet } = require("ethers"); const { Defender } = require("@openzeppelin/defender-sdk"); const { ethereumAddress, privateKey } = require("./regex"); @@ -103,7 +103,7 @@ async function impersonateAndFund(account, amount = "100") { const signer = await impersonateAccount(account); log(`Funding account ${account} with ${amount} ETH`); - await hardhatSetBalance(account, amount); + await hardhatSetBalance(account, amount.toString()); return signer; } diff --git a/contracts/utils/ssv.js b/contracts/utils/ssv.js new file mode 100644 index 0000000000..c756c82d13 --- /dev/null +++ b/contracts/utils/ssv.js @@ -0,0 +1,172 @@ +const { ClusterScanner, NonceScanner } = require("ssv-scanner"); +const { SSVKeys, KeyShares, KeySharesItem } = require("ssv-keys"); +const path = require("path"); +const fsp = require("fs").promises; + +const { isForkWithLocalNode } = require("../test/helpers"); + +const log = require("../utils/logger")("utils:ssv"); + +const splitValidatorKey = async ({ + keystorelocation, + keystorepass, + operatorIds, + operatorkeys, + ownerAddress, + chainId, + ssvNetwork, +}) => { + const operatorKeys = operatorkeys.split("."); + const keystoreLocation = path.join(__dirname, "..", "..", keystorelocation); + const nextNonce = await getClusterNonce({ + ownerAddress, + operatorIds, + chainId, + ssvNetwork, + }); + + log(`Reading keystore location: ${keystoreLocation}`); + log(`For operatorIds: ${operatorIds}`); + log( + `Next SSV register validator nonce for owner ${ownerAddress}: ${nextNonce}` + ); + // TODO: 30+ start and end character of operators are the same. how to represent this? + log( + "Operator keys: ", + operatorKeys.map((key) => `${key.slice(0, 10)}...${key.slice(-10)}`) + ); + + const keystoreJson = require(keystoreLocation); + + // 1. Initialize SSVKeys SDK and read the keystore file + const ssvKeys = new SSVKeys(); + const { publicKey, privateKey } = await ssvKeys.extractKeys( + keystoreJson, + keystorepass + ); + + const operators = operatorKeys.map((operatorKey, index) => ({ + id: operatorIds[index], + operatorKey, + })); + + // 2. Build shares from operator IDs and public keys + const encryptedShares = await ssvKeys.buildShares(privateKey, operators); + const keySharesItem = new KeySharesItem(); + await keySharesItem.update({ operators }); + await keySharesItem.update({ + ownerAddress: ownerAddress, + ownerNonce: nextNonce, + publicKey, + }); + + // 3. Build final web3 transaction payload and update keyshares file with payload data + await keySharesItem.buildPayload( + { + publicKey, + operators, + encryptedShares, + }, + { + ownerAddress: ownerAddress, + ownerNonce: nextNonce, + privateKey, + } + ); + + const keyShares = new KeyShares(); + keyShares.add(keySharesItem); + + const keystoreFilePath = path.join( + __dirname, + "..", + "..", + "validator_key_data", + "keyshares_data", + `${publicKey.slice(0, 10)}_keyshares.json` + ); + log(`Saving distributed validator shares_data into: ${keystoreFilePath}`); + await fsp.writeFile(keystoreFilePath, keyShares.toJson(), { + encoding: "utf-8", + }); +}; + +const getClusterInfo = async ({ + ownerAddress, + operatorIds, + chainId, + ssvNetwork, +}) => { + const ssvNetworkName = chainId === 1 ? "MAINNET" : "HOLESKY"; + log(`SSV network: ${ssvNetworkName}`); + const providerUrl = isForkWithLocalNode + ? "http://localhost:8545/" + : process.env.PROVIDER_URL; + log(`Provider URL: ${providerUrl}`); + + const params = { + nodeUrl: providerUrl, // this can be an Infura, or Alchemy node, necessary to query the blockchain + contractAddress: ssvNetwork, // this is the address of SSV smart contract + ownerAddress, // this is the wallet address of the cluster owner + /* Based on the network they fetch contract ABIs. See code: https://github.com/bloxapp/ssv-scanner/blob/v1.0.3/src/lib/contract.provider.ts#L16-L22 + * and the ABIs are fetched from here: https://github.com/bloxapp/ssv-scanner/tree/v1.0.3/src/shared/abi + * + * Prater seems to work for Goerli at the moment + */ + network: ssvNetworkName, + operatorIds, // this is a list of operator IDs chosen by the owner for their cluster + }; + + // ClusterScanner is initialized with the given parameters + const clusterScanner = new ClusterScanner(params); + // and when run, it returns the Cluster Snapshot + const result = await clusterScanner.run(params.operatorIds); + const cluster = { + block: result.payload.Block, + snapshot: result.cluster, + cluster: Object.values(result.cluster), + }; + log(`Cluster info ${JSON.stringify(cluster)}`); + return cluster; +}; + +const getClusterNonce = async ({ + ownerAddress, + operatorIds, + chainId, + ssvNetwork, +}) => { + const ssvNetworkName = chainId === 1 ? "MAINNET" : "HOLESKY"; + const providerUrl = process.env.PROVIDER_URL; + + const params = { + nodeUrl: providerUrl, // this can be an Infura, or Alchemy node, necessary to query the blockchain + contractAddress: ssvNetwork, // this is the address of SSV smart contract + ownerAddress, // this is the wallet address of the cluster owner + /* Based on the network they fetch contract ABIs. See code: https://github.com/bloxapp/ssv-scanner/blob/v1.0.3/src/lib/contract.provider.ts#L16-L22 + * and the ABIs are fetched from here: https://github.com/bloxapp/ssv-scanner/tree/v1.0.3/src/shared/abi + * + * Prater seems to work for Goerli at the moment + */ + network: ssvNetworkName, + operatorIds, // this is a list of operator IDs chosen by the owner for their cluster + }; + + const nonceScanner = new NonceScanner(params); + const nextNonce = await nonceScanner.run(); + return nextNonce; +}; + +const printClusterInfo = async (options) => { + const cluster = await getClusterInfo(options); + const nextNonce = await getClusterNonce(options); + console.log(`block ${cluster.block}`); + console.log(`Cluster: ${JSON.stringify(cluster.snapshot, null, " ")}`); + console.log("Next Nonce:", nextNonce); +}; + +module.exports = { + printClusterInfo, + getClusterInfo, + splitValidatorKey, +}; diff --git a/contracts/yarn.lock b/contracts/yarn.lock index df633b97f9..2ffb02816b 100644 --- a/contracts/yarn.lock +++ b/contracts/yarn.lock @@ -233,7 +233,7 @@ crc-32 "^1.2.0" ethereumjs-util "^7.1.3" -"@ethereumjs/common@2.6.5", "@ethereumjs/common@^2.6.0", "@ethereumjs/common@^2.6.4", "@ethereumjs/common@^2.6.5": +"@ethereumjs/common@2.6.5", "@ethereumjs/common@^2.5.0", "@ethereumjs/common@^2.6.0", "@ethereumjs/common@^2.6.4", "@ethereumjs/common@^2.6.5": version "2.6.5" resolved "https://registry.yarnpkg.com/@ethereumjs/common/-/common-2.6.5.tgz#0a75a22a046272579d91919cb12d84f2756e8d30" integrity sha512-lRyVQOeCDaIVtgfbowla32pzeDv2Obr8oR8Put5RdUBNRGr1VGPGQNGP6elWIpgK3YdpzqTOh4GyUGOureVeeA== @@ -265,7 +265,7 @@ "@ethereumjs/common" "^2.6.0" ethereumjs-util "^7.1.3" -"@ethereumjs/tx@3.5.2", "@ethereumjs/tx@^3.4.0", "@ethereumjs/tx@^3.5.2": +"@ethereumjs/tx@3.5.2", "@ethereumjs/tx@^3.3.2", "@ethereumjs/tx@^3.4.0", "@ethereumjs/tx@^3.5.2": version "3.5.2" resolved "https://registry.yarnpkg.com/@ethereumjs/tx/-/tx-3.5.2.tgz#197b9b6299582ad84f9527ca961466fce2296c1c" integrity sha512-gQDNJWKrSDGu2w7w0PzVXVBNMzb7wwdDOmOqczmhNjqFxFuIbhVJDwiGEnxFNC2/b8ifcZzY7MLcluizohRzNw== @@ -300,6 +300,21 @@ merkle-patricia-tree "^4.2.2" rustbn.js "~0.2.0" +"@ethersproject/abi@5.0.7": + version "5.0.7" + resolved "https://registry.yarnpkg.com/@ethersproject/abi/-/abi-5.0.7.tgz#79e52452bd3ca2956d0e1c964207a58ad1a0ee7b" + integrity sha512-Cqktk+hSIckwP/W8O47Eef60VwmoSC/L3lY0+dIBhQPCNn9E4V7rwmm2aFrNRRDJfFlGuZ1khkQUOc3oBX+niw== + dependencies: + "@ethersproject/address" "^5.0.4" + "@ethersproject/bignumber" "^5.0.7" + "@ethersproject/bytes" "^5.0.4" + "@ethersproject/constants" "^5.0.4" + "@ethersproject/hash" "^5.0.4" + "@ethersproject/keccak256" "^5.0.3" + "@ethersproject/logger" "^5.0.5" + "@ethersproject/properties" "^5.0.3" + "@ethersproject/strings" "^5.0.4" + "@ethersproject/abi@5.7.0", "@ethersproject/abi@^5.0.0-beta.146", "@ethersproject/abi@^5.0.9", "@ethersproject/abi@^5.1.2", "@ethersproject/abi@^5.6.3", "@ethersproject/abi@^5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/abi/-/abi-5.7.0.tgz#b3f3e045bbbeed1af3947335c247ad625a44e449" @@ -339,7 +354,7 @@ "@ethersproject/logger" "^5.7.0" "@ethersproject/properties" "^5.7.0" -"@ethersproject/address@5.7.0", "@ethersproject/address@^5.0.2", "@ethersproject/address@^5.7.0": +"@ethersproject/address@5.7.0", "@ethersproject/address@^5.0.2", "@ethersproject/address@^5.0.4", "@ethersproject/address@^5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/address/-/address-5.7.0.tgz#19b56c4d74a3b0a46bfdbb6cfcc0a153fc697f37" integrity sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA== @@ -365,7 +380,7 @@ "@ethersproject/bytes" "^5.7.0" "@ethersproject/properties" "^5.7.0" -"@ethersproject/bignumber@5.7.0", "@ethersproject/bignumber@^5.7.0": +"@ethersproject/bignumber@5.7.0", "@ethersproject/bignumber@^5.0.7", "@ethersproject/bignumber@^5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/bignumber/-/bignumber-5.7.0.tgz#e2f03837f268ba655ffba03a57853e18a18dc9c2" integrity sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw== @@ -374,14 +389,14 @@ "@ethersproject/logger" "^5.7.0" bn.js "^5.2.1" -"@ethersproject/bytes@5.7.0", "@ethersproject/bytes@^5.7.0": +"@ethersproject/bytes@5.7.0", "@ethersproject/bytes@^5.0.4", "@ethersproject/bytes@^5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/bytes/-/bytes-5.7.0.tgz#a00f6ea8d7e7534d6d87f47188af1148d71f155d" integrity sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A== dependencies: "@ethersproject/logger" "^5.7.0" -"@ethersproject/constants@5.7.0", "@ethersproject/constants@^5.7.0": +"@ethersproject/constants@5.7.0", "@ethersproject/constants@^5.0.4", "@ethersproject/constants@^5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/constants/-/constants-5.7.0.tgz#df80a9705a7e08984161f09014ea012d1c75295e" integrity sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA== @@ -404,7 +419,7 @@ "@ethersproject/properties" "^5.7.0" "@ethersproject/transactions" "^5.7.0" -"@ethersproject/hash@5.7.0", "@ethersproject/hash@^5.7.0": +"@ethersproject/hash@5.7.0", "@ethersproject/hash@^5.0.4", "@ethersproject/hash@^5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/hash/-/hash-5.7.0.tgz#eb7aca84a588508369562e16e514b539ba5240a7" integrity sha512-qX5WrQfnah1EFnO5zJv1v46a8HW0+E5xuBBDTwMFZLuVTx0tbU2kkx15NqdjxecrLGatQN9FGQKpb1FKdHCt+g== @@ -456,7 +471,7 @@ aes-js "3.0.0" scrypt-js "3.0.1" -"@ethersproject/keccak256@5.7.0", "@ethersproject/keccak256@^5.7.0": +"@ethersproject/keccak256@5.7.0", "@ethersproject/keccak256@^5.0.3", "@ethersproject/keccak256@^5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/keccak256/-/keccak256-5.7.0.tgz#3186350c6e1cd6aba7940384ec7d6d9db01f335a" integrity sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg== @@ -464,7 +479,7 @@ "@ethersproject/bytes" "^5.7.0" js-sha3 "0.8.0" -"@ethersproject/logger@5.7.0", "@ethersproject/logger@^5.7.0": +"@ethersproject/logger@5.7.0", "@ethersproject/logger@^5.0.5", "@ethersproject/logger@^5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/logger/-/logger-5.7.0.tgz#6ce9ae168e74fecf287be17062b590852c311892" integrity sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig== @@ -484,7 +499,7 @@ "@ethersproject/bytes" "^5.7.0" "@ethersproject/sha2" "^5.7.0" -"@ethersproject/properties@5.7.0", "@ethersproject/properties@^5.7.0": +"@ethersproject/properties@5.7.0", "@ethersproject/properties@^5.0.3", "@ethersproject/properties@^5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/properties/-/properties-5.7.0.tgz#a6e12cb0439b878aaf470f1902a176033067ed30" integrity sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw== @@ -566,7 +581,7 @@ "@ethersproject/sha2" "^5.7.0" "@ethersproject/strings" "^5.7.0" -"@ethersproject/strings@5.7.0", "@ethersproject/strings@^5.7.0": +"@ethersproject/strings@5.7.0", "@ethersproject/strings@^5.0.4", "@ethersproject/strings@^5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/strings/-/strings-5.7.0.tgz#54c9d2a7c57ae8f1205c88a9d3a56471e14d5ed2" integrity sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg== @@ -575,7 +590,7 @@ "@ethersproject/constants" "^5.7.0" "@ethersproject/logger" "^5.7.0" -"@ethersproject/transactions@5.7.0", "@ethersproject/transactions@^5.6.2", "@ethersproject/transactions@^5.7.0": +"@ethersproject/transactions@5.7.0", "@ethersproject/transactions@^5.0.0-beta.135", "@ethersproject/transactions@^5.6.2", "@ethersproject/transactions@^5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/transactions/-/transactions-5.7.0.tgz#91318fc24063e057885a6af13fdb703e1f993d3b" integrity sha512-kmcNicCp1lp8qanMTC3RIikGgoJ80ztTyvtsFvCYpSCfkjhD0jZ2LOrnbcuxuToLIUYYf+4XwD1rP+B/erDIhQ== @@ -1322,6 +1337,11 @@ "@sentry/types" "5.30.0" tslib "^1.9.3" +"@sindresorhus/is@^0.14.0": + version "0.14.0" + resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea" + integrity sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ== + "@sindresorhus/is@^4.0.0", "@sindresorhus/is@^4.6.0": version "4.6.0" resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-4.6.0.tgz#3c7c9c46e678feefe7a2e5bb609d3dbd665ffb3f" @@ -1353,6 +1373,13 @@ dependencies: antlr4ts "^0.5.0-alpha.4" +"@szmarczak/http-timer@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-1.1.2.tgz#b1665e2c461a2cd92f4c1bbf50d5454de0d4b421" + integrity sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA== + dependencies: + defer-to-connect "^1.0.1" + "@szmarczak/http-timer@^4.0.5": version "4.0.6" resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-4.0.6.tgz#b4a914bb62e7c272d4e5989fe4440f812ab1d807" @@ -1394,7 +1421,7 @@ resolved "https://registry.yarnpkg.com/@types/abstract-leveldown/-/abstract-leveldown-7.2.1.tgz#bb16403c17754b0c4d5772d71d03b924a03d4c80" integrity sha512-YK8irIC+eMrrmtGx0H4ISn9GgzLd9dojZWJaMbjp1YHLl2VqqNFBNrL5Q3KjGf4VE3sf/4hmq6EhQZ7kZp1NoQ== -"@types/bn.js@^4.11.3": +"@types/bn.js@^4.11.3", "@types/bn.js@^4.11.5": version "4.11.6" resolved "https://registry.yarnpkg.com/@types/bn.js/-/bn.js-4.11.6.tgz#c306c70d9358aaea33cd4eda092a742b9505967c" integrity sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg== @@ -1523,6 +1550,11 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.55.tgz#c329cbd434c42164f846b909bd6f85b5537f6240" integrity sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ== +"@types/node@^15.12.2": + version "15.14.9" + resolved "https://registry.yarnpkg.com/@types/node/-/node-15.14.9.tgz#bc43c990c3c9be7281868bbc7b8fdd6e2b57adfa" + integrity sha512-qjd88DrCxupx/kJD5yQgZdcYKZKSIGBVDIBE1/LTGcNm3d2Np/jxojkdePDdfnBHJc5W7vSMpbJ1aB7p/Py69A== + "@types/node@^8.0.0": version "8.10.66" resolved "https://registry.yarnpkg.com/@types/node/-/node-8.10.66.tgz#dd035d409df322acc83dff62a602f12a5783bbb3" @@ -1572,6 +1604,23 @@ resolved "https://registry.yarnpkg.com/@types/seedrandom/-/seedrandom-3.0.1.tgz#1254750a4fec4aff2ebec088ccd0bb02e91fedb4" integrity sha512-giB9gzDeiCeloIXDgzFBCgjj1k4WxcDrZtGl6h1IqmUPlxF+Nx8Ve+96QCyDZ/HseB/uvDsKbpib9hU5cU53pw== +"@types/underscore@^1.11.4": + version "1.11.15" + resolved "https://registry.yarnpkg.com/@types/underscore/-/underscore-1.11.15.tgz#29c776daecf6f1935da9adda17509686bf979947" + integrity sha512-HP38xE+GuWGlbSRq9WrZkousaQ7dragtZCruBVMi0oX1migFZavZ3OROKHSkNp/9ouq82zrWtZpg18jFnVN96g== + +"@types/yargs-parser@*": + version "21.0.3" + resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.3.tgz#815e30b786d2e8f0dcd85fd5bcf5e1a04d008f15" + integrity sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ== + +"@types/yargs@^17.0.12": + version "17.0.32" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.32.tgz#030774723a2f7faafebf645f4e5a48371dca6229" + integrity sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog== + dependencies: + "@types/yargs-parser" "*" + "@uniswap/lib@^4.0.1-alpha": version "4.0.1-alpha" resolved "https://registry.yarnpkg.com/@uniswap/lib/-/lib-4.0.1-alpha.tgz#2881008e55f075344675b3bca93f020b028fbd02" @@ -1710,6 +1759,11 @@ aes-js@3.0.0: resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-3.0.0.tgz#e21df10ad6c2053295bcbb8dab40b09dbea87e4d" integrity sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw== +aes-js@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-3.1.2.tgz#db9aabde85d5caabbfc0d4f2a4446960f627146a" + integrity sha512-e5pEa2kBnBOgR4Y/p20pskXI74UEz7de8ZGVo58asOtvSVG5YAbJeELPZxOmt+Bnz3rX753YKhfIn4X4l1PPRQ== + agent-base@6: version "6.0.2" resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" @@ -1901,6 +1955,15 @@ asap@~2.0.6: resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" integrity sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA== +asn1.js@^4.10.1: + version "4.10.1" + resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.10.1.tgz#b9c2bf5805f1e64aadeed6df3a2bfafb5a73f5a0" + integrity sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw== + dependencies: + bn.js "^4.0.0" + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + asn1@~0.2.3: version "0.2.6" resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.6.tgz#0d3a7bb6e64e02a90c0303b31f292868ea09a08d" @@ -1913,6 +1976,17 @@ assert-plus@1.0.0, assert-plus@^1.0.0: resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" integrity sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw== +assert@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/assert/-/assert-2.1.0.tgz#6d92a238d05dc02e7427c881fb8be81c8448b2dd" + integrity sha512-eLHpSK/Y4nhMJ07gDaAzoX/XAKS8PSaojml3M0DM4JpV1LAi5JOJ/p6H/XWrl8L+DzVEvVCW1z3vWAaB9oTsQw== + dependencies: + call-bind "^1.0.2" + is-nan "^1.3.2" + object-is "^1.1.5" + object.assign "^4.1.4" + util "^0.12.5" + assertion-error@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" @@ -1969,6 +2043,11 @@ asynckit@^0.4.0: resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== +atob@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" + integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== + available-typed-arrays@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7" @@ -2071,6 +2150,16 @@ blakejs@^1.1.0: resolved "https://registry.yarnpkg.com/blakejs/-/blakejs-1.2.1.tgz#5057e4206eadb4a97f7c0b6e197a505042fc3814" integrity sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ== +bls-eth-wasm@^1.0.4: + version "1.2.1" + resolved "https://registry.yarnpkg.com/bls-eth-wasm/-/bls-eth-wasm-1.2.1.tgz#85f165c17d8f16000f46695b56f72bf6af386825" + integrity sha512-hl4oBzZQmPGNb9Wt5GI+oEuHM6twGc5HzXCzNZMVLMMg+dltsOuvuioRyLolpDFbncC0BJbGPzP1ZTysUGkksw== + +bls-signatures@^0.2.5: + version "0.2.5" + resolved "https://registry.yarnpkg.com/bls-signatures/-/bls-signatures-0.2.5.tgz#7c285e3cb535f279d842e53d1f6e0c8ceda793d1" + integrity sha512-5TzQNCtR4zWE4lM08EOMIT8l3b4h8g5LNKu50fUYP1PnupaLGSLklAcTto4lnH7VXpyhsar+74L9wNJII4E/4Q== + bluebird@^3.5.0: version "3.7.2" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" @@ -2081,12 +2170,12 @@ bn.js@4.11.6: resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.6.tgz#53344adb14617a13f6e8dd2ce28905d1c0ba3215" integrity sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA== -bn.js@^4.0.0, bn.js@^4.11.0, bn.js@^4.11.1, bn.js@^4.11.6, bn.js@^4.11.8, bn.js@^4.11.9: +bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.11.0, bn.js@^4.11.1, bn.js@^4.11.6, bn.js@^4.11.8, bn.js@^4.11.9: version "4.12.0" resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== -bn.js@^5.1.2, bn.js@^5.2.0, bn.js@^5.2.1: +bn.js@^5.0.0, bn.js@^5.1.2, bn.js@^5.2.0, bn.js@^5.2.1: version "5.2.1" resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70" integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ== @@ -2151,7 +2240,7 @@ browser-stdout@1.3.1: resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== -browserify-aes@^1.2.0: +browserify-aes@^1.0.4, browserify-aes@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" integrity sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA== @@ -2163,6 +2252,49 @@ browserify-aes@^1.2.0: inherits "^2.0.1" safe-buffer "^5.0.1" +browserify-cipher@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.1.tgz#8d6474c1b870bfdabcd3bcfcc1934a10e94f15f0" + integrity sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w== + dependencies: + browserify-aes "^1.0.4" + browserify-des "^1.0.0" + evp_bytestokey "^1.0.0" + +browserify-des@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.2.tgz#3af4f1f59839403572f1c66204375f7a7f703e9c" + integrity sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A== + dependencies: + cipher-base "^1.0.1" + des.js "^1.0.0" + inherits "^2.0.1" + safe-buffer "^5.1.2" + +browserify-rsa@^4.0.0, browserify-rsa@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.1.0.tgz#b2fd06b5b75ae297f7ce2dc651f918f5be158c8d" + integrity sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog== + dependencies: + bn.js "^5.0.0" + randombytes "^2.0.1" + +browserify-sign@^4.0.0: + version "4.2.3" + resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.2.3.tgz#7afe4c01ec7ee59a89a558a4b75bd85ae62d4208" + integrity sha512-JWCZW6SKhfhjJxO8Tyiiy+XYB7cqd2S5/+WeYHsKdNKFlCBhKbblba1A/HN/90YwtxKc8tCErjffZl++UNmGiw== + dependencies: + bn.js "^5.2.1" + browserify-rsa "^4.1.0" + create-hash "^1.2.0" + create-hmac "^1.1.7" + elliptic "^6.5.5" + hash-base "~3.0" + inherits "^2.0.4" + parse-asn1 "^5.1.7" + readable-stream "^2.3.8" + safe-buffer "^5.2.1" + bs58@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/bs58/-/bs58-4.0.1.tgz#be161e76c354f6f788ae4071f63f34e8c4f0a42a" @@ -2179,6 +2311,11 @@ bs58check@^2.1.2: create-hash "^1.1.0" safe-buffer "^5.1.2" +btoa@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/btoa/-/btoa-1.2.1.tgz#01a9909f8b2c93f6bf680ba26131eb30f7fa3d73" + integrity sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g== + buffer-from@^1.0.0: version "1.1.2" resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" @@ -2245,6 +2382,11 @@ bufio@^1.0.7: resolved "https://registry.yarnpkg.com/bufio/-/bufio-1.2.1.tgz#8d4ab3ddfcd5faa90f996f922f9397d41cbaf2de" integrity sha512-9oR3zNdupcg/Ge2sSHQF3GX+kmvL/fTPvD0nd5AGLq8SjUYnTz+SlFjK/GXidndbZtIj+pVKXiWeR9w6e9wKCA== +builtin-modules@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" + integrity sha512-wxXCdllwGhI2kCC0MnvTGYTMvnVZTvqgypkiTI8Pa5tcz2i6VqsqwYGgqwXji+4RgCzms6EajE4IxiUH6HH8nQ== + busboy@^1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/busboy/-/busboy-1.6.0.tgz#966ea36a9502e43cdb9146962523b92f531f6893" @@ -2267,6 +2409,19 @@ cacheable-lookup@^6.0.4: resolved "https://registry.yarnpkg.com/cacheable-lookup/-/cacheable-lookup-6.1.0.tgz#0330a543471c61faa4e9035db583aad753b36385" integrity sha512-KJ/Dmo1lDDhmW2XDPMo+9oiy/CeqosPguPCrgcVzKyZrL6pM1gU2GmPY/xo6OQPTUaA/c0kwHuywB4E6nmT9ww== +cacheable-request@^6.0.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-6.1.0.tgz#20ffb8bd162ba4be11e9567d823db651052ca912" + integrity sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg== + dependencies: + clone-response "^1.0.2" + get-stream "^5.1.0" + http-cache-semantics "^4.0.0" + keyv "^3.0.0" + lowercase-keys "^2.0.0" + normalize-url "^4.1.0" + responselike "^1.0.2" + cacheable-request@^7.0.2: version "7.0.4" resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-7.0.4.tgz#7a33ebf08613178b403635be7b899d3e69bbe817" @@ -2368,7 +2523,7 @@ chai@^4.3.4: pathval "^1.1.1" type-detect "^4.0.5" -chalk@^2.0.0, chalk@^2.1.0, chalk@^2.4.2: +chalk@^2.0.0, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== @@ -2464,6 +2619,14 @@ class-is@^1.1.0: resolved "https://registry.yarnpkg.com/class-is/-/class-is-1.1.0.tgz#9d3c0fba0440d211d843cec3dedfa48055005825" integrity sha512-rhjH9AG1fvabIDoGRVH587413LPjTZgmDF9fOFCbFJQV4yuocX1mHxxvXI4g3cGwbVY9wAYIoKlg1N79frJKQw== +class-validator@^0.13.2: + version "0.13.2" + resolved "https://registry.yarnpkg.com/class-validator/-/class-validator-0.13.2.tgz#64b031e9f3f81a1e1dcd04a5d604734608b24143" + integrity sha512-yBUcQy07FPlGzUjoLuUfIOXzgynnQPPruyK1Ge2B74k9ROwnle1E+NxLWnUv5OLU8hA/qL5leAE9XnXq3byaBw== + dependencies: + libphonenumber-js "^1.9.43" + validator "^13.7.0" + classic-level@^1.2.0: version "1.3.0" resolved "https://registry.yarnpkg.com/classic-level/-/classic-level-1.3.0.tgz#5e36680e01dc6b271775c093f2150844c5edd5c8" @@ -2536,6 +2699,15 @@ cliui@^7.0.2: strip-ansi "^6.0.0" wrap-ansi "^7.0.0" +cliui@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa" + integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.1" + wrap-ansi "^7.0.0" + clone-response@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.3.tgz#af2032aa47816399cf5f0a1d0db902f517abb8c3" @@ -2567,7 +2739,7 @@ color-name@~1.1.4: resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== -colors@1.4.0, colors@^1.1.2: +colors@1.4.0, colors@^1.1.2, colors@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78" integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA== @@ -2619,6 +2791,11 @@ commander@^10.0.0: resolved "https://registry.yarnpkg.com/commander/-/commander-10.0.1.tgz#881ee46b4f77d1c1dccc5823433aa39b022cbe06" integrity sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug== +commander@^2.12.1: + version "2.20.3" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" + integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== + commander@^8.1.0: version "8.3.0" resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66" @@ -2680,6 +2857,11 @@ cookie@^0.4.1: resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.2.tgz#0e41f24de5ecf317947c82fc789e06a884824432" integrity sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA== +cookiejar@^2.1.1: + version "2.1.4" + resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.1.4.tgz#ee669c1fea2cf42dc31585469d193fef0d65771b" + integrity sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw== + core-js-pure@^3.0.1: version "3.31.0" resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.31.0.tgz#052fd9e82fbaaf86457f5db1fadcd06f15966ff2" @@ -2728,6 +2910,14 @@ crc-32@^1.2.0: resolved "https://registry.yarnpkg.com/crc-32/-/crc-32-1.2.2.tgz#3cad35a934b8bf71f25ca524b6da51fb7eace2ff" integrity sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ== +create-ecdh@^4.0.0: + version "4.0.4" + resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.4.tgz#d6e7f4bffa66736085a0762fd3a632684dabcc4e" + integrity sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A== + dependencies: + bn.js "^4.1.0" + elliptic "^6.5.3" + create-hash@^1.1.0, create-hash@^1.1.2, create-hash@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" @@ -2739,7 +2929,7 @@ create-hash@^1.1.0, create-hash@^1.1.2, create-hash@^1.2.0: ripemd160 "^2.0.1" sha.js "^2.4.0" -create-hmac@^1.1.4, create-hmac@^1.1.7: +create-hmac@^1.1.0, create-hmac@^1.1.4, create-hmac@^1.1.7: version "1.1.7" resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff" integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg== @@ -2783,6 +2973,28 @@ cross-spawn@^7.0.2: resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b" integrity sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow== +crypto-browserify@3.12.0: + version "3.12.0" + resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" + integrity sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg== + dependencies: + browserify-cipher "^1.0.0" + browserify-sign "^4.0.0" + create-ecdh "^4.0.0" + create-hash "^1.1.0" + create-hmac "^1.1.0" + diffie-hellman "^5.0.0" + inherits "^2.0.1" + pbkdf2 "^3.0.3" + public-encrypt "^4.0.0" + randombytes "^2.0.0" + randomfill "^1.0.3" + +crypto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/crypto/-/crypto-1.0.1.tgz#2af1b7cad8175d24c8a1b0778255794a21803037" + integrity sha512-VxBKmeNcqQdiUQUW2Tzq0t377b54N2bMtXO/qiLa+6eRRmmC4qT3D4OnTGoT/U6O9aklQ/jTwbOtRMTTY8G0Ig== + d@1, d@^1.0.1, d@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/d/-/d-1.0.2.tgz#2aefd554b81981e7dccf72d6842ae725cb17e5de" @@ -2888,6 +3100,11 @@ defender-base-client@^1.44.0: lodash "^4.17.19" node-fetch "^2.6.0" +defer-to-connect@^1.0.1: + version "1.1.3" + resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-1.1.3.tgz#331ae050c08dcf789f8c83a7b81f0ed94f4ac591" + integrity sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ== + defer-to-connect@^2.0.0, defer-to-connect@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-2.0.1.tgz#8016bdb4143e4632b77a3449c6236277de520587" @@ -2901,7 +3118,7 @@ deferred-leveldown@~5.3.0: abstract-leveldown "~6.2.1" inherits "^2.0.3" -define-data-property@^1.1.4: +define-data-property@^1.0.1, define-data-property@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e" integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A== @@ -2918,6 +3135,15 @@ define-properties@^1.1.2, define-properties@^1.1.3, define-properties@^1.1.4, de has-property-descriptors "^1.0.0" object-keys "^1.1.1" +define-properties@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.1.tgz#10781cc616eb951a80a034bafcaa7377f6af2b6c" + integrity sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg== + dependencies: + define-data-property "^1.0.1" + has-property-descriptors "^1.0.0" + object-keys "^1.1.1" + delayed-stream@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" @@ -2928,6 +3154,14 @@ depd@2.0.0: resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== +des.js@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.1.0.tgz#1d37f5766f3bbff4ee9638e871a8768c173b81da" + integrity sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg== + dependencies: + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + destroy@1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" @@ -2951,6 +3185,20 @@ diff@5.0.0: resolved "https://registry.yarnpkg.com/diff/-/diff-5.0.0.tgz#7ed6ad76d859d030787ec35855f5b1daf31d852b" integrity sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w== +diff@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" + integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== + +diffie-hellman@^5.0.0: + version "5.0.3" + resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875" + integrity sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg== + dependencies: + bn.js "^4.1.0" + miller-rabin "^4.0.0" + randombytes "^2.0.0" + difflib@^0.2.4: version "0.2.4" resolved "https://registry.yarnpkg.com/difflib/-/difflib-0.2.4.tgz#b5e30361a6db023176d562892db85940a718f47e" @@ -2982,6 +3230,11 @@ dotenv@^10.0.0: resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-10.0.0.tgz#3d4227b8fb95f81096cdd2b66653fb2c7085ba81" integrity sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q== +duplexer3@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.5.tgz#0b5e4d7bad5de8901ea4440624c8e1d20099217e" + integrity sha512-1A8za6ws41LQgv9HrE/66jyC5yuSjQ3L/KOpFtoBilsAK2iA2wuS5rTt1OCzIvtS2V7nVmedsUU+DGRcjBmOYA== + ecc-jsbn@~0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" @@ -3008,7 +3261,7 @@ elliptic@6.5.4, elliptic@^6.5.2, elliptic@^6.5.4: minimalistic-assert "^1.0.1" minimalistic-crypto-utils "^1.0.1" -elliptic@^6.4.0: +elliptic@^6.4.0, elliptic@^6.5.3, elliptic@^6.5.5: version "6.5.5" resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.5.tgz#c715e09f78b6923977610d4c2346d6ce22e6dded" integrity sha512-7EjbcmUm17NQFu4Pmgmq2olYMj8nwMnpcddByChSUjArp8F5DQWcIcpriwO4ZToLNAJig0yiyjswfyGNje/ixw== @@ -3021,6 +3274,11 @@ elliptic@^6.4.0: minimalistic-assert "^1.0.1" minimalistic-crypto-utils "^1.0.1" +emitter-component@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/emitter-component/-/emitter-component-1.1.2.tgz#d65af5833dc7c682fd0ade35f902d16bc4bad772" + integrity sha512-QdXO3nXOzZB4pAjM0n6ZE+R9/+kPpECA/XSELIcc54NeYVnBqIk+4DFiBgK+8QbV3mdvTG6nedl7dTYgO+5wDw== + emittery@0.10.0: version "0.10.0" resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.10.0.tgz#bb373c660a9d421bb44706ec4967ed50c02a8026" @@ -3488,6 +3746,21 @@ eth-lib@^0.1.26: ws "^3.0.0" xhr-request-promise "^0.1.2" +eth2-keystore-js@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/eth2-keystore-js/-/eth2-keystore-js-1.0.8.tgz#f3ac4d6e6ec670d8d491dce25bfaf5b36475ed86" + integrity sha512-H5JLUeo7aiZs7zVAb+9gSJZZxfcx5na8zPxcgFbggNfac+atyO5H6KpvDUPJFRm/umHWM7++MdvS/q5Sbw+f9g== + dependencies: + "@types/node" "^15.12.2" + crypto "^1.0.1" + ethereumjs-util "^7.0.10" + ethereumjs-wallet "^1.0.1" + husky "^6.0.0" + scrypt-js "^3.0.1" + tslint "^6.1.3" + tslint-config-prettier "^1.18.0" + typescript "^4.3.2" + ethereum-bloom-filters@^1.0.6: version "1.0.10" resolved "https://registry.yarnpkg.com/ethereum-bloom-filters/-/ethereum-bloom-filters-1.0.10.tgz#3ca07f4aed698e75bd134584850260246a5fed8a" @@ -3580,7 +3853,7 @@ ethereumjs-util@^6.0.0, ethereumjs-util@^6.2.1: ethjs-util "0.1.6" rlp "^2.2.3" -ethereumjs-util@^7.0.3, ethereumjs-util@^7.1.0, ethereumjs-util@^7.1.1, ethereumjs-util@^7.1.3, ethereumjs-util@^7.1.4, ethereumjs-util@^7.1.5: +ethereumjs-util@^7.0.10, ethereumjs-util@^7.0.3, ethereumjs-util@^7.1.0, ethereumjs-util@^7.1.1, ethereumjs-util@^7.1.2, ethereumjs-util@^7.1.3, ethereumjs-util@^7.1.4, ethereumjs-util@^7.1.5: version "7.1.5" resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz#9ecf04861e4fbbeed7465ece5f23317ad1129181" integrity sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg== @@ -3591,6 +3864,20 @@ ethereumjs-util@^7.0.3, ethereumjs-util@^7.1.0, ethereumjs-util@^7.1.1, ethereum ethereum-cryptography "^0.1.3" rlp "^2.2.4" +ethereumjs-wallet@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/ethereumjs-wallet/-/ethereumjs-wallet-1.0.2.tgz#2c000504b4c71e8f3782dabe1113d192522e99b6" + integrity sha512-CCWV4RESJgRdHIvFciVQFnCHfqyhXWchTPlkfp28Qc53ufs+doi5I/cV2+xeK9+qEo25XCWfP9MiL+WEPAZfdA== + dependencies: + aes-js "^3.1.2" + bs58check "^2.1.2" + ethereum-cryptography "^0.1.3" + ethereumjs-util "^7.1.2" + randombytes "^2.1.0" + scrypt-js "^3.0.1" + utf8 "^3.0.0" + uuid "^8.3.2" + ethers@^4.0.40: version "4.0.49" resolved "https://registry.yarnpkg.com/ethers/-/ethers-4.0.49.tgz#0eb0e9161a0c8b4761be547396bbe2fb121a8894" @@ -3676,7 +3963,12 @@ eventemitter3@4.0.4: resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.4.tgz#b5463ace635a083d018bdc7c917b4c5f10a85384" integrity sha512-rlaVLnVxtxvoyLsQQFBx53YmXHDxRIzzTLbdfxqi4yocpSjAxXwkU0cScM5JgSKMqEhrZpnvQ2D9gjylR0AimQ== -evp_bytestokey@^1.0.3: +events@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" + integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== + +evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" integrity sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA== @@ -4151,6 +4443,20 @@ get-port@^3.1.0: resolved "https://registry.yarnpkg.com/get-port/-/get-port-3.2.0.tgz#dd7ce7de187c06c8bf353796ac71e099f0980ebc" integrity sha512-x5UJKlgeUiNT8nyo/AcnwLnZuZNcSjSw0kogRB+Whd1fjjFq4B1hySFxSFWWSn4mIBzg3sRNUDFYc4g5gjPoLg== +get-random-values@^1.2.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/get-random-values/-/get-random-values-1.2.2.tgz#f1d944d0025433d53a2bd9941b9e975d98a2f7ff" + integrity sha512-lMyPjQyl0cNNdDf2oR+IQ/fM3itDvpoHy45Ymo2r0L1EjazeSl13SfbKZs7KtZ/3MDCeueiaJiuOEfKqRTsSgA== + dependencies: + global "^4.4.0" + +get-stream@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" + integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== + dependencies: + pump "^3.0.0" + get-stream@^5.1.0: version "5.2.0" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3" @@ -4240,7 +4546,7 @@ glob@^5.0.15: once "^1.3.0" path-is-absolute "^1.0.0" -glob@^7.0.0, glob@^7.1.2, glob@^7.1.3, glob@^7.1.6: +glob@^7.0.0, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.6: version "7.2.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== @@ -4279,7 +4585,7 @@ global-prefix@^3.0.0: kind-of "^6.0.2" which "^1.3.1" -global@~4.4.0: +global@^4.4.0, global@~4.4.0: version "4.4.0" resolved "https://registry.yarnpkg.com/global/-/global-4.4.0.tgz#3e7b105179006a323ed71aafca3e9c57a5cc6406" integrity sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w== @@ -4346,6 +4652,23 @@ got@12.1.0: p-cancelable "^3.0.0" responselike "^2.0.0" +got@9.6.0: + version "9.6.0" + resolved "https://registry.yarnpkg.com/got/-/got-9.6.0.tgz#edf45e7d67f99545705de1f7bbeeeb121765ed85" + integrity sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q== + dependencies: + "@sindresorhus/is" "^0.14.0" + "@szmarczak/http-timer" "^1.1.2" + cacheable-request "^6.0.0" + decompress-response "^3.3.0" + duplexer3 "^0.1.4" + get-stream "^4.1.0" + lowercase-keys "^1.0.1" + mimic-response "^1.0.1" + p-cancelable "^1.0.0" + to-readable-stream "^1.0.0" + url-parse-lax "^3.0.0" + got@^11.8.5: version "11.8.6" resolved "https://registry.yarnpkg.com/got/-/got-11.8.6.tgz#276e827ead8772eddbcfc97170590b841823233a" @@ -4589,6 +4912,14 @@ hash-base@^3.0.0: readable-stream "^3.6.0" safe-buffer "^5.2.0" +hash-base@~3.0: + version "3.0.4" + resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.0.4.tgz#5fc8686847ecd73499403319a6b0a3f3f6ae4918" + integrity sha512-EeeoJKjTyt868liAlVmcv2ZsUfGHlE3Q+BICOXcZiwN3osr5Q/zFGYmTJpoIzuaSTAwndFy+GqhEwlU4L3j4Ow== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + hash.js@1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.3.tgz#340dedbe6290187151c1ea1d777a3448935df846" @@ -4707,6 +5038,11 @@ https-proxy-agent@^5.0.0: agent-base "6" debug "4" +husky@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/husky/-/husky-6.0.0.tgz#810f11869adf51604c32ea577edbc377d7f9319e" + integrity sha512-SQS2gDTB7tBN486QSoKPKQItZw97BMOd+Kdb6ghfpBc0yXyzrddI0oDV5MkDAbuB4X2mO3/nj60TRMcYxwzZeQ== + husky@^7.0.2: version "7.0.4" resolved "https://registry.yarnpkg.com/husky/-/husky-7.0.4.tgz#242048245dc49c8fb1bf0cc7cfb98dd722531535" @@ -4916,6 +5252,13 @@ is-core-module@^2.11.0: dependencies: has "^1.0.3" +is-core-module@^2.13.0: + version "2.13.1" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.1.tgz#ad0d7532c6fea9da1ebdc82742d74525c6273384" + integrity sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw== + dependencies: + hasown "^2.0.0" + is-date-object@^1.0.1: version "1.0.5" resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" @@ -4967,6 +5310,14 @@ is-hex-prefixed@1.0.0: resolved "https://registry.yarnpkg.com/is-hex-prefixed/-/is-hex-prefixed-1.0.0.tgz#7d8d37e6ad77e5d127148913c573e082d777f554" integrity sha512-WvtOiug1VFrE9v1Cydwm+FnXd3+w9GaeVUss5W4v/SLy3UW00vP+6iNF2SdnfiBoLy4bTqVdkftNGTUeOFVsbA== +is-nan@^1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/is-nan/-/is-nan-1.3.2.tgz#043a54adea31748b55b6cd4e09aadafa69bd9e1d" + integrity sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w== + dependencies: + call-bind "^1.0.0" + define-properties "^1.1.3" + is-negative-zero@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150" @@ -5086,6 +5437,11 @@ isstream@~0.1.2: resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" integrity sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g== +js-base64@^3.7.2: + version "3.7.7" + resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-3.7.7.tgz#e51b84bf78fbf5702b9541e2cb7bfcb893b43e79" + integrity sha512-7rCnleh0z2CkXhH67J8K1Ytz0b2Y+yxTPL+/KOJoa20hfnVQ/3/T6W/KflYI4bRHRagNeXeU2bkNGI3v1oS/lw== + js-cookie@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/js-cookie/-/js-cookie-2.2.1.tgz#69e106dc5d5806894562902aa5baec3744e9b2b8" @@ -5139,6 +5495,11 @@ jsbn@~0.1.0: resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" integrity sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg== +jsencrypt@3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/jsencrypt/-/jsencrypt-3.2.1.tgz#09766983cc760088ff26b12fe7e574252af97727" + integrity sha512-k1sD5QV0KPn+D8uG9AdGzTQuamt82QZ3A3l6f7TRwMU6Oi2Vg0BsL+wZIQBONcraO1pc78ExMdvmBBJ8WhNYUA== + json-bigint@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/json-bigint/-/json-bigint-1.0.0.tgz#ae547823ac0cad8398667f8cd9ef4730f5b01ff1" @@ -5146,6 +5507,11 @@ json-bigint@^1.0.0: dependencies: bignumber.js "^9.0.0" +json-buffer@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898" + integrity sha512-CuUqjv0FUZIdXkHPI8MezCnFCdaTAacej1TZYulLoAg1h/PhwkdXFN4V/gzY4g+fMBCOV2xF+rp7t2XD2ns/NQ== + json-buffer@3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" @@ -5260,6 +5626,13 @@ keccak@^3.0.0, keccak@^3.0.2: node-gyp-build "^4.2.0" readable-stream "^3.6.0" +keyv@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.1.0.tgz#ecc228486f69991e49e9476485a5be1e8fc5c4d9" + integrity sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA== + dependencies: + json-buffer "3.0.0" + keyv@^4.0.0: version "4.5.4" resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" @@ -5279,6 +5652,11 @@ klaw@^1.0.0: optionalDependencies: graceful-fs "^4.1.9" +kleur@^4.0.1: + version "4.1.5" + resolved "https://registry.yarnpkg.com/kleur/-/kleur-4.1.5.tgz#95106101795f7050c6c650f350c683febddb1780" + integrity sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ== + level-codec@^9.0.0: version "9.0.2" resolved "https://registry.yarnpkg.com/level-codec/-/level-codec-9.0.2.tgz#fd60df8c64786a80d44e63423096ffead63d8cbc" @@ -5408,6 +5786,11 @@ levn@^0.4.1: prelude-ls "^1.2.1" type-check "~0.4.0" +libphonenumber-js@^1.9.43: + version "1.10.61" + resolved "https://registry.yarnpkg.com/libphonenumber-js/-/libphonenumber-js-1.10.61.tgz#efd350a6283e5d6a804f0cd17dae1f563410241d" + integrity sha512-TsQsyzDttDvvzWNkbp/i0fVbzTGJIG0mUu/uNalIaRQEYeJxVQ/FPg+EJgSqfSXezREjM0V3RZ8cLVsKYhhw0Q== + lie@~3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/lie/-/lie-3.3.0.tgz#dcf82dee545f46074daf200c7c1c5a08e0f40f6a" @@ -5485,6 +5868,11 @@ loupe@^2.3.1: dependencies: get-func-name "^2.0.0" +lowercase-keys@^1.0.0, lowercase-keys@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" + integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA== + lowercase-keys@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479" @@ -5644,7 +6032,7 @@ mimic-fn@^1.0.0: resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ== -mimic-response@^1.0.0: +mimic-response@^1.0.0, mimic-response@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== @@ -5738,7 +6126,7 @@ mkdirp@0.5.5: dependencies: minimist "^1.2.5" -mkdirp@0.5.x, mkdirp@^0.5.1, mkdirp@^0.5.5: +mkdirp@0.5.x, mkdirp@^0.5.1, mkdirp@^0.5.3, mkdirp@^0.5.5: version "0.5.6" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6" integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw== @@ -5854,6 +6242,11 @@ module-error@^1.0.1, module-error@^1.0.2: resolved "https://registry.yarnpkg.com/module-error/-/module-error-1.0.2.tgz#8d1a48897ca883f47a45816d4fb3e3c6ba404d86" integrity sha512-0yuvsqSCv8LbaOKhnsQ/T5JhyFlCYLPXK3U2sgV10zoKQwzs/MyfuQUOZQ1V/6OCOJsK/TRgNVrPuPDqtdMFtA== +moment@^2.29.3: + version "2.30.1" + resolved "https://registry.yarnpkg.com/moment/-/moment-2.30.1.tgz#f8c91c07b7a786e30c59926df530b4eac96974ae" + integrity sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how== + ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" @@ -6022,6 +6415,13 @@ node-gyp-build@^4.2.0, node-gyp-build@^4.3.0: resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.6.0.tgz#0c52e4cbf54bbd28b709820ef7b6a3c2d6209055" integrity sha512-NTZVKn9IylLwUzaKjkas1e4u2DLNcV4rdYagA4PWdPwW87Bi7z+BznyKSRwS/761tV/lzCGXplWsiaMjLqP2zQ== +node-jsencrypt@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/node-jsencrypt/-/node-jsencrypt-1.0.0.tgz#83ffced414ecbe12fea017c6c585c9bfc49ad19b" + integrity sha512-ANQ/XkOVS02R89MtfoelFxarMsLA12nlOT802VS4LVhl+JRSRZIvkLIjvKYZmIar+mENUkR9mBKUdcdiPy/7lA== + dependencies: + get-random-values "^1.2.0" + nofilter@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/nofilter/-/nofilter-3.1.0.tgz#c757ba68801d41ff930ba2ec55bab52ca184aa66" @@ -6039,6 +6439,11 @@ normalize-path@^3.0.0, normalize-path@~3.0.0: resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== +normalize-url@^4.1.0: + version "4.5.1" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.5.1.tgz#0dd90cf1288ee1d1313b87081c9a5932ee48518a" + integrity sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA== + normalize-url@^6.0.1: version "6.1.0" resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a" @@ -6067,6 +6472,14 @@ object-inspect@^1.12.3, object-inspect@^1.9.0: resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.3.tgz#ba62dffd67ee256c8c086dfae69e016cd1f198b9" integrity sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g== +object-is@^1.1.5: + version "1.1.6" + resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.6.tgz#1a6a53aed2dd8f7e6775ff870bea58545956ab07" + integrity sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + object-keys@^1.0.11, object-keys@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" @@ -6165,6 +6578,11 @@ os-tmpdir@~1.0.2: resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" integrity sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g== +p-cancelable@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-1.1.0.tgz#d078d15a3af409220c886f1d9a0ca2e441ab26cc" + integrity sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw== + p-cancelable@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-2.1.1.tgz#aab7fbd416582fa32a3db49859c122487c5ed2cf" @@ -6251,6 +6669,18 @@ parent-module@^1.0.0: dependencies: callsites "^3.0.0" +parse-asn1@^5.0.0, parse-asn1@^5.1.7: + version "5.1.7" + resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.7.tgz#73cdaaa822125f9647165625eb45f8a051d2df06" + integrity sha512-CTM5kuWR3sx9IFamcl5ErfPl6ea/N8IYwiJ+vpeB2g+1iknv7zBl5uPwbMbRVznRVbrNY6lGuDoE5b30grmbqg== + dependencies: + asn1.js "^4.10.1" + browserify-aes "^1.2.0" + evp_bytestokey "^1.0.3" + hash-base "~3.0" + pbkdf2 "^3.1.2" + safe-buffer "^5.2.1" + parse-cache-control@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/parse-cache-control/-/parse-cache-control-1.0.1.tgz#8eeab3e54fa56920fe16ba38f77fa21aacc2d74e" @@ -6339,7 +6769,7 @@ pathval@^1.1.1: resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.1.tgz#8534e77a77ce7ac5a2512ea21e0fdb8fcf6c3d8d" integrity sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ== -pbkdf2@^3.0.17, pbkdf2@^3.0.9: +pbkdf2@^3.0.17, pbkdf2@^3.0.3, pbkdf2@^3.0.9, pbkdf2@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.1.2.tgz#dd822aa0887580e52f1a039dc3eda108efae3075" integrity sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA== @@ -6396,6 +6826,11 @@ prelude-ls@~1.1.2: resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" integrity sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w== +prepend-http@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" + integrity sha512-ravE6m9Atw9Z/jjttRUZ+clIXogdghyZAuWJ3qEzjT+jI/dL1ifAqhZeC5VHzQp1MSt1+jxKkFNemj/iO7tVUA== + prettier-plugin-solidity@1.0.0-beta.17: version "1.0.0-beta.17" resolved "https://registry.yarnpkg.com/prettier-plugin-solidity/-/prettier-plugin-solidity-1.0.0-beta.17.tgz#fc0fe977202b6503763a338383efeceaa6c7661e" @@ -6440,6 +6875,13 @@ promise@^8.0.0: dependencies: asap "~2.0.6" +"prompts@git+https://github.com/meshin-blox/prompts.git": + version "2.4.2" + resolved "git+https://github.com/meshin-blox/prompts.git#a22bdac044f6b32ba67adb4eacc2e58322512a2d" + dependencies: + kleur "^4.0.1" + sisteransi "^1.0.5" + proper-lockfile@^4.1.1: version "4.1.2" resolved "https://registry.yarnpkg.com/proper-lockfile/-/proper-lockfile-4.1.2.tgz#c8b9de2af6b2f1601067f98e01ac66baa223141f" @@ -6472,6 +6914,18 @@ psl@^1.1.28: resolved "https://registry.yarnpkg.com/psl/-/psl-1.9.0.tgz#d0df2a137f00794565fcaf3b2c00cd09f8d5a5a7" integrity sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag== +public-encrypt@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.3.tgz#4fcc9d77a07e48ba7527e7cbe0de33d0701331e0" + integrity sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q== + dependencies: + bn.js "^4.1.0" + browserify-rsa "^4.0.0" + create-hash "^1.1.0" + parse-asn1 "^5.0.0" + randombytes "^2.0.1" + safe-buffer "^5.1.2" + pump@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" @@ -6533,13 +6987,21 @@ quick-lru@^5.1.1: resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932" integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA== -randombytes@^2.0.1, randombytes@^2.1.0: +randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5, randombytes@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== dependencies: safe-buffer "^5.1.0" +randomfill@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/randomfill/-/randomfill-1.0.4.tgz#c92196fc86ab42be983f1bf31778224931d61458" + integrity sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw== + dependencies: + randombytes "^2.0.5" + safe-buffer "^5.1.0" + range-parser@~1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" @@ -6555,7 +7017,7 @@ raw-body@2.5.2, raw-body@^2.4.1: iconv-lite "0.4.24" unpipe "1.0.0" -readable-stream@^2.2.2, readable-stream@~2.3.6: +readable-stream@^2.2.2, readable-stream@^2.3.8, readable-stream@~2.3.6: version "2.3.8" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b" integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== @@ -6736,6 +7198,22 @@ resolve@^1.1.6: path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" +resolve@^1.3.2: + version "1.22.8" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" + integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== + dependencies: + is-core-module "^2.13.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +responselike@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7" + integrity sha512-/Fpe5guzJk1gPqdJLJR5u7eG/gNY4nImjbRDaVWVMRhne55TCmj2i9Q+54PBRfatRC8v/rIiv9BN0pMd9OV5EQ== + dependencies: + lowercase-keys "^1.0.0" + responselike@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/responselike/-/responselike-2.0.1.tgz#9a0bc8fdc252f3fb1cca68b016591059ba1422bc" @@ -6923,6 +7401,11 @@ semaphore-async-await@^1.5.1: resolved "https://registry.yarnpkg.com/semaphore-async-await/-/semaphore-async-await-1.5.1.tgz#857bef5e3644601ca4b9570b87e9df5ca12974fa" integrity sha512-b/ptP11hETwYWpeilHXXQiV5UJNJl7ZWWooKRE5eBIYWoom6dZ0SluCIdCtKycsMtZgKWE01/qAw6jblw1YVhg== +semver@^5.3.0: + version "5.7.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" + integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== + semver@^5.5.0, semver@^5.5.1, semver@^5.7.0: version "5.7.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" @@ -6940,6 +7423,13 @@ semver@^7.2.1, semver@^7.3.4, semver@^7.3.5: dependencies: lru-cache "^6.0.0" +semver@^7.5.1: + version "7.6.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.0.tgz#1a46a4db4bffcccd97b743b5005c8325f23d4e2d" + integrity sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg== + dependencies: + lru-cache "^6.0.0" + send@0.18.0: version "0.18.0" resolved "https://registry.yarnpkg.com/send/-/send-0.18.0.tgz#670167cc654b05f5aa4a767f9113bb371bc706be" @@ -7096,6 +7586,11 @@ simple-get@^2.7.0: once "^1.3.1" simple-concat "^1.0.0" +sisteransi@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" + integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== + slash@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" @@ -7290,6 +7785,42 @@ sshpk@^1.7.0: safer-buffer "^2.0.2" tweetnacl "~0.14.0" +ssv-keys@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/ssv-keys/-/ssv-keys-1.1.0.tgz#bbd5f7c0c51cb16899938c8ea6aab543f1ef6963" + integrity sha512-nKxKbGkqhw3pPHfDvwOgOSD5IYLRx7WPxBJQRMorzv0q6FIFUl7T+sBbBzL0AHvv4H/BBNUFQyHBRSo6TIrRyA== + dependencies: + "@types/figlet" "^1.5.4" + "@types/underscore" "^1.11.4" + "@types/yargs" "^17.0.12" + argparse "^2.0.1" + assert "^2.0.0" + atob "^2.1.2" + bls-eth-wasm "^1.0.4" + bls-signatures "^0.2.5" + btoa "^1.2.1" + class-validator "^0.13.2" + colors "^1.4.0" + crypto "^1.0.1" + eth2-keystore-js "^1.0.8" + ethereumjs-util "^7.1.5" + ethereumjs-wallet "^1.0.1" + ethers "^5.7.2" + events "^3.3.0" + figlet "^1.5.2" + js-base64 "^3.7.2" + jsencrypt "3.2.1" + minimist "^1.2.6" + moment "^2.29.3" + node-jsencrypt "^1.0.0" + prompts "https://github.com/meshin-blox/prompts.git" + scrypt-js "^3.0.1" + semver "^7.5.1" + stream "^0.0.2" + underscore "^1.13.4" + web3 "1.7.3" + yargs "^17.5.1" + "ssv-scanner@github:bloxapp/ssv-scanner": version "1.0.3" resolved "https://codeload.github.com/bloxapp/ssv-scanner/tar.gz/b508efe18acb5ae1b94d13eae993d5dcaccf000b" @@ -7317,6 +7848,13 @@ stealthy-require@^1.1.1: resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b" integrity sha512-ZnWpYnYugiOVEY5GkcuJK1io5V8QmNYChG62gSit9pQVGErXtrKuPC55ITaVSukmMta5qpMU7vqLt2Lnni4f/g== +stream@^0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/stream/-/stream-0.0.2.tgz#7f5363f057f6592c5595f00bc80a27f5cec1f0ef" + integrity sha512-gCq3NDI2P35B2n6t76YJuOp7d6cN/C7Rt0577l91wllh0sY9ZBuw9KaSGqH/b0hzn3CWWJbpbW0W0WvQ1H/Q7g== + dependencies: + emitter-component "^1.1.1" + streamsearch@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-1.1.0.tgz#404dd1e2247ca94af554e841a8ef0eaa238da764" @@ -7600,6 +8138,11 @@ tmp@0.0.33, tmp@^0.0.33: dependencies: os-tmpdir "~1.0.2" +to-readable-stream@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/to-readable-stream/-/to-readable-stream-1.0.0.tgz#ce0aa0c2f3df6adf852efb404a783e77c0475771" + integrity sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q== + to-regex-range@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" @@ -7640,7 +8183,7 @@ ts-essentials@^7.0.1: resolved "https://registry.yarnpkg.com/ts-essentials/-/ts-essentials-7.0.3.tgz#686fd155a02133eedcc5362dc8b5056cde3e5a38" integrity sha512-8+gr5+lqO3G84KdiTSMRLtuyJ+nTBVRKuCrK4lidMPdVeEp0uqC875uE5NMcaA7YYMN7XsNiFQuMvasF8HT/xQ== -tslib@^1.11.1, tslib@^1.9.0, tslib@^1.9.3: +tslib@^1.11.1, tslib@^1.13.0, tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3: version "1.14.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== @@ -7650,11 +8193,42 @@ tslib@^2.3.1, tslib@^2.5.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.5.3.tgz#24944ba2d990940e6e982c4bea147aba80209913" integrity sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w== +tslint-config-prettier@^1.18.0: + version "1.18.0" + resolved "https://registry.yarnpkg.com/tslint-config-prettier/-/tslint-config-prettier-1.18.0.tgz#75f140bde947d35d8f0d238e0ebf809d64592c37" + integrity sha512-xPw9PgNPLG3iKRxmK7DWr+Ea/SzrvfHtjFt5LBl61gk2UBG/DB9kCXRjv+xyIU1rUtnayLeMUVJBcMX8Z17nDg== + +tslint@^6.1.3: + version "6.1.3" + resolved "https://registry.yarnpkg.com/tslint/-/tslint-6.1.3.tgz#5c23b2eccc32487d5523bd3a470e9aa31789d904" + integrity sha512-IbR4nkT96EQOvKE2PW/djGz8iGNeJ4rF2mBfiYaR/nvUWYKJhLwimoJKgjIFEIDibBtOevj7BqCRL4oHeWWUCg== + dependencies: + "@babel/code-frame" "^7.0.0" + builtin-modules "^1.1.1" + chalk "^2.3.0" + commander "^2.12.1" + diff "^4.0.1" + glob "^7.1.1" + js-yaml "^3.13.1" + minimatch "^3.0.4" + mkdirp "^0.5.3" + resolve "^1.3.2" + semver "^5.3.0" + tslib "^1.13.0" + tsutils "^2.29.0" + tsort@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/tsort/-/tsort-0.0.1.tgz#e2280f5e817f8bf4275657fd0f9aebd44f5a2786" integrity sha512-Tyrf5mxF8Ofs1tNoxA13lFeZ2Zrbd6cKbuH3V+MQ5sb6DtBj5FjrXVsRWT8YvNAQTqNoz66dz1WsbigI22aEnw== +tsutils@^2.29.0: + version "2.29.0" + resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.29.0.tgz#32b488501467acbedd4b85498673a0812aca0b99" + integrity sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA== + dependencies: + tslib "^1.8.1" + tunnel-agent@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" @@ -7761,6 +8335,11 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA== +typescript@^4.3.2: + version "4.9.5" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a" + integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g== + typical@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/typical/-/typical-4.0.0.tgz#cbeaff3b9d7ae1e2bbfaf5a4e6f11eccfde94fc4" @@ -7791,6 +8370,11 @@ unbox-primitive@^1.0.2: has-symbols "^1.0.3" which-boxed-primitive "^1.0.2" +underscore@^1.13.4: + version "1.13.6" + resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.13.6.tgz#04786a1f589dc6c09f761fc5f45b89e935136441" + integrity sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A== + undici@^5.14.0: version "5.22.1" resolved "https://registry.yarnpkg.com/undici/-/undici-5.22.1.tgz#877d512effef2ac8be65e695f3586922e1a57d7b" @@ -7825,6 +8409,13 @@ uri-js@^4.2.2: dependencies: punycode "^2.1.0" +url-parse-lax@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-3.0.0.tgz#16b5cafc07dbe3676c1b1999177823d6503acb0c" + integrity sha512-NjFKA0DidqPa5ciFcSrXnAltTtzz84ogy+NebPvfEgAck0+TNg4UJ4IN+fB7zRZfbgUf0syOo9MDxFkDSMuFaQ== + dependencies: + prepend-http "^2.0.0" + url-set-query@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/url-set-query/-/url-set-query-1.0.0.tgz#016e8cfd7c20ee05cafe7795e892bd0702faa339" @@ -7852,7 +8443,7 @@ utf-8-validate@^5.0.2: dependencies: node-gyp-build "^4.3.0" -utf8@3.0.0: +utf8@3.0.0, utf8@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/utf8/-/utf8-3.0.0.tgz#f052eed1364d696e769ef058b183df88c87f69d1" integrity sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ== @@ -7862,7 +8453,7 @@ util-deprecate@^1.0.1, util-deprecate@~1.0.1: resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== -util@^0.12.5: +util@^0.12.0, util@^0.12.5: version "0.12.5" resolved "https://registry.yarnpkg.com/util/-/util-0.12.5.tgz#5f17a6059b73db61a875668781a1c2b136bd6fbc" integrity sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA== @@ -7883,6 +8474,11 @@ uuid@2.0.1: resolved "https://registry.yarnpkg.com/uuid/-/uuid-2.0.1.tgz#c2a30dedb3e535d72ccf82e343941a50ba8533ac" integrity sha512-nWg9+Oa3qD2CQzHIP4qKUqwNfzKn8P0LtFhotaCTFchsV7ZfDhAybeip/HZVeMIpZi9JgY1E3nUlwaCmZT1sEg== +uuid@3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" + integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA== + uuid@^3.3.2: version "3.4.0" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" @@ -7893,7 +8489,7 @@ uuid@^8.3.2: resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== -uuid@^9.0.0: +uuid@^9.0.0, uuid@^9.0.1: version "9.0.1" resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30" integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA== @@ -7903,6 +8499,11 @@ v8-compile-cache@^2.0.3: resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== +validator@^13.7.0: + version "13.11.0" + resolved "https://registry.yarnpkg.com/validator/-/validator-13.11.0.tgz#23ab3fd59290c61248364eabf4067f04955fbb1b" + integrity sha512-Ii+sehpSfZy+At5nPdnyMhx78fEoPDkR2XW/zimHEL3MyGJQOCQ7WeP20jPYRz7ZCpcKLB21NxuXHF3bxjStBQ== + varint@^5.0.0: version "5.0.2" resolved "https://registry.yarnpkg.com/varint/-/varint-5.0.2.tgz#5b47f8a947eb668b848e034dcfa87d0ff8a7f7a4" @@ -7931,6 +8532,15 @@ web3-bzz@1.10.4: got "12.1.0" swarm-js "^0.1.40" +web3-bzz@1.7.3: + version "1.7.3" + resolved "https://registry.yarnpkg.com/web3-bzz/-/web3-bzz-1.7.3.tgz#6860a584f748838af5e3932b6798e024ab8ae951" + integrity sha512-y2i2IW0MfSqFc1JBhBSQ59Ts9xE30hhxSmLS13jLKWzie24/An5dnoGarp2rFAy20tevJu1zJVPYrEl14jiL5w== + dependencies: + "@types/node" "^12.12.6" + got "9.6.0" + swarm-js "^0.1.40" + web3-core-helpers@1.10.4: version "1.10.4" resolved "https://registry.yarnpkg.com/web3-core-helpers/-/web3-core-helpers-1.10.4.tgz#bd2b4140df2016d5dd3bb2b925fc29ad8678677c" @@ -7939,6 +8549,14 @@ web3-core-helpers@1.10.4: web3-eth-iban "1.10.4" web3-utils "1.10.4" +web3-core-helpers@1.7.3: + version "1.7.3" + resolved "https://registry.yarnpkg.com/web3-core-helpers/-/web3-core-helpers-1.7.3.tgz#9a8d7830737d0e9c48694b244f4ce0f769ba67b9" + integrity sha512-qS2t6UKLhRV/6C7OFHtMeoHphkcA+CKUr2vfpxy4hubs3+Nj28K9pgiqFuvZiXmtEEwIAE2A28GBOC3RdcSuFg== + dependencies: + web3-eth-iban "1.7.3" + web3-utils "1.7.3" + web3-core-method@1.10.4: version "1.10.4" resolved "https://registry.yarnpkg.com/web3-core-method/-/web3-core-method-1.10.4.tgz#566b52f006d3cbb13b21b72b8d2108999bf5d6bf" @@ -7950,6 +8568,17 @@ web3-core-method@1.10.4: web3-core-subscriptions "1.10.4" web3-utils "1.10.4" +web3-core-method@1.7.3: + version "1.7.3" + resolved "https://registry.yarnpkg.com/web3-core-method/-/web3-core-method-1.7.3.tgz#eb2a4f140448445c939518c0fa6216b3d265c5e9" + integrity sha512-SeF8YL/NVFbj/ddwLhJeS0io8y7wXaPYA2AVT0h2C2ESYkpvOtQmyw2Bc3aXxBmBErKcbOJjE2ABOKdUmLSmMA== + dependencies: + "@ethersproject/transactions" "^5.0.0-beta.135" + web3-core-helpers "1.7.3" + web3-core-promievent "1.7.3" + web3-core-subscriptions "1.7.3" + web3-utils "1.7.3" + web3-core-promievent@1.10.4: version "1.10.4" resolved "https://registry.yarnpkg.com/web3-core-promievent/-/web3-core-promievent-1.10.4.tgz#629b970b7934430b03c5033c79f3bb3893027e22" @@ -7957,6 +8586,13 @@ web3-core-promievent@1.10.4: dependencies: eventemitter3 "4.0.4" +web3-core-promievent@1.7.3: + version "1.7.3" + resolved "https://registry.yarnpkg.com/web3-core-promievent/-/web3-core-promievent-1.7.3.tgz#2d0eeef694569b61355054c721578f67df925b80" + integrity sha512-+mcfNJLP8h2JqcL/UdMGdRVfTdm+bsoLzAFtLpazE4u9kU7yJUgMMAqnK59fKD3Zpke3DjaUJKwz1TyiGM5wig== + dependencies: + eventemitter3 "4.0.4" + web3-core-requestmanager@1.10.4: version "1.10.4" resolved "https://registry.yarnpkg.com/web3-core-requestmanager/-/web3-core-requestmanager-1.10.4.tgz#eb1f147e6b9df84e3a37e602162f8925bdb4bb9a" @@ -7968,6 +8604,17 @@ web3-core-requestmanager@1.10.4: web3-providers-ipc "1.10.4" web3-providers-ws "1.10.4" +web3-core-requestmanager@1.7.3: + version "1.7.3" + resolved "https://registry.yarnpkg.com/web3-core-requestmanager/-/web3-core-requestmanager-1.7.3.tgz#226f79d16e546c9157d00908de215e984cae84e9" + integrity sha512-bC+jeOjPbagZi2IuL1J5d44f3zfPcgX+GWYUpE9vicNkPUxFBWRG+olhMo7L+BIcD57cTmukDlnz+1xBULAjFg== + dependencies: + util "^0.12.0" + web3-core-helpers "1.7.3" + web3-providers-http "1.7.3" + web3-providers-ipc "1.7.3" + web3-providers-ws "1.7.3" + web3-core-subscriptions@1.10.4: version "1.10.4" resolved "https://registry.yarnpkg.com/web3-core-subscriptions/-/web3-core-subscriptions-1.10.4.tgz#2f4dcb404237e92802a563265d11a33934dc38e6" @@ -7976,6 +8623,14 @@ web3-core-subscriptions@1.10.4: eventemitter3 "4.0.4" web3-core-helpers "1.10.4" +web3-core-subscriptions@1.7.3: + version "1.7.3" + resolved "https://registry.yarnpkg.com/web3-core-subscriptions/-/web3-core-subscriptions-1.7.3.tgz#ca456dfe2c219a0696c5cf34c13b03c3599ec5d5" + integrity sha512-/i1ZCLW3SDxEs5mu7HW8KL4Vq7x4/fDXY+yf/vPoDljlpvcLEOnI8y9r7om+0kYwvuTlM6DUHHafvW0221TyRQ== + dependencies: + eventemitter3 "4.0.4" + web3-core-helpers "1.7.3" + web3-core@1.10.4: version "1.10.4" resolved "https://registry.yarnpkg.com/web3-core/-/web3-core-1.10.4.tgz#639de68b8b9871d2dc8892e0dd4e380cb1361a98" @@ -7989,6 +8644,19 @@ web3-core@1.10.4: web3-core-requestmanager "1.10.4" web3-utils "1.10.4" +web3-core@1.7.3: + version "1.7.3" + resolved "https://registry.yarnpkg.com/web3-core/-/web3-core-1.7.3.tgz#2ef25c4cc023997f43af9f31a03b571729ff3cda" + integrity sha512-4RNxueGyevD1XSjdHE57vz/YWRHybpcd3wfQS33fgMyHZBVLFDNwhn+4dX4BeofVlK/9/cmPAokLfBUStZMLdw== + dependencies: + "@types/bn.js" "^4.11.5" + "@types/node" "^12.12.6" + bignumber.js "^9.0.0" + web3-core-helpers "1.7.3" + web3-core-method "1.7.3" + web3-core-requestmanager "1.7.3" + web3-utils "1.7.3" + web3-eth-abi@1.10.4: version "1.10.4" resolved "https://registry.yarnpkg.com/web3-eth-abi/-/web3-eth-abi-1.10.4.tgz#16c19d0bde0aaf8c1a56cb7743a83156d148d798" @@ -7997,6 +8665,14 @@ web3-eth-abi@1.10.4: "@ethersproject/abi" "^5.6.3" web3-utils "1.10.4" +web3-eth-abi@1.7.3: + version "1.7.3" + resolved "https://registry.yarnpkg.com/web3-eth-abi/-/web3-eth-abi-1.7.3.tgz#2a1123c7252c37100eecd0b1fb2fb2c51366071f" + integrity sha512-ZlD8DrJro0ocnbZViZpAoMX44x5aYAb73u2tMq557rMmpiluZNnhcCYF/NnVMy6UIkn7SF/qEA45GXA1ne6Tnw== + dependencies: + "@ethersproject/abi" "5.0.7" + web3-utils "1.7.3" + web3-eth-accounts@1.10.4: version "1.10.4" resolved "https://registry.yarnpkg.com/web3-eth-accounts/-/web3-eth-accounts-1.10.4.tgz#df30e85a7cd70e475f8cf52361befba408829e34" @@ -8013,6 +8689,23 @@ web3-eth-accounts@1.10.4: web3-core-method "1.10.4" web3-utils "1.10.4" +web3-eth-accounts@1.7.3: + version "1.7.3" + resolved "https://registry.yarnpkg.com/web3-eth-accounts/-/web3-eth-accounts-1.7.3.tgz#cd1789000f13ed3c438e96b3e80ee7be8d3f1a9b" + integrity sha512-aDaWjW1oJeh0LeSGRVyEBiTe/UD2/cMY4dD6pQYa8dOhwgMtNQjxIQ7kacBBXe7ZKhjbIFZDhvXN4mjXZ82R2Q== + dependencies: + "@ethereumjs/common" "^2.5.0" + "@ethereumjs/tx" "^3.3.2" + crypto-browserify "3.12.0" + eth-lib "0.2.8" + ethereumjs-util "^7.0.10" + scrypt-js "^3.0.1" + uuid "3.3.2" + web3-core "1.7.3" + web3-core-helpers "1.7.3" + web3-core-method "1.7.3" + web3-utils "1.7.3" + web3-eth-contract@1.10.4: version "1.10.4" resolved "https://registry.yarnpkg.com/web3-eth-contract/-/web3-eth-contract-1.10.4.tgz#22d39f04e11d9ff4e726e8025a56d78e843a2c3d" @@ -8027,6 +8720,20 @@ web3-eth-contract@1.10.4: web3-eth-abi "1.10.4" web3-utils "1.10.4" +web3-eth-contract@1.7.3: + version "1.7.3" + resolved "https://registry.yarnpkg.com/web3-eth-contract/-/web3-eth-contract-1.7.3.tgz#c4efc118ed7adafbc1270b633f33e696a39c7fc7" + integrity sha512-7mjkLxCNMWlQrlfM/MmNnlKRHwFk5XrZcbndoMt3KejcqDP6dPHi2PZLutEcw07n/Sk8OMpSamyF3QiGfmyRxw== + dependencies: + "@types/bn.js" "^4.11.5" + web3-core "1.7.3" + web3-core-helpers "1.7.3" + web3-core-method "1.7.3" + web3-core-promievent "1.7.3" + web3-core-subscriptions "1.7.3" + web3-eth-abi "1.7.3" + web3-utils "1.7.3" + web3-eth-ens@1.10.4: version "1.10.4" resolved "https://registry.yarnpkg.com/web3-eth-ens/-/web3-eth-ens-1.10.4.tgz#3d991adac52bc8e598f1f1b8528337fa6291004c" @@ -8041,6 +8748,20 @@ web3-eth-ens@1.10.4: web3-eth-contract "1.10.4" web3-utils "1.10.4" +web3-eth-ens@1.7.3: + version "1.7.3" + resolved "https://registry.yarnpkg.com/web3-eth-ens/-/web3-eth-ens-1.7.3.tgz#ebc56a4dc7007f4f899259bbae1237d3095e2f3f" + integrity sha512-q7+hFGHIc0mBI3LwgRVcLCQmp6GItsWgUtEZ5bjwdjOnJdbjYddm7PO9RDcTDQ6LIr7hqYaY4WTRnDHZ6BEt5Q== + dependencies: + content-hash "^2.5.2" + eth-ens-namehash "2.0.8" + web3-core "1.7.3" + web3-core-helpers "1.7.3" + web3-core-promievent "1.7.3" + web3-eth-abi "1.7.3" + web3-eth-contract "1.7.3" + web3-utils "1.7.3" + web3-eth-iban@1.10.4: version "1.10.4" resolved "https://registry.yarnpkg.com/web3-eth-iban/-/web3-eth-iban-1.10.4.tgz#bc61b4a1930d19b1df8762c606d669902558e54d" @@ -8049,6 +8770,14 @@ web3-eth-iban@1.10.4: bn.js "^5.2.1" web3-utils "1.10.4" +web3-eth-iban@1.7.3: + version "1.7.3" + resolved "https://registry.yarnpkg.com/web3-eth-iban/-/web3-eth-iban-1.7.3.tgz#47433a73380322bba04e17b91fccd4a0e63a390a" + integrity sha512-1GPVWgajwhh7g53mmYDD1YxcftQniIixMiRfOqlnA1w0mFGrTbCoPeVaSQ3XtSf+rYehNJIZAUeDBnONVjXXmg== + dependencies: + bn.js "^4.11.9" + web3-utils "1.7.3" + web3-eth-personal@1.10.4: version "1.10.4" resolved "https://registry.yarnpkg.com/web3-eth-personal/-/web3-eth-personal-1.10.4.tgz#e2ee920f47e84848288e03442659cdbb2c4deea2" @@ -8061,6 +8790,18 @@ web3-eth-personal@1.10.4: web3-net "1.10.4" web3-utils "1.10.4" +web3-eth-personal@1.7.3: + version "1.7.3" + resolved "https://registry.yarnpkg.com/web3-eth-personal/-/web3-eth-personal-1.7.3.tgz#ca2464dca356d4335aa8141cf75a6947f10f45a6" + integrity sha512-iTLz2OYzEsJj2qGE4iXC1Gw+KZN924fTAl0ESBFs2VmRhvVaM7GFqZz/wx7/XESl3GVxGxlRje3gNK0oGIoYYQ== + dependencies: + "@types/node" "^12.12.6" + web3-core "1.7.3" + web3-core-helpers "1.7.3" + web3-core-method "1.7.3" + web3-net "1.7.3" + web3-utils "1.7.3" + web3-eth@1.10.4: version "1.10.4" resolved "https://registry.yarnpkg.com/web3-eth/-/web3-eth-1.10.4.tgz#3a908c635cb5d935bd30473e452f3bd7f2ee66a5" @@ -8079,6 +8820,24 @@ web3-eth@1.10.4: web3-net "1.10.4" web3-utils "1.10.4" +web3-eth@1.7.3: + version "1.7.3" + resolved "https://registry.yarnpkg.com/web3-eth/-/web3-eth-1.7.3.tgz#9e92785ea18d682548b6044551abe7f2918fc0b5" + integrity sha512-BCIRMPwaMlTCbswXyGT6jj9chCh9RirbDFkPtvqozfQ73HGW7kP78TXXf9+Xdo1GjutQfxi/fQ9yPdxtDJEpDA== + dependencies: + web3-core "1.7.3" + web3-core-helpers "1.7.3" + web3-core-method "1.7.3" + web3-core-subscriptions "1.7.3" + web3-eth-abi "1.7.3" + web3-eth-accounts "1.7.3" + web3-eth-contract "1.7.3" + web3-eth-ens "1.7.3" + web3-eth-iban "1.7.3" + web3-eth-personal "1.7.3" + web3-net "1.7.3" + web3-utils "1.7.3" + web3-net@1.10.4: version "1.10.4" resolved "https://registry.yarnpkg.com/web3-net/-/web3-net-1.10.4.tgz#20e12c60e4477d4298979d8d5d66b9abf8e66a09" @@ -8088,6 +8847,15 @@ web3-net@1.10.4: web3-core-method "1.10.4" web3-utils "1.10.4" +web3-net@1.7.3: + version "1.7.3" + resolved "https://registry.yarnpkg.com/web3-net/-/web3-net-1.7.3.tgz#54e35bcc829fdc40cf5001a3870b885d95069810" + integrity sha512-zAByK0Qrr71k9XW0Adtn+EOuhS9bt77vhBO6epAeQ2/VKl8rCGLAwrl3GbeEl7kWa8s/su72cjI5OetG7cYR0g== + dependencies: + web3-core "1.7.3" + web3-core-method "1.7.3" + web3-utils "1.7.3" + web3-providers-http@1.10.4: version "1.10.4" resolved "https://registry.yarnpkg.com/web3-providers-http/-/web3-providers-http-1.10.4.tgz#ca7aa58aeaf8123500c24ffe0595896319f830e8" @@ -8098,6 +8866,14 @@ web3-providers-http@1.10.4: es6-promise "^4.2.8" web3-core-helpers "1.10.4" +web3-providers-http@1.7.3: + version "1.7.3" + resolved "https://registry.yarnpkg.com/web3-providers-http/-/web3-providers-http-1.7.3.tgz#8ea5e39f6ceee0b5bc4e45403fae75cad8ff4cf7" + integrity sha512-TQJfMsDQ5Uq9zGMYlu7azx1L7EvxW+Llks3MaWn3cazzr5tnrDbGh6V17x6LN4t8tFDHWx0rYKr3mDPqyTjOZw== + dependencies: + web3-core-helpers "1.7.3" + xhr2-cookies "1.1.0" + web3-providers-ipc@1.10.4: version "1.10.4" resolved "https://registry.yarnpkg.com/web3-providers-ipc/-/web3-providers-ipc-1.10.4.tgz#2e03437909e4e7771d646ff05518efae44b783c3" @@ -8106,6 +8882,14 @@ web3-providers-ipc@1.10.4: oboe "2.1.5" web3-core-helpers "1.10.4" +web3-providers-ipc@1.7.3: + version "1.7.3" + resolved "https://registry.yarnpkg.com/web3-providers-ipc/-/web3-providers-ipc-1.7.3.tgz#a34872103a8d37a03795fa2f9b259e869287dcaa" + integrity sha512-Z4EGdLKzz6I1Bw+VcSyqVN4EJiT2uAro48Am1eRvxUi4vktGoZtge1ixiyfrRIVb6nPe7KnTFl30eQBtMqS0zA== + dependencies: + oboe "2.1.5" + web3-core-helpers "1.7.3" + web3-providers-ws@1.10.4: version "1.10.4" resolved "https://registry.yarnpkg.com/web3-providers-ws/-/web3-providers-ws-1.10.4.tgz#55d0c3ba36c6a79d105f02e20a707eb3978e7f82" @@ -8115,6 +8899,15 @@ web3-providers-ws@1.10.4: web3-core-helpers "1.10.4" websocket "^1.0.32" +web3-providers-ws@1.7.3: + version "1.7.3" + resolved "https://registry.yarnpkg.com/web3-providers-ws/-/web3-providers-ws-1.7.3.tgz#87564facc47387c9004a043a6686e4881ed6acfe" + integrity sha512-PpykGbkkkKtxPgv7U4ny4UhnkqSZDfLgBEvFTXuXLAngbX/qdgfYkhIuz3MiGplfL7Yh93SQw3xDjImXmn2Rgw== + dependencies: + eventemitter3 "4.0.4" + web3-core-helpers "1.7.3" + websocket "^1.0.32" + web3-shh@1.10.4: version "1.10.4" resolved "https://registry.yarnpkg.com/web3-shh/-/web3-shh-1.10.4.tgz#9852d6f3d05678e31e49235a60fea10ca7a9e21d" @@ -8125,6 +8918,16 @@ web3-shh@1.10.4: web3-core-subscriptions "1.10.4" web3-net "1.10.4" +web3-shh@1.7.3: + version "1.7.3" + resolved "https://registry.yarnpkg.com/web3-shh/-/web3-shh-1.7.3.tgz#84e10adf628556798244b58f73cda1447bb7075e" + integrity sha512-bQTSKkyG7GkuULdZInJ0osHjnmkHij9tAySibpev1XjYdjLiQnd0J9YGF4HjvxoG3glNROpuCyTaRLrsLwaZuw== + dependencies: + web3-core "1.7.3" + web3-core-method "1.7.3" + web3-core-subscriptions "1.7.3" + web3-net "1.7.3" + web3-utils@1.10.4: version "1.10.4" resolved "https://registry.yarnpkg.com/web3-utils/-/web3-utils-1.10.4.tgz#0daee7d6841641655d8b3726baf33b08eda1cbec" @@ -8139,6 +8942,19 @@ web3-utils@1.10.4: randombytes "^2.1.0" utf8 "3.0.0" +web3-utils@1.7.3: + version "1.7.3" + resolved "https://registry.yarnpkg.com/web3-utils/-/web3-utils-1.7.3.tgz#b214d05f124530d8694ad364509ac454d05f207c" + integrity sha512-g6nQgvb/bUpVUIxJE+ezVN+rYwYmlFyMvMIRSuqpi1dk6ApDD00YNArrk7sPcZnjvxOJ76813Xs2vIN2rgh4lg== + dependencies: + bn.js "^4.11.9" + ethereum-bloom-filters "^1.0.6" + ethereumjs-util "^7.1.0" + ethjs-unit "0.1.6" + number-to-bn "1.7.0" + randombytes "^2.1.0" + utf8 "3.0.0" + web3-utils@^1.3.6, web3-utils@^1.5.2: version "1.10.0" resolved "https://registry.yarnpkg.com/web3-utils/-/web3-utils-1.10.0.tgz#ca4c1b431a765c14ac7f773e92e0fd9377ccf578" @@ -8152,6 +8968,19 @@ web3-utils@^1.3.6, web3-utils@^1.5.2: randombytes "^2.1.0" utf8 "3.0.0" +web3@1.7.3: + version "1.7.3" + resolved "https://registry.yarnpkg.com/web3/-/web3-1.7.3.tgz#30fe786338b2cc775881cb28c056ee5da4be65b8" + integrity sha512-UgBvQnKIXncGYzsiGacaiHtm0xzQ/JtGqcSO/ddzQHYxnNuwI72j1Pb4gskztLYihizV9qPNQYHMSCiBlStI9A== + dependencies: + web3-bzz "1.7.3" + web3-core "1.7.3" + web3-eth "1.7.3" + web3-eth-personal "1.7.3" + web3-net "1.7.3" + web3-shh "1.7.3" + web3-utils "1.7.3" + web3@^1.10.0: version "1.10.4" resolved "https://registry.yarnpkg.com/web3/-/web3-1.10.4.tgz#5d5e59b976eaf758b060fe1a296da5fe87bdc79c" @@ -8342,6 +9171,13 @@ xhr-request@^1.0.1, xhr-request@^1.1.0: url-set-query "^1.0.0" xhr "^2.0.4" +xhr2-cookies@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/xhr2-cookies/-/xhr2-cookies-1.1.0.tgz#7d77449d0999197f155cb73b23df72505ed89d48" + integrity sha512-hjXUA6q+jl/bd8ADHcVfFsSPIf+tyLIjuO9TwJC9WI6JP2zKcS7C+p56I9kCLLsaCiNT035iYvEUUzdEFj/8+g== + dependencies: + cookiejar "^2.1.1" + xhr@^2.0.4, xhr@^2.3.3: version "2.6.0" resolved "https://registry.yarnpkg.com/xhr/-/xhr-2.6.0.tgz#b69d4395e792b4173d6b7df077f0fc5e4e2b249d" @@ -8405,6 +9241,11 @@ yargs-parser@^20.2.2: resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== +yargs-parser@^21.1.1: + version "21.1.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" + integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== + yargs-unparser@1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-1.6.0.tgz#ef25c2c769ff6bd09e4b0f9d7c605fb27846ea9f" @@ -8453,6 +9294,19 @@ yargs@16.2.0: y18n "^5.0.5" yargs-parser "^20.2.2" +yargs@^17.5.1: + version "17.7.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" + integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== + dependencies: + cliui "^8.0.1" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.3" + y18n "^5.0.5" + yargs-parser "^21.1.1" + yocto-queue@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" From ce2ec6399723d3958d231beb3e2bdf99cb36effa Mon Sep 17 00:00:00 2001 From: Domen Grabec Date: Mon, 6 May 2024 14:29:13 +0200 Subject: [PATCH 027/273] fix unit tests --- contracts/deploy/deployActions.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/contracts/deploy/deployActions.js b/contracts/deploy/deployActions.js index 625f4c1840..39651d573a 100644 --- a/contracts/deploy/deployActions.js +++ b/contracts/deploy/deployActions.js @@ -584,8 +584,7 @@ const deployOETHHarvester = async (oethDripper) => { await withConfirmation( // prettier-ignore - cOETHHarvesterProxy - .connect(sGovernor)["initialize(address,address,bytes)"]( + cOETHHarvesterProxy["initialize(address,address,bytes)"]( dOETHHarvester.address, governorAddr, [] From fe12d23acd1b953d28982eeee4b5a99509ec881f Mon Sep 17 00:00:00 2001 From: Domen Grabec Date: Tue, 7 May 2024 17:36:52 +0200 Subject: [PATCH 028/273] fix global hooks filter --- contracts/test/_global-hooks.js | 24 +++++++++++++++++------- contracts/test/helpers.js | 2 ++ 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/contracts/test/_global-hooks.js b/contracts/test/_global-hooks.js index 0ad9877e84..3492812b2d 100644 --- a/contracts/test/_global-hooks.js +++ b/contracts/test/_global-hooks.js @@ -1,6 +1,6 @@ const mocha = require("mocha"); -const { isForkTest, isArbFork, isHoleskyFork } = require("./helpers"); +const { isMainnetForkTest, isArbFork, isHoleskyFork } = require("./helpers"); const _chunkId = Number(process.env.CHUNK_ID); const _maxChunks = Number(process.env.MAX_CHUNKS); @@ -34,12 +34,22 @@ mocha.before(function () { // If you are running unit tests, scrape out all fork tests. // For fork tests, scrape out all unit tests. - root.suites = root.suites.filter( - (s) => - s.file.endsWith(".fork-test.js") == isForkTest || - s.file.endsWith(".holesky-fork-test.js") == isHoleskyFork || - s.file.endsWith(".arb.fork-test.js") == isArbFork - ); + root.suites = root.suites.filter((s) => { + const isMainnetForkTestFile = s.file.endsWith(".fork-test.js"); + const isHoleskyTestFile = s.file.endsWith(".holesky-fork-test.js"); + const isArbTestFile = s.file.endsWith(".arb.fork-test.js"); + + if (isMainnetForkTest) { + return isMainnetForkTestFile; + } else if (isHoleskyFork) { + return isHoleskyTestFile; + } else if (isArbFork) { + return isArbTestFile; + } else { + // else is unit test + return !isMainnetForkTestFile && !isHoleskyTestFile && !isArbTestFile; + } + }); if (!runTestsParallely) { // When running serially diff --git a/contracts/test/helpers.js b/contracts/test/helpers.js index 407d54dd60..87bbdd6ec9 100644 --- a/contracts/test/helpers.js +++ b/contracts/test/helpers.js @@ -261,6 +261,7 @@ const isSmokeTest = process.env.SMOKE_TEST === "true"; const isMainnetOrFork = isMainnet || (isFork && process.env.FORK_NETWORK_NAME == "mainnet"); const isForkTest = isFork && isTest; +const isMainnetForkTest = isForkTest && hre.network.config.chainId == 1; const isForkWithLocalNode = isFork && process.env.LOCAL_PROVIDER_URL; const isArbitrumOne = hre.network.name == "arbitrumOne"; const isTestnetSimplifiedDeploy = isHolesky; @@ -791,6 +792,7 @@ module.exports = { isLocalhost, isMainnetOrFork, isForkTest, + isMainnetForkTest, isForkWithLocalNode, isArbitrumOne, isHolesky, From c61c9bb4afb8cc6ced3d2916d02c273b76ae3a69 Mon Sep 17 00:00:00 2001 From: Domen Grabec Date: Tue, 7 May 2024 17:57:53 +0200 Subject: [PATCH 029/273] add github workflow --- .github/workflows/defi.yml | 40 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/.github/workflows/defi.yml b/.github/workflows/defi.yml index 3cc78c00a7..1ab9d8fa60 100644 --- a/.github/workflows/defi.yml +++ b/.github/workflows/defi.yml @@ -178,6 +178,46 @@ jobs: ./contracts/coverage.json ./contracts/coverage/**/* retention-days: 1 + + contracts-arb-forktest: + name: "Holesky Fork Tests" + runs-on: ubuntu-latest + continue-on-error: true + env: + HARDHAT_CACHE_DIR: ./cache + PROVIDER_URL: ${{ secrets.PROVIDER_URL }} + HOLESKY_PROVIDER_URL: ${{ secrets.HOLESKY_PROVIDER_URL }} + steps: + - uses: actions/checkout@v3 + + - name: Use Node.js + uses: actions/setup-node@v3 + with: + node-version: "16.x" + cache: "yarn" + cache-dependency-path: contracts/yarn.lock + + - uses: actions/cache@v3 + id: hardhat-cache + with: + path: contracts/cache + key: ${{ runner.os }}-hardhat-${{ hashFiles('contracts/cache/*.json') }} + restore-keys: | + ${{ runner.os }}-hardhat-cache + + - run: yarn install --frozen-lockfile + working-directory: ./contracts + + - run: yarn run test:coverage:hol-fork + working-directory: ./contracts + + - uses: actions/upload-artifact@v3 + with: + name: fork-test-arb-coverage-${{ github.sha }} + path: | + ./contracts/coverage.json + ./contracts/coverage/**/* + retention-days: 1 coverage-uploader: name: "Upload Coverage Reports" From 7e2e640614fed274fb699c8a4eb999ee85f36441 Mon Sep 17 00:00:00 2001 From: Domen Grabec Date: Tue, 7 May 2024 18:07:47 +0200 Subject: [PATCH 030/273] another workflow fix --- .github/workflows/defi.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/defi.yml b/.github/workflows/defi.yml index 1ab9d8fa60..384cf09438 100644 --- a/.github/workflows/defi.yml +++ b/.github/workflows/defi.yml @@ -179,7 +179,7 @@ jobs: ./contracts/coverage/**/* retention-days: 1 - contracts-arb-forktest: + contracts-hol-forktest: name: "Holesky Fork Tests" runs-on: ubuntu-latest continue-on-error: true From af8ea036a80ce7df5bc4eb115db4e222def8acb1 Mon Sep 17 00:00:00 2001 From: Domen Grabec Date: Tue, 7 May 2024 18:08:13 +0200 Subject: [PATCH 031/273] another workflow fix --- .github/workflows/defi.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/defi.yml b/.github/workflows/defi.yml index 384cf09438..38508e73a9 100644 --- a/.github/workflows/defi.yml +++ b/.github/workflows/defi.yml @@ -226,6 +226,7 @@ jobs: - contracts-unit-coverage - contracts-forktest - contracts-arb-forktest + - contracts-hol-forktest steps: - uses: actions/checkout@v3 From 32480dd11a027111854f8e007749699b0f0dcf1f Mon Sep 17 00:00:00 2001 From: Domen Grabec Date: Tue, 7 May 2024 19:58:14 +0200 Subject: [PATCH 032/273] fix holesky tests --- contracts/test/behaviour/ssvStrategy.js | 11 +++++++++-- contracts/test/helpers.js | 4 ++-- .../strategies/nativeSsvStaking.holesky-fork-test.js | 8 ++++---- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/contracts/test/behaviour/ssvStrategy.js b/contracts/test/behaviour/ssvStrategy.js index 5aeec4864e..198fb01b7a 100644 --- a/contracts/test/behaviour/ssvStrategy.js +++ b/contracts/test/behaviour/ssvStrategy.js @@ -4,12 +4,14 @@ const { setBalance, setStorageAt, } = require("@nomicfoundation/hardhat-network-helpers"); +const hre = require("hardhat"); const { oethUnits } = require("../helpers"); const addresses = require("../../utils/addresses"); const { impersonateAndFund } = require("../../utils/signers"); const { getClusterInfo } = require("../../utils/ssv"); const { parseEther } = require("ethers/lib/utils"); +const { setERC20TokenBalance } = require("../_fund"); /** * @@ -135,9 +137,10 @@ const shouldBehaveLikeAnSsvStrategy = (context) => { .transfer(nativeStakingSSVStrategy.address, oethUnits("32")); }); - it("Should register and staked 32 ETH by validator registrator", async () => { + it.only("Should register and staked 32 ETH by validator registrator", async () => { const { weth, + ssv, nativeStakingSSVStrategy, validatorRegistrator, testValidator, @@ -156,6 +159,8 @@ const shouldBehaveLikeAnSsvStrategy = (context) => { const stakeAmount = oethUnits("32"); + await setERC20TokenBalance(nativeStakingSSVStrategy.address, ssv, "1000", hre); + // Register a new validator with the SSV Network const regTx = await nativeStakingSSVStrategy .connect(validatorRegistrator) @@ -196,8 +201,9 @@ const shouldBehaveLikeAnSsvStrategy = (context) => { ); }); - it("Should exit and remove validator by validator registrator", async () => { + it.only("Should exit and remove validator by validator registrator", async () => { const { + ssv, nativeStakingSSVStrategy, ssvNetwork, validatorRegistrator, @@ -213,6 +219,7 @@ const shouldBehaveLikeAnSsvStrategy = (context) => { }); const stakeAmount = oethUnits("32"); + await setERC20TokenBalance(nativeStakingSSVStrategy.address, ssv, "1000", hre); // Register a new validator with the SSV network const regTx = await nativeStakingSSVStrategy diff --git a/contracts/test/helpers.js b/contracts/test/helpers.js index 87bbdd6ec9..bf9d563032 100644 --- a/contracts/test/helpers.js +++ b/contracts/test/helpers.js @@ -259,14 +259,14 @@ const isExternalNet = isMainnet || isHolesky; const isTest = process.env.IS_TEST === "true"; const isSmokeTest = process.env.SMOKE_TEST === "true"; const isMainnetOrFork = - isMainnet || (isFork && process.env.FORK_NETWORK_NAME == "mainnet"); + isMainnet || (isFork && hre.network.config.chainId == 1); const isForkTest = isFork && isTest; const isMainnetForkTest = isForkTest && hre.network.config.chainId == 1; const isForkWithLocalNode = isFork && process.env.LOCAL_PROVIDER_URL; const isArbitrumOne = hre.network.name == "arbitrumOne"; const isTestnetSimplifiedDeploy = isHolesky; const isArbFork = isFork && process.env.FORK_NETWORK_NAME == "arbitrumOne"; -const isHoleskyFork = isFork && process.env.FORK_NETWORK_NAME == "holesky"; +const isHoleskyFork = isFork && hre.network.config.chainId == 17000; const isHoleskyOrFork = isHolesky || isHoleskyFork; const isArbitrumOneOrFork = isArbitrumOne || isArbFork; const isCI = process.env.GITHUB_ACTIONS; diff --git a/contracts/test/strategies/nativeSsvStaking.holesky-fork-test.js b/contracts/test/strategies/nativeSsvStaking.holesky-fork-test.js index f5447b1dcd..babdd482ef 100644 --- a/contracts/test/strategies/nativeSsvStaking.holesky-fork-test.js +++ b/contracts/test/strategies/nativeSsvStaking.holesky-fork-test.js @@ -28,14 +28,14 @@ describe("Holesky ForkTest: Native SSV Staking Strategy", function () { ), testValidator: { publicKey: - "0xb279166b18ca9ced3e0a83385799ae33b27c6cd2ad2083b9b7c33c555d091933a09b1af9fb65c6c4d51c40ca931447a9", + "0x8c463b743efcea2acd67357acce713519444f4d55ece45fba603d66f488e69a781ba9592f017cb3d47ce6e35f10bc5f7", operatorIds: [111, 119, 230, 252], sharesData: - "0xb1edfddfdf70c8c56cfba3f00ae09815db2383c4faa328733df73dd4616492a58648d543642078c72e2bad60a22322d70ea44cc953c05aa0404681fb57498daa9cbd5c8cc98f736c75a8bf908f0eb98d6448b6778f35b1ce724fee8a1bb53f9ab60f29c5fc7c53e1577a27581b8aff689ac2fdeda72e9620f6991edb7779acef68ed2e6ea4ccfaecd00ccac09b7ed8b7abc72ea5c5469e1b5603c73fe3d054e074c88446c4e31abbc34ee309022524da5aacecb4aa83bf0ac658931813a402e4a4b1d9f83d54404b730e04e61dc82e872fa397e3a9ea249715c861ef0d4b309fdba762cd07f0506925a7a4e3e52d2c0e8f07ae01b8bb393df14c17648340c55e3a82564efb943de4033308d197d562c8bf377a589c87e4c7757afe5964ec92a616622138797c4a647dda550e3b94e3a6152cdda20d4a7b491218ab7df46a2eb9c3963811bf0555b272bf4ef5a8c0c2496e133d1cc34b01c7a5cb40d379e607d0bd7f0d8fcb965ab8d5c7634d80dbd3fac67227b53ec6fbd1a5207bfea8cb202ac88fef732328a2b717b6284af9f34a251e5ecf5eb744a4cf4df35abb423ca02556df957cd8bc645b83d497235b92f310996748c54a89106937cfcf182744ad423b104ca0a61a351d15aa9ae98093f64de31e14a7203304021ebbe2ee0e3f91e1641ff7da84396a83643101cfe67640c05467ffa8de458ebb4db0fcffe9210b72c50f8835cb636e1f5e7356092f15b29fb11761ce36a6601d599eb02d82aa02ce300a7e6c538ca72133036e5f3634c29b27c66964f65086e3f725d535f5e7d92f6a0b589a71caa7d0ca572c5192fe6ef5a4b44ad05cbb8c214a444a399b035263a1d2853bfe43b457873e700be599d3ff03532df1f52be09f6607acfc466f8bb4c4d98d74908c7394d516b738a6143a5456dc43a45f1f00a6515e11b5efc6f4dabfb3d967941ac159a8b6f7c464760c4770082b1d97600cabb1dc286d20c321e6bcb36138507915c399d8639d8a66143bff1f5a6d6cb63d0a8b560134dab42e9d23100c05e51104e068c0c76ecb5382d04e34375efea6467dfb096f6dc12b67609ea1d8310044ab8e80f75341b4aa3eb8dd5f465a3dc6b3f1dea8f25c77cdc34f0eb04247c1ac73bde467c8048cc4d57afefcb33de7520048baeaa9401fc175061881d5c60c89a4fe71cf6af8ed7ba3f6b5da42ef2ee5454f422ecf0b02d09f1ba77d35b56240232237810ffe4ff8e49c4a40a9aab7880ea91472440f30b22797f97d90a68e7904513a4267af47d988d96a17c5a2e90c4ad7c6fb56de8ba7e5488cfc16d1015963e2778e2b3def5ffdda1439cf8750b5823e31f4ba59f1eaf17c7ee98a69495a3c38c177175554b343c21f91a708c6313f146bbdde18b1fcead4e0d0274c8c1010c96f79b81060b850ab5c1da001fc908e45b84d57837fbbd272a4349261e500ce56560939cba45a58f2d0bdba3c6631e52d4e0b7a29ea50f14ed36c1ccb5fca6fdc45f881764b3ee39949ef5df255d9afdedfdf390409dadd31df7540d25174cf21a33dce1a2fd6097967be67267aa7e9353db71821bd89db0b3887eebc01cb64a4116edefac323fdde618a34d91545bab38f920e8e6f38b22a3a243b261fd56f0ec1ff6187b3ed42ddeeadf2c7a78c154d44ab332e293ca2b03e77ae1fe628378e336bc73149df4d7cbc86df73d04b9d35a9fe6a87a865f92337a8df10d5a5cf4dcc6cfba73bdd9b13d3b671acfc829b87f869ed42a48ced74099f92ac79721a79ac93d7c4d5e9be780fe1a78f807fd6a222fac05c3c8b9cd4182cb84617abaa72815b5dceec1d58b1278bf90498e4be3a456428866170046c", + "0x8cc3e43193adde4dba3109918a1be4fbeaeb3c446d3859d689578342bc4a8cc14b02d06e7beba6aa68b71b4de3d9d337137a98dae8299e7ae06250357fd355d1380b0a2da2c35b821cfa39bb24cac3867cd6693ab3e9f85b49d936e54fbb87a180108acfe3f6f757875477614f83758ae09b8f6f8aa42b32c84933d8dcd2cb67f587fcbd0c23797758a4472495f86d9da1906636e26632ab876c9e8923ea9bc4a20ca1c37d019ee9763467964a2535210a2beeee39d93d164e0df34d1e382b4b8d3ea82e799e5d41b8edd17be893d646a27815750b08ef1ca1e136c3ce08cbed4980ccf72de6ecee53d53784c16228cd83dabc6f3db1872c323169f653d49b5214723c35117deb7f944a9dde9d0b11446673744f212f3797e748d8c9ad1e8737a58af47b050d99556254d347854cae6211826b668b92a878e676bee46d393e4701eb342a4667cbf4880614853e316b2e4b849eedd27a9243aac4cd0b8ca3c1186ae51fec04d9f95017d69b3a7b25d389d46b8f2571b4983fe42b7f718fd12f5197414ba73ce98a8a0df2bf5d8d7f71bde9b324535bd8c2f5cc89b24d985975707a79e0c59bf416a39b501963655276b97b9545988c479ccee25cefdd8786b1586b97cc922a3c46445e1e0495a36243abaa40bedf09a41fc90cf9d65eebbc50b931f5c598b0d12e0aaf38923ffb19ce6bebbd324692e5fdebee5716e3afa91c3b0a589afb04896c04d87abd4742ea2b03922922adc9badc1a92ded6d5c73b820d430c40ce9ce9c559caa400f6b880982b78c71db8d0b38c982a8b15776dc5f1290592ca5cc99ebe4d4677177243db86c0cfab9979e37f821bc6a1070fa0d9b7c1b5eeff393034b0b8d8cb8089960dcd9db47d4c7cd88e67ad40dc1857d7c655554d0771aa14810a18c3cd38f930adb8734992882b7942c001c971196ebc2ed74b5a7559127fa8f0561cb6ad5efccc2b8be858773b523ef6611430f05e878aa4e560e3bfbcab47777fc6763f1ab1957fa5cbf663f1cd3238022d0e1348b56726eaee420909acd2b8017ef9c2308baf58cc85d56270a6e85fca636a8b49eba6650d514edd95bebe464843f154559bc1019c6f303df43bebb2110e4f2f4df7e36e03869be204fd2b966f3c328ee3b642510da3ced59f82ff61702529a9ed80c8b3899eeb8865e9483b159e0e2f750181e60a5454cdfb3e15d3ba76b3f2cf38a281dbbe266dd4d210920a8bd6ac1eec1ab13faadb4372b323e23f804a9ea303f4806fdf470f5df08e8d6a9ee3fb0c93dff220087d6129943b5626756664e9d649f83085e439d964337134e0bccd15338a988f238a2ac03a5e29e20fe9477a32347ca45932992b433d7eda470052980d07018919d91613f3925d6bed5dea7cacf246c71321dc371809e3b8b94cb779c3811b5ff11f6c9dd19cb05cc6bc21c75b0366c9809472bd10e54f10acaec6f3266665dfa4a05676dad0d2e3958e74443631aa8c52ee02e0ae6a8019f19c0118e472a9b3aab1ca618413e22edb82ee976deb4d1c44c6609a14954957b389ff38ef08a6ad0cf067a70e485ad0d8aff075f16bc1f9374ec6b9fc5ebd76dbe118bcfe14fba8669687603edcbdfb845d79f2f9847476542a84045589bfb6ff80dce7757527b96af96c85e6109a21e64303d4ada08b1093ac6ef4354c233fa4bcddb86af7f2e0cc836d3076ac62a903f1b74026049046b8460717c101dd5e674eeded11d0fa3e61f2f17f296192a2385f8abd576893d72163d0707b0201c391b1d55a63deee508e9e982ffd623fdbf5ac171fdffa87dda6b8662504cf69fc6e91617dc9e846fdb1f4ca93de618ea763915a13426ee7b8", signature: - "0xa450d596551c7fb7aca201e9a075b034d8da1ec7bf8806740ca53c0e8653465ed9cd26d6ce10290581586676eb0dd896022a243dc42179337c9c4c2a60969a11bb9e4a2dcf57a783daf880999f6db34d1e42163cb96287b3bb91b03361942b80", + "0x83284a7b54224056515bcd0ade22521881755a31d15410d911a9d680a7b7fbf34707118881a880aad04bff2ea58595660a057f6a9889b869246c10d2da0cf243f7b78ab705b71d37cfa282fbeaeeee3092848148b818fe5e764f5d1c09ee6fd9", depositDataRoot: - "0x3f327f69bb527386ff4c2f820e6e375fcc632b1b7ee826bd53d4d2807cfd6769", + "0xf867a406f19c798b5fef29e37a5e7a0eb9b75ffcbeb72b7f337628ccebd3d73a", }, }; }); From 0fb09eabea8cbe207175635d890fcabba87d975c Mon Sep 17 00:00:00 2001 From: Domen Grabec Date: Tue, 7 May 2024 20:02:04 +0200 Subject: [PATCH 033/273] remove the .only --- contracts/test/behaviour/ssvStrategy.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/test/behaviour/ssvStrategy.js b/contracts/test/behaviour/ssvStrategy.js index 198fb01b7a..80f0a766b9 100644 --- a/contracts/test/behaviour/ssvStrategy.js +++ b/contracts/test/behaviour/ssvStrategy.js @@ -137,7 +137,7 @@ const shouldBehaveLikeAnSsvStrategy = (context) => { .transfer(nativeStakingSSVStrategy.address, oethUnits("32")); }); - it.only("Should register and staked 32 ETH by validator registrator", async () => { + it("Should register and staked 32 ETH by validator registrator", async () => { const { weth, ssv, @@ -201,7 +201,7 @@ const shouldBehaveLikeAnSsvStrategy = (context) => { ); }); - it.only("Should exit and remove validator by validator registrator", async () => { + it("Should exit and remove validator by validator registrator", async () => { const { ssv, nativeStakingSSVStrategy, From c7175bbd05abfeeed028d0dd56f0426a6ca8340c Mon Sep 17 00:00:00 2001 From: Domen Grabec Date: Tue, 7 May 2024 21:35:08 +0200 Subject: [PATCH 034/273] prettier --- contracts/test/behaviour/ssvStrategy.js | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/contracts/test/behaviour/ssvStrategy.js b/contracts/test/behaviour/ssvStrategy.js index 80f0a766b9..a28d47294e 100644 --- a/contracts/test/behaviour/ssvStrategy.js +++ b/contracts/test/behaviour/ssvStrategy.js @@ -159,7 +159,12 @@ const shouldBehaveLikeAnSsvStrategy = (context) => { const stakeAmount = oethUnits("32"); - await setERC20TokenBalance(nativeStakingSSVStrategy.address, ssv, "1000", hre); + await setERC20TokenBalance( + nativeStakingSSVStrategy.address, + ssv, + "1000", + hre + ); // Register a new validator with the SSV Network const regTx = await nativeStakingSSVStrategy @@ -219,7 +224,12 @@ const shouldBehaveLikeAnSsvStrategy = (context) => { }); const stakeAmount = oethUnits("32"); - await setERC20TokenBalance(nativeStakingSSVStrategy.address, ssv, "1000", hre); + await setERC20TokenBalance( + nativeStakingSSVStrategy.address, + ssv, + "1000", + hre + ); // Register a new validator with the SSV network const regTx = await nativeStakingSSVStrategy From 69abd8fac5ba74b4d83040cd6986234d55ce9fb0 Mon Sep 17 00:00:00 2001 From: Domen Grabec Date: Thu, 9 May 2024 03:20:47 +0200 Subject: [PATCH 035/273] Sparrow dom/native staking defender action (#2051) * adding defender action task * fix unit tests setup * update the registrator address of the native staking contract * fix up the operate validators script so that it works for native staking on holesky * also add the gitignore * add ability to exit if staking contract is paused --- .gitignore | 3 + contracts/deploy/deployActions.js | 3 +- .../deploy/holesky/006_update_registrator.js | 31 ++++++ .../deployments/holesky/.migrations.json | 3 +- contracts/dev.env | 4 + contracts/package.json | 1 + contracts/tasks/tasks.js | 99 +++++++++++++++++++ contracts/tasks/validator.js | 75 +++++++++----- contracts/utils/addresses.js | 4 +- contracts/utils/signers.js | 20 +++- contracts/utils/time.js | 7 ++ contracts/yarn.lock | 42 +++++++- 12 files changed, 257 insertions(+), 35 deletions(-) create mode 100644 contracts/deploy/holesky/006_update_registrator.js create mode 100644 contracts/utils/time.js diff --git a/.gitignore b/.gitignore index 37f3a25c43..7770a7cb26 100644 --- a/.gitignore +++ b/.gitignore @@ -59,6 +59,9 @@ contracts/coverage/ contracts/coverage.json contracts/build/ contracts/dist/ +contracts/.localKeyValueStorage +contracts/.localKeyValueStorageMainnet +contracts/.localKeyValueStorageHolesky todo.txt brownie/env-brownie/ diff --git a/contracts/deploy/deployActions.js b/contracts/deploy/deployActions.js index 39651d573a..4d1550cf55 100644 --- a/contracts/deploy/deployActions.js +++ b/contracts/deploy/deployActions.js @@ -584,7 +584,8 @@ const deployOETHHarvester = async (oethDripper) => { await withConfirmation( // prettier-ignore - cOETHHarvesterProxy["initialize(address,address,bytes)"]( + cOETHHarvesterProxy + ["initialize(address,address,bytes)"]( dOETHHarvester.address, governorAddr, [] diff --git a/contracts/deploy/holesky/006_update_registrator.js b/contracts/deploy/holesky/006_update_registrator.js new file mode 100644 index 0000000000..c14bc8dcd3 --- /dev/null +++ b/contracts/deploy/holesky/006_update_registrator.js @@ -0,0 +1,31 @@ +const { parseEther } = require("ethers/lib/utils"); + +const { deployNativeStakingSSVStrategy } = require("../deployActions"); +const { withConfirmation } = require("../../utils/deploy"); +const { resolveContract } = require("../../utils/resolvers"); +const addresses = require("../../utils/addresses"); + +const mainExport = async () => { + console.log("Running 006 deployment on Holesky..."); + + const cNativeStakingStrategy = await resolveContract( + "NativeStakingSSVStrategyProxy", + "NativeStakingSSVStrategy" + ); + + await withConfirmation( + cNativeStakingStrategy + // Holesky defender relayer + .setRegistrator(addresses.holesky.validatorRegistrator) + ); + + console.log("Running 006 deployment done"); + return true; +}; + +mainExport.id = "006_update_registrator"; +mainExport.tags = []; +mainExport.dependencies = []; +mainExport.skip = () => false; + +module.exports = mainExport; diff --git a/contracts/deployments/holesky/.migrations.json b/contracts/deployments/holesky/.migrations.json index 7e8f3cdbad..8448ae20e6 100644 --- a/contracts/deployments/holesky/.migrations.json +++ b/contracts/deployments/holesky/.migrations.json @@ -3,5 +3,6 @@ "002_upgrade_strategy": 1714233842, "003_deposit_to_native_strategy": 1714307581, "004_upgrade_strategy": 1714944723, - "005_deploy_new_harvester": 1714998707 + "005_deploy_new_harvester": 1714998707, + "006_update_registrator": 1715184342 } \ No newline at end of file diff --git a/contracts/dev.env b/contracts/dev.env index 874bf5275d..f7754465b6 100644 --- a/contracts/dev.env +++ b/contracts/dev.env @@ -31,3 +31,7 @@ ACCOUNTS_TO_FUND= # need of running migration scripts. # HOT_DEPLOY=strategy,vaultCore,vaultAdmin,harvester + +#P2P API KEYS +P2P_MAINNET_API_KEY=[SET API Key] +P2P_HOLESKY_API_KEY=[SET API Key] \ No newline at end of file diff --git a/contracts/package.json b/contracts/package.json index a45dee4888..973416ddf3 100644 --- a/contracts/package.json +++ b/contracts/package.json @@ -55,6 +55,7 @@ "axios": "^1.4.0", "chai": "^4.3.4", "debug": "^4.3.4", + "defender-kvstore-client": "^1.38.1-rc.0", "dotenv": "^10.0.0", "eslint": "^7.32.0", "ethereum-waffle": "^4.0.10", diff --git a/contracts/tasks/tasks.js b/contracts/tasks/tasks.js index d922fdf25f..55fd7c0b28 100644 --- a/contracts/tasks/tasks.js +++ b/contracts/tasks/tasks.js @@ -5,7 +5,12 @@ const { env } = require("./env"); const { execute, executeOnFork, proposal, governors } = require("./governance"); const { smokeTest, smokeTestCheck } = require("./smokeTest"); const addresses = require("../utils/addresses"); +const { getDefenderSigner } = require("../utils/signers"); const { networkMap } = require("../utils/hardhat-helpers"); +const { resolveContract } = require("../utils/resolvers"); +const { KeyValueStoreClient } = require("defender-kvstore-client"); +const { operateValidators } = require("./validator"); +const { formatUnits } = require("ethers/lib/utils"); const { storeStorageLayoutForAllContracts, @@ -879,3 +884,97 @@ subtask( task("depositSSV").setAction(async (_, __, runSuper) => { return runSuper(); }); + +// Defender +subtask( + "operateValidators", + "Creates the required amount of new SSV validators and stakes ETH" +) + .addOptionalParam("index", "Index of Native Staking contract", 1, types.int) + .addOptionalParam( + "stake", + "Stake 32 ether after registering a new SSV validator", + true, + types.boolean + ) + .addOptionalParam( + "days", + "SSV Cluster operational time in days", + 40, + types.int + ) + .addOptionalParam("clear", "Clear storage", true, types.boolean) + .setAction(async (taskArgs) => { + const network = await ethers.provider.getNetwork(); + const isMainnet = network.chainId === 1; + const isHolesky = network.chainId === 17000; + const addressesSet = isMainnet ? addresses.mainnet : addresses.holesky; + + if (!isMainnet && !isHolesky) { + throw new Error( + "operate validatos is supported on Mainnet and Holesky only" + ); + } + + const storeFilePath = require("path").join( + __dirname, + "..", + `.localKeyValueStorage${isMainnet ? "Mainnet" : "Holesky"}` + ); + + const store = new KeyValueStoreClient({ path: storeFilePath }); + const signer = await getDefenderSigner(); + + const WETH = await ethers.getContractAt("IWETH9", addressesSet.WETH); + const SSV = await ethers.getContractAt("IERC20", addressesSet.SSV); + + // TODO: use index to target different native staking strategies when we have more than 1 + const nativeStakingStrategy = await resolveContract( + "NativeStakingSSVStrategyProxy", + "NativeStakingSSVStrategy" + ); + + log( + "Balance of SSV tokens on the native staking contract: ", + formatUnits(await SSV.balanceOf(nativeStakingStrategy.address)) + ); + + const contracts = { + nativeStakingStrategy, + WETH, + }; + const feeAccumulatorAddress = + await nativeStakingStrategy.FEE_ACCUMULATOR_ADDRESS(); + + const p2p_api_key = isMainnet + ? process.env.P2P_MAINNET_API_KEY + : process.env.P2P_HOLESKY_API_KEY; + if (!p2p_api_key) { + throw new Error( + "P2P API key environment variable is not set. P2P_MAINNET_API_KEY or P2P_HOLESKY_API_KEY" + ); + } + const p2p_base_url = isMainnet ? "api.p2p.org" : "api-test-holesky.p2p.org"; + + const config = { + feeAccumulatorAddress, + p2p_api_key, + p2p_base_url, + // how much SSV (expressed in days of runway) gets deposited into the + // SSV Network contract on validator registration. This is calculated + // at a Cluster level rather than a single validator. + validatorSpawnOperationalPeriodInDays: taskArgs.days, + stake: taskArgs.stake, + clear: taskArgs.clear, + }; + + await operateValidators({ + signer, + contracts, + store, + config, + }); + }); +task("operateValidators").setAction(async (_, __, runSuper) => { + return runSuper(); +}); diff --git a/contracts/tasks/validator.js b/contracts/tasks/validator.js index 566dbef27c..9b9f484238 100644 --- a/contracts/tasks/validator.js +++ b/contracts/tasks/validator.js @@ -5,8 +5,8 @@ const { v4: uuidv4 } = require("uuid"); const { resolveContract } = require("../utils/resolvers"); const { getSigner } = require("../utils/signers"); -const { getClusterInfo } = require("../utils/ssv"); const { sleep } = require("../utils/time"); +const { getClusterInfo } = require("./ssv"); const { logTxDetails } = require("../utils/txLogger"); const log = require("../utils/logger")("task:p2p"); @@ -31,15 +31,17 @@ const ERROR_THRESHOLD = 5; * - if spawn process gets stuck at any of the above steps and is not able to * recover in X amount of times (e.g. 5 times). Mark the process as failed * and start over. + * - TODO: (implement this) if fuse of the native staking strategy is blown + * stop with all the operations */ const operateValidators = async ({ store, signer, contracts, config }) => { const { - clear, - eigenPodAddress, + feeAccumulatorAddress, p2p_api_key, - validatorSpawnOperationalPeriodInDays, p2p_base_url, + validatorSpawnOperationalPeriodInDays, stake, + clear, } = config; let currentState = await getState(store); @@ -50,8 +52,13 @@ const operateValidators = async ({ store, signer, contracts, config }) => { currentState = undefined; } - if (!(await nodeDelegatorHas32Eth(contracts))) { - log(`Node delegator doesn't have enough ETH, exiting`); + if (!(await stakingContractHas32ETH(contracts))) { + log(`Native staking contract doesn't have enough ETH, exiting`); + return; + } + + if (await stakingContractPaused(contracts)) { + log(`Native staking contract is paused... exiting`); return; } @@ -61,8 +68,8 @@ const operateValidators = async ({ store, signer, contracts, config }) => { await createValidatorRequest( p2p_api_key, // api key p2p_base_url, - contracts.nodeDelegator.address, // node delegator address - eigenPodAddress, // eigenPod address + contracts.nativeStakingStrategy.address, // SSV owner address & withdrawal address + feeAccumulatorAddress, // execution layer fee recipient validatorSpawnOperationalPeriodInDays, store ); @@ -85,7 +92,7 @@ const operateValidators = async ({ store, signer, contracts, config }) => { store, currentState.uuid, currentState.metadata, - contracts.nodeDelegator + contracts.nativeStakingStrategy ); currentState = await getState(store); } @@ -94,7 +101,7 @@ const operateValidators = async ({ store, signer, contracts, config }) => { await waitForTransactionAndUpdateStateOnSuccess( store, currentState.uuid, - contracts.nodeDelegator.provider, + contracts.nativeStakingStrategy.provider, currentState.metadata.validatorRegistrationTx, "registerSsvValidator", // name of transaction we are waiting for "validator_registered" // new state when transaction confirmed @@ -109,7 +116,7 @@ const operateValidators = async ({ store, signer, contracts, config }) => { signer, store, currentState.uuid, - contracts.nodeDelegator, + contracts.nativeStakingStrategy, currentState.metadata.depositData ); currentState = await getState(store); @@ -119,7 +126,7 @@ const operateValidators = async ({ store, signer, contracts, config }) => { await waitForTransactionAndUpdateStateOnSuccess( store, currentState.uuid, - contracts.nodeDelegator.provider, + contracts.nativeStakingStrategy.provider, currentState.metadata.depositTx, "stakeEth", // name of transaction we are waiting for "deposit_confirmed" // new state when transaction confirmed @@ -249,14 +256,21 @@ const getState = async (store) => { return JSON.parse(await store.get("currentRequest")); }; -const nodeDelegatorHas32Eth = async (contracts) => { - const address = contracts.nodeDelegator.address; +const stakingContractPaused = async (contracts) => { + const paused = await contracts.nativeStakingStrategy.paused(); + + log(`Native staking contract is ${paused ? "" : "not "}paused`); + return paused; +}; + +const stakingContractHas32ETH = async (contracts) => { + const address = contracts.nativeStakingStrategy.address; const wethBalance = await contracts.WETH.balanceOf(address); - const ethBalance = await contracts.nodeDelegator.provider.getBalance(address); - const totalBalance = wethBalance.add(ethBalance); - log(`Node delegator has ${formatUnits(totalBalance, 18)} ETH in total`); - return totalBalance.gte(parseEther("32")); + log( + `Native staking contract has ${formatUnits(wethBalance, 18)} WETH in total` + ); + return wethBalance.gte(parseEther("32")); }; /* Make a GET or POST request to P2P service @@ -302,8 +316,8 @@ const p2pRequest = async (url, api_key, method, body) => { const createValidatorRequest = async ( p2p_api_key, p2p_base_url, - nodeDelegatorAddress, - eigenPodAddress, + nativeStakingStrategy, + feeAccumulatorAddress, validatorSpawnOperationalPeriodInDays, store ) => { @@ -315,9 +329,10 @@ const createValidatorRequest = async ( { validatorsCount: 1, id: uuid, - withdrawalAddress: eigenPodAddress, - feeRecipientAddress: nodeDelegatorAddress, - ssvOwnerAddress: nodeDelegatorAddress, + withdrawalAddress: nativeStakingStrategy, + feeRecipientAddress: feeAccumulatorAddress, + ssvOwnerAddress: nativeStakingStrategy, + // TODO: we need to alter this and store the key somewhere type: "without-encrypt-key", operationPeriodInDays: validatorSpawnOperationalPeriodInDays, } @@ -346,14 +361,20 @@ const waitForTransactionAndUpdateStateOnSuccess = async ( await updateState(uuid, newState, store); }; -const depositEth = async (signer, store, uuid, nodeDelegator, depositData) => { +const depositEth = async ( + signer, + store, + uuid, + nativeStakingStrategy, + depositData +) => { const { pubkey, signature, depositDataRoot } = depositData; try { log(`About to stake ETH with:`); log(`pubkey: ${pubkey}`); log(`signature: ${signature}`); log(`depositDataRoot: ${depositDataRoot}`); - const tx = await nodeDelegator.connect(signer).stakeEth([ + const tx = await nativeStakingStrategy.connect(signer).stakeEth([ { pubkey, signature, @@ -378,7 +399,7 @@ const broadcastRegisterValidator = async ( store, uuid, metadata, - nodeDelegator + nativeStakingStrategy ) => { const registerTransactionParams = defaultAbiCoder.decode( [ @@ -412,7 +433,7 @@ const broadcastRegisterValidator = async ( log(`cluster: ${cluster}`); try { - const tx = await nodeDelegator + const tx = await nativeStakingStrategy .connect(signer) .registerSsvValidator( publicKey, diff --git a/contracts/utils/addresses.js b/contracts/utils/addresses.js index aa6885e32e..4d2ac56496 100644 --- a/contracts/utils/addresses.js +++ b/contracts/utils/addresses.js @@ -271,6 +271,8 @@ addresses.holesky.beaconChainDepositContract = "0x4242424242424242424242424242424242424242"; addresses.holesky.OETHVaultProxy = "0x19d2bAaBA949eFfa163bFB9efB53ed8701aA5dD9"; +// Address of the Holesky defender relayer addresses.holesky.validatorRegistrator = - "0x1b94CA50D3Ad9f8368851F8526132272d1a5028C"; + "0x3C6B0c7835a2E2E0A45889F64DcE4ee14c1D5CB4"; + module.exports = addresses; diff --git a/contracts/utils/signers.js b/contracts/utils/signers.js index 3ec192d55c..439d6ee07f 100644 --- a/contracts/utils/signers.js +++ b/contracts/utils/signers.js @@ -66,16 +66,29 @@ const getDefenderSigner = async () => { ); process.exit(2); } + + const network = await ethers.provider.getNetwork(); + const isMainnet = network.chainId === 1; + const isHolesky = network.chainId === 17000; + + const apiKeyName = isMainnet + ? "DEFENDER_API_KEY" + : "HOLESKY_DEFENDER_API_KEY"; + const apiKeySecret = isMainnet + ? "DEFENDER_API_SECRET" + : "HOLESKY_DEFENDER_API_SECRET"; + const credentials = { - relayerApiKey: process.env.DEFENDER_API_KEY, - relayerApiSecret: process.env.DEFENDER_API_SECRET, + relayerApiKey: process.env[apiKeyName], + relayerApiSecret: process.env[apiKeySecret], }; + const client = new Defender(credentials); const provider = client.relaySigner.getProvider(); const signer = client.relaySigner.getSigner(provider, { speed }); log( - `Using Defender Relayer account ${await signer.getAddress()} from env vars DEFENDER_API_KEY and DEFENDER_API_SECRET` + `Using Defender Relayer account ${await signer.getAddress()} from env vars ${apiKeyName} and ${apiKeySecret}` ); return signer; }; @@ -112,4 +125,5 @@ module.exports = { getSigner, impersonateAccount, impersonateAndFund, + getDefenderSigner, }; diff --git a/contracts/utils/time.js b/contracts/utils/time.js new file mode 100644 index 0000000000..d761801638 --- /dev/null +++ b/contracts/utils/time.js @@ -0,0 +1,7 @@ +function sleep(ms) { + return new Promise((resolve) => setTimeout(resolve, ms)); +} + +module.exports = { + sleep, +}; diff --git a/contracts/yarn.lock b/contracts/yarn.lock index 2ffb02816b..7b81d1aa61 100644 --- a/contracts/yarn.lock +++ b/contracts/yarn.lock @@ -1799,6 +1799,17 @@ ajv@^8.0.1: require-from-string "^2.0.2" uri-js "^4.2.2" +amazon-cognito-identity-js@^4.3.3: + version "4.6.3" + resolved "https://registry.yarnpkg.com/amazon-cognito-identity-js/-/amazon-cognito-identity-js-4.6.3.tgz#889410379a5fc5e883edc95f4ce233cc628e354c" + integrity sha512-MPVJfirbdmSGo7l4h7Kbn3ms1eJXT5Xq8ly+mCPPi8yAxaxdg7ouMUUNTqtDykoZxIdDLF/P6F3Zbg3dlGKOWg== + dependencies: + buffer "4.9.2" + crypto-js "^4.0.0" + fast-base64-decode "^1.0.0" + isomorphic-unfetch "^3.0.0" + js-cookie "^2.2.1" + amazon-cognito-identity-js@^6.0.1: version "6.2.0" resolved "https://registry.yarnpkg.com/amazon-cognito-identity-js/-/amazon-cognito-identity-js-6.2.0.tgz#99e96666944429cb8f67b62e4cf7ad77fbe71ad0" @@ -2990,6 +3001,11 @@ crypto-browserify@3.12.0: randombytes "^2.0.0" randomfill "^1.0.3" +crypto-js@^4.0.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/crypto-js/-/crypto-js-4.2.0.tgz#4d931639ecdfd12ff80e8186dba6af2c2e856631" + integrity sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q== + crypto@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/crypto/-/crypto-1.0.1.tgz#2af1b7cad8175d24c8a1b0778255794a21803037" @@ -3089,6 +3105,17 @@ deep-is@^0.1.3, deep-is@~0.1.3: resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== +defender-base-client@1.38.1-rc.0: + version "1.38.1-rc.0" + resolved "https://registry.yarnpkg.com/defender-base-client/-/defender-base-client-1.38.1-rc.0.tgz#0d167845648a38bd2f5f80f5c50e081ec5f58b54" + integrity sha512-LNsuop5CE7fYyfWV3C4tlqkZawnxsMKW1SeF8TnobhZ6V5pO9LKyGSOo/V3KvPhO2/cTw5/S66+p1f6nkGCREA== + dependencies: + amazon-cognito-identity-js "^4.3.3" + async-retry "^1.3.3" + axios "^0.21.2" + lodash "^4.17.19" + node-fetch "^2.6.0" + defender-base-client@^1.44.0: version "1.44.0" resolved "https://registry.yarnpkg.com/defender-base-client/-/defender-base-client-1.44.0.tgz#afe724447c0f9177b999b70b9f14dd70d61d5a7a" @@ -3100,6 +3127,17 @@ defender-base-client@^1.44.0: lodash "^4.17.19" node-fetch "^2.6.0" +defender-kvstore-client@^1.38.1-rc.0: + version "1.38.1-rc.0" + resolved "https://registry.yarnpkg.com/defender-kvstore-client/-/defender-kvstore-client-1.38.1-rc.0.tgz#6e33633a90e1355893141bad72298c6727abf30d" + integrity sha512-MeN8CtQSY72QFIys56Phxcn3tQ1nnmDXVtP/RlY9HCMynUO4zOQZaanDkgUmXTb+MYMj5VO3y+qfOfdEE+5EWA== + dependencies: + axios "^0.21.2" + defender-base-client "1.38.1-rc.0" + fs-extra "^10.0.0" + lodash "^4.17.19" + node-fetch "^2.6.0" + defer-to-connect@^1.0.1: version "1.1.3" resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-1.1.3.tgz#331ae050c08dcf789f8c83a7b81f0ed94f4ac591" @@ -6875,9 +6913,9 @@ promise@^8.0.0: dependencies: asap "~2.0.6" -"prompts@git+https://github.com/meshin-blox/prompts.git": +"prompts@https://github.com/meshin-blox/prompts.git": version "2.4.2" - resolved "git+https://github.com/meshin-blox/prompts.git#a22bdac044f6b32ba67adb4eacc2e58322512a2d" + resolved "https://github.com/meshin-blox/prompts.git#a22bdac044f6b32ba67adb4eacc2e58322512a2d" dependencies: kleur "^4.0.1" sisteransi "^1.0.5" From 2f7a9cd57391377c42980dc75b415f9dfc121731 Mon Sep 17 00:00:00 2001 From: Nick Addison Date: Fri, 10 May 2024 08:16:59 +1000 Subject: [PATCH 036/273] Fix fork tests (#2050) * Fixed resolveAsset * Fixed validator fork tests Added error func sigs to ISSVNetwork * Fixed harvester behaviour tests * Fix global hooks * Fix tooling --------- Co-authored-by: Shahul Hameed <10547529+shahthepro@users.noreply.github.com> --- .../contracts/interfaces/ISSVNetwork.sol | 70 +++++++++++-------- contracts/test/_global-hooks.js | 10 +-- .../test/behaviour/reward-tokens.fork.js | 5 +- .../strategies/nativeSsvStaking.fork-test.js | 10 +-- contracts/test/vault/oeth-vault.fork-test.js | 1 + contracts/utils/resolvers.js | 17 +++-- 6 files changed, 66 insertions(+), 47 deletions(-) diff --git a/contracts/contracts/interfaces/ISSVNetwork.sol b/contracts/contracts/interfaces/ISSVNetwork.sol index 9f37388663..f069138177 100644 --- a/contracts/contracts/interfaces/ISSVNetwork.sol +++ b/contracts/contracts/interfaces/ISSVNetwork.sol @@ -10,36 +10,46 @@ struct Cluster { } interface ISSVNetwork { - error ApprovalNotWithinTimeframe(); - error CallerNotOwner(); - error CallerNotWhitelisted(); - error ClusterAlreadyEnabled(); - error ClusterDoesNotExists(); - error ClusterIsLiquidated(); - error ClusterNotLiquidatable(); - error ExceedValidatorLimit(); - error FeeExceedsIncreaseLimit(); - error FeeIncreaseNotAllowed(); - error FeeTooHigh(); - error FeeTooLow(); - error IncorrectClusterState(); - error IncorrectValidatorState(); - error InsufficientBalance(); - error InvalidOperatorIdsLength(); - error InvalidPublicKeyLength(); - error MaxValueExceeded(); - error NewBlockPeriodIsBelowMinimum(); - error NoFeeDeclared(); - error NotAuthorized(); - error OperatorAlreadyExists(); - error OperatorDoesNotExist(); - error OperatorsListNotUnique(); - error SameFeeChangeNotAllowed(); - error TargetModuleDoesNotExist(); - error TokenTransferFailed(); - error UnsortedOperatorsList(); - error ValidatorAlreadyExists(); - error ValidatorDoesNotExist(); + /**********/ + /* Errors */ + /**********/ + + error CallerNotOwner(); // 0x5cd83192 + error CallerNotWhitelisted(); // 0x8c6e5d71 + error FeeTooLow(); // 0x732f9413 + error FeeExceedsIncreaseLimit(); // 0x958065d9 + error NoFeeDeclared(); // 0x1d226c30 + error ApprovalNotWithinTimeframe(); // 0x97e4b518 + error OperatorDoesNotExist(); // 0x961e3e8c + error InsufficientBalance(); // 0xf4d678b8 + error ValidatorDoesNotExist(); // 0xe51315d2 + error ClusterNotLiquidatable(); // 0x60300a8d + error InvalidPublicKeyLength(); // 0x637297a4 + error InvalidOperatorIdsLength(); // 0x38186224 + error ClusterAlreadyEnabled(); // 0x3babafd2 + error ClusterIsLiquidated(); // 0x95a0cf33 + error ClusterDoesNotExists(); // 0x185e2b16 + error IncorrectClusterState(); // 0x12e04c87 + error UnsortedOperatorsList(); // 0xdd020e25 + error NewBlockPeriodIsBelowMinimum(); // 0x6e6c9cac + error ExceedValidatorLimit(); // 0x6df5ab76 + error TokenTransferFailed(); // 0x045c4b02 + error SameFeeChangeNotAllowed(); // 0xc81272f8 + error FeeIncreaseNotAllowed(); // 0x410a2b6c + error NotAuthorized(); // 0xea8e4eb5 + error OperatorsListNotUnique(); // 0xa5a1ff5d + error OperatorAlreadyExists(); // 0x289c9494 + error TargetModuleDoesNotExist(); // 0x8f9195fb + error MaxValueExceeded(); // 0x91aa3017 + error FeeTooHigh(); // 0xcd4e6167 + error PublicKeysSharesLengthMismatch(); // 0x9ad467b8 + error IncorrectValidatorStateWithData(bytes publicKey); // 0x89307938 + error ValidatorAlreadyExistsWithData(bytes publicKey); // 0x388e7999 + error EmptyPublicKeysList(); // df83e679 + + // legacy errors + error ValidatorAlreadyExists(); // 0x8d09a73e + error IncorrectValidatorState(); // 0x2feda3c1 event AdminChanged(address previousAdmin, address newAdmin); event BeaconUpgraded(address indexed beacon); diff --git a/contracts/test/_global-hooks.js b/contracts/test/_global-hooks.js index 3492812b2d..68e3cd9a9f 100644 --- a/contracts/test/_global-hooks.js +++ b/contracts/test/_global-hooks.js @@ -39,15 +39,15 @@ mocha.before(function () { const isHoleskyTestFile = s.file.endsWith(".holesky-fork-test.js"); const isArbTestFile = s.file.endsWith(".arb.fork-test.js"); - if (isMainnetForkTest) { - return isMainnetForkTestFile; + if (isArbFork) { + return isArbTestFile; + } else if (isMainnetForkTest) { + return isMainnetForkTestFile && !isArbTestFile; } else if (isHoleskyFork) { return isHoleskyTestFile; - } else if (isArbFork) { - return isArbTestFile; } else { // else is unit test - return !isMainnetForkTestFile && !isHoleskyTestFile && !isArbTestFile; + return !isMainnetForkTestFile && !isHoleskyTestFile; } }); diff --git a/contracts/test/behaviour/reward-tokens.fork.js b/contracts/test/behaviour/reward-tokens.fork.js index 068ff475ae..d0c48eb779 100644 --- a/contracts/test/behaviour/reward-tokens.fork.js +++ b/contracts/test/behaviour/reward-tokens.fork.js @@ -14,6 +14,7 @@ const { BigNumber } = require("ethers"); shouldHaveRewardTokensConfigured(() => ({ harvester: fixture.harvester, vault: fixture.vault, + ignoreTokens: [fixture.weth.address.toLowerCase()], expectedConfigs: { [fixture.cvx.address]: { allowedSlippageBps: 300, @@ -46,7 +47,7 @@ const shouldHaveRewardTokensConfigured = (context) => { describe("Reward Tokens", () => { it("Should have swap config for all reward tokens from strategies", async () => { - let { vault, harvester, expectedConfigs } = context(); + let { vault, harvester, expectedConfigs, ignoreTokens } = context(); const strategies = await vault.getAllStrategies(); expectedConfigs = Object.keys(expectedConfigs).reduce( @@ -57,7 +58,7 @@ const shouldHaveRewardTokensConfigured = (context) => { {} ); - const checkedConfigs = []; + const checkedConfigs = ignoreTokens || []; for (const strategyAddr of strategies) { const strategy = await ethers.getContractAt("IStrategy", strategyAddr); diff --git a/contracts/test/strategies/nativeSsvStaking.fork-test.js b/contracts/test/strategies/nativeSsvStaking.fork-test.js index 3652fa8955..12b502c26d 100644 --- a/contracts/test/strategies/nativeSsvStaking.fork-test.js +++ b/contracts/test/strategies/nativeSsvStaking.fork-test.js @@ -21,14 +21,14 @@ describe("ForkTest: Native SSV Staking Strategy", function () { addresses: addresses.mainnet, testValidator: { publicKey: - "0xad9ade40c386259fe4161ec12d7746ab49a098a4760a279c56dc7e26b56fc4d985e74eeecdd2bc5a1decceb5174204f4", - operatorIds: [193, 196, 199, 202], + "0x93d60259213f491a910ee8f6504d51ba5fc28085981eccd6c20ca646525c626013c75b04f061fbf3de839ac602c64698", + operatorIds: [348, 352, 361, 377], sharesData: - "0x8308e4b6ad536304f978077a0cd3685a98d5847bb1b05e0a4c5994ddf64ce48daa917f666d86f3125aac139a4fc7b07119ea2c7fc0fe5cfb316a5687dbddf621b0229e55230f0857d426697513ee2556d2c730595268358ebe8e16331bd2dd53acfd93e4e96c5fb510f78dc0f11e5097f83b2609a5711b233fa843935125dbbd90e43dc4f7d181221a42fcc02fe58aeb90fefb6a1d46faad099b6fa8e68351ff21f52d90a96bffeb33d1c0517bf39e413a441f1c290f1289021e9bd47146689ba139bccfaf7d6d1a6fba03c177d9ffca11f347b0f16a1cd8b1808a9b46ec0849ff45562a853ea137dfea3a0ed43ceac5805a993edd6b618cf7aa1441b2deeb2a7a573f0a44d9ed6bffb75573a91e9de2c21e198815d9b133ce7060ff339bf23b12af3c15f566b81842f307066205f09b40b4db045af881f5ca571289d1aa52555002544e8941b854b1b565b5e76c845c4b287a46890d6ad3e01185d2fb5485ecb136814a23378d37ff53244c1420af43db268f74bf0532dd235cb2afd49d1dce7158d1f51650bc32b790f29bdfc2bafc9990a55a15d005139c6ede259a6a9426400d67192ec697a8990c326bc63fe8a809515d0cc311059da2e333cb92331c45ac8b8d2e09a8cc4092016ade9f90a4b1a89a89f9da38818a5a77f84ae2aba340719dc6a01810ddfcd9e9cf9ebfab033363d2a58296cd1ab8e33ea4e04738111a3e2d80d34c601b0b49e95412cdd554a844f02a94f7f239e70cb72247c36218de79b5d0d73a7429cccf1999eca2611b1c486e8148451cac60bc60280764948f54100a39d9290c368a2ace60daa3ff1bf9dd7514afd02397c196b9cee8ef94478619a114cbebdf4475053857f2728c7621c5fb6739cbf8a15727c5d15a354e20ac054f31e51288a4f94a4215d00d23d2e5a82f745f2f15d6b147ecf817165913f2f72f492075de8f339efe54f163311f7de056c36a900949f7f026c17a96770edd29ba0301732bb83d218a0fb28d466858118e7240725ee74a45fd3acf8ca7310cb72f6cb3c6f8517b89984ad622ffeb39dad587d2e944d59fe849841fc5f09e9f1935cc59b10c795446eb18a2f87e6ee1a497fe0bb556164cd2d7b5c7cf5fdb758e8fc26711116bf59a08be68d2ddb9a97300d2ac43055877a0cc3be97c8b82ceb5dd59f6222c23d849dc7620ffca0393d685cb609059e0e8a76500c9c92d7878a3939c346897d10c6707d39bd10d0f546f6506b6b087dea16156478e11d9537d169d582ca26a04dceede25a38b5a4bf2e16db9db97bdb320f198632a0b60af8ebdf3e6a0bda19f34c9ddc7e437d3fef3da021cae41dd99d2898d825db9de51561dee2a5587fa75453609fff5aec3e949a34fd438f00ab6dbca03e385059003936db14c66d4fec38d6ba729051866c336c51c802507dc5b16b591a4905636736a05bbd0d39ba965de131abad34797e3521ff01612b1bd17aca6af61abf8bd24182a1e2848fc41819c0ce7065000747023db82de23eef601ed7cdaffd39b005e8bb8156f4986d9825e62cd2f13f8c0e33e5825e8d81730ef1a63dfd19af6afd08f9f102f403783dca89173456d9e60fb72b2c153bf0bb73bed799a15eb94923f7cadd9c9bc529a86051d8202b1af53ccb161179f9c4609084dd977091082fc14c20ff21efd70bb9ca56b0ea80c7fc16e2f1718c7b306944fa6c7572440c7d6035a22cea8858f64bb3b6d147a05743021ca1b79d71bac87888bb5fd343b1817a28dda336f1d640f8adae159020deba8d3e1e97ae0b9a4ba23112e59d93169a7b875fc878f66f13b2568ed326f9da7ba6c2bd08d37f5b0ef6bfe56febe20e366fa9d", + "0x861fce88da51de578b2a3f9fa32b3c56499b1261d33f8adbb24932cc906edfd6383b63ac37bfd8b2e9f7087622c1f14b1651426316c741bd8470315d63393bbdc8a0a097f1ac728315fbf17b79b675e9c40605913fff64800a5c7c2057e30f44abed76d8ce797db6f03219e077a3d1fa3945f37d8eeb4c52aee99b4a5f606be50515d347405db37b37a063cd1cd315818521decd2e44878a1a53e84a4186ea3e896a29e0e34c68091a4575b5834e6bfa6c5987916ae49d77347ee7b2f7428f8489a07e54e9d05690f5f8acc2eeab46f44a0f39e5e0e41fde76d29e2660fb5349e00d264527f92d71cfa27a51d9285873908757f42f8f9e40a9c3ec5d9adc966a4dde82d0b87c48ffaebfe2bda73ff388197829d24eb2b18cc50dbae96473a95d819dc1dc99959811e832396eec4773701dbaf86d6449c8310f7fa9ed289675a0ba1be59881fe7b1e64d4485654bab3f9010e575773262ac65f7fa24663f090d413ca74572dac7df3cf06c1fdc226acfc1380441c2d9c4b31fbdd5ee12d83e2d36b9512f4e9c5f0b3607b51665479a9ce035ee952c9d743b5d7b3fa1acec222b447bf8e98397a6e79569a1487adff39f06bfa0a51b022d1798738b37a0801a1f97498c6c3633404f251c137b21e0eec92bcb7a4eb00cad9c826327f4712643035e4b79d14d3e5b0bcf791e6bbfa447f30d362570c26c29787d7c9360b3566b1e9c6eb3f785c96c6d3642a2332910fe3f0b78d4d18d7d4bbedd0b919c8a2853a0babd353c695960d4ec00727a3a91192b8b3a4d4e7cfd1620cdb4936afd91f5155c20bbe8a3dd96790d5e623f9cea53fa32ebe8f2f2572d5d99686ba735d824aaa74a56fd0fde9c219811cb79760410be3815ca95b75551608ee945b895a5c08b760b90aa4836128048b4fd19e0ed475c720d83a76af7e8c3e571f11b0fc540c788d7daea8bc923db44a6f8d208e0140a18d1c811029419d27b4ed994f0ec21c8f65df2f0c83cf5d0111694c18076e7441b0e0fa8e58da3a6c3b94e819550322765d70fbd4f053f2edcba3050cfe14d0efe7280c4a3990182a46cdf4a7f8cf20e0fc17d4fb5becb35908a04e19f5be2df7db81edf9cae016ac88769cb1a644189d84e35e18ff0d2fea6b02a406129487009311525199ffec581fd587521a239f6514e6e10aeef63e531cbe4c37f08592999ce3c3146e76e2793a974d49e0c7264c214133bd2049eacb8f09b3184130812b71fb0cd02d2f044f1d38ab34d1a9bed9940b5691f396c7e2ad25b6baf6ed14baa0f70ef3fd2d5cafd16c7775f6583971223eab2276b98e1998e87692e8474647bc135fab8d8ff7bbdd3d669856897cf7776b594f7cf49ac02870df621eca1919b39f9d28bddee92f3b5150e806b9fe9db01e6e1474d09239799c1265bdab86e8eda0f69cebf921af3ba852f5b64d2129bfa09155dc411165d66c0d750fa9fc07a6be3fdbce769bb494b84eff41319618c1611fe3f62b39066e81ee5ead615d7a576cc8fe68e8bb6ba1d4088810c701f0c1873df8cd02d5019589c095bb730a5625a3996c0b240aaf4484f2502d4aa377d462894557615a5d486339b4ad108ef6ffef0a26ba0136e3d969b4337954069aaeaa73e64757477f30d723ba38dc644f6e371088d9e2b1ff50ecbddad48198e525963fabda4e196c9ddf0d89abcdc3a3d395a96b22254242ce93804e4d6673265e7c4d56b1195aada97bbe9050e843bd56181a533fa03e01285ade0f715d0f9830b1f0ae7586d8485bf76ace561ea6c8c4c9497674d96182a9e289ddcc722814f14b8ce8a70bbb6dec40f84cde55e0d16d4ec043561d6a1d16790b5bc4f02ab9", signature: - "0xadf71438600db72305e4a277554c06359d25e59480e2c4d5ea9d12d132088893d2df141c60a0857c63edc10b9800ac0e0e3e3dcd7b5fdfbcab8fbf377816811becc8be9420c17a725dff9dac6653230b9c5c04fd2ea19f9313fe943e1a562a18", + "0x8522f6464ddc5550f70ed8cd58ed26961d8755111d5e967ee815730bc2e9ad24e7ca718fcf56f1af785bc25dfac719a615a4c4e029a352840edca0d78c9a46ef35202f42311918f70d8ddde9de25fe091889283b9778ea15403fe87dc5f7527e", depositDataRoot: - "0x0d12c28849771f3f946d8d705a1f73683d97add9edaec5e6b30650cc03bc57d5", + "0xcbcd1da8a9ba0e30b2dd8a955591ac4a759bf5ee6f5295d72f5b89b1b175193b", }, }; }); diff --git a/contracts/test/vault/oeth-vault.fork-test.js b/contracts/test/vault/oeth-vault.fork-test.js index 7ade3fd9da..59177c0cbf 100644 --- a/contracts/test/vault/oeth-vault.fork-test.js +++ b/contracts/test/vault/oeth-vault.fork-test.js @@ -219,6 +219,7 @@ describe("ForkTest: OETH Vault", function () { shouldHaveRewardTokensConfigured(() => ({ vault: fixture.oethVault, harvester: fixture.oethHarvester, + ignoreTokens: [fixture.weth.address.toLowerCase()], expectedConfigs: { [fixture.cvx.address]: { allowedSlippageBps: 300, diff --git a/contracts/utils/resolvers.js b/contracts/utils/resolvers.js index e1bc803f06..5791420874 100644 --- a/contracts/utils/resolvers.js +++ b/contracts/utils/resolvers.js @@ -13,16 +13,23 @@ const resolveAsset = async (symbol) => { // "Hardhat can't be initialized while its config is being defined" const hre = require("hardhat"); - if (hre.network.name != "hardhat") { + // Not using helpers here as they import hardhat which won't work for Hardhat tasks + if (process.env.FORK === "true" || hre.network.name != "hardhat") { + const network = + hre.network.name != "hardhat" + ? hre.network.name != "hardhat" + : hre.network.config.chainId == 17000 + ? "holesky" + : "mainnet"; + const assetAddr = - addresses[hre.network.name][symbol + "Proxy"] || - addresses[hre.network.name][symbol]; + addresses[network][symbol + "Proxy"] || addresses[network][symbol]; if (!assetAddr) { throw Error( - `Failed to resolve symbol "${symbol}" to an address on the "${hre.network.name}" network` + `Failed to resolve symbol "${symbol}" to an address on the "${network}" network` ); } - log(`Resolved ${symbol} to ${assetAddr}`); + log(`Resolved ${symbol} to ${assetAddr} on the ${network} network`); const asset = await ethers.getContractAt("IERC20Metadata", assetAddr); return asset; } From 0623a47dbe5e8026a0352d4ba5c8ac41ecce3ae9 Mon Sep 17 00:00:00 2001 From: Domen Grabec Date: Fri, 10 May 2024 00:20:13 +0200 Subject: [PATCH 037/273] add payable to fee accumulator (#2053) * add payable to fee accumulator * remove zero initializers * some gas savings --- .../NativeStaking/FeeAccumulator.sol | 5 + .../NativeStakingSSVStrategy.sol | 4 +- .../NativeStaking/ValidatorAccountant.sol | 6 +- .../NativeStaking/ValidatorRegistrator.sol | 6 +- contracts/deploy/deployActions.js | 27 +++++ .../deploy/holesky/007_upgrade_strategy.js | 25 +++++ .../deployments/holesky/.migrations.json | 3 +- .../deployments/holesky/FeeAccumulator.json | 46 ++++---- .../holesky/NativeStakingSSVStrategy.json | 94 ++++++++-------- .../94a4e2017aae119860e82f5bc90e390d.json | 104 ++++++++++++++++++ contracts/test/behaviour/ssvStrategy.js | 7 +- 11 files changed, 250 insertions(+), 77 deletions(-) create mode 100644 contracts/deploy/holesky/007_upgrade_strategy.js create mode 100644 contracts/deployments/holesky/solcInputs/94a4e2017aae119860e82f5bc90e390d.json diff --git a/contracts/contracts/strategies/NativeStaking/FeeAccumulator.sol b/contracts/contracts/strategies/NativeStaking/FeeAccumulator.sol index 175c2e5edc..99e09b369b 100644 --- a/contracts/contracts/strategies/NativeStaking/FeeAccumulator.sol +++ b/contracts/contracts/strategies/NativeStaking/FeeAccumulator.sol @@ -36,4 +36,9 @@ contract FeeAccumulator is Governable { Address.sendValue(payable(STRATEGY), eth); } } + + /** + * @dev Accept ETH + */ + receive() external payable {} } diff --git a/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol b/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol index 55ec51a306..c15629be71 100644 --- a/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol +++ b/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol @@ -31,7 +31,7 @@ contract NativeStakingSSVStrategy is /// executing transactions on the Ethereum network as part of block proposals. They include /// priority fees (fees paid by users for their transactions to be included) and MEV rewards /// (rewards for arranging transactions in a way that benefits the validator). - address public immutable FEE_ACCUMULATOR_ADDRESS; + address payable public immutable FEE_ACCUMULATOR_ADDRESS; // For future use uint256[50] private __gap; @@ -60,7 +60,7 @@ contract NativeStakingSSVStrategy is ) { SSV_TOKEN_ADDRESS = _ssvToken; - FEE_ACCUMULATOR_ADDRESS = _feeAccumulator; + FEE_ACCUMULATOR_ADDRESS = payable(_feeAccumulator); } /// @notice initialize function, to set up initial internal state diff --git a/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol b/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol index b94d3d8942..0be35263bf 100644 --- a/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol +++ b/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol @@ -15,12 +15,12 @@ abstract contract ValidatorAccountant is ValidatorRegistrator { uint256 public constant MAX_STAKE = 32 ether; /// @notice Keeps track of the total consensus rewards swept from the beacon chain - uint256 public consensusRewards = 0; + uint256 public consensusRewards; /// @notice start of fuse interval - uint256 public fuseIntervalStart = 0; + uint256 public fuseIntervalStart; /// @notice end of fuse interval - uint256 public fuseIntervalEnd = 0; + uint256 public fuseIntervalEnd; uint256[50] private __gap; diff --git a/contracts/contracts/strategies/NativeStaking/ValidatorRegistrator.sol b/contracts/contracts/strategies/NativeStaking/ValidatorRegistrator.sol index b6f61eecd2..6b51c2c39f 100644 --- a/contracts/contracts/strategies/NativeStaking/ValidatorRegistrator.sol +++ b/contracts/contracts/strategies/NativeStaking/ValidatorRegistrator.sol @@ -114,8 +114,9 @@ abstract contract ValidatorRegistrator is Governable, Pausable { // Convert required ETH from WETH IWETH9(WETH_TOKEN_ADDRESS).withdraw(requiredETH); + uint256 validatorsLength = validators.length; // For each validator - for (uint256 i = 0; i < validators.length; ) { + for (uint256 i = 0; i < validatorsLength; ) { bytes32 pubkeyHash = keccak256(validators[i].pubkey); VALIDATOR_STATE currentState = validatorsStates[pubkeyHash]; @@ -143,7 +144,6 @@ abstract contract ValidatorRegistrator is Governable, Pausable { validators[i].depositDataRoot ); - activeDepositedValidators += 1; emit ETHStaked( validators[i].pubkey, 32 ether, @@ -156,6 +156,8 @@ abstract contract ValidatorRegistrator is Governable, Pausable { ++i; } } + // save gas by changing this storage variable only once rather each time in the loop. + activeDepositedValidators += validatorsLength; } /// @notice Registers a new validator in the SSV Cluster. diff --git a/contracts/deploy/deployActions.js b/contracts/deploy/deployActions.js index 4d1550cf55..b4849c14c3 100644 --- a/contracts/deploy/deployActions.js +++ b/contracts/deploy/deployActions.js @@ -807,6 +807,32 @@ const deployFraxEthStrategy = async () => { return cFraxETHStrategy; }; +/** + * upgradeNativeStakingFeeAccumulator + */ +const upgradeNativeStakingFeeAccumulator = async () => { + const { deployerAddr } = await getNamedAccounts(); + const sDeployer = await ethers.provider.getSigner(deployerAddr); + + const strategyProxy = await ethers.getContract( + "NativeStakingSSVStrategyProxy" + ); + const feeAccumulatorProxy = await ethers.getContract( + "NativeStakingFeeAccumulatorProxy" + ); + + log("Deploy fee accumulator implementation"); + const dFeeAccumulatorImpl = await deployWithConfirmation("FeeAccumulator", [ + strategyProxy.address, // STRATEGY + ]); + + await withConfirmation( + feeAccumulatorProxy + .connect(sDeployer) + .upgradeTo(dFeeAccumulatorImpl.address) + ); +}; + /** * Upgrade NativeStakingSSVStrategy */ @@ -1538,4 +1564,5 @@ module.exports = { deployOETHSwapper, deployOUSDSwapper, upgradeNativeStakingSSVStrategy, + upgradeNativeStakingFeeAccumulator, }; diff --git a/contracts/deploy/holesky/007_upgrade_strategy.js b/contracts/deploy/holesky/007_upgrade_strategy.js new file mode 100644 index 0000000000..0d1373b3b3 --- /dev/null +++ b/contracts/deploy/holesky/007_upgrade_strategy.js @@ -0,0 +1,25 @@ +const { + upgradeNativeStakingSSVStrategy, + upgradeNativeStakingFeeAccumulator, +} = require("../deployActions"); +const { withConfirmation } = require("../../utils/deploy"); + +const mainExport = async () => { + console.log("Running 007 deployment on Holesky..."); + + console.log("Upgrading native staking fee accumulator"); + await upgradeNativeStakingFeeAccumulator(); + + console.log("Upgrading native staking strategy"); + await upgradeNativeStakingSSVStrategy(); + + console.log("Running 007 deployment done"); + return true; +}; + +mainExport.id = "007_upgrade_strategy"; +mainExport.tags = []; +mainExport.dependencies = []; +mainExport.skip = () => false; + +module.exports = mainExport; diff --git a/contracts/deployments/holesky/.migrations.json b/contracts/deployments/holesky/.migrations.json index 8448ae20e6..bca53380ee 100644 --- a/contracts/deployments/holesky/.migrations.json +++ b/contracts/deployments/holesky/.migrations.json @@ -4,5 +4,6 @@ "003_deposit_to_native_strategy": 1714307581, "004_upgrade_strategy": 1714944723, "005_deploy_new_harvester": 1714998707, - "006_update_registrator": 1715184342 + "006_update_registrator": 1715184342, + "007_upgrade_strategy": 1715251466 } \ No newline at end of file diff --git a/contracts/deployments/holesky/FeeAccumulator.json b/contracts/deployments/holesky/FeeAccumulator.json index dbee10dcb3..241a82fda1 100644 --- a/contracts/deployments/holesky/FeeAccumulator.json +++ b/contracts/deployments/holesky/FeeAccumulator.json @@ -1,5 +1,5 @@ { - "address": "0xa3f54f30cDefaBd9527FF11ad51Ba20c3b77ffDD", + "address": "0x5AE7AbA61EA37f8a2378d3554d156Fd968e62490", "abi": [ { "inputs": [ @@ -121,47 +121,51 @@ "outputs": [], "stateMutability": "nonpayable", "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" } ], - "transactionHash": "0xa7a9c1f0210822c01adc6baec616c8b15880fa006bfb44e2fd11e8eed5c4d79e", + "transactionHash": "0x569ba4143c55ed118f24e22bd3e8a16ac73119589910477e48c7dbde55542ea8", "receipt": { "to": null, "from": "0x1b94CA50D3Ad9f8368851F8526132272d1a5028C", - "contractAddress": "0xa3f54f30cDefaBd9527FF11ad51Ba20c3b77ffDD", - "transactionIndex": 41, - "gasUsed": "405585", - "logsBloom": "0x00000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000000004000000000100002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000010000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000", - "blockHash": "0xeb75a4f4e090ead69abb76fa8002957b1d721ef4121f27dd6b32b784c7ac347c", - "transactionHash": "0xa7a9c1f0210822c01adc6baec616c8b15880fa006bfb44e2fd11e8eed5c4d79e", + "contractAddress": "0x5AE7AbA61EA37f8a2378d3554d156Fd968e62490", + "transactionIndex": 17, + "gasUsed": "421947", + "logsBloom": "0x00000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000000004000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800010000000000010000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000800000000", + "blockHash": "0x75e43a53123c9ea48a03e97ebe80ddc2dcfa932b1a75eab6d406b3e030f8b0f8", + "transactionHash": "0x569ba4143c55ed118f24e22bd3e8a16ac73119589910477e48c7dbde55542ea8", "logs": [ { - "transactionIndex": 41, - "blockNumber": 1489385, - "transactionHash": "0xa7a9c1f0210822c01adc6baec616c8b15880fa006bfb44e2fd11e8eed5c4d79e", - "address": "0xa3f54f30cDefaBd9527FF11ad51Ba20c3b77ffDD", + "transactionIndex": 17, + "blockNumber": 1509018, + "transactionHash": "0x569ba4143c55ed118f24e22bd3e8a16ac73119589910477e48c7dbde55542ea8", + "address": "0x5AE7AbA61EA37f8a2378d3554d156Fd968e62490", "topics": [ "0xc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000001b94ca50d3ad9f8368851f8526132272d1a5028c" ], "data": "0x", - "logIndex": 567, - "blockHash": "0xeb75a4f4e090ead69abb76fa8002957b1d721ef4121f27dd6b32b784c7ac347c" + "logIndex": 18, + "blockHash": "0x75e43a53123c9ea48a03e97ebe80ddc2dcfa932b1a75eab6d406b3e030f8b0f8" } ], - "blockNumber": 1489385, - "cumulativeGasUsed": "21569388", + "blockNumber": 1509018, + "cumulativeGasUsed": "2105362", "status": 1, "byzantium": true }, "args": [ "0xcf4a9e80Ddb173cc17128A361B98B9A140e3932E" ], - "numDeployments": 1, - "solcInputHash": "66dbdc9fbde8f1c7cc59f29d272eb661", - "metadata": "{\"compiler\":{\"version\":\"0.8.7+commit.e28d00a7\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_strategy\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"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\":true,\"internalType\":\"address\",\"name\":\"previousGovernor\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newGovernor\",\"type\":\"address\"}],\"name\":\"PendingGovernorshipTransfer\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"STRATEGY\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"claimGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"collect\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"eth\",\"type\":\"uint256\"}],\"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\":[{\"internalType\":\"address\",\"name\":\"_newGovernor\",\"type\":\"address\"}],\"name\":\"transferGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"author\":\"Origin Protocol Inc\",\"kind\":\"dev\",\"methods\":{\"collect()\":{\"returns\":{\"eth\":\"The amount of execution rewards that were sent to the Native Staking Strategy\"}},\"constructor\":{\"params\":{\"_strategy\":\"Address of the Native Staking Strategy\"}},\"transferGovernance(address)\":{\"params\":{\"_newGovernor\":\"Address of the new Governor\"}}},\"title\":\"Fee Accumulator for Native Staking SSV Strategy\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"STRATEGY()\":{\"notice\":\"The address of the Native Staking Strategy\"},\"claimGovernance()\":{\"notice\":\"Claim Governance of the contract to a new account (`newGovernor`). Can only be called by the new Governor.\"},\"collect()\":{\"notice\":\"sends all ETH in this FeeAccumulator contract to the Native Staking Strategy.\"},\"governor()\":{\"notice\":\"Returns the address of the current Governor.\"},\"isGovernor()\":{\"notice\":\"Returns true if the caller is the current Governor.\"},\"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\"}},\"notice\":\"Receives execution rewards which includes tx fees and MEV rewards like tx priority and tx ordering. It does NOT include swept ETH from beacon chain consensus rewards or full validator withdrawals.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/strategies/NativeStaking/FeeAccumulator.sol\":\"FeeAccumulator\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@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\"},\"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/strategies/NativeStaking/FeeAccumulator.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport { Address } from \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\n\\nimport { Governable } from \\\"../../governance/Governable.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 is Governable {\\n /// @notice The address of the Native Staking Strategy\\n address public immutable STRATEGY;\\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 }\\n}\\n\",\"keccak256\":\"0xf47bcc46ce70f649f061bec3d2303f376a15700ba18fe471fba823f60bdfed8b\",\"license\":\"MIT\"}},\"version\":1}", - "bytecode": "0x60a060405234801561001057600080fd5b506040516106fe3803806106fe83398101604081905261002f916100a1565b610045336000805160206106de83398151915255565b6000805160206106de833981519152546040516001600160a01b03909116906000907fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a908290a360601b6001600160601b0319166080526100d1565b6000602082840312156100b357600080fd5b81516001600160a01b03811681146100ca57600080fd5b9392505050565b60805160601c6105e26100fc600039600081816091015281816102d8015261035201526105e26000f3fe608060405234801561001057600080fd5b50600436106100625760003560e01c80630c340a2414610067578063185025ef1461008c5780635d36b190146100b3578063c7af3352146100bd578063d38bfff4146100d5578063e5225381146100e8575b600080fd5b61006f6100fe565b6040516001600160a01b0390911681526020015b60405180910390f35b61006f7f000000000000000000000000000000000000000000000000000000000000000081565b6100bb61011b565b005b6100c56101c6565b6040519015158152602001610083565b6100bb6100e336600461055c565b6101f7565b6100f06102cb565b604051908152602001610083565b600061011660008051602061058d8339815191525490565b905090565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b0316146101bb5760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b60648201526084015b60405180910390fd5b6101c43361037a565b565b60006101de60008051602061058d8339815191525490565b6001600160a01b0316336001600160a01b031614905090565b6101ff6101c6565b61024b5760405162461bcd60e51b815260206004820152601a60248201527f43616c6c6572206973206e6f742074686520476f7665726e6f7200000000000060448201526064016101b2565b610273817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b031661029360008051602061058d8339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b6000336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146103455760405162461bcd60e51b815260206004820152601a60248201527f43616c6c6572206973206e6f742074686520537472617465677900000000000060448201526064016101b2565b50478015610377576103777f00000000000000000000000000000000000000000000000000000000000000008261043e565b90565b6001600160a01b0381166103d05760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f72206973206164647265737328302900000000000060448201526064016101b2565b806001600160a01b03166103f060008051602061058d8339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a361043b8160008051602061058d83398151915255565b50565b8047101561048e5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e636500000060448201526064016101b2565b6000826001600160a01b03168260405160006040518083038185875af1925050503d80600081146104db576040519150601f19603f3d011682016040523d82523d6000602084013e6104e0565b606091505b50509050806105575760405162461bcd60e51b815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d6179206861766520726576657274656400000000000060648201526084016101b2565b505050565b60006020828403121561056e57600080fd5b81356001600160a01b038116811461058557600080fd5b939250505056fe7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa26469706673582212200be77de36795d09032129c2625dac1fb5df5aa816a58c269aa5090717764a41664736f6c634300080700337bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a", - "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106100625760003560e01c80630c340a2414610067578063185025ef1461008c5780635d36b190146100b3578063c7af3352146100bd578063d38bfff4146100d5578063e5225381146100e8575b600080fd5b61006f6100fe565b6040516001600160a01b0390911681526020015b60405180910390f35b61006f7f000000000000000000000000000000000000000000000000000000000000000081565b6100bb61011b565b005b6100c56101c6565b6040519015158152602001610083565b6100bb6100e336600461055c565b6101f7565b6100f06102cb565b604051908152602001610083565b600061011660008051602061058d8339815191525490565b905090565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b0316146101bb5760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b60648201526084015b60405180910390fd5b6101c43361037a565b565b60006101de60008051602061058d8339815191525490565b6001600160a01b0316336001600160a01b031614905090565b6101ff6101c6565b61024b5760405162461bcd60e51b815260206004820152601a60248201527f43616c6c6572206973206e6f742074686520476f7665726e6f7200000000000060448201526064016101b2565b610273817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b031661029360008051602061058d8339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b6000336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146103455760405162461bcd60e51b815260206004820152601a60248201527f43616c6c6572206973206e6f742074686520537472617465677900000000000060448201526064016101b2565b50478015610377576103777f00000000000000000000000000000000000000000000000000000000000000008261043e565b90565b6001600160a01b0381166103d05760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f72206973206164647265737328302900000000000060448201526064016101b2565b806001600160a01b03166103f060008051602061058d8339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a361043b8160008051602061058d83398151915255565b50565b8047101561048e5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e636500000060448201526064016101b2565b6000826001600160a01b03168260405160006040518083038185875af1925050503d80600081146104db576040519150601f19603f3d011682016040523d82523d6000602084013e6104e0565b606091505b50509050806105575760405162461bcd60e51b815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d6179206861766520726576657274656400000000000060648201526084016101b2565b505050565b60006020828403121561056e57600080fd5b81356001600160a01b038116811461058557600080fd5b939250505056fe7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa26469706673582212200be77de36795d09032129c2625dac1fb5df5aa816a58c269aa5090717764a41664736f6c63430008070033", + "numDeployments": 2, + "solcInputHash": "94a4e2017aae119860e82f5bc90e390d", + "metadata": "{\"compiler\":{\"version\":\"0.8.7+commit.e28d00a7\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_strategy\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"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\":true,\"internalType\":\"address\",\"name\":\"previousGovernor\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newGovernor\",\"type\":\"address\"}],\"name\":\"PendingGovernorshipTransfer\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"STRATEGY\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"claimGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"collect\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"eth\",\"type\":\"uint256\"}],\"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\":[{\"internalType\":\"address\",\"name\":\"_newGovernor\",\"type\":\"address\"}],\"name\":\"transferGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"author\":\"Origin Protocol Inc\",\"kind\":\"dev\",\"methods\":{\"collect()\":{\"returns\":{\"eth\":\"The amount of execution rewards that were sent to the Native Staking Strategy\"}},\"constructor\":{\"params\":{\"_strategy\":\"Address of the Native Staking Strategy\"}},\"transferGovernance(address)\":{\"params\":{\"_newGovernor\":\"Address of the new Governor\"}}},\"title\":\"Fee Accumulator for Native Staking SSV Strategy\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"STRATEGY()\":{\"notice\":\"The address of the Native Staking Strategy\"},\"claimGovernance()\":{\"notice\":\"Claim Governance of the contract to a new account (`newGovernor`). Can only be called by the new Governor.\"},\"collect()\":{\"notice\":\"sends all ETH in this FeeAccumulator contract to the Native Staking Strategy.\"},\"governor()\":{\"notice\":\"Returns the address of the current Governor.\"},\"isGovernor()\":{\"notice\":\"Returns true if the caller is the current Governor.\"},\"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\"}},\"notice\":\"Receives execution rewards which includes tx fees and MEV rewards like tx priority and tx ordering. It does NOT include swept ETH from beacon chain consensus rewards or full validator withdrawals.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/strategies/NativeStaking/FeeAccumulator.sol\":\"FeeAccumulator\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@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\"},\"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/strategies/NativeStaking/FeeAccumulator.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport { Address } from \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\n\\nimport { Governable } from \\\"../../governance/Governable.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 is Governable {\\n /// @notice The address of the Native Staking Strategy\\n address public immutable STRATEGY;\\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 }\\n\\n /**\\n * @dev Accept ETH\\n */\\n receive() external payable {}\\n}\\n\",\"keccak256\":\"0xb8fda3b87dc5d6f8aee4bf1d015a585211e5b5a319dfa4b0f4770e3f5a2d5939\",\"license\":\"MIT\"}},\"version\":1}", + "bytecode": "0x60a060405234801561001057600080fd5b5060405161074a38038061074a83398101604081905261002f916100a1565b6100453360008051602061072a83398151915255565b60008051602061072a833981519152546040516001600160a01b03909116906000907fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a908290a360601b6001600160601b0319166080526100d1565b6000602082840312156100b357600080fd5b81516001600160a01b03811681146100ca57600080fd5b9392505050565b60805160601c61062e6100fc6000396000818160a901528181610324015261039e015261062e6000f3fe6080604052600436106100595760003560e01c80630c340a2414610065578063185025ef146100975780635d36b190146100cb578063c7af3352146100e2578063d38bfff414610107578063e52253811461012757600080fd5b3661006057005b600080fd5b34801561007157600080fd5b5061007a61014a565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156100a357600080fd5b5061007a7f000000000000000000000000000000000000000000000000000000000000000081565b3480156100d757600080fd5b506100e0610167565b005b3480156100ee57600080fd5b506100f7610212565b604051901515815260200161008e565b34801561011357600080fd5b506100e06101223660046105a8565b610243565b34801561013357600080fd5b5061013c610317565b60405190815260200161008e565b60006101626000805160206105d98339815191525490565b905090565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b0316146102075760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b60648201526084015b60405180910390fd5b610210336103c6565b565b600061022a6000805160206105d98339815191525490565b6001600160a01b0316336001600160a01b031614905090565b61024b610212565b6102975760405162461bcd60e51b815260206004820152601a60248201527f43616c6c6572206973206e6f742074686520476f7665726e6f7200000000000060448201526064016101fe565b6102bf817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b03166102df6000805160206105d98339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b6000336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146103915760405162461bcd60e51b815260206004820152601a60248201527f43616c6c6572206973206e6f742074686520537472617465677900000000000060448201526064016101fe565b504780156103c3576103c37f00000000000000000000000000000000000000000000000000000000000000008261048a565b90565b6001600160a01b03811661041c5760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f72206973206164647265737328302900000000000060448201526064016101fe565b806001600160a01b031661043c6000805160206105d98339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a3610487816000805160206105d983398151915255565b50565b804710156104da5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e636500000060448201526064016101fe565b6000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114610527576040519150601f19603f3d011682016040523d82523d6000602084013e61052c565b606091505b50509050806105a35760405162461bcd60e51b815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d6179206861766520726576657274656400000000000060648201526084016101fe565b505050565b6000602082840312156105ba57600080fd5b81356001600160a01b03811681146105d157600080fd5b939250505056fe7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa26469706673582212209299b541e31a72d89aa7c5cbb606b8c4e2cdd875ab8119601694f4954c09ec9564736f6c634300080700337bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a", + "deployedBytecode": "0x6080604052600436106100595760003560e01c80630c340a2414610065578063185025ef146100975780635d36b190146100cb578063c7af3352146100e2578063d38bfff414610107578063e52253811461012757600080fd5b3661006057005b600080fd5b34801561007157600080fd5b5061007a61014a565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156100a357600080fd5b5061007a7f000000000000000000000000000000000000000000000000000000000000000081565b3480156100d757600080fd5b506100e0610167565b005b3480156100ee57600080fd5b506100f7610212565b604051901515815260200161008e565b34801561011357600080fd5b506100e06101223660046105a8565b610243565b34801561013357600080fd5b5061013c610317565b60405190815260200161008e565b60006101626000805160206105d98339815191525490565b905090565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b0316146102075760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b60648201526084015b60405180910390fd5b610210336103c6565b565b600061022a6000805160206105d98339815191525490565b6001600160a01b0316336001600160a01b031614905090565b61024b610212565b6102975760405162461bcd60e51b815260206004820152601a60248201527f43616c6c6572206973206e6f742074686520476f7665726e6f7200000000000060448201526064016101fe565b6102bf817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b03166102df6000805160206105d98339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b6000336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146103915760405162461bcd60e51b815260206004820152601a60248201527f43616c6c6572206973206e6f742074686520537472617465677900000000000060448201526064016101fe565b504780156103c3576103c37f00000000000000000000000000000000000000000000000000000000000000008261048a565b90565b6001600160a01b03811661041c5760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f72206973206164647265737328302900000000000060448201526064016101fe565b806001600160a01b031661043c6000805160206105d98339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a3610487816000805160206105d983398151915255565b50565b804710156104da5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e636500000060448201526064016101fe565b6000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114610527576040519150601f19603f3d011682016040523d82523d6000602084013e61052c565b606091505b50509050806105a35760405162461bcd60e51b815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d6179206861766520726576657274656400000000000060648201526084016101fe565b505050565b6000602082840312156105ba57600080fd5b81356001600160a01b03811681146105d157600080fd5b939250505056fe7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa26469706673582212209299b541e31a72d89aa7c5cbb606b8c4e2cdd875ab8119601694f4954c09ec9564736f6c63430008070033", "libraries": {}, "devdoc": { "author": "Origin Protocol Inc", diff --git a/contracts/deployments/holesky/NativeStakingSSVStrategy.json b/contracts/deployments/holesky/NativeStakingSSVStrategy.json index fc66b58e4c..f1396fd9fc 100644 --- a/contracts/deployments/holesky/NativeStakingSSVStrategy.json +++ b/contracts/deployments/holesky/NativeStakingSSVStrategy.json @@ -1,5 +1,5 @@ { - "address": "0xaf3fCA5376354c8a51dc3cB02D586530Cc61d164", + "address": "0x2cFc4691484D155142368d0ac2b954a0424a7EEd", "abi": [ { "inputs": [ @@ -478,7 +478,7 @@ "name": "FEE_ACCUMULATOR_ADDRESS", "outputs": [ { - "internalType": "address", + "internalType": "address payable", "name": "", "type": "address" } @@ -1276,34 +1276,34 @@ "type": "receive" } ], - "transactionHash": "0xddb5a6d8ad3f95e324b44bfe1d2cb508bcf734deb36c3f6dfb2f29e44f36e797", + "transactionHash": "0xd5bf651afbcae48e57d3767f34cde444061033c2ee656a377d989e8f820ecb87", "receipt": { "to": null, "from": "0x1b94CA50D3Ad9f8368851F8526132272d1a5028C", - "contractAddress": "0xaf3fCA5376354c8a51dc3cB02D586530Cc61d164", - "transactionIndex": 9, + "contractAddress": "0x2cFc4691484D155142368d0ac2b954a0424a7EEd", + "transactionIndex": 21, "gasUsed": "4109268", - "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000020000000000000000000800000000000000000000000000000000000004000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000010000000000000000000000000000000000000000020000400000000000000000000000000000000000000000000000000000000000001", - "blockHash": "0x95040d373bc67c18914c67055beff42c69ea4eab3fae944856d9e458a49bfac7", - "transactionHash": "0xddb5a6d8ad3f95e324b44bfe1d2cb508bcf734deb36c3f6dfb2f29e44f36e797", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000020000000000000000000800200000000000000000000000000000000004000000000000002000000000000000000040000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000010000000000010000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x5d3b7bb32953cd32eb25cd96b3ebcd5123ecfd7497f30ffa63b544440e11e2da", + "transactionHash": "0xd5bf651afbcae48e57d3767f34cde444061033c2ee656a377d989e8f820ecb87", "logs": [ { - "transactionIndex": 9, - "blockNumber": 1489371, - "transactionHash": "0xddb5a6d8ad3f95e324b44bfe1d2cb508bcf734deb36c3f6dfb2f29e44f36e797", - "address": "0xaf3fCA5376354c8a51dc3cB02D586530Cc61d164", + "transactionIndex": 21, + "blockNumber": 1509026, + "transactionHash": "0xd5bf651afbcae48e57d3767f34cde444061033c2ee656a377d989e8f820ecb87", + "address": "0x2cFc4691484D155142368d0ac2b954a0424a7EEd", "topics": [ "0xc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000001b94ca50d3ad9f8368851f8526132272d1a5028c" ], "data": "0x", - "logIndex": 400, - "blockHash": "0x95040d373bc67c18914c67055beff42c69ea4eab3fae944856d9e458a49bfac7" + "logIndex": 34, + "blockHash": "0x5d3b7bb32953cd32eb25cd96b3ebcd5123ecfd7497f30ffa63b544440e11e2da" } ], - "blockNumber": 1489371, - "cumulativeGasUsed": "20992246", + "blockNumber": 1509026, + "cumulativeGasUsed": "6356303", "status": 1, "byzantium": true }, @@ -1318,11 +1318,11 @@ "0x65a289f4BF934c964C942eFF6E6F83b6481BE550", "0x4242424242424242424242424242424242424242" ], - "numDeployments": 1, - "solcInputHash": "66dbdc9fbde8f1c7cc59f29d272eb661", - "metadata": "{\"compiler\":{\"version\":\"0.8.7+commit.e28d00a7\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"platformAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"vaultAddress\",\"type\":\"address\"}],\"internalType\":\"struct InitializableAbstractStrategy.BaseStrategyConfig\",\"name\":\"_baseConfig\",\"type\":\"tuple\"},{\"internalType\":\"address\",\"name\":\"_wethAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_ssvToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_ssvNetwork\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_feeAccumulator\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_beaconChainDepositContract\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"AccountingConsensusRewards\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"noOfValidators\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"remainingValidators\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"wethSentToVault\",\"type\":\"uint256\"}],\"name\":\"AccountingFullyWithdrawnValidator\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"validatorsDelta\",\"type\":\"int256\"},{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"consensusRewardsDelta\",\"type\":\"int256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"wethToVault\",\"type\":\"uint256\"}],\"name\":\"AccountingManuallyFixed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"remainingValidators\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"wethSentToVault\",\"type\":\"uint256\"}],\"name\":\"AccountingValidatorSlashed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"Deposit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"pubkey\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"withdrawal_credentials\",\"type\":\"bytes\"}],\"name\":\"ETHStaked\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"start\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"end\",\"type\":\"uint256\"}],\"name\":\"FuseIntervalUpdated\",\"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\":\"address\",\"name\":\"_oldHarvesterAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_newHarvesterAddress\",\"type\":\"address\"}],\"name\":\"HarvesterAddressesUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"}],\"name\":\"PTokenAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"}],\"name\":\"PTokenRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Paused\",\"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\":\"newAddress\",\"type\":\"address\"}],\"name\":\"RegistratorChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"_oldAddresses\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"_newAddresses\",\"type\":\"address[]\"}],\"name\":\"RewardTokenAddressesUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"rewardToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"RewardTokenCollected\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"pubkey\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"}],\"name\":\"SSVValidatorExitCompleted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"pubkey\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"}],\"name\":\"SSVValidatorExitInitiated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"pubkey\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"}],\"name\":\"SSVValidatorRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Unpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"Withdrawal\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"BEACON_CHAIN_DEPOSIT_CONTRACT\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_ACCUMULATOR_ADDRESS\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MAX_STAKE\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"SSV_NETWORK_ADDRESS\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"SSV_TOKEN_ADDRESS\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"VAULT_ADDRESS\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"WETH_TOKEN_ADDRESS\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"activeDepositedValidators\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"assetToPToken\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"}],\"name\":\"checkBalance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"claimGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"collectRewardTokens\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"consensusRewards\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"depositAll\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"validatorCount\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"networkFeeIndex\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"index\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"active\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"internalType\":\"struct Cluster\",\"name\":\"cluster\",\"type\":\"tuple\"}],\"name\":\"depositSSV\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"doAccounting\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"accountingValid\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"publicKey\",\"type\":\"bytes\"},{\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"}],\"name\":\"exitSsvValidator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fuseIntervalEnd\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fuseIntervalStart\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRewardTokenAddresses\",\"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\":\"harvesterAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"_rewardTokenAddresses\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"_assets\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"_pTokens\",\"type\":\"address[]\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isGovernor\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"int256\",\"name\":\"_validatorsDelta\",\"type\":\"int256\"},{\"internalType\":\"int256\",\"name\":\"_consensusRewardsDelta\",\"type\":\"int256\"},{\"internalType\":\"uint256\",\"name\":\"_wethToVaultAmount\",\"type\":\"uint256\"}],\"name\":\"manuallyFixAccounting\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"paused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"platformAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"publicKey\",\"type\":\"bytes\"},{\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"},{\"internalType\":\"bytes\",\"name\":\"sharesData\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"validatorCount\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"networkFeeIndex\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"index\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"active\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"internalType\":\"struct Cluster\",\"name\":\"cluster\",\"type\":\"tuple\"}],\"name\":\"registerSsvValidator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_assetIndex\",\"type\":\"uint256\"}],\"name\":\"removePToken\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"publicKey\",\"type\":\"bytes\"},{\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"validatorCount\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"networkFeeIndex\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"index\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"active\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"internalType\":\"struct Cluster\",\"name\":\"cluster\",\"type\":\"tuple\"}],\"name\":\"removeSsvValidator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"rewardTokenAddresses\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"safeApproveAllTokens\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_fuseIntervalStart\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_fuseIntervalEnd\",\"type\":\"uint256\"}],\"name\":\"setFuseInterval\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_harvesterAddress\",\"type\":\"address\"}],\"name\":\"setHarvesterAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"}],\"name\":\"setPTokenAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"setRegistrator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"_rewardTokenAddresses\",\"type\":\"address[]\"}],\"name\":\"setRewardTokenAddresses\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"pubkey\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"depositDataRoot\",\"type\":\"bytes32\"}],\"internalType\":\"struct ValidatorStakeData[]\",\"name\":\"validators\",\"type\":\"tuple[]\"}],\"name\":\"stakeEth\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"}],\"name\":\"supportsAsset\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"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\":\"validatorRegistrator\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"validatorsStates\",\"outputs\":[{\"internalType\":\"enum ValidatorRegistrator.VALIDATOR_STATE\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"vaultAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"withdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdrawAll\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"author\":\"Origin Protocol Inc\",\"kind\":\"dev\",\"methods\":{\"checkBalance(address)\":{\"params\":{\"_asset\":\"Address of weth asset\"},\"returns\":{\"balance\":\" Total value of (W)ETH\"}},\"constructor\":{\"params\":{\"_baseConfig\":\"Base strategy config with platformAddress (ERC-4626 Vault contract), eg sfrxETH or sDAI, and vaultAddress (OToken Vault contract), eg VaultProxy or OETHVaultProxy\",\"_beaconChainDepositContract\":\"Address of the beacon chain deposit contract\",\"_feeAccumulator\":\"Address of the fee accumulator receiving execution layer validator rewards\",\"_ssvNetwork\":\"Address of the SSV Network contract\",\"_ssvToken\":\"Address of the Erc20 SSV Token contract\",\"_wethAddress\":\"Address of the Erc20 WETH Token contract\"}},\"deposit(address,uint256)\":{\"params\":{\"_amount\":\"Amount of assets that were transferred to the strategy by the vault.\",\"_asset\":\"Address of asset to deposit. Has to be WETH.\"}},\"depositSSV(uint64[],uint256,(uint32,uint64,uint64,bool,uint256))\":{\"details\":\"A SSV cluster is defined by the SSVOwnerAddress and the set of operatorIds. uses \\\"onlyStrategist\\\" modifier so continuous front-running can't DOS our maintenance service that tries to top up SSV tokens.\",\"params\":{\"cluster\":\"The SSV cluster details that must be derived from emitted events from the SSVNetwork contract.\"}},\"doAccounting()\":{\"details\":\"This function could in theory be permission-less but lets allow only the Registrator (Defender Action) to call it for now.\",\"returns\":{\"accountingValid\":\"true if accounting was successful, false if fuse is blown\"}},\"getRewardTokenAddresses()\":{\"returns\":{\"_0\":\"address[] the reward token addresses.\"}},\"initialize(address[],address[],address[])\":{\"params\":{\"_assets\":\"Addresses of initial supported assets\",\"_pTokens\":\"Platform Token corresponding addresses\",\"_rewardTokenAddresses\":\"Address of reward token for platform\"}},\"manuallyFixAccounting(int256,int256,uint256)\":{\"params\":{\"_consensusRewardsDelta\":\"adjust the accounted for consensus rewards up or down\",\"_validatorsDelta\":\"adjust the active validators by plus one, minus one or unchanged with zero\",\"_wethToVaultAmount\":\"the amount of WETH to be sent to the Vault\"}},\"paused()\":{\"details\":\"Returns true if the contract is paused, and false otherwise.\"},\"removePToken(uint256)\":{\"params\":{\"_assetIndex\":\"Index of the asset to be removed\"}},\"setHarvesterAddress(address)\":{\"params\":{\"_harvesterAddress\":\"Address of the harvester contract.\"}},\"setPTokenAddress(address,address)\":{\"params\":{\"_asset\":\"Address for the asset\",\"_pToken\":\"Address for the corresponding platform token\"}},\"setRewardTokenAddresses(address[])\":{\"params\":{\"_rewardTokenAddresses\":\"Array of reward token addresses\"}},\"stakeEth((bytes,bytes,bytes32)[])\":{\"params\":{\"validators\":\"A list of validator data needed to stake. The `ValidatorStakeData` struct contains the pubkey, signature and depositDataRoot. Only the registrator can call this function.\"}},\"supportsAsset(address)\":{\"params\":{\"_asset\":\"The address of the asset token.\"}},\"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\"}},\"withdraw(address,address,uint256)\":{\"params\":{\"_amount\":\"Amount of WETH to withdraw\",\"_asset\":\"WETH to withdraw\",\"_recipient\":\"Address to receive withdrawn assets\"}}},\"stateVariables\":{\"FEE_ACCUMULATOR_ADDRESS\":{\"details\":\"this address will receive Execution layer rewards - These are rewards earned for executing transactions on the Ethereum network as part of block proposals. They include priority fees (fees paid by users for their transactions to be included) and MEV rewards (rewards for arranging transactions in a way that benefits the validator).\"}},\"title\":\"Native Staking SSV Strategy\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"BEACON_CHAIN_DEPOSIT_CONTRACT()\":{\"notice\":\"The address of the beacon chain deposit contract\"},\"FEE_ACCUMULATOR_ADDRESS()\":{\"notice\":\"Fee collector address\"},\"MAX_STAKE()\":{\"notice\":\"The maximum amount of ETH that can be staked by a validator\"},\"SSV_NETWORK_ADDRESS()\":{\"notice\":\"The address of the SSV Network contract used to interface with\"},\"SSV_TOKEN_ADDRESS()\":{\"notice\":\"SSV ERC20 token that serves as a payment for operating SSV validators\"},\"VAULT_ADDRESS()\":{\"notice\":\"Address of the OETH Vault proxy contract\"},\"WETH_TOKEN_ADDRESS()\":{\"notice\":\"The address of the Wrapped ETH (WETH) token contract\"},\"activeDepositedValidators()\":{\"notice\":\"The number of validators that have 32 (!) ETH actively deposited. When a new deposit to a validator happens this number increases, when a validator exit is detected this number decreases.\"},\"assetToPToken(address)\":{\"notice\":\"asset => pToken (Platform Specific Token Address)\"},\"checkBalance(address)\":{\"notice\":\"Returns the total value of (W)ETH that is staked to the validators and WETH deposits that are still to be staked. This does not include ETH from consensus rewards sitting in this strategy or ETH from MEV rewards in the FeeAccumulator. These rewards are harvested and sent to the Dripper so will eventually be sent to the Vault as WETH.\"},\"claimGovernance()\":{\"notice\":\"Claim Governance of the contract to a new account (`newGovernor`). Can only be called by the new Governor.\"},\"collectRewardTokens()\":{\"notice\":\"Collect accumulated reward token and send to Vault.\"},\"consensusRewards()\":{\"notice\":\"Keeps track of the total consensus rewards swept from the beacon chain\"},\"deposit(address,uint256)\":{\"notice\":\"Unlike other strategies, this does not deposit assets into the underlying platform. It just checks the asset is WETH and emits the Deposit event. To deposit WETH into validators `registerSsvValidator` and `stakeEth` must be used. Will NOT revert if the strategy is paused from an accounting failure.\"},\"depositAll()\":{\"notice\":\"Unlike other strategies, this does not deposit assets into the underlying platform. It just emits the Deposit event. To deposit WETH into validators `registerSsvValidator` and `stakeEth` must be used. Will NOT revert if the strategy is paused from an accounting failure.\"},\"depositSSV(uint64[],uint256,(uint32,uint64,uint64,bool,uint256))\":{\"notice\":\"Deposits more SSV Tokens to the SSV Network contract which is used to pay the SSV Operators.\"},\"doAccounting()\":{\"notice\":\"This notion page offers a good explanation of how the accounting functions https://www.notion.so/originprotocol/Limited-simplified-native-staking-accounting-67a217c8420d40678eb943b9da0ee77d In short, after dividing by 32, if the ETH remaining on the contract falls between 0 and fuseIntervalStart, the accounting function will treat that ETH as Beacon chain consensus rewards. On the contrary, if after dividing by 32, the ETH remaining on the contract falls between fuseIntervalEnd and 32, the accounting function will treat that as a validator slashing.Perform the accounting attributing beacon chain ETH to either full or partial withdrawals. Returns true when accounting is valid and fuse isn't \\\"blown\\\". Returns false when fuse is blown.\"},\"exitSsvValidator(bytes,uint64[])\":{\"notice\":\"Exit a validator from the Beacon chain. The staked ETH will eventually swept to this native staking strategy. Only the registrator can call this function.\"},\"fuseIntervalEnd()\":{\"notice\":\"end of fuse interval\"},\"fuseIntervalStart()\":{\"notice\":\"start of fuse interval\"},\"getRewardTokenAddresses()\":{\"notice\":\"Get the reward token addresses.\"},\"governor()\":{\"notice\":\"Returns the address of the current Governor.\"},\"harvesterAddress()\":{\"notice\":\"Address of the Harvester contract allowed to collect reward tokens\"},\"initialize(address[],address[],address[])\":{\"notice\":\"initialize function, to set up initial internal state\"},\"isGovernor()\":{\"notice\":\"Returns true if the caller is the current Governor.\"},\"manuallyFixAccounting(int256,int256,uint256)\":{\"notice\":\"Allow the Strategist to fix the accounting of this strategy and unpause.\"},\"platformAddress()\":{\"notice\":\"Address of the underlying platform\"},\"registerSsvValidator(bytes,uint64[],bytes,uint256,(uint32,uint64,uint64,bool,uint256))\":{\"notice\":\"Registers a new validator in the SSV Cluster. Only the registrator can call this function.\"},\"removePToken(uint256)\":{\"notice\":\"Remove a supported asset by passing its index. This method can only be called by the system Governor\"},\"removeSsvValidator(bytes,uint64[],(uint32,uint64,uint64,bool,uint256))\":{\"notice\":\"Remove a validator from the SSV Cluster. Make sure `exitSsvValidator` is called before and the validate has exited the Beacon chain. If removed before the validator has exited the beacon chain will result in the validator being slashed. Only the registrator can call this function.\"},\"rewardTokenAddresses(uint256)\":{\"notice\":\"Address of the reward tokens. eg CRV, BAL, CVX, AURA\"},\"safeApproveAllTokens()\":{\"notice\":\"Approves the SSV Network contract to transfer SSV tokens for deposits\"},\"setFuseInterval(uint256,uint256)\":{\"notice\":\"set fuse interval values\"},\"setHarvesterAddress(address)\":{\"notice\":\"Set the Harvester contract that can collect rewards.\"},\"setPTokenAddress(address,address)\":{\"notice\":\"Provide support for asset by passing its pToken address. This method can only be called by the system Governor\"},\"setRegistrator(address)\":{\"notice\":\"Set the address of the registrator which can register, exit and remove validators\"},\"setRewardTokenAddresses(address[])\":{\"notice\":\"Set the reward token addresses. Any old addresses will be overwritten.\"},\"stakeEth((bytes,bytes,bytes32)[])\":{\"notice\":\"Stakes WETH to the node validators\"},\"supportsAsset(address)\":{\"notice\":\"Returns bool indicating whether asset is supported by strategy.\"},\"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 strategy contracts, i.e. mistaken sends.\"},\"validatorRegistrator()\":{\"notice\":\"Address of the registrator - allowed to register, exit and remove validators\"},\"validatorsStates(bytes32)\":{\"notice\":\"State of the validators keccak256(pubKey) => state\"},\"vaultAddress()\":{\"notice\":\"Address of the OToken vault\"},\"withdraw(address,address,uint256)\":{\"notice\":\"Withdraw WETH from this contract. Used only if some WETH for is lingering on the contract. That can happen when: - the deposit was not a multiple of 32 WETH - someone sent WETH directly to this contract Will NOT revert if the strategy is paused from an accounting failure.\"},\"withdrawAll()\":{\"notice\":\"transfer all WETH deposits back to the vault. This does not withdraw from the validators. That has to be done separately with the `exitSsvValidator` and `removeSsvValidator` operations. This does not withdraw any execution rewards from the FeeAccumulator or consensus rewards in this strategy. Any ETH in this strategy that was swept from a full validator withdrawal will not be withdrawn. ETH from full validator withdrawals is sent to the Vault using `doAccounting`. Will NOT revert if the strategy is paused from an accounting failure.\"}},\"notice\":\"Strategy to deploy funds into DVT validators powered by the SSV Network\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol\":\"NativeStakingSSVStrategy\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"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\",\"keccak256\":\"0xe68ed7fb8766ed1e888291f881e36b616037f852b37d96877045319ad298ba87\",\"license\":\"MIT\"},\"@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/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\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"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/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\",\"keccak256\":\"0x598f90bdbc854250bbd5991426bfb43367207e64e33109c41aa8b54323fd8d8e\",\"license\":\"MIT\"},\"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 error ApprovalNotWithinTimeframe();\\n error CallerNotOwner();\\n error CallerNotWhitelisted();\\n error ClusterAlreadyEnabled();\\n error ClusterDoesNotExists();\\n error ClusterIsLiquidated();\\n error ClusterNotLiquidatable();\\n error ExceedValidatorLimit();\\n error FeeExceedsIncreaseLimit();\\n error FeeIncreaseNotAllowed();\\n error FeeTooHigh();\\n error FeeTooLow();\\n error IncorrectClusterState();\\n error IncorrectValidatorState();\\n error InsufficientBalance();\\n error InvalidOperatorIdsLength();\\n error InvalidPublicKeyLength();\\n error MaxValueExceeded();\\n error NewBlockPeriodIsBelowMinimum();\\n error NoFeeDeclared();\\n error NotAuthorized();\\n error OperatorAlreadyExists();\\n error OperatorDoesNotExist();\\n error OperatorsListNotUnique();\\n error SameFeeChangeNotAllowed();\\n error TargetModuleDoesNotExist();\\n error TokenTransferFailed();\\n error UnsortedOperatorsList();\\n error ValidatorAlreadyExists();\\n error ValidatorDoesNotExist();\\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 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 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 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\",\"keccak256\":\"0x76e2c5148727b72752939b06fee7abc1f732c18970b8c7db7fe7cdfe74629d36\",\"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/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/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\",\"keccak256\":\"0x05b7dce6c24d3cd4e48b5c6346d86e5e40ecc3291bcdf3f3ef091c98fc826519\",\"license\":\"MIT\"},\"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\\nimport { Governable } from \\\"../../governance/Governable.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 is Governable {\\n /// @notice The address of the Native Staking Strategy\\n address public immutable STRATEGY;\\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 }\\n}\\n\",\"keccak256\":\"0xf47bcc46ce70f649f061bec3d2303f376a15700ba18fe471fba823f60bdfed8b\",\"license\":\"MIT\"},\"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\\\";\\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\\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_ADDRESS;\\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 public immutable FEE_ACCUMULATOR_ADDRESS;\\n\\n // For future use\\n uint256[50] 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 _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 address _feeAccumulator,\\n address _beaconChainDepositContract\\n )\\n InitializableAbstractStrategy(_baseConfig)\\n ValidatorAccountant(\\n _wethAddress,\\n _baseConfig.vaultAddress,\\n _beaconChainDepositContract,\\n _ssvNetwork\\n )\\n {\\n SSV_TOKEN_ADDRESS = _ssvToken;\\n FEE_ACCUMULATOR_ADDRESS = _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 /// @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_TOKEN_ADDRESS).deposit{ value: ethRewards }();\\n\\n emit RewardTokenCollected(\\n harvesterAddress,\\n WETH_TOKEN_ADDRESS,\\n ethRewards\\n );\\n IERC20(WETH_TOKEN_ADDRESS).safeTransfer(\\n harvesterAddress,\\n ethRewards\\n );\\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_TOKEN_ADDRESS, \\\"Unsupported asset\\\");\\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_TOKEN_ADDRESS).balanceOf(\\n address(this)\\n );\\n if (wethBalance > 0) {\\n _deposit(WETH_TOKEN_ADDRESS, wethBalance);\\n }\\n }\\n\\n /// @notice Withdraw WETH from this contract. Used only if some WETH for is lingering on the contract. That\\n /// can happen when:\\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 _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 emit Withdrawal(_asset, address(0), _amount);\\n IERC20(_asset).safeTransfer(_recipient, _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_TOKEN_ADDRESS).balanceOf(\\n address(this)\\n );\\n if (wethBalance > 0) {\\n _withdraw(vaultAddress, WETH_TOKEN_ADDRESS, wethBalance);\\n }\\n }\\n\\n function _abstractSetPToken(address _asset, address) internal override {}\\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_TOKEN_ADDRESS, \\\"Unsupported asset\\\");\\n\\n balance =\\n // add the ETH that has been staked in validators\\n activeDepositedValidators *\\n 32 ether +\\n // add the WETH in the strategy from deposits that are still to be staked\\n IERC20(WETH_TOKEN_ADDRESS).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_TOKEN_ADDRESS;\\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_ADDRESS).approve(\\n SSV_NETWORK_ADDRESS,\\n type(uint256).max\\n );\\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 ||\\n msg.sender == WETH_TOKEN_ADDRESS,\\n \\\"eth not from allowed contracts\\\"\\n );\\n }\\n}\\n\",\"keccak256\":\"0x16d14755655e07e98a4758a1328a8117192b3cb8a4c74725b67c2584560fcb2d\",\"license\":\"MIT\"},\"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 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 MAX_STAKE = 32 ether;\\n\\n /// @notice Keeps track of the total consensus rewards swept from the beacon chain\\n uint256 public consensusRewards = 0;\\n\\n /// @notice start of fuse interval\\n uint256 public fuseIntervalStart = 0;\\n /// @notice end of fuse interval\\n uint256 public fuseIntervalEnd = 0;\\n\\n uint256[50] 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 constructor(\\n address _wethAddress,\\n address _vaultAddress,\\n address _beaconChainDepositContract,\\n address _ssvNetwork\\n )\\n ValidatorRegistrator(\\n _wethAddress,\\n _vaultAddress,\\n _beaconChainDepositContract,\\n _ssvNetwork\\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 _fuseIntervalStart < 32 ether &&\\n _fuseIntervalEnd < 32 ether &&\\n _fuseIntervalEnd - _fuseIntervalStart >= 4 ether,\\n \\\"incorrect fuse interval\\\"\\n );\\n\\n emit FuseIntervalUpdated(_fuseIntervalStart, _fuseIntervalEnd);\\n\\n fuseIntervalStart = _fuseIntervalStart;\\n fuseIntervalEnd = _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 returns (bool accountingValid)\\n {\\n // pause the accounting on failure\\n accountingValid = _doAccounting(true);\\n }\\n\\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 >= MAX_STAKE) {\\n uint256 fullyWithdrawnValidators = newSweptETH / MAX_STAKE;\\n if (activeDepositedValidators < fullyWithdrawnValidators) {\\n return _failAccounting(pauseOnFail);\\n }\\n activeDepositedValidators -= fullyWithdrawnValidators;\\n\\n uint256 wethToVault = MAX_STAKE * fullyWithdrawnValidators;\\n IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: wethToVault }();\\n IWETH9(WETH_TOKEN_ADDRESS).transfer(VAULT_ADDRESS, 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 < 32 ether, \\\"unexpected accounting\\\");\\n\\n // If no Beacon chain consensus rewards swept\\n if (ethRemaining == 0) {\\n // do nothing\\n return accountingValid;\\n }\\n // Beacon chain consensus rewards swept (partial validator withdrawals)\\n else if (ethRemaining < fuseIntervalStart) {\\n // solhint-disable-next-line reentrancy\\n consensusRewards += ethRemaining;\\n emit AccountingConsensusRewards(ethRemaining);\\n }\\n // Beacon chain consensus rewards swept but also a slashed validator fully exited\\n else if (ethRemaining > fuseIntervalEnd) {\\n IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: ethRemaining }();\\n IWETH9(WETH_TOKEN_ADDRESS).transfer(VAULT_ADDRESS, ethRemaining);\\n activeDepositedValidators -= 1;\\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 /// @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 plus one, minus one or unchanged with zero\\n /// @param _wethToVaultAmount the amount of WETH to be sent to the Vault\\n /// @param _consensusRewardsDelta adjust the accounted for consensus rewards up or down\\n function manuallyFixAccounting(\\n int256 _validatorsDelta,\\n int256 _consensusRewardsDelta,\\n uint256 _wethToVaultAmount\\n ) external onlyStrategist whenPaused {\\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(_wethToVaultAmount <= 32 ether, \\\"invalid wethToVaultAmount\\\");\\n\\n emit AccountingManuallyFixed(\\n _validatorsDelta,\\n _consensusRewardsDelta,\\n _wethToVaultAmount\\n );\\n\\n activeDepositedValidators = uint256(\\n int256(activeDepositedValidators) + _validatorsDelta\\n );\\n consensusRewards = uint256(\\n int256(consensusRewards) + _consensusRewardsDelta\\n );\\n if (_wethToVaultAmount > 0) {\\n IWETH9(WETH_TOKEN_ADDRESS).transfer(\\n VAULT_ADDRESS,\\n _wethToVaultAmount\\n );\\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\",\"keccak256\":\"0xc6c306bde6b18189944f3d03fc82996b2e0c54b3a2882ee8d0fece0d71949e11\",\"license\":\"MIT\"},\"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 address of the Wrapped ETH (WETH) token contract\\n address public immutable WETH_TOKEN_ADDRESS;\\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_ADDRESS;\\n /// @notice Address of the OETH Vault proxy contract\\n address public immutable VAULT_ADDRESS;\\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\\n // For future use\\n uint256[50] private __gap;\\n\\n enum VALIDATOR_STATE {\\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 newAddress);\\n event ETHStaked(bytes pubkey, uint256 amount, bytes withdrawal_credentials);\\n event SSVValidatorRegistered(bytes pubkey, uint64[] operatorIds);\\n event SSVValidatorExitInitiated(bytes pubkey, uint64[] operatorIds);\\n event SSVValidatorExitCompleted(bytes pubkey, uint64[] operatorIds);\\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 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 constructor(\\n address _wethAddress,\\n address _vaultAddress,\\n address _beaconChainDepositContract,\\n address _ssvNetwork\\n ) {\\n WETH_TOKEN_ADDRESS = _wethAddress;\\n BEACON_CHAIN_DEPOSIT_CONTRACT = _beaconChainDepositContract;\\n SSV_NETWORK_ADDRESS = _ssvNetwork;\\n VAULT_ADDRESS = _vaultAddress;\\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 emit RegistratorChanged(_address);\\n validatorRegistrator = _address;\\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 function stakeEth(ValidatorStakeData[] calldata validators)\\n external\\n onlyRegistrator\\n whenNotPaused\\n {\\n uint256 requiredETH = validators.length * 32 ether;\\n\\n // Check there is enough WETH from the deposits sitting in this strategy contract\\n require(\\n requiredETH <= IWETH9(WETH_TOKEN_ADDRESS).balanceOf(address(this)),\\n \\\"insufficient WETH\\\"\\n );\\n\\n // Convert required ETH from WETH\\n IWETH9(WETH_TOKEN_ADDRESS).withdraw(requiredETH);\\n\\n // For each validator\\n for (uint256 i = 0; i < validators.length; ) {\\n bytes32 pubkeyHash = keccak256(validators[i].pubkey);\\n VALIDATOR_STATE currentState = validatorsStates[pubkeyHash];\\n\\n require(\\n currentState == VALIDATOR_STATE.REGISTERED,\\n \\\"Validator not registered\\\"\\n );\\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 withdrawal_credentials = abi.encodePacked(\\n bytes1(0x01),\\n bytes11(0),\\n address(this)\\n );\\n IDepositContract(BEACON_CHAIN_DEPOSIT_CONTRACT).deposit{\\n value: 32 ether\\n }(\\n validators[i].pubkey,\\n withdrawal_credentials,\\n validators[i].signature,\\n validators[i].depositDataRoot\\n );\\n\\n activeDepositedValidators += 1;\\n emit ETHStaked(\\n validators[i].pubkey,\\n 32 ether,\\n withdrawal_credentials\\n );\\n\\n validatorsStates[pubkeyHash] = VALIDATOR_STATE.STAKED;\\n\\n unchecked {\\n ++i;\\n }\\n }\\n }\\n\\n /// @notice Registers a new validator in the SSV Cluster.\\n /// Only the registrator can call this function.\\n function registerSsvValidator(\\n bytes calldata publicKey,\\n uint64[] calldata operatorIds,\\n bytes calldata sharesData,\\n uint256 amount,\\n Cluster calldata cluster\\n ) external onlyRegistrator whenNotPaused {\\n ISSVNetwork(SSV_NETWORK_ADDRESS).registerValidator(\\n publicKey,\\n operatorIds,\\n sharesData,\\n amount,\\n cluster\\n );\\n validatorsStates[keccak256(publicKey)] = VALIDATOR_STATE.REGISTERED;\\n emit SSVValidatorRegistered(publicKey, operatorIds);\\n }\\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 function exitSsvValidator(\\n bytes calldata publicKey,\\n uint64[] calldata operatorIds\\n ) external onlyRegistrator whenNotPaused {\\n VALIDATOR_STATE currentState = validatorsStates[keccak256(publicKey)];\\n require(currentState == VALIDATOR_STATE.STAKED, \\\"Validator not staked\\\");\\n\\n ISSVNetwork(SSV_NETWORK_ADDRESS).exitValidator(publicKey, operatorIds);\\n emit SSVValidatorExitInitiated(publicKey, operatorIds);\\n\\n validatorsStates[keccak256(publicKey)] = VALIDATOR_STATE.EXITING;\\n }\\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 function removeSsvValidator(\\n bytes calldata publicKey,\\n uint64[] calldata operatorIds,\\n Cluster calldata cluster\\n ) external onlyRegistrator whenNotPaused {\\n VALIDATOR_STATE currentState = validatorsStates[keccak256(publicKey)];\\n require(\\n currentState == VALIDATOR_STATE.EXITING,\\n \\\"Validator not exiting\\\"\\n );\\n\\n ISSVNetwork(SSV_NETWORK_ADDRESS).removeValidator(\\n publicKey,\\n operatorIds,\\n cluster\\n );\\n emit SSVValidatorExitCompleted(publicKey, operatorIds);\\n\\n validatorsStates[keccak256(publicKey)] = VALIDATOR_STATE.EXIT_COMPLETE;\\n }\\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 cluster The SSV cluster details that must be derived from emitted events from the SSVNetwork contract.\\n function depositSSV(\\n uint64[] memory operatorIds,\\n uint256 amount,\\n Cluster memory cluster\\n ) external onlyStrategist {\\n ISSVNetwork(SSV_NETWORK_ADDRESS).deposit(\\n address(this),\\n operatorIds,\\n amount,\\n cluster\\n );\\n }\\n}\\n\",\"keccak256\":\"0x4bc23d19500e2d306fd546c4ab9c4c53292d4ef54392ec4f1ae62dd7601a3d24\",\"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/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\",\"keccak256\":\"0x5e17bb3db9f9e1014b7c5c836547f8fa81e02af7568c0bb8f2a2e0e7c2192db4\",\"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/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": "0x610180604052600060685560006069556000606a553480156200002157600080fd5b5060405162004c9a38038062004c9a833981016040819052620000449162000147565b8585876020015183868383838362000062336200011760201b60201c565b60008051602062004c7a833981519152546040516001600160a01b03909116906000907fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a908290a36033805460ff191690556001600160601b0319606094851b811660805291841b821660a052831b811660c05290821b811660e0528651821b811661010052602090960151811b86166101205298891b851661014052505050509190931b1661016052506200022292505050565b60008051602062004c7a83398151915255565b80516001600160a01b03811681146200014257600080fd5b919050565b60008060008060008086880360e08112156200016257600080fd5b60408112156200017157600080fd5b50604080519081016001600160401b0381118282101715620001a357634e487b7160e01b600052604160045260246000fd5b604052620001b1886200012a565b8152620001c1602089016200012a565b60208201529550620001d6604088016200012a565b9450620001e6606088016200012a565b9350620001f6608088016200012a565b92506200020660a088016200012a565b91506200021660c088016200012a565b90509295509295509295565b60805160601c60a05160601c60c05160601c60e05160601c6101005160601c6101205160601c6101405160601c6101605160601c6148c2620003b8600039600081816102a70152818161096e0152612da901526000818161057d01526122fc01526000818161045101528181610d41015281816118c001528181611a390152818161265b01526128e30152600061093a0152600081816106ec01528181610b09015281816117ee01528181611a8901528181611d6c0152818161332201526135730152600081816109b701528181610bdf015281816116c0015281816122cc015281816123e401526127d90152600081816108a601526114070152600081816102d9015281816104db015281816107bd01528181610a7001528181610db601528181610f850152818161100d015281816111bc01528181611297015281816119aa01528181611a5a01528181611d9b0152818161296e015281816129fd01528181612eae01528181612f3301528181612fa70152818161329c01528181613351015281816134ed01526135a201526148c26000f3fe6080604052600436106102975760003560e01c8063853828b61161015a578063c2e1e3f4116100c1578063d9f00ec71161007a578063d9f00ec714610908578063dbe55e5614610928578063dd505df61461095c578063de5f626814610990578063f1188e40146109a5578063f6ca71b0146109d957600080fd5b8063c2e1e3f414610842578063c7af335214610862578063c98517c514610877578063cceab75014610894578063d38bfff4146108c8578063d9caed12146108e857600080fd5b80639da0e462116101135780639da0e4621461074e578063a4f98af41461078b578063aa388af6146107a0578063ab12edf5146107ed578063ad1728cb1461080d578063bb1b918d1461082257600080fd5b8063853828b61461068057806387bae867146106955780638d7c0e46146106ba5780639092c31c146106da5780639136616a1461070e57806396d538bb1461072e57600080fd5b80635c975abb116101fe5780636e811d38116101b75780636e811d38146105d55780636ef38795146105f557806371a735f3146106155780637b2d9b2c14610635578063842f5c46146106555780638456cb591461066b57600080fd5b80635c975abb146105125780635d36b190146105365780635f5152261461054b5780636093d3801461056b57806366e3667e1461059f57806367c7066c146105b557600080fd5b8063430bf08a11610250578063430bf08a1461043f578063435356d11461047357806347e7ef2414610493578063484be812146104b3578063579a7e1a146104c95780635a063f63146104fd57600080fd5b80630c340a24146103535780630ed57b3a146103855780630fc3b4c4146103a55780631072cbea146103db57806322495dc8146103fb5780633c8649591461041b57600080fd5b3661034e57336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614806102fb5750336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016145b61034c5760405162461bcd60e51b815260206004820152601e60248201527f657468206e6f742066726f6d20616c6c6f77656420636f6e747261637473000060448201526064015b60405180910390fd5b005b600080fd5b34801561035f57600080fd5b506103686109fb565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561039157600080fd5b5061034c6103a0366004613c43565b610a18565b3480156103b157600080fd5b506103686103c0366004613c09565b609f602052600090815260409020546001600160a01b031681565b3480156103e757600080fd5b5061034c6103f6366004613cbd565b610a4a565b34801561040757600080fd5b5061034c610416366004613db1565b610b07565b34801561042757600080fd5b5061043160695481565b60405190815260200161037c565b34801561044b57600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b34801561047f57600080fd5b5061034c61048e366004613d2a565b610c51565b34801561049f57600080fd5b5061034c6104ae366004613cbd565b610d36565b3480156104bf57600080fd5b50610431606a5481565b3480156104d557600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b34801561050957600080fd5b5061034c610e3c565b34801561051e57600080fd5b5060335460ff165b604051901515815260200161037c565b34801561054257600080fd5b5061034c610edb565b34801561055757600080fd5b50610431610566366004613c09565b610f81565b34801561057757600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b3480156105ab57600080fd5b5061043160345481565b3480156105c157600080fd5b5060a354610368906001600160a01b031681565b3480156105e157600080fd5b5061034c6105f0366004613c09565b6110b5565b34801561060157600080fd5b5061034c610610366004613ce9565b61113d565b34801561062157600080fd5b5061034c610630366004613fbf565b6115c9565b34801561064157600080fd5b50610368610650366004613e87565b6117c2565b34801561066157600080fd5b5061043160685481565b34801561067757600080fd5b5061034c6117ec565b34801561068c57600080fd5b5061034c6118b5565b3480156106a157600080fd5b506033546103689061010090046001600160a01b031681565b3480156106c657600080fd5b5061034c6106d5366004614040565b611a87565b3480156106e657600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b34801561071a57600080fd5b5061034c610729366004613e87565b611e6f565b34801561073a57600080fd5b5061034c610749366004613ce9565b61203a565b34801561075a57600080fd5b5061077e610769366004613e87565b60356020526000908152604090205460ff1681565b60405161037c91906144ab565b34801561079757600080fd5b5061052661215a565b3480156107ac57600080fd5b506105266107bb366004613c09565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0390811691161490565b3480156107f957600080fd5b5061034c610808366004614085565b6121b9565b34801561081957600080fd5b5061034c6122b5565b34801561082e57600080fd5b5061034c61083d366004613f0b565b61237b565b34801561084e57600080fd5b5061034c61085d366004613c09565b6124ee565b34801561086e57600080fd5b5061052661257b565b34801561088357600080fd5b506104316801bc16d674ec80000081565b3480156108a057600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b3480156108d457600080fd5b5061034c6108e3366004613c09565b6125ac565b3480156108f457600080fd5b5061034c610903366004613c7c565b612650565b34801561091457600080fd5b5061034c610923366004613ea0565b6126e3565b34801561093457600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b34801561096857600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b34801561099c57600080fd5b5061034c6128d8565b3480156109b157600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b3480156109e557600080fd5b506109ee612a22565b60405161037c9190614281565b6000610a1360008051602061486d8339815191525490565b905090565b610a2061257b565b610a3c5760405162461bcd60e51b81526004016103439061451d565b610a468282612a84565b5050565b610a5261257b565b610a6e5760405162461bcd60e51b81526004016103439061451d565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b039081169083161415610aeb5760405162461bcd60e51b815260206004820152601f60248201527f43616e6e6f74207472616e7366657220737570706f72746564206173736574006044820152606401610343565b610a46610af66109fb565b6001600160a01b0384169083612be3565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b158015610b6057600080fd5b505afa158015610b74573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b989190613c26565b6001600160a01b0316336001600160a01b031614610bc85760405162461bcd60e51b8152600401610343906145dd565b60405163bc26e7e560e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063bc26e7e590610c1a9030908790879087906004016141d1565b600060405180830381600087803b158015610c3457600080fd5b505af1158015610c48573d6000803e3d6000fd5b50505050505050565b610c5961257b565b610c755760405162461bcd60e51b81526004016103439061451d565b600054610100900460ff1680610c8e575060005460ff16155b610cf15760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610343565b600054610100900460ff16158015610d13576000805461ffff19166101011790555b610d1e848484612c35565b8015610d30576000805461ff00191690555b50505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610d7e5760405162461bcd60e51b8152600401610343906144e6565b60008051602061484d83398151915280546002811415610db05760405162461bcd60e51b8152600401610343906145b5565b600282557f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316846001600160a01b031614610e295760405162461bcd60e51b8152602060048201526011602482015270155b9cdd5c1c1bdc9d195908185cdcd95d607a1b6044820152606401610343565b610e338484612cf0565b50600190555050565b60a3546001600160a01b03163314610e965760405162461bcd60e51b815260206004820152601b60248201527f43616c6c6572206973206e6f74207468652048617276657374657200000000006044820152606401610343565b60008051602061484d83398151915280546002811415610ec85760405162461bcd60e51b8152600401610343906145b5565b60028255610ed4612d82565b5060019055565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b031614610f765760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b6064820152608401610343565b610f7f33612fd0565b565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b031614610ff85760405162461bcd60e51b8152602060048201526011602482015270155b9cdd5c1c1bdc9d195908185cdcd95d607a1b6044820152606401610343565b6040516370a0823160e01b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b15801561105757600080fd5b505afa15801561106b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061108f919061406c565b6034546110a5906801bc16d674ec80000061473e565b6110af9190614704565b92915050565b6110bd61257b565b6110d95760405162461bcd60e51b81526004016103439061451d565b6040516001600160a01b03821681527f83f29c79feb71f8fba9d0fbc4ba5f0982a28b6b1e868b3fc50e6400d100bca0f9060200160405180910390a1603380546001600160a01b0390921661010002610100600160a81b0319909216919091179055565b60335461010090046001600160a01b0316331461116c5760405162461bcd60e51b81526004016103439061457e565b60335460ff161561118f5760405162461bcd60e51b815260040161034390614554565b60006111a4826801bc16d674ec80000061473e565b6040516370a0823160e01b81523060048201529091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b15801561120657600080fd5b505afa15801561121a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061123e919061406c565b8111156112815760405162461bcd60e51b81526020600482015260116024820152700d2dce6eaccccd2c6d2cadce840ae8aa89607b1b6044820152606401610343565b604051632e1a7d4d60e01b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b1580156112e357600080fd5b505af11580156112f7573d6000803e3d6000fd5b5050505060005b82811015610d3057600084848381811061131a5761131a6147fd565b905060200281019061132c919061465a565b6113369080614614565b6040516113449291906141a5565b6040805191829003909120600081815260356020529182205490925060ff1690816003811115611376576113766147d1565b146113c35760405162461bcd60e51b815260206004820152601860248201527f56616c696461746f72206e6f74207265676973746572656400000000000000006044820152606401610343565b60408051600160f81b60208201526000602182018190526bffffffffffffffffffffffff193060601b16602c830152910160405160208183030381529060405290507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663228951186801bc16d674ec800000898988818110611450576114506147fd565b9050602002810190611462919061465a565b61146c9080614614565b858c8c8b81811061147f5761147f6147fd565b9050602002810190611491919061465a565b61149f906020810190614614565b8e8e8d8181106114b1576114b16147fd565b90506020028101906114c3919061465a565b604001356040518863ffffffff1660e01b81526004016114e896959493929190614430565b6000604051808303818588803b15801561150157600080fd5b505af1158015611515573d6000803e3d6000fd5b505050505060016034600082825461152d9190614704565b909155507ffeb31a79d38edb1b090d516e4df3e273651179c6f2c2ec53a9a22ae015b70ba99050878786818110611566576115666147fd565b9050602002810190611578919061465a565b6115829080614614565b6801bc16d674ec8000008460405161159d949392919061447f565b60405180910390a150506000908152603560205260409020805460ff19166001908117909155016112fe565b60335461010090046001600160a01b031633146115f85760405162461bcd60e51b81526004016103439061457e565b60335460ff161561161b5760405162461bcd60e51b815260040161034390614554565b60006035600087876040516116319291906141a5565b604080519182900390912082526020820192909252016000205460ff1690506002816003811115611664576116646147d1565b146116a95760405162461bcd60e51b815260206004820152601560248201527456616c696461746f72206e6f742065786974696e6760581b6044820152606401610343565b6040516312b3fc1960e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906312b3fc19906116fd90899089908990899089906004016143ef565b600060405180830381600087803b15801561171757600080fd5b505af115801561172b573d6000803e3d6000fd5b505050507ff72821b8777f002ccdf6326f1242d9e0f762eb077668b67bebe640535378066d868686866040516117649493929190614366565b60405180910390a160036035600088886040516117829291906141a5565b60408051918290039091208252602082019290925201600020805460ff191660018360038111156117b5576117b56147d1565b0217905550505050505050565b60a481815481106117d257600080fd5b6000918252602090912001546001600160a01b0316905081565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b15801561184557600080fd5b505afa158015611859573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061187d9190613c26565b6001600160a01b0316336001600160a01b0316146118ad5760405162461bcd60e51b8152600401610343906145dd565b610f7f613091565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016148061190457506118ef6109fb565b6001600160a01b0316336001600160a01b0316145b61195c5760405162461bcd60e51b815260206004820152602360248201527f43616c6c6572206973206e6f7420746865205661756c74206f7220476f7665726044820152623737b960e91b6064820152608401610343565b60008051602061484d8339815191528054600281141561198e5760405162461bcd60e51b8152600401610343906145b5565b600282556040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b1580156119f457600080fd5b505afa158015611a08573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a2c919061406c565b90508015611a7f57611a7f7f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000083613106565b505060019055565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b158015611ae057600080fd5b505afa158015611af4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b189190613c26565b6001600160a01b0316336001600160a01b031614611b485760405162461bcd60e51b8152600401610343906145dd565b60335460ff16611b915760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610343565b6002198312158015611ba4575060038313155b8015611bbe5750600083603454611bbb91906146c3565b12155b611c0a5760405162461bcd60e51b815260206004820152601760248201527f696e76616c69642076616c696461746f727344656c74610000000000000000006044820152606401610343565b6811ff6cf0fd15afffff198212158015611c2d57506811ff6cf0fd15b000008213155b8015611c475750600082606854611c4491906146c3565b12155b611c935760405162461bcd60e51b815260206004820152601d60248201527f696e76616c696420636f6e73656e7375735265776172647344656c74610000006044820152606401610343565b6801bc16d674ec800000811115611cec5760405162461bcd60e51b815260206004820152601960248201527f696e76616c69642077657468546f5661756c74416d6f756e74000000000000006044820152606401610343565b60408051848152602081018490529081018290527f80d022717ea022455c5886b8dd8a29c037570aae58aeb4d7b136d7a10ec2e4319060600160405180910390a182603454611d3b91906146c3565b603455606854611d4c9083906146c3565b6068558015611e195760405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018390527f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb90604401602060405180830381600087803b158015611ddf57600080fd5b505af1158015611df3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e179190613e6a565b505b611e2360006131fe565b611e625760405162461bcd60e51b815260206004820152601060248201526f333ab9b29039ba34b63610313637bbb760811b6044820152606401610343565b611e6a613684565b505050565b611e7761257b565b611e935760405162461bcd60e51b81526004016103439061451d565b60a0548110611ed45760405162461bcd60e51b815260206004820152600d60248201526c092dcecc2d8d2c840d2dcc8caf609b1b6044820152606401610343565b600060a08281548110611ee957611ee96147fd565b60009182526020808320909101546001600160a01b03908116808452609f90925260409092205460a05491935090911690611f269060019061475d565b831015611fa85760a08054611f3d9060019061475d565b81548110611f4d57611f4d6147fd565b60009182526020909120015460a080546001600160a01b039092169185908110611f7957611f796147fd565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505b60a0805480611fb957611fb96147e7565b60008281526020808220600019908401810180546001600160a01b031990811690915593019093556001600160a01b03858116808352609f855260409283902080549094169093559051908416815290917f16b7600acff27e39a8a96056b3d533045298de927507f5c1d97e4accde60488c910160405180910390a2505050565b61204261257b565b61205e5760405162461bcd60e51b81526004016103439061451d565b8060005b8181101561211157600084848381811061207e5761207e6147fd565b90506020020160208101906120939190613c09565b6001600160a01b031614156121015760405162461bcd60e51b815260206004820152602e60248201527f43616e206e6f742073657420616e20656d70747920616464726573732061732060448201526d30903932bbb0b932103a37b5b2b760911b6064820152608401610343565b61210a816147a0565b9050612062565b507f04c0b9649497d316554306e53678d5f5f5dbc3a06f97dec13ff4cfe98b986bbc60a48484604051612146939291906142ce565b60405180910390a1610d3060a48484613962565b60335460009061010090046001600160a01b0316331461218c5760405162461bcd60e51b81526004016103439061457e565b60335460ff16156121af5760405162461bcd60e51b815260040161034390614554565b610a1360016131fe565b6121c161257b565b6121dd5760405162461bcd60e51b81526004016103439061451d565b80821080156121f457506801bc16d674ec80000082105b801561220857506801bc16d674ec80000081105b80156122255750673782dace9d900000612222838361475d565b10155b6122715760405162461bcd60e51b815260206004820152601760248201527f696e636f7272656374206675736520696e74657276616c0000000000000000006044820152606401610343565b60408051838152602081018390527fcb8d24e46eb3c402bf344ee60a6576cba9ef2f59ea1af3b311520704924e901a910160405180910390a1606991909155606a55565b60405163095ea7b360e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015260001960248301527f0000000000000000000000000000000000000000000000000000000000000000169063095ea7b390604401602060405180830381600087803b15801561234057600080fd5b505af1158015612354573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123789190613e6a565b50565b60335461010090046001600160a01b031633146123aa5760405162461bcd60e51b81526004016103439061457e565b60335460ff16156123cd5760405162461bcd60e51b815260040161034390614554565b6040516301ba3ee760e21b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906306e8fb9c90612427908b908b908b908b908b908b908b908b9060040161438d565b600060405180830381600087803b15801561244157600080fd5b505af1158015612455573d6000803e3d6000fd5b505050506000603560008a8a60405161246f9291906141a5565b60408051918290039091208252602082019290925201600020805460ff191660018360038111156124a2576124a26147d1565b02179055507f75c4a66b2c6c28cf46db7131182a812e4fbbb2f0591377aa83a737909a9b68c3888888886040516124dc9493929190614366565b60405180910390a15050505050505050565b6124f661257b565b6125125760405162461bcd60e51b81526004016103439061451d565b60a354604080516001600160a01b03928316815291831660208301527fe48386b84419f4d36e0f96c10cc3510b6fb1a33795620c5098b22472bbe90796910160405180910390a160a380546001600160a01b0319166001600160a01b0392909216919091179055565b600061259360008051602061486d8339815191525490565b6001600160a01b0316336001600160a01b031614905090565b6125b461257b565b6125d05760405162461bcd60e51b81526004016103439061451d565b6125f8817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b031661261860008051602061486d8339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146126985760405162461bcd60e51b8152600401610343906144e6565b60008051602061484d833981519152805460028114156126ca5760405162461bcd60e51b8152600401610343906145b5565b600282556126d9858585613106565b5060019055505050565b60335461010090046001600160a01b031633146127125760405162461bcd60e51b81526004016103439061457e565b60335460ff16156127355760405162461bcd60e51b815260040161034390614554565b600060356000868660405161274b9291906141a5565b604080519182900390912082526020820192909252016000205460ff169050600181600381111561277e5761277e6147d1565b146127c25760405162461bcd60e51b815260206004820152601460248201527315985b1a59185d1bdc881b9bdd081cdd185ad95960621b6044820152606401610343565b604051633877322b60e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690633877322b90612814908890889088908890600401614366565b600060405180830381600087803b15801561282e57600080fd5b505af1158015612842573d6000803e3d6000fd5b505050507ff8821da16f5ed966b41e0343c3eff9903af782d74f99f1689dd9d4562b6545b38585858560405161287b9493929190614366565b60405180910390a160026035600087876040516128999291906141a5565b60408051918290039091208252602082019290925201600020805460ff191660018360038111156128cc576128cc6147d1565b02179055505050505050565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146129205760405162461bcd60e51b8152600401610343906144e6565b60008051602061484d833981519152805460028114156129525760405162461bcd60e51b8152600401610343906145b5565b600282556040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b1580156129b857600080fd5b505afa1580156129cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129f0919061406c565b90508015611a7f57611a7f7f000000000000000000000000000000000000000000000000000000000000000082612cf0565b606060a4805480602002602001604051908101604052809291908181526020018280548015612a7a57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612a5c575b5050505050905090565b6001600160a01b038281166000908152609f60205260409020541615612ae15760405162461bcd60e51b81526020600482015260126024820152711c151bdad95b88185b1c9958591e481cd95d60721b6044820152606401610343565b6001600160a01b03821615801590612b0157506001600160a01b03811615155b612b415760405162461bcd60e51b8152602060048201526011602482015270496e76616c69642061646472657373657360781b6044820152606401610343565b6001600160a01b038281166000818152609f6020908152604080832080549587166001600160a01b0319968716811790915560a0805460018101825594527f78fdc8d422c49ced035a9edf18d00d3c6a8d81df210f3e5e448e045e77b41e8890930180549095168417909455925190815290917fef6485b84315f9b1483beffa32aae9a0596890395e3d7521f1c5fbb51790e765910160405180910390a25050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052611e6a9084906136fe565b8251612c489060a49060208601906139c5565b50815181518114612c925760405162461bcd60e51b8152602060048201526014602482015273496e76616c696420696e7075742061727261797360601b6044820152606401610343565b60005b81811015612ce957612cd9848281518110612cb257612cb26147fd565b6020026020010151848381518110612ccc57612ccc6147fd565b6020026020010151612a84565b612ce2816147a0565b9050612c95565b5050505050565b60008111612d395760405162461bcd60e51b81526020600482015260166024820152754d757374206465706f73697420736f6d657468696e6760501b6044820152606401610343565b6040805160008152602081018390526001600160a01b038416917f5548c837ab068cf56a2c2479df0882a4922fd203edb7517321831d95078c5f62910160405180910390a25050565b60335460ff1615612da55760405162461bcd60e51b815260040161034390614554565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663e52253816040518163ffffffff1660e01b8152600401602060405180830381600087803b158015612e0257600080fd5b505af1158015612e16573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e3a919061406c565b9050600060685482612e4c9190614704565b905080471015612e9e5760405162461bcd60e51b815260206004820152601860248201527f696e73756666696369656e74206574682062616c616e636500000000000000006044820152606401610343565b8015610a465760006068819055507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b158015612f0757600080fd5b505af1158015612f1b573d6000803e3d6000fd5b505060a354604080516001600160a01b0392831681527f0000000000000000000000000000000000000000000000000000000000000000909216602083015281018590527ff6c07a063ed4e63808eb8da7112d46dbcd38de2b40a73dbcc9353c5a94c7235393506060019150612f8e9050565b60405180910390a160a354610a46906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116911683612be3565b6001600160a01b0381166130265760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f7220697320616464726573732830290000000000006044820152606401610343565b806001600160a01b031661304660008051602061486d8339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a36123788160008051602061486d83398151915255565b60335460ff16156130b45760405162461bcd60e51b815260040161034390614554565b6033805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586130e93390565b6040516001600160a01b03909116815260200160405180910390a1565b600081116131565760405162461bcd60e51b815260206004820152601760248201527f4d75737420776974686472617720736f6d657468696e670000000000000000006044820152606401610343565b6001600160a01b0383166131a55760405162461bcd60e51b8152602060048201526016602482015275135d5cdd081cdc1958da599e481c9958da5c1a595b9d60521b6044820152606401610343565b6040805160008152602081018390526001600160a01b038416917f2717ead6b9200dd235aad468c9809ea400fe33ac69b5bfaa6d3e90fc922b6398910160405180910390a2611e6a6001600160a01b0383168483612be3565b6000606854471015613213576110af826137d0565b600060685447613223919061475d565b9050600191506801bc16d674ec800000811061341957600061324e6801bc16d674ec8000008361471c565b905080603454101561326b57613263846137d0565b949350505050565b806034600082825461327d919061475d565b9091555060009050613298826801bc16d674ec80000061473e565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b1580156132f557600080fd5b505af1158015613309573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb92506044019050602060405180830381600087803b15801561339957600080fd5b505af11580156133ad573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133d19190613e6a565b5060345460408051848152602081019290925281018290527fbe7040030ff7b347853214bf49820c6d455fedf58f3815f85c7bc5216993682b9060600160405180910390a150505b600060685447613429919061475d565b90506801bc16d674ec800000811061347b5760405162461bcd60e51b8152602060048201526015602482015274756e6578706563746564206163636f756e74696e6760581b6044820152606401610343565b80613487575050919050565b6069548110156134e15780606860008282546134a39190614704565b90915550506040518181527f7a745a2c63a535068f52ceca27debd5297bbad5f7f37ec53d044a59d0362445d906020015b60405180910390a161367d565b606a54811115613674577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b15801561354657600080fd5b505af115801561355a573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb92506044019050602060405180830381600087803b1580156135ea57600080fd5b505af11580156135fe573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136229190613e6a565b50600160346000828254613636919061475d565b909155505060345460408051918252602082018390527f6aa7e30787b26429ced603a7aba8b19c4b5d5bcf29a3257da953c8d53bcaa3a691016134d4565b613263846137d0565b5050919050565b60335460ff166136cd5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610343565b6033805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa336130e9565b6000613753826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166137e89092919063ffffffff16565b805190915015611e6a57808060200190518101906137719190613e6a565b611e6a5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610343565b600081156137e0576137e0613091565b506000919050565b60606137f78484600085613801565b90505b9392505050565b6060824710156138625760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610343565b843b6138b05760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610343565b600080866001600160a01b031685876040516138cc91906141b5565b60006040518083038185875af1925050503d8060008114613909576040519150601f19603f3d011682016040523d82523d6000602084013e61390e565b606091505b509150915061391e828286613929565b979650505050505050565b606083156139385750816137fa565b8251156139485782518084602001fd5b8160405162461bcd60e51b815260040161034391906144d3565b8280548282559060005260206000209081019282156139b5579160200282015b828111156139b55781546001600160a01b0319166001600160a01b03843516178255602090920191600190910190613982565b506139c1929150613a1a565b5090565b8280548282559060005260206000209081019282156139b5579160200282015b828111156139b557825182546001600160a01b0319166001600160a01b039091161782556020909201916001909101906139e5565b5b808211156139c15760008155600101613a1b565b60008083601f840112613a4157600080fd5b5081356001600160401b03811115613a5857600080fd5b6020830191508360208260051b8501011115613a7357600080fd5b9250929050565b600082601f830112613a8b57600080fd5b81356020613aa0613a9b836146a0565b614670565b80838252828201915082860187848660051b8901011115613ac057600080fd5b60005b85811015613ae8578135613ad681614829565b84529284019290840190600101613ac3565b5090979650505050505050565b60008083601f840112613b0757600080fd5b5081356001600160401b03811115613b1e57600080fd5b602083019150836020828501011115613a7357600080fd5b600060a08284031215613b4857600080fd5b50919050565b600060a08284031215613b6057600080fd5b60405160a081018181106001600160401b0382111715613b8257613b82614813565b604052905080613b9183613bd9565b8152613b9f60208401613bf2565b6020820152613bb060408401613bf2565b60408201526060830135613bc38161483e565b6060820152608092830135920191909152919050565b803563ffffffff81168114613bed57600080fd5b919050565b80356001600160401b0381168114613bed57600080fd5b600060208284031215613c1b57600080fd5b81356137fa81614829565b600060208284031215613c3857600080fd5b81516137fa81614829565b60008060408385031215613c5657600080fd5b8235613c6181614829565b91506020830135613c7181614829565b809150509250929050565b600080600060608486031215613c9157600080fd5b8335613c9c81614829565b92506020840135613cac81614829565b929592945050506040919091013590565b60008060408385031215613cd057600080fd5b8235613cdb81614829565b946020939093013593505050565b60008060208385031215613cfc57600080fd5b82356001600160401b03811115613d1257600080fd5b613d1e85828601613a2f565b90969095509350505050565b600080600060608486031215613d3f57600080fd5b83356001600160401b0380821115613d5657600080fd5b613d6287838801613a7a565b94506020860135915080821115613d7857600080fd5b613d8487838801613a7a565b93506040860135915080821115613d9a57600080fd5b50613da786828701613a7a565b9150509250925092565b600080600060e08486031215613dc657600080fd5b83356001600160401b03811115613ddc57600080fd5b8401601f81018613613ded57600080fd5b80356020613dfd613a9b836146a0565b8083825282820191508285018a848660051b8801011115613e1d57600080fd5b600095505b84861015613e4757613e3381613bf2565b835260019590950194918301918301613e22565b509650508601359350613e61915086905060408601613b4e565b90509250925092565b600060208284031215613e7c57600080fd5b81516137fa8161483e565b600060208284031215613e9957600080fd5b5035919050565b60008060008060408587031215613eb657600080fd5b84356001600160401b0380821115613ecd57600080fd5b613ed988838901613af5565b90965094506020870135915080821115613ef257600080fd5b50613eff87828801613a2f565b95989497509550505050565b600080600080600080600080610120898b031215613f2857600080fd5b88356001600160401b0380821115613f3f57600080fd5b613f4b8c838d01613af5565b909a50985060208b0135915080821115613f6457600080fd5b613f708c838d01613a2f565b909850965060408b0135915080821115613f8957600080fd5b50613f968b828c01613af5565b90955093505060608901359150613fb08a60808b01613b36565b90509295985092959890939650565b600080600080600060e08688031215613fd757600080fd5b85356001600160401b0380821115613fee57600080fd5b613ffa89838a01613af5565b9097509550602088013591508082111561401357600080fd5b5061402088828901613a2f565b909450925061403490508760408801613b36565b90509295509295909350565b60008060006060848603121561405557600080fd5b505081359360208301359350604090920135919050565b60006020828403121561407e57600080fd5b5051919050565b6000806040838503121561409857600080fd5b50508035926020909101359150565b8183526000602080850194508260005b858110156140e3576001600160401b036140d083613bf2565b16875295820195908201906001016140b7565b509495945050505050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6000815180845261412f816020860160208601614774565b601f01601f19169290920160200192915050565b63ffffffff61415182613bd9565b16825261416060208201613bf2565b6001600160401b0380821660208501528061417d60408501613bf2565b166040850152505060608101356141938161483e565b15156060830152608090810135910152565b8183823760009101908152919050565b600082516141c7818460208701614774565b9190910192915050565b6001600160a01b03851681526101006020808301829052855191830182905260009161012084019187810191845b818110156142245783516001600160401b0316855293820193928201926001016141ff565b505082935086604086015263ffffffff865116606086015280860151925050506001600160401b0380821660808501528060408601511660a085015250506060830151151560c0830152608083015160e083015295945050505050565b6020808252825182820181905260009190848201906040850190845b818110156142c25783516001600160a01b03168352928401929184019160010161429d565b50909695505050505050565b6000604082016040835280865480835260608501915087600052602092508260002060005b828110156143185781546001600160a01b0316845292840192600191820191016142f3565b505050838103828501528481528590820160005b8681101561435a57823561433f81614829565b6001600160a01b03168252918301919083019060010161432c565b50979650505050505050565b60408152600061437a6040830186886140ee565b828103602084015261391e8185876140a7565b60006101208083526143a28184018b8d6140ee565b905082810360208401526143b781898b6140a7565b905082810360408401526143cc8187896140ee565b9150508360608301526143e26080830184614143565b9998505050505050505050565b60e08152600061440360e0830187896140ee565b82810360208401526144168186886140a7565b9150506144266040830184614143565b9695505050505050565b60808152600061444460808301888a6140ee565b82810360208401526144568188614117565b9050828103604084015261446b8186886140ee565b915050826060830152979650505050505050565b6060815260006144936060830186886140ee565b846020840152828103604084015261391e8185614117565b60208101600483106144cd57634e487b7160e01b600052602160045260246000fd5b91905290565b6020815260006137fa6020830184614117565b60208082526017908201527f43616c6c6572206973206e6f7420746865205661756c74000000000000000000604082015260600190565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b60208082526010908201526f14185d5cd8589b194e881c185d5cd95960821b604082015260600190565b6020808252601d908201527f43616c6c6572206973206e6f7420746865205265676973747261746f72000000604082015260600190565b6020808252600e908201526d1499595b9d1c985b9d0818d85b1b60921b604082015260600190565b6020808252601c908201527f43616c6c6572206973206e6f7420746865205374726174656769737400000000604082015260600190565b6000808335601e1984360301811261462b57600080fd5b8301803591506001600160401b0382111561464557600080fd5b602001915036819003821315613a7357600080fd5b60008235605e198336030181126141c757600080fd5b604051601f8201601f191681016001600160401b038111828210171561469857614698614813565b604052919050565b60006001600160401b038211156146b9576146b9614813565b5060051b60200190565b600080821280156001600160ff1b03849003851316156146e5576146e56147bb565b600160ff1b83900384128116156146fe576146fe6147bb565b50500190565b60008219821115614717576147176147bb565b500190565b60008261473957634e487b7160e01b600052601260045260246000fd5b500490565b6000816000190483118215151615614758576147586147bb565b500290565b60008282101561476f5761476f6147bb565b500390565b60005b8381101561478f578181015183820152602001614777565b83811115610d305750506000910152565b60006000198214156147b4576147b46147bb565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b038116811461237857600080fd5b801515811461237857600080fdfe53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac45357bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa264697066735822122002c6785cb55b316b2eea75081179f6e1764ee917e56d0fc72bd1ea4c6b39fa5064736f6c634300080700337bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a", - "deployedBytecode": "0x6080604052600436106102975760003560e01c8063853828b61161015a578063c2e1e3f4116100c1578063d9f00ec71161007a578063d9f00ec714610908578063dbe55e5614610928578063dd505df61461095c578063de5f626814610990578063f1188e40146109a5578063f6ca71b0146109d957600080fd5b8063c2e1e3f414610842578063c7af335214610862578063c98517c514610877578063cceab75014610894578063d38bfff4146108c8578063d9caed12146108e857600080fd5b80639da0e462116101135780639da0e4621461074e578063a4f98af41461078b578063aa388af6146107a0578063ab12edf5146107ed578063ad1728cb1461080d578063bb1b918d1461082257600080fd5b8063853828b61461068057806387bae867146106955780638d7c0e46146106ba5780639092c31c146106da5780639136616a1461070e57806396d538bb1461072e57600080fd5b80635c975abb116101fe5780636e811d38116101b75780636e811d38146105d55780636ef38795146105f557806371a735f3146106155780637b2d9b2c14610635578063842f5c46146106555780638456cb591461066b57600080fd5b80635c975abb146105125780635d36b190146105365780635f5152261461054b5780636093d3801461056b57806366e3667e1461059f57806367c7066c146105b557600080fd5b8063430bf08a11610250578063430bf08a1461043f578063435356d11461047357806347e7ef2414610493578063484be812146104b3578063579a7e1a146104c95780635a063f63146104fd57600080fd5b80630c340a24146103535780630ed57b3a146103855780630fc3b4c4146103a55780631072cbea146103db57806322495dc8146103fb5780633c8649591461041b57600080fd5b3661034e57336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614806102fb5750336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016145b61034c5760405162461bcd60e51b815260206004820152601e60248201527f657468206e6f742066726f6d20616c6c6f77656420636f6e747261637473000060448201526064015b60405180910390fd5b005b600080fd5b34801561035f57600080fd5b506103686109fb565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561039157600080fd5b5061034c6103a0366004613c43565b610a18565b3480156103b157600080fd5b506103686103c0366004613c09565b609f602052600090815260409020546001600160a01b031681565b3480156103e757600080fd5b5061034c6103f6366004613cbd565b610a4a565b34801561040757600080fd5b5061034c610416366004613db1565b610b07565b34801561042757600080fd5b5061043160695481565b60405190815260200161037c565b34801561044b57600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b34801561047f57600080fd5b5061034c61048e366004613d2a565b610c51565b34801561049f57600080fd5b5061034c6104ae366004613cbd565b610d36565b3480156104bf57600080fd5b50610431606a5481565b3480156104d557600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b34801561050957600080fd5b5061034c610e3c565b34801561051e57600080fd5b5060335460ff165b604051901515815260200161037c565b34801561054257600080fd5b5061034c610edb565b34801561055757600080fd5b50610431610566366004613c09565b610f81565b34801561057757600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b3480156105ab57600080fd5b5061043160345481565b3480156105c157600080fd5b5060a354610368906001600160a01b031681565b3480156105e157600080fd5b5061034c6105f0366004613c09565b6110b5565b34801561060157600080fd5b5061034c610610366004613ce9565b61113d565b34801561062157600080fd5b5061034c610630366004613fbf565b6115c9565b34801561064157600080fd5b50610368610650366004613e87565b6117c2565b34801561066157600080fd5b5061043160685481565b34801561067757600080fd5b5061034c6117ec565b34801561068c57600080fd5b5061034c6118b5565b3480156106a157600080fd5b506033546103689061010090046001600160a01b031681565b3480156106c657600080fd5b5061034c6106d5366004614040565b611a87565b3480156106e657600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b34801561071a57600080fd5b5061034c610729366004613e87565b611e6f565b34801561073a57600080fd5b5061034c610749366004613ce9565b61203a565b34801561075a57600080fd5b5061077e610769366004613e87565b60356020526000908152604090205460ff1681565b60405161037c91906144ab565b34801561079757600080fd5b5061052661215a565b3480156107ac57600080fd5b506105266107bb366004613c09565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0390811691161490565b3480156107f957600080fd5b5061034c610808366004614085565b6121b9565b34801561081957600080fd5b5061034c6122b5565b34801561082e57600080fd5b5061034c61083d366004613f0b565b61237b565b34801561084e57600080fd5b5061034c61085d366004613c09565b6124ee565b34801561086e57600080fd5b5061052661257b565b34801561088357600080fd5b506104316801bc16d674ec80000081565b3480156108a057600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b3480156108d457600080fd5b5061034c6108e3366004613c09565b6125ac565b3480156108f457600080fd5b5061034c610903366004613c7c565b612650565b34801561091457600080fd5b5061034c610923366004613ea0565b6126e3565b34801561093457600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b34801561096857600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b34801561099c57600080fd5b5061034c6128d8565b3480156109b157600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b3480156109e557600080fd5b506109ee612a22565b60405161037c9190614281565b6000610a1360008051602061486d8339815191525490565b905090565b610a2061257b565b610a3c5760405162461bcd60e51b81526004016103439061451d565b610a468282612a84565b5050565b610a5261257b565b610a6e5760405162461bcd60e51b81526004016103439061451d565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b039081169083161415610aeb5760405162461bcd60e51b815260206004820152601f60248201527f43616e6e6f74207472616e7366657220737570706f72746564206173736574006044820152606401610343565b610a46610af66109fb565b6001600160a01b0384169083612be3565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b158015610b6057600080fd5b505afa158015610b74573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b989190613c26565b6001600160a01b0316336001600160a01b031614610bc85760405162461bcd60e51b8152600401610343906145dd565b60405163bc26e7e560e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063bc26e7e590610c1a9030908790879087906004016141d1565b600060405180830381600087803b158015610c3457600080fd5b505af1158015610c48573d6000803e3d6000fd5b50505050505050565b610c5961257b565b610c755760405162461bcd60e51b81526004016103439061451d565b600054610100900460ff1680610c8e575060005460ff16155b610cf15760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610343565b600054610100900460ff16158015610d13576000805461ffff19166101011790555b610d1e848484612c35565b8015610d30576000805461ff00191690555b50505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610d7e5760405162461bcd60e51b8152600401610343906144e6565b60008051602061484d83398151915280546002811415610db05760405162461bcd60e51b8152600401610343906145b5565b600282557f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316846001600160a01b031614610e295760405162461bcd60e51b8152602060048201526011602482015270155b9cdd5c1c1bdc9d195908185cdcd95d607a1b6044820152606401610343565b610e338484612cf0565b50600190555050565b60a3546001600160a01b03163314610e965760405162461bcd60e51b815260206004820152601b60248201527f43616c6c6572206973206e6f74207468652048617276657374657200000000006044820152606401610343565b60008051602061484d83398151915280546002811415610ec85760405162461bcd60e51b8152600401610343906145b5565b60028255610ed4612d82565b5060019055565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b031614610f765760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b6064820152608401610343565b610f7f33612fd0565b565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b031614610ff85760405162461bcd60e51b8152602060048201526011602482015270155b9cdd5c1c1bdc9d195908185cdcd95d607a1b6044820152606401610343565b6040516370a0823160e01b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b15801561105757600080fd5b505afa15801561106b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061108f919061406c565b6034546110a5906801bc16d674ec80000061473e565b6110af9190614704565b92915050565b6110bd61257b565b6110d95760405162461bcd60e51b81526004016103439061451d565b6040516001600160a01b03821681527f83f29c79feb71f8fba9d0fbc4ba5f0982a28b6b1e868b3fc50e6400d100bca0f9060200160405180910390a1603380546001600160a01b0390921661010002610100600160a81b0319909216919091179055565b60335461010090046001600160a01b0316331461116c5760405162461bcd60e51b81526004016103439061457e565b60335460ff161561118f5760405162461bcd60e51b815260040161034390614554565b60006111a4826801bc16d674ec80000061473e565b6040516370a0823160e01b81523060048201529091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b15801561120657600080fd5b505afa15801561121a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061123e919061406c565b8111156112815760405162461bcd60e51b81526020600482015260116024820152700d2dce6eaccccd2c6d2cadce840ae8aa89607b1b6044820152606401610343565b604051632e1a7d4d60e01b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b1580156112e357600080fd5b505af11580156112f7573d6000803e3d6000fd5b5050505060005b82811015610d3057600084848381811061131a5761131a6147fd565b905060200281019061132c919061465a565b6113369080614614565b6040516113449291906141a5565b6040805191829003909120600081815260356020529182205490925060ff1690816003811115611376576113766147d1565b146113c35760405162461bcd60e51b815260206004820152601860248201527f56616c696461746f72206e6f74207265676973746572656400000000000000006044820152606401610343565b60408051600160f81b60208201526000602182018190526bffffffffffffffffffffffff193060601b16602c830152910160405160208183030381529060405290507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663228951186801bc16d674ec800000898988818110611450576114506147fd565b9050602002810190611462919061465a565b61146c9080614614565b858c8c8b81811061147f5761147f6147fd565b9050602002810190611491919061465a565b61149f906020810190614614565b8e8e8d8181106114b1576114b16147fd565b90506020028101906114c3919061465a565b604001356040518863ffffffff1660e01b81526004016114e896959493929190614430565b6000604051808303818588803b15801561150157600080fd5b505af1158015611515573d6000803e3d6000fd5b505050505060016034600082825461152d9190614704565b909155507ffeb31a79d38edb1b090d516e4df3e273651179c6f2c2ec53a9a22ae015b70ba99050878786818110611566576115666147fd565b9050602002810190611578919061465a565b6115829080614614565b6801bc16d674ec8000008460405161159d949392919061447f565b60405180910390a150506000908152603560205260409020805460ff19166001908117909155016112fe565b60335461010090046001600160a01b031633146115f85760405162461bcd60e51b81526004016103439061457e565b60335460ff161561161b5760405162461bcd60e51b815260040161034390614554565b60006035600087876040516116319291906141a5565b604080519182900390912082526020820192909252016000205460ff1690506002816003811115611664576116646147d1565b146116a95760405162461bcd60e51b815260206004820152601560248201527456616c696461746f72206e6f742065786974696e6760581b6044820152606401610343565b6040516312b3fc1960e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906312b3fc19906116fd90899089908990899089906004016143ef565b600060405180830381600087803b15801561171757600080fd5b505af115801561172b573d6000803e3d6000fd5b505050507ff72821b8777f002ccdf6326f1242d9e0f762eb077668b67bebe640535378066d868686866040516117649493929190614366565b60405180910390a160036035600088886040516117829291906141a5565b60408051918290039091208252602082019290925201600020805460ff191660018360038111156117b5576117b56147d1565b0217905550505050505050565b60a481815481106117d257600080fd5b6000918252602090912001546001600160a01b0316905081565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b15801561184557600080fd5b505afa158015611859573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061187d9190613c26565b6001600160a01b0316336001600160a01b0316146118ad5760405162461bcd60e51b8152600401610343906145dd565b610f7f613091565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016148061190457506118ef6109fb565b6001600160a01b0316336001600160a01b0316145b61195c5760405162461bcd60e51b815260206004820152602360248201527f43616c6c6572206973206e6f7420746865205661756c74206f7220476f7665726044820152623737b960e91b6064820152608401610343565b60008051602061484d8339815191528054600281141561198e5760405162461bcd60e51b8152600401610343906145b5565b600282556040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b1580156119f457600080fd5b505afa158015611a08573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a2c919061406c565b90508015611a7f57611a7f7f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000083613106565b505060019055565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b158015611ae057600080fd5b505afa158015611af4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b189190613c26565b6001600160a01b0316336001600160a01b031614611b485760405162461bcd60e51b8152600401610343906145dd565b60335460ff16611b915760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610343565b6002198312158015611ba4575060038313155b8015611bbe5750600083603454611bbb91906146c3565b12155b611c0a5760405162461bcd60e51b815260206004820152601760248201527f696e76616c69642076616c696461746f727344656c74610000000000000000006044820152606401610343565b6811ff6cf0fd15afffff198212158015611c2d57506811ff6cf0fd15b000008213155b8015611c475750600082606854611c4491906146c3565b12155b611c935760405162461bcd60e51b815260206004820152601d60248201527f696e76616c696420636f6e73656e7375735265776172647344656c74610000006044820152606401610343565b6801bc16d674ec800000811115611cec5760405162461bcd60e51b815260206004820152601960248201527f696e76616c69642077657468546f5661756c74416d6f756e74000000000000006044820152606401610343565b60408051848152602081018490529081018290527f80d022717ea022455c5886b8dd8a29c037570aae58aeb4d7b136d7a10ec2e4319060600160405180910390a182603454611d3b91906146c3565b603455606854611d4c9083906146c3565b6068558015611e195760405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018390527f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb90604401602060405180830381600087803b158015611ddf57600080fd5b505af1158015611df3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e179190613e6a565b505b611e2360006131fe565b611e625760405162461bcd60e51b815260206004820152601060248201526f333ab9b29039ba34b63610313637bbb760811b6044820152606401610343565b611e6a613684565b505050565b611e7761257b565b611e935760405162461bcd60e51b81526004016103439061451d565b60a0548110611ed45760405162461bcd60e51b815260206004820152600d60248201526c092dcecc2d8d2c840d2dcc8caf609b1b6044820152606401610343565b600060a08281548110611ee957611ee96147fd565b60009182526020808320909101546001600160a01b03908116808452609f90925260409092205460a05491935090911690611f269060019061475d565b831015611fa85760a08054611f3d9060019061475d565b81548110611f4d57611f4d6147fd565b60009182526020909120015460a080546001600160a01b039092169185908110611f7957611f796147fd565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505b60a0805480611fb957611fb96147e7565b60008281526020808220600019908401810180546001600160a01b031990811690915593019093556001600160a01b03858116808352609f855260409283902080549094169093559051908416815290917f16b7600acff27e39a8a96056b3d533045298de927507f5c1d97e4accde60488c910160405180910390a2505050565b61204261257b565b61205e5760405162461bcd60e51b81526004016103439061451d565b8060005b8181101561211157600084848381811061207e5761207e6147fd565b90506020020160208101906120939190613c09565b6001600160a01b031614156121015760405162461bcd60e51b815260206004820152602e60248201527f43616e206e6f742073657420616e20656d70747920616464726573732061732060448201526d30903932bbb0b932103a37b5b2b760911b6064820152608401610343565b61210a816147a0565b9050612062565b507f04c0b9649497d316554306e53678d5f5f5dbc3a06f97dec13ff4cfe98b986bbc60a48484604051612146939291906142ce565b60405180910390a1610d3060a48484613962565b60335460009061010090046001600160a01b0316331461218c5760405162461bcd60e51b81526004016103439061457e565b60335460ff16156121af5760405162461bcd60e51b815260040161034390614554565b610a1360016131fe565b6121c161257b565b6121dd5760405162461bcd60e51b81526004016103439061451d565b80821080156121f457506801bc16d674ec80000082105b801561220857506801bc16d674ec80000081105b80156122255750673782dace9d900000612222838361475d565b10155b6122715760405162461bcd60e51b815260206004820152601760248201527f696e636f7272656374206675736520696e74657276616c0000000000000000006044820152606401610343565b60408051838152602081018390527fcb8d24e46eb3c402bf344ee60a6576cba9ef2f59ea1af3b311520704924e901a910160405180910390a1606991909155606a55565b60405163095ea7b360e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015260001960248301527f0000000000000000000000000000000000000000000000000000000000000000169063095ea7b390604401602060405180830381600087803b15801561234057600080fd5b505af1158015612354573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123789190613e6a565b50565b60335461010090046001600160a01b031633146123aa5760405162461bcd60e51b81526004016103439061457e565b60335460ff16156123cd5760405162461bcd60e51b815260040161034390614554565b6040516301ba3ee760e21b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906306e8fb9c90612427908b908b908b908b908b908b908b908b9060040161438d565b600060405180830381600087803b15801561244157600080fd5b505af1158015612455573d6000803e3d6000fd5b505050506000603560008a8a60405161246f9291906141a5565b60408051918290039091208252602082019290925201600020805460ff191660018360038111156124a2576124a26147d1565b02179055507f75c4a66b2c6c28cf46db7131182a812e4fbbb2f0591377aa83a737909a9b68c3888888886040516124dc9493929190614366565b60405180910390a15050505050505050565b6124f661257b565b6125125760405162461bcd60e51b81526004016103439061451d565b60a354604080516001600160a01b03928316815291831660208301527fe48386b84419f4d36e0f96c10cc3510b6fb1a33795620c5098b22472bbe90796910160405180910390a160a380546001600160a01b0319166001600160a01b0392909216919091179055565b600061259360008051602061486d8339815191525490565b6001600160a01b0316336001600160a01b031614905090565b6125b461257b565b6125d05760405162461bcd60e51b81526004016103439061451d565b6125f8817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b031661261860008051602061486d8339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146126985760405162461bcd60e51b8152600401610343906144e6565b60008051602061484d833981519152805460028114156126ca5760405162461bcd60e51b8152600401610343906145b5565b600282556126d9858585613106565b5060019055505050565b60335461010090046001600160a01b031633146127125760405162461bcd60e51b81526004016103439061457e565b60335460ff16156127355760405162461bcd60e51b815260040161034390614554565b600060356000868660405161274b9291906141a5565b604080519182900390912082526020820192909252016000205460ff169050600181600381111561277e5761277e6147d1565b146127c25760405162461bcd60e51b815260206004820152601460248201527315985b1a59185d1bdc881b9bdd081cdd185ad95960621b6044820152606401610343565b604051633877322b60e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690633877322b90612814908890889088908890600401614366565b600060405180830381600087803b15801561282e57600080fd5b505af1158015612842573d6000803e3d6000fd5b505050507ff8821da16f5ed966b41e0343c3eff9903af782d74f99f1689dd9d4562b6545b38585858560405161287b9493929190614366565b60405180910390a160026035600087876040516128999291906141a5565b60408051918290039091208252602082019290925201600020805460ff191660018360038111156128cc576128cc6147d1565b02179055505050505050565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146129205760405162461bcd60e51b8152600401610343906144e6565b60008051602061484d833981519152805460028114156129525760405162461bcd60e51b8152600401610343906145b5565b600282556040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b1580156129b857600080fd5b505afa1580156129cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129f0919061406c565b90508015611a7f57611a7f7f000000000000000000000000000000000000000000000000000000000000000082612cf0565b606060a4805480602002602001604051908101604052809291908181526020018280548015612a7a57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612a5c575b5050505050905090565b6001600160a01b038281166000908152609f60205260409020541615612ae15760405162461bcd60e51b81526020600482015260126024820152711c151bdad95b88185b1c9958591e481cd95d60721b6044820152606401610343565b6001600160a01b03821615801590612b0157506001600160a01b03811615155b612b415760405162461bcd60e51b8152602060048201526011602482015270496e76616c69642061646472657373657360781b6044820152606401610343565b6001600160a01b038281166000818152609f6020908152604080832080549587166001600160a01b0319968716811790915560a0805460018101825594527f78fdc8d422c49ced035a9edf18d00d3c6a8d81df210f3e5e448e045e77b41e8890930180549095168417909455925190815290917fef6485b84315f9b1483beffa32aae9a0596890395e3d7521f1c5fbb51790e765910160405180910390a25050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052611e6a9084906136fe565b8251612c489060a49060208601906139c5565b50815181518114612c925760405162461bcd60e51b8152602060048201526014602482015273496e76616c696420696e7075742061727261797360601b6044820152606401610343565b60005b81811015612ce957612cd9848281518110612cb257612cb26147fd565b6020026020010151848381518110612ccc57612ccc6147fd565b6020026020010151612a84565b612ce2816147a0565b9050612c95565b5050505050565b60008111612d395760405162461bcd60e51b81526020600482015260166024820152754d757374206465706f73697420736f6d657468696e6760501b6044820152606401610343565b6040805160008152602081018390526001600160a01b038416917f5548c837ab068cf56a2c2479df0882a4922fd203edb7517321831d95078c5f62910160405180910390a25050565b60335460ff1615612da55760405162461bcd60e51b815260040161034390614554565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663e52253816040518163ffffffff1660e01b8152600401602060405180830381600087803b158015612e0257600080fd5b505af1158015612e16573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e3a919061406c565b9050600060685482612e4c9190614704565b905080471015612e9e5760405162461bcd60e51b815260206004820152601860248201527f696e73756666696369656e74206574682062616c616e636500000000000000006044820152606401610343565b8015610a465760006068819055507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b158015612f0757600080fd5b505af1158015612f1b573d6000803e3d6000fd5b505060a354604080516001600160a01b0392831681527f0000000000000000000000000000000000000000000000000000000000000000909216602083015281018590527ff6c07a063ed4e63808eb8da7112d46dbcd38de2b40a73dbcc9353c5a94c7235393506060019150612f8e9050565b60405180910390a160a354610a46906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116911683612be3565b6001600160a01b0381166130265760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f7220697320616464726573732830290000000000006044820152606401610343565b806001600160a01b031661304660008051602061486d8339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a36123788160008051602061486d83398151915255565b60335460ff16156130b45760405162461bcd60e51b815260040161034390614554565b6033805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586130e93390565b6040516001600160a01b03909116815260200160405180910390a1565b600081116131565760405162461bcd60e51b815260206004820152601760248201527f4d75737420776974686472617720736f6d657468696e670000000000000000006044820152606401610343565b6001600160a01b0383166131a55760405162461bcd60e51b8152602060048201526016602482015275135d5cdd081cdc1958da599e481c9958da5c1a595b9d60521b6044820152606401610343565b6040805160008152602081018390526001600160a01b038416917f2717ead6b9200dd235aad468c9809ea400fe33ac69b5bfaa6d3e90fc922b6398910160405180910390a2611e6a6001600160a01b0383168483612be3565b6000606854471015613213576110af826137d0565b600060685447613223919061475d565b9050600191506801bc16d674ec800000811061341957600061324e6801bc16d674ec8000008361471c565b905080603454101561326b57613263846137d0565b949350505050565b806034600082825461327d919061475d565b9091555060009050613298826801bc16d674ec80000061473e565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b1580156132f557600080fd5b505af1158015613309573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb92506044019050602060405180830381600087803b15801561339957600080fd5b505af11580156133ad573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133d19190613e6a565b5060345460408051848152602081019290925281018290527fbe7040030ff7b347853214bf49820c6d455fedf58f3815f85c7bc5216993682b9060600160405180910390a150505b600060685447613429919061475d565b90506801bc16d674ec800000811061347b5760405162461bcd60e51b8152602060048201526015602482015274756e6578706563746564206163636f756e74696e6760581b6044820152606401610343565b80613487575050919050565b6069548110156134e15780606860008282546134a39190614704565b90915550506040518181527f7a745a2c63a535068f52ceca27debd5297bbad5f7f37ec53d044a59d0362445d906020015b60405180910390a161367d565b606a54811115613674577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b15801561354657600080fd5b505af115801561355a573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb92506044019050602060405180830381600087803b1580156135ea57600080fd5b505af11580156135fe573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136229190613e6a565b50600160346000828254613636919061475d565b909155505060345460408051918252602082018390527f6aa7e30787b26429ced603a7aba8b19c4b5d5bcf29a3257da953c8d53bcaa3a691016134d4565b613263846137d0565b5050919050565b60335460ff166136cd5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610343565b6033805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa336130e9565b6000613753826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166137e89092919063ffffffff16565b805190915015611e6a57808060200190518101906137719190613e6a565b611e6a5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610343565b600081156137e0576137e0613091565b506000919050565b60606137f78484600085613801565b90505b9392505050565b6060824710156138625760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610343565b843b6138b05760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610343565b600080866001600160a01b031685876040516138cc91906141b5565b60006040518083038185875af1925050503d8060008114613909576040519150601f19603f3d011682016040523d82523d6000602084013e61390e565b606091505b509150915061391e828286613929565b979650505050505050565b606083156139385750816137fa565b8251156139485782518084602001fd5b8160405162461bcd60e51b815260040161034391906144d3565b8280548282559060005260206000209081019282156139b5579160200282015b828111156139b55781546001600160a01b0319166001600160a01b03843516178255602090920191600190910190613982565b506139c1929150613a1a565b5090565b8280548282559060005260206000209081019282156139b5579160200282015b828111156139b557825182546001600160a01b0319166001600160a01b039091161782556020909201916001909101906139e5565b5b808211156139c15760008155600101613a1b565b60008083601f840112613a4157600080fd5b5081356001600160401b03811115613a5857600080fd5b6020830191508360208260051b8501011115613a7357600080fd5b9250929050565b600082601f830112613a8b57600080fd5b81356020613aa0613a9b836146a0565b614670565b80838252828201915082860187848660051b8901011115613ac057600080fd5b60005b85811015613ae8578135613ad681614829565b84529284019290840190600101613ac3565b5090979650505050505050565b60008083601f840112613b0757600080fd5b5081356001600160401b03811115613b1e57600080fd5b602083019150836020828501011115613a7357600080fd5b600060a08284031215613b4857600080fd5b50919050565b600060a08284031215613b6057600080fd5b60405160a081018181106001600160401b0382111715613b8257613b82614813565b604052905080613b9183613bd9565b8152613b9f60208401613bf2565b6020820152613bb060408401613bf2565b60408201526060830135613bc38161483e565b6060820152608092830135920191909152919050565b803563ffffffff81168114613bed57600080fd5b919050565b80356001600160401b0381168114613bed57600080fd5b600060208284031215613c1b57600080fd5b81356137fa81614829565b600060208284031215613c3857600080fd5b81516137fa81614829565b60008060408385031215613c5657600080fd5b8235613c6181614829565b91506020830135613c7181614829565b809150509250929050565b600080600060608486031215613c9157600080fd5b8335613c9c81614829565b92506020840135613cac81614829565b929592945050506040919091013590565b60008060408385031215613cd057600080fd5b8235613cdb81614829565b946020939093013593505050565b60008060208385031215613cfc57600080fd5b82356001600160401b03811115613d1257600080fd5b613d1e85828601613a2f565b90969095509350505050565b600080600060608486031215613d3f57600080fd5b83356001600160401b0380821115613d5657600080fd5b613d6287838801613a7a565b94506020860135915080821115613d7857600080fd5b613d8487838801613a7a565b93506040860135915080821115613d9a57600080fd5b50613da786828701613a7a565b9150509250925092565b600080600060e08486031215613dc657600080fd5b83356001600160401b03811115613ddc57600080fd5b8401601f81018613613ded57600080fd5b80356020613dfd613a9b836146a0565b8083825282820191508285018a848660051b8801011115613e1d57600080fd5b600095505b84861015613e4757613e3381613bf2565b835260019590950194918301918301613e22565b509650508601359350613e61915086905060408601613b4e565b90509250925092565b600060208284031215613e7c57600080fd5b81516137fa8161483e565b600060208284031215613e9957600080fd5b5035919050565b60008060008060408587031215613eb657600080fd5b84356001600160401b0380821115613ecd57600080fd5b613ed988838901613af5565b90965094506020870135915080821115613ef257600080fd5b50613eff87828801613a2f565b95989497509550505050565b600080600080600080600080610120898b031215613f2857600080fd5b88356001600160401b0380821115613f3f57600080fd5b613f4b8c838d01613af5565b909a50985060208b0135915080821115613f6457600080fd5b613f708c838d01613a2f565b909850965060408b0135915080821115613f8957600080fd5b50613f968b828c01613af5565b90955093505060608901359150613fb08a60808b01613b36565b90509295985092959890939650565b600080600080600060e08688031215613fd757600080fd5b85356001600160401b0380821115613fee57600080fd5b613ffa89838a01613af5565b9097509550602088013591508082111561401357600080fd5b5061402088828901613a2f565b909450925061403490508760408801613b36565b90509295509295909350565b60008060006060848603121561405557600080fd5b505081359360208301359350604090920135919050565b60006020828403121561407e57600080fd5b5051919050565b6000806040838503121561409857600080fd5b50508035926020909101359150565b8183526000602080850194508260005b858110156140e3576001600160401b036140d083613bf2565b16875295820195908201906001016140b7565b509495945050505050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6000815180845261412f816020860160208601614774565b601f01601f19169290920160200192915050565b63ffffffff61415182613bd9565b16825261416060208201613bf2565b6001600160401b0380821660208501528061417d60408501613bf2565b166040850152505060608101356141938161483e565b15156060830152608090810135910152565b8183823760009101908152919050565b600082516141c7818460208701614774565b9190910192915050565b6001600160a01b03851681526101006020808301829052855191830182905260009161012084019187810191845b818110156142245783516001600160401b0316855293820193928201926001016141ff565b505082935086604086015263ffffffff865116606086015280860151925050506001600160401b0380821660808501528060408601511660a085015250506060830151151560c0830152608083015160e083015295945050505050565b6020808252825182820181905260009190848201906040850190845b818110156142c25783516001600160a01b03168352928401929184019160010161429d565b50909695505050505050565b6000604082016040835280865480835260608501915087600052602092508260002060005b828110156143185781546001600160a01b0316845292840192600191820191016142f3565b505050838103828501528481528590820160005b8681101561435a57823561433f81614829565b6001600160a01b03168252918301919083019060010161432c565b50979650505050505050565b60408152600061437a6040830186886140ee565b828103602084015261391e8185876140a7565b60006101208083526143a28184018b8d6140ee565b905082810360208401526143b781898b6140a7565b905082810360408401526143cc8187896140ee565b9150508360608301526143e26080830184614143565b9998505050505050505050565b60e08152600061440360e0830187896140ee565b82810360208401526144168186886140a7565b9150506144266040830184614143565b9695505050505050565b60808152600061444460808301888a6140ee565b82810360208401526144568188614117565b9050828103604084015261446b8186886140ee565b915050826060830152979650505050505050565b6060815260006144936060830186886140ee565b846020840152828103604084015261391e8185614117565b60208101600483106144cd57634e487b7160e01b600052602160045260246000fd5b91905290565b6020815260006137fa6020830184614117565b60208082526017908201527f43616c6c6572206973206e6f7420746865205661756c74000000000000000000604082015260600190565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b60208082526010908201526f14185d5cd8589b194e881c185d5cd95960821b604082015260600190565b6020808252601d908201527f43616c6c6572206973206e6f7420746865205265676973747261746f72000000604082015260600190565b6020808252600e908201526d1499595b9d1c985b9d0818d85b1b60921b604082015260600190565b6020808252601c908201527f43616c6c6572206973206e6f7420746865205374726174656769737400000000604082015260600190565b6000808335601e1984360301811261462b57600080fd5b8301803591506001600160401b0382111561464557600080fd5b602001915036819003821315613a7357600080fd5b60008235605e198336030181126141c757600080fd5b604051601f8201601f191681016001600160401b038111828210171561469857614698614813565b604052919050565b60006001600160401b038211156146b9576146b9614813565b5060051b60200190565b600080821280156001600160ff1b03849003851316156146e5576146e56147bb565b600160ff1b83900384128116156146fe576146fe6147bb565b50500190565b60008219821115614717576147176147bb565b500190565b60008261473957634e487b7160e01b600052601260045260246000fd5b500490565b6000816000190483118215151615614758576147586147bb565b500290565b60008282101561476f5761476f6147bb565b500390565b60005b8381101561478f578181015183820152602001614777565b83811115610d305750506000910152565b60006000198214156147b4576147b46147bb565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b038116811461237857600080fd5b801515811461237857600080fdfe53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac45357bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa264697066735822122002c6785cb55b316b2eea75081179f6e1764ee917e56d0fc72bd1ea4c6b39fa5064736f6c63430008070033", + "numDeployments": 2, + "solcInputHash": "94a4e2017aae119860e82f5bc90e390d", + "metadata": "{\"compiler\":{\"version\":\"0.8.7+commit.e28d00a7\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"platformAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"vaultAddress\",\"type\":\"address\"}],\"internalType\":\"struct InitializableAbstractStrategy.BaseStrategyConfig\",\"name\":\"_baseConfig\",\"type\":\"tuple\"},{\"internalType\":\"address\",\"name\":\"_wethAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_ssvToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_ssvNetwork\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_feeAccumulator\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_beaconChainDepositContract\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"AccountingConsensusRewards\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"noOfValidators\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"remainingValidators\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"wethSentToVault\",\"type\":\"uint256\"}],\"name\":\"AccountingFullyWithdrawnValidator\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"validatorsDelta\",\"type\":\"int256\"},{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"consensusRewardsDelta\",\"type\":\"int256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"wethToVault\",\"type\":\"uint256\"}],\"name\":\"AccountingManuallyFixed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"remainingValidators\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"wethSentToVault\",\"type\":\"uint256\"}],\"name\":\"AccountingValidatorSlashed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"Deposit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"pubkey\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"withdrawal_credentials\",\"type\":\"bytes\"}],\"name\":\"ETHStaked\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"start\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"end\",\"type\":\"uint256\"}],\"name\":\"FuseIntervalUpdated\",\"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\":\"address\",\"name\":\"_oldHarvesterAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_newHarvesterAddress\",\"type\":\"address\"}],\"name\":\"HarvesterAddressesUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"}],\"name\":\"PTokenAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"}],\"name\":\"PTokenRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Paused\",\"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\":\"newAddress\",\"type\":\"address\"}],\"name\":\"RegistratorChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"_oldAddresses\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"_newAddresses\",\"type\":\"address[]\"}],\"name\":\"RewardTokenAddressesUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"rewardToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"RewardTokenCollected\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"pubkey\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"}],\"name\":\"SSVValidatorExitCompleted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"pubkey\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"}],\"name\":\"SSVValidatorExitInitiated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"pubkey\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"}],\"name\":\"SSVValidatorRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Unpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"Withdrawal\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"BEACON_CHAIN_DEPOSIT_CONTRACT\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_ACCUMULATOR_ADDRESS\",\"outputs\":[{\"internalType\":\"address payable\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MAX_STAKE\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"SSV_NETWORK_ADDRESS\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"SSV_TOKEN_ADDRESS\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"VAULT_ADDRESS\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"WETH_TOKEN_ADDRESS\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"activeDepositedValidators\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"assetToPToken\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"}],\"name\":\"checkBalance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"claimGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"collectRewardTokens\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"consensusRewards\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"depositAll\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"validatorCount\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"networkFeeIndex\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"index\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"active\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"internalType\":\"struct Cluster\",\"name\":\"cluster\",\"type\":\"tuple\"}],\"name\":\"depositSSV\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"doAccounting\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"accountingValid\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"publicKey\",\"type\":\"bytes\"},{\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"}],\"name\":\"exitSsvValidator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fuseIntervalEnd\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fuseIntervalStart\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRewardTokenAddresses\",\"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\":\"harvesterAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"_rewardTokenAddresses\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"_assets\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"_pTokens\",\"type\":\"address[]\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isGovernor\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"int256\",\"name\":\"_validatorsDelta\",\"type\":\"int256\"},{\"internalType\":\"int256\",\"name\":\"_consensusRewardsDelta\",\"type\":\"int256\"},{\"internalType\":\"uint256\",\"name\":\"_wethToVaultAmount\",\"type\":\"uint256\"}],\"name\":\"manuallyFixAccounting\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"paused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"platformAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"publicKey\",\"type\":\"bytes\"},{\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"},{\"internalType\":\"bytes\",\"name\":\"sharesData\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"validatorCount\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"networkFeeIndex\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"index\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"active\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"internalType\":\"struct Cluster\",\"name\":\"cluster\",\"type\":\"tuple\"}],\"name\":\"registerSsvValidator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_assetIndex\",\"type\":\"uint256\"}],\"name\":\"removePToken\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"publicKey\",\"type\":\"bytes\"},{\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"validatorCount\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"networkFeeIndex\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"index\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"active\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"internalType\":\"struct Cluster\",\"name\":\"cluster\",\"type\":\"tuple\"}],\"name\":\"removeSsvValidator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"rewardTokenAddresses\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"safeApproveAllTokens\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_fuseIntervalStart\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_fuseIntervalEnd\",\"type\":\"uint256\"}],\"name\":\"setFuseInterval\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_harvesterAddress\",\"type\":\"address\"}],\"name\":\"setHarvesterAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"}],\"name\":\"setPTokenAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"setRegistrator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"_rewardTokenAddresses\",\"type\":\"address[]\"}],\"name\":\"setRewardTokenAddresses\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"pubkey\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"depositDataRoot\",\"type\":\"bytes32\"}],\"internalType\":\"struct ValidatorStakeData[]\",\"name\":\"validators\",\"type\":\"tuple[]\"}],\"name\":\"stakeEth\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"}],\"name\":\"supportsAsset\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"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\":\"validatorRegistrator\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"validatorsStates\",\"outputs\":[{\"internalType\":\"enum ValidatorRegistrator.VALIDATOR_STATE\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"vaultAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"withdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdrawAll\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"author\":\"Origin Protocol Inc\",\"kind\":\"dev\",\"methods\":{\"checkBalance(address)\":{\"params\":{\"_asset\":\"Address of weth asset\"},\"returns\":{\"balance\":\" Total value of (W)ETH\"}},\"constructor\":{\"params\":{\"_baseConfig\":\"Base strategy config with platformAddress (ERC-4626 Vault contract), eg sfrxETH or sDAI, and vaultAddress (OToken Vault contract), eg VaultProxy or OETHVaultProxy\",\"_beaconChainDepositContract\":\"Address of the beacon chain deposit contract\",\"_feeAccumulator\":\"Address of the fee accumulator receiving execution layer validator rewards\",\"_ssvNetwork\":\"Address of the SSV Network contract\",\"_ssvToken\":\"Address of the Erc20 SSV Token contract\",\"_wethAddress\":\"Address of the Erc20 WETH Token contract\"}},\"deposit(address,uint256)\":{\"params\":{\"_amount\":\"Amount of assets that were transferred to the strategy by the vault.\",\"_asset\":\"Address of asset to deposit. Has to be WETH.\"}},\"depositSSV(uint64[],uint256,(uint32,uint64,uint64,bool,uint256))\":{\"details\":\"A SSV cluster is defined by the SSVOwnerAddress and the set of operatorIds. uses \\\"onlyStrategist\\\" modifier so continuous front-running can't DOS our maintenance service that tries to top up SSV tokens.\",\"params\":{\"cluster\":\"The SSV cluster details that must be derived from emitted events from the SSVNetwork contract.\"}},\"doAccounting()\":{\"details\":\"This function could in theory be permission-less but lets allow only the Registrator (Defender Action) to call it for now.\",\"returns\":{\"accountingValid\":\"true if accounting was successful, false if fuse is blown\"}},\"getRewardTokenAddresses()\":{\"returns\":{\"_0\":\"address[] the reward token addresses.\"}},\"initialize(address[],address[],address[])\":{\"params\":{\"_assets\":\"Addresses of initial supported assets\",\"_pTokens\":\"Platform Token corresponding addresses\",\"_rewardTokenAddresses\":\"Address of reward token for platform\"}},\"manuallyFixAccounting(int256,int256,uint256)\":{\"params\":{\"_consensusRewardsDelta\":\"adjust the accounted for consensus rewards up or down\",\"_validatorsDelta\":\"adjust the active validators by plus one, minus one or unchanged with zero\",\"_wethToVaultAmount\":\"the amount of WETH to be sent to the Vault\"}},\"paused()\":{\"details\":\"Returns true if the contract is paused, and false otherwise.\"},\"removePToken(uint256)\":{\"params\":{\"_assetIndex\":\"Index of the asset to be removed\"}},\"setHarvesterAddress(address)\":{\"params\":{\"_harvesterAddress\":\"Address of the harvester contract.\"}},\"setPTokenAddress(address,address)\":{\"params\":{\"_asset\":\"Address for the asset\",\"_pToken\":\"Address for the corresponding platform token\"}},\"setRewardTokenAddresses(address[])\":{\"params\":{\"_rewardTokenAddresses\":\"Array of reward token addresses\"}},\"stakeEth((bytes,bytes,bytes32)[])\":{\"params\":{\"validators\":\"A list of validator data needed to stake. The `ValidatorStakeData` struct contains the pubkey, signature and depositDataRoot. Only the registrator can call this function.\"}},\"supportsAsset(address)\":{\"params\":{\"_asset\":\"The address of the asset token.\"}},\"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\"}},\"withdraw(address,address,uint256)\":{\"params\":{\"_amount\":\"Amount of WETH to withdraw\",\"_asset\":\"WETH to withdraw\",\"_recipient\":\"Address to receive withdrawn assets\"}}},\"stateVariables\":{\"FEE_ACCUMULATOR_ADDRESS\":{\"details\":\"this address will receive Execution layer rewards - These are rewards earned for executing transactions on the Ethereum network as part of block proposals. They include priority fees (fees paid by users for their transactions to be included) and MEV rewards (rewards for arranging transactions in a way that benefits the validator).\"}},\"title\":\"Native Staking SSV Strategy\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"BEACON_CHAIN_DEPOSIT_CONTRACT()\":{\"notice\":\"The address of the beacon chain deposit contract\"},\"FEE_ACCUMULATOR_ADDRESS()\":{\"notice\":\"Fee collector address\"},\"MAX_STAKE()\":{\"notice\":\"The maximum amount of ETH that can be staked by a validator\"},\"SSV_NETWORK_ADDRESS()\":{\"notice\":\"The address of the SSV Network contract used to interface with\"},\"SSV_TOKEN_ADDRESS()\":{\"notice\":\"SSV ERC20 token that serves as a payment for operating SSV validators\"},\"VAULT_ADDRESS()\":{\"notice\":\"Address of the OETH Vault proxy contract\"},\"WETH_TOKEN_ADDRESS()\":{\"notice\":\"The address of the Wrapped ETH (WETH) token contract\"},\"activeDepositedValidators()\":{\"notice\":\"The number of validators that have 32 (!) ETH actively deposited. When a new deposit to a validator happens this number increases, when a validator exit is detected this number decreases.\"},\"assetToPToken(address)\":{\"notice\":\"asset => pToken (Platform Specific Token Address)\"},\"checkBalance(address)\":{\"notice\":\"Returns the total value of (W)ETH that is staked to the validators and WETH deposits that are still to be staked. This does not include ETH from consensus rewards sitting in this strategy or ETH from MEV rewards in the FeeAccumulator. These rewards are harvested and sent to the Dripper so will eventually be sent to the Vault as WETH.\"},\"claimGovernance()\":{\"notice\":\"Claim Governance of the contract to a new account (`newGovernor`). Can only be called by the new Governor.\"},\"collectRewardTokens()\":{\"notice\":\"Collect accumulated reward token and send to Vault.\"},\"consensusRewards()\":{\"notice\":\"Keeps track of the total consensus rewards swept from the beacon chain\"},\"deposit(address,uint256)\":{\"notice\":\"Unlike other strategies, this does not deposit assets into the underlying platform. It just checks the asset is WETH and emits the Deposit event. To deposit WETH into validators `registerSsvValidator` and `stakeEth` must be used. Will NOT revert if the strategy is paused from an accounting failure.\"},\"depositAll()\":{\"notice\":\"Unlike other strategies, this does not deposit assets into the underlying platform. It just emits the Deposit event. To deposit WETH into validators `registerSsvValidator` and `stakeEth` must be used. Will NOT revert if the strategy is paused from an accounting failure.\"},\"depositSSV(uint64[],uint256,(uint32,uint64,uint64,bool,uint256))\":{\"notice\":\"Deposits more SSV Tokens to the SSV Network contract which is used to pay the SSV Operators.\"},\"doAccounting()\":{\"notice\":\"This notion page offers a good explanation of how the accounting functions https://www.notion.so/originprotocol/Limited-simplified-native-staking-accounting-67a217c8420d40678eb943b9da0ee77d In short, after dividing by 32, if the ETH remaining on the contract falls between 0 and fuseIntervalStart, the accounting function will treat that ETH as Beacon chain consensus rewards. On the contrary, if after dividing by 32, the ETH remaining on the contract falls between fuseIntervalEnd and 32, the accounting function will treat that as a validator slashing.Perform the accounting attributing beacon chain ETH to either full or partial withdrawals. Returns true when accounting is valid and fuse isn't \\\"blown\\\". Returns false when fuse is blown.\"},\"exitSsvValidator(bytes,uint64[])\":{\"notice\":\"Exit a validator from the Beacon chain. The staked ETH will eventually swept to this native staking strategy. Only the registrator can call this function.\"},\"fuseIntervalEnd()\":{\"notice\":\"end of fuse interval\"},\"fuseIntervalStart()\":{\"notice\":\"start of fuse interval\"},\"getRewardTokenAddresses()\":{\"notice\":\"Get the reward token addresses.\"},\"governor()\":{\"notice\":\"Returns the address of the current Governor.\"},\"harvesterAddress()\":{\"notice\":\"Address of the Harvester contract allowed to collect reward tokens\"},\"initialize(address[],address[],address[])\":{\"notice\":\"initialize function, to set up initial internal state\"},\"isGovernor()\":{\"notice\":\"Returns true if the caller is the current Governor.\"},\"manuallyFixAccounting(int256,int256,uint256)\":{\"notice\":\"Allow the Strategist to fix the accounting of this strategy and unpause.\"},\"platformAddress()\":{\"notice\":\"Address of the underlying platform\"},\"registerSsvValidator(bytes,uint64[],bytes,uint256,(uint32,uint64,uint64,bool,uint256))\":{\"notice\":\"Registers a new validator in the SSV Cluster. Only the registrator can call this function.\"},\"removePToken(uint256)\":{\"notice\":\"Remove a supported asset by passing its index. This method can only be called by the system Governor\"},\"removeSsvValidator(bytes,uint64[],(uint32,uint64,uint64,bool,uint256))\":{\"notice\":\"Remove a validator from the SSV Cluster. Make sure `exitSsvValidator` is called before and the validate has exited the Beacon chain. If removed before the validator has exited the beacon chain will result in the validator being slashed. Only the registrator can call this function.\"},\"rewardTokenAddresses(uint256)\":{\"notice\":\"Address of the reward tokens. eg CRV, BAL, CVX, AURA\"},\"safeApproveAllTokens()\":{\"notice\":\"Approves the SSV Network contract to transfer SSV tokens for deposits\"},\"setFuseInterval(uint256,uint256)\":{\"notice\":\"set fuse interval values\"},\"setHarvesterAddress(address)\":{\"notice\":\"Set the Harvester contract that can collect rewards.\"},\"setPTokenAddress(address,address)\":{\"notice\":\"Provide support for asset by passing its pToken address. This method can only be called by the system Governor\"},\"setRegistrator(address)\":{\"notice\":\"Set the address of the registrator which can register, exit and remove validators\"},\"setRewardTokenAddresses(address[])\":{\"notice\":\"Set the reward token addresses. Any old addresses will be overwritten.\"},\"stakeEth((bytes,bytes,bytes32)[])\":{\"notice\":\"Stakes WETH to the node validators\"},\"supportsAsset(address)\":{\"notice\":\"Returns bool indicating whether asset is supported by strategy.\"},\"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 strategy contracts, i.e. mistaken sends.\"},\"validatorRegistrator()\":{\"notice\":\"Address of the registrator - allowed to register, exit and remove validators\"},\"validatorsStates(bytes32)\":{\"notice\":\"State of the validators keccak256(pubKey) => state\"},\"vaultAddress()\":{\"notice\":\"Address of the OToken vault\"},\"withdraw(address,address,uint256)\":{\"notice\":\"Withdraw WETH from this contract. Used only if some WETH for is lingering on the contract. That can happen when: - the deposit was not a multiple of 32 WETH - someone sent WETH directly to this contract Will NOT revert if the strategy is paused from an accounting failure.\"},\"withdrawAll()\":{\"notice\":\"transfer all WETH deposits back to the vault. This does not withdraw from the validators. That has to be done separately with the `exitSsvValidator` and `removeSsvValidator` operations. This does not withdraw any execution rewards from the FeeAccumulator or consensus rewards in this strategy. Any ETH in this strategy that was swept from a full validator withdrawal will not be withdrawn. ETH from full validator withdrawals is sent to the Vault using `doAccounting`. Will NOT revert if the strategy is paused from an accounting failure.\"}},\"notice\":\"Strategy to deploy funds into DVT validators powered by the SSV Network\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol\":\"NativeStakingSSVStrategy\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"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\",\"keccak256\":\"0xe68ed7fb8766ed1e888291f881e36b616037f852b37d96877045319ad298ba87\",\"license\":\"MIT\"},\"@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/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\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"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/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\",\"keccak256\":\"0x598f90bdbc854250bbd5991426bfb43367207e64e33109c41aa8b54323fd8d8e\",\"license\":\"MIT\"},\"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 error ApprovalNotWithinTimeframe();\\n error CallerNotOwner();\\n error CallerNotWhitelisted();\\n error ClusterAlreadyEnabled();\\n error ClusterDoesNotExists();\\n error ClusterIsLiquidated();\\n error ClusterNotLiquidatable();\\n error ExceedValidatorLimit();\\n error FeeExceedsIncreaseLimit();\\n error FeeIncreaseNotAllowed();\\n error FeeTooHigh();\\n error FeeTooLow();\\n error IncorrectClusterState();\\n error IncorrectValidatorState();\\n error InsufficientBalance();\\n error InvalidOperatorIdsLength();\\n error InvalidPublicKeyLength();\\n error MaxValueExceeded();\\n error NewBlockPeriodIsBelowMinimum();\\n error NoFeeDeclared();\\n error NotAuthorized();\\n error OperatorAlreadyExists();\\n error OperatorDoesNotExist();\\n error OperatorsListNotUnique();\\n error SameFeeChangeNotAllowed();\\n error TargetModuleDoesNotExist();\\n error TokenTransferFailed();\\n error UnsortedOperatorsList();\\n error ValidatorAlreadyExists();\\n error ValidatorDoesNotExist();\\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 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 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 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\",\"keccak256\":\"0x76e2c5148727b72752939b06fee7abc1f732c18970b8c7db7fe7cdfe74629d36\",\"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/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/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\",\"keccak256\":\"0x05b7dce6c24d3cd4e48b5c6346d86e5e40ecc3291bcdf3f3ef091c98fc826519\",\"license\":\"MIT\"},\"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\\nimport { Governable } from \\\"../../governance/Governable.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 is Governable {\\n /// @notice The address of the Native Staking Strategy\\n address public immutable STRATEGY;\\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 }\\n\\n /**\\n * @dev Accept ETH\\n */\\n receive() external payable {}\\n}\\n\",\"keccak256\":\"0xb8fda3b87dc5d6f8aee4bf1d015a585211e5b5a319dfa4b0f4770e3f5a2d5939\",\"license\":\"MIT\"},\"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\\\";\\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\\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_ADDRESS;\\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 // For future use\\n uint256[50] 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 _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 address _feeAccumulator,\\n address _beaconChainDepositContract\\n )\\n InitializableAbstractStrategy(_baseConfig)\\n ValidatorAccountant(\\n _wethAddress,\\n _baseConfig.vaultAddress,\\n _beaconChainDepositContract,\\n _ssvNetwork\\n )\\n {\\n SSV_TOKEN_ADDRESS = _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 /// @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_TOKEN_ADDRESS).deposit{ value: ethRewards }();\\n\\n emit RewardTokenCollected(\\n harvesterAddress,\\n WETH_TOKEN_ADDRESS,\\n ethRewards\\n );\\n IERC20(WETH_TOKEN_ADDRESS).safeTransfer(\\n harvesterAddress,\\n ethRewards\\n );\\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_TOKEN_ADDRESS, \\\"Unsupported asset\\\");\\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_TOKEN_ADDRESS).balanceOf(\\n address(this)\\n );\\n if (wethBalance > 0) {\\n _deposit(WETH_TOKEN_ADDRESS, wethBalance);\\n }\\n }\\n\\n /// @notice Withdraw WETH from this contract. Used only if some WETH for is lingering on the contract. That\\n /// can happen when:\\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 _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 emit Withdrawal(_asset, address(0), _amount);\\n IERC20(_asset).safeTransfer(_recipient, _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_TOKEN_ADDRESS).balanceOf(\\n address(this)\\n );\\n if (wethBalance > 0) {\\n _withdraw(vaultAddress, WETH_TOKEN_ADDRESS, wethBalance);\\n }\\n }\\n\\n function _abstractSetPToken(address _asset, address) internal override {}\\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_TOKEN_ADDRESS, \\\"Unsupported asset\\\");\\n\\n balance =\\n // add the ETH that has been staked in validators\\n activeDepositedValidators *\\n 32 ether +\\n // add the WETH in the strategy from deposits that are still to be staked\\n IERC20(WETH_TOKEN_ADDRESS).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_TOKEN_ADDRESS;\\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_ADDRESS).approve(\\n SSV_NETWORK_ADDRESS,\\n type(uint256).max\\n );\\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 ||\\n msg.sender == WETH_TOKEN_ADDRESS,\\n \\\"eth not from allowed contracts\\\"\\n );\\n }\\n}\\n\",\"keccak256\":\"0x9ba7e5cc1fbf9e4a8559d9872dcdf8959b4f3ef9d9a2ff8e0f74c36ec9efb4fe\",\"license\":\"MIT\"},\"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 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 MAX_STAKE = 32 ether;\\n\\n /// @notice Keeps track of the total consensus rewards swept from the beacon chain\\n uint256 public consensusRewards = 0;\\n\\n /// @notice start of fuse interval\\n uint256 public fuseIntervalStart = 0;\\n /// @notice end of fuse interval\\n uint256 public fuseIntervalEnd = 0;\\n\\n uint256[50] 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 constructor(\\n address _wethAddress,\\n address _vaultAddress,\\n address _beaconChainDepositContract,\\n address _ssvNetwork\\n )\\n ValidatorRegistrator(\\n _wethAddress,\\n _vaultAddress,\\n _beaconChainDepositContract,\\n _ssvNetwork\\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 _fuseIntervalStart < 32 ether &&\\n _fuseIntervalEnd < 32 ether &&\\n _fuseIntervalEnd - _fuseIntervalStart >= 4 ether,\\n \\\"incorrect fuse interval\\\"\\n );\\n\\n emit FuseIntervalUpdated(_fuseIntervalStart, _fuseIntervalEnd);\\n\\n fuseIntervalStart = _fuseIntervalStart;\\n fuseIntervalEnd = _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 returns (bool accountingValid)\\n {\\n // pause the accounting on failure\\n accountingValid = _doAccounting(true);\\n }\\n\\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 >= MAX_STAKE) {\\n uint256 fullyWithdrawnValidators = newSweptETH / MAX_STAKE;\\n if (activeDepositedValidators < fullyWithdrawnValidators) {\\n return _failAccounting(pauseOnFail);\\n }\\n activeDepositedValidators -= fullyWithdrawnValidators;\\n\\n uint256 wethToVault = MAX_STAKE * fullyWithdrawnValidators;\\n IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: wethToVault }();\\n IWETH9(WETH_TOKEN_ADDRESS).transfer(VAULT_ADDRESS, 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 < 32 ether, \\\"unexpected accounting\\\");\\n\\n // If no Beacon chain consensus rewards swept\\n if (ethRemaining == 0) {\\n // do nothing\\n return accountingValid;\\n }\\n // Beacon chain consensus rewards swept (partial validator withdrawals)\\n else if (ethRemaining < fuseIntervalStart) {\\n // solhint-disable-next-line reentrancy\\n consensusRewards += ethRemaining;\\n emit AccountingConsensusRewards(ethRemaining);\\n }\\n // Beacon chain consensus rewards swept but also a slashed validator fully exited\\n else if (ethRemaining > fuseIntervalEnd) {\\n IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: ethRemaining }();\\n IWETH9(WETH_TOKEN_ADDRESS).transfer(VAULT_ADDRESS, ethRemaining);\\n activeDepositedValidators -= 1;\\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 /// @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 plus one, minus one or unchanged with zero\\n /// @param _wethToVaultAmount the amount of WETH to be sent to the Vault\\n /// @param _consensusRewardsDelta adjust the accounted for consensus rewards up or down\\n function manuallyFixAccounting(\\n int256 _validatorsDelta,\\n int256 _consensusRewardsDelta,\\n uint256 _wethToVaultAmount\\n ) external onlyStrategist whenPaused {\\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(_wethToVaultAmount <= 32 ether, \\\"invalid wethToVaultAmount\\\");\\n\\n emit AccountingManuallyFixed(\\n _validatorsDelta,\\n _consensusRewardsDelta,\\n _wethToVaultAmount\\n );\\n\\n activeDepositedValidators = uint256(\\n int256(activeDepositedValidators) + _validatorsDelta\\n );\\n consensusRewards = uint256(\\n int256(consensusRewards) + _consensusRewardsDelta\\n );\\n if (_wethToVaultAmount > 0) {\\n IWETH9(WETH_TOKEN_ADDRESS).transfer(\\n VAULT_ADDRESS,\\n _wethToVaultAmount\\n );\\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\",\"keccak256\":\"0xc6c306bde6b18189944f3d03fc82996b2e0c54b3a2882ee8d0fece0d71949e11\",\"license\":\"MIT\"},\"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 address of the Wrapped ETH (WETH) token contract\\n address public immutable WETH_TOKEN_ADDRESS;\\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_ADDRESS;\\n /// @notice Address of the OETH Vault proxy contract\\n address public immutable VAULT_ADDRESS;\\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\\n // For future use\\n uint256[50] private __gap;\\n\\n enum VALIDATOR_STATE {\\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 newAddress);\\n event ETHStaked(bytes pubkey, uint256 amount, bytes withdrawal_credentials);\\n event SSVValidatorRegistered(bytes pubkey, uint64[] operatorIds);\\n event SSVValidatorExitInitiated(bytes pubkey, uint64[] operatorIds);\\n event SSVValidatorExitCompleted(bytes pubkey, uint64[] operatorIds);\\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 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 constructor(\\n address _wethAddress,\\n address _vaultAddress,\\n address _beaconChainDepositContract,\\n address _ssvNetwork\\n ) {\\n WETH_TOKEN_ADDRESS = _wethAddress;\\n BEACON_CHAIN_DEPOSIT_CONTRACT = _beaconChainDepositContract;\\n SSV_NETWORK_ADDRESS = _ssvNetwork;\\n VAULT_ADDRESS = _vaultAddress;\\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 emit RegistratorChanged(_address);\\n validatorRegistrator = _address;\\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 function stakeEth(ValidatorStakeData[] calldata validators)\\n external\\n onlyRegistrator\\n whenNotPaused\\n {\\n uint256 requiredETH = validators.length * 32 ether;\\n\\n // Check there is enough WETH from the deposits sitting in this strategy contract\\n require(\\n requiredETH <= IWETH9(WETH_TOKEN_ADDRESS).balanceOf(address(this)),\\n \\\"insufficient WETH\\\"\\n );\\n\\n // Convert required ETH from WETH\\n IWETH9(WETH_TOKEN_ADDRESS).withdraw(requiredETH);\\n\\n // For each validator\\n for (uint256 i = 0; i < validators.length; ) {\\n bytes32 pubkeyHash = keccak256(validators[i].pubkey);\\n VALIDATOR_STATE currentState = validatorsStates[pubkeyHash];\\n\\n require(\\n currentState == VALIDATOR_STATE.REGISTERED,\\n \\\"Validator not registered\\\"\\n );\\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 withdrawal_credentials = abi.encodePacked(\\n bytes1(0x01),\\n bytes11(0),\\n address(this)\\n );\\n IDepositContract(BEACON_CHAIN_DEPOSIT_CONTRACT).deposit{\\n value: 32 ether\\n }(\\n validators[i].pubkey,\\n withdrawal_credentials,\\n validators[i].signature,\\n validators[i].depositDataRoot\\n );\\n\\n activeDepositedValidators += 1;\\n emit ETHStaked(\\n validators[i].pubkey,\\n 32 ether,\\n withdrawal_credentials\\n );\\n\\n validatorsStates[pubkeyHash] = VALIDATOR_STATE.STAKED;\\n\\n unchecked {\\n ++i;\\n }\\n }\\n }\\n\\n /// @notice Registers a new validator in the SSV Cluster.\\n /// Only the registrator can call this function.\\n function registerSsvValidator(\\n bytes calldata publicKey,\\n uint64[] calldata operatorIds,\\n bytes calldata sharesData,\\n uint256 amount,\\n Cluster calldata cluster\\n ) external onlyRegistrator whenNotPaused {\\n ISSVNetwork(SSV_NETWORK_ADDRESS).registerValidator(\\n publicKey,\\n operatorIds,\\n sharesData,\\n amount,\\n cluster\\n );\\n validatorsStates[keccak256(publicKey)] = VALIDATOR_STATE.REGISTERED;\\n emit SSVValidatorRegistered(publicKey, operatorIds);\\n }\\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 function exitSsvValidator(\\n bytes calldata publicKey,\\n uint64[] calldata operatorIds\\n ) external onlyRegistrator whenNotPaused {\\n VALIDATOR_STATE currentState = validatorsStates[keccak256(publicKey)];\\n require(currentState == VALIDATOR_STATE.STAKED, \\\"Validator not staked\\\");\\n\\n ISSVNetwork(SSV_NETWORK_ADDRESS).exitValidator(publicKey, operatorIds);\\n emit SSVValidatorExitInitiated(publicKey, operatorIds);\\n\\n validatorsStates[keccak256(publicKey)] = VALIDATOR_STATE.EXITING;\\n }\\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 function removeSsvValidator(\\n bytes calldata publicKey,\\n uint64[] calldata operatorIds,\\n Cluster calldata cluster\\n ) external onlyRegistrator whenNotPaused {\\n VALIDATOR_STATE currentState = validatorsStates[keccak256(publicKey)];\\n require(\\n currentState == VALIDATOR_STATE.EXITING,\\n \\\"Validator not exiting\\\"\\n );\\n\\n ISSVNetwork(SSV_NETWORK_ADDRESS).removeValidator(\\n publicKey,\\n operatorIds,\\n cluster\\n );\\n emit SSVValidatorExitCompleted(publicKey, operatorIds);\\n\\n validatorsStates[keccak256(publicKey)] = VALIDATOR_STATE.EXIT_COMPLETE;\\n }\\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 cluster The SSV cluster details that must be derived from emitted events from the SSVNetwork contract.\\n function depositSSV(\\n uint64[] memory operatorIds,\\n uint256 amount,\\n Cluster memory cluster\\n ) external onlyStrategist {\\n ISSVNetwork(SSV_NETWORK_ADDRESS).deposit(\\n address(this),\\n operatorIds,\\n amount,\\n cluster\\n );\\n }\\n}\\n\",\"keccak256\":\"0x4bc23d19500e2d306fd546c4ab9c4c53292d4ef54392ec4f1ae62dd7601a3d24\",\"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/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\",\"keccak256\":\"0x5e17bb3db9f9e1014b7c5c836547f8fa81e02af7568c0bb8f2a2e0e7c2192db4\",\"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/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": "0x610180604052600060685560006069556000606a553480156200002157600080fd5b5060405162004c9a38038062004c9a833981016040819052620000449162000147565b8585876020015183868383838362000062336200011760201b60201c565b60008051602062004c7a833981519152546040516001600160a01b03909116906000907fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a908290a36033805460ff191690556001600160601b0319606094851b811660805291841b821660a052831b811660c05290821b811660e0528651821b811661010052602090960151811b86166101205298891b851661014052505050509190931b1661016052506200022292505050565b60008051602062004c7a83398151915255565b80516001600160a01b03811681146200014257600080fd5b919050565b60008060008060008086880360e08112156200016257600080fd5b60408112156200017157600080fd5b50604080519081016001600160401b0381118282101715620001a357634e487b7160e01b600052604160045260246000fd5b604052620001b1886200012a565b8152620001c1602089016200012a565b60208201529550620001d6604088016200012a565b9450620001e6606088016200012a565b9350620001f6608088016200012a565b92506200020660a088016200012a565b91506200021660c088016200012a565b90509295509295509295565b60805160601c60a05160601c60c05160601c60e05160601c6101005160601c6101205160601c6101405160601c6101605160601c6148c2620003b8600039600081816102a70152818161096e0152612da901526000818161057d01526122fc01526000818161045101528181610d41015281816118c001528181611a390152818161265b01526128e30152600061093a0152600081816106ec01528181610b09015281816117ee01528181611a8901528181611d6c0152818161332201526135730152600081816109b701528181610bdf015281816116c0015281816122cc015281816123e401526127d90152600081816108a601526114070152600081816102d9015281816104db015281816107bd01528181610a7001528181610db601528181610f850152818161100d015281816111bc01528181611297015281816119aa01528181611a5a01528181611d9b0152818161296e015281816129fd01528181612eae01528181612f3301528181612fa70152818161329c01528181613351015281816134ed01526135a201526148c26000f3fe6080604052600436106102975760003560e01c8063853828b61161015a578063c2e1e3f4116100c1578063d9f00ec71161007a578063d9f00ec714610908578063dbe55e5614610928578063dd505df61461095c578063de5f626814610990578063f1188e40146109a5578063f6ca71b0146109d957600080fd5b8063c2e1e3f414610842578063c7af335214610862578063c98517c514610877578063cceab75014610894578063d38bfff4146108c8578063d9caed12146108e857600080fd5b80639da0e462116101135780639da0e4621461074e578063a4f98af41461078b578063aa388af6146107a0578063ab12edf5146107ed578063ad1728cb1461080d578063bb1b918d1461082257600080fd5b8063853828b61461068057806387bae867146106955780638d7c0e46146106ba5780639092c31c146106da5780639136616a1461070e57806396d538bb1461072e57600080fd5b80635c975abb116101fe5780636e811d38116101b75780636e811d38146105d55780636ef38795146105f557806371a735f3146106155780637b2d9b2c14610635578063842f5c46146106555780638456cb591461066b57600080fd5b80635c975abb146105125780635d36b190146105365780635f5152261461054b5780636093d3801461056b57806366e3667e1461059f57806367c7066c146105b557600080fd5b8063430bf08a11610250578063430bf08a1461043f578063435356d11461047357806347e7ef2414610493578063484be812146104b3578063579a7e1a146104c95780635a063f63146104fd57600080fd5b80630c340a24146103535780630ed57b3a146103855780630fc3b4c4146103a55780631072cbea146103db57806322495dc8146103fb5780633c8649591461041b57600080fd5b3661034e57336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614806102fb5750336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016145b61034c5760405162461bcd60e51b815260206004820152601e60248201527f657468206e6f742066726f6d20616c6c6f77656420636f6e747261637473000060448201526064015b60405180910390fd5b005b600080fd5b34801561035f57600080fd5b506103686109fb565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561039157600080fd5b5061034c6103a0366004613c43565b610a18565b3480156103b157600080fd5b506103686103c0366004613c09565b609f602052600090815260409020546001600160a01b031681565b3480156103e757600080fd5b5061034c6103f6366004613cbd565b610a4a565b34801561040757600080fd5b5061034c610416366004613db1565b610b07565b34801561042757600080fd5b5061043160695481565b60405190815260200161037c565b34801561044b57600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b34801561047f57600080fd5b5061034c61048e366004613d2a565b610c51565b34801561049f57600080fd5b5061034c6104ae366004613cbd565b610d36565b3480156104bf57600080fd5b50610431606a5481565b3480156104d557600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b34801561050957600080fd5b5061034c610e3c565b34801561051e57600080fd5b5060335460ff165b604051901515815260200161037c565b34801561054257600080fd5b5061034c610edb565b34801561055757600080fd5b50610431610566366004613c09565b610f81565b34801561057757600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b3480156105ab57600080fd5b5061043160345481565b3480156105c157600080fd5b5060a354610368906001600160a01b031681565b3480156105e157600080fd5b5061034c6105f0366004613c09565b6110b5565b34801561060157600080fd5b5061034c610610366004613ce9565b61113d565b34801561062157600080fd5b5061034c610630366004613fbf565b6115c9565b34801561064157600080fd5b50610368610650366004613e87565b6117c2565b34801561066157600080fd5b5061043160685481565b34801561067757600080fd5b5061034c6117ec565b34801561068c57600080fd5b5061034c6118b5565b3480156106a157600080fd5b506033546103689061010090046001600160a01b031681565b3480156106c657600080fd5b5061034c6106d5366004614040565b611a87565b3480156106e657600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b34801561071a57600080fd5b5061034c610729366004613e87565b611e6f565b34801561073a57600080fd5b5061034c610749366004613ce9565b61203a565b34801561075a57600080fd5b5061077e610769366004613e87565b60356020526000908152604090205460ff1681565b60405161037c91906144ab565b34801561079757600080fd5b5061052661215a565b3480156107ac57600080fd5b506105266107bb366004613c09565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0390811691161490565b3480156107f957600080fd5b5061034c610808366004614085565b6121b9565b34801561081957600080fd5b5061034c6122b5565b34801561082e57600080fd5b5061034c61083d366004613f0b565b61237b565b34801561084e57600080fd5b5061034c61085d366004613c09565b6124ee565b34801561086e57600080fd5b5061052661257b565b34801561088357600080fd5b506104316801bc16d674ec80000081565b3480156108a057600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b3480156108d457600080fd5b5061034c6108e3366004613c09565b6125ac565b3480156108f457600080fd5b5061034c610903366004613c7c565b612650565b34801561091457600080fd5b5061034c610923366004613ea0565b6126e3565b34801561093457600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b34801561096857600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b34801561099c57600080fd5b5061034c6128d8565b3480156109b157600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b3480156109e557600080fd5b506109ee612a22565b60405161037c9190614281565b6000610a1360008051602061486d8339815191525490565b905090565b610a2061257b565b610a3c5760405162461bcd60e51b81526004016103439061451d565b610a468282612a84565b5050565b610a5261257b565b610a6e5760405162461bcd60e51b81526004016103439061451d565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b039081169083161415610aeb5760405162461bcd60e51b815260206004820152601f60248201527f43616e6e6f74207472616e7366657220737570706f72746564206173736574006044820152606401610343565b610a46610af66109fb565b6001600160a01b0384169083612be3565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b158015610b6057600080fd5b505afa158015610b74573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b989190613c26565b6001600160a01b0316336001600160a01b031614610bc85760405162461bcd60e51b8152600401610343906145dd565b60405163bc26e7e560e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063bc26e7e590610c1a9030908790879087906004016141d1565b600060405180830381600087803b158015610c3457600080fd5b505af1158015610c48573d6000803e3d6000fd5b50505050505050565b610c5961257b565b610c755760405162461bcd60e51b81526004016103439061451d565b600054610100900460ff1680610c8e575060005460ff16155b610cf15760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610343565b600054610100900460ff16158015610d13576000805461ffff19166101011790555b610d1e848484612c35565b8015610d30576000805461ff00191690555b50505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610d7e5760405162461bcd60e51b8152600401610343906144e6565b60008051602061484d83398151915280546002811415610db05760405162461bcd60e51b8152600401610343906145b5565b600282557f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316846001600160a01b031614610e295760405162461bcd60e51b8152602060048201526011602482015270155b9cdd5c1c1bdc9d195908185cdcd95d607a1b6044820152606401610343565b610e338484612cf0565b50600190555050565b60a3546001600160a01b03163314610e965760405162461bcd60e51b815260206004820152601b60248201527f43616c6c6572206973206e6f74207468652048617276657374657200000000006044820152606401610343565b60008051602061484d83398151915280546002811415610ec85760405162461bcd60e51b8152600401610343906145b5565b60028255610ed4612d82565b5060019055565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b031614610f765760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b6064820152608401610343565b610f7f33612fd0565b565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b031614610ff85760405162461bcd60e51b8152602060048201526011602482015270155b9cdd5c1c1bdc9d195908185cdcd95d607a1b6044820152606401610343565b6040516370a0823160e01b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b15801561105757600080fd5b505afa15801561106b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061108f919061406c565b6034546110a5906801bc16d674ec80000061473e565b6110af9190614704565b92915050565b6110bd61257b565b6110d95760405162461bcd60e51b81526004016103439061451d565b6040516001600160a01b03821681527f83f29c79feb71f8fba9d0fbc4ba5f0982a28b6b1e868b3fc50e6400d100bca0f9060200160405180910390a1603380546001600160a01b0390921661010002610100600160a81b0319909216919091179055565b60335461010090046001600160a01b0316331461116c5760405162461bcd60e51b81526004016103439061457e565b60335460ff161561118f5760405162461bcd60e51b815260040161034390614554565b60006111a4826801bc16d674ec80000061473e565b6040516370a0823160e01b81523060048201529091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b15801561120657600080fd5b505afa15801561121a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061123e919061406c565b8111156112815760405162461bcd60e51b81526020600482015260116024820152700d2dce6eaccccd2c6d2cadce840ae8aa89607b1b6044820152606401610343565b604051632e1a7d4d60e01b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b1580156112e357600080fd5b505af11580156112f7573d6000803e3d6000fd5b5050505060005b82811015610d3057600084848381811061131a5761131a6147fd565b905060200281019061132c919061465a565b6113369080614614565b6040516113449291906141a5565b6040805191829003909120600081815260356020529182205490925060ff1690816003811115611376576113766147d1565b146113c35760405162461bcd60e51b815260206004820152601860248201527f56616c696461746f72206e6f74207265676973746572656400000000000000006044820152606401610343565b60408051600160f81b60208201526000602182018190526bffffffffffffffffffffffff193060601b16602c830152910160405160208183030381529060405290507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663228951186801bc16d674ec800000898988818110611450576114506147fd565b9050602002810190611462919061465a565b61146c9080614614565b858c8c8b81811061147f5761147f6147fd565b9050602002810190611491919061465a565b61149f906020810190614614565b8e8e8d8181106114b1576114b16147fd565b90506020028101906114c3919061465a565b604001356040518863ffffffff1660e01b81526004016114e896959493929190614430565b6000604051808303818588803b15801561150157600080fd5b505af1158015611515573d6000803e3d6000fd5b505050505060016034600082825461152d9190614704565b909155507ffeb31a79d38edb1b090d516e4df3e273651179c6f2c2ec53a9a22ae015b70ba99050878786818110611566576115666147fd565b9050602002810190611578919061465a565b6115829080614614565b6801bc16d674ec8000008460405161159d949392919061447f565b60405180910390a150506000908152603560205260409020805460ff19166001908117909155016112fe565b60335461010090046001600160a01b031633146115f85760405162461bcd60e51b81526004016103439061457e565b60335460ff161561161b5760405162461bcd60e51b815260040161034390614554565b60006035600087876040516116319291906141a5565b604080519182900390912082526020820192909252016000205460ff1690506002816003811115611664576116646147d1565b146116a95760405162461bcd60e51b815260206004820152601560248201527456616c696461746f72206e6f742065786974696e6760581b6044820152606401610343565b6040516312b3fc1960e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906312b3fc19906116fd90899089908990899089906004016143ef565b600060405180830381600087803b15801561171757600080fd5b505af115801561172b573d6000803e3d6000fd5b505050507ff72821b8777f002ccdf6326f1242d9e0f762eb077668b67bebe640535378066d868686866040516117649493929190614366565b60405180910390a160036035600088886040516117829291906141a5565b60408051918290039091208252602082019290925201600020805460ff191660018360038111156117b5576117b56147d1565b0217905550505050505050565b60a481815481106117d257600080fd5b6000918252602090912001546001600160a01b0316905081565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b15801561184557600080fd5b505afa158015611859573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061187d9190613c26565b6001600160a01b0316336001600160a01b0316146118ad5760405162461bcd60e51b8152600401610343906145dd565b610f7f613091565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016148061190457506118ef6109fb565b6001600160a01b0316336001600160a01b0316145b61195c5760405162461bcd60e51b815260206004820152602360248201527f43616c6c6572206973206e6f7420746865205661756c74206f7220476f7665726044820152623737b960e91b6064820152608401610343565b60008051602061484d8339815191528054600281141561198e5760405162461bcd60e51b8152600401610343906145b5565b600282556040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b1580156119f457600080fd5b505afa158015611a08573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a2c919061406c565b90508015611a7f57611a7f7f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000083613106565b505060019055565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b158015611ae057600080fd5b505afa158015611af4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b189190613c26565b6001600160a01b0316336001600160a01b031614611b485760405162461bcd60e51b8152600401610343906145dd565b60335460ff16611b915760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610343565b6002198312158015611ba4575060038313155b8015611bbe5750600083603454611bbb91906146c3565b12155b611c0a5760405162461bcd60e51b815260206004820152601760248201527f696e76616c69642076616c696461746f727344656c74610000000000000000006044820152606401610343565b6811ff6cf0fd15afffff198212158015611c2d57506811ff6cf0fd15b000008213155b8015611c475750600082606854611c4491906146c3565b12155b611c935760405162461bcd60e51b815260206004820152601d60248201527f696e76616c696420636f6e73656e7375735265776172647344656c74610000006044820152606401610343565b6801bc16d674ec800000811115611cec5760405162461bcd60e51b815260206004820152601960248201527f696e76616c69642077657468546f5661756c74416d6f756e74000000000000006044820152606401610343565b60408051848152602081018490529081018290527f80d022717ea022455c5886b8dd8a29c037570aae58aeb4d7b136d7a10ec2e4319060600160405180910390a182603454611d3b91906146c3565b603455606854611d4c9083906146c3565b6068558015611e195760405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018390527f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb90604401602060405180830381600087803b158015611ddf57600080fd5b505af1158015611df3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e179190613e6a565b505b611e2360006131fe565b611e625760405162461bcd60e51b815260206004820152601060248201526f333ab9b29039ba34b63610313637bbb760811b6044820152606401610343565b611e6a613684565b505050565b611e7761257b565b611e935760405162461bcd60e51b81526004016103439061451d565b60a0548110611ed45760405162461bcd60e51b815260206004820152600d60248201526c092dcecc2d8d2c840d2dcc8caf609b1b6044820152606401610343565b600060a08281548110611ee957611ee96147fd565b60009182526020808320909101546001600160a01b03908116808452609f90925260409092205460a05491935090911690611f269060019061475d565b831015611fa85760a08054611f3d9060019061475d565b81548110611f4d57611f4d6147fd565b60009182526020909120015460a080546001600160a01b039092169185908110611f7957611f796147fd565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505b60a0805480611fb957611fb96147e7565b60008281526020808220600019908401810180546001600160a01b031990811690915593019093556001600160a01b03858116808352609f855260409283902080549094169093559051908416815290917f16b7600acff27e39a8a96056b3d533045298de927507f5c1d97e4accde60488c910160405180910390a2505050565b61204261257b565b61205e5760405162461bcd60e51b81526004016103439061451d565b8060005b8181101561211157600084848381811061207e5761207e6147fd565b90506020020160208101906120939190613c09565b6001600160a01b031614156121015760405162461bcd60e51b815260206004820152602e60248201527f43616e206e6f742073657420616e20656d70747920616464726573732061732060448201526d30903932bbb0b932103a37b5b2b760911b6064820152608401610343565b61210a816147a0565b9050612062565b507f04c0b9649497d316554306e53678d5f5f5dbc3a06f97dec13ff4cfe98b986bbc60a48484604051612146939291906142ce565b60405180910390a1610d3060a48484613962565b60335460009061010090046001600160a01b0316331461218c5760405162461bcd60e51b81526004016103439061457e565b60335460ff16156121af5760405162461bcd60e51b815260040161034390614554565b610a1360016131fe565b6121c161257b565b6121dd5760405162461bcd60e51b81526004016103439061451d565b80821080156121f457506801bc16d674ec80000082105b801561220857506801bc16d674ec80000081105b80156122255750673782dace9d900000612222838361475d565b10155b6122715760405162461bcd60e51b815260206004820152601760248201527f696e636f7272656374206675736520696e74657276616c0000000000000000006044820152606401610343565b60408051838152602081018390527fcb8d24e46eb3c402bf344ee60a6576cba9ef2f59ea1af3b311520704924e901a910160405180910390a1606991909155606a55565b60405163095ea7b360e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015260001960248301527f0000000000000000000000000000000000000000000000000000000000000000169063095ea7b390604401602060405180830381600087803b15801561234057600080fd5b505af1158015612354573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123789190613e6a565b50565b60335461010090046001600160a01b031633146123aa5760405162461bcd60e51b81526004016103439061457e565b60335460ff16156123cd5760405162461bcd60e51b815260040161034390614554565b6040516301ba3ee760e21b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906306e8fb9c90612427908b908b908b908b908b908b908b908b9060040161438d565b600060405180830381600087803b15801561244157600080fd5b505af1158015612455573d6000803e3d6000fd5b505050506000603560008a8a60405161246f9291906141a5565b60408051918290039091208252602082019290925201600020805460ff191660018360038111156124a2576124a26147d1565b02179055507f75c4a66b2c6c28cf46db7131182a812e4fbbb2f0591377aa83a737909a9b68c3888888886040516124dc9493929190614366565b60405180910390a15050505050505050565b6124f661257b565b6125125760405162461bcd60e51b81526004016103439061451d565b60a354604080516001600160a01b03928316815291831660208301527fe48386b84419f4d36e0f96c10cc3510b6fb1a33795620c5098b22472bbe90796910160405180910390a160a380546001600160a01b0319166001600160a01b0392909216919091179055565b600061259360008051602061486d8339815191525490565b6001600160a01b0316336001600160a01b031614905090565b6125b461257b565b6125d05760405162461bcd60e51b81526004016103439061451d565b6125f8817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b031661261860008051602061486d8339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146126985760405162461bcd60e51b8152600401610343906144e6565b60008051602061484d833981519152805460028114156126ca5760405162461bcd60e51b8152600401610343906145b5565b600282556126d9858585613106565b5060019055505050565b60335461010090046001600160a01b031633146127125760405162461bcd60e51b81526004016103439061457e565b60335460ff16156127355760405162461bcd60e51b815260040161034390614554565b600060356000868660405161274b9291906141a5565b604080519182900390912082526020820192909252016000205460ff169050600181600381111561277e5761277e6147d1565b146127c25760405162461bcd60e51b815260206004820152601460248201527315985b1a59185d1bdc881b9bdd081cdd185ad95960621b6044820152606401610343565b604051633877322b60e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690633877322b90612814908890889088908890600401614366565b600060405180830381600087803b15801561282e57600080fd5b505af1158015612842573d6000803e3d6000fd5b505050507ff8821da16f5ed966b41e0343c3eff9903af782d74f99f1689dd9d4562b6545b38585858560405161287b9493929190614366565b60405180910390a160026035600087876040516128999291906141a5565b60408051918290039091208252602082019290925201600020805460ff191660018360038111156128cc576128cc6147d1565b02179055505050505050565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146129205760405162461bcd60e51b8152600401610343906144e6565b60008051602061484d833981519152805460028114156129525760405162461bcd60e51b8152600401610343906145b5565b600282556040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b1580156129b857600080fd5b505afa1580156129cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129f0919061406c565b90508015611a7f57611a7f7f000000000000000000000000000000000000000000000000000000000000000082612cf0565b606060a4805480602002602001604051908101604052809291908181526020018280548015612a7a57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612a5c575b5050505050905090565b6001600160a01b038281166000908152609f60205260409020541615612ae15760405162461bcd60e51b81526020600482015260126024820152711c151bdad95b88185b1c9958591e481cd95d60721b6044820152606401610343565b6001600160a01b03821615801590612b0157506001600160a01b03811615155b612b415760405162461bcd60e51b8152602060048201526011602482015270496e76616c69642061646472657373657360781b6044820152606401610343565b6001600160a01b038281166000818152609f6020908152604080832080549587166001600160a01b0319968716811790915560a0805460018101825594527f78fdc8d422c49ced035a9edf18d00d3c6a8d81df210f3e5e448e045e77b41e8890930180549095168417909455925190815290917fef6485b84315f9b1483beffa32aae9a0596890395e3d7521f1c5fbb51790e765910160405180910390a25050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052611e6a9084906136fe565b8251612c489060a49060208601906139c5565b50815181518114612c925760405162461bcd60e51b8152602060048201526014602482015273496e76616c696420696e7075742061727261797360601b6044820152606401610343565b60005b81811015612ce957612cd9848281518110612cb257612cb26147fd565b6020026020010151848381518110612ccc57612ccc6147fd565b6020026020010151612a84565b612ce2816147a0565b9050612c95565b5050505050565b60008111612d395760405162461bcd60e51b81526020600482015260166024820152754d757374206465706f73697420736f6d657468696e6760501b6044820152606401610343565b6040805160008152602081018390526001600160a01b038416917f5548c837ab068cf56a2c2479df0882a4922fd203edb7517321831d95078c5f62910160405180910390a25050565b60335460ff1615612da55760405162461bcd60e51b815260040161034390614554565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663e52253816040518163ffffffff1660e01b8152600401602060405180830381600087803b158015612e0257600080fd5b505af1158015612e16573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e3a919061406c565b9050600060685482612e4c9190614704565b905080471015612e9e5760405162461bcd60e51b815260206004820152601860248201527f696e73756666696369656e74206574682062616c616e636500000000000000006044820152606401610343565b8015610a465760006068819055507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b158015612f0757600080fd5b505af1158015612f1b573d6000803e3d6000fd5b505060a354604080516001600160a01b0392831681527f0000000000000000000000000000000000000000000000000000000000000000909216602083015281018590527ff6c07a063ed4e63808eb8da7112d46dbcd38de2b40a73dbcc9353c5a94c7235393506060019150612f8e9050565b60405180910390a160a354610a46906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116911683612be3565b6001600160a01b0381166130265760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f7220697320616464726573732830290000000000006044820152606401610343565b806001600160a01b031661304660008051602061486d8339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a36123788160008051602061486d83398151915255565b60335460ff16156130b45760405162461bcd60e51b815260040161034390614554565b6033805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586130e93390565b6040516001600160a01b03909116815260200160405180910390a1565b600081116131565760405162461bcd60e51b815260206004820152601760248201527f4d75737420776974686472617720736f6d657468696e670000000000000000006044820152606401610343565b6001600160a01b0383166131a55760405162461bcd60e51b8152602060048201526016602482015275135d5cdd081cdc1958da599e481c9958da5c1a595b9d60521b6044820152606401610343565b6040805160008152602081018390526001600160a01b038416917f2717ead6b9200dd235aad468c9809ea400fe33ac69b5bfaa6d3e90fc922b6398910160405180910390a2611e6a6001600160a01b0383168483612be3565b6000606854471015613213576110af826137d0565b600060685447613223919061475d565b9050600191506801bc16d674ec800000811061341957600061324e6801bc16d674ec8000008361471c565b905080603454101561326b57613263846137d0565b949350505050565b806034600082825461327d919061475d565b9091555060009050613298826801bc16d674ec80000061473e565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b1580156132f557600080fd5b505af1158015613309573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb92506044019050602060405180830381600087803b15801561339957600080fd5b505af11580156133ad573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133d19190613e6a565b5060345460408051848152602081019290925281018290527fbe7040030ff7b347853214bf49820c6d455fedf58f3815f85c7bc5216993682b9060600160405180910390a150505b600060685447613429919061475d565b90506801bc16d674ec800000811061347b5760405162461bcd60e51b8152602060048201526015602482015274756e6578706563746564206163636f756e74696e6760581b6044820152606401610343565b80613487575050919050565b6069548110156134e15780606860008282546134a39190614704565b90915550506040518181527f7a745a2c63a535068f52ceca27debd5297bbad5f7f37ec53d044a59d0362445d906020015b60405180910390a161367d565b606a54811115613674577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b15801561354657600080fd5b505af115801561355a573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb92506044019050602060405180830381600087803b1580156135ea57600080fd5b505af11580156135fe573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136229190613e6a565b50600160346000828254613636919061475d565b909155505060345460408051918252602082018390527f6aa7e30787b26429ced603a7aba8b19c4b5d5bcf29a3257da953c8d53bcaa3a691016134d4565b613263846137d0565b5050919050565b60335460ff166136cd5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610343565b6033805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa336130e9565b6000613753826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166137e89092919063ffffffff16565b805190915015611e6a57808060200190518101906137719190613e6a565b611e6a5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610343565b600081156137e0576137e0613091565b506000919050565b60606137f78484600085613801565b90505b9392505050565b6060824710156138625760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610343565b843b6138b05760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610343565b600080866001600160a01b031685876040516138cc91906141b5565b60006040518083038185875af1925050503d8060008114613909576040519150601f19603f3d011682016040523d82523d6000602084013e61390e565b606091505b509150915061391e828286613929565b979650505050505050565b606083156139385750816137fa565b8251156139485782518084602001fd5b8160405162461bcd60e51b815260040161034391906144d3565b8280548282559060005260206000209081019282156139b5579160200282015b828111156139b55781546001600160a01b0319166001600160a01b03843516178255602090920191600190910190613982565b506139c1929150613a1a565b5090565b8280548282559060005260206000209081019282156139b5579160200282015b828111156139b557825182546001600160a01b0319166001600160a01b039091161782556020909201916001909101906139e5565b5b808211156139c15760008155600101613a1b565b60008083601f840112613a4157600080fd5b5081356001600160401b03811115613a5857600080fd5b6020830191508360208260051b8501011115613a7357600080fd5b9250929050565b600082601f830112613a8b57600080fd5b81356020613aa0613a9b836146a0565b614670565b80838252828201915082860187848660051b8901011115613ac057600080fd5b60005b85811015613ae8578135613ad681614829565b84529284019290840190600101613ac3565b5090979650505050505050565b60008083601f840112613b0757600080fd5b5081356001600160401b03811115613b1e57600080fd5b602083019150836020828501011115613a7357600080fd5b600060a08284031215613b4857600080fd5b50919050565b600060a08284031215613b6057600080fd5b60405160a081018181106001600160401b0382111715613b8257613b82614813565b604052905080613b9183613bd9565b8152613b9f60208401613bf2565b6020820152613bb060408401613bf2565b60408201526060830135613bc38161483e565b6060820152608092830135920191909152919050565b803563ffffffff81168114613bed57600080fd5b919050565b80356001600160401b0381168114613bed57600080fd5b600060208284031215613c1b57600080fd5b81356137fa81614829565b600060208284031215613c3857600080fd5b81516137fa81614829565b60008060408385031215613c5657600080fd5b8235613c6181614829565b91506020830135613c7181614829565b809150509250929050565b600080600060608486031215613c9157600080fd5b8335613c9c81614829565b92506020840135613cac81614829565b929592945050506040919091013590565b60008060408385031215613cd057600080fd5b8235613cdb81614829565b946020939093013593505050565b60008060208385031215613cfc57600080fd5b82356001600160401b03811115613d1257600080fd5b613d1e85828601613a2f565b90969095509350505050565b600080600060608486031215613d3f57600080fd5b83356001600160401b0380821115613d5657600080fd5b613d6287838801613a7a565b94506020860135915080821115613d7857600080fd5b613d8487838801613a7a565b93506040860135915080821115613d9a57600080fd5b50613da786828701613a7a565b9150509250925092565b600080600060e08486031215613dc657600080fd5b83356001600160401b03811115613ddc57600080fd5b8401601f81018613613ded57600080fd5b80356020613dfd613a9b836146a0565b8083825282820191508285018a848660051b8801011115613e1d57600080fd5b600095505b84861015613e4757613e3381613bf2565b835260019590950194918301918301613e22565b509650508601359350613e61915086905060408601613b4e565b90509250925092565b600060208284031215613e7c57600080fd5b81516137fa8161483e565b600060208284031215613e9957600080fd5b5035919050565b60008060008060408587031215613eb657600080fd5b84356001600160401b0380821115613ecd57600080fd5b613ed988838901613af5565b90965094506020870135915080821115613ef257600080fd5b50613eff87828801613a2f565b95989497509550505050565b600080600080600080600080610120898b031215613f2857600080fd5b88356001600160401b0380821115613f3f57600080fd5b613f4b8c838d01613af5565b909a50985060208b0135915080821115613f6457600080fd5b613f708c838d01613a2f565b909850965060408b0135915080821115613f8957600080fd5b50613f968b828c01613af5565b90955093505060608901359150613fb08a60808b01613b36565b90509295985092959890939650565b600080600080600060e08688031215613fd757600080fd5b85356001600160401b0380821115613fee57600080fd5b613ffa89838a01613af5565b9097509550602088013591508082111561401357600080fd5b5061402088828901613a2f565b909450925061403490508760408801613b36565b90509295509295909350565b60008060006060848603121561405557600080fd5b505081359360208301359350604090920135919050565b60006020828403121561407e57600080fd5b5051919050565b6000806040838503121561409857600080fd5b50508035926020909101359150565b8183526000602080850194508260005b858110156140e3576001600160401b036140d083613bf2565b16875295820195908201906001016140b7565b509495945050505050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6000815180845261412f816020860160208601614774565b601f01601f19169290920160200192915050565b63ffffffff61415182613bd9565b16825261416060208201613bf2565b6001600160401b0380821660208501528061417d60408501613bf2565b166040850152505060608101356141938161483e565b15156060830152608090810135910152565b8183823760009101908152919050565b600082516141c7818460208701614774565b9190910192915050565b6001600160a01b03851681526101006020808301829052855191830182905260009161012084019187810191845b818110156142245783516001600160401b0316855293820193928201926001016141ff565b505082935086604086015263ffffffff865116606086015280860151925050506001600160401b0380821660808501528060408601511660a085015250506060830151151560c0830152608083015160e083015295945050505050565b6020808252825182820181905260009190848201906040850190845b818110156142c25783516001600160a01b03168352928401929184019160010161429d565b50909695505050505050565b6000604082016040835280865480835260608501915087600052602092508260002060005b828110156143185781546001600160a01b0316845292840192600191820191016142f3565b505050838103828501528481528590820160005b8681101561435a57823561433f81614829565b6001600160a01b03168252918301919083019060010161432c565b50979650505050505050565b60408152600061437a6040830186886140ee565b828103602084015261391e8185876140a7565b60006101208083526143a28184018b8d6140ee565b905082810360208401526143b781898b6140a7565b905082810360408401526143cc8187896140ee565b9150508360608301526143e26080830184614143565b9998505050505050505050565b60e08152600061440360e0830187896140ee565b82810360208401526144168186886140a7565b9150506144266040830184614143565b9695505050505050565b60808152600061444460808301888a6140ee565b82810360208401526144568188614117565b9050828103604084015261446b8186886140ee565b915050826060830152979650505050505050565b6060815260006144936060830186886140ee565b846020840152828103604084015261391e8185614117565b60208101600483106144cd57634e487b7160e01b600052602160045260246000fd5b91905290565b6020815260006137fa6020830184614117565b60208082526017908201527f43616c6c6572206973206e6f7420746865205661756c74000000000000000000604082015260600190565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b60208082526010908201526f14185d5cd8589b194e881c185d5cd95960821b604082015260600190565b6020808252601d908201527f43616c6c6572206973206e6f7420746865205265676973747261746f72000000604082015260600190565b6020808252600e908201526d1499595b9d1c985b9d0818d85b1b60921b604082015260600190565b6020808252601c908201527f43616c6c6572206973206e6f7420746865205374726174656769737400000000604082015260600190565b6000808335601e1984360301811261462b57600080fd5b8301803591506001600160401b0382111561464557600080fd5b602001915036819003821315613a7357600080fd5b60008235605e198336030181126141c757600080fd5b604051601f8201601f191681016001600160401b038111828210171561469857614698614813565b604052919050565b60006001600160401b038211156146b9576146b9614813565b5060051b60200190565b600080821280156001600160ff1b03849003851316156146e5576146e56147bb565b600160ff1b83900384128116156146fe576146fe6147bb565b50500190565b60008219821115614717576147176147bb565b500190565b60008261473957634e487b7160e01b600052601260045260246000fd5b500490565b6000816000190483118215151615614758576147586147bb565b500290565b60008282101561476f5761476f6147bb565b500390565b60005b8381101561478f578181015183820152602001614777565b83811115610d305750506000910152565b60006000198214156147b4576147b46147bb565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b038116811461237857600080fd5b801515811461237857600080fdfe53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac45357bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa2646970667358221220113919d09ddf52cbaf34c41b4ba31e1d6e98f959c68a6c638232aecc6636f9ac64736f6c634300080700337bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a", + "deployedBytecode": "0x6080604052600436106102975760003560e01c8063853828b61161015a578063c2e1e3f4116100c1578063d9f00ec71161007a578063d9f00ec714610908578063dbe55e5614610928578063dd505df61461095c578063de5f626814610990578063f1188e40146109a5578063f6ca71b0146109d957600080fd5b8063c2e1e3f414610842578063c7af335214610862578063c98517c514610877578063cceab75014610894578063d38bfff4146108c8578063d9caed12146108e857600080fd5b80639da0e462116101135780639da0e4621461074e578063a4f98af41461078b578063aa388af6146107a0578063ab12edf5146107ed578063ad1728cb1461080d578063bb1b918d1461082257600080fd5b8063853828b61461068057806387bae867146106955780638d7c0e46146106ba5780639092c31c146106da5780639136616a1461070e57806396d538bb1461072e57600080fd5b80635c975abb116101fe5780636e811d38116101b75780636e811d38146105d55780636ef38795146105f557806371a735f3146106155780637b2d9b2c14610635578063842f5c46146106555780638456cb591461066b57600080fd5b80635c975abb146105125780635d36b190146105365780635f5152261461054b5780636093d3801461056b57806366e3667e1461059f57806367c7066c146105b557600080fd5b8063430bf08a11610250578063430bf08a1461043f578063435356d11461047357806347e7ef2414610493578063484be812146104b3578063579a7e1a146104c95780635a063f63146104fd57600080fd5b80630c340a24146103535780630ed57b3a146103855780630fc3b4c4146103a55780631072cbea146103db57806322495dc8146103fb5780633c8649591461041b57600080fd5b3661034e57336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614806102fb5750336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016145b61034c5760405162461bcd60e51b815260206004820152601e60248201527f657468206e6f742066726f6d20616c6c6f77656420636f6e747261637473000060448201526064015b60405180910390fd5b005b600080fd5b34801561035f57600080fd5b506103686109fb565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561039157600080fd5b5061034c6103a0366004613c43565b610a18565b3480156103b157600080fd5b506103686103c0366004613c09565b609f602052600090815260409020546001600160a01b031681565b3480156103e757600080fd5b5061034c6103f6366004613cbd565b610a4a565b34801561040757600080fd5b5061034c610416366004613db1565b610b07565b34801561042757600080fd5b5061043160695481565b60405190815260200161037c565b34801561044b57600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b34801561047f57600080fd5b5061034c61048e366004613d2a565b610c51565b34801561049f57600080fd5b5061034c6104ae366004613cbd565b610d36565b3480156104bf57600080fd5b50610431606a5481565b3480156104d557600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b34801561050957600080fd5b5061034c610e3c565b34801561051e57600080fd5b5060335460ff165b604051901515815260200161037c565b34801561054257600080fd5b5061034c610edb565b34801561055757600080fd5b50610431610566366004613c09565b610f81565b34801561057757600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b3480156105ab57600080fd5b5061043160345481565b3480156105c157600080fd5b5060a354610368906001600160a01b031681565b3480156105e157600080fd5b5061034c6105f0366004613c09565b6110b5565b34801561060157600080fd5b5061034c610610366004613ce9565b61113d565b34801561062157600080fd5b5061034c610630366004613fbf565b6115c9565b34801561064157600080fd5b50610368610650366004613e87565b6117c2565b34801561066157600080fd5b5061043160685481565b34801561067757600080fd5b5061034c6117ec565b34801561068c57600080fd5b5061034c6118b5565b3480156106a157600080fd5b506033546103689061010090046001600160a01b031681565b3480156106c657600080fd5b5061034c6106d5366004614040565b611a87565b3480156106e657600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b34801561071a57600080fd5b5061034c610729366004613e87565b611e6f565b34801561073a57600080fd5b5061034c610749366004613ce9565b61203a565b34801561075a57600080fd5b5061077e610769366004613e87565b60356020526000908152604090205460ff1681565b60405161037c91906144ab565b34801561079757600080fd5b5061052661215a565b3480156107ac57600080fd5b506105266107bb366004613c09565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0390811691161490565b3480156107f957600080fd5b5061034c610808366004614085565b6121b9565b34801561081957600080fd5b5061034c6122b5565b34801561082e57600080fd5b5061034c61083d366004613f0b565b61237b565b34801561084e57600080fd5b5061034c61085d366004613c09565b6124ee565b34801561086e57600080fd5b5061052661257b565b34801561088357600080fd5b506104316801bc16d674ec80000081565b3480156108a057600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b3480156108d457600080fd5b5061034c6108e3366004613c09565b6125ac565b3480156108f457600080fd5b5061034c610903366004613c7c565b612650565b34801561091457600080fd5b5061034c610923366004613ea0565b6126e3565b34801561093457600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b34801561096857600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b34801561099c57600080fd5b5061034c6128d8565b3480156109b157600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b3480156109e557600080fd5b506109ee612a22565b60405161037c9190614281565b6000610a1360008051602061486d8339815191525490565b905090565b610a2061257b565b610a3c5760405162461bcd60e51b81526004016103439061451d565b610a468282612a84565b5050565b610a5261257b565b610a6e5760405162461bcd60e51b81526004016103439061451d565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b039081169083161415610aeb5760405162461bcd60e51b815260206004820152601f60248201527f43616e6e6f74207472616e7366657220737570706f72746564206173736574006044820152606401610343565b610a46610af66109fb565b6001600160a01b0384169083612be3565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b158015610b6057600080fd5b505afa158015610b74573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b989190613c26565b6001600160a01b0316336001600160a01b031614610bc85760405162461bcd60e51b8152600401610343906145dd565b60405163bc26e7e560e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063bc26e7e590610c1a9030908790879087906004016141d1565b600060405180830381600087803b158015610c3457600080fd5b505af1158015610c48573d6000803e3d6000fd5b50505050505050565b610c5961257b565b610c755760405162461bcd60e51b81526004016103439061451d565b600054610100900460ff1680610c8e575060005460ff16155b610cf15760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610343565b600054610100900460ff16158015610d13576000805461ffff19166101011790555b610d1e848484612c35565b8015610d30576000805461ff00191690555b50505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610d7e5760405162461bcd60e51b8152600401610343906144e6565b60008051602061484d83398151915280546002811415610db05760405162461bcd60e51b8152600401610343906145b5565b600282557f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316846001600160a01b031614610e295760405162461bcd60e51b8152602060048201526011602482015270155b9cdd5c1c1bdc9d195908185cdcd95d607a1b6044820152606401610343565b610e338484612cf0565b50600190555050565b60a3546001600160a01b03163314610e965760405162461bcd60e51b815260206004820152601b60248201527f43616c6c6572206973206e6f74207468652048617276657374657200000000006044820152606401610343565b60008051602061484d83398151915280546002811415610ec85760405162461bcd60e51b8152600401610343906145b5565b60028255610ed4612d82565b5060019055565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b031614610f765760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b6064820152608401610343565b610f7f33612fd0565b565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b031614610ff85760405162461bcd60e51b8152602060048201526011602482015270155b9cdd5c1c1bdc9d195908185cdcd95d607a1b6044820152606401610343565b6040516370a0823160e01b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b15801561105757600080fd5b505afa15801561106b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061108f919061406c565b6034546110a5906801bc16d674ec80000061473e565b6110af9190614704565b92915050565b6110bd61257b565b6110d95760405162461bcd60e51b81526004016103439061451d565b6040516001600160a01b03821681527f83f29c79feb71f8fba9d0fbc4ba5f0982a28b6b1e868b3fc50e6400d100bca0f9060200160405180910390a1603380546001600160a01b0390921661010002610100600160a81b0319909216919091179055565b60335461010090046001600160a01b0316331461116c5760405162461bcd60e51b81526004016103439061457e565b60335460ff161561118f5760405162461bcd60e51b815260040161034390614554565b60006111a4826801bc16d674ec80000061473e565b6040516370a0823160e01b81523060048201529091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b15801561120657600080fd5b505afa15801561121a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061123e919061406c565b8111156112815760405162461bcd60e51b81526020600482015260116024820152700d2dce6eaccccd2c6d2cadce840ae8aa89607b1b6044820152606401610343565b604051632e1a7d4d60e01b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b1580156112e357600080fd5b505af11580156112f7573d6000803e3d6000fd5b5050505060005b82811015610d3057600084848381811061131a5761131a6147fd565b905060200281019061132c919061465a565b6113369080614614565b6040516113449291906141a5565b6040805191829003909120600081815260356020529182205490925060ff1690816003811115611376576113766147d1565b146113c35760405162461bcd60e51b815260206004820152601860248201527f56616c696461746f72206e6f74207265676973746572656400000000000000006044820152606401610343565b60408051600160f81b60208201526000602182018190526bffffffffffffffffffffffff193060601b16602c830152910160405160208183030381529060405290507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663228951186801bc16d674ec800000898988818110611450576114506147fd565b9050602002810190611462919061465a565b61146c9080614614565b858c8c8b81811061147f5761147f6147fd565b9050602002810190611491919061465a565b61149f906020810190614614565b8e8e8d8181106114b1576114b16147fd565b90506020028101906114c3919061465a565b604001356040518863ffffffff1660e01b81526004016114e896959493929190614430565b6000604051808303818588803b15801561150157600080fd5b505af1158015611515573d6000803e3d6000fd5b505050505060016034600082825461152d9190614704565b909155507ffeb31a79d38edb1b090d516e4df3e273651179c6f2c2ec53a9a22ae015b70ba99050878786818110611566576115666147fd565b9050602002810190611578919061465a565b6115829080614614565b6801bc16d674ec8000008460405161159d949392919061447f565b60405180910390a150506000908152603560205260409020805460ff19166001908117909155016112fe565b60335461010090046001600160a01b031633146115f85760405162461bcd60e51b81526004016103439061457e565b60335460ff161561161b5760405162461bcd60e51b815260040161034390614554565b60006035600087876040516116319291906141a5565b604080519182900390912082526020820192909252016000205460ff1690506002816003811115611664576116646147d1565b146116a95760405162461bcd60e51b815260206004820152601560248201527456616c696461746f72206e6f742065786974696e6760581b6044820152606401610343565b6040516312b3fc1960e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906312b3fc19906116fd90899089908990899089906004016143ef565b600060405180830381600087803b15801561171757600080fd5b505af115801561172b573d6000803e3d6000fd5b505050507ff72821b8777f002ccdf6326f1242d9e0f762eb077668b67bebe640535378066d868686866040516117649493929190614366565b60405180910390a160036035600088886040516117829291906141a5565b60408051918290039091208252602082019290925201600020805460ff191660018360038111156117b5576117b56147d1565b0217905550505050505050565b60a481815481106117d257600080fd5b6000918252602090912001546001600160a01b0316905081565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b15801561184557600080fd5b505afa158015611859573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061187d9190613c26565b6001600160a01b0316336001600160a01b0316146118ad5760405162461bcd60e51b8152600401610343906145dd565b610f7f613091565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016148061190457506118ef6109fb565b6001600160a01b0316336001600160a01b0316145b61195c5760405162461bcd60e51b815260206004820152602360248201527f43616c6c6572206973206e6f7420746865205661756c74206f7220476f7665726044820152623737b960e91b6064820152608401610343565b60008051602061484d8339815191528054600281141561198e5760405162461bcd60e51b8152600401610343906145b5565b600282556040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b1580156119f457600080fd5b505afa158015611a08573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a2c919061406c565b90508015611a7f57611a7f7f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000083613106565b505060019055565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b158015611ae057600080fd5b505afa158015611af4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b189190613c26565b6001600160a01b0316336001600160a01b031614611b485760405162461bcd60e51b8152600401610343906145dd565b60335460ff16611b915760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610343565b6002198312158015611ba4575060038313155b8015611bbe5750600083603454611bbb91906146c3565b12155b611c0a5760405162461bcd60e51b815260206004820152601760248201527f696e76616c69642076616c696461746f727344656c74610000000000000000006044820152606401610343565b6811ff6cf0fd15afffff198212158015611c2d57506811ff6cf0fd15b000008213155b8015611c475750600082606854611c4491906146c3565b12155b611c935760405162461bcd60e51b815260206004820152601d60248201527f696e76616c696420636f6e73656e7375735265776172647344656c74610000006044820152606401610343565b6801bc16d674ec800000811115611cec5760405162461bcd60e51b815260206004820152601960248201527f696e76616c69642077657468546f5661756c74416d6f756e74000000000000006044820152606401610343565b60408051848152602081018490529081018290527f80d022717ea022455c5886b8dd8a29c037570aae58aeb4d7b136d7a10ec2e4319060600160405180910390a182603454611d3b91906146c3565b603455606854611d4c9083906146c3565b6068558015611e195760405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018390527f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb90604401602060405180830381600087803b158015611ddf57600080fd5b505af1158015611df3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e179190613e6a565b505b611e2360006131fe565b611e625760405162461bcd60e51b815260206004820152601060248201526f333ab9b29039ba34b63610313637bbb760811b6044820152606401610343565b611e6a613684565b505050565b611e7761257b565b611e935760405162461bcd60e51b81526004016103439061451d565b60a0548110611ed45760405162461bcd60e51b815260206004820152600d60248201526c092dcecc2d8d2c840d2dcc8caf609b1b6044820152606401610343565b600060a08281548110611ee957611ee96147fd565b60009182526020808320909101546001600160a01b03908116808452609f90925260409092205460a05491935090911690611f269060019061475d565b831015611fa85760a08054611f3d9060019061475d565b81548110611f4d57611f4d6147fd565b60009182526020909120015460a080546001600160a01b039092169185908110611f7957611f796147fd565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505b60a0805480611fb957611fb96147e7565b60008281526020808220600019908401810180546001600160a01b031990811690915593019093556001600160a01b03858116808352609f855260409283902080549094169093559051908416815290917f16b7600acff27e39a8a96056b3d533045298de927507f5c1d97e4accde60488c910160405180910390a2505050565b61204261257b565b61205e5760405162461bcd60e51b81526004016103439061451d565b8060005b8181101561211157600084848381811061207e5761207e6147fd565b90506020020160208101906120939190613c09565b6001600160a01b031614156121015760405162461bcd60e51b815260206004820152602e60248201527f43616e206e6f742073657420616e20656d70747920616464726573732061732060448201526d30903932bbb0b932103a37b5b2b760911b6064820152608401610343565b61210a816147a0565b9050612062565b507f04c0b9649497d316554306e53678d5f5f5dbc3a06f97dec13ff4cfe98b986bbc60a48484604051612146939291906142ce565b60405180910390a1610d3060a48484613962565b60335460009061010090046001600160a01b0316331461218c5760405162461bcd60e51b81526004016103439061457e565b60335460ff16156121af5760405162461bcd60e51b815260040161034390614554565b610a1360016131fe565b6121c161257b565b6121dd5760405162461bcd60e51b81526004016103439061451d565b80821080156121f457506801bc16d674ec80000082105b801561220857506801bc16d674ec80000081105b80156122255750673782dace9d900000612222838361475d565b10155b6122715760405162461bcd60e51b815260206004820152601760248201527f696e636f7272656374206675736520696e74657276616c0000000000000000006044820152606401610343565b60408051838152602081018390527fcb8d24e46eb3c402bf344ee60a6576cba9ef2f59ea1af3b311520704924e901a910160405180910390a1606991909155606a55565b60405163095ea7b360e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015260001960248301527f0000000000000000000000000000000000000000000000000000000000000000169063095ea7b390604401602060405180830381600087803b15801561234057600080fd5b505af1158015612354573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123789190613e6a565b50565b60335461010090046001600160a01b031633146123aa5760405162461bcd60e51b81526004016103439061457e565b60335460ff16156123cd5760405162461bcd60e51b815260040161034390614554565b6040516301ba3ee760e21b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906306e8fb9c90612427908b908b908b908b908b908b908b908b9060040161438d565b600060405180830381600087803b15801561244157600080fd5b505af1158015612455573d6000803e3d6000fd5b505050506000603560008a8a60405161246f9291906141a5565b60408051918290039091208252602082019290925201600020805460ff191660018360038111156124a2576124a26147d1565b02179055507f75c4a66b2c6c28cf46db7131182a812e4fbbb2f0591377aa83a737909a9b68c3888888886040516124dc9493929190614366565b60405180910390a15050505050505050565b6124f661257b565b6125125760405162461bcd60e51b81526004016103439061451d565b60a354604080516001600160a01b03928316815291831660208301527fe48386b84419f4d36e0f96c10cc3510b6fb1a33795620c5098b22472bbe90796910160405180910390a160a380546001600160a01b0319166001600160a01b0392909216919091179055565b600061259360008051602061486d8339815191525490565b6001600160a01b0316336001600160a01b031614905090565b6125b461257b565b6125d05760405162461bcd60e51b81526004016103439061451d565b6125f8817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b031661261860008051602061486d8339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146126985760405162461bcd60e51b8152600401610343906144e6565b60008051602061484d833981519152805460028114156126ca5760405162461bcd60e51b8152600401610343906145b5565b600282556126d9858585613106565b5060019055505050565b60335461010090046001600160a01b031633146127125760405162461bcd60e51b81526004016103439061457e565b60335460ff16156127355760405162461bcd60e51b815260040161034390614554565b600060356000868660405161274b9291906141a5565b604080519182900390912082526020820192909252016000205460ff169050600181600381111561277e5761277e6147d1565b146127c25760405162461bcd60e51b815260206004820152601460248201527315985b1a59185d1bdc881b9bdd081cdd185ad95960621b6044820152606401610343565b604051633877322b60e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690633877322b90612814908890889088908890600401614366565b600060405180830381600087803b15801561282e57600080fd5b505af1158015612842573d6000803e3d6000fd5b505050507ff8821da16f5ed966b41e0343c3eff9903af782d74f99f1689dd9d4562b6545b38585858560405161287b9493929190614366565b60405180910390a160026035600087876040516128999291906141a5565b60408051918290039091208252602082019290925201600020805460ff191660018360038111156128cc576128cc6147d1565b02179055505050505050565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146129205760405162461bcd60e51b8152600401610343906144e6565b60008051602061484d833981519152805460028114156129525760405162461bcd60e51b8152600401610343906145b5565b600282556040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b1580156129b857600080fd5b505afa1580156129cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129f0919061406c565b90508015611a7f57611a7f7f000000000000000000000000000000000000000000000000000000000000000082612cf0565b606060a4805480602002602001604051908101604052809291908181526020018280548015612a7a57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612a5c575b5050505050905090565b6001600160a01b038281166000908152609f60205260409020541615612ae15760405162461bcd60e51b81526020600482015260126024820152711c151bdad95b88185b1c9958591e481cd95d60721b6044820152606401610343565b6001600160a01b03821615801590612b0157506001600160a01b03811615155b612b415760405162461bcd60e51b8152602060048201526011602482015270496e76616c69642061646472657373657360781b6044820152606401610343565b6001600160a01b038281166000818152609f6020908152604080832080549587166001600160a01b0319968716811790915560a0805460018101825594527f78fdc8d422c49ced035a9edf18d00d3c6a8d81df210f3e5e448e045e77b41e8890930180549095168417909455925190815290917fef6485b84315f9b1483beffa32aae9a0596890395e3d7521f1c5fbb51790e765910160405180910390a25050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052611e6a9084906136fe565b8251612c489060a49060208601906139c5565b50815181518114612c925760405162461bcd60e51b8152602060048201526014602482015273496e76616c696420696e7075742061727261797360601b6044820152606401610343565b60005b81811015612ce957612cd9848281518110612cb257612cb26147fd565b6020026020010151848381518110612ccc57612ccc6147fd565b6020026020010151612a84565b612ce2816147a0565b9050612c95565b5050505050565b60008111612d395760405162461bcd60e51b81526020600482015260166024820152754d757374206465706f73697420736f6d657468696e6760501b6044820152606401610343565b6040805160008152602081018390526001600160a01b038416917f5548c837ab068cf56a2c2479df0882a4922fd203edb7517321831d95078c5f62910160405180910390a25050565b60335460ff1615612da55760405162461bcd60e51b815260040161034390614554565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663e52253816040518163ffffffff1660e01b8152600401602060405180830381600087803b158015612e0257600080fd5b505af1158015612e16573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e3a919061406c565b9050600060685482612e4c9190614704565b905080471015612e9e5760405162461bcd60e51b815260206004820152601860248201527f696e73756666696369656e74206574682062616c616e636500000000000000006044820152606401610343565b8015610a465760006068819055507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b158015612f0757600080fd5b505af1158015612f1b573d6000803e3d6000fd5b505060a354604080516001600160a01b0392831681527f0000000000000000000000000000000000000000000000000000000000000000909216602083015281018590527ff6c07a063ed4e63808eb8da7112d46dbcd38de2b40a73dbcc9353c5a94c7235393506060019150612f8e9050565b60405180910390a160a354610a46906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116911683612be3565b6001600160a01b0381166130265760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f7220697320616464726573732830290000000000006044820152606401610343565b806001600160a01b031661304660008051602061486d8339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a36123788160008051602061486d83398151915255565b60335460ff16156130b45760405162461bcd60e51b815260040161034390614554565b6033805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586130e93390565b6040516001600160a01b03909116815260200160405180910390a1565b600081116131565760405162461bcd60e51b815260206004820152601760248201527f4d75737420776974686472617720736f6d657468696e670000000000000000006044820152606401610343565b6001600160a01b0383166131a55760405162461bcd60e51b8152602060048201526016602482015275135d5cdd081cdc1958da599e481c9958da5c1a595b9d60521b6044820152606401610343565b6040805160008152602081018390526001600160a01b038416917f2717ead6b9200dd235aad468c9809ea400fe33ac69b5bfaa6d3e90fc922b6398910160405180910390a2611e6a6001600160a01b0383168483612be3565b6000606854471015613213576110af826137d0565b600060685447613223919061475d565b9050600191506801bc16d674ec800000811061341957600061324e6801bc16d674ec8000008361471c565b905080603454101561326b57613263846137d0565b949350505050565b806034600082825461327d919061475d565b9091555060009050613298826801bc16d674ec80000061473e565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b1580156132f557600080fd5b505af1158015613309573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb92506044019050602060405180830381600087803b15801561339957600080fd5b505af11580156133ad573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133d19190613e6a565b5060345460408051848152602081019290925281018290527fbe7040030ff7b347853214bf49820c6d455fedf58f3815f85c7bc5216993682b9060600160405180910390a150505b600060685447613429919061475d565b90506801bc16d674ec800000811061347b5760405162461bcd60e51b8152602060048201526015602482015274756e6578706563746564206163636f756e74696e6760581b6044820152606401610343565b80613487575050919050565b6069548110156134e15780606860008282546134a39190614704565b90915550506040518181527f7a745a2c63a535068f52ceca27debd5297bbad5f7f37ec53d044a59d0362445d906020015b60405180910390a161367d565b606a54811115613674577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b15801561354657600080fd5b505af115801561355a573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb92506044019050602060405180830381600087803b1580156135ea57600080fd5b505af11580156135fe573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136229190613e6a565b50600160346000828254613636919061475d565b909155505060345460408051918252602082018390527f6aa7e30787b26429ced603a7aba8b19c4b5d5bcf29a3257da953c8d53bcaa3a691016134d4565b613263846137d0565b5050919050565b60335460ff166136cd5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610343565b6033805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa336130e9565b6000613753826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166137e89092919063ffffffff16565b805190915015611e6a57808060200190518101906137719190613e6a565b611e6a5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610343565b600081156137e0576137e0613091565b506000919050565b60606137f78484600085613801565b90505b9392505050565b6060824710156138625760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610343565b843b6138b05760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610343565b600080866001600160a01b031685876040516138cc91906141b5565b60006040518083038185875af1925050503d8060008114613909576040519150601f19603f3d011682016040523d82523d6000602084013e61390e565b606091505b509150915061391e828286613929565b979650505050505050565b606083156139385750816137fa565b8251156139485782518084602001fd5b8160405162461bcd60e51b815260040161034391906144d3565b8280548282559060005260206000209081019282156139b5579160200282015b828111156139b55781546001600160a01b0319166001600160a01b03843516178255602090920191600190910190613982565b506139c1929150613a1a565b5090565b8280548282559060005260206000209081019282156139b5579160200282015b828111156139b557825182546001600160a01b0319166001600160a01b039091161782556020909201916001909101906139e5565b5b808211156139c15760008155600101613a1b565b60008083601f840112613a4157600080fd5b5081356001600160401b03811115613a5857600080fd5b6020830191508360208260051b8501011115613a7357600080fd5b9250929050565b600082601f830112613a8b57600080fd5b81356020613aa0613a9b836146a0565b614670565b80838252828201915082860187848660051b8901011115613ac057600080fd5b60005b85811015613ae8578135613ad681614829565b84529284019290840190600101613ac3565b5090979650505050505050565b60008083601f840112613b0757600080fd5b5081356001600160401b03811115613b1e57600080fd5b602083019150836020828501011115613a7357600080fd5b600060a08284031215613b4857600080fd5b50919050565b600060a08284031215613b6057600080fd5b60405160a081018181106001600160401b0382111715613b8257613b82614813565b604052905080613b9183613bd9565b8152613b9f60208401613bf2565b6020820152613bb060408401613bf2565b60408201526060830135613bc38161483e565b6060820152608092830135920191909152919050565b803563ffffffff81168114613bed57600080fd5b919050565b80356001600160401b0381168114613bed57600080fd5b600060208284031215613c1b57600080fd5b81356137fa81614829565b600060208284031215613c3857600080fd5b81516137fa81614829565b60008060408385031215613c5657600080fd5b8235613c6181614829565b91506020830135613c7181614829565b809150509250929050565b600080600060608486031215613c9157600080fd5b8335613c9c81614829565b92506020840135613cac81614829565b929592945050506040919091013590565b60008060408385031215613cd057600080fd5b8235613cdb81614829565b946020939093013593505050565b60008060208385031215613cfc57600080fd5b82356001600160401b03811115613d1257600080fd5b613d1e85828601613a2f565b90969095509350505050565b600080600060608486031215613d3f57600080fd5b83356001600160401b0380821115613d5657600080fd5b613d6287838801613a7a565b94506020860135915080821115613d7857600080fd5b613d8487838801613a7a565b93506040860135915080821115613d9a57600080fd5b50613da786828701613a7a565b9150509250925092565b600080600060e08486031215613dc657600080fd5b83356001600160401b03811115613ddc57600080fd5b8401601f81018613613ded57600080fd5b80356020613dfd613a9b836146a0565b8083825282820191508285018a848660051b8801011115613e1d57600080fd5b600095505b84861015613e4757613e3381613bf2565b835260019590950194918301918301613e22565b509650508601359350613e61915086905060408601613b4e565b90509250925092565b600060208284031215613e7c57600080fd5b81516137fa8161483e565b600060208284031215613e9957600080fd5b5035919050565b60008060008060408587031215613eb657600080fd5b84356001600160401b0380821115613ecd57600080fd5b613ed988838901613af5565b90965094506020870135915080821115613ef257600080fd5b50613eff87828801613a2f565b95989497509550505050565b600080600080600080600080610120898b031215613f2857600080fd5b88356001600160401b0380821115613f3f57600080fd5b613f4b8c838d01613af5565b909a50985060208b0135915080821115613f6457600080fd5b613f708c838d01613a2f565b909850965060408b0135915080821115613f8957600080fd5b50613f968b828c01613af5565b90955093505060608901359150613fb08a60808b01613b36565b90509295985092959890939650565b600080600080600060e08688031215613fd757600080fd5b85356001600160401b0380821115613fee57600080fd5b613ffa89838a01613af5565b9097509550602088013591508082111561401357600080fd5b5061402088828901613a2f565b909450925061403490508760408801613b36565b90509295509295909350565b60008060006060848603121561405557600080fd5b505081359360208301359350604090920135919050565b60006020828403121561407e57600080fd5b5051919050565b6000806040838503121561409857600080fd5b50508035926020909101359150565b8183526000602080850194508260005b858110156140e3576001600160401b036140d083613bf2565b16875295820195908201906001016140b7565b509495945050505050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6000815180845261412f816020860160208601614774565b601f01601f19169290920160200192915050565b63ffffffff61415182613bd9565b16825261416060208201613bf2565b6001600160401b0380821660208501528061417d60408501613bf2565b166040850152505060608101356141938161483e565b15156060830152608090810135910152565b8183823760009101908152919050565b600082516141c7818460208701614774565b9190910192915050565b6001600160a01b03851681526101006020808301829052855191830182905260009161012084019187810191845b818110156142245783516001600160401b0316855293820193928201926001016141ff565b505082935086604086015263ffffffff865116606086015280860151925050506001600160401b0380821660808501528060408601511660a085015250506060830151151560c0830152608083015160e083015295945050505050565b6020808252825182820181905260009190848201906040850190845b818110156142c25783516001600160a01b03168352928401929184019160010161429d565b50909695505050505050565b6000604082016040835280865480835260608501915087600052602092508260002060005b828110156143185781546001600160a01b0316845292840192600191820191016142f3565b505050838103828501528481528590820160005b8681101561435a57823561433f81614829565b6001600160a01b03168252918301919083019060010161432c565b50979650505050505050565b60408152600061437a6040830186886140ee565b828103602084015261391e8185876140a7565b60006101208083526143a28184018b8d6140ee565b905082810360208401526143b781898b6140a7565b905082810360408401526143cc8187896140ee565b9150508360608301526143e26080830184614143565b9998505050505050505050565b60e08152600061440360e0830187896140ee565b82810360208401526144168186886140a7565b9150506144266040830184614143565b9695505050505050565b60808152600061444460808301888a6140ee565b82810360208401526144568188614117565b9050828103604084015261446b8186886140ee565b915050826060830152979650505050505050565b6060815260006144936060830186886140ee565b846020840152828103604084015261391e8185614117565b60208101600483106144cd57634e487b7160e01b600052602160045260246000fd5b91905290565b6020815260006137fa6020830184614117565b60208082526017908201527f43616c6c6572206973206e6f7420746865205661756c74000000000000000000604082015260600190565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b60208082526010908201526f14185d5cd8589b194e881c185d5cd95960821b604082015260600190565b6020808252601d908201527f43616c6c6572206973206e6f7420746865205265676973747261746f72000000604082015260600190565b6020808252600e908201526d1499595b9d1c985b9d0818d85b1b60921b604082015260600190565b6020808252601c908201527f43616c6c6572206973206e6f7420746865205374726174656769737400000000604082015260600190565b6000808335601e1984360301811261462b57600080fd5b8301803591506001600160401b0382111561464557600080fd5b602001915036819003821315613a7357600080fd5b60008235605e198336030181126141c757600080fd5b604051601f8201601f191681016001600160401b038111828210171561469857614698614813565b604052919050565b60006001600160401b038211156146b9576146b9614813565b5060051b60200190565b600080821280156001600160ff1b03849003851316156146e5576146e56147bb565b600160ff1b83900384128116156146fe576146fe6147bb565b50500190565b60008219821115614717576147176147bb565b500190565b60008261473957634e487b7160e01b600052601260045260246000fd5b500490565b6000816000190483118215151615614758576147586147bb565b500290565b60008282101561476f5761476f6147bb565b500390565b60005b8381101561478f578181015183820152602001614777565b83811115610d305750506000910152565b60006000198214156147b4576147b46147bb565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b038116811461237857600080fd5b801515811461237857600080fdfe53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac45357bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa2646970667358221220113919d09ddf52cbaf34c41b4ba31e1d6e98f959c68a6c638232aecc6636f9ac64736f6c63430008070033", "libraries": {}, "devdoc": { "author": "Origin Protocol Inc", @@ -1592,7 +1592,7 @@ "storageLayout": { "storage": [ { - "astId": 41335, + "astId": 5243, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "initialized", "offset": 0, @@ -1600,7 +1600,7 @@ "type": "t_bool" }, { - "astId": 41338, + "astId": 5246, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "initializing", "offset": 1, @@ -1608,7 +1608,7 @@ "type": "t_bool" }, { - "astId": 41378, + "astId": 5286, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "______gap", "offset": 0, @@ -1616,7 +1616,7 @@ "type": "t_array(t_uint256)50_storage" }, { - "astId": 549, + "astId": 17, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "_paused", "offset": 0, @@ -1624,7 +1624,7 @@ "type": "t_bool" }, { - "astId": 34647, + "astId": 3506, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "validatorRegistrator", "offset": 1, @@ -1632,7 +1632,7 @@ "type": "t_address" }, { - "astId": 34650, + "astId": 3509, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "activeDepositedValidators", "offset": 0, @@ -1640,15 +1640,15 @@ "type": "t_uint256" }, { - "astId": 34656, + "astId": 3515, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "validatorsStates", "offset": 0, "slot": "53", - "type": "t_mapping(t_bytes32,t_enum(VALIDATOR_STATE)34665)" + "type": "t_mapping(t_bytes32,t_enum(VALIDATOR_STATE)3524)" }, { - "astId": 34660, + "astId": 3519, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "__gap", "offset": 0, @@ -1656,7 +1656,7 @@ "type": "t_array(t_uint256)50_storage" }, { - "astId": 34184, + "astId": 3043, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "consensusRewards", "offset": 0, @@ -1664,7 +1664,7 @@ "type": "t_uint256" }, { - "astId": 34188, + "astId": 3047, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "fuseIntervalStart", "offset": 0, @@ -1672,7 +1672,7 @@ "type": "t_uint256" }, { - "astId": 34192, + "astId": 3051, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "fuseIntervalEnd", "offset": 0, @@ -1680,7 +1680,7 @@ "type": "t_uint256" }, { - "astId": 34196, + "astId": 3055, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "__gap", "offset": 0, @@ -1688,7 +1688,7 @@ "type": "t_array(t_uint256)50_storage" }, { - "astId": 41458, + "astId": 5366, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "_deprecated_platformAddress", "offset": 0, @@ -1696,7 +1696,7 @@ "type": "t_address" }, { - "astId": 41461, + "astId": 5369, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "_deprecated_vaultAddress", "offset": 0, @@ -1704,7 +1704,7 @@ "type": "t_address" }, { - "astId": 41466, + "astId": 5374, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "assetToPToken", "offset": 0, @@ -1712,7 +1712,7 @@ "type": "t_mapping(t_address,t_address)" }, { - "astId": 41470, + "astId": 5378, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "assetsMapped", "offset": 0, @@ -1720,7 +1720,7 @@ "type": "t_array(t_address)dyn_storage" }, { - "astId": 41472, + "astId": 5380, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "_deprecated_rewardTokenAddress", "offset": 0, @@ -1728,7 +1728,7 @@ "type": "t_address" }, { - "astId": 41474, + "astId": 5382, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "_deprecated_rewardLiquidationThreshold", "offset": 0, @@ -1736,7 +1736,7 @@ "type": "t_uint256" }, { - "astId": 41477, + "astId": 5385, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "harvesterAddress", "offset": 0, @@ -1744,7 +1744,7 @@ "type": "t_address" }, { - "astId": 41481, + "astId": 5389, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "rewardTokenAddresses", "offset": 0, @@ -1752,7 +1752,7 @@ "type": "t_array(t_address)dyn_storage" }, { - "astId": 41485, + "astId": 5393, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "_reserved", "offset": 0, @@ -1760,7 +1760,7 @@ "type": "t_array(t_int256)98_storage" }, { - "astId": 33757, + "astId": 2613, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "__gap", "offset": 0, @@ -1802,7 +1802,7 @@ "label": "bytes32", "numberOfBytes": "32" }, - "t_enum(VALIDATOR_STATE)34665": { + "t_enum(VALIDATOR_STATE)3524": { "encoding": "inplace", "label": "enum ValidatorRegistrator.VALIDATOR_STATE", "numberOfBytes": "1" @@ -1819,12 +1819,12 @@ "numberOfBytes": "32", "value": "t_address" }, - "t_mapping(t_bytes32,t_enum(VALIDATOR_STATE)34665)": { + "t_mapping(t_bytes32,t_enum(VALIDATOR_STATE)3524)": { "encoding": "mapping", "key": "t_bytes32", "label": "mapping(bytes32 => enum ValidatorRegistrator.VALIDATOR_STATE)", "numberOfBytes": "32", - "value": "t_enum(VALIDATOR_STATE)34665" + "value": "t_enum(VALIDATOR_STATE)3524" }, "t_uint256": { "encoding": "inplace", diff --git a/contracts/deployments/holesky/solcInputs/94a4e2017aae119860e82f5bc90e390d.json b/contracts/deployments/holesky/solcInputs/94a4e2017aae119860e82f5bc90e390d.json new file mode 100644 index 0000000000..c9e855611d --- /dev/null +++ b/contracts/deployments/holesky/solcInputs/94a4e2017aae119860e82f5bc90e390d.json @@ -0,0 +1,104 @@ +{ + "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/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/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/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" + }, + "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/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/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/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 error ApprovalNotWithinTimeframe();\n error CallerNotOwner();\n error CallerNotWhitelisted();\n error ClusterAlreadyEnabled();\n error ClusterDoesNotExists();\n error ClusterIsLiquidated();\n error ClusterNotLiquidatable();\n error ExceedValidatorLimit();\n error FeeExceedsIncreaseLimit();\n error FeeIncreaseNotAllowed();\n error FeeTooHigh();\n error FeeTooLow();\n error IncorrectClusterState();\n error IncorrectValidatorState();\n error InsufficientBalance();\n error InvalidOperatorIdsLength();\n error InvalidPublicKeyLength();\n error MaxValueExceeded();\n error NewBlockPeriodIsBelowMinimum();\n error NoFeeDeclared();\n error NotAuthorized();\n error OperatorAlreadyExists();\n error OperatorDoesNotExist();\n error OperatorsListNotUnique();\n error SameFeeChangeNotAllowed();\n error TargetModuleDoesNotExist();\n error TokenTransferFailed();\n error UnsortedOperatorsList();\n error ValidatorAlreadyExists();\n error ValidatorDoesNotExist();\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 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 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 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/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" + }, + "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/strategies/NativeStaking/FeeAccumulator.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { Address } from \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport { Governable } from \"../../governance/Governable.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 is Governable {\n /// @notice The address of the Native Staking Strategy\n address public immutable STRATEGY;\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 }\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\";\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\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_ADDRESS;\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 // For future use\n uint256[50] 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 _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 address _feeAccumulator,\n address _beaconChainDepositContract\n )\n InitializableAbstractStrategy(_baseConfig)\n ValidatorAccountant(\n _wethAddress,\n _baseConfig.vaultAddress,\n _beaconChainDepositContract,\n _ssvNetwork\n )\n {\n SSV_TOKEN_ADDRESS = _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 /// @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_TOKEN_ADDRESS).deposit{ value: ethRewards }();\n\n emit RewardTokenCollected(\n harvesterAddress,\n WETH_TOKEN_ADDRESS,\n ethRewards\n );\n IERC20(WETH_TOKEN_ADDRESS).safeTransfer(\n harvesterAddress,\n ethRewards\n );\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_TOKEN_ADDRESS, \"Unsupported asset\");\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_TOKEN_ADDRESS).balanceOf(\n address(this)\n );\n if (wethBalance > 0) {\n _deposit(WETH_TOKEN_ADDRESS, wethBalance);\n }\n }\n\n /// @notice Withdraw WETH from this contract. Used only if some WETH for is lingering on the contract. That\n /// can happen when:\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 _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 emit Withdrawal(_asset, address(0), _amount);\n IERC20(_asset).safeTransfer(_recipient, _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_TOKEN_ADDRESS).balanceOf(\n address(this)\n );\n if (wethBalance > 0) {\n _withdraw(vaultAddress, WETH_TOKEN_ADDRESS, wethBalance);\n }\n }\n\n function _abstractSetPToken(address _asset, address) internal override {}\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_TOKEN_ADDRESS, \"Unsupported asset\");\n\n balance =\n // add the ETH that has been staked in validators\n activeDepositedValidators *\n 32 ether +\n // add the WETH in the strategy from deposits that are still to be staked\n IERC20(WETH_TOKEN_ADDRESS).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_TOKEN_ADDRESS;\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_ADDRESS).approve(\n SSV_NETWORK_ADDRESS,\n type(uint256).max\n );\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 ||\n msg.sender == WETH_TOKEN_ADDRESS,\n \"eth not from allowed contracts\"\n );\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 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 MAX_STAKE = 32 ether;\n\n /// @notice Keeps track of the total consensus rewards swept from the beacon chain\n uint256 public consensusRewards = 0;\n\n /// @notice start of fuse interval\n uint256 public fuseIntervalStart = 0;\n /// @notice end of fuse interval\n uint256 public fuseIntervalEnd = 0;\n\n uint256[50] 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 constructor(\n address _wethAddress,\n address _vaultAddress,\n address _beaconChainDepositContract,\n address _ssvNetwork\n )\n ValidatorRegistrator(\n _wethAddress,\n _vaultAddress,\n _beaconChainDepositContract,\n _ssvNetwork\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 _fuseIntervalStart < 32 ether &&\n _fuseIntervalEnd < 32 ether &&\n _fuseIntervalEnd - _fuseIntervalStart >= 4 ether,\n \"incorrect fuse interval\"\n );\n\n emit FuseIntervalUpdated(_fuseIntervalStart, _fuseIntervalEnd);\n\n fuseIntervalStart = _fuseIntervalStart;\n fuseIntervalEnd = _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 returns (bool accountingValid)\n {\n // pause the accounting on failure\n accountingValid = _doAccounting(true);\n }\n\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 >= MAX_STAKE) {\n uint256 fullyWithdrawnValidators = newSweptETH / MAX_STAKE;\n if (activeDepositedValidators < fullyWithdrawnValidators) {\n return _failAccounting(pauseOnFail);\n }\n activeDepositedValidators -= fullyWithdrawnValidators;\n\n uint256 wethToVault = MAX_STAKE * fullyWithdrawnValidators;\n IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: wethToVault }();\n IWETH9(WETH_TOKEN_ADDRESS).transfer(VAULT_ADDRESS, 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 < 32 ether, \"unexpected accounting\");\n\n // If no Beacon chain consensus rewards swept\n if (ethRemaining == 0) {\n // do nothing\n return accountingValid;\n }\n // Beacon chain consensus rewards swept (partial validator withdrawals)\n else if (ethRemaining < fuseIntervalStart) {\n // solhint-disable-next-line reentrancy\n consensusRewards += ethRemaining;\n emit AccountingConsensusRewards(ethRemaining);\n }\n // Beacon chain consensus rewards swept but also a slashed validator fully exited\n else if (ethRemaining > fuseIntervalEnd) {\n IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: ethRemaining }();\n IWETH9(WETH_TOKEN_ADDRESS).transfer(VAULT_ADDRESS, ethRemaining);\n activeDepositedValidators -= 1;\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 /// @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 plus one, minus one or unchanged with zero\n /// @param _wethToVaultAmount the amount of WETH to be sent to the Vault\n /// @param _consensusRewardsDelta adjust the accounted for consensus rewards up or down\n function manuallyFixAccounting(\n int256 _validatorsDelta,\n int256 _consensusRewardsDelta,\n uint256 _wethToVaultAmount\n ) external onlyStrategist whenPaused {\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(_wethToVaultAmount <= 32 ether, \"invalid wethToVaultAmount\");\n\n emit AccountingManuallyFixed(\n _validatorsDelta,\n _consensusRewardsDelta,\n _wethToVaultAmount\n );\n\n activeDepositedValidators = uint256(\n int256(activeDepositedValidators) + _validatorsDelta\n );\n consensusRewards = uint256(\n int256(consensusRewards) + _consensusRewardsDelta\n );\n if (_wethToVaultAmount > 0) {\n IWETH9(WETH_TOKEN_ADDRESS).transfer(\n VAULT_ADDRESS,\n _wethToVaultAmount\n );\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" + }, + "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 address of the Wrapped ETH (WETH) token contract\n address public immutable WETH_TOKEN_ADDRESS;\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_ADDRESS;\n /// @notice Address of the OETH Vault proxy contract\n address public immutable VAULT_ADDRESS;\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\n // For future use\n uint256[50] private __gap;\n\n enum VALIDATOR_STATE {\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 newAddress);\n event ETHStaked(bytes pubkey, uint256 amount, bytes withdrawal_credentials);\n event SSVValidatorRegistered(bytes pubkey, uint64[] operatorIds);\n event SSVValidatorExitInitiated(bytes pubkey, uint64[] operatorIds);\n event SSVValidatorExitCompleted(bytes pubkey, uint64[] operatorIds);\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 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 constructor(\n address _wethAddress,\n address _vaultAddress,\n address _beaconChainDepositContract,\n address _ssvNetwork\n ) {\n WETH_TOKEN_ADDRESS = _wethAddress;\n BEACON_CHAIN_DEPOSIT_CONTRACT = _beaconChainDepositContract;\n SSV_NETWORK_ADDRESS = _ssvNetwork;\n VAULT_ADDRESS = _vaultAddress;\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 emit RegistratorChanged(_address);\n validatorRegistrator = _address;\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 function stakeEth(ValidatorStakeData[] calldata validators)\n external\n onlyRegistrator\n whenNotPaused\n {\n uint256 requiredETH = validators.length * 32 ether;\n\n // Check there is enough WETH from the deposits sitting in this strategy contract\n require(\n requiredETH <= IWETH9(WETH_TOKEN_ADDRESS).balanceOf(address(this)),\n \"insufficient WETH\"\n );\n\n // Convert required ETH from WETH\n IWETH9(WETH_TOKEN_ADDRESS).withdraw(requiredETH);\n\n // For each validator\n for (uint256 i = 0; i < validators.length; ) {\n bytes32 pubkeyHash = keccak256(validators[i].pubkey);\n VALIDATOR_STATE currentState = validatorsStates[pubkeyHash];\n\n require(\n currentState == VALIDATOR_STATE.REGISTERED,\n \"Validator not registered\"\n );\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 withdrawal_credentials = abi.encodePacked(\n bytes1(0x01),\n bytes11(0),\n address(this)\n );\n IDepositContract(BEACON_CHAIN_DEPOSIT_CONTRACT).deposit{\n value: 32 ether\n }(\n validators[i].pubkey,\n withdrawal_credentials,\n validators[i].signature,\n validators[i].depositDataRoot\n );\n\n activeDepositedValidators += 1;\n emit ETHStaked(\n validators[i].pubkey,\n 32 ether,\n withdrawal_credentials\n );\n\n validatorsStates[pubkeyHash] = VALIDATOR_STATE.STAKED;\n\n unchecked {\n ++i;\n }\n }\n }\n\n /// @notice Registers a new validator in the SSV Cluster.\n /// Only the registrator can call this function.\n function registerSsvValidator(\n bytes calldata publicKey,\n uint64[] calldata operatorIds,\n bytes calldata sharesData,\n uint256 amount,\n Cluster calldata cluster\n ) external onlyRegistrator whenNotPaused {\n ISSVNetwork(SSV_NETWORK_ADDRESS).registerValidator(\n publicKey,\n operatorIds,\n sharesData,\n amount,\n cluster\n );\n validatorsStates[keccak256(publicKey)] = VALIDATOR_STATE.REGISTERED;\n emit SSVValidatorRegistered(publicKey, operatorIds);\n }\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 function exitSsvValidator(\n bytes calldata publicKey,\n uint64[] calldata operatorIds\n ) external onlyRegistrator whenNotPaused {\n VALIDATOR_STATE currentState = validatorsStates[keccak256(publicKey)];\n require(currentState == VALIDATOR_STATE.STAKED, \"Validator not staked\");\n\n ISSVNetwork(SSV_NETWORK_ADDRESS).exitValidator(publicKey, operatorIds);\n emit SSVValidatorExitInitiated(publicKey, operatorIds);\n\n validatorsStates[keccak256(publicKey)] = VALIDATOR_STATE.EXITING;\n }\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 function removeSsvValidator(\n bytes calldata publicKey,\n uint64[] calldata operatorIds,\n Cluster calldata cluster\n ) external onlyRegistrator whenNotPaused {\n VALIDATOR_STATE currentState = validatorsStates[keccak256(publicKey)];\n require(\n currentState == VALIDATOR_STATE.EXITING,\n \"Validator not exiting\"\n );\n\n ISSVNetwork(SSV_NETWORK_ADDRESS).removeValidator(\n publicKey,\n operatorIds,\n cluster\n );\n emit SSVValidatorExitCompleted(publicKey, operatorIds);\n\n validatorsStates[keccak256(publicKey)] = VALIDATOR_STATE.EXIT_COMPLETE;\n }\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 cluster The SSV cluster details that must be derived from emitted events from the SSVNetwork contract.\n function depositSSV(\n uint64[] memory operatorIds,\n uint256 amount,\n Cluster memory cluster\n ) external onlyStrategist {\n ISSVNetwork(SSV_NETWORK_ADDRESS).deposit(\n address(this),\n operatorIds,\n amount,\n cluster\n );\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/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/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" + } + }, + "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/test/behaviour/ssvStrategy.js b/contracts/test/behaviour/ssvStrategy.js index a28d47294e..f11ef2cf02 100644 --- a/contracts/test/behaviour/ssvStrategy.js +++ b/contracts/test/behaviour/ssvStrategy.js @@ -410,7 +410,12 @@ const shouldBehaveLikeAnSsvStrategy = (context) => { // add some ETH to the FeeAccumulator to simulate execution rewards const executionRewards = parseEther("7"); - await setBalance(nativeStakingFeeAccumulator.address, executionRewards); + //await setBalance(nativeStakingFeeAccumulator.address, executionRewards); + await josh.sendTransaction({ + to: nativeStakingFeeAccumulator.address, + value: executionRewards, + }); + // simulate consensus rewards const consensusRewards = parseEther("5"); await setBalance(nativeStakingSSVStrategy.address, consensusRewards); From f26874225c8e904a2a709b263eea979122e47a53 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Fri, 10 May 2024 08:35:06 +1000 Subject: [PATCH 038/273] fix linter --- contracts/deploy/deployActions.js | 3 +-- contracts/deploy/holesky/006_update_registrator.js | 3 --- contracts/deploy/holesky/007_upgrade_strategy.js | 1 - 3 files changed, 1 insertion(+), 6 deletions(-) diff --git a/contracts/deploy/deployActions.js b/contracts/deploy/deployActions.js index b4849c14c3..7b2f41a71b 100644 --- a/contracts/deploy/deployActions.js +++ b/contracts/deploy/deployActions.js @@ -584,8 +584,7 @@ const deployOETHHarvester = async (oethDripper) => { await withConfirmation( // prettier-ignore - cOETHHarvesterProxy - ["initialize(address,address,bytes)"]( + cOETHHarvesterProxy["initialize(address,address,bytes)"]( dOETHHarvester.address, governorAddr, [] diff --git a/contracts/deploy/holesky/006_update_registrator.js b/contracts/deploy/holesky/006_update_registrator.js index c14bc8dcd3..0ae5784138 100644 --- a/contracts/deploy/holesky/006_update_registrator.js +++ b/contracts/deploy/holesky/006_update_registrator.js @@ -1,6 +1,3 @@ -const { parseEther } = require("ethers/lib/utils"); - -const { deployNativeStakingSSVStrategy } = require("../deployActions"); const { withConfirmation } = require("../../utils/deploy"); const { resolveContract } = require("../../utils/resolvers"); const addresses = require("../../utils/addresses"); diff --git a/contracts/deploy/holesky/007_upgrade_strategy.js b/contracts/deploy/holesky/007_upgrade_strategy.js index 0d1373b3b3..8a7ba86edb 100644 --- a/contracts/deploy/holesky/007_upgrade_strategy.js +++ b/contracts/deploy/holesky/007_upgrade_strategy.js @@ -2,7 +2,6 @@ const { upgradeNativeStakingSSVStrategy, upgradeNativeStakingFeeAccumulator, } = require("../deployActions"); -const { withConfirmation } = require("../../utils/deploy"); const mainExport = async () => { console.log("Running 007 deployment on Holesky..."); From 20d29a180057562e5f12e5fece4d51407ed613a4 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Fri, 10 May 2024 10:12:16 +1000 Subject: [PATCH 039/273] Fix balancer fork test --- .../strategies/balancerMetaStablePool.fork-test.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/contracts/test/strategies/balancerMetaStablePool.fork-test.js b/contracts/test/strategies/balancerMetaStablePool.fork-test.js index 5aeb7d6ce8..6ca919b81c 100644 --- a/contracts/test/strategies/balancerMetaStablePool.fork-test.js +++ b/contracts/test/strategies/balancerMetaStablePool.fork-test.js @@ -170,6 +170,9 @@ describe("ForkTest: Balancer MetaStablePool rETH/WETH Strategy", function () { describe("Deposit", function () { beforeEach(async () => { fixture = await loadBalancerREthFixtureNotDefault(); + const { oethVault, josh, reth } = fixture; + + await reth.connect(josh).transfer(oethVault.address, oethUnits("32")); }); it("Should deposit 5 WETH and 5 rETH in Balancer MetaStablePool strategy", async function () { const { reth, rEthBPT, weth } = fixture; @@ -267,9 +270,11 @@ describe("ForkTest: Balancer MetaStablePool rETH/WETH Strategy", function () { describe("Withdraw", function () { beforeEach(async () => { fixture = await loadBalancerREthFixtureNotDefault(); - const { balancerREthStrategy, oethVault, strategist, reth, weth } = + const { balancerREthStrategy, oethVault, josh, strategist, reth, weth } = fixture; + await reth.connect(josh).transfer(oethVault.address, oethUnits("32")); + await oethVault .connect(strategist) .depositToStrategy( @@ -543,8 +548,11 @@ describe("ForkTest: Balancer MetaStablePool rETH/WETH Strategy", function () { describe("Harvest rewards", function () { beforeEach(async () => { fixture = await loadBalancerREthFixtureDefault(); - }); + const { oethVault, josh, reth } = fixture; + + await reth.connect(josh).transfer(oethVault.address, oethUnits("32")); + }); it("Should be able to collect reward tokens", async function () { const { weth, From b8988011928ba9eb5d35b008e997d18dfca75208 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Fri, 10 May 2024 14:19:50 +1000 Subject: [PATCH 040/273] Fixed resolveContract for none proxied contracts --- contracts/utils/resolvers.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/utils/resolvers.js b/contracts/utils/resolvers.js index 5791420874..b47f5b229e 100644 --- a/contracts/utils/resolvers.js +++ b/contracts/utils/resolvers.js @@ -82,7 +82,7 @@ const resolveContract = async (proxy, abiName) => { return contract; } - return proxy; + return proxyContract; }; module.exports = { From 25170aafacbd004f5114976fdd02d397cfe487d9 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Fri, 10 May 2024 14:20:25 +1000 Subject: [PATCH 041/273] simplified woethCcipZapperFixture --- contracts/test/_fixture.js | 50 ++++++-------------------------------- 1 file changed, 7 insertions(+), 43 deletions(-) diff --git a/contracts/test/_fixture.js b/contracts/test/_fixture.js index 5b4881458c..0583a6e100 100644 --- a/contracts/test/_fixture.js +++ b/contracts/test/_fixture.js @@ -9,11 +9,12 @@ require("./_global-hooks"); const { hotDeployOption } = require("./_hot-deploy.js"); const addresses = require("../utils/addresses"); const { setFraxOraclePrice } = require("../utils/frax"); +const { resolveContract } = require("../utils/resolvers"); //const { setChainlinkOraclePrice } = require("../utils/oracle"); + const { balancer_rETH_WETH_PID, balancer_stETH_WETH_PID, - ccip_arbChainSelector, } = require("../utils/constants"); const { fundAccounts, @@ -2363,48 +2364,11 @@ async function harvesterFixture() { } async function woethCcipZapperFixture() { - let fixture = {}; - let woethZapper; - let oethZapper; - let destinationChainSelector = ccip_arbChainSelector; - let woethOnSourceChain = addresses.mainnet.WOETHProxy; - let woethOnDestinationChain = addresses.arbitrumOne.WOETHProxy; - - oethZapper = await ethers.getContractAt( - "OETHZapper", - addresses.mainnet.OETHZapper - ); - - const ccipRouter = await ethers.getContractAt( - "IRouterClient", - addresses.mainnet.ccipRouterMainnet - ); - - const WOETHZapper = await ethers.getContractFactory("WOETHCCIPZapper"); - woethZapper = await WOETHZapper.deploy( - ccipRouter.address, - destinationChainSelector, - woethOnSourceChain, - woethOnDestinationChain, - oethZapper.address, - addresses.mainnet.OETHProxy - ); - await woethZapper.deployed(); - woethOnSourceChain = await ethers.getContractAt( - "WOETH", - addresses.mainnet.WOETHProxy - ); - - fixture.oethZapper = oethZapper; - fixture.woethOnSourceChain = woethOnSourceChain; - fixture.woethZapper = woethZapper; - fixture.ccipRouter = ccipRouter; - - const [josh, alice] = await ethers.getSigners(); - await impersonateAndFund(josh.address, "10"); + const fixture = await defaultFixture(); - fixture.josh = josh; - fixture.alice = alice; + fixture.oethZapper = await resolveContract("OETHZapper"); + fixture.woethOnSourceChain = await resolveContract("WOETHProxy", "WOETH"); + fixture.woethZapper = await resolveContract("WOETHCCIPZapper"); return fixture; } @@ -2412,7 +2376,7 @@ async function woethCcipZapperFixture() { /** * A fixture is a setup function that is run only the first time it's invoked. On subsequent invocations, * Hardhat will reset the state of the network to what it was at the point after the fixture was initially executed. - * The returned `loadFixture` function is typically inlcuded in the beforeEach(). + * The returned `loadFixture` function is typically included in the beforeEach(). * @example * const loadFixture = createFixtureLoader(convexOETHMetaVaultFixture); * beforeEach(async () => { From e1ff7284e8c185dce8d85b9e90c0d21f370f4ba6 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Fri, 10 May 2024 15:20:42 +1000 Subject: [PATCH 042/273] Regenerated latest contract diagrams --- contracts/docs/FeeAccumulatorHierarchy.svg | 8 +- contracts/docs/FeeAccumulatorSquashed.svg | 53 ++++---- .../NativeStakingSSVStrategyHierarchy.svg | 72 +++++----- .../docs/NativeStakingSSVStrategySquashed.svg | 123 +++++++++--------- 4 files changed, 129 insertions(+), 127 deletions(-) diff --git a/contracts/docs/FeeAccumulatorHierarchy.svg b/contracts/docs/FeeAccumulatorHierarchy.svg index 3ddcdb22a3..cfda7c9b49 100644 --- a/contracts/docs/FeeAccumulatorHierarchy.svg +++ b/contracts/docs/FeeAccumulatorHierarchy.svg @@ -16,16 +16,16 @@ Governable ../contracts/governance/Governable.sol - + -279 +282 FeeAccumulator ../contracts/strategies/NativeStaking/FeeAccumulator.sol - + -279->20 +282->20 diff --git a/contracts/docs/FeeAccumulatorSquashed.svg b/contracts/docs/FeeAccumulatorSquashed.svg index c41be6097f..751660ae8d 100644 --- a/contracts/docs/FeeAccumulatorSquashed.svg +++ b/contracts/docs/FeeAccumulatorSquashed.svg @@ -4,34 +4,35 @@ - - + + UmlClassDiagram - - + + -278 - -FeeAccumulator -../contracts/strategies/NativeStaking/FeeAccumulator.sol - -Private: -   governorPosition: bytes32 <<Governable>> -   pendingGovernorPosition: bytes32 <<Governable>> -   reentryStatusPosition: bytes32 <<Governable>> -Public: -   _NOT_ENTERED: uint256 <<Governable>> -   _ENTERED: uint256 <<Governable>> -   STRATEGY: address <<FeeAccumulator>> - -Internal: -    _governor(): (governorOut: address) <<Governable>> -    _pendingGovernor(): (pendingGovernor: address) <<Governable>> -    _setGovernor(newGovernor: address) <<Governable>> -    _setPendingGovernor(newGovernor: address) <<Governable>> -    _changeGovernor(_newGovernor: address) <<Governable>> -External: +282 + +FeeAccumulator +../contracts/strategies/NativeStaking/FeeAccumulator.sol + +Private: +   governorPosition: bytes32 <<Governable>> +   pendingGovernorPosition: bytes32 <<Governable>> +   reentryStatusPosition: bytes32 <<Governable>> +Public: +   _NOT_ENTERED: uint256 <<Governable>> +   _ENTERED: uint256 <<Governable>> +   STRATEGY: address <<FeeAccumulator>> + +Internal: +    _governor(): (governorOut: address) <<Governable>> +    _pendingGovernor(): (pendingGovernor: address) <<Governable>> +    _setGovernor(newGovernor: address) <<Governable>> +    _setPendingGovernor(newGovernor: address) <<Governable>> +    _changeGovernor(_newGovernor: address) <<Governable>> +External: +    <<payable>> null() <<FeeAccumulator>>    transferGovernance(_newGovernor: address) <<onlyGovernor>> <<Governable>>    claimGovernance() <<Governable>>    collect(): (eth: uint256) <<FeeAccumulator>> diff --git a/contracts/docs/NativeStakingSSVStrategyHierarchy.svg b/contracts/docs/NativeStakingSSVStrategyHierarchy.svg index 0686fa8c78..9b26343942 100644 --- a/contracts/docs/NativeStakingSSVStrategyHierarchy.svg +++ b/contracts/docs/NativeStakingSSVStrategyHierarchy.svg @@ -16,125 +16,125 @@ Governable ../contracts/governance/Governable.sol - + -278 +282 FeeAccumulator ../contracts/strategies/NativeStaking/FeeAccumulator.sol - + -278->20 +282->20 - + -280 +284 NativeStakingSSVStrategy ../contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol - + -280->278 +284->282 - + -281 +285 <<Abstract>> ValidatorAccountant ../contracts/strategies/NativeStaking/ValidatorAccountant.sol - + -280->281 +284->285 - + -210 +213 <<Abstract>> InitializableAbstractStrategy ../contracts/utils/InitializableAbstractStrategy.sol - + -280->210 +284->213 - + -283 +287 <<Abstract>> ValidatorRegistrator ../contracts/strategies/NativeStaking/ValidatorRegistrator.sol - + -281->283 +285->287 - + -283->20 +287->20 - + -340 +344 <<Abstract>> Pausable ../node_modules/@openzeppelin/contracts/security/Pausable.sol - + -283->340 +287->344 - + -209 +212 <<Abstract>> Initializable ../contracts/utils/Initializable.sol - + -210->20 +213->20 - + -210->209 +213->212 - + -345 +349 <<Abstract>> Context ../node_modules/@openzeppelin/contracts/utils/Context.sol - + -340->345 +344->349 diff --git a/contracts/docs/NativeStakingSSVStrategySquashed.svg b/contracts/docs/NativeStakingSSVStrategySquashed.svg index e66ffdaf08..22da401020 100644 --- a/contracts/docs/NativeStakingSSVStrategySquashed.svg +++ b/contracts/docs/NativeStakingSSVStrategySquashed.svg @@ -4,69 +4,70 @@ - - + + UmlClassDiagram - - + + -280 - -NativeStakingSSVStrategy -../contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol - -Private: -   governorPosition: bytes32 <<Governable>> -   pendingGovernorPosition: bytes32 <<Governable>> -   reentryStatusPosition: bytes32 <<Governable>> -   _paused: bool <<Pausable>> -   __gap: uint256[50] <<ValidatorRegistrator>> -   __gap: uint256[50] <<ValidatorAccountant>> -   initialized: bool <<Initializable>> -   initializing: bool <<Initializable>> -   ______gap: uint256[50] <<Initializable>> -   _deprecated_platformAddress: address <<InitializableAbstractStrategy>> -   _deprecated_vaultAddress: address <<InitializableAbstractStrategy>> -   _deprecated_rewardTokenAddress: address <<InitializableAbstractStrategy>> -   _deprecated_rewardLiquidationThreshold: uint256 <<InitializableAbstractStrategy>> -   _reserved: int256[98] <<InitializableAbstractStrategy>> -   __gap: uint256[50] <<NativeStakingSSVStrategy>> -Internal: -   assetsMapped: address[] <<InitializableAbstractStrategy>> -Public: -   _NOT_ENTERED: uint256 <<Governable>> -   _ENTERED: uint256 <<Governable>> -   WETH_TOKEN_ADDRESS: address <<ValidatorRegistrator>> -   BEACON_CHAIN_DEPOSIT_CONTRACT: address <<ValidatorRegistrator>> -   SSV_NETWORK_ADDRESS: address <<ValidatorRegistrator>> -   VAULT_ADDRESS: address <<ValidatorRegistrator>> -   validatorRegistrator: address <<ValidatorRegistrator>> -   activeDepositedValidators: uint256 <<ValidatorRegistrator>> -   validatorsStates: mapping(bytes32=>VALIDATOR_STATE) <<ValidatorRegistrator>> -   MAX_STAKE: uint256 <<ValidatorAccountant>> -   consensusRewards: uint256 <<ValidatorAccountant>> -   fuseIntervalStart: uint256 <<ValidatorAccountant>> -   fuseIntervalEnd: uint256 <<ValidatorAccountant>> -   platformAddress: address <<InitializableAbstractStrategy>> -   vaultAddress: address <<InitializableAbstractStrategy>> -   assetToPToken: mapping(address=>address) <<InitializableAbstractStrategy>> -   harvesterAddress: address <<InitializableAbstractStrategy>> -   rewardTokenAddresses: address[] <<InitializableAbstractStrategy>> -   SSV_TOKEN_ADDRESS: address <<NativeStakingSSVStrategy>> -   FEE_ACCUMULATOR_ADDRESS: address <<NativeStakingSSVStrategy>> - -Internal: -    _governor(): (governorOut: address) <<Governable>> -    _pendingGovernor(): (pendingGovernor: address) <<Governable>> -    _setGovernor(newGovernor: address) <<Governable>> -    _setPendingGovernor(newGovernor: address) <<Governable>> -    _changeGovernor(_newGovernor: address) <<Governable>> -    _msgSender(): address <<Context>> -    _msgData(): bytes <<Context>> -    _pause() <<whenNotPaused>> <<Pausable>> -    _unpause() <<whenPaused>> <<Pausable>> -    _doAccounting(pauseOnFail: bool): (accountingValid: bool) <<ValidatorAccountant>> +284 + +NativeStakingSSVStrategy +../contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol + +Private: +   governorPosition: bytes32 <<Governable>> +   pendingGovernorPosition: bytes32 <<Governable>> +   reentryStatusPosition: bytes32 <<Governable>> +   _paused: bool <<Pausable>> +   __gap: uint256[50] <<ValidatorRegistrator>> +   __gap: uint256[50] <<ValidatorAccountant>> +   initialized: bool <<Initializable>> +   initializing: bool <<Initializable>> +   ______gap: uint256[50] <<Initializable>> +   _deprecated_platformAddress: address <<InitializableAbstractStrategy>> +   _deprecated_vaultAddress: address <<InitializableAbstractStrategy>> +   _deprecated_rewardTokenAddress: address <<InitializableAbstractStrategy>> +   _deprecated_rewardLiquidationThreshold: uint256 <<InitializableAbstractStrategy>> +   _reserved: int256[98] <<InitializableAbstractStrategy>> +   __gap: uint256[50] <<NativeStakingSSVStrategy>> +Internal: +   assetsMapped: address[] <<InitializableAbstractStrategy>> +Public: +   _NOT_ENTERED: uint256 <<Governable>> +   _ENTERED: uint256 <<Governable>> +   WETH_TOKEN_ADDRESS: address <<ValidatorRegistrator>> +   BEACON_CHAIN_DEPOSIT_CONTRACT: address <<ValidatorRegistrator>> +   SSV_NETWORK_ADDRESS: address <<ValidatorRegistrator>> +   VAULT_ADDRESS: address <<ValidatorRegistrator>> +   validatorRegistrator: address <<ValidatorRegistrator>> +   activeDepositedValidators: uint256 <<ValidatorRegistrator>> +   validatorsStates: mapping(bytes32=>VALIDATOR_STATE) <<ValidatorRegistrator>> +   MAX_STAKE: uint256 <<ValidatorAccountant>> +   consensusRewards: uint256 <<ValidatorAccountant>> +   fuseIntervalStart: uint256 <<ValidatorAccountant>> +   fuseIntervalEnd: uint256 <<ValidatorAccountant>> +   platformAddress: address <<InitializableAbstractStrategy>> +   vaultAddress: address <<InitializableAbstractStrategy>> +   assetToPToken: mapping(address=>address) <<InitializableAbstractStrategy>> +   harvesterAddress: address <<InitializableAbstractStrategy>> +   rewardTokenAddresses: address[] <<InitializableAbstractStrategy>> +   SSV_TOKEN_ADDRESS: address <<NativeStakingSSVStrategy>> +   FEE_ACCUMULATOR_ADDRESS: address <<NativeStakingSSVStrategy>> + +Internal: +    _governor(): (governorOut: address) <<Governable>> +    _pendingGovernor(): (pendingGovernor: address) <<Governable>> +    _setGovernor(newGovernor: address) <<Governable>> +    _setPendingGovernor(newGovernor: address) <<Governable>> +    _changeGovernor(_newGovernor: address) <<Governable>> +    _msgSender(): address <<Context>> +    _msgData(): bytes <<Context>> +    _pause() <<whenNotPaused>> <<Pausable>> +    _unpause() <<whenPaused>> <<Pausable>> +    _doAccounting(pauseOnFail: bool): (accountingValid: bool) <<ValidatorAccountant>> +    _failAccounting(pauseOnFail: bool): (accountingValid: bool) <<ValidatorAccountant>>    _initialize(_rewardTokenAddresses: address[], _assets: address[], _pTokens: address[]) <<InitializableAbstractStrategy>>    _collectRewardTokens() <<whenNotPaused>> <<NativeStakingSSVStrategy>>    _setPTokenAddress(_asset: address, _pToken: address) <<InitializableAbstractStrategy>> From c09cd468c69ae74f6a8b96afb7772a94f1a57cf9 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Fri, 10 May 2024 15:51:12 +1000 Subject: [PATCH 043/273] Resolved Slither divide-before-multiply warning --- .../contracts/strategies/NativeStaking/ValidatorAccountant.sol | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol b/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol index 0be35263bf..fa70b61290 100644 --- a/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol +++ b/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol @@ -116,7 +116,8 @@ abstract contract ValidatorAccountant is ValidatorRegistrator { // send the ETH that is from fully withdrawn validators to the Vault if (newSweptETH >= MAX_STAKE) { - uint256 fullyWithdrawnValidators = newSweptETH / MAX_STAKE; + // explicitly cast to uint256 as we want to round to a whole number of validators + uint256 fullyWithdrawnValidators = uint256(newSweptETH / MAX_STAKE); if (activeDepositedValidators < fullyWithdrawnValidators) { return _failAccounting(pauseOnFail); } From 9d83e97e0960387f308a705883e254351fa739e0 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Fri, 10 May 2024 16:47:23 +1000 Subject: [PATCH 044/273] Native staking deployment to reduceQueueTime --- ...91_native_ssv_staking.js => 096_native_ssv_staking.js} | 1 + contracts/test/_fixture.js | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) rename contracts/deploy/mainnet/{091_native_ssv_staking.js => 096_native_ssv_staking.js} (99%) diff --git a/contracts/deploy/mainnet/091_native_ssv_staking.js b/contracts/deploy/mainnet/096_native_ssv_staking.js similarity index 99% rename from contracts/deploy/mainnet/091_native_ssv_staking.js rename to contracts/deploy/mainnet/096_native_ssv_staking.js index 689853af98..63bfbdaaae 100644 --- a/contracts/deploy/mainnet/091_native_ssv_staking.js +++ b/contracts/deploy/mainnet/096_native_ssv_staking.js @@ -6,6 +6,7 @@ module.exports = deploymentWithGovernanceProposal( deployName: "091_native_ssv_staking", forceDeploy: false, //forceSkip: true, + reduceQueueTime: true, deployerIsProposer: false, // proposalId: }, diff --git a/contracts/test/_fixture.js b/contracts/test/_fixture.js index 0583a6e100..a99294e146 100644 --- a/contracts/test/_fixture.js +++ b/contracts/test/_fixture.js @@ -2364,12 +2364,18 @@ async function harvesterFixture() { } async function woethCcipZapperFixture() { - const fixture = await defaultFixture(); + const fixture = {}; fixture.oethZapper = await resolveContract("OETHZapper"); fixture.woethOnSourceChain = await resolveContract("WOETHProxy", "WOETH"); fixture.woethZapper = await resolveContract("WOETHCCIPZapper"); + const [josh, alice] = await ethers.getSigners(); + await impersonateAndFund(josh.address, "10"); + + fixture.josh = josh; + fixture.alice = alice; + return fixture; } From 7eb135b60b494427a510540348ede9ddd7eec42a Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Fri, 10 May 2024 17:05:41 +1000 Subject: [PATCH 045/273] Fixed fork test harvesting CRV rewards --- contracts/test/strategies/oeth-metapool.fork-test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/test/strategies/oeth-metapool.fork-test.js b/contracts/test/strategies/oeth-metapool.fork-test.js index e19ed0c0f6..001d491fa7 100644 --- a/contracts/test/strategies/oeth-metapool.fork-test.js +++ b/contracts/test/strategies/oeth-metapool.fork-test.js @@ -94,7 +94,7 @@ describe("ForkTest: OETH AMO Curve Metapool Strategy", function () { ); await oethVault.connect(josh).rebase(); - await expect(wethDiff).to.be.gte(parseUnits("0.2")); + await expect(wethDiff).to.be.gte(parseUnits("0.1")); }); it("Only Governor can approve all tokens", async () => { const { From 579a93c6c06d03fc439031959b60025148c2a348 Mon Sep 17 00:00:00 2001 From: Domen Grabec Date: Fri, 10 May 2024 10:56:32 +0200 Subject: [PATCH 046/273] gas optimisation --- .../strategies/NativeStaking/ValidatorAccountant.sol | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol b/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol index fa70b61290..aebdb0a662 100644 --- a/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol +++ b/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol @@ -116,10 +116,11 @@ abstract contract ValidatorAccountant is ValidatorRegistrator { // send the ETH that is from fully withdrawn validators to the Vault if (newSweptETH >= MAX_STAKE) { - // explicitly cast to uint256 as we want to round to a whole number of validators - uint256 fullyWithdrawnValidators = uint256(newSweptETH / MAX_STAKE); - if (activeDepositedValidators < fullyWithdrawnValidators) { - return _failAccounting(pauseOnFail); + uint256 fullyWithdrawnValidators; + // safe since MAX_STAKE is hardcoded to 32ETH + unchecked { + // explicitly cast to uint256 as we want to round to a whole number of validators + fullyWithdrawnValidators = uint256(newSweptETH / MAX_STAKE); } activeDepositedValidators -= fullyWithdrawnValidators; From e7b96e9ea812761fb75f1cbe8bc5f2b03a1fae0f Mon Sep 17 00:00:00 2001 From: Domen Grabec Date: Fri, 10 May 2024 13:35:47 +0200 Subject: [PATCH 047/273] make verification automatic --- .../deploy/verifySimpleOETHDeployment.sh | 58 +++++++++++-------- 1 file changed, 35 insertions(+), 23 deletions(-) diff --git a/contracts/scripts/deploy/verifySimpleOETHDeployment.sh b/contracts/scripts/deploy/verifySimpleOETHDeployment.sh index 7fc14add36..8033c5ae97 100755 --- a/contracts/scripts/deploy/verifySimpleOETHDeployment.sh +++ b/contracts/scripts/deploy/verifySimpleOETHDeployment.sh @@ -1,30 +1,42 @@ #!/bin/bash -export OETH_VAULT=0xa7191fEE1Ed313908FCb09D09b82ABB7BC56F71B -export OETH_VAULT_PROXY=0x19d2bAaBA949eFfa163bFB9efB53ed8701aA5dD9 -export OETH_VAULT_CORE=0xE92e25B81E44B8377Df1362f8fFBc426A00d6ef4 -export OETH_VAULT_ADMIN=0xa94c4aab0Cf9f6E79bB064DB145fBe2506b9Fa75 -export OETH_PROXY=0xB1876706d2402d300bf263F9e53335CEFc53d9Cb -export OETH=0x7909c19E355E95043e277e76Dd6680fE899F61D6 -export FEE_ACC=0x79681d3f14a0068479420eE5fDdF59B62301f810 -export FEE_ACC_PROXY=0x590B781b511e953dbFC49e7E7864A6E787aFBDCc -export OETH_DRIPPER=0x3833C32826A7f2a93C48D50ae44D45F45Ab17B7F -export OETH_DRIPPER_PROXY=0xaFF1E6263F4004C95Ae611DEb2ADaC049B5aD121 -export OETH_HARVESTER=0xBd09F938259AE61e089959d52580235b76C69A83 -export OETH_HARVESTER_PROXY=0xB7491cdf36367C89001cc41312F22f63A3a17931 -export OETH_ORACLE_ROUTER=0x7e2bf9A89180f20591EcFA42C0dd7e52b2C546E3 -export NATIVE_STAKING=0x51766Fd366D6C9121F6Aeec20267ecA87c2c9793 -export NATIVE_STAKING_PROXY=0x4Eac8847c7AE50e3A3551B1Aa4FF7Cc162151410 -export WETH=0x94373a4919b3240d86ea41593d5eba789fef3848 -export ZERO=0x0000000000000000000000000000000000000000 -export SSV=0xad45A78180961079BFaeEe349704F411dfF947C6 -export SSVNetwork=0x38A4794cCEd47d3baf7370CcC43B560D3a1beEFA -export beaconChainDepositContract=0x4242424242424242424242424242424242424242 +export NETWORK=holesky +# TODO: fetch these addresses from deployment files +export OETH_VAULT=$(jq -r ".address" deployments/$NETWORK/OETHVault.json) +export OETH_VAULT_PROXY=$(jq -r ".address" deployments/$NETWORK/OETHVaultProxy.json) +export OETH_VAULT_CORE=$(jq -r ".address" deployments/$NETWORK/OETHVaultCore.json) +export OETH_VAULT_ADMIN=$(jq -r ".address" deployments/$NETWORK/OETHVaultAdmin.json) +export OETH_PROXY=$(jq -r ".address" deployments/$NETWORK/OETHProxy.json) +export OETH=$(jq -r ".address" deployments/$NETWORK/OETH.json) +export FEE_ACC=$(jq -r ".address" deployments/$NETWORK/FeeAccumulator.json) +export FEE_ACC_PROXY=$(jq -r ".address" deployments/$NETWORK/NativeStakingFeeAccumulatorProxy.json) +export OETH_DRIPPER=$(jq -r ".address" deployments/$NETWORK/OETHDripper.json) +export OETH_DRIPPER_PROXY=$(jq -r ".address" deployments/$NETWORK/OETHDripperProxy.json) +export OETH_HARVESTER=$(jq -r ".address" deployments/$NETWORK/OETHHarvesterProxy.json) +export OETH_HARVESTER_PROXY=$(jq -r ".address" deployments/$NETWORK/OETHHarvester.json) +export OETH_ORACLE_ROUTER=$(jq -r ".address" deployments/$NETWORK/OETHOracleRouter.json) +export NATIVE_STAKING=$(jq -r ".address" deployments/$NETWORK/NativeStakingSSVStrategy.json) +export NATIVE_STAKING_PROXY=$(jq -r ".address" deployments/$NETWORK/NativeStakingSSVStrategyProxy.json) + +if [ NETWORK="holesky" ]; then + export WETH=0x94373a4919b3240d86ea41593d5eba789fef3848 + export ZERO=0x0000000000000000000000000000000000000000 + export SSV=0xad45A78180961079BFaeEe349704F411dfF947C6 + export SSVNetwork=0x38A4794cCEd47d3baf7370CcC43B560D3a1beEFA + export beaconChainDepositContract=0x4242424242424242424242424242424242424242 +# else mainnet +else + export WETH=0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 + export ZERO=0x0000000000000000000000000000000000000000 + export SSV=0x9D65fF81a3c488d585bBfb0Bfe3c7707c7917f54 + export SSVNetwork=0xDD9BC35aE942eF0cFa76930954a156B3fF30a4E1 + export beaconChainDepositContract=0x00000000219ab540356cBB839Cbe05303d7705Fa +fi yarn run hardhat verify --contract contracts/vault/OETHVault.sol:OETHVault --network holesky $OETH_VAULT -echo "module.exports = [\"0xD8724322f44E5c58D7A815F542036fb17DbbF839\"]" > vault_args.js +echo "module.exports = [\"$WETH\"]" > vault_args.js yarn run hardhat verify --contract contracts/vault/OETHVaultCore.sol:OETHVaultCore --network holesky --constructor-args vault_args.js $OETH_VAULT_CORE -yarn run hardhat verify --contract contracts/proxies/Proxies.sol:OETHVaultAdmin --network holesky --constructor-args vault_args.js $OETH_VAULT_ADMIN +yarn run hardhat verify --contract contracts/proxies/Proxies.sol:OETHVaultAdmin --network holesky $OETH_VAULT_ADMIN yarn run hardhat verify --contract contracts/proxies/Proxies.sol:OETHVaultProxy --network holesky $OETH_VAULT_PROXY yarn run hardhat verify --contract contracts/proxies/Proxies.sol:OETHProxy --network holesky $OETH_PROXY yarn run hardhat verify --contract contracts/token/OETH.sol:OETH --network holesky $OETH @@ -32,7 +44,7 @@ yarn run hardhat verify --contract contracts/token/OETH.sol:OETH --network holes echo "module.exports = [\"$NATIVE_STAKING_PROXY\"]" > fee_acc_args.js yarn run hardhat verify --contract contracts/strategies/NativeStaking/FeeAccumulator.sol:FeeAccumulator --network holesky --constructor-args fee_acc_args.js $FEE_ACC yarn run hardhat verify --contract contracts/proxies/Proxies.sol:NativeStakingFeeAccumulatorProxy --network holesky $FEE_ACC_PROXY -echo "module.exports = [\"$OETH_VAULT_PROXY\", \"$OETH_PROXY\"]" > dripper_acc_args.js +echo "module.exports = [\"$OETH_VAULT_PROXY\", \"$WETH\"]" > dripper_acc_args.js yarn run hardhat verify --contract contracts/harvest/OETHDripper.sol:OETHDripper --network holesky --constructor-args dripper_acc_args.js $OETH_DRIPPER yarn run hardhat verify --contract contracts/proxies/Proxies.sol:OETHDripperProxy --network holesky $OETH_DRIPPER_PROXY echo "module.exports = [\"$OETH_VAULT_PROXY\", \"$WETH\"]" > harvester_acc_args.js From 8a53f3e4efcc6c5b9ef4e0c424cec31b89b3ee9f Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Fri, 10 May 2024 22:33:58 +1000 Subject: [PATCH 048/273] removed wethToVault from manuallyFixAccounting --- .../NativeStaking/ValidatorAccountant.sol | 20 +---- .../docs/NativeStakingSSVStrategySquashed.svg | 4 +- contracts/test/strategies/nativeSSVStaking.js | 80 +++---------------- 3 files changed, 15 insertions(+), 89 deletions(-) diff --git a/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol b/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol index aebdb0a662..8d8aaaaca1 100644 --- a/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol +++ b/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol @@ -38,8 +38,7 @@ abstract contract ValidatorAccountant is ValidatorRegistrator { event AccountingManuallyFixed( int256 validatorsDelta, - int256 consensusRewardsDelta, - uint256 wethToVault + int256 consensusRewardsDelta ); /// @param _wethAddress Address of the Erc20 WETH Token contract @@ -182,12 +181,10 @@ abstract contract ValidatorAccountant is ValidatorRegistrator { /// @notice Allow the Strategist to fix the accounting of this strategy and unpause. /// @param _validatorsDelta adjust the active validators by plus one, minus one or unchanged with zero - /// @param _wethToVaultAmount the amount of WETH to be sent to the Vault /// @param _consensusRewardsDelta adjust the accounted for consensus rewards up or down function manuallyFixAccounting( int256 _validatorsDelta, - int256 _consensusRewardsDelta, - uint256 _wethToVaultAmount + int256 _consensusRewardsDelta ) external onlyStrategist whenPaused { require( _validatorsDelta >= -3 && @@ -203,13 +200,8 @@ abstract contract ValidatorAccountant is ValidatorRegistrator { int256(consensusRewards) + _consensusRewardsDelta >= 0, "invalid consensusRewardsDelta" ); - require(_wethToVaultAmount <= 32 ether, "invalid wethToVaultAmount"); - emit AccountingManuallyFixed( - _validatorsDelta, - _consensusRewardsDelta, - _wethToVaultAmount - ); + emit AccountingManuallyFixed(_validatorsDelta, _consensusRewardsDelta); activeDepositedValidators = uint256( int256(activeDepositedValidators) + _validatorsDelta @@ -217,12 +209,6 @@ abstract contract ValidatorAccountant is ValidatorRegistrator { consensusRewards = uint256( int256(consensusRewards) + _consensusRewardsDelta ); - if (_wethToVaultAmount > 0) { - IWETH9(WETH_TOKEN_ADDRESS).transfer( - VAULT_ADDRESS, - _wethToVaultAmount - ); - } // rerun the accounting to see if it has now been fixed. // Do not pause the accounting on failure as it is already paused diff --git a/contracts/docs/NativeStakingSSVStrategySquashed.svg b/contracts/docs/NativeStakingSSVStrategySquashed.svg index 22da401020..13b0b7d2aa 100644 --- a/contracts/docs/NativeStakingSSVStrategySquashed.svg +++ b/contracts/docs/NativeStakingSSVStrategySquashed.svg @@ -86,7 +86,7 @@    depositSSV(operatorIds: uint64[], amount: uint256, cluster: Cluster) <<onlyStrategist>> <<ValidatorRegistrator>>    setFuseInterval(_fuseIntervalStart: uint256, _fuseIntervalEnd: uint256) <<onlyGovernor>> <<ValidatorAccountant>>    doAccounting(): (accountingValid: bool) <<onlyRegistrator, whenNotPaused>> <<ValidatorAccountant>> -    manuallyFixAccounting(_validatorsDelta: int256, _consensusRewardsDelta: int256, _wethToVaultAmount: uint256) <<onlyStrategist, whenPaused>> <<ValidatorAccountant>> +    manuallyFixAccounting(_validatorsDelta: int256, _consensusRewardsDelta: int256) <<onlyStrategist, whenPaused>> <<ValidatorAccountant>>    collectRewardTokens() <<onlyHarvester, nonReentrant>> <<InitializableAbstractStrategy>>    setRewardTokenAddresses(_rewardTokenAddresses: address[]) <<onlyGovernor>> <<InitializableAbstractStrategy>>    getRewardTokenAddresses(): address[] <<InitializableAbstractStrategy>> @@ -115,7 +115,7 @@    <<event>> AccountingFullyWithdrawnValidator(noOfValidators: uint256, remainingValidators: uint256, wethSentToVault: uint256) <<ValidatorAccountant>>    <<event>> AccountingValidatorSlashed(remainingValidators: uint256, wethSentToVault: uint256) <<ValidatorAccountant>>    <<event>> AccountingConsensusRewards(amount: uint256) <<ValidatorAccountant>> -    <<event>> AccountingManuallyFixed(validatorsDelta: int256, consensusRewardsDelta: int256, wethToVault: uint256) <<ValidatorAccountant>> +    <<event>> AccountingManuallyFixed(validatorsDelta: int256, consensusRewardsDelta: int256) <<ValidatorAccountant>>    <<event>> PTokenAdded(_asset: address, _pToken: address) <<InitializableAbstractStrategy>>    <<event>> PTokenRemoved(_asset: address, _pToken: address) <<InitializableAbstractStrategy>>    <<event>> Deposit(_asset: address, _pToken: address, _amount: uint256) <<InitializableAbstractStrategy>> diff --git a/contracts/test/strategies/nativeSSVStaking.js b/contracts/test/strategies/nativeSSVStaking.js index af6e2b4a3a..da1babcf5f 100644 --- a/contracts/test/strategies/nativeSSVStaking.js +++ b/contracts/test/strategies/nativeSSVStaking.js @@ -522,8 +522,7 @@ describe("Unit test: Native SSV Staking Strategy", function () { await expect( nativeStakingSSVStrategy.connect(governor).manuallyFixAccounting( 1, //_validatorsDelta - parseEther("2"), //_consensusRewardsDelta - parseEther("2") //_wethToVault + parseEther("2") //_consensusRewardsDelta ) ).to.be.revertedWith("Caller is not the Strategist"); }); @@ -535,8 +534,7 @@ describe("Unit test: Native SSV Staking Strategy", function () { await expect( nativeStakingSSVStrategy.connect(strategist).manuallyFixAccounting( 1, //_validatorsDelta - parseEther("2"), //_consensusRewardsDelta - parseEther("2") //_wethToVault + parseEther("2") //_consensusRewardsDelta ) ).to.be.revertedWith("Pausable: not paused"); }); @@ -549,16 +547,14 @@ describe("Unit test: Native SSV Staking Strategy", function () { await expect( nativeStakingSSVStrategy.connect(strategist).manuallyFixAccounting( -4, //_validatorsDelta - 0, //_consensusRewardsDelta - 0 //_wethToVault + 0 //_consensusRewardsDelta ) ).to.be.revertedWith("invalid validatorsDelta"); await expect( nativeStakingSSVStrategy.connect(strategist).manuallyFixAccounting( 4, //_validatorsDelta - 0, //_consensusRewardsDelta - 0 //_wethToVault + 0 //_consensusRewardsDelta ) ).to.be.revertedWith("invalid validatorsDelta"); }); @@ -571,34 +567,18 @@ describe("Unit test: Native SSV Staking Strategy", function () { await expect( nativeStakingSSVStrategy.connect(strategist).manuallyFixAccounting( 0, //_validatorsDelta - parseEther("-333"), //_consensusRewardsDelta - 0 //_wethToVault + parseEther("-333") //_consensusRewardsDelta ) ).to.be.revertedWith("invalid consensusRewardsDelta"); await expect( nativeStakingSSVStrategy.connect(strategist).manuallyFixAccounting( 0, //_validatorsDelta - parseEther("333"), //_consensusRewardsDelta - 0 //_wethToVault + parseEther("333") //_consensusRewardsDelta ) ).to.be.revertedWith("invalid consensusRewardsDelta"); }); - it("WETH to Vault amount should not be >32 for fix accounting function", async () => { - const { nativeStakingSSVStrategy, strategist } = fixture; - - await nativeStakingSSVStrategy.connect(strategist).pause(); - - await expect( - nativeStakingSSVStrategy.connect(strategist).manuallyFixAccounting( - 0, //_validatorsDelta - 0, //_consensusRewardsDelta - parseEther("33") //_wethToVault - ) - ).to.be.revertedWith("invalid wethToVaultAmount"); - }); - describe("Should allow strategist to recover paused contract", async () => { for (const validatorsDelta of [-3, -2, -1, 0, 1, 2, 3]) { it(`by changing validators by ${validatorsDelta}`, async () => { @@ -612,7 +592,7 @@ describe("Unit test: Native SSV Staking Strategy", function () { const tx = await nativeStakingSSVStrategy .connect(strategist) - .manuallyFixAccounting(validatorsDelta, 0, 0); + .manuallyFixAccounting(validatorsDelta, 0); expect(tx) .to.emit(nativeStakingSSVStrategy, "AccountingManuallyFixed") @@ -643,7 +623,7 @@ describe("Unit test: Native SSV Staking Strategy", function () { const tx = await nativeStakingSSVStrategy .connect(strategist) - .manuallyFixAccounting(0, consensusRewardsDelta, 0); + .manuallyFixAccounting(0, consensusRewardsDelta); expect(tx) .to.emit(nativeStakingSSVStrategy, "AccountingManuallyFixed") @@ -658,44 +638,6 @@ describe("Unit test: Native SSV Staking Strategy", function () { }); } - it("by sending WETH to vault", async () => { - const { nativeStakingSSVStrategy, strategist, josh, weth } = fixture; - - await weth - .connect(josh) - .transfer(nativeStakingSSVStrategy.address, parseEther("100")); - - for (const wethInEthers of [0, 1, 26, 32]) { - await nativeStakingSSVStrategy.connect(strategist).pause(); - const wethBefore = await weth.balanceOf( - nativeStakingSSVStrategy.address - ); - const wethToVault = parseEther(wethInEthers.toString()); - - const tx = await nativeStakingSSVStrategy - .connect(strategist) - .manuallyFixAccounting(0, 0, wethToVault); - - expect(tx) - .to.emit(nativeStakingSSVStrategy, "AccountingManuallyFixed") - .withArgs(0, 0, wethToVault); - - expect( - await weth.balanceOf(nativeStakingSSVStrategy.address) - ).to.equal( - wethBefore.sub(wethToVault), - "consensus rewards not updated" - ); - - expect(await nativeStakingSSVStrategy.consensusRewards()).to.equal( - await nativeStakingSSVStrategy.provider.getBalance( - nativeStakingSSVStrategy.address - ), - "consensus rewards matches eth balance" - ); - } - }); - it("by changing all three manuallyFixAccounting delta values", async () => { const { nativeStakingSSVStrategy, strategist, josh, weth } = fixture; @@ -710,16 +652,14 @@ describe("Unit test: Native SSV Staking Strategy", function () { .connect(strategist) .manuallyFixAccounting( 1, //_validatorsDelta - parseEther("2.3"), //_consensusRewardsDeltaDelta - parseEther("2.2") //_wethToVault + parseEther("2.3") //_consensusRewardsDeltaDelta ); expect(tx) .to.emit(nativeStakingSSVStrategy, "AccountingManuallyFixed") .withArgs( 1, // validatorsDelta - parseEther("2.3"), // consensusRewards - parseEther("2.2") // wethToVault + parseEther("2.3") // consensusRewards ); }); }); From 905abf97ae831eb7c4e6ad71d3f4a437e1ee7529 Mon Sep 17 00:00:00 2001 From: Domen Grabec Date: Fri, 10 May 2024 14:40:05 +0200 Subject: [PATCH 049/273] native staking strategy redeployed --- .../deploy/holesky/008_upgrade_strategy.js | 24 ++++ .../deployments/holesky/.migrations.json | 3 +- .../holesky/NativeStakingSSVStrategy.json | 92 ++++++++-------- .../02842452c275dc62641a0db2f51fdc73.json | 104 ++++++++++++++++++ 4 files changed, 176 insertions(+), 47 deletions(-) create mode 100644 contracts/deploy/holesky/008_upgrade_strategy.js create mode 100644 contracts/deployments/holesky/solcInputs/02842452c275dc62641a0db2f51fdc73.json diff --git a/contracts/deploy/holesky/008_upgrade_strategy.js b/contracts/deploy/holesky/008_upgrade_strategy.js new file mode 100644 index 0000000000..08dd962c08 --- /dev/null +++ b/contracts/deploy/holesky/008_upgrade_strategy.js @@ -0,0 +1,24 @@ +const { + upgradeNativeStakingSSVStrategy, + upgradeNativeStakingFeeAccumulator, +} = require("../deployActions"); + +const mainExport = async () => { + console.log("Running 008 deployment on Holesky..."); + + console.log("Upgrading native staking fee accumulator"); + await upgradeNativeStakingFeeAccumulator(); + + console.log("Upgrading native staking strategy"); + await upgradeNativeStakingSSVStrategy(); + + console.log("Running 008 deployment done"); + return true; +}; + +mainExport.id = "008_upgrade_strategy"; +mainExport.tags = []; +mainExport.dependencies = []; +mainExport.skip = () => false; + +module.exports = mainExport; diff --git a/contracts/deployments/holesky/.migrations.json b/contracts/deployments/holesky/.migrations.json index bca53380ee..d184f8298b 100644 --- a/contracts/deployments/holesky/.migrations.json +++ b/contracts/deployments/holesky/.migrations.json @@ -5,5 +5,6 @@ "004_upgrade_strategy": 1714944723, "005_deploy_new_harvester": 1714998707, "006_update_registrator": 1715184342, - "007_upgrade_strategy": 1715251466 + "007_upgrade_strategy": 1715251466, + "008_upgrade_strategy": 1715341541 } \ No newline at end of file diff --git a/contracts/deployments/holesky/NativeStakingSSVStrategy.json b/contracts/deployments/holesky/NativeStakingSSVStrategy.json index f1396fd9fc..d4dc37f2d3 100644 --- a/contracts/deployments/holesky/NativeStakingSSVStrategy.json +++ b/contracts/deployments/holesky/NativeStakingSSVStrategy.json @@ -1,5 +1,5 @@ { - "address": "0x2cFc4691484D155142368d0ac2b954a0424a7EEd", + "address": "0x52a825Fe934303f0c1b33Aee00A830ce984BAadB", "abi": [ { "inputs": [ @@ -1276,34 +1276,34 @@ "type": "receive" } ], - "transactionHash": "0xd5bf651afbcae48e57d3767f34cde444061033c2ee656a377d989e8f820ecb87", + "transactionHash": "0xb602601e65659bec956b861609b760722c3801a76375aa64020d6c951ef5e791", "receipt": { "to": null, "from": "0x1b94CA50D3Ad9f8368851F8526132272d1a5028C", - "contractAddress": "0x2cFc4691484D155142368d0ac2b954a0424a7EEd", - "transactionIndex": 21, - "gasUsed": "4109268", - "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000020000000000000000000800200000000000000000000000000000000004000000000000002000000000000000000040000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000010000000000010000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000", - "blockHash": "0x5d3b7bb32953cd32eb25cd96b3ebcd5123ecfd7497f30ffa63b544440e11e2da", - "transactionHash": "0xd5bf651afbcae48e57d3767f34cde444061033c2ee656a377d989e8f820ecb87", + "contractAddress": "0x52a825Fe934303f0c1b33Aee00A830ce984BAadB", + "transactionIndex": 28, + "gasUsed": "4091194", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000800000000000000000000000004000000000004000000000000002000000000080000000040000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000010000000000010000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x3e35a66d156ee4f1ea266be3771b244e6952db22d5290cb8f87f0d7cb40eaf22", + "transactionHash": "0xb602601e65659bec956b861609b760722c3801a76375aa64020d6c951ef5e791", "logs": [ { - "transactionIndex": 21, - "blockNumber": 1509026, - "transactionHash": "0xd5bf651afbcae48e57d3767f34cde444061033c2ee656a377d989e8f820ecb87", - "address": "0x2cFc4691484D155142368d0ac2b954a0424a7EEd", + "transactionIndex": 28, + "blockNumber": 1515917, + "transactionHash": "0xb602601e65659bec956b861609b760722c3801a76375aa64020d6c951ef5e791", + "address": "0x52a825Fe934303f0c1b33Aee00A830ce984BAadB", "topics": [ "0xc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000001b94ca50d3ad9f8368851f8526132272d1a5028c" ], "data": "0x", - "logIndex": 34, - "blockHash": "0x5d3b7bb32953cd32eb25cd96b3ebcd5123ecfd7497f30ffa63b544440e11e2da" + "logIndex": 363, + "blockHash": "0x3e35a66d156ee4f1ea266be3771b244e6952db22d5290cb8f87f0d7cb40eaf22" } ], - "blockNumber": 1509026, - "cumulativeGasUsed": "6356303", + "blockNumber": 1515917, + "cumulativeGasUsed": "15703993", "status": 1, "byzantium": true }, @@ -1318,11 +1318,11 @@ "0x65a289f4BF934c964C942eFF6E6F83b6481BE550", "0x4242424242424242424242424242424242424242" ], - "numDeployments": 2, - "solcInputHash": "94a4e2017aae119860e82f5bc90e390d", - "metadata": "{\"compiler\":{\"version\":\"0.8.7+commit.e28d00a7\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"platformAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"vaultAddress\",\"type\":\"address\"}],\"internalType\":\"struct InitializableAbstractStrategy.BaseStrategyConfig\",\"name\":\"_baseConfig\",\"type\":\"tuple\"},{\"internalType\":\"address\",\"name\":\"_wethAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_ssvToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_ssvNetwork\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_feeAccumulator\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_beaconChainDepositContract\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"AccountingConsensusRewards\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"noOfValidators\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"remainingValidators\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"wethSentToVault\",\"type\":\"uint256\"}],\"name\":\"AccountingFullyWithdrawnValidator\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"validatorsDelta\",\"type\":\"int256\"},{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"consensusRewardsDelta\",\"type\":\"int256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"wethToVault\",\"type\":\"uint256\"}],\"name\":\"AccountingManuallyFixed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"remainingValidators\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"wethSentToVault\",\"type\":\"uint256\"}],\"name\":\"AccountingValidatorSlashed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"Deposit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"pubkey\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"withdrawal_credentials\",\"type\":\"bytes\"}],\"name\":\"ETHStaked\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"start\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"end\",\"type\":\"uint256\"}],\"name\":\"FuseIntervalUpdated\",\"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\":\"address\",\"name\":\"_oldHarvesterAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_newHarvesterAddress\",\"type\":\"address\"}],\"name\":\"HarvesterAddressesUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"}],\"name\":\"PTokenAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"}],\"name\":\"PTokenRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Paused\",\"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\":\"newAddress\",\"type\":\"address\"}],\"name\":\"RegistratorChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"_oldAddresses\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"_newAddresses\",\"type\":\"address[]\"}],\"name\":\"RewardTokenAddressesUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"rewardToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"RewardTokenCollected\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"pubkey\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"}],\"name\":\"SSVValidatorExitCompleted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"pubkey\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"}],\"name\":\"SSVValidatorExitInitiated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"pubkey\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"}],\"name\":\"SSVValidatorRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Unpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"Withdrawal\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"BEACON_CHAIN_DEPOSIT_CONTRACT\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_ACCUMULATOR_ADDRESS\",\"outputs\":[{\"internalType\":\"address payable\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MAX_STAKE\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"SSV_NETWORK_ADDRESS\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"SSV_TOKEN_ADDRESS\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"VAULT_ADDRESS\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"WETH_TOKEN_ADDRESS\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"activeDepositedValidators\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"assetToPToken\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"}],\"name\":\"checkBalance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"claimGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"collectRewardTokens\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"consensusRewards\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"depositAll\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"validatorCount\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"networkFeeIndex\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"index\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"active\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"internalType\":\"struct Cluster\",\"name\":\"cluster\",\"type\":\"tuple\"}],\"name\":\"depositSSV\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"doAccounting\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"accountingValid\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"publicKey\",\"type\":\"bytes\"},{\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"}],\"name\":\"exitSsvValidator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fuseIntervalEnd\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fuseIntervalStart\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRewardTokenAddresses\",\"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\":\"harvesterAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"_rewardTokenAddresses\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"_assets\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"_pTokens\",\"type\":\"address[]\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isGovernor\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"int256\",\"name\":\"_validatorsDelta\",\"type\":\"int256\"},{\"internalType\":\"int256\",\"name\":\"_consensusRewardsDelta\",\"type\":\"int256\"},{\"internalType\":\"uint256\",\"name\":\"_wethToVaultAmount\",\"type\":\"uint256\"}],\"name\":\"manuallyFixAccounting\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"paused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"platformAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"publicKey\",\"type\":\"bytes\"},{\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"},{\"internalType\":\"bytes\",\"name\":\"sharesData\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"validatorCount\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"networkFeeIndex\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"index\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"active\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"internalType\":\"struct Cluster\",\"name\":\"cluster\",\"type\":\"tuple\"}],\"name\":\"registerSsvValidator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_assetIndex\",\"type\":\"uint256\"}],\"name\":\"removePToken\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"publicKey\",\"type\":\"bytes\"},{\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"validatorCount\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"networkFeeIndex\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"index\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"active\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"internalType\":\"struct Cluster\",\"name\":\"cluster\",\"type\":\"tuple\"}],\"name\":\"removeSsvValidator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"rewardTokenAddresses\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"safeApproveAllTokens\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_fuseIntervalStart\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_fuseIntervalEnd\",\"type\":\"uint256\"}],\"name\":\"setFuseInterval\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_harvesterAddress\",\"type\":\"address\"}],\"name\":\"setHarvesterAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"}],\"name\":\"setPTokenAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"setRegistrator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"_rewardTokenAddresses\",\"type\":\"address[]\"}],\"name\":\"setRewardTokenAddresses\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"pubkey\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"depositDataRoot\",\"type\":\"bytes32\"}],\"internalType\":\"struct ValidatorStakeData[]\",\"name\":\"validators\",\"type\":\"tuple[]\"}],\"name\":\"stakeEth\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"}],\"name\":\"supportsAsset\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"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\":\"validatorRegistrator\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"validatorsStates\",\"outputs\":[{\"internalType\":\"enum ValidatorRegistrator.VALIDATOR_STATE\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"vaultAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"withdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdrawAll\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"author\":\"Origin Protocol Inc\",\"kind\":\"dev\",\"methods\":{\"checkBalance(address)\":{\"params\":{\"_asset\":\"Address of weth asset\"},\"returns\":{\"balance\":\" Total value of (W)ETH\"}},\"constructor\":{\"params\":{\"_baseConfig\":\"Base strategy config with platformAddress (ERC-4626 Vault contract), eg sfrxETH or sDAI, and vaultAddress (OToken Vault contract), eg VaultProxy or OETHVaultProxy\",\"_beaconChainDepositContract\":\"Address of the beacon chain deposit contract\",\"_feeAccumulator\":\"Address of the fee accumulator receiving execution layer validator rewards\",\"_ssvNetwork\":\"Address of the SSV Network contract\",\"_ssvToken\":\"Address of the Erc20 SSV Token contract\",\"_wethAddress\":\"Address of the Erc20 WETH Token contract\"}},\"deposit(address,uint256)\":{\"params\":{\"_amount\":\"Amount of assets that were transferred to the strategy by the vault.\",\"_asset\":\"Address of asset to deposit. Has to be WETH.\"}},\"depositSSV(uint64[],uint256,(uint32,uint64,uint64,bool,uint256))\":{\"details\":\"A SSV cluster is defined by the SSVOwnerAddress and the set of operatorIds. uses \\\"onlyStrategist\\\" modifier so continuous front-running can't DOS our maintenance service that tries to top up SSV tokens.\",\"params\":{\"cluster\":\"The SSV cluster details that must be derived from emitted events from the SSVNetwork contract.\"}},\"doAccounting()\":{\"details\":\"This function could in theory be permission-less but lets allow only the Registrator (Defender Action) to call it for now.\",\"returns\":{\"accountingValid\":\"true if accounting was successful, false if fuse is blown\"}},\"getRewardTokenAddresses()\":{\"returns\":{\"_0\":\"address[] the reward token addresses.\"}},\"initialize(address[],address[],address[])\":{\"params\":{\"_assets\":\"Addresses of initial supported assets\",\"_pTokens\":\"Platform Token corresponding addresses\",\"_rewardTokenAddresses\":\"Address of reward token for platform\"}},\"manuallyFixAccounting(int256,int256,uint256)\":{\"params\":{\"_consensusRewardsDelta\":\"adjust the accounted for consensus rewards up or down\",\"_validatorsDelta\":\"adjust the active validators by plus one, minus one or unchanged with zero\",\"_wethToVaultAmount\":\"the amount of WETH to be sent to the Vault\"}},\"paused()\":{\"details\":\"Returns true if the contract is paused, and false otherwise.\"},\"removePToken(uint256)\":{\"params\":{\"_assetIndex\":\"Index of the asset to be removed\"}},\"setHarvesterAddress(address)\":{\"params\":{\"_harvesterAddress\":\"Address of the harvester contract.\"}},\"setPTokenAddress(address,address)\":{\"params\":{\"_asset\":\"Address for the asset\",\"_pToken\":\"Address for the corresponding platform token\"}},\"setRewardTokenAddresses(address[])\":{\"params\":{\"_rewardTokenAddresses\":\"Array of reward token addresses\"}},\"stakeEth((bytes,bytes,bytes32)[])\":{\"params\":{\"validators\":\"A list of validator data needed to stake. The `ValidatorStakeData` struct contains the pubkey, signature and depositDataRoot. Only the registrator can call this function.\"}},\"supportsAsset(address)\":{\"params\":{\"_asset\":\"The address of the asset token.\"}},\"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\"}},\"withdraw(address,address,uint256)\":{\"params\":{\"_amount\":\"Amount of WETH to withdraw\",\"_asset\":\"WETH to withdraw\",\"_recipient\":\"Address to receive withdrawn assets\"}}},\"stateVariables\":{\"FEE_ACCUMULATOR_ADDRESS\":{\"details\":\"this address will receive Execution layer rewards - These are rewards earned for executing transactions on the Ethereum network as part of block proposals. They include priority fees (fees paid by users for their transactions to be included) and MEV rewards (rewards for arranging transactions in a way that benefits the validator).\"}},\"title\":\"Native Staking SSV Strategy\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"BEACON_CHAIN_DEPOSIT_CONTRACT()\":{\"notice\":\"The address of the beacon chain deposit contract\"},\"FEE_ACCUMULATOR_ADDRESS()\":{\"notice\":\"Fee collector address\"},\"MAX_STAKE()\":{\"notice\":\"The maximum amount of ETH that can be staked by a validator\"},\"SSV_NETWORK_ADDRESS()\":{\"notice\":\"The address of the SSV Network contract used to interface with\"},\"SSV_TOKEN_ADDRESS()\":{\"notice\":\"SSV ERC20 token that serves as a payment for operating SSV validators\"},\"VAULT_ADDRESS()\":{\"notice\":\"Address of the OETH Vault proxy contract\"},\"WETH_TOKEN_ADDRESS()\":{\"notice\":\"The address of the Wrapped ETH (WETH) token contract\"},\"activeDepositedValidators()\":{\"notice\":\"The number of validators that have 32 (!) ETH actively deposited. When a new deposit to a validator happens this number increases, when a validator exit is detected this number decreases.\"},\"assetToPToken(address)\":{\"notice\":\"asset => pToken (Platform Specific Token Address)\"},\"checkBalance(address)\":{\"notice\":\"Returns the total value of (W)ETH that is staked to the validators and WETH deposits that are still to be staked. This does not include ETH from consensus rewards sitting in this strategy or ETH from MEV rewards in the FeeAccumulator. These rewards are harvested and sent to the Dripper so will eventually be sent to the Vault as WETH.\"},\"claimGovernance()\":{\"notice\":\"Claim Governance of the contract to a new account (`newGovernor`). Can only be called by the new Governor.\"},\"collectRewardTokens()\":{\"notice\":\"Collect accumulated reward token and send to Vault.\"},\"consensusRewards()\":{\"notice\":\"Keeps track of the total consensus rewards swept from the beacon chain\"},\"deposit(address,uint256)\":{\"notice\":\"Unlike other strategies, this does not deposit assets into the underlying platform. It just checks the asset is WETH and emits the Deposit event. To deposit WETH into validators `registerSsvValidator` and `stakeEth` must be used. Will NOT revert if the strategy is paused from an accounting failure.\"},\"depositAll()\":{\"notice\":\"Unlike other strategies, this does not deposit assets into the underlying platform. It just emits the Deposit event. To deposit WETH into validators `registerSsvValidator` and `stakeEth` must be used. Will NOT revert if the strategy is paused from an accounting failure.\"},\"depositSSV(uint64[],uint256,(uint32,uint64,uint64,bool,uint256))\":{\"notice\":\"Deposits more SSV Tokens to the SSV Network contract which is used to pay the SSV Operators.\"},\"doAccounting()\":{\"notice\":\"This notion page offers a good explanation of how the accounting functions https://www.notion.so/originprotocol/Limited-simplified-native-staking-accounting-67a217c8420d40678eb943b9da0ee77d In short, after dividing by 32, if the ETH remaining on the contract falls between 0 and fuseIntervalStart, the accounting function will treat that ETH as Beacon chain consensus rewards. On the contrary, if after dividing by 32, the ETH remaining on the contract falls between fuseIntervalEnd and 32, the accounting function will treat that as a validator slashing.Perform the accounting attributing beacon chain ETH to either full or partial withdrawals. Returns true when accounting is valid and fuse isn't \\\"blown\\\". Returns false when fuse is blown.\"},\"exitSsvValidator(bytes,uint64[])\":{\"notice\":\"Exit a validator from the Beacon chain. The staked ETH will eventually swept to this native staking strategy. Only the registrator can call this function.\"},\"fuseIntervalEnd()\":{\"notice\":\"end of fuse interval\"},\"fuseIntervalStart()\":{\"notice\":\"start of fuse interval\"},\"getRewardTokenAddresses()\":{\"notice\":\"Get the reward token addresses.\"},\"governor()\":{\"notice\":\"Returns the address of the current Governor.\"},\"harvesterAddress()\":{\"notice\":\"Address of the Harvester contract allowed to collect reward tokens\"},\"initialize(address[],address[],address[])\":{\"notice\":\"initialize function, to set up initial internal state\"},\"isGovernor()\":{\"notice\":\"Returns true if the caller is the current Governor.\"},\"manuallyFixAccounting(int256,int256,uint256)\":{\"notice\":\"Allow the Strategist to fix the accounting of this strategy and unpause.\"},\"platformAddress()\":{\"notice\":\"Address of the underlying platform\"},\"registerSsvValidator(bytes,uint64[],bytes,uint256,(uint32,uint64,uint64,bool,uint256))\":{\"notice\":\"Registers a new validator in the SSV Cluster. Only the registrator can call this function.\"},\"removePToken(uint256)\":{\"notice\":\"Remove a supported asset by passing its index. This method can only be called by the system Governor\"},\"removeSsvValidator(bytes,uint64[],(uint32,uint64,uint64,bool,uint256))\":{\"notice\":\"Remove a validator from the SSV Cluster. Make sure `exitSsvValidator` is called before and the validate has exited the Beacon chain. If removed before the validator has exited the beacon chain will result in the validator being slashed. Only the registrator can call this function.\"},\"rewardTokenAddresses(uint256)\":{\"notice\":\"Address of the reward tokens. eg CRV, BAL, CVX, AURA\"},\"safeApproveAllTokens()\":{\"notice\":\"Approves the SSV Network contract to transfer SSV tokens for deposits\"},\"setFuseInterval(uint256,uint256)\":{\"notice\":\"set fuse interval values\"},\"setHarvesterAddress(address)\":{\"notice\":\"Set the Harvester contract that can collect rewards.\"},\"setPTokenAddress(address,address)\":{\"notice\":\"Provide support for asset by passing its pToken address. This method can only be called by the system Governor\"},\"setRegistrator(address)\":{\"notice\":\"Set the address of the registrator which can register, exit and remove validators\"},\"setRewardTokenAddresses(address[])\":{\"notice\":\"Set the reward token addresses. Any old addresses will be overwritten.\"},\"stakeEth((bytes,bytes,bytes32)[])\":{\"notice\":\"Stakes WETH to the node validators\"},\"supportsAsset(address)\":{\"notice\":\"Returns bool indicating whether asset is supported by strategy.\"},\"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 strategy contracts, i.e. mistaken sends.\"},\"validatorRegistrator()\":{\"notice\":\"Address of the registrator - allowed to register, exit and remove validators\"},\"validatorsStates(bytes32)\":{\"notice\":\"State of the validators keccak256(pubKey) => state\"},\"vaultAddress()\":{\"notice\":\"Address of the OToken vault\"},\"withdraw(address,address,uint256)\":{\"notice\":\"Withdraw WETH from this contract. Used only if some WETH for is lingering on the contract. That can happen when: - the deposit was not a multiple of 32 WETH - someone sent WETH directly to this contract Will NOT revert if the strategy is paused from an accounting failure.\"},\"withdrawAll()\":{\"notice\":\"transfer all WETH deposits back to the vault. This does not withdraw from the validators. That has to be done separately with the `exitSsvValidator` and `removeSsvValidator` operations. This does not withdraw any execution rewards from the FeeAccumulator or consensus rewards in this strategy. Any ETH in this strategy that was swept from a full validator withdrawal will not be withdrawn. ETH from full validator withdrawals is sent to the Vault using `doAccounting`. Will NOT revert if the strategy is paused from an accounting failure.\"}},\"notice\":\"Strategy to deploy funds into DVT validators powered by the SSV Network\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol\":\"NativeStakingSSVStrategy\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"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\",\"keccak256\":\"0xe68ed7fb8766ed1e888291f881e36b616037f852b37d96877045319ad298ba87\",\"license\":\"MIT\"},\"@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/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\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"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/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\",\"keccak256\":\"0x598f90bdbc854250bbd5991426bfb43367207e64e33109c41aa8b54323fd8d8e\",\"license\":\"MIT\"},\"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 error ApprovalNotWithinTimeframe();\\n error CallerNotOwner();\\n error CallerNotWhitelisted();\\n error ClusterAlreadyEnabled();\\n error ClusterDoesNotExists();\\n error ClusterIsLiquidated();\\n error ClusterNotLiquidatable();\\n error ExceedValidatorLimit();\\n error FeeExceedsIncreaseLimit();\\n error FeeIncreaseNotAllowed();\\n error FeeTooHigh();\\n error FeeTooLow();\\n error IncorrectClusterState();\\n error IncorrectValidatorState();\\n error InsufficientBalance();\\n error InvalidOperatorIdsLength();\\n error InvalidPublicKeyLength();\\n error MaxValueExceeded();\\n error NewBlockPeriodIsBelowMinimum();\\n error NoFeeDeclared();\\n error NotAuthorized();\\n error OperatorAlreadyExists();\\n error OperatorDoesNotExist();\\n error OperatorsListNotUnique();\\n error SameFeeChangeNotAllowed();\\n error TargetModuleDoesNotExist();\\n error TokenTransferFailed();\\n error UnsortedOperatorsList();\\n error ValidatorAlreadyExists();\\n error ValidatorDoesNotExist();\\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 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 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 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\",\"keccak256\":\"0x76e2c5148727b72752939b06fee7abc1f732c18970b8c7db7fe7cdfe74629d36\",\"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/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/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\",\"keccak256\":\"0x05b7dce6c24d3cd4e48b5c6346d86e5e40ecc3291bcdf3f3ef091c98fc826519\",\"license\":\"MIT\"},\"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\\nimport { Governable } from \\\"../../governance/Governable.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 is Governable {\\n /// @notice The address of the Native Staking Strategy\\n address public immutable STRATEGY;\\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 }\\n\\n /**\\n * @dev Accept ETH\\n */\\n receive() external payable {}\\n}\\n\",\"keccak256\":\"0xb8fda3b87dc5d6f8aee4bf1d015a585211e5b5a319dfa4b0f4770e3f5a2d5939\",\"license\":\"MIT\"},\"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\\\";\\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\\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_ADDRESS;\\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 // For future use\\n uint256[50] 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 _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 address _feeAccumulator,\\n address _beaconChainDepositContract\\n )\\n InitializableAbstractStrategy(_baseConfig)\\n ValidatorAccountant(\\n _wethAddress,\\n _baseConfig.vaultAddress,\\n _beaconChainDepositContract,\\n _ssvNetwork\\n )\\n {\\n SSV_TOKEN_ADDRESS = _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 /// @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_TOKEN_ADDRESS).deposit{ value: ethRewards }();\\n\\n emit RewardTokenCollected(\\n harvesterAddress,\\n WETH_TOKEN_ADDRESS,\\n ethRewards\\n );\\n IERC20(WETH_TOKEN_ADDRESS).safeTransfer(\\n harvesterAddress,\\n ethRewards\\n );\\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_TOKEN_ADDRESS, \\\"Unsupported asset\\\");\\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_TOKEN_ADDRESS).balanceOf(\\n address(this)\\n );\\n if (wethBalance > 0) {\\n _deposit(WETH_TOKEN_ADDRESS, wethBalance);\\n }\\n }\\n\\n /// @notice Withdraw WETH from this contract. Used only if some WETH for is lingering on the contract. That\\n /// can happen when:\\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 _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 emit Withdrawal(_asset, address(0), _amount);\\n IERC20(_asset).safeTransfer(_recipient, _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_TOKEN_ADDRESS).balanceOf(\\n address(this)\\n );\\n if (wethBalance > 0) {\\n _withdraw(vaultAddress, WETH_TOKEN_ADDRESS, wethBalance);\\n }\\n }\\n\\n function _abstractSetPToken(address _asset, address) internal override {}\\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_TOKEN_ADDRESS, \\\"Unsupported asset\\\");\\n\\n balance =\\n // add the ETH that has been staked in validators\\n activeDepositedValidators *\\n 32 ether +\\n // add the WETH in the strategy from deposits that are still to be staked\\n IERC20(WETH_TOKEN_ADDRESS).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_TOKEN_ADDRESS;\\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_ADDRESS).approve(\\n SSV_NETWORK_ADDRESS,\\n type(uint256).max\\n );\\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 ||\\n msg.sender == WETH_TOKEN_ADDRESS,\\n \\\"eth not from allowed contracts\\\"\\n );\\n }\\n}\\n\",\"keccak256\":\"0x9ba7e5cc1fbf9e4a8559d9872dcdf8959b4f3ef9d9a2ff8e0f74c36ec9efb4fe\",\"license\":\"MIT\"},\"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 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 MAX_STAKE = 32 ether;\\n\\n /// @notice Keeps track of the total consensus rewards swept from the beacon chain\\n uint256 public consensusRewards = 0;\\n\\n /// @notice start of fuse interval\\n uint256 public fuseIntervalStart = 0;\\n /// @notice end of fuse interval\\n uint256 public fuseIntervalEnd = 0;\\n\\n uint256[50] 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 constructor(\\n address _wethAddress,\\n address _vaultAddress,\\n address _beaconChainDepositContract,\\n address _ssvNetwork\\n )\\n ValidatorRegistrator(\\n _wethAddress,\\n _vaultAddress,\\n _beaconChainDepositContract,\\n _ssvNetwork\\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 _fuseIntervalStart < 32 ether &&\\n _fuseIntervalEnd < 32 ether &&\\n _fuseIntervalEnd - _fuseIntervalStart >= 4 ether,\\n \\\"incorrect fuse interval\\\"\\n );\\n\\n emit FuseIntervalUpdated(_fuseIntervalStart, _fuseIntervalEnd);\\n\\n fuseIntervalStart = _fuseIntervalStart;\\n fuseIntervalEnd = _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 returns (bool accountingValid)\\n {\\n // pause the accounting on failure\\n accountingValid = _doAccounting(true);\\n }\\n\\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 >= MAX_STAKE) {\\n uint256 fullyWithdrawnValidators = newSweptETH / MAX_STAKE;\\n if (activeDepositedValidators < fullyWithdrawnValidators) {\\n return _failAccounting(pauseOnFail);\\n }\\n activeDepositedValidators -= fullyWithdrawnValidators;\\n\\n uint256 wethToVault = MAX_STAKE * fullyWithdrawnValidators;\\n IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: wethToVault }();\\n IWETH9(WETH_TOKEN_ADDRESS).transfer(VAULT_ADDRESS, 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 < 32 ether, \\\"unexpected accounting\\\");\\n\\n // If no Beacon chain consensus rewards swept\\n if (ethRemaining == 0) {\\n // do nothing\\n return accountingValid;\\n }\\n // Beacon chain consensus rewards swept (partial validator withdrawals)\\n else if (ethRemaining < fuseIntervalStart) {\\n // solhint-disable-next-line reentrancy\\n consensusRewards += ethRemaining;\\n emit AccountingConsensusRewards(ethRemaining);\\n }\\n // Beacon chain consensus rewards swept but also a slashed validator fully exited\\n else if (ethRemaining > fuseIntervalEnd) {\\n IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: ethRemaining }();\\n IWETH9(WETH_TOKEN_ADDRESS).transfer(VAULT_ADDRESS, ethRemaining);\\n activeDepositedValidators -= 1;\\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 /// @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 plus one, minus one or unchanged with zero\\n /// @param _wethToVaultAmount the amount of WETH to be sent to the Vault\\n /// @param _consensusRewardsDelta adjust the accounted for consensus rewards up or down\\n function manuallyFixAccounting(\\n int256 _validatorsDelta,\\n int256 _consensusRewardsDelta,\\n uint256 _wethToVaultAmount\\n ) external onlyStrategist whenPaused {\\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(_wethToVaultAmount <= 32 ether, \\\"invalid wethToVaultAmount\\\");\\n\\n emit AccountingManuallyFixed(\\n _validatorsDelta,\\n _consensusRewardsDelta,\\n _wethToVaultAmount\\n );\\n\\n activeDepositedValidators = uint256(\\n int256(activeDepositedValidators) + _validatorsDelta\\n );\\n consensusRewards = uint256(\\n int256(consensusRewards) + _consensusRewardsDelta\\n );\\n if (_wethToVaultAmount > 0) {\\n IWETH9(WETH_TOKEN_ADDRESS).transfer(\\n VAULT_ADDRESS,\\n _wethToVaultAmount\\n );\\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\",\"keccak256\":\"0xc6c306bde6b18189944f3d03fc82996b2e0c54b3a2882ee8d0fece0d71949e11\",\"license\":\"MIT\"},\"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 address of the Wrapped ETH (WETH) token contract\\n address public immutable WETH_TOKEN_ADDRESS;\\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_ADDRESS;\\n /// @notice Address of the OETH Vault proxy contract\\n address public immutable VAULT_ADDRESS;\\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\\n // For future use\\n uint256[50] private __gap;\\n\\n enum VALIDATOR_STATE {\\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 newAddress);\\n event ETHStaked(bytes pubkey, uint256 amount, bytes withdrawal_credentials);\\n event SSVValidatorRegistered(bytes pubkey, uint64[] operatorIds);\\n event SSVValidatorExitInitiated(bytes pubkey, uint64[] operatorIds);\\n event SSVValidatorExitCompleted(bytes pubkey, uint64[] operatorIds);\\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 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 constructor(\\n address _wethAddress,\\n address _vaultAddress,\\n address _beaconChainDepositContract,\\n address _ssvNetwork\\n ) {\\n WETH_TOKEN_ADDRESS = _wethAddress;\\n BEACON_CHAIN_DEPOSIT_CONTRACT = _beaconChainDepositContract;\\n SSV_NETWORK_ADDRESS = _ssvNetwork;\\n VAULT_ADDRESS = _vaultAddress;\\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 emit RegistratorChanged(_address);\\n validatorRegistrator = _address;\\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 function stakeEth(ValidatorStakeData[] calldata validators)\\n external\\n onlyRegistrator\\n whenNotPaused\\n {\\n uint256 requiredETH = validators.length * 32 ether;\\n\\n // Check there is enough WETH from the deposits sitting in this strategy contract\\n require(\\n requiredETH <= IWETH9(WETH_TOKEN_ADDRESS).balanceOf(address(this)),\\n \\\"insufficient WETH\\\"\\n );\\n\\n // Convert required ETH from WETH\\n IWETH9(WETH_TOKEN_ADDRESS).withdraw(requiredETH);\\n\\n // For each validator\\n for (uint256 i = 0; i < validators.length; ) {\\n bytes32 pubkeyHash = keccak256(validators[i].pubkey);\\n VALIDATOR_STATE currentState = validatorsStates[pubkeyHash];\\n\\n require(\\n currentState == VALIDATOR_STATE.REGISTERED,\\n \\\"Validator not registered\\\"\\n );\\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 withdrawal_credentials = abi.encodePacked(\\n bytes1(0x01),\\n bytes11(0),\\n address(this)\\n );\\n IDepositContract(BEACON_CHAIN_DEPOSIT_CONTRACT).deposit{\\n value: 32 ether\\n }(\\n validators[i].pubkey,\\n withdrawal_credentials,\\n validators[i].signature,\\n validators[i].depositDataRoot\\n );\\n\\n activeDepositedValidators += 1;\\n emit ETHStaked(\\n validators[i].pubkey,\\n 32 ether,\\n withdrawal_credentials\\n );\\n\\n validatorsStates[pubkeyHash] = VALIDATOR_STATE.STAKED;\\n\\n unchecked {\\n ++i;\\n }\\n }\\n }\\n\\n /// @notice Registers a new validator in the SSV Cluster.\\n /// Only the registrator can call this function.\\n function registerSsvValidator(\\n bytes calldata publicKey,\\n uint64[] calldata operatorIds,\\n bytes calldata sharesData,\\n uint256 amount,\\n Cluster calldata cluster\\n ) external onlyRegistrator whenNotPaused {\\n ISSVNetwork(SSV_NETWORK_ADDRESS).registerValidator(\\n publicKey,\\n operatorIds,\\n sharesData,\\n amount,\\n cluster\\n );\\n validatorsStates[keccak256(publicKey)] = VALIDATOR_STATE.REGISTERED;\\n emit SSVValidatorRegistered(publicKey, operatorIds);\\n }\\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 function exitSsvValidator(\\n bytes calldata publicKey,\\n uint64[] calldata operatorIds\\n ) external onlyRegistrator whenNotPaused {\\n VALIDATOR_STATE currentState = validatorsStates[keccak256(publicKey)];\\n require(currentState == VALIDATOR_STATE.STAKED, \\\"Validator not staked\\\");\\n\\n ISSVNetwork(SSV_NETWORK_ADDRESS).exitValidator(publicKey, operatorIds);\\n emit SSVValidatorExitInitiated(publicKey, operatorIds);\\n\\n validatorsStates[keccak256(publicKey)] = VALIDATOR_STATE.EXITING;\\n }\\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 function removeSsvValidator(\\n bytes calldata publicKey,\\n uint64[] calldata operatorIds,\\n Cluster calldata cluster\\n ) external onlyRegistrator whenNotPaused {\\n VALIDATOR_STATE currentState = validatorsStates[keccak256(publicKey)];\\n require(\\n currentState == VALIDATOR_STATE.EXITING,\\n \\\"Validator not exiting\\\"\\n );\\n\\n ISSVNetwork(SSV_NETWORK_ADDRESS).removeValidator(\\n publicKey,\\n operatorIds,\\n cluster\\n );\\n emit SSVValidatorExitCompleted(publicKey, operatorIds);\\n\\n validatorsStates[keccak256(publicKey)] = VALIDATOR_STATE.EXIT_COMPLETE;\\n }\\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 cluster The SSV cluster details that must be derived from emitted events from the SSVNetwork contract.\\n function depositSSV(\\n uint64[] memory operatorIds,\\n uint256 amount,\\n Cluster memory cluster\\n ) external onlyStrategist {\\n ISSVNetwork(SSV_NETWORK_ADDRESS).deposit(\\n address(this),\\n operatorIds,\\n amount,\\n cluster\\n );\\n }\\n}\\n\",\"keccak256\":\"0x4bc23d19500e2d306fd546c4ab9c4c53292d4ef54392ec4f1ae62dd7601a3d24\",\"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/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\",\"keccak256\":\"0x5e17bb3db9f9e1014b7c5c836547f8fa81e02af7568c0bb8f2a2e0e7c2192db4\",\"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/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": "0x610180604052600060685560006069556000606a553480156200002157600080fd5b5060405162004c9a38038062004c9a833981016040819052620000449162000147565b8585876020015183868383838362000062336200011760201b60201c565b60008051602062004c7a833981519152546040516001600160a01b03909116906000907fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a908290a36033805460ff191690556001600160601b0319606094851b811660805291841b821660a052831b811660c05290821b811660e0528651821b811661010052602090960151811b86166101205298891b851661014052505050509190931b1661016052506200022292505050565b60008051602062004c7a83398151915255565b80516001600160a01b03811681146200014257600080fd5b919050565b60008060008060008086880360e08112156200016257600080fd5b60408112156200017157600080fd5b50604080519081016001600160401b0381118282101715620001a357634e487b7160e01b600052604160045260246000fd5b604052620001b1886200012a565b8152620001c1602089016200012a565b60208201529550620001d6604088016200012a565b9450620001e6606088016200012a565b9350620001f6608088016200012a565b92506200020660a088016200012a565b91506200021660c088016200012a565b90509295509295509295565b60805160601c60a05160601c60c05160601c60e05160601c6101005160601c6101205160601c6101405160601c6101605160601c6148c2620003b8600039600081816102a70152818161096e0152612da901526000818161057d01526122fc01526000818161045101528181610d41015281816118c001528181611a390152818161265b01526128e30152600061093a0152600081816106ec01528181610b09015281816117ee01528181611a8901528181611d6c0152818161332201526135730152600081816109b701528181610bdf015281816116c0015281816122cc015281816123e401526127d90152600081816108a601526114070152600081816102d9015281816104db015281816107bd01528181610a7001528181610db601528181610f850152818161100d015281816111bc01528181611297015281816119aa01528181611a5a01528181611d9b0152818161296e015281816129fd01528181612eae01528181612f3301528181612fa70152818161329c01528181613351015281816134ed01526135a201526148c26000f3fe6080604052600436106102975760003560e01c8063853828b61161015a578063c2e1e3f4116100c1578063d9f00ec71161007a578063d9f00ec714610908578063dbe55e5614610928578063dd505df61461095c578063de5f626814610990578063f1188e40146109a5578063f6ca71b0146109d957600080fd5b8063c2e1e3f414610842578063c7af335214610862578063c98517c514610877578063cceab75014610894578063d38bfff4146108c8578063d9caed12146108e857600080fd5b80639da0e462116101135780639da0e4621461074e578063a4f98af41461078b578063aa388af6146107a0578063ab12edf5146107ed578063ad1728cb1461080d578063bb1b918d1461082257600080fd5b8063853828b61461068057806387bae867146106955780638d7c0e46146106ba5780639092c31c146106da5780639136616a1461070e57806396d538bb1461072e57600080fd5b80635c975abb116101fe5780636e811d38116101b75780636e811d38146105d55780636ef38795146105f557806371a735f3146106155780637b2d9b2c14610635578063842f5c46146106555780638456cb591461066b57600080fd5b80635c975abb146105125780635d36b190146105365780635f5152261461054b5780636093d3801461056b57806366e3667e1461059f57806367c7066c146105b557600080fd5b8063430bf08a11610250578063430bf08a1461043f578063435356d11461047357806347e7ef2414610493578063484be812146104b3578063579a7e1a146104c95780635a063f63146104fd57600080fd5b80630c340a24146103535780630ed57b3a146103855780630fc3b4c4146103a55780631072cbea146103db57806322495dc8146103fb5780633c8649591461041b57600080fd5b3661034e57336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614806102fb5750336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016145b61034c5760405162461bcd60e51b815260206004820152601e60248201527f657468206e6f742066726f6d20616c6c6f77656420636f6e747261637473000060448201526064015b60405180910390fd5b005b600080fd5b34801561035f57600080fd5b506103686109fb565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561039157600080fd5b5061034c6103a0366004613c43565b610a18565b3480156103b157600080fd5b506103686103c0366004613c09565b609f602052600090815260409020546001600160a01b031681565b3480156103e757600080fd5b5061034c6103f6366004613cbd565b610a4a565b34801561040757600080fd5b5061034c610416366004613db1565b610b07565b34801561042757600080fd5b5061043160695481565b60405190815260200161037c565b34801561044b57600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b34801561047f57600080fd5b5061034c61048e366004613d2a565b610c51565b34801561049f57600080fd5b5061034c6104ae366004613cbd565b610d36565b3480156104bf57600080fd5b50610431606a5481565b3480156104d557600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b34801561050957600080fd5b5061034c610e3c565b34801561051e57600080fd5b5060335460ff165b604051901515815260200161037c565b34801561054257600080fd5b5061034c610edb565b34801561055757600080fd5b50610431610566366004613c09565b610f81565b34801561057757600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b3480156105ab57600080fd5b5061043160345481565b3480156105c157600080fd5b5060a354610368906001600160a01b031681565b3480156105e157600080fd5b5061034c6105f0366004613c09565b6110b5565b34801561060157600080fd5b5061034c610610366004613ce9565b61113d565b34801561062157600080fd5b5061034c610630366004613fbf565b6115c9565b34801561064157600080fd5b50610368610650366004613e87565b6117c2565b34801561066157600080fd5b5061043160685481565b34801561067757600080fd5b5061034c6117ec565b34801561068c57600080fd5b5061034c6118b5565b3480156106a157600080fd5b506033546103689061010090046001600160a01b031681565b3480156106c657600080fd5b5061034c6106d5366004614040565b611a87565b3480156106e657600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b34801561071a57600080fd5b5061034c610729366004613e87565b611e6f565b34801561073a57600080fd5b5061034c610749366004613ce9565b61203a565b34801561075a57600080fd5b5061077e610769366004613e87565b60356020526000908152604090205460ff1681565b60405161037c91906144ab565b34801561079757600080fd5b5061052661215a565b3480156107ac57600080fd5b506105266107bb366004613c09565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0390811691161490565b3480156107f957600080fd5b5061034c610808366004614085565b6121b9565b34801561081957600080fd5b5061034c6122b5565b34801561082e57600080fd5b5061034c61083d366004613f0b565b61237b565b34801561084e57600080fd5b5061034c61085d366004613c09565b6124ee565b34801561086e57600080fd5b5061052661257b565b34801561088357600080fd5b506104316801bc16d674ec80000081565b3480156108a057600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b3480156108d457600080fd5b5061034c6108e3366004613c09565b6125ac565b3480156108f457600080fd5b5061034c610903366004613c7c565b612650565b34801561091457600080fd5b5061034c610923366004613ea0565b6126e3565b34801561093457600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b34801561096857600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b34801561099c57600080fd5b5061034c6128d8565b3480156109b157600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b3480156109e557600080fd5b506109ee612a22565b60405161037c9190614281565b6000610a1360008051602061486d8339815191525490565b905090565b610a2061257b565b610a3c5760405162461bcd60e51b81526004016103439061451d565b610a468282612a84565b5050565b610a5261257b565b610a6e5760405162461bcd60e51b81526004016103439061451d565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b039081169083161415610aeb5760405162461bcd60e51b815260206004820152601f60248201527f43616e6e6f74207472616e7366657220737570706f72746564206173736574006044820152606401610343565b610a46610af66109fb565b6001600160a01b0384169083612be3565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b158015610b6057600080fd5b505afa158015610b74573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b989190613c26565b6001600160a01b0316336001600160a01b031614610bc85760405162461bcd60e51b8152600401610343906145dd565b60405163bc26e7e560e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063bc26e7e590610c1a9030908790879087906004016141d1565b600060405180830381600087803b158015610c3457600080fd5b505af1158015610c48573d6000803e3d6000fd5b50505050505050565b610c5961257b565b610c755760405162461bcd60e51b81526004016103439061451d565b600054610100900460ff1680610c8e575060005460ff16155b610cf15760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610343565b600054610100900460ff16158015610d13576000805461ffff19166101011790555b610d1e848484612c35565b8015610d30576000805461ff00191690555b50505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610d7e5760405162461bcd60e51b8152600401610343906144e6565b60008051602061484d83398151915280546002811415610db05760405162461bcd60e51b8152600401610343906145b5565b600282557f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316846001600160a01b031614610e295760405162461bcd60e51b8152602060048201526011602482015270155b9cdd5c1c1bdc9d195908185cdcd95d607a1b6044820152606401610343565b610e338484612cf0565b50600190555050565b60a3546001600160a01b03163314610e965760405162461bcd60e51b815260206004820152601b60248201527f43616c6c6572206973206e6f74207468652048617276657374657200000000006044820152606401610343565b60008051602061484d83398151915280546002811415610ec85760405162461bcd60e51b8152600401610343906145b5565b60028255610ed4612d82565b5060019055565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b031614610f765760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b6064820152608401610343565b610f7f33612fd0565b565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b031614610ff85760405162461bcd60e51b8152602060048201526011602482015270155b9cdd5c1c1bdc9d195908185cdcd95d607a1b6044820152606401610343565b6040516370a0823160e01b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b15801561105757600080fd5b505afa15801561106b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061108f919061406c565b6034546110a5906801bc16d674ec80000061473e565b6110af9190614704565b92915050565b6110bd61257b565b6110d95760405162461bcd60e51b81526004016103439061451d565b6040516001600160a01b03821681527f83f29c79feb71f8fba9d0fbc4ba5f0982a28b6b1e868b3fc50e6400d100bca0f9060200160405180910390a1603380546001600160a01b0390921661010002610100600160a81b0319909216919091179055565b60335461010090046001600160a01b0316331461116c5760405162461bcd60e51b81526004016103439061457e565b60335460ff161561118f5760405162461bcd60e51b815260040161034390614554565b60006111a4826801bc16d674ec80000061473e565b6040516370a0823160e01b81523060048201529091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b15801561120657600080fd5b505afa15801561121a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061123e919061406c565b8111156112815760405162461bcd60e51b81526020600482015260116024820152700d2dce6eaccccd2c6d2cadce840ae8aa89607b1b6044820152606401610343565b604051632e1a7d4d60e01b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b1580156112e357600080fd5b505af11580156112f7573d6000803e3d6000fd5b5050505060005b82811015610d3057600084848381811061131a5761131a6147fd565b905060200281019061132c919061465a565b6113369080614614565b6040516113449291906141a5565b6040805191829003909120600081815260356020529182205490925060ff1690816003811115611376576113766147d1565b146113c35760405162461bcd60e51b815260206004820152601860248201527f56616c696461746f72206e6f74207265676973746572656400000000000000006044820152606401610343565b60408051600160f81b60208201526000602182018190526bffffffffffffffffffffffff193060601b16602c830152910160405160208183030381529060405290507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663228951186801bc16d674ec800000898988818110611450576114506147fd565b9050602002810190611462919061465a565b61146c9080614614565b858c8c8b81811061147f5761147f6147fd565b9050602002810190611491919061465a565b61149f906020810190614614565b8e8e8d8181106114b1576114b16147fd565b90506020028101906114c3919061465a565b604001356040518863ffffffff1660e01b81526004016114e896959493929190614430565b6000604051808303818588803b15801561150157600080fd5b505af1158015611515573d6000803e3d6000fd5b505050505060016034600082825461152d9190614704565b909155507ffeb31a79d38edb1b090d516e4df3e273651179c6f2c2ec53a9a22ae015b70ba99050878786818110611566576115666147fd565b9050602002810190611578919061465a565b6115829080614614565b6801bc16d674ec8000008460405161159d949392919061447f565b60405180910390a150506000908152603560205260409020805460ff19166001908117909155016112fe565b60335461010090046001600160a01b031633146115f85760405162461bcd60e51b81526004016103439061457e565b60335460ff161561161b5760405162461bcd60e51b815260040161034390614554565b60006035600087876040516116319291906141a5565b604080519182900390912082526020820192909252016000205460ff1690506002816003811115611664576116646147d1565b146116a95760405162461bcd60e51b815260206004820152601560248201527456616c696461746f72206e6f742065786974696e6760581b6044820152606401610343565b6040516312b3fc1960e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906312b3fc19906116fd90899089908990899089906004016143ef565b600060405180830381600087803b15801561171757600080fd5b505af115801561172b573d6000803e3d6000fd5b505050507ff72821b8777f002ccdf6326f1242d9e0f762eb077668b67bebe640535378066d868686866040516117649493929190614366565b60405180910390a160036035600088886040516117829291906141a5565b60408051918290039091208252602082019290925201600020805460ff191660018360038111156117b5576117b56147d1565b0217905550505050505050565b60a481815481106117d257600080fd5b6000918252602090912001546001600160a01b0316905081565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b15801561184557600080fd5b505afa158015611859573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061187d9190613c26565b6001600160a01b0316336001600160a01b0316146118ad5760405162461bcd60e51b8152600401610343906145dd565b610f7f613091565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016148061190457506118ef6109fb565b6001600160a01b0316336001600160a01b0316145b61195c5760405162461bcd60e51b815260206004820152602360248201527f43616c6c6572206973206e6f7420746865205661756c74206f7220476f7665726044820152623737b960e91b6064820152608401610343565b60008051602061484d8339815191528054600281141561198e5760405162461bcd60e51b8152600401610343906145b5565b600282556040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b1580156119f457600080fd5b505afa158015611a08573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a2c919061406c565b90508015611a7f57611a7f7f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000083613106565b505060019055565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b158015611ae057600080fd5b505afa158015611af4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b189190613c26565b6001600160a01b0316336001600160a01b031614611b485760405162461bcd60e51b8152600401610343906145dd565b60335460ff16611b915760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610343565b6002198312158015611ba4575060038313155b8015611bbe5750600083603454611bbb91906146c3565b12155b611c0a5760405162461bcd60e51b815260206004820152601760248201527f696e76616c69642076616c696461746f727344656c74610000000000000000006044820152606401610343565b6811ff6cf0fd15afffff198212158015611c2d57506811ff6cf0fd15b000008213155b8015611c475750600082606854611c4491906146c3565b12155b611c935760405162461bcd60e51b815260206004820152601d60248201527f696e76616c696420636f6e73656e7375735265776172647344656c74610000006044820152606401610343565b6801bc16d674ec800000811115611cec5760405162461bcd60e51b815260206004820152601960248201527f696e76616c69642077657468546f5661756c74416d6f756e74000000000000006044820152606401610343565b60408051848152602081018490529081018290527f80d022717ea022455c5886b8dd8a29c037570aae58aeb4d7b136d7a10ec2e4319060600160405180910390a182603454611d3b91906146c3565b603455606854611d4c9083906146c3565b6068558015611e195760405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018390527f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb90604401602060405180830381600087803b158015611ddf57600080fd5b505af1158015611df3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e179190613e6a565b505b611e2360006131fe565b611e625760405162461bcd60e51b815260206004820152601060248201526f333ab9b29039ba34b63610313637bbb760811b6044820152606401610343565b611e6a613684565b505050565b611e7761257b565b611e935760405162461bcd60e51b81526004016103439061451d565b60a0548110611ed45760405162461bcd60e51b815260206004820152600d60248201526c092dcecc2d8d2c840d2dcc8caf609b1b6044820152606401610343565b600060a08281548110611ee957611ee96147fd565b60009182526020808320909101546001600160a01b03908116808452609f90925260409092205460a05491935090911690611f269060019061475d565b831015611fa85760a08054611f3d9060019061475d565b81548110611f4d57611f4d6147fd565b60009182526020909120015460a080546001600160a01b039092169185908110611f7957611f796147fd565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505b60a0805480611fb957611fb96147e7565b60008281526020808220600019908401810180546001600160a01b031990811690915593019093556001600160a01b03858116808352609f855260409283902080549094169093559051908416815290917f16b7600acff27e39a8a96056b3d533045298de927507f5c1d97e4accde60488c910160405180910390a2505050565b61204261257b565b61205e5760405162461bcd60e51b81526004016103439061451d565b8060005b8181101561211157600084848381811061207e5761207e6147fd565b90506020020160208101906120939190613c09565b6001600160a01b031614156121015760405162461bcd60e51b815260206004820152602e60248201527f43616e206e6f742073657420616e20656d70747920616464726573732061732060448201526d30903932bbb0b932103a37b5b2b760911b6064820152608401610343565b61210a816147a0565b9050612062565b507f04c0b9649497d316554306e53678d5f5f5dbc3a06f97dec13ff4cfe98b986bbc60a48484604051612146939291906142ce565b60405180910390a1610d3060a48484613962565b60335460009061010090046001600160a01b0316331461218c5760405162461bcd60e51b81526004016103439061457e565b60335460ff16156121af5760405162461bcd60e51b815260040161034390614554565b610a1360016131fe565b6121c161257b565b6121dd5760405162461bcd60e51b81526004016103439061451d565b80821080156121f457506801bc16d674ec80000082105b801561220857506801bc16d674ec80000081105b80156122255750673782dace9d900000612222838361475d565b10155b6122715760405162461bcd60e51b815260206004820152601760248201527f696e636f7272656374206675736520696e74657276616c0000000000000000006044820152606401610343565b60408051838152602081018390527fcb8d24e46eb3c402bf344ee60a6576cba9ef2f59ea1af3b311520704924e901a910160405180910390a1606991909155606a55565b60405163095ea7b360e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015260001960248301527f0000000000000000000000000000000000000000000000000000000000000000169063095ea7b390604401602060405180830381600087803b15801561234057600080fd5b505af1158015612354573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123789190613e6a565b50565b60335461010090046001600160a01b031633146123aa5760405162461bcd60e51b81526004016103439061457e565b60335460ff16156123cd5760405162461bcd60e51b815260040161034390614554565b6040516301ba3ee760e21b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906306e8fb9c90612427908b908b908b908b908b908b908b908b9060040161438d565b600060405180830381600087803b15801561244157600080fd5b505af1158015612455573d6000803e3d6000fd5b505050506000603560008a8a60405161246f9291906141a5565b60408051918290039091208252602082019290925201600020805460ff191660018360038111156124a2576124a26147d1565b02179055507f75c4a66b2c6c28cf46db7131182a812e4fbbb2f0591377aa83a737909a9b68c3888888886040516124dc9493929190614366565b60405180910390a15050505050505050565b6124f661257b565b6125125760405162461bcd60e51b81526004016103439061451d565b60a354604080516001600160a01b03928316815291831660208301527fe48386b84419f4d36e0f96c10cc3510b6fb1a33795620c5098b22472bbe90796910160405180910390a160a380546001600160a01b0319166001600160a01b0392909216919091179055565b600061259360008051602061486d8339815191525490565b6001600160a01b0316336001600160a01b031614905090565b6125b461257b565b6125d05760405162461bcd60e51b81526004016103439061451d565b6125f8817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b031661261860008051602061486d8339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146126985760405162461bcd60e51b8152600401610343906144e6565b60008051602061484d833981519152805460028114156126ca5760405162461bcd60e51b8152600401610343906145b5565b600282556126d9858585613106565b5060019055505050565b60335461010090046001600160a01b031633146127125760405162461bcd60e51b81526004016103439061457e565b60335460ff16156127355760405162461bcd60e51b815260040161034390614554565b600060356000868660405161274b9291906141a5565b604080519182900390912082526020820192909252016000205460ff169050600181600381111561277e5761277e6147d1565b146127c25760405162461bcd60e51b815260206004820152601460248201527315985b1a59185d1bdc881b9bdd081cdd185ad95960621b6044820152606401610343565b604051633877322b60e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690633877322b90612814908890889088908890600401614366565b600060405180830381600087803b15801561282e57600080fd5b505af1158015612842573d6000803e3d6000fd5b505050507ff8821da16f5ed966b41e0343c3eff9903af782d74f99f1689dd9d4562b6545b38585858560405161287b9493929190614366565b60405180910390a160026035600087876040516128999291906141a5565b60408051918290039091208252602082019290925201600020805460ff191660018360038111156128cc576128cc6147d1565b02179055505050505050565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146129205760405162461bcd60e51b8152600401610343906144e6565b60008051602061484d833981519152805460028114156129525760405162461bcd60e51b8152600401610343906145b5565b600282556040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b1580156129b857600080fd5b505afa1580156129cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129f0919061406c565b90508015611a7f57611a7f7f000000000000000000000000000000000000000000000000000000000000000082612cf0565b606060a4805480602002602001604051908101604052809291908181526020018280548015612a7a57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612a5c575b5050505050905090565b6001600160a01b038281166000908152609f60205260409020541615612ae15760405162461bcd60e51b81526020600482015260126024820152711c151bdad95b88185b1c9958591e481cd95d60721b6044820152606401610343565b6001600160a01b03821615801590612b0157506001600160a01b03811615155b612b415760405162461bcd60e51b8152602060048201526011602482015270496e76616c69642061646472657373657360781b6044820152606401610343565b6001600160a01b038281166000818152609f6020908152604080832080549587166001600160a01b0319968716811790915560a0805460018101825594527f78fdc8d422c49ced035a9edf18d00d3c6a8d81df210f3e5e448e045e77b41e8890930180549095168417909455925190815290917fef6485b84315f9b1483beffa32aae9a0596890395e3d7521f1c5fbb51790e765910160405180910390a25050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052611e6a9084906136fe565b8251612c489060a49060208601906139c5565b50815181518114612c925760405162461bcd60e51b8152602060048201526014602482015273496e76616c696420696e7075742061727261797360601b6044820152606401610343565b60005b81811015612ce957612cd9848281518110612cb257612cb26147fd565b6020026020010151848381518110612ccc57612ccc6147fd565b6020026020010151612a84565b612ce2816147a0565b9050612c95565b5050505050565b60008111612d395760405162461bcd60e51b81526020600482015260166024820152754d757374206465706f73697420736f6d657468696e6760501b6044820152606401610343565b6040805160008152602081018390526001600160a01b038416917f5548c837ab068cf56a2c2479df0882a4922fd203edb7517321831d95078c5f62910160405180910390a25050565b60335460ff1615612da55760405162461bcd60e51b815260040161034390614554565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663e52253816040518163ffffffff1660e01b8152600401602060405180830381600087803b158015612e0257600080fd5b505af1158015612e16573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e3a919061406c565b9050600060685482612e4c9190614704565b905080471015612e9e5760405162461bcd60e51b815260206004820152601860248201527f696e73756666696369656e74206574682062616c616e636500000000000000006044820152606401610343565b8015610a465760006068819055507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b158015612f0757600080fd5b505af1158015612f1b573d6000803e3d6000fd5b505060a354604080516001600160a01b0392831681527f0000000000000000000000000000000000000000000000000000000000000000909216602083015281018590527ff6c07a063ed4e63808eb8da7112d46dbcd38de2b40a73dbcc9353c5a94c7235393506060019150612f8e9050565b60405180910390a160a354610a46906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116911683612be3565b6001600160a01b0381166130265760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f7220697320616464726573732830290000000000006044820152606401610343565b806001600160a01b031661304660008051602061486d8339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a36123788160008051602061486d83398151915255565b60335460ff16156130b45760405162461bcd60e51b815260040161034390614554565b6033805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586130e93390565b6040516001600160a01b03909116815260200160405180910390a1565b600081116131565760405162461bcd60e51b815260206004820152601760248201527f4d75737420776974686472617720736f6d657468696e670000000000000000006044820152606401610343565b6001600160a01b0383166131a55760405162461bcd60e51b8152602060048201526016602482015275135d5cdd081cdc1958da599e481c9958da5c1a595b9d60521b6044820152606401610343565b6040805160008152602081018390526001600160a01b038416917f2717ead6b9200dd235aad468c9809ea400fe33ac69b5bfaa6d3e90fc922b6398910160405180910390a2611e6a6001600160a01b0383168483612be3565b6000606854471015613213576110af826137d0565b600060685447613223919061475d565b9050600191506801bc16d674ec800000811061341957600061324e6801bc16d674ec8000008361471c565b905080603454101561326b57613263846137d0565b949350505050565b806034600082825461327d919061475d565b9091555060009050613298826801bc16d674ec80000061473e565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b1580156132f557600080fd5b505af1158015613309573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb92506044019050602060405180830381600087803b15801561339957600080fd5b505af11580156133ad573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133d19190613e6a565b5060345460408051848152602081019290925281018290527fbe7040030ff7b347853214bf49820c6d455fedf58f3815f85c7bc5216993682b9060600160405180910390a150505b600060685447613429919061475d565b90506801bc16d674ec800000811061347b5760405162461bcd60e51b8152602060048201526015602482015274756e6578706563746564206163636f756e74696e6760581b6044820152606401610343565b80613487575050919050565b6069548110156134e15780606860008282546134a39190614704565b90915550506040518181527f7a745a2c63a535068f52ceca27debd5297bbad5f7f37ec53d044a59d0362445d906020015b60405180910390a161367d565b606a54811115613674577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b15801561354657600080fd5b505af115801561355a573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb92506044019050602060405180830381600087803b1580156135ea57600080fd5b505af11580156135fe573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136229190613e6a565b50600160346000828254613636919061475d565b909155505060345460408051918252602082018390527f6aa7e30787b26429ced603a7aba8b19c4b5d5bcf29a3257da953c8d53bcaa3a691016134d4565b613263846137d0565b5050919050565b60335460ff166136cd5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610343565b6033805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa336130e9565b6000613753826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166137e89092919063ffffffff16565b805190915015611e6a57808060200190518101906137719190613e6a565b611e6a5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610343565b600081156137e0576137e0613091565b506000919050565b60606137f78484600085613801565b90505b9392505050565b6060824710156138625760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610343565b843b6138b05760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610343565b600080866001600160a01b031685876040516138cc91906141b5565b60006040518083038185875af1925050503d8060008114613909576040519150601f19603f3d011682016040523d82523d6000602084013e61390e565b606091505b509150915061391e828286613929565b979650505050505050565b606083156139385750816137fa565b8251156139485782518084602001fd5b8160405162461bcd60e51b815260040161034391906144d3565b8280548282559060005260206000209081019282156139b5579160200282015b828111156139b55781546001600160a01b0319166001600160a01b03843516178255602090920191600190910190613982565b506139c1929150613a1a565b5090565b8280548282559060005260206000209081019282156139b5579160200282015b828111156139b557825182546001600160a01b0319166001600160a01b039091161782556020909201916001909101906139e5565b5b808211156139c15760008155600101613a1b565b60008083601f840112613a4157600080fd5b5081356001600160401b03811115613a5857600080fd5b6020830191508360208260051b8501011115613a7357600080fd5b9250929050565b600082601f830112613a8b57600080fd5b81356020613aa0613a9b836146a0565b614670565b80838252828201915082860187848660051b8901011115613ac057600080fd5b60005b85811015613ae8578135613ad681614829565b84529284019290840190600101613ac3565b5090979650505050505050565b60008083601f840112613b0757600080fd5b5081356001600160401b03811115613b1e57600080fd5b602083019150836020828501011115613a7357600080fd5b600060a08284031215613b4857600080fd5b50919050565b600060a08284031215613b6057600080fd5b60405160a081018181106001600160401b0382111715613b8257613b82614813565b604052905080613b9183613bd9565b8152613b9f60208401613bf2565b6020820152613bb060408401613bf2565b60408201526060830135613bc38161483e565b6060820152608092830135920191909152919050565b803563ffffffff81168114613bed57600080fd5b919050565b80356001600160401b0381168114613bed57600080fd5b600060208284031215613c1b57600080fd5b81356137fa81614829565b600060208284031215613c3857600080fd5b81516137fa81614829565b60008060408385031215613c5657600080fd5b8235613c6181614829565b91506020830135613c7181614829565b809150509250929050565b600080600060608486031215613c9157600080fd5b8335613c9c81614829565b92506020840135613cac81614829565b929592945050506040919091013590565b60008060408385031215613cd057600080fd5b8235613cdb81614829565b946020939093013593505050565b60008060208385031215613cfc57600080fd5b82356001600160401b03811115613d1257600080fd5b613d1e85828601613a2f565b90969095509350505050565b600080600060608486031215613d3f57600080fd5b83356001600160401b0380821115613d5657600080fd5b613d6287838801613a7a565b94506020860135915080821115613d7857600080fd5b613d8487838801613a7a565b93506040860135915080821115613d9a57600080fd5b50613da786828701613a7a565b9150509250925092565b600080600060e08486031215613dc657600080fd5b83356001600160401b03811115613ddc57600080fd5b8401601f81018613613ded57600080fd5b80356020613dfd613a9b836146a0565b8083825282820191508285018a848660051b8801011115613e1d57600080fd5b600095505b84861015613e4757613e3381613bf2565b835260019590950194918301918301613e22565b509650508601359350613e61915086905060408601613b4e565b90509250925092565b600060208284031215613e7c57600080fd5b81516137fa8161483e565b600060208284031215613e9957600080fd5b5035919050565b60008060008060408587031215613eb657600080fd5b84356001600160401b0380821115613ecd57600080fd5b613ed988838901613af5565b90965094506020870135915080821115613ef257600080fd5b50613eff87828801613a2f565b95989497509550505050565b600080600080600080600080610120898b031215613f2857600080fd5b88356001600160401b0380821115613f3f57600080fd5b613f4b8c838d01613af5565b909a50985060208b0135915080821115613f6457600080fd5b613f708c838d01613a2f565b909850965060408b0135915080821115613f8957600080fd5b50613f968b828c01613af5565b90955093505060608901359150613fb08a60808b01613b36565b90509295985092959890939650565b600080600080600060e08688031215613fd757600080fd5b85356001600160401b0380821115613fee57600080fd5b613ffa89838a01613af5565b9097509550602088013591508082111561401357600080fd5b5061402088828901613a2f565b909450925061403490508760408801613b36565b90509295509295909350565b60008060006060848603121561405557600080fd5b505081359360208301359350604090920135919050565b60006020828403121561407e57600080fd5b5051919050565b6000806040838503121561409857600080fd5b50508035926020909101359150565b8183526000602080850194508260005b858110156140e3576001600160401b036140d083613bf2565b16875295820195908201906001016140b7565b509495945050505050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6000815180845261412f816020860160208601614774565b601f01601f19169290920160200192915050565b63ffffffff61415182613bd9565b16825261416060208201613bf2565b6001600160401b0380821660208501528061417d60408501613bf2565b166040850152505060608101356141938161483e565b15156060830152608090810135910152565b8183823760009101908152919050565b600082516141c7818460208701614774565b9190910192915050565b6001600160a01b03851681526101006020808301829052855191830182905260009161012084019187810191845b818110156142245783516001600160401b0316855293820193928201926001016141ff565b505082935086604086015263ffffffff865116606086015280860151925050506001600160401b0380821660808501528060408601511660a085015250506060830151151560c0830152608083015160e083015295945050505050565b6020808252825182820181905260009190848201906040850190845b818110156142c25783516001600160a01b03168352928401929184019160010161429d565b50909695505050505050565b6000604082016040835280865480835260608501915087600052602092508260002060005b828110156143185781546001600160a01b0316845292840192600191820191016142f3565b505050838103828501528481528590820160005b8681101561435a57823561433f81614829565b6001600160a01b03168252918301919083019060010161432c565b50979650505050505050565b60408152600061437a6040830186886140ee565b828103602084015261391e8185876140a7565b60006101208083526143a28184018b8d6140ee565b905082810360208401526143b781898b6140a7565b905082810360408401526143cc8187896140ee565b9150508360608301526143e26080830184614143565b9998505050505050505050565b60e08152600061440360e0830187896140ee565b82810360208401526144168186886140a7565b9150506144266040830184614143565b9695505050505050565b60808152600061444460808301888a6140ee565b82810360208401526144568188614117565b9050828103604084015261446b8186886140ee565b915050826060830152979650505050505050565b6060815260006144936060830186886140ee565b846020840152828103604084015261391e8185614117565b60208101600483106144cd57634e487b7160e01b600052602160045260246000fd5b91905290565b6020815260006137fa6020830184614117565b60208082526017908201527f43616c6c6572206973206e6f7420746865205661756c74000000000000000000604082015260600190565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b60208082526010908201526f14185d5cd8589b194e881c185d5cd95960821b604082015260600190565b6020808252601d908201527f43616c6c6572206973206e6f7420746865205265676973747261746f72000000604082015260600190565b6020808252600e908201526d1499595b9d1c985b9d0818d85b1b60921b604082015260600190565b6020808252601c908201527f43616c6c6572206973206e6f7420746865205374726174656769737400000000604082015260600190565b6000808335601e1984360301811261462b57600080fd5b8301803591506001600160401b0382111561464557600080fd5b602001915036819003821315613a7357600080fd5b60008235605e198336030181126141c757600080fd5b604051601f8201601f191681016001600160401b038111828210171561469857614698614813565b604052919050565b60006001600160401b038211156146b9576146b9614813565b5060051b60200190565b600080821280156001600160ff1b03849003851316156146e5576146e56147bb565b600160ff1b83900384128116156146fe576146fe6147bb565b50500190565b60008219821115614717576147176147bb565b500190565b60008261473957634e487b7160e01b600052601260045260246000fd5b500490565b6000816000190483118215151615614758576147586147bb565b500290565b60008282101561476f5761476f6147bb565b500390565b60005b8381101561478f578181015183820152602001614777565b83811115610d305750506000910152565b60006000198214156147b4576147b46147bb565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b038116811461237857600080fd5b801515811461237857600080fdfe53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac45357bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa2646970667358221220113919d09ddf52cbaf34c41b4ba31e1d6e98f959c68a6c638232aecc6636f9ac64736f6c634300080700337bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a", - "deployedBytecode": "0x6080604052600436106102975760003560e01c8063853828b61161015a578063c2e1e3f4116100c1578063d9f00ec71161007a578063d9f00ec714610908578063dbe55e5614610928578063dd505df61461095c578063de5f626814610990578063f1188e40146109a5578063f6ca71b0146109d957600080fd5b8063c2e1e3f414610842578063c7af335214610862578063c98517c514610877578063cceab75014610894578063d38bfff4146108c8578063d9caed12146108e857600080fd5b80639da0e462116101135780639da0e4621461074e578063a4f98af41461078b578063aa388af6146107a0578063ab12edf5146107ed578063ad1728cb1461080d578063bb1b918d1461082257600080fd5b8063853828b61461068057806387bae867146106955780638d7c0e46146106ba5780639092c31c146106da5780639136616a1461070e57806396d538bb1461072e57600080fd5b80635c975abb116101fe5780636e811d38116101b75780636e811d38146105d55780636ef38795146105f557806371a735f3146106155780637b2d9b2c14610635578063842f5c46146106555780638456cb591461066b57600080fd5b80635c975abb146105125780635d36b190146105365780635f5152261461054b5780636093d3801461056b57806366e3667e1461059f57806367c7066c146105b557600080fd5b8063430bf08a11610250578063430bf08a1461043f578063435356d11461047357806347e7ef2414610493578063484be812146104b3578063579a7e1a146104c95780635a063f63146104fd57600080fd5b80630c340a24146103535780630ed57b3a146103855780630fc3b4c4146103a55780631072cbea146103db57806322495dc8146103fb5780633c8649591461041b57600080fd5b3661034e57336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614806102fb5750336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016145b61034c5760405162461bcd60e51b815260206004820152601e60248201527f657468206e6f742066726f6d20616c6c6f77656420636f6e747261637473000060448201526064015b60405180910390fd5b005b600080fd5b34801561035f57600080fd5b506103686109fb565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561039157600080fd5b5061034c6103a0366004613c43565b610a18565b3480156103b157600080fd5b506103686103c0366004613c09565b609f602052600090815260409020546001600160a01b031681565b3480156103e757600080fd5b5061034c6103f6366004613cbd565b610a4a565b34801561040757600080fd5b5061034c610416366004613db1565b610b07565b34801561042757600080fd5b5061043160695481565b60405190815260200161037c565b34801561044b57600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b34801561047f57600080fd5b5061034c61048e366004613d2a565b610c51565b34801561049f57600080fd5b5061034c6104ae366004613cbd565b610d36565b3480156104bf57600080fd5b50610431606a5481565b3480156104d557600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b34801561050957600080fd5b5061034c610e3c565b34801561051e57600080fd5b5060335460ff165b604051901515815260200161037c565b34801561054257600080fd5b5061034c610edb565b34801561055757600080fd5b50610431610566366004613c09565b610f81565b34801561057757600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b3480156105ab57600080fd5b5061043160345481565b3480156105c157600080fd5b5060a354610368906001600160a01b031681565b3480156105e157600080fd5b5061034c6105f0366004613c09565b6110b5565b34801561060157600080fd5b5061034c610610366004613ce9565b61113d565b34801561062157600080fd5b5061034c610630366004613fbf565b6115c9565b34801561064157600080fd5b50610368610650366004613e87565b6117c2565b34801561066157600080fd5b5061043160685481565b34801561067757600080fd5b5061034c6117ec565b34801561068c57600080fd5b5061034c6118b5565b3480156106a157600080fd5b506033546103689061010090046001600160a01b031681565b3480156106c657600080fd5b5061034c6106d5366004614040565b611a87565b3480156106e657600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b34801561071a57600080fd5b5061034c610729366004613e87565b611e6f565b34801561073a57600080fd5b5061034c610749366004613ce9565b61203a565b34801561075a57600080fd5b5061077e610769366004613e87565b60356020526000908152604090205460ff1681565b60405161037c91906144ab565b34801561079757600080fd5b5061052661215a565b3480156107ac57600080fd5b506105266107bb366004613c09565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0390811691161490565b3480156107f957600080fd5b5061034c610808366004614085565b6121b9565b34801561081957600080fd5b5061034c6122b5565b34801561082e57600080fd5b5061034c61083d366004613f0b565b61237b565b34801561084e57600080fd5b5061034c61085d366004613c09565b6124ee565b34801561086e57600080fd5b5061052661257b565b34801561088357600080fd5b506104316801bc16d674ec80000081565b3480156108a057600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b3480156108d457600080fd5b5061034c6108e3366004613c09565b6125ac565b3480156108f457600080fd5b5061034c610903366004613c7c565b612650565b34801561091457600080fd5b5061034c610923366004613ea0565b6126e3565b34801561093457600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b34801561096857600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b34801561099c57600080fd5b5061034c6128d8565b3480156109b157600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b3480156109e557600080fd5b506109ee612a22565b60405161037c9190614281565b6000610a1360008051602061486d8339815191525490565b905090565b610a2061257b565b610a3c5760405162461bcd60e51b81526004016103439061451d565b610a468282612a84565b5050565b610a5261257b565b610a6e5760405162461bcd60e51b81526004016103439061451d565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b039081169083161415610aeb5760405162461bcd60e51b815260206004820152601f60248201527f43616e6e6f74207472616e7366657220737570706f72746564206173736574006044820152606401610343565b610a46610af66109fb565b6001600160a01b0384169083612be3565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b158015610b6057600080fd5b505afa158015610b74573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b989190613c26565b6001600160a01b0316336001600160a01b031614610bc85760405162461bcd60e51b8152600401610343906145dd565b60405163bc26e7e560e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063bc26e7e590610c1a9030908790879087906004016141d1565b600060405180830381600087803b158015610c3457600080fd5b505af1158015610c48573d6000803e3d6000fd5b50505050505050565b610c5961257b565b610c755760405162461bcd60e51b81526004016103439061451d565b600054610100900460ff1680610c8e575060005460ff16155b610cf15760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610343565b600054610100900460ff16158015610d13576000805461ffff19166101011790555b610d1e848484612c35565b8015610d30576000805461ff00191690555b50505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610d7e5760405162461bcd60e51b8152600401610343906144e6565b60008051602061484d83398151915280546002811415610db05760405162461bcd60e51b8152600401610343906145b5565b600282557f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316846001600160a01b031614610e295760405162461bcd60e51b8152602060048201526011602482015270155b9cdd5c1c1bdc9d195908185cdcd95d607a1b6044820152606401610343565b610e338484612cf0565b50600190555050565b60a3546001600160a01b03163314610e965760405162461bcd60e51b815260206004820152601b60248201527f43616c6c6572206973206e6f74207468652048617276657374657200000000006044820152606401610343565b60008051602061484d83398151915280546002811415610ec85760405162461bcd60e51b8152600401610343906145b5565b60028255610ed4612d82565b5060019055565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b031614610f765760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b6064820152608401610343565b610f7f33612fd0565b565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b031614610ff85760405162461bcd60e51b8152602060048201526011602482015270155b9cdd5c1c1bdc9d195908185cdcd95d607a1b6044820152606401610343565b6040516370a0823160e01b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b15801561105757600080fd5b505afa15801561106b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061108f919061406c565b6034546110a5906801bc16d674ec80000061473e565b6110af9190614704565b92915050565b6110bd61257b565b6110d95760405162461bcd60e51b81526004016103439061451d565b6040516001600160a01b03821681527f83f29c79feb71f8fba9d0fbc4ba5f0982a28b6b1e868b3fc50e6400d100bca0f9060200160405180910390a1603380546001600160a01b0390921661010002610100600160a81b0319909216919091179055565b60335461010090046001600160a01b0316331461116c5760405162461bcd60e51b81526004016103439061457e565b60335460ff161561118f5760405162461bcd60e51b815260040161034390614554565b60006111a4826801bc16d674ec80000061473e565b6040516370a0823160e01b81523060048201529091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b15801561120657600080fd5b505afa15801561121a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061123e919061406c565b8111156112815760405162461bcd60e51b81526020600482015260116024820152700d2dce6eaccccd2c6d2cadce840ae8aa89607b1b6044820152606401610343565b604051632e1a7d4d60e01b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b1580156112e357600080fd5b505af11580156112f7573d6000803e3d6000fd5b5050505060005b82811015610d3057600084848381811061131a5761131a6147fd565b905060200281019061132c919061465a565b6113369080614614565b6040516113449291906141a5565b6040805191829003909120600081815260356020529182205490925060ff1690816003811115611376576113766147d1565b146113c35760405162461bcd60e51b815260206004820152601860248201527f56616c696461746f72206e6f74207265676973746572656400000000000000006044820152606401610343565b60408051600160f81b60208201526000602182018190526bffffffffffffffffffffffff193060601b16602c830152910160405160208183030381529060405290507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663228951186801bc16d674ec800000898988818110611450576114506147fd565b9050602002810190611462919061465a565b61146c9080614614565b858c8c8b81811061147f5761147f6147fd565b9050602002810190611491919061465a565b61149f906020810190614614565b8e8e8d8181106114b1576114b16147fd565b90506020028101906114c3919061465a565b604001356040518863ffffffff1660e01b81526004016114e896959493929190614430565b6000604051808303818588803b15801561150157600080fd5b505af1158015611515573d6000803e3d6000fd5b505050505060016034600082825461152d9190614704565b909155507ffeb31a79d38edb1b090d516e4df3e273651179c6f2c2ec53a9a22ae015b70ba99050878786818110611566576115666147fd565b9050602002810190611578919061465a565b6115829080614614565b6801bc16d674ec8000008460405161159d949392919061447f565b60405180910390a150506000908152603560205260409020805460ff19166001908117909155016112fe565b60335461010090046001600160a01b031633146115f85760405162461bcd60e51b81526004016103439061457e565b60335460ff161561161b5760405162461bcd60e51b815260040161034390614554565b60006035600087876040516116319291906141a5565b604080519182900390912082526020820192909252016000205460ff1690506002816003811115611664576116646147d1565b146116a95760405162461bcd60e51b815260206004820152601560248201527456616c696461746f72206e6f742065786974696e6760581b6044820152606401610343565b6040516312b3fc1960e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906312b3fc19906116fd90899089908990899089906004016143ef565b600060405180830381600087803b15801561171757600080fd5b505af115801561172b573d6000803e3d6000fd5b505050507ff72821b8777f002ccdf6326f1242d9e0f762eb077668b67bebe640535378066d868686866040516117649493929190614366565b60405180910390a160036035600088886040516117829291906141a5565b60408051918290039091208252602082019290925201600020805460ff191660018360038111156117b5576117b56147d1565b0217905550505050505050565b60a481815481106117d257600080fd5b6000918252602090912001546001600160a01b0316905081565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b15801561184557600080fd5b505afa158015611859573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061187d9190613c26565b6001600160a01b0316336001600160a01b0316146118ad5760405162461bcd60e51b8152600401610343906145dd565b610f7f613091565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016148061190457506118ef6109fb565b6001600160a01b0316336001600160a01b0316145b61195c5760405162461bcd60e51b815260206004820152602360248201527f43616c6c6572206973206e6f7420746865205661756c74206f7220476f7665726044820152623737b960e91b6064820152608401610343565b60008051602061484d8339815191528054600281141561198e5760405162461bcd60e51b8152600401610343906145b5565b600282556040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b1580156119f457600080fd5b505afa158015611a08573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a2c919061406c565b90508015611a7f57611a7f7f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000083613106565b505060019055565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b158015611ae057600080fd5b505afa158015611af4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b189190613c26565b6001600160a01b0316336001600160a01b031614611b485760405162461bcd60e51b8152600401610343906145dd565b60335460ff16611b915760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610343565b6002198312158015611ba4575060038313155b8015611bbe5750600083603454611bbb91906146c3565b12155b611c0a5760405162461bcd60e51b815260206004820152601760248201527f696e76616c69642076616c696461746f727344656c74610000000000000000006044820152606401610343565b6811ff6cf0fd15afffff198212158015611c2d57506811ff6cf0fd15b000008213155b8015611c475750600082606854611c4491906146c3565b12155b611c935760405162461bcd60e51b815260206004820152601d60248201527f696e76616c696420636f6e73656e7375735265776172647344656c74610000006044820152606401610343565b6801bc16d674ec800000811115611cec5760405162461bcd60e51b815260206004820152601960248201527f696e76616c69642077657468546f5661756c74416d6f756e74000000000000006044820152606401610343565b60408051848152602081018490529081018290527f80d022717ea022455c5886b8dd8a29c037570aae58aeb4d7b136d7a10ec2e4319060600160405180910390a182603454611d3b91906146c3565b603455606854611d4c9083906146c3565b6068558015611e195760405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018390527f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb90604401602060405180830381600087803b158015611ddf57600080fd5b505af1158015611df3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e179190613e6a565b505b611e2360006131fe565b611e625760405162461bcd60e51b815260206004820152601060248201526f333ab9b29039ba34b63610313637bbb760811b6044820152606401610343565b611e6a613684565b505050565b611e7761257b565b611e935760405162461bcd60e51b81526004016103439061451d565b60a0548110611ed45760405162461bcd60e51b815260206004820152600d60248201526c092dcecc2d8d2c840d2dcc8caf609b1b6044820152606401610343565b600060a08281548110611ee957611ee96147fd565b60009182526020808320909101546001600160a01b03908116808452609f90925260409092205460a05491935090911690611f269060019061475d565b831015611fa85760a08054611f3d9060019061475d565b81548110611f4d57611f4d6147fd565b60009182526020909120015460a080546001600160a01b039092169185908110611f7957611f796147fd565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505b60a0805480611fb957611fb96147e7565b60008281526020808220600019908401810180546001600160a01b031990811690915593019093556001600160a01b03858116808352609f855260409283902080549094169093559051908416815290917f16b7600acff27e39a8a96056b3d533045298de927507f5c1d97e4accde60488c910160405180910390a2505050565b61204261257b565b61205e5760405162461bcd60e51b81526004016103439061451d565b8060005b8181101561211157600084848381811061207e5761207e6147fd565b90506020020160208101906120939190613c09565b6001600160a01b031614156121015760405162461bcd60e51b815260206004820152602e60248201527f43616e206e6f742073657420616e20656d70747920616464726573732061732060448201526d30903932bbb0b932103a37b5b2b760911b6064820152608401610343565b61210a816147a0565b9050612062565b507f04c0b9649497d316554306e53678d5f5f5dbc3a06f97dec13ff4cfe98b986bbc60a48484604051612146939291906142ce565b60405180910390a1610d3060a48484613962565b60335460009061010090046001600160a01b0316331461218c5760405162461bcd60e51b81526004016103439061457e565b60335460ff16156121af5760405162461bcd60e51b815260040161034390614554565b610a1360016131fe565b6121c161257b565b6121dd5760405162461bcd60e51b81526004016103439061451d565b80821080156121f457506801bc16d674ec80000082105b801561220857506801bc16d674ec80000081105b80156122255750673782dace9d900000612222838361475d565b10155b6122715760405162461bcd60e51b815260206004820152601760248201527f696e636f7272656374206675736520696e74657276616c0000000000000000006044820152606401610343565b60408051838152602081018390527fcb8d24e46eb3c402bf344ee60a6576cba9ef2f59ea1af3b311520704924e901a910160405180910390a1606991909155606a55565b60405163095ea7b360e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015260001960248301527f0000000000000000000000000000000000000000000000000000000000000000169063095ea7b390604401602060405180830381600087803b15801561234057600080fd5b505af1158015612354573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123789190613e6a565b50565b60335461010090046001600160a01b031633146123aa5760405162461bcd60e51b81526004016103439061457e565b60335460ff16156123cd5760405162461bcd60e51b815260040161034390614554565b6040516301ba3ee760e21b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906306e8fb9c90612427908b908b908b908b908b908b908b908b9060040161438d565b600060405180830381600087803b15801561244157600080fd5b505af1158015612455573d6000803e3d6000fd5b505050506000603560008a8a60405161246f9291906141a5565b60408051918290039091208252602082019290925201600020805460ff191660018360038111156124a2576124a26147d1565b02179055507f75c4a66b2c6c28cf46db7131182a812e4fbbb2f0591377aa83a737909a9b68c3888888886040516124dc9493929190614366565b60405180910390a15050505050505050565b6124f661257b565b6125125760405162461bcd60e51b81526004016103439061451d565b60a354604080516001600160a01b03928316815291831660208301527fe48386b84419f4d36e0f96c10cc3510b6fb1a33795620c5098b22472bbe90796910160405180910390a160a380546001600160a01b0319166001600160a01b0392909216919091179055565b600061259360008051602061486d8339815191525490565b6001600160a01b0316336001600160a01b031614905090565b6125b461257b565b6125d05760405162461bcd60e51b81526004016103439061451d565b6125f8817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b031661261860008051602061486d8339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146126985760405162461bcd60e51b8152600401610343906144e6565b60008051602061484d833981519152805460028114156126ca5760405162461bcd60e51b8152600401610343906145b5565b600282556126d9858585613106565b5060019055505050565b60335461010090046001600160a01b031633146127125760405162461bcd60e51b81526004016103439061457e565b60335460ff16156127355760405162461bcd60e51b815260040161034390614554565b600060356000868660405161274b9291906141a5565b604080519182900390912082526020820192909252016000205460ff169050600181600381111561277e5761277e6147d1565b146127c25760405162461bcd60e51b815260206004820152601460248201527315985b1a59185d1bdc881b9bdd081cdd185ad95960621b6044820152606401610343565b604051633877322b60e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690633877322b90612814908890889088908890600401614366565b600060405180830381600087803b15801561282e57600080fd5b505af1158015612842573d6000803e3d6000fd5b505050507ff8821da16f5ed966b41e0343c3eff9903af782d74f99f1689dd9d4562b6545b38585858560405161287b9493929190614366565b60405180910390a160026035600087876040516128999291906141a5565b60408051918290039091208252602082019290925201600020805460ff191660018360038111156128cc576128cc6147d1565b02179055505050505050565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146129205760405162461bcd60e51b8152600401610343906144e6565b60008051602061484d833981519152805460028114156129525760405162461bcd60e51b8152600401610343906145b5565b600282556040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b1580156129b857600080fd5b505afa1580156129cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129f0919061406c565b90508015611a7f57611a7f7f000000000000000000000000000000000000000000000000000000000000000082612cf0565b606060a4805480602002602001604051908101604052809291908181526020018280548015612a7a57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612a5c575b5050505050905090565b6001600160a01b038281166000908152609f60205260409020541615612ae15760405162461bcd60e51b81526020600482015260126024820152711c151bdad95b88185b1c9958591e481cd95d60721b6044820152606401610343565b6001600160a01b03821615801590612b0157506001600160a01b03811615155b612b415760405162461bcd60e51b8152602060048201526011602482015270496e76616c69642061646472657373657360781b6044820152606401610343565b6001600160a01b038281166000818152609f6020908152604080832080549587166001600160a01b0319968716811790915560a0805460018101825594527f78fdc8d422c49ced035a9edf18d00d3c6a8d81df210f3e5e448e045e77b41e8890930180549095168417909455925190815290917fef6485b84315f9b1483beffa32aae9a0596890395e3d7521f1c5fbb51790e765910160405180910390a25050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052611e6a9084906136fe565b8251612c489060a49060208601906139c5565b50815181518114612c925760405162461bcd60e51b8152602060048201526014602482015273496e76616c696420696e7075742061727261797360601b6044820152606401610343565b60005b81811015612ce957612cd9848281518110612cb257612cb26147fd565b6020026020010151848381518110612ccc57612ccc6147fd565b6020026020010151612a84565b612ce2816147a0565b9050612c95565b5050505050565b60008111612d395760405162461bcd60e51b81526020600482015260166024820152754d757374206465706f73697420736f6d657468696e6760501b6044820152606401610343565b6040805160008152602081018390526001600160a01b038416917f5548c837ab068cf56a2c2479df0882a4922fd203edb7517321831d95078c5f62910160405180910390a25050565b60335460ff1615612da55760405162461bcd60e51b815260040161034390614554565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663e52253816040518163ffffffff1660e01b8152600401602060405180830381600087803b158015612e0257600080fd5b505af1158015612e16573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e3a919061406c565b9050600060685482612e4c9190614704565b905080471015612e9e5760405162461bcd60e51b815260206004820152601860248201527f696e73756666696369656e74206574682062616c616e636500000000000000006044820152606401610343565b8015610a465760006068819055507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b158015612f0757600080fd5b505af1158015612f1b573d6000803e3d6000fd5b505060a354604080516001600160a01b0392831681527f0000000000000000000000000000000000000000000000000000000000000000909216602083015281018590527ff6c07a063ed4e63808eb8da7112d46dbcd38de2b40a73dbcc9353c5a94c7235393506060019150612f8e9050565b60405180910390a160a354610a46906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116911683612be3565b6001600160a01b0381166130265760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f7220697320616464726573732830290000000000006044820152606401610343565b806001600160a01b031661304660008051602061486d8339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a36123788160008051602061486d83398151915255565b60335460ff16156130b45760405162461bcd60e51b815260040161034390614554565b6033805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586130e93390565b6040516001600160a01b03909116815260200160405180910390a1565b600081116131565760405162461bcd60e51b815260206004820152601760248201527f4d75737420776974686472617720736f6d657468696e670000000000000000006044820152606401610343565b6001600160a01b0383166131a55760405162461bcd60e51b8152602060048201526016602482015275135d5cdd081cdc1958da599e481c9958da5c1a595b9d60521b6044820152606401610343565b6040805160008152602081018390526001600160a01b038416917f2717ead6b9200dd235aad468c9809ea400fe33ac69b5bfaa6d3e90fc922b6398910160405180910390a2611e6a6001600160a01b0383168483612be3565b6000606854471015613213576110af826137d0565b600060685447613223919061475d565b9050600191506801bc16d674ec800000811061341957600061324e6801bc16d674ec8000008361471c565b905080603454101561326b57613263846137d0565b949350505050565b806034600082825461327d919061475d565b9091555060009050613298826801bc16d674ec80000061473e565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b1580156132f557600080fd5b505af1158015613309573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb92506044019050602060405180830381600087803b15801561339957600080fd5b505af11580156133ad573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133d19190613e6a565b5060345460408051848152602081019290925281018290527fbe7040030ff7b347853214bf49820c6d455fedf58f3815f85c7bc5216993682b9060600160405180910390a150505b600060685447613429919061475d565b90506801bc16d674ec800000811061347b5760405162461bcd60e51b8152602060048201526015602482015274756e6578706563746564206163636f756e74696e6760581b6044820152606401610343565b80613487575050919050565b6069548110156134e15780606860008282546134a39190614704565b90915550506040518181527f7a745a2c63a535068f52ceca27debd5297bbad5f7f37ec53d044a59d0362445d906020015b60405180910390a161367d565b606a54811115613674577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b15801561354657600080fd5b505af115801561355a573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb92506044019050602060405180830381600087803b1580156135ea57600080fd5b505af11580156135fe573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136229190613e6a565b50600160346000828254613636919061475d565b909155505060345460408051918252602082018390527f6aa7e30787b26429ced603a7aba8b19c4b5d5bcf29a3257da953c8d53bcaa3a691016134d4565b613263846137d0565b5050919050565b60335460ff166136cd5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610343565b6033805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa336130e9565b6000613753826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166137e89092919063ffffffff16565b805190915015611e6a57808060200190518101906137719190613e6a565b611e6a5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610343565b600081156137e0576137e0613091565b506000919050565b60606137f78484600085613801565b90505b9392505050565b6060824710156138625760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610343565b843b6138b05760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610343565b600080866001600160a01b031685876040516138cc91906141b5565b60006040518083038185875af1925050503d8060008114613909576040519150601f19603f3d011682016040523d82523d6000602084013e61390e565b606091505b509150915061391e828286613929565b979650505050505050565b606083156139385750816137fa565b8251156139485782518084602001fd5b8160405162461bcd60e51b815260040161034391906144d3565b8280548282559060005260206000209081019282156139b5579160200282015b828111156139b55781546001600160a01b0319166001600160a01b03843516178255602090920191600190910190613982565b506139c1929150613a1a565b5090565b8280548282559060005260206000209081019282156139b5579160200282015b828111156139b557825182546001600160a01b0319166001600160a01b039091161782556020909201916001909101906139e5565b5b808211156139c15760008155600101613a1b565b60008083601f840112613a4157600080fd5b5081356001600160401b03811115613a5857600080fd5b6020830191508360208260051b8501011115613a7357600080fd5b9250929050565b600082601f830112613a8b57600080fd5b81356020613aa0613a9b836146a0565b614670565b80838252828201915082860187848660051b8901011115613ac057600080fd5b60005b85811015613ae8578135613ad681614829565b84529284019290840190600101613ac3565b5090979650505050505050565b60008083601f840112613b0757600080fd5b5081356001600160401b03811115613b1e57600080fd5b602083019150836020828501011115613a7357600080fd5b600060a08284031215613b4857600080fd5b50919050565b600060a08284031215613b6057600080fd5b60405160a081018181106001600160401b0382111715613b8257613b82614813565b604052905080613b9183613bd9565b8152613b9f60208401613bf2565b6020820152613bb060408401613bf2565b60408201526060830135613bc38161483e565b6060820152608092830135920191909152919050565b803563ffffffff81168114613bed57600080fd5b919050565b80356001600160401b0381168114613bed57600080fd5b600060208284031215613c1b57600080fd5b81356137fa81614829565b600060208284031215613c3857600080fd5b81516137fa81614829565b60008060408385031215613c5657600080fd5b8235613c6181614829565b91506020830135613c7181614829565b809150509250929050565b600080600060608486031215613c9157600080fd5b8335613c9c81614829565b92506020840135613cac81614829565b929592945050506040919091013590565b60008060408385031215613cd057600080fd5b8235613cdb81614829565b946020939093013593505050565b60008060208385031215613cfc57600080fd5b82356001600160401b03811115613d1257600080fd5b613d1e85828601613a2f565b90969095509350505050565b600080600060608486031215613d3f57600080fd5b83356001600160401b0380821115613d5657600080fd5b613d6287838801613a7a565b94506020860135915080821115613d7857600080fd5b613d8487838801613a7a565b93506040860135915080821115613d9a57600080fd5b50613da786828701613a7a565b9150509250925092565b600080600060e08486031215613dc657600080fd5b83356001600160401b03811115613ddc57600080fd5b8401601f81018613613ded57600080fd5b80356020613dfd613a9b836146a0565b8083825282820191508285018a848660051b8801011115613e1d57600080fd5b600095505b84861015613e4757613e3381613bf2565b835260019590950194918301918301613e22565b509650508601359350613e61915086905060408601613b4e565b90509250925092565b600060208284031215613e7c57600080fd5b81516137fa8161483e565b600060208284031215613e9957600080fd5b5035919050565b60008060008060408587031215613eb657600080fd5b84356001600160401b0380821115613ecd57600080fd5b613ed988838901613af5565b90965094506020870135915080821115613ef257600080fd5b50613eff87828801613a2f565b95989497509550505050565b600080600080600080600080610120898b031215613f2857600080fd5b88356001600160401b0380821115613f3f57600080fd5b613f4b8c838d01613af5565b909a50985060208b0135915080821115613f6457600080fd5b613f708c838d01613a2f565b909850965060408b0135915080821115613f8957600080fd5b50613f968b828c01613af5565b90955093505060608901359150613fb08a60808b01613b36565b90509295985092959890939650565b600080600080600060e08688031215613fd757600080fd5b85356001600160401b0380821115613fee57600080fd5b613ffa89838a01613af5565b9097509550602088013591508082111561401357600080fd5b5061402088828901613a2f565b909450925061403490508760408801613b36565b90509295509295909350565b60008060006060848603121561405557600080fd5b505081359360208301359350604090920135919050565b60006020828403121561407e57600080fd5b5051919050565b6000806040838503121561409857600080fd5b50508035926020909101359150565b8183526000602080850194508260005b858110156140e3576001600160401b036140d083613bf2565b16875295820195908201906001016140b7565b509495945050505050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6000815180845261412f816020860160208601614774565b601f01601f19169290920160200192915050565b63ffffffff61415182613bd9565b16825261416060208201613bf2565b6001600160401b0380821660208501528061417d60408501613bf2565b166040850152505060608101356141938161483e565b15156060830152608090810135910152565b8183823760009101908152919050565b600082516141c7818460208701614774565b9190910192915050565b6001600160a01b03851681526101006020808301829052855191830182905260009161012084019187810191845b818110156142245783516001600160401b0316855293820193928201926001016141ff565b505082935086604086015263ffffffff865116606086015280860151925050506001600160401b0380821660808501528060408601511660a085015250506060830151151560c0830152608083015160e083015295945050505050565b6020808252825182820181905260009190848201906040850190845b818110156142c25783516001600160a01b03168352928401929184019160010161429d565b50909695505050505050565b6000604082016040835280865480835260608501915087600052602092508260002060005b828110156143185781546001600160a01b0316845292840192600191820191016142f3565b505050838103828501528481528590820160005b8681101561435a57823561433f81614829565b6001600160a01b03168252918301919083019060010161432c565b50979650505050505050565b60408152600061437a6040830186886140ee565b828103602084015261391e8185876140a7565b60006101208083526143a28184018b8d6140ee565b905082810360208401526143b781898b6140a7565b905082810360408401526143cc8187896140ee565b9150508360608301526143e26080830184614143565b9998505050505050505050565b60e08152600061440360e0830187896140ee565b82810360208401526144168186886140a7565b9150506144266040830184614143565b9695505050505050565b60808152600061444460808301888a6140ee565b82810360208401526144568188614117565b9050828103604084015261446b8186886140ee565b915050826060830152979650505050505050565b6060815260006144936060830186886140ee565b846020840152828103604084015261391e8185614117565b60208101600483106144cd57634e487b7160e01b600052602160045260246000fd5b91905290565b6020815260006137fa6020830184614117565b60208082526017908201527f43616c6c6572206973206e6f7420746865205661756c74000000000000000000604082015260600190565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b60208082526010908201526f14185d5cd8589b194e881c185d5cd95960821b604082015260600190565b6020808252601d908201527f43616c6c6572206973206e6f7420746865205265676973747261746f72000000604082015260600190565b6020808252600e908201526d1499595b9d1c985b9d0818d85b1b60921b604082015260600190565b6020808252601c908201527f43616c6c6572206973206e6f7420746865205374726174656769737400000000604082015260600190565b6000808335601e1984360301811261462b57600080fd5b8301803591506001600160401b0382111561464557600080fd5b602001915036819003821315613a7357600080fd5b60008235605e198336030181126141c757600080fd5b604051601f8201601f191681016001600160401b038111828210171561469857614698614813565b604052919050565b60006001600160401b038211156146b9576146b9614813565b5060051b60200190565b600080821280156001600160ff1b03849003851316156146e5576146e56147bb565b600160ff1b83900384128116156146fe576146fe6147bb565b50500190565b60008219821115614717576147176147bb565b500190565b60008261473957634e487b7160e01b600052601260045260246000fd5b500490565b6000816000190483118215151615614758576147586147bb565b500290565b60008282101561476f5761476f6147bb565b500390565b60005b8381101561478f578181015183820152602001614777565b83811115610d305750506000910152565b60006000198214156147b4576147b46147bb565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b038116811461237857600080fd5b801515811461237857600080fdfe53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac45357bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa2646970667358221220113919d09ddf52cbaf34c41b4ba31e1d6e98f959c68a6c638232aecc6636f9ac64736f6c63430008070033", + "numDeployments": 3, + "solcInputHash": "02842452c275dc62641a0db2f51fdc73", + "metadata": "{\"compiler\":{\"version\":\"0.8.7+commit.e28d00a7\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"platformAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"vaultAddress\",\"type\":\"address\"}],\"internalType\":\"struct InitializableAbstractStrategy.BaseStrategyConfig\",\"name\":\"_baseConfig\",\"type\":\"tuple\"},{\"internalType\":\"address\",\"name\":\"_wethAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_ssvToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_ssvNetwork\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_feeAccumulator\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_beaconChainDepositContract\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"AccountingConsensusRewards\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"noOfValidators\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"remainingValidators\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"wethSentToVault\",\"type\":\"uint256\"}],\"name\":\"AccountingFullyWithdrawnValidator\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"validatorsDelta\",\"type\":\"int256\"},{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"consensusRewardsDelta\",\"type\":\"int256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"wethToVault\",\"type\":\"uint256\"}],\"name\":\"AccountingManuallyFixed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"remainingValidators\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"wethSentToVault\",\"type\":\"uint256\"}],\"name\":\"AccountingValidatorSlashed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"Deposit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"pubkey\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"withdrawal_credentials\",\"type\":\"bytes\"}],\"name\":\"ETHStaked\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"start\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"end\",\"type\":\"uint256\"}],\"name\":\"FuseIntervalUpdated\",\"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\":\"address\",\"name\":\"_oldHarvesterAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_newHarvesterAddress\",\"type\":\"address\"}],\"name\":\"HarvesterAddressesUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"}],\"name\":\"PTokenAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"}],\"name\":\"PTokenRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Paused\",\"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\":\"newAddress\",\"type\":\"address\"}],\"name\":\"RegistratorChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"_oldAddresses\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"_newAddresses\",\"type\":\"address[]\"}],\"name\":\"RewardTokenAddressesUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"rewardToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"RewardTokenCollected\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"pubkey\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"}],\"name\":\"SSVValidatorExitCompleted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"pubkey\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"}],\"name\":\"SSVValidatorExitInitiated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"pubkey\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"}],\"name\":\"SSVValidatorRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Unpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"Withdrawal\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"BEACON_CHAIN_DEPOSIT_CONTRACT\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_ACCUMULATOR_ADDRESS\",\"outputs\":[{\"internalType\":\"address payable\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MAX_STAKE\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"SSV_NETWORK_ADDRESS\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"SSV_TOKEN_ADDRESS\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"VAULT_ADDRESS\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"WETH_TOKEN_ADDRESS\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"activeDepositedValidators\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"assetToPToken\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"}],\"name\":\"checkBalance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"claimGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"collectRewardTokens\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"consensusRewards\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"depositAll\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"validatorCount\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"networkFeeIndex\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"index\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"active\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"internalType\":\"struct Cluster\",\"name\":\"cluster\",\"type\":\"tuple\"}],\"name\":\"depositSSV\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"doAccounting\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"accountingValid\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"publicKey\",\"type\":\"bytes\"},{\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"}],\"name\":\"exitSsvValidator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fuseIntervalEnd\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fuseIntervalStart\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRewardTokenAddresses\",\"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\":\"harvesterAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"_rewardTokenAddresses\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"_assets\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"_pTokens\",\"type\":\"address[]\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isGovernor\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"int256\",\"name\":\"_validatorsDelta\",\"type\":\"int256\"},{\"internalType\":\"int256\",\"name\":\"_consensusRewardsDelta\",\"type\":\"int256\"},{\"internalType\":\"uint256\",\"name\":\"_wethToVaultAmount\",\"type\":\"uint256\"}],\"name\":\"manuallyFixAccounting\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"paused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"platformAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"publicKey\",\"type\":\"bytes\"},{\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"},{\"internalType\":\"bytes\",\"name\":\"sharesData\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"validatorCount\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"networkFeeIndex\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"index\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"active\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"internalType\":\"struct Cluster\",\"name\":\"cluster\",\"type\":\"tuple\"}],\"name\":\"registerSsvValidator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_assetIndex\",\"type\":\"uint256\"}],\"name\":\"removePToken\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"publicKey\",\"type\":\"bytes\"},{\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"validatorCount\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"networkFeeIndex\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"index\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"active\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"internalType\":\"struct Cluster\",\"name\":\"cluster\",\"type\":\"tuple\"}],\"name\":\"removeSsvValidator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"rewardTokenAddresses\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"safeApproveAllTokens\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_fuseIntervalStart\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_fuseIntervalEnd\",\"type\":\"uint256\"}],\"name\":\"setFuseInterval\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_harvesterAddress\",\"type\":\"address\"}],\"name\":\"setHarvesterAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"}],\"name\":\"setPTokenAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"setRegistrator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"_rewardTokenAddresses\",\"type\":\"address[]\"}],\"name\":\"setRewardTokenAddresses\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"pubkey\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"depositDataRoot\",\"type\":\"bytes32\"}],\"internalType\":\"struct ValidatorStakeData[]\",\"name\":\"validators\",\"type\":\"tuple[]\"}],\"name\":\"stakeEth\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"}],\"name\":\"supportsAsset\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"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\":\"validatorRegistrator\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"validatorsStates\",\"outputs\":[{\"internalType\":\"enum ValidatorRegistrator.VALIDATOR_STATE\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"vaultAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"withdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdrawAll\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"author\":\"Origin Protocol Inc\",\"kind\":\"dev\",\"methods\":{\"checkBalance(address)\":{\"params\":{\"_asset\":\"Address of weth asset\"},\"returns\":{\"balance\":\" Total value of (W)ETH\"}},\"constructor\":{\"params\":{\"_baseConfig\":\"Base strategy config with platformAddress (ERC-4626 Vault contract), eg sfrxETH or sDAI, and vaultAddress (OToken Vault contract), eg VaultProxy or OETHVaultProxy\",\"_beaconChainDepositContract\":\"Address of the beacon chain deposit contract\",\"_feeAccumulator\":\"Address of the fee accumulator receiving execution layer validator rewards\",\"_ssvNetwork\":\"Address of the SSV Network contract\",\"_ssvToken\":\"Address of the Erc20 SSV Token contract\",\"_wethAddress\":\"Address of the Erc20 WETH Token contract\"}},\"deposit(address,uint256)\":{\"params\":{\"_amount\":\"Amount of assets that were transferred to the strategy by the vault.\",\"_asset\":\"Address of asset to deposit. Has to be WETH.\"}},\"depositSSV(uint64[],uint256,(uint32,uint64,uint64,bool,uint256))\":{\"details\":\"A SSV cluster is defined by the SSVOwnerAddress and the set of operatorIds. uses \\\"onlyStrategist\\\" modifier so continuous front-running can't DOS our maintenance service that tries to top up SSV tokens.\",\"params\":{\"cluster\":\"The SSV cluster details that must be derived from emitted events from the SSVNetwork contract.\"}},\"doAccounting()\":{\"details\":\"This function could in theory be permission-less but lets allow only the Registrator (Defender Action) to call it for now.\",\"returns\":{\"accountingValid\":\"true if accounting was successful, false if fuse is blown\"}},\"getRewardTokenAddresses()\":{\"returns\":{\"_0\":\"address[] the reward token addresses.\"}},\"initialize(address[],address[],address[])\":{\"params\":{\"_assets\":\"Addresses of initial supported assets\",\"_pTokens\":\"Platform Token corresponding addresses\",\"_rewardTokenAddresses\":\"Address of reward token for platform\"}},\"manuallyFixAccounting(int256,int256,uint256)\":{\"params\":{\"_consensusRewardsDelta\":\"adjust the accounted for consensus rewards up or down\",\"_validatorsDelta\":\"adjust the active validators by plus one, minus one or unchanged with zero\",\"_wethToVaultAmount\":\"the amount of WETH to be sent to the Vault\"}},\"paused()\":{\"details\":\"Returns true if the contract is paused, and false otherwise.\"},\"removePToken(uint256)\":{\"params\":{\"_assetIndex\":\"Index of the asset to be removed\"}},\"setHarvesterAddress(address)\":{\"params\":{\"_harvesterAddress\":\"Address of the harvester contract.\"}},\"setPTokenAddress(address,address)\":{\"params\":{\"_asset\":\"Address for the asset\",\"_pToken\":\"Address for the corresponding platform token\"}},\"setRewardTokenAddresses(address[])\":{\"params\":{\"_rewardTokenAddresses\":\"Array of reward token addresses\"}},\"stakeEth((bytes,bytes,bytes32)[])\":{\"params\":{\"validators\":\"A list of validator data needed to stake. The `ValidatorStakeData` struct contains the pubkey, signature and depositDataRoot. Only the registrator can call this function.\"}},\"supportsAsset(address)\":{\"params\":{\"_asset\":\"The address of the asset token.\"}},\"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\"}},\"withdraw(address,address,uint256)\":{\"params\":{\"_amount\":\"Amount of WETH to withdraw\",\"_asset\":\"WETH to withdraw\",\"_recipient\":\"Address to receive withdrawn assets\"}}},\"stateVariables\":{\"FEE_ACCUMULATOR_ADDRESS\":{\"details\":\"this address will receive Execution layer rewards - These are rewards earned for executing transactions on the Ethereum network as part of block proposals. They include priority fees (fees paid by users for their transactions to be included) and MEV rewards (rewards for arranging transactions in a way that benefits the validator).\"}},\"title\":\"Native Staking SSV Strategy\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"BEACON_CHAIN_DEPOSIT_CONTRACT()\":{\"notice\":\"The address of the beacon chain deposit contract\"},\"FEE_ACCUMULATOR_ADDRESS()\":{\"notice\":\"Fee collector address\"},\"MAX_STAKE()\":{\"notice\":\"The maximum amount of ETH that can be staked by a validator\"},\"SSV_NETWORK_ADDRESS()\":{\"notice\":\"The address of the SSV Network contract used to interface with\"},\"SSV_TOKEN_ADDRESS()\":{\"notice\":\"SSV ERC20 token that serves as a payment for operating SSV validators\"},\"VAULT_ADDRESS()\":{\"notice\":\"Address of the OETH Vault proxy contract\"},\"WETH_TOKEN_ADDRESS()\":{\"notice\":\"The address of the Wrapped ETH (WETH) token contract\"},\"activeDepositedValidators()\":{\"notice\":\"The number of validators that have 32 (!) ETH actively deposited. When a new deposit to a validator happens this number increases, when a validator exit is detected this number decreases.\"},\"assetToPToken(address)\":{\"notice\":\"asset => pToken (Platform Specific Token Address)\"},\"checkBalance(address)\":{\"notice\":\"Returns the total value of (W)ETH that is staked to the validators and WETH deposits that are still to be staked. This does not include ETH from consensus rewards sitting in this strategy or ETH from MEV rewards in the FeeAccumulator. These rewards are harvested and sent to the Dripper so will eventually be sent to the Vault as WETH.\"},\"claimGovernance()\":{\"notice\":\"Claim Governance of the contract to a new account (`newGovernor`). Can only be called by the new Governor.\"},\"collectRewardTokens()\":{\"notice\":\"Collect accumulated reward token and send to Vault.\"},\"consensusRewards()\":{\"notice\":\"Keeps track of the total consensus rewards swept from the beacon chain\"},\"deposit(address,uint256)\":{\"notice\":\"Unlike other strategies, this does not deposit assets into the underlying platform. It just checks the asset is WETH and emits the Deposit event. To deposit WETH into validators `registerSsvValidator` and `stakeEth` must be used. Will NOT revert if the strategy is paused from an accounting failure.\"},\"depositAll()\":{\"notice\":\"Unlike other strategies, this does not deposit assets into the underlying platform. It just emits the Deposit event. To deposit WETH into validators `registerSsvValidator` and `stakeEth` must be used. Will NOT revert if the strategy is paused from an accounting failure.\"},\"depositSSV(uint64[],uint256,(uint32,uint64,uint64,bool,uint256))\":{\"notice\":\"Deposits more SSV Tokens to the SSV Network contract which is used to pay the SSV Operators.\"},\"doAccounting()\":{\"notice\":\"This notion page offers a good explanation of how the accounting functions https://www.notion.so/originprotocol/Limited-simplified-native-staking-accounting-67a217c8420d40678eb943b9da0ee77d In short, after dividing by 32, if the ETH remaining on the contract falls between 0 and fuseIntervalStart, the accounting function will treat that ETH as Beacon chain consensus rewards. On the contrary, if after dividing by 32, the ETH remaining on the contract falls between fuseIntervalEnd and 32, the accounting function will treat that as a validator slashing.Perform the accounting attributing beacon chain ETH to either full or partial withdrawals. Returns true when accounting is valid and fuse isn't \\\"blown\\\". Returns false when fuse is blown.\"},\"exitSsvValidator(bytes,uint64[])\":{\"notice\":\"Exit a validator from the Beacon chain. The staked ETH will eventually swept to this native staking strategy. Only the registrator can call this function.\"},\"fuseIntervalEnd()\":{\"notice\":\"end of fuse interval\"},\"fuseIntervalStart()\":{\"notice\":\"start of fuse interval\"},\"getRewardTokenAddresses()\":{\"notice\":\"Get the reward token addresses.\"},\"governor()\":{\"notice\":\"Returns the address of the current Governor.\"},\"harvesterAddress()\":{\"notice\":\"Address of the Harvester contract allowed to collect reward tokens\"},\"initialize(address[],address[],address[])\":{\"notice\":\"initialize function, to set up initial internal state\"},\"isGovernor()\":{\"notice\":\"Returns true if the caller is the current Governor.\"},\"manuallyFixAccounting(int256,int256,uint256)\":{\"notice\":\"Allow the Strategist to fix the accounting of this strategy and unpause.\"},\"platformAddress()\":{\"notice\":\"Address of the underlying platform\"},\"registerSsvValidator(bytes,uint64[],bytes,uint256,(uint32,uint64,uint64,bool,uint256))\":{\"notice\":\"Registers a new validator in the SSV Cluster. Only the registrator can call this function.\"},\"removePToken(uint256)\":{\"notice\":\"Remove a supported asset by passing its index. This method can only be called by the system Governor\"},\"removeSsvValidator(bytes,uint64[],(uint32,uint64,uint64,bool,uint256))\":{\"notice\":\"Remove a validator from the SSV Cluster. Make sure `exitSsvValidator` is called before and the validate has exited the Beacon chain. If removed before the validator has exited the beacon chain will result in the validator being slashed. Only the registrator can call this function.\"},\"rewardTokenAddresses(uint256)\":{\"notice\":\"Address of the reward tokens. eg CRV, BAL, CVX, AURA\"},\"safeApproveAllTokens()\":{\"notice\":\"Approves the SSV Network contract to transfer SSV tokens for deposits\"},\"setFuseInterval(uint256,uint256)\":{\"notice\":\"set fuse interval values\"},\"setHarvesterAddress(address)\":{\"notice\":\"Set the Harvester contract that can collect rewards.\"},\"setPTokenAddress(address,address)\":{\"notice\":\"Provide support for asset by passing its pToken address. This method can only be called by the system Governor\"},\"setRegistrator(address)\":{\"notice\":\"Set the address of the registrator which can register, exit and remove validators\"},\"setRewardTokenAddresses(address[])\":{\"notice\":\"Set the reward token addresses. Any old addresses will be overwritten.\"},\"stakeEth((bytes,bytes,bytes32)[])\":{\"notice\":\"Stakes WETH to the node validators\"},\"supportsAsset(address)\":{\"notice\":\"Returns bool indicating whether asset is supported by strategy.\"},\"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 strategy contracts, i.e. mistaken sends.\"},\"validatorRegistrator()\":{\"notice\":\"Address of the registrator - allowed to register, exit and remove validators\"},\"validatorsStates(bytes32)\":{\"notice\":\"State of the validators keccak256(pubKey) => state\"},\"vaultAddress()\":{\"notice\":\"Address of the OToken vault\"},\"withdraw(address,address,uint256)\":{\"notice\":\"Withdraw WETH from this contract. Used only if some WETH for is lingering on the contract. That can happen when: - the deposit was not a multiple of 32 WETH - someone sent WETH directly to this contract Will NOT revert if the strategy is paused from an accounting failure.\"},\"withdrawAll()\":{\"notice\":\"transfer all WETH deposits back to the vault. This does not withdraw from the validators. That has to be done separately with the `exitSsvValidator` and `removeSsvValidator` operations. This does not withdraw any execution rewards from the FeeAccumulator or consensus rewards in this strategy. Any ETH in this strategy that was swept from a full validator withdrawal will not be withdrawn. ETH from full validator withdrawals is sent to the Vault using `doAccounting`. Will NOT revert if the strategy is paused from an accounting failure.\"}},\"notice\":\"Strategy to deploy funds into DVT validators powered by the SSV Network\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol\":\"NativeStakingSSVStrategy\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"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\",\"keccak256\":\"0xe68ed7fb8766ed1e888291f881e36b616037f852b37d96877045319ad298ba87\",\"license\":\"MIT\"},\"@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/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\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"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/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\",\"keccak256\":\"0x598f90bdbc854250bbd5991426bfb43367207e64e33109c41aa8b54323fd8d8e\",\"license\":\"MIT\"},\"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 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 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 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\",\"keccak256\":\"0xbef02bd5257e61dec0a6be4b1531064a7fdfeb4043885443a1902fb5d1b23e1b\",\"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/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/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\",\"keccak256\":\"0x05b7dce6c24d3cd4e48b5c6346d86e5e40ecc3291bcdf3f3ef091c98fc826519\",\"license\":\"MIT\"},\"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\\nimport { Governable } from \\\"../../governance/Governable.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 is Governable {\\n /// @notice The address of the Native Staking Strategy\\n address public immutable STRATEGY;\\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 }\\n\\n /**\\n * @dev Accept ETH\\n */\\n receive() external payable {}\\n}\\n\",\"keccak256\":\"0xb8fda3b87dc5d6f8aee4bf1d015a585211e5b5a319dfa4b0f4770e3f5a2d5939\",\"license\":\"MIT\"},\"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\\\";\\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\\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_ADDRESS;\\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 // For future use\\n uint256[50] 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 _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 address _feeAccumulator,\\n address _beaconChainDepositContract\\n )\\n InitializableAbstractStrategy(_baseConfig)\\n ValidatorAccountant(\\n _wethAddress,\\n _baseConfig.vaultAddress,\\n _beaconChainDepositContract,\\n _ssvNetwork\\n )\\n {\\n SSV_TOKEN_ADDRESS = _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 /// @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_TOKEN_ADDRESS).deposit{ value: ethRewards }();\\n\\n emit RewardTokenCollected(\\n harvesterAddress,\\n WETH_TOKEN_ADDRESS,\\n ethRewards\\n );\\n IERC20(WETH_TOKEN_ADDRESS).safeTransfer(\\n harvesterAddress,\\n ethRewards\\n );\\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_TOKEN_ADDRESS, \\\"Unsupported asset\\\");\\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_TOKEN_ADDRESS).balanceOf(\\n address(this)\\n );\\n if (wethBalance > 0) {\\n _deposit(WETH_TOKEN_ADDRESS, wethBalance);\\n }\\n }\\n\\n /// @notice Withdraw WETH from this contract. Used only if some WETH for is lingering on the contract. That\\n /// can happen when:\\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 _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 emit Withdrawal(_asset, address(0), _amount);\\n IERC20(_asset).safeTransfer(_recipient, _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_TOKEN_ADDRESS).balanceOf(\\n address(this)\\n );\\n if (wethBalance > 0) {\\n _withdraw(vaultAddress, WETH_TOKEN_ADDRESS, wethBalance);\\n }\\n }\\n\\n function _abstractSetPToken(address _asset, address) internal override {}\\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_TOKEN_ADDRESS, \\\"Unsupported asset\\\");\\n\\n balance =\\n // add the ETH that has been staked in validators\\n activeDepositedValidators *\\n 32 ether +\\n // add the WETH in the strategy from deposits that are still to be staked\\n IERC20(WETH_TOKEN_ADDRESS).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_TOKEN_ADDRESS;\\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_ADDRESS).approve(\\n SSV_NETWORK_ADDRESS,\\n type(uint256).max\\n );\\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 ||\\n msg.sender == WETH_TOKEN_ADDRESS,\\n \\\"eth not from allowed contracts\\\"\\n );\\n }\\n}\\n\",\"keccak256\":\"0x9ba7e5cc1fbf9e4a8559d9872dcdf8959b4f3ef9d9a2ff8e0f74c36ec9efb4fe\",\"license\":\"MIT\"},\"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 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 MAX_STAKE = 32 ether;\\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\\n uint256[50] 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 constructor(\\n address _wethAddress,\\n address _vaultAddress,\\n address _beaconChainDepositContract,\\n address _ssvNetwork\\n )\\n ValidatorRegistrator(\\n _wethAddress,\\n _vaultAddress,\\n _beaconChainDepositContract,\\n _ssvNetwork\\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 _fuseIntervalStart < 32 ether &&\\n _fuseIntervalEnd < 32 ether &&\\n _fuseIntervalEnd - _fuseIntervalStart >= 4 ether,\\n \\\"incorrect fuse interval\\\"\\n );\\n\\n emit FuseIntervalUpdated(_fuseIntervalStart, _fuseIntervalEnd);\\n\\n fuseIntervalStart = _fuseIntervalStart;\\n fuseIntervalEnd = _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 returns (bool accountingValid)\\n {\\n // pause the accounting on failure\\n accountingValid = _doAccounting(true);\\n }\\n\\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 >= MAX_STAKE) {\\n uint256 fullyWithdrawnValidators;\\n // safe since MAX_STAKE is hardcoded to 32ETH\\n unchecked {\\n // explicitly cast to uint256 as we want to round to a whole number of validators\\n fullyWithdrawnValidators = uint256(newSweptETH / MAX_STAKE);\\n }\\n activeDepositedValidators -= fullyWithdrawnValidators;\\n\\n uint256 wethToVault = MAX_STAKE * fullyWithdrawnValidators;\\n IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: wethToVault }();\\n IWETH9(WETH_TOKEN_ADDRESS).transfer(VAULT_ADDRESS, 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 < 32 ether, \\\"unexpected accounting\\\");\\n\\n // If no Beacon chain consensus rewards swept\\n if (ethRemaining == 0) {\\n // do nothing\\n return accountingValid;\\n }\\n // Beacon chain consensus rewards swept (partial validator withdrawals)\\n else if (ethRemaining < fuseIntervalStart) {\\n // solhint-disable-next-line reentrancy\\n consensusRewards += ethRemaining;\\n emit AccountingConsensusRewards(ethRemaining);\\n }\\n // Beacon chain consensus rewards swept but also a slashed validator fully exited\\n else if (ethRemaining > fuseIntervalEnd) {\\n IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: ethRemaining }();\\n IWETH9(WETH_TOKEN_ADDRESS).transfer(VAULT_ADDRESS, ethRemaining);\\n activeDepositedValidators -= 1;\\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 /// @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 plus one, minus one or unchanged with zero\\n /// @param _wethToVaultAmount the amount of WETH to be sent to the Vault\\n /// @param _consensusRewardsDelta adjust the accounted for consensus rewards up or down\\n function manuallyFixAccounting(\\n int256 _validatorsDelta,\\n int256 _consensusRewardsDelta,\\n uint256 _wethToVaultAmount\\n ) external onlyStrategist whenPaused {\\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(_wethToVaultAmount <= 32 ether, \\\"invalid wethToVaultAmount\\\");\\n\\n emit AccountingManuallyFixed(\\n _validatorsDelta,\\n _consensusRewardsDelta,\\n _wethToVaultAmount\\n );\\n\\n activeDepositedValidators = uint256(\\n int256(activeDepositedValidators) + _validatorsDelta\\n );\\n consensusRewards = uint256(\\n int256(consensusRewards) + _consensusRewardsDelta\\n );\\n if (_wethToVaultAmount > 0) {\\n IWETH9(WETH_TOKEN_ADDRESS).transfer(\\n VAULT_ADDRESS,\\n _wethToVaultAmount\\n );\\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\",\"keccak256\":\"0xc2887e7aa41c2d7f435c7c18364c261564866a896939caa735a6dfeaeba34bbe\",\"license\":\"MIT\"},\"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 address of the Wrapped ETH (WETH) token contract\\n address public immutable WETH_TOKEN_ADDRESS;\\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_ADDRESS;\\n /// @notice Address of the OETH Vault proxy contract\\n address public immutable VAULT_ADDRESS;\\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\\n // For future use\\n uint256[50] private __gap;\\n\\n enum VALIDATOR_STATE {\\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 newAddress);\\n event ETHStaked(bytes pubkey, uint256 amount, bytes withdrawal_credentials);\\n event SSVValidatorRegistered(bytes pubkey, uint64[] operatorIds);\\n event SSVValidatorExitInitiated(bytes pubkey, uint64[] operatorIds);\\n event SSVValidatorExitCompleted(bytes pubkey, uint64[] operatorIds);\\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 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 constructor(\\n address _wethAddress,\\n address _vaultAddress,\\n address _beaconChainDepositContract,\\n address _ssvNetwork\\n ) {\\n WETH_TOKEN_ADDRESS = _wethAddress;\\n BEACON_CHAIN_DEPOSIT_CONTRACT = _beaconChainDepositContract;\\n SSV_NETWORK_ADDRESS = _ssvNetwork;\\n VAULT_ADDRESS = _vaultAddress;\\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 emit RegistratorChanged(_address);\\n validatorRegistrator = _address;\\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 function stakeEth(ValidatorStakeData[] calldata validators)\\n external\\n onlyRegistrator\\n whenNotPaused\\n {\\n uint256 requiredETH = validators.length * 32 ether;\\n\\n // Check there is enough WETH from the deposits sitting in this strategy contract\\n require(\\n requiredETH <= IWETH9(WETH_TOKEN_ADDRESS).balanceOf(address(this)),\\n \\\"insufficient WETH\\\"\\n );\\n\\n // Convert required ETH from WETH\\n IWETH9(WETH_TOKEN_ADDRESS).withdraw(requiredETH);\\n\\n uint256 validatorsLength = validators.length;\\n // For each validator\\n for (uint256 i = 0; i < validatorsLength; ) {\\n bytes32 pubkeyHash = keccak256(validators[i].pubkey);\\n VALIDATOR_STATE currentState = validatorsStates[pubkeyHash];\\n\\n require(\\n currentState == VALIDATOR_STATE.REGISTERED,\\n \\\"Validator not registered\\\"\\n );\\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 withdrawal_credentials = abi.encodePacked(\\n bytes1(0x01),\\n bytes11(0),\\n address(this)\\n );\\n IDepositContract(BEACON_CHAIN_DEPOSIT_CONTRACT).deposit{\\n value: 32 ether\\n }(\\n validators[i].pubkey,\\n withdrawal_credentials,\\n validators[i].signature,\\n validators[i].depositDataRoot\\n );\\n\\n emit ETHStaked(\\n validators[i].pubkey,\\n 32 ether,\\n withdrawal_credentials\\n );\\n\\n validatorsStates[pubkeyHash] = VALIDATOR_STATE.STAKED;\\n\\n unchecked {\\n ++i;\\n }\\n }\\n // save gas by changing this storage variable only once rather each time in the loop.\\n activeDepositedValidators += validatorsLength;\\n }\\n\\n /// @notice Registers a new validator in the SSV Cluster.\\n /// Only the registrator can call this function.\\n function registerSsvValidator(\\n bytes calldata publicKey,\\n uint64[] calldata operatorIds,\\n bytes calldata sharesData,\\n uint256 amount,\\n Cluster calldata cluster\\n ) external onlyRegistrator whenNotPaused {\\n ISSVNetwork(SSV_NETWORK_ADDRESS).registerValidator(\\n publicKey,\\n operatorIds,\\n sharesData,\\n amount,\\n cluster\\n );\\n validatorsStates[keccak256(publicKey)] = VALIDATOR_STATE.REGISTERED;\\n emit SSVValidatorRegistered(publicKey, operatorIds);\\n }\\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 function exitSsvValidator(\\n bytes calldata publicKey,\\n uint64[] calldata operatorIds\\n ) external onlyRegistrator whenNotPaused {\\n VALIDATOR_STATE currentState = validatorsStates[keccak256(publicKey)];\\n require(currentState == VALIDATOR_STATE.STAKED, \\\"Validator not staked\\\");\\n\\n ISSVNetwork(SSV_NETWORK_ADDRESS).exitValidator(publicKey, operatorIds);\\n emit SSVValidatorExitInitiated(publicKey, operatorIds);\\n\\n validatorsStates[keccak256(publicKey)] = VALIDATOR_STATE.EXITING;\\n }\\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 function removeSsvValidator(\\n bytes calldata publicKey,\\n uint64[] calldata operatorIds,\\n Cluster calldata cluster\\n ) external onlyRegistrator whenNotPaused {\\n VALIDATOR_STATE currentState = validatorsStates[keccak256(publicKey)];\\n require(\\n currentState == VALIDATOR_STATE.EXITING,\\n \\\"Validator not exiting\\\"\\n );\\n\\n ISSVNetwork(SSV_NETWORK_ADDRESS).removeValidator(\\n publicKey,\\n operatorIds,\\n cluster\\n );\\n emit SSVValidatorExitCompleted(publicKey, operatorIds);\\n\\n validatorsStates[keccak256(publicKey)] = VALIDATOR_STATE.EXIT_COMPLETE;\\n }\\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 cluster The SSV cluster details that must be derived from emitted events from the SSVNetwork contract.\\n function depositSSV(\\n uint64[] memory operatorIds,\\n uint256 amount,\\n Cluster memory cluster\\n ) external onlyStrategist {\\n ISSVNetwork(SSV_NETWORK_ADDRESS).deposit(\\n address(this),\\n operatorIds,\\n amount,\\n cluster\\n );\\n }\\n}\\n\",\"keccak256\":\"0x51ec570f03257b9c9dfb7a4204ebd66c9e7b36584da8831aace7a8b90c627394\",\"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/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\",\"keccak256\":\"0x5e17bb3db9f9e1014b7c5c836547f8fa81e02af7568c0bb8f2a2e0e7c2192db4\",\"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/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": "0x6101806040523480156200001257600080fd5b5060405162004c5738038062004c57833981016040819052620000359162000138565b8585876020015183868383838362000053336200010860201b60201c565b60008051602062004c37833981519152546040516001600160a01b03909116906000907fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a908290a36033805460ff191690556001600160601b0319606094851b811660805291841b821660a052831b811660c05290821b811660e0528651821b811661010052602090960151811b86166101205298891b851661014052505050509190931b1661016052506200021392505050565b60008051602062004c3783398151915255565b80516001600160a01b03811681146200013357600080fd5b919050565b60008060008060008086880360e08112156200015357600080fd5b60408112156200016257600080fd5b50604080519081016001600160401b03811182821017156200019457634e487b7160e01b600052604160045260246000fd5b604052620001a2886200011b565b8152620001b2602089016200011b565b60208201529550620001c7604088016200011b565b9450620001d7606088016200011b565b9350620001e7608088016200011b565b9250620001f760a088016200011b565b91506200020760c088016200011b565b90509295509295509295565b60805160601c60a05160601c60c05160601c60e05160601c6101005160601c6101205160601c6101405160601c6101605160601c61488e620003a9600039600081816102a70152818161096e0152612db101526000818161057d015261230401526000818161045101528181610d41015281816118c801528181611a410152818161266301526128eb0152600061093a0152600081816106ec01528181610b09015281816117f601528181611a9101528181611d740152818161330801526135590152600081816109b701528181610bdf015281816116c8015281816122d4015281816123ec01526127e10152600081816108a6015261140a0152600081816102d9015281816104db015281816107bd01528181610a7001528181610db601528181610f850152818161100d015281816111bc01528181611297015281816119b201528181611a6201528181611da30152818161297601528181612a0501528181612eb601528181612f3b01528181612faf0152818161328201528181613337015281816134d30152613588015261488e6000f3fe6080604052600436106102975760003560e01c8063853828b61161015a578063c2e1e3f4116100c1578063d9f00ec71161007a578063d9f00ec714610908578063dbe55e5614610928578063dd505df61461095c578063de5f626814610990578063f1188e40146109a5578063f6ca71b0146109d957600080fd5b8063c2e1e3f414610842578063c7af335214610862578063c98517c514610877578063cceab75014610894578063d38bfff4146108c8578063d9caed12146108e857600080fd5b80639da0e462116101135780639da0e4621461074e578063a4f98af41461078b578063aa388af6146107a0578063ab12edf5146107ed578063ad1728cb1461080d578063bb1b918d1461082257600080fd5b8063853828b61461068057806387bae867146106955780638d7c0e46146106ba5780639092c31c146106da5780639136616a1461070e57806396d538bb1461072e57600080fd5b80635c975abb116101fe5780636e811d38116101b75780636e811d38146105d55780636ef38795146105f557806371a735f3146106155780637b2d9b2c14610635578063842f5c46146106555780638456cb591461066b57600080fd5b80635c975abb146105125780635d36b190146105365780635f5152261461054b5780636093d3801461056b57806366e3667e1461059f57806367c7066c146105b557600080fd5b8063430bf08a11610250578063430bf08a1461043f578063435356d11461047357806347e7ef2414610493578063484be812146104b3578063579a7e1a146104c95780635a063f63146104fd57600080fd5b80630c340a24146103535780630ed57b3a146103855780630fc3b4c4146103a55780631072cbea146103db57806322495dc8146103fb5780633c8649591461041b57600080fd5b3661034e57336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614806102fb5750336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016145b61034c5760405162461bcd60e51b815260206004820152601e60248201527f657468206e6f742066726f6d20616c6c6f77656420636f6e747261637473000060448201526064015b60405180910390fd5b005b600080fd5b34801561035f57600080fd5b506103686109fb565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561039157600080fd5b5061034c6103a0366004613c31565b610a18565b3480156103b157600080fd5b506103686103c0366004613bf7565b609f602052600090815260409020546001600160a01b031681565b3480156103e757600080fd5b5061034c6103f6366004613cab565b610a4a565b34801561040757600080fd5b5061034c610416366004613d9f565b610b07565b34801561042757600080fd5b5061043160695481565b60405190815260200161037c565b34801561044b57600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b34801561047f57600080fd5b5061034c61048e366004613d18565b610c51565b34801561049f57600080fd5b5061034c6104ae366004613cab565b610d36565b3480156104bf57600080fd5b50610431606a5481565b3480156104d557600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b34801561050957600080fd5b5061034c610e3c565b34801561051e57600080fd5b5060335460ff165b604051901515815260200161037c565b34801561054257600080fd5b5061034c610edb565b34801561055757600080fd5b50610431610566366004613bf7565b610f81565b34801561057757600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b3480156105ab57600080fd5b5061043160345481565b3480156105c157600080fd5b5060a354610368906001600160a01b031681565b3480156105e157600080fd5b5061034c6105f0366004613bf7565b6110b5565b34801561060157600080fd5b5061034c610610366004613cd7565b61113d565b34801561062157600080fd5b5061034c610630366004613fad565b6115d1565b34801561064157600080fd5b50610368610650366004613e75565b6117ca565b34801561066157600080fd5b5061043160685481565b34801561067757600080fd5b5061034c6117f4565b34801561068c57600080fd5b5061034c6118bd565b3480156106a157600080fd5b506033546103689061010090046001600160a01b031681565b3480156106c657600080fd5b5061034c6106d536600461402e565b611a8f565b3480156106e657600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b34801561071a57600080fd5b5061034c610729366004613e75565b611e77565b34801561073a57600080fd5b5061034c610749366004613cd7565b612042565b34801561075a57600080fd5b5061077e610769366004613e75565b60356020526000908152604090205460ff1681565b60405161037c9190614499565b34801561079757600080fd5b50610526612162565b3480156107ac57600080fd5b506105266107bb366004613bf7565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0390811691161490565b3480156107f957600080fd5b5061034c610808366004614073565b6121c1565b34801561081957600080fd5b5061034c6122bd565b34801561082e57600080fd5b5061034c61083d366004613ef9565b612383565b34801561084e57600080fd5b5061034c61085d366004613bf7565b6124f6565b34801561086e57600080fd5b50610526612583565b34801561088357600080fd5b506104316801bc16d674ec80000081565b3480156108a057600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b3480156108d457600080fd5b5061034c6108e3366004613bf7565b6125b4565b3480156108f457600080fd5b5061034c610903366004613c6a565b612658565b34801561091457600080fd5b5061034c610923366004613e8e565b6126eb565b34801561093457600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b34801561096857600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b34801561099c57600080fd5b5061034c6128e0565b3480156109b157600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b3480156109e557600080fd5b506109ee612a2a565b60405161037c919061426f565b6000610a136000805160206148398339815191525490565b905090565b610a20612583565b610a3c5760405162461bcd60e51b81526004016103439061450b565b610a468282612a8c565b5050565b610a52612583565b610a6e5760405162461bcd60e51b81526004016103439061450b565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b039081169083161415610aeb5760405162461bcd60e51b815260206004820152601f60248201527f43616e6e6f74207472616e7366657220737570706f72746564206173736574006044820152606401610343565b610a46610af66109fb565b6001600160a01b0384169083612beb565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b158015610b6057600080fd5b505afa158015610b74573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b989190613c14565b6001600160a01b0316336001600160a01b031614610bc85760405162461bcd60e51b8152600401610343906145cb565b60405163bc26e7e560e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063bc26e7e590610c1a9030908790879087906004016141bf565b600060405180830381600087803b158015610c3457600080fd5b505af1158015610c48573d6000803e3d6000fd5b50505050505050565b610c59612583565b610c755760405162461bcd60e51b81526004016103439061450b565b600054610100900460ff1680610c8e575060005460ff16155b610cf15760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610343565b600054610100900460ff16158015610d13576000805461ffff19166101011790555b610d1e848484612c3d565b8015610d30576000805461ff00191690555b50505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610d7e5760405162461bcd60e51b8152600401610343906144d4565b60008051602061481983398151915280546002811415610db05760405162461bcd60e51b8152600401610343906145a3565b600282557f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316846001600160a01b031614610e295760405162461bcd60e51b8152602060048201526011602482015270155b9cdd5c1c1bdc9d195908185cdcd95d607a1b6044820152606401610343565b610e338484612cf8565b50600190555050565b60a3546001600160a01b03163314610e965760405162461bcd60e51b815260206004820152601b60248201527f43616c6c6572206973206e6f74207468652048617276657374657200000000006044820152606401610343565b60008051602061481983398151915280546002811415610ec85760405162461bcd60e51b8152600401610343906145a3565b60028255610ed4612d8a565b5060019055565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b031614610f765760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b6064820152608401610343565b610f7f33612fd8565b565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b031614610ff85760405162461bcd60e51b8152602060048201526011602482015270155b9cdd5c1c1bdc9d195908185cdcd95d607a1b6044820152606401610343565b6040516370a0823160e01b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b15801561105757600080fd5b505afa15801561106b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061108f919061405a565b6034546110a5906801bc16d674ec80000061470a565b6110af91906146f2565b92915050565b6110bd612583565b6110d95760405162461bcd60e51b81526004016103439061450b565b6040516001600160a01b03821681527f83f29c79feb71f8fba9d0fbc4ba5f0982a28b6b1e868b3fc50e6400d100bca0f9060200160405180910390a1603380546001600160a01b0390921661010002610100600160a81b0319909216919091179055565b60335461010090046001600160a01b0316331461116c5760405162461bcd60e51b81526004016103439061456c565b60335460ff161561118f5760405162461bcd60e51b815260040161034390614542565b60006111a4826801bc16d674ec80000061470a565b6040516370a0823160e01b81523060048201529091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b15801561120657600080fd5b505afa15801561121a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061123e919061405a565b8111156112815760405162461bcd60e51b81526020600482015260116024820152700d2dce6eaccccd2c6d2cadce840ae8aa89607b1b6044820152606401610343565b604051632e1a7d4d60e01b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b1580156112e357600080fd5b505af11580156112f7573d6000803e3d6000fd5b5084925060009150505b818110156115b357600085858381811061131d5761131d6147c9565b905060200281019061132f9190614648565b6113399080614602565b604051611347929190614193565b6040805191829003909120600081815260356020529182205490925060ff16908160038111156113795761137961479d565b146113c65760405162461bcd60e51b815260206004820152601860248201527f56616c696461746f72206e6f74207265676973746572656400000000000000006044820152606401610343565b60408051600160f81b60208201526000602182018190526bffffffffffffffffffffffff193060601b16602c830152910160405160208183030381529060405290507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663228951186801bc16d674ec8000008a8a88818110611453576114536147c9565b90506020028101906114659190614648565b61146f9080614602565b858d8d8b818110611482576114826147c9565b90506020028101906114949190614648565b6114a2906020810190614602565b8f8f8d8181106114b4576114b46147c9565b90506020028101906114c69190614648565b604001356040518863ffffffff1660e01b81526004016114eb9695949392919061441e565b6000604051808303818588803b15801561150457600080fd5b505af1158015611518573d6000803e3d6000fd5b50505050507ffeb31a79d38edb1b090d516e4df3e273651179c6f2c2ec53a9a22ae015b70ba9888886818110611550576115506147c9565b90506020028101906115629190614648565b61156c9080614602565b6801bc16d674ec80000084604051611587949392919061446d565b60405180910390a150506000908152603560205260409020805460ff1916600190811790915501611301565b5080603460008282546115c691906146f2565b909155505050505050565b60335461010090046001600160a01b031633146116005760405162461bcd60e51b81526004016103439061456c565b60335460ff16156116235760405162461bcd60e51b815260040161034390614542565b6000603560008787604051611639929190614193565b604080519182900390912082526020820192909252016000205460ff169050600281600381111561166c5761166c61479d565b146116b15760405162461bcd60e51b815260206004820152601560248201527456616c696461746f72206e6f742065786974696e6760581b6044820152606401610343565b6040516312b3fc1960e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906312b3fc199061170590899089908990899089906004016143dd565b600060405180830381600087803b15801561171f57600080fd5b505af1158015611733573d6000803e3d6000fd5b505050507ff72821b8777f002ccdf6326f1242d9e0f762eb077668b67bebe640535378066d8686868660405161176c9493929190614354565b60405180910390a1600360356000888860405161178a929190614193565b60408051918290039091208252602082019290925201600020805460ff191660018360038111156117bd576117bd61479d565b0217905550505050505050565b60a481815481106117da57600080fd5b6000918252602090912001546001600160a01b0316905081565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b15801561184d57600080fd5b505afa158015611861573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118859190613c14565b6001600160a01b0316336001600160a01b0316146118b55760405162461bcd60e51b8152600401610343906145cb565b610f7f613099565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016148061190c57506118f76109fb565b6001600160a01b0316336001600160a01b0316145b6119645760405162461bcd60e51b815260206004820152602360248201527f43616c6c6572206973206e6f7420746865205661756c74206f7220476f7665726044820152623737b960e91b6064820152608401610343565b600080516020614819833981519152805460028114156119965760405162461bcd60e51b8152600401610343906145a3565b600282556040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b1580156119fc57600080fd5b505afa158015611a10573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a34919061405a565b90508015611a8757611a877f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000008361310e565b505060019055565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b158015611ae857600080fd5b505afa158015611afc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b209190613c14565b6001600160a01b0316336001600160a01b031614611b505760405162461bcd60e51b8152600401610343906145cb565b60335460ff16611b995760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610343565b6002198312158015611bac575060038313155b8015611bc65750600083603454611bc391906146b1565b12155b611c125760405162461bcd60e51b815260206004820152601760248201527f696e76616c69642076616c696461746f727344656c74610000000000000000006044820152606401610343565b6811ff6cf0fd15afffff198212158015611c3557506811ff6cf0fd15b000008213155b8015611c4f5750600082606854611c4c91906146b1565b12155b611c9b5760405162461bcd60e51b815260206004820152601d60248201527f696e76616c696420636f6e73656e7375735265776172647344656c74610000006044820152606401610343565b6801bc16d674ec800000811115611cf45760405162461bcd60e51b815260206004820152601960248201527f696e76616c69642077657468546f5661756c74416d6f756e74000000000000006044820152606401610343565b60408051848152602081018490529081018290527f80d022717ea022455c5886b8dd8a29c037570aae58aeb4d7b136d7a10ec2e4319060600160405180910390a182603454611d4391906146b1565b603455606854611d549083906146b1565b6068558015611e215760405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018390527f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb90604401602060405180830381600087803b158015611de757600080fd5b505af1158015611dfb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e1f9190613e58565b505b611e2b6000613206565b611e6a5760405162461bcd60e51b815260206004820152601060248201526f333ab9b29039ba34b63610313637bbb760811b6044820152606401610343565b611e72613672565b505050565b611e7f612583565b611e9b5760405162461bcd60e51b81526004016103439061450b565b60a0548110611edc5760405162461bcd60e51b815260206004820152600d60248201526c092dcecc2d8d2c840d2dcc8caf609b1b6044820152606401610343565b600060a08281548110611ef157611ef16147c9565b60009182526020808320909101546001600160a01b03908116808452609f90925260409092205460a05491935090911690611f2e90600190614729565b831015611fb05760a08054611f4590600190614729565b81548110611f5557611f556147c9565b60009182526020909120015460a080546001600160a01b039092169185908110611f8157611f816147c9565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505b60a0805480611fc157611fc16147b3565b60008281526020808220600019908401810180546001600160a01b031990811690915593019093556001600160a01b03858116808352609f855260409283902080549094169093559051908416815290917f16b7600acff27e39a8a96056b3d533045298de927507f5c1d97e4accde60488c910160405180910390a2505050565b61204a612583565b6120665760405162461bcd60e51b81526004016103439061450b565b8060005b81811015612119576000848483818110612086576120866147c9565b905060200201602081019061209b9190613bf7565b6001600160a01b031614156121095760405162461bcd60e51b815260206004820152602e60248201527f43616e206e6f742073657420616e20656d70747920616464726573732061732060448201526d30903932bbb0b932103a37b5b2b760911b6064820152608401610343565b6121128161476c565b905061206a565b507f04c0b9649497d316554306e53678d5f5f5dbc3a06f97dec13ff4cfe98b986bbc60a4848460405161214e939291906142bc565b60405180910390a1610d3060a48484613950565b60335460009061010090046001600160a01b031633146121945760405162461bcd60e51b81526004016103439061456c565b60335460ff16156121b75760405162461bcd60e51b815260040161034390614542565b610a136001613206565b6121c9612583565b6121e55760405162461bcd60e51b81526004016103439061450b565b80821080156121fc57506801bc16d674ec80000082105b801561221057506801bc16d674ec80000081105b801561222d5750673782dace9d90000061222a8383614729565b10155b6122795760405162461bcd60e51b815260206004820152601760248201527f696e636f7272656374206675736520696e74657276616c0000000000000000006044820152606401610343565b60408051838152602081018390527fcb8d24e46eb3c402bf344ee60a6576cba9ef2f59ea1af3b311520704924e901a910160405180910390a1606991909155606a55565b60405163095ea7b360e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015260001960248301527f0000000000000000000000000000000000000000000000000000000000000000169063095ea7b390604401602060405180830381600087803b15801561234857600080fd5b505af115801561235c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123809190613e58565b50565b60335461010090046001600160a01b031633146123b25760405162461bcd60e51b81526004016103439061456c565b60335460ff16156123d55760405162461bcd60e51b815260040161034390614542565b6040516301ba3ee760e21b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906306e8fb9c9061242f908b908b908b908b908b908b908b908b9060040161437b565b600060405180830381600087803b15801561244957600080fd5b505af115801561245d573d6000803e3d6000fd5b505050506000603560008a8a604051612477929190614193565b60408051918290039091208252602082019290925201600020805460ff191660018360038111156124aa576124aa61479d565b02179055507f75c4a66b2c6c28cf46db7131182a812e4fbbb2f0591377aa83a737909a9b68c3888888886040516124e49493929190614354565b60405180910390a15050505050505050565b6124fe612583565b61251a5760405162461bcd60e51b81526004016103439061450b565b60a354604080516001600160a01b03928316815291831660208301527fe48386b84419f4d36e0f96c10cc3510b6fb1a33795620c5098b22472bbe90796910160405180910390a160a380546001600160a01b0319166001600160a01b0392909216919091179055565b600061259b6000805160206148398339815191525490565b6001600160a01b0316336001600160a01b031614905090565b6125bc612583565b6125d85760405162461bcd60e51b81526004016103439061450b565b612600817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b03166126206000805160206148398339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146126a05760405162461bcd60e51b8152600401610343906144d4565b600080516020614819833981519152805460028114156126d25760405162461bcd60e51b8152600401610343906145a3565b600282556126e185858561310e565b5060019055505050565b60335461010090046001600160a01b0316331461271a5760405162461bcd60e51b81526004016103439061456c565b60335460ff161561273d5760405162461bcd60e51b815260040161034390614542565b6000603560008686604051612753929190614193565b604080519182900390912082526020820192909252016000205460ff16905060018160038111156127865761278661479d565b146127ca5760405162461bcd60e51b815260206004820152601460248201527315985b1a59185d1bdc881b9bdd081cdd185ad95960621b6044820152606401610343565b604051633877322b60e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690633877322b9061281c908890889088908890600401614354565b600060405180830381600087803b15801561283657600080fd5b505af115801561284a573d6000803e3d6000fd5b505050507ff8821da16f5ed966b41e0343c3eff9903af782d74f99f1689dd9d4562b6545b3858585856040516128839493929190614354565b60405180910390a160026035600087876040516128a1929190614193565b60408051918290039091208252602082019290925201600020805460ff191660018360038111156128d4576128d461479d565b02179055505050505050565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146129285760405162461bcd60e51b8152600401610343906144d4565b6000805160206148198339815191528054600281141561295a5760405162461bcd60e51b8152600401610343906145a3565b600282556040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b1580156129c057600080fd5b505afa1580156129d4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129f8919061405a565b90508015611a8757611a877f000000000000000000000000000000000000000000000000000000000000000082612cf8565b606060a4805480602002602001604051908101604052809291908181526020018280548015612a8257602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612a64575b5050505050905090565b6001600160a01b038281166000908152609f60205260409020541615612ae95760405162461bcd60e51b81526020600482015260126024820152711c151bdad95b88185b1c9958591e481cd95d60721b6044820152606401610343565b6001600160a01b03821615801590612b0957506001600160a01b03811615155b612b495760405162461bcd60e51b8152602060048201526011602482015270496e76616c69642061646472657373657360781b6044820152606401610343565b6001600160a01b038281166000818152609f6020908152604080832080549587166001600160a01b0319968716811790915560a0805460018101825594527f78fdc8d422c49ced035a9edf18d00d3c6a8d81df210f3e5e448e045e77b41e8890930180549095168417909455925190815290917fef6485b84315f9b1483beffa32aae9a0596890395e3d7521f1c5fbb51790e765910160405180910390a25050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052611e729084906136ec565b8251612c509060a49060208601906139b3565b50815181518114612c9a5760405162461bcd60e51b8152602060048201526014602482015273496e76616c696420696e7075742061727261797360601b6044820152606401610343565b60005b81811015612cf157612ce1848281518110612cba57612cba6147c9565b6020026020010151848381518110612cd457612cd46147c9565b6020026020010151612a8c565b612cea8161476c565b9050612c9d565b5050505050565b60008111612d415760405162461bcd60e51b81526020600482015260166024820152754d757374206465706f73697420736f6d657468696e6760501b6044820152606401610343565b6040805160008152602081018390526001600160a01b038416917f5548c837ab068cf56a2c2479df0882a4922fd203edb7517321831d95078c5f62910160405180910390a25050565b60335460ff1615612dad5760405162461bcd60e51b815260040161034390614542565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663e52253816040518163ffffffff1660e01b8152600401602060405180830381600087803b158015612e0a57600080fd5b505af1158015612e1e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e42919061405a565b9050600060685482612e5491906146f2565b905080471015612ea65760405162461bcd60e51b815260206004820152601860248201527f696e73756666696369656e74206574682062616c616e636500000000000000006044820152606401610343565b8015610a465760006068819055507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b158015612f0f57600080fd5b505af1158015612f23573d6000803e3d6000fd5b505060a354604080516001600160a01b0392831681527f0000000000000000000000000000000000000000000000000000000000000000909216602083015281018590527ff6c07a063ed4e63808eb8da7112d46dbcd38de2b40a73dbcc9353c5a94c7235393506060019150612f969050565b60405180910390a160a354610a46906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116911683612beb565b6001600160a01b03811661302e5760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f7220697320616464726573732830290000000000006044820152606401610343565b806001600160a01b031661304e6000805160206148398339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a36123808160008051602061483983398151915255565b60335460ff16156130bc5760405162461bcd60e51b815260040161034390614542565b6033805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586130f13390565b6040516001600160a01b03909116815260200160405180910390a1565b6000811161315e5760405162461bcd60e51b815260206004820152601760248201527f4d75737420776974686472617720736f6d657468696e670000000000000000006044820152606401610343565b6001600160a01b0383166131ad5760405162461bcd60e51b8152602060048201526016602482015275135d5cdd081cdc1958da599e481c9958da5c1a595b9d60521b6044820152606401610343565b6040805160008152602081018390526001600160a01b038416917f2717ead6b9200dd235aad468c9809ea400fe33ac69b5bfaa6d3e90fc922b6398910160405180910390a2611e726001600160a01b0383168483612beb565b600060685447101561321b576110af826137be565b60006068544761322b9190614729565b9050600191506801bc16d674ec80000081106133ff5760006801bc16d674ec8000008204905080603460008282546132639190614729565b909155506000905061327e826801bc16d674ec80000061470a565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b1580156132db57600080fd5b505af11580156132ef573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb92506044019050602060405180830381600087803b15801561337f57600080fd5b505af1158015613393573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133b79190613e58565b5060345460408051848152602081019290925281018290527fbe7040030ff7b347853214bf49820c6d455fedf58f3815f85c7bc5216993682b9060600160405180910390a150505b60006068544761340f9190614729565b90506801bc16d674ec80000081106134615760405162461bcd60e51b8152602060048201526015602482015274756e6578706563746564206163636f756e74696e6760581b6044820152606401610343565b8061346d575050919050565b6069548110156134c757806068600082825461348991906146f2565b90915550506040518181527f7a745a2c63a535068f52ceca27debd5297bbad5f7f37ec53d044a59d0362445d906020015b60405180910390a161366b565b606a5481111561365a577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b15801561352c57600080fd5b505af1158015613540573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb92506044019050602060405180830381600087803b1580156135d057600080fd5b505af11580156135e4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136089190613e58565b5060016034600082825461361c9190614729565b909155505060345460408051918252602082018390527f6aa7e30787b26429ced603a7aba8b19c4b5d5bcf29a3257da953c8d53bcaa3a691016134ba565b613663846137be565b949350505050565b5050919050565b60335460ff166136bb5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610343565b6033805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa336130f1565b6000613741826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166137d69092919063ffffffff16565b805190915015611e72578080602001905181019061375f9190613e58565b611e725760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610343565b600081156137ce576137ce613099565b506000919050565b60606137e584846000856137ef565b90505b9392505050565b6060824710156138505760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610343565b843b61389e5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610343565b600080866001600160a01b031685876040516138ba91906141a3565b60006040518083038185875af1925050503d80600081146138f7576040519150601f19603f3d011682016040523d82523d6000602084013e6138fc565b606091505b509150915061390c828286613917565b979650505050505050565b606083156139265750816137e8565b8251156139365782518084602001fd5b8160405162461bcd60e51b815260040161034391906144c1565b8280548282559060005260206000209081019282156139a3579160200282015b828111156139a35781546001600160a01b0319166001600160a01b03843516178255602090920191600190910190613970565b506139af929150613a08565b5090565b8280548282559060005260206000209081019282156139a3579160200282015b828111156139a357825182546001600160a01b0319166001600160a01b039091161782556020909201916001909101906139d3565b5b808211156139af5760008155600101613a09565b60008083601f840112613a2f57600080fd5b5081356001600160401b03811115613a4657600080fd5b6020830191508360208260051b8501011115613a6157600080fd5b9250929050565b600082601f830112613a7957600080fd5b81356020613a8e613a898361468e565b61465e565b80838252828201915082860187848660051b8901011115613aae57600080fd5b60005b85811015613ad6578135613ac4816147f5565b84529284019290840190600101613ab1565b5090979650505050505050565b60008083601f840112613af557600080fd5b5081356001600160401b03811115613b0c57600080fd5b602083019150836020828501011115613a6157600080fd5b600060a08284031215613b3657600080fd5b50919050565b600060a08284031215613b4e57600080fd5b60405160a081018181106001600160401b0382111715613b7057613b706147df565b604052905080613b7f83613bc7565b8152613b8d60208401613be0565b6020820152613b9e60408401613be0565b60408201526060830135613bb18161480a565b6060820152608092830135920191909152919050565b803563ffffffff81168114613bdb57600080fd5b919050565b80356001600160401b0381168114613bdb57600080fd5b600060208284031215613c0957600080fd5b81356137e8816147f5565b600060208284031215613c2657600080fd5b81516137e8816147f5565b60008060408385031215613c4457600080fd5b8235613c4f816147f5565b91506020830135613c5f816147f5565b809150509250929050565b600080600060608486031215613c7f57600080fd5b8335613c8a816147f5565b92506020840135613c9a816147f5565b929592945050506040919091013590565b60008060408385031215613cbe57600080fd5b8235613cc9816147f5565b946020939093013593505050565b60008060208385031215613cea57600080fd5b82356001600160401b03811115613d0057600080fd5b613d0c85828601613a1d565b90969095509350505050565b600080600060608486031215613d2d57600080fd5b83356001600160401b0380821115613d4457600080fd5b613d5087838801613a68565b94506020860135915080821115613d6657600080fd5b613d7287838801613a68565b93506040860135915080821115613d8857600080fd5b50613d9586828701613a68565b9150509250925092565b600080600060e08486031215613db457600080fd5b83356001600160401b03811115613dca57600080fd5b8401601f81018613613ddb57600080fd5b80356020613deb613a898361468e565b8083825282820191508285018a848660051b8801011115613e0b57600080fd5b600095505b84861015613e3557613e2181613be0565b835260019590950194918301918301613e10565b509650508601359350613e4f915086905060408601613b3c565b90509250925092565b600060208284031215613e6a57600080fd5b81516137e88161480a565b600060208284031215613e8757600080fd5b5035919050565b60008060008060408587031215613ea457600080fd5b84356001600160401b0380821115613ebb57600080fd5b613ec788838901613ae3565b90965094506020870135915080821115613ee057600080fd5b50613eed87828801613a1d565b95989497509550505050565b600080600080600080600080610120898b031215613f1657600080fd5b88356001600160401b0380821115613f2d57600080fd5b613f398c838d01613ae3565b909a50985060208b0135915080821115613f5257600080fd5b613f5e8c838d01613a1d565b909850965060408b0135915080821115613f7757600080fd5b50613f848b828c01613ae3565b90955093505060608901359150613f9e8a60808b01613b24565b90509295985092959890939650565b600080600080600060e08688031215613fc557600080fd5b85356001600160401b0380821115613fdc57600080fd5b613fe889838a01613ae3565b9097509550602088013591508082111561400157600080fd5b5061400e88828901613a1d565b909450925061402290508760408801613b24565b90509295509295909350565b60008060006060848603121561404357600080fd5b505081359360208301359350604090920135919050565b60006020828403121561406c57600080fd5b5051919050565b6000806040838503121561408657600080fd5b50508035926020909101359150565b8183526000602080850194508260005b858110156140d1576001600160401b036140be83613be0565b16875295820195908201906001016140a5565b509495945050505050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6000815180845261411d816020860160208601614740565b601f01601f19169290920160200192915050565b63ffffffff61413f82613bc7565b16825261414e60208201613be0565b6001600160401b0380821660208501528061416b60408501613be0565b166040850152505060608101356141818161480a565b15156060830152608090810135910152565b8183823760009101908152919050565b600082516141b5818460208701614740565b9190910192915050565b6001600160a01b03851681526101006020808301829052855191830182905260009161012084019187810191845b818110156142125783516001600160401b0316855293820193928201926001016141ed565b505082935086604086015263ffffffff865116606086015280860151925050506001600160401b0380821660808501528060408601511660a085015250506060830151151560c0830152608083015160e083015295945050505050565b6020808252825182820181905260009190848201906040850190845b818110156142b05783516001600160a01b03168352928401929184019160010161428b565b50909695505050505050565b6000604082016040835280865480835260608501915087600052602092508260002060005b828110156143065781546001600160a01b0316845292840192600191820191016142e1565b505050838103828501528481528590820160005b8681101561434857823561432d816147f5565b6001600160a01b03168252918301919083019060010161431a565b50979650505050505050565b6040815260006143686040830186886140dc565b828103602084015261390c818587614095565b60006101208083526143908184018b8d6140dc565b905082810360208401526143a581898b614095565b905082810360408401526143ba8187896140dc565b9150508360608301526143d06080830184614131565b9998505050505050505050565b60e0815260006143f160e0830187896140dc565b8281036020840152614404818688614095565b9150506144146040830184614131565b9695505050505050565b60808152600061443260808301888a6140dc565b82810360208401526144448188614105565b905082810360408401526144598186886140dc565b915050826060830152979650505050505050565b6060815260006144816060830186886140dc565b846020840152828103604084015261390c8185614105565b60208101600483106144bb57634e487b7160e01b600052602160045260246000fd5b91905290565b6020815260006137e86020830184614105565b60208082526017908201527f43616c6c6572206973206e6f7420746865205661756c74000000000000000000604082015260600190565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b60208082526010908201526f14185d5cd8589b194e881c185d5cd95960821b604082015260600190565b6020808252601d908201527f43616c6c6572206973206e6f7420746865205265676973747261746f72000000604082015260600190565b6020808252600e908201526d1499595b9d1c985b9d0818d85b1b60921b604082015260600190565b6020808252601c908201527f43616c6c6572206973206e6f7420746865205374726174656769737400000000604082015260600190565b6000808335601e1984360301811261461957600080fd5b8301803591506001600160401b0382111561463357600080fd5b602001915036819003821315613a6157600080fd5b60008235605e198336030181126141b557600080fd5b604051601f8201601f191681016001600160401b0381118282101715614686576146866147df565b604052919050565b60006001600160401b038211156146a7576146a76147df565b5060051b60200190565b600080821280156001600160ff1b03849003851316156146d3576146d3614787565b600160ff1b83900384128116156146ec576146ec614787565b50500190565b6000821982111561470557614705614787565b500190565b600081600019048311821515161561472457614724614787565b500290565b60008282101561473b5761473b614787565b500390565b60005b8381101561475b578181015183820152602001614743565b83811115610d305750506000910152565b600060001982141561478057614780614787565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b038116811461238057600080fd5b801515811461238057600080fdfe53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac45357bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa2646970667358221220cb53a48aebce08cd91f08713d34b94e51baee827b032c246ff83f59c6d6e39d364736f6c634300080700337bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a", + "deployedBytecode": "0x6080604052600436106102975760003560e01c8063853828b61161015a578063c2e1e3f4116100c1578063d9f00ec71161007a578063d9f00ec714610908578063dbe55e5614610928578063dd505df61461095c578063de5f626814610990578063f1188e40146109a5578063f6ca71b0146109d957600080fd5b8063c2e1e3f414610842578063c7af335214610862578063c98517c514610877578063cceab75014610894578063d38bfff4146108c8578063d9caed12146108e857600080fd5b80639da0e462116101135780639da0e4621461074e578063a4f98af41461078b578063aa388af6146107a0578063ab12edf5146107ed578063ad1728cb1461080d578063bb1b918d1461082257600080fd5b8063853828b61461068057806387bae867146106955780638d7c0e46146106ba5780639092c31c146106da5780639136616a1461070e57806396d538bb1461072e57600080fd5b80635c975abb116101fe5780636e811d38116101b75780636e811d38146105d55780636ef38795146105f557806371a735f3146106155780637b2d9b2c14610635578063842f5c46146106555780638456cb591461066b57600080fd5b80635c975abb146105125780635d36b190146105365780635f5152261461054b5780636093d3801461056b57806366e3667e1461059f57806367c7066c146105b557600080fd5b8063430bf08a11610250578063430bf08a1461043f578063435356d11461047357806347e7ef2414610493578063484be812146104b3578063579a7e1a146104c95780635a063f63146104fd57600080fd5b80630c340a24146103535780630ed57b3a146103855780630fc3b4c4146103a55780631072cbea146103db57806322495dc8146103fb5780633c8649591461041b57600080fd5b3661034e57336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614806102fb5750336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016145b61034c5760405162461bcd60e51b815260206004820152601e60248201527f657468206e6f742066726f6d20616c6c6f77656420636f6e747261637473000060448201526064015b60405180910390fd5b005b600080fd5b34801561035f57600080fd5b506103686109fb565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561039157600080fd5b5061034c6103a0366004613c31565b610a18565b3480156103b157600080fd5b506103686103c0366004613bf7565b609f602052600090815260409020546001600160a01b031681565b3480156103e757600080fd5b5061034c6103f6366004613cab565b610a4a565b34801561040757600080fd5b5061034c610416366004613d9f565b610b07565b34801561042757600080fd5b5061043160695481565b60405190815260200161037c565b34801561044b57600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b34801561047f57600080fd5b5061034c61048e366004613d18565b610c51565b34801561049f57600080fd5b5061034c6104ae366004613cab565b610d36565b3480156104bf57600080fd5b50610431606a5481565b3480156104d557600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b34801561050957600080fd5b5061034c610e3c565b34801561051e57600080fd5b5060335460ff165b604051901515815260200161037c565b34801561054257600080fd5b5061034c610edb565b34801561055757600080fd5b50610431610566366004613bf7565b610f81565b34801561057757600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b3480156105ab57600080fd5b5061043160345481565b3480156105c157600080fd5b5060a354610368906001600160a01b031681565b3480156105e157600080fd5b5061034c6105f0366004613bf7565b6110b5565b34801561060157600080fd5b5061034c610610366004613cd7565b61113d565b34801561062157600080fd5b5061034c610630366004613fad565b6115d1565b34801561064157600080fd5b50610368610650366004613e75565b6117ca565b34801561066157600080fd5b5061043160685481565b34801561067757600080fd5b5061034c6117f4565b34801561068c57600080fd5b5061034c6118bd565b3480156106a157600080fd5b506033546103689061010090046001600160a01b031681565b3480156106c657600080fd5b5061034c6106d536600461402e565b611a8f565b3480156106e657600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b34801561071a57600080fd5b5061034c610729366004613e75565b611e77565b34801561073a57600080fd5b5061034c610749366004613cd7565b612042565b34801561075a57600080fd5b5061077e610769366004613e75565b60356020526000908152604090205460ff1681565b60405161037c9190614499565b34801561079757600080fd5b50610526612162565b3480156107ac57600080fd5b506105266107bb366004613bf7565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0390811691161490565b3480156107f957600080fd5b5061034c610808366004614073565b6121c1565b34801561081957600080fd5b5061034c6122bd565b34801561082e57600080fd5b5061034c61083d366004613ef9565b612383565b34801561084e57600080fd5b5061034c61085d366004613bf7565b6124f6565b34801561086e57600080fd5b50610526612583565b34801561088357600080fd5b506104316801bc16d674ec80000081565b3480156108a057600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b3480156108d457600080fd5b5061034c6108e3366004613bf7565b6125b4565b3480156108f457600080fd5b5061034c610903366004613c6a565b612658565b34801561091457600080fd5b5061034c610923366004613e8e565b6126eb565b34801561093457600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b34801561096857600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b34801561099c57600080fd5b5061034c6128e0565b3480156109b157600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b3480156109e557600080fd5b506109ee612a2a565b60405161037c919061426f565b6000610a136000805160206148398339815191525490565b905090565b610a20612583565b610a3c5760405162461bcd60e51b81526004016103439061450b565b610a468282612a8c565b5050565b610a52612583565b610a6e5760405162461bcd60e51b81526004016103439061450b565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b039081169083161415610aeb5760405162461bcd60e51b815260206004820152601f60248201527f43616e6e6f74207472616e7366657220737570706f72746564206173736574006044820152606401610343565b610a46610af66109fb565b6001600160a01b0384169083612beb565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b158015610b6057600080fd5b505afa158015610b74573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b989190613c14565b6001600160a01b0316336001600160a01b031614610bc85760405162461bcd60e51b8152600401610343906145cb565b60405163bc26e7e560e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063bc26e7e590610c1a9030908790879087906004016141bf565b600060405180830381600087803b158015610c3457600080fd5b505af1158015610c48573d6000803e3d6000fd5b50505050505050565b610c59612583565b610c755760405162461bcd60e51b81526004016103439061450b565b600054610100900460ff1680610c8e575060005460ff16155b610cf15760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610343565b600054610100900460ff16158015610d13576000805461ffff19166101011790555b610d1e848484612c3d565b8015610d30576000805461ff00191690555b50505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610d7e5760405162461bcd60e51b8152600401610343906144d4565b60008051602061481983398151915280546002811415610db05760405162461bcd60e51b8152600401610343906145a3565b600282557f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316846001600160a01b031614610e295760405162461bcd60e51b8152602060048201526011602482015270155b9cdd5c1c1bdc9d195908185cdcd95d607a1b6044820152606401610343565b610e338484612cf8565b50600190555050565b60a3546001600160a01b03163314610e965760405162461bcd60e51b815260206004820152601b60248201527f43616c6c6572206973206e6f74207468652048617276657374657200000000006044820152606401610343565b60008051602061481983398151915280546002811415610ec85760405162461bcd60e51b8152600401610343906145a3565b60028255610ed4612d8a565b5060019055565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b031614610f765760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b6064820152608401610343565b610f7f33612fd8565b565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b031614610ff85760405162461bcd60e51b8152602060048201526011602482015270155b9cdd5c1c1bdc9d195908185cdcd95d607a1b6044820152606401610343565b6040516370a0823160e01b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b15801561105757600080fd5b505afa15801561106b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061108f919061405a565b6034546110a5906801bc16d674ec80000061470a565b6110af91906146f2565b92915050565b6110bd612583565b6110d95760405162461bcd60e51b81526004016103439061450b565b6040516001600160a01b03821681527f83f29c79feb71f8fba9d0fbc4ba5f0982a28b6b1e868b3fc50e6400d100bca0f9060200160405180910390a1603380546001600160a01b0390921661010002610100600160a81b0319909216919091179055565b60335461010090046001600160a01b0316331461116c5760405162461bcd60e51b81526004016103439061456c565b60335460ff161561118f5760405162461bcd60e51b815260040161034390614542565b60006111a4826801bc16d674ec80000061470a565b6040516370a0823160e01b81523060048201529091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b15801561120657600080fd5b505afa15801561121a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061123e919061405a565b8111156112815760405162461bcd60e51b81526020600482015260116024820152700d2dce6eaccccd2c6d2cadce840ae8aa89607b1b6044820152606401610343565b604051632e1a7d4d60e01b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b1580156112e357600080fd5b505af11580156112f7573d6000803e3d6000fd5b5084925060009150505b818110156115b357600085858381811061131d5761131d6147c9565b905060200281019061132f9190614648565b6113399080614602565b604051611347929190614193565b6040805191829003909120600081815260356020529182205490925060ff16908160038111156113795761137961479d565b146113c65760405162461bcd60e51b815260206004820152601860248201527f56616c696461746f72206e6f74207265676973746572656400000000000000006044820152606401610343565b60408051600160f81b60208201526000602182018190526bffffffffffffffffffffffff193060601b16602c830152910160405160208183030381529060405290507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663228951186801bc16d674ec8000008a8a88818110611453576114536147c9565b90506020028101906114659190614648565b61146f9080614602565b858d8d8b818110611482576114826147c9565b90506020028101906114949190614648565b6114a2906020810190614602565b8f8f8d8181106114b4576114b46147c9565b90506020028101906114c69190614648565b604001356040518863ffffffff1660e01b81526004016114eb9695949392919061441e565b6000604051808303818588803b15801561150457600080fd5b505af1158015611518573d6000803e3d6000fd5b50505050507ffeb31a79d38edb1b090d516e4df3e273651179c6f2c2ec53a9a22ae015b70ba9888886818110611550576115506147c9565b90506020028101906115629190614648565b61156c9080614602565b6801bc16d674ec80000084604051611587949392919061446d565b60405180910390a150506000908152603560205260409020805460ff1916600190811790915501611301565b5080603460008282546115c691906146f2565b909155505050505050565b60335461010090046001600160a01b031633146116005760405162461bcd60e51b81526004016103439061456c565b60335460ff16156116235760405162461bcd60e51b815260040161034390614542565b6000603560008787604051611639929190614193565b604080519182900390912082526020820192909252016000205460ff169050600281600381111561166c5761166c61479d565b146116b15760405162461bcd60e51b815260206004820152601560248201527456616c696461746f72206e6f742065786974696e6760581b6044820152606401610343565b6040516312b3fc1960e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906312b3fc199061170590899089908990899089906004016143dd565b600060405180830381600087803b15801561171f57600080fd5b505af1158015611733573d6000803e3d6000fd5b505050507ff72821b8777f002ccdf6326f1242d9e0f762eb077668b67bebe640535378066d8686868660405161176c9493929190614354565b60405180910390a1600360356000888860405161178a929190614193565b60408051918290039091208252602082019290925201600020805460ff191660018360038111156117bd576117bd61479d565b0217905550505050505050565b60a481815481106117da57600080fd5b6000918252602090912001546001600160a01b0316905081565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b15801561184d57600080fd5b505afa158015611861573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118859190613c14565b6001600160a01b0316336001600160a01b0316146118b55760405162461bcd60e51b8152600401610343906145cb565b610f7f613099565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016148061190c57506118f76109fb565b6001600160a01b0316336001600160a01b0316145b6119645760405162461bcd60e51b815260206004820152602360248201527f43616c6c6572206973206e6f7420746865205661756c74206f7220476f7665726044820152623737b960e91b6064820152608401610343565b600080516020614819833981519152805460028114156119965760405162461bcd60e51b8152600401610343906145a3565b600282556040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b1580156119fc57600080fd5b505afa158015611a10573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a34919061405a565b90508015611a8757611a877f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000008361310e565b505060019055565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b158015611ae857600080fd5b505afa158015611afc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b209190613c14565b6001600160a01b0316336001600160a01b031614611b505760405162461bcd60e51b8152600401610343906145cb565b60335460ff16611b995760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610343565b6002198312158015611bac575060038313155b8015611bc65750600083603454611bc391906146b1565b12155b611c125760405162461bcd60e51b815260206004820152601760248201527f696e76616c69642076616c696461746f727344656c74610000000000000000006044820152606401610343565b6811ff6cf0fd15afffff198212158015611c3557506811ff6cf0fd15b000008213155b8015611c4f5750600082606854611c4c91906146b1565b12155b611c9b5760405162461bcd60e51b815260206004820152601d60248201527f696e76616c696420636f6e73656e7375735265776172647344656c74610000006044820152606401610343565b6801bc16d674ec800000811115611cf45760405162461bcd60e51b815260206004820152601960248201527f696e76616c69642077657468546f5661756c74416d6f756e74000000000000006044820152606401610343565b60408051848152602081018490529081018290527f80d022717ea022455c5886b8dd8a29c037570aae58aeb4d7b136d7a10ec2e4319060600160405180910390a182603454611d4391906146b1565b603455606854611d549083906146b1565b6068558015611e215760405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018390527f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb90604401602060405180830381600087803b158015611de757600080fd5b505af1158015611dfb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e1f9190613e58565b505b611e2b6000613206565b611e6a5760405162461bcd60e51b815260206004820152601060248201526f333ab9b29039ba34b63610313637bbb760811b6044820152606401610343565b611e72613672565b505050565b611e7f612583565b611e9b5760405162461bcd60e51b81526004016103439061450b565b60a0548110611edc5760405162461bcd60e51b815260206004820152600d60248201526c092dcecc2d8d2c840d2dcc8caf609b1b6044820152606401610343565b600060a08281548110611ef157611ef16147c9565b60009182526020808320909101546001600160a01b03908116808452609f90925260409092205460a05491935090911690611f2e90600190614729565b831015611fb05760a08054611f4590600190614729565b81548110611f5557611f556147c9565b60009182526020909120015460a080546001600160a01b039092169185908110611f8157611f816147c9565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505b60a0805480611fc157611fc16147b3565b60008281526020808220600019908401810180546001600160a01b031990811690915593019093556001600160a01b03858116808352609f855260409283902080549094169093559051908416815290917f16b7600acff27e39a8a96056b3d533045298de927507f5c1d97e4accde60488c910160405180910390a2505050565b61204a612583565b6120665760405162461bcd60e51b81526004016103439061450b565b8060005b81811015612119576000848483818110612086576120866147c9565b905060200201602081019061209b9190613bf7565b6001600160a01b031614156121095760405162461bcd60e51b815260206004820152602e60248201527f43616e206e6f742073657420616e20656d70747920616464726573732061732060448201526d30903932bbb0b932103a37b5b2b760911b6064820152608401610343565b6121128161476c565b905061206a565b507f04c0b9649497d316554306e53678d5f5f5dbc3a06f97dec13ff4cfe98b986bbc60a4848460405161214e939291906142bc565b60405180910390a1610d3060a48484613950565b60335460009061010090046001600160a01b031633146121945760405162461bcd60e51b81526004016103439061456c565b60335460ff16156121b75760405162461bcd60e51b815260040161034390614542565b610a136001613206565b6121c9612583565b6121e55760405162461bcd60e51b81526004016103439061450b565b80821080156121fc57506801bc16d674ec80000082105b801561221057506801bc16d674ec80000081105b801561222d5750673782dace9d90000061222a8383614729565b10155b6122795760405162461bcd60e51b815260206004820152601760248201527f696e636f7272656374206675736520696e74657276616c0000000000000000006044820152606401610343565b60408051838152602081018390527fcb8d24e46eb3c402bf344ee60a6576cba9ef2f59ea1af3b311520704924e901a910160405180910390a1606991909155606a55565b60405163095ea7b360e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015260001960248301527f0000000000000000000000000000000000000000000000000000000000000000169063095ea7b390604401602060405180830381600087803b15801561234857600080fd5b505af115801561235c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123809190613e58565b50565b60335461010090046001600160a01b031633146123b25760405162461bcd60e51b81526004016103439061456c565b60335460ff16156123d55760405162461bcd60e51b815260040161034390614542565b6040516301ba3ee760e21b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906306e8fb9c9061242f908b908b908b908b908b908b908b908b9060040161437b565b600060405180830381600087803b15801561244957600080fd5b505af115801561245d573d6000803e3d6000fd5b505050506000603560008a8a604051612477929190614193565b60408051918290039091208252602082019290925201600020805460ff191660018360038111156124aa576124aa61479d565b02179055507f75c4a66b2c6c28cf46db7131182a812e4fbbb2f0591377aa83a737909a9b68c3888888886040516124e49493929190614354565b60405180910390a15050505050505050565b6124fe612583565b61251a5760405162461bcd60e51b81526004016103439061450b565b60a354604080516001600160a01b03928316815291831660208301527fe48386b84419f4d36e0f96c10cc3510b6fb1a33795620c5098b22472bbe90796910160405180910390a160a380546001600160a01b0319166001600160a01b0392909216919091179055565b600061259b6000805160206148398339815191525490565b6001600160a01b0316336001600160a01b031614905090565b6125bc612583565b6125d85760405162461bcd60e51b81526004016103439061450b565b612600817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b03166126206000805160206148398339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146126a05760405162461bcd60e51b8152600401610343906144d4565b600080516020614819833981519152805460028114156126d25760405162461bcd60e51b8152600401610343906145a3565b600282556126e185858561310e565b5060019055505050565b60335461010090046001600160a01b0316331461271a5760405162461bcd60e51b81526004016103439061456c565b60335460ff161561273d5760405162461bcd60e51b815260040161034390614542565b6000603560008686604051612753929190614193565b604080519182900390912082526020820192909252016000205460ff16905060018160038111156127865761278661479d565b146127ca5760405162461bcd60e51b815260206004820152601460248201527315985b1a59185d1bdc881b9bdd081cdd185ad95960621b6044820152606401610343565b604051633877322b60e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690633877322b9061281c908890889088908890600401614354565b600060405180830381600087803b15801561283657600080fd5b505af115801561284a573d6000803e3d6000fd5b505050507ff8821da16f5ed966b41e0343c3eff9903af782d74f99f1689dd9d4562b6545b3858585856040516128839493929190614354565b60405180910390a160026035600087876040516128a1929190614193565b60408051918290039091208252602082019290925201600020805460ff191660018360038111156128d4576128d461479d565b02179055505050505050565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146129285760405162461bcd60e51b8152600401610343906144d4565b6000805160206148198339815191528054600281141561295a5760405162461bcd60e51b8152600401610343906145a3565b600282556040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b1580156129c057600080fd5b505afa1580156129d4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129f8919061405a565b90508015611a8757611a877f000000000000000000000000000000000000000000000000000000000000000082612cf8565b606060a4805480602002602001604051908101604052809291908181526020018280548015612a8257602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612a64575b5050505050905090565b6001600160a01b038281166000908152609f60205260409020541615612ae95760405162461bcd60e51b81526020600482015260126024820152711c151bdad95b88185b1c9958591e481cd95d60721b6044820152606401610343565b6001600160a01b03821615801590612b0957506001600160a01b03811615155b612b495760405162461bcd60e51b8152602060048201526011602482015270496e76616c69642061646472657373657360781b6044820152606401610343565b6001600160a01b038281166000818152609f6020908152604080832080549587166001600160a01b0319968716811790915560a0805460018101825594527f78fdc8d422c49ced035a9edf18d00d3c6a8d81df210f3e5e448e045e77b41e8890930180549095168417909455925190815290917fef6485b84315f9b1483beffa32aae9a0596890395e3d7521f1c5fbb51790e765910160405180910390a25050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052611e729084906136ec565b8251612c509060a49060208601906139b3565b50815181518114612c9a5760405162461bcd60e51b8152602060048201526014602482015273496e76616c696420696e7075742061727261797360601b6044820152606401610343565b60005b81811015612cf157612ce1848281518110612cba57612cba6147c9565b6020026020010151848381518110612cd457612cd46147c9565b6020026020010151612a8c565b612cea8161476c565b9050612c9d565b5050505050565b60008111612d415760405162461bcd60e51b81526020600482015260166024820152754d757374206465706f73697420736f6d657468696e6760501b6044820152606401610343565b6040805160008152602081018390526001600160a01b038416917f5548c837ab068cf56a2c2479df0882a4922fd203edb7517321831d95078c5f62910160405180910390a25050565b60335460ff1615612dad5760405162461bcd60e51b815260040161034390614542565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663e52253816040518163ffffffff1660e01b8152600401602060405180830381600087803b158015612e0a57600080fd5b505af1158015612e1e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e42919061405a565b9050600060685482612e5491906146f2565b905080471015612ea65760405162461bcd60e51b815260206004820152601860248201527f696e73756666696369656e74206574682062616c616e636500000000000000006044820152606401610343565b8015610a465760006068819055507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b158015612f0f57600080fd5b505af1158015612f23573d6000803e3d6000fd5b505060a354604080516001600160a01b0392831681527f0000000000000000000000000000000000000000000000000000000000000000909216602083015281018590527ff6c07a063ed4e63808eb8da7112d46dbcd38de2b40a73dbcc9353c5a94c7235393506060019150612f969050565b60405180910390a160a354610a46906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116911683612beb565b6001600160a01b03811661302e5760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f7220697320616464726573732830290000000000006044820152606401610343565b806001600160a01b031661304e6000805160206148398339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a36123808160008051602061483983398151915255565b60335460ff16156130bc5760405162461bcd60e51b815260040161034390614542565b6033805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586130f13390565b6040516001600160a01b03909116815260200160405180910390a1565b6000811161315e5760405162461bcd60e51b815260206004820152601760248201527f4d75737420776974686472617720736f6d657468696e670000000000000000006044820152606401610343565b6001600160a01b0383166131ad5760405162461bcd60e51b8152602060048201526016602482015275135d5cdd081cdc1958da599e481c9958da5c1a595b9d60521b6044820152606401610343565b6040805160008152602081018390526001600160a01b038416917f2717ead6b9200dd235aad468c9809ea400fe33ac69b5bfaa6d3e90fc922b6398910160405180910390a2611e726001600160a01b0383168483612beb565b600060685447101561321b576110af826137be565b60006068544761322b9190614729565b9050600191506801bc16d674ec80000081106133ff5760006801bc16d674ec8000008204905080603460008282546132639190614729565b909155506000905061327e826801bc16d674ec80000061470a565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b1580156132db57600080fd5b505af11580156132ef573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb92506044019050602060405180830381600087803b15801561337f57600080fd5b505af1158015613393573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133b79190613e58565b5060345460408051848152602081019290925281018290527fbe7040030ff7b347853214bf49820c6d455fedf58f3815f85c7bc5216993682b9060600160405180910390a150505b60006068544761340f9190614729565b90506801bc16d674ec80000081106134615760405162461bcd60e51b8152602060048201526015602482015274756e6578706563746564206163636f756e74696e6760581b6044820152606401610343565b8061346d575050919050565b6069548110156134c757806068600082825461348991906146f2565b90915550506040518181527f7a745a2c63a535068f52ceca27debd5297bbad5f7f37ec53d044a59d0362445d906020015b60405180910390a161366b565b606a5481111561365a577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b15801561352c57600080fd5b505af1158015613540573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb92506044019050602060405180830381600087803b1580156135d057600080fd5b505af11580156135e4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136089190613e58565b5060016034600082825461361c9190614729565b909155505060345460408051918252602082018390527f6aa7e30787b26429ced603a7aba8b19c4b5d5bcf29a3257da953c8d53bcaa3a691016134ba565b613663846137be565b949350505050565b5050919050565b60335460ff166136bb5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610343565b6033805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa336130f1565b6000613741826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166137d69092919063ffffffff16565b805190915015611e72578080602001905181019061375f9190613e58565b611e725760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610343565b600081156137ce576137ce613099565b506000919050565b60606137e584846000856137ef565b90505b9392505050565b6060824710156138505760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610343565b843b61389e5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610343565b600080866001600160a01b031685876040516138ba91906141a3565b60006040518083038185875af1925050503d80600081146138f7576040519150601f19603f3d011682016040523d82523d6000602084013e6138fc565b606091505b509150915061390c828286613917565b979650505050505050565b606083156139265750816137e8565b8251156139365782518084602001fd5b8160405162461bcd60e51b815260040161034391906144c1565b8280548282559060005260206000209081019282156139a3579160200282015b828111156139a35781546001600160a01b0319166001600160a01b03843516178255602090920191600190910190613970565b506139af929150613a08565b5090565b8280548282559060005260206000209081019282156139a3579160200282015b828111156139a357825182546001600160a01b0319166001600160a01b039091161782556020909201916001909101906139d3565b5b808211156139af5760008155600101613a09565b60008083601f840112613a2f57600080fd5b5081356001600160401b03811115613a4657600080fd5b6020830191508360208260051b8501011115613a6157600080fd5b9250929050565b600082601f830112613a7957600080fd5b81356020613a8e613a898361468e565b61465e565b80838252828201915082860187848660051b8901011115613aae57600080fd5b60005b85811015613ad6578135613ac4816147f5565b84529284019290840190600101613ab1565b5090979650505050505050565b60008083601f840112613af557600080fd5b5081356001600160401b03811115613b0c57600080fd5b602083019150836020828501011115613a6157600080fd5b600060a08284031215613b3657600080fd5b50919050565b600060a08284031215613b4e57600080fd5b60405160a081018181106001600160401b0382111715613b7057613b706147df565b604052905080613b7f83613bc7565b8152613b8d60208401613be0565b6020820152613b9e60408401613be0565b60408201526060830135613bb18161480a565b6060820152608092830135920191909152919050565b803563ffffffff81168114613bdb57600080fd5b919050565b80356001600160401b0381168114613bdb57600080fd5b600060208284031215613c0957600080fd5b81356137e8816147f5565b600060208284031215613c2657600080fd5b81516137e8816147f5565b60008060408385031215613c4457600080fd5b8235613c4f816147f5565b91506020830135613c5f816147f5565b809150509250929050565b600080600060608486031215613c7f57600080fd5b8335613c8a816147f5565b92506020840135613c9a816147f5565b929592945050506040919091013590565b60008060408385031215613cbe57600080fd5b8235613cc9816147f5565b946020939093013593505050565b60008060208385031215613cea57600080fd5b82356001600160401b03811115613d0057600080fd5b613d0c85828601613a1d565b90969095509350505050565b600080600060608486031215613d2d57600080fd5b83356001600160401b0380821115613d4457600080fd5b613d5087838801613a68565b94506020860135915080821115613d6657600080fd5b613d7287838801613a68565b93506040860135915080821115613d8857600080fd5b50613d9586828701613a68565b9150509250925092565b600080600060e08486031215613db457600080fd5b83356001600160401b03811115613dca57600080fd5b8401601f81018613613ddb57600080fd5b80356020613deb613a898361468e565b8083825282820191508285018a848660051b8801011115613e0b57600080fd5b600095505b84861015613e3557613e2181613be0565b835260019590950194918301918301613e10565b509650508601359350613e4f915086905060408601613b3c565b90509250925092565b600060208284031215613e6a57600080fd5b81516137e88161480a565b600060208284031215613e8757600080fd5b5035919050565b60008060008060408587031215613ea457600080fd5b84356001600160401b0380821115613ebb57600080fd5b613ec788838901613ae3565b90965094506020870135915080821115613ee057600080fd5b50613eed87828801613a1d565b95989497509550505050565b600080600080600080600080610120898b031215613f1657600080fd5b88356001600160401b0380821115613f2d57600080fd5b613f398c838d01613ae3565b909a50985060208b0135915080821115613f5257600080fd5b613f5e8c838d01613a1d565b909850965060408b0135915080821115613f7757600080fd5b50613f848b828c01613ae3565b90955093505060608901359150613f9e8a60808b01613b24565b90509295985092959890939650565b600080600080600060e08688031215613fc557600080fd5b85356001600160401b0380821115613fdc57600080fd5b613fe889838a01613ae3565b9097509550602088013591508082111561400157600080fd5b5061400e88828901613a1d565b909450925061402290508760408801613b24565b90509295509295909350565b60008060006060848603121561404357600080fd5b505081359360208301359350604090920135919050565b60006020828403121561406c57600080fd5b5051919050565b6000806040838503121561408657600080fd5b50508035926020909101359150565b8183526000602080850194508260005b858110156140d1576001600160401b036140be83613be0565b16875295820195908201906001016140a5565b509495945050505050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6000815180845261411d816020860160208601614740565b601f01601f19169290920160200192915050565b63ffffffff61413f82613bc7565b16825261414e60208201613be0565b6001600160401b0380821660208501528061416b60408501613be0565b166040850152505060608101356141818161480a565b15156060830152608090810135910152565b8183823760009101908152919050565b600082516141b5818460208701614740565b9190910192915050565b6001600160a01b03851681526101006020808301829052855191830182905260009161012084019187810191845b818110156142125783516001600160401b0316855293820193928201926001016141ed565b505082935086604086015263ffffffff865116606086015280860151925050506001600160401b0380821660808501528060408601511660a085015250506060830151151560c0830152608083015160e083015295945050505050565b6020808252825182820181905260009190848201906040850190845b818110156142b05783516001600160a01b03168352928401929184019160010161428b565b50909695505050505050565b6000604082016040835280865480835260608501915087600052602092508260002060005b828110156143065781546001600160a01b0316845292840192600191820191016142e1565b505050838103828501528481528590820160005b8681101561434857823561432d816147f5565b6001600160a01b03168252918301919083019060010161431a565b50979650505050505050565b6040815260006143686040830186886140dc565b828103602084015261390c818587614095565b60006101208083526143908184018b8d6140dc565b905082810360208401526143a581898b614095565b905082810360408401526143ba8187896140dc565b9150508360608301526143d06080830184614131565b9998505050505050505050565b60e0815260006143f160e0830187896140dc565b8281036020840152614404818688614095565b9150506144146040830184614131565b9695505050505050565b60808152600061443260808301888a6140dc565b82810360208401526144448188614105565b905082810360408401526144598186886140dc565b915050826060830152979650505050505050565b6060815260006144816060830186886140dc565b846020840152828103604084015261390c8185614105565b60208101600483106144bb57634e487b7160e01b600052602160045260246000fd5b91905290565b6020815260006137e86020830184614105565b60208082526017908201527f43616c6c6572206973206e6f7420746865205661756c74000000000000000000604082015260600190565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b60208082526010908201526f14185d5cd8589b194e881c185d5cd95960821b604082015260600190565b6020808252601d908201527f43616c6c6572206973206e6f7420746865205265676973747261746f72000000604082015260600190565b6020808252600e908201526d1499595b9d1c985b9d0818d85b1b60921b604082015260600190565b6020808252601c908201527f43616c6c6572206973206e6f7420746865205374726174656769737400000000604082015260600190565b6000808335601e1984360301811261461957600080fd5b8301803591506001600160401b0382111561463357600080fd5b602001915036819003821315613a6157600080fd5b60008235605e198336030181126141b557600080fd5b604051601f8201601f191681016001600160401b0381118282101715614686576146866147df565b604052919050565b60006001600160401b038211156146a7576146a76147df565b5060051b60200190565b600080821280156001600160ff1b03849003851316156146d3576146d3614787565b600160ff1b83900384128116156146ec576146ec614787565b50500190565b6000821982111561470557614705614787565b500190565b600081600019048311821515161561472457614724614787565b500290565b60008282101561473b5761473b614787565b500390565b60005b8381101561475b578181015183820152602001614743565b83811115610d305750506000910152565b600060001982141561478057614780614787565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b038116811461238057600080fd5b801515811461238057600080fdfe53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac45357bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa2646970667358221220cb53a48aebce08cd91f08713d34b94e51baee827b032c246ff83f59c6d6e39d364736f6c63430008070033", "libraries": {}, "devdoc": { "author": "Origin Protocol Inc", @@ -1592,7 +1592,7 @@ "storageLayout": { "storage": [ { - "astId": 5243, + "astId": 5254, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "initialized", "offset": 0, @@ -1600,7 +1600,7 @@ "type": "t_bool" }, { - "astId": 5246, + "astId": 5257, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "initializing", "offset": 1, @@ -1608,7 +1608,7 @@ "type": "t_bool" }, { - "astId": 5286, + "astId": 5297, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "______gap", "offset": 0, @@ -1624,7 +1624,7 @@ "type": "t_bool" }, { - "astId": 3506, + "astId": 3513, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "validatorRegistrator", "offset": 1, @@ -1632,7 +1632,7 @@ "type": "t_address" }, { - "astId": 3509, + "astId": 3516, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "activeDepositedValidators", "offset": 0, @@ -1640,15 +1640,15 @@ "type": "t_uint256" }, { - "astId": 3515, + "astId": 3522, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "validatorsStates", "offset": 0, "slot": "53", - "type": "t_mapping(t_bytes32,t_enum(VALIDATOR_STATE)3524)" + "type": "t_mapping(t_bytes32,t_enum(VALIDATOR_STATE)3531)" }, { - "astId": 3519, + "astId": 3526, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "__gap", "offset": 0, @@ -1656,7 +1656,7 @@ "type": "t_array(t_uint256)50_storage" }, { - "astId": 3043, + "astId": 3054, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "consensusRewards", "offset": 0, @@ -1664,7 +1664,7 @@ "type": "t_uint256" }, { - "astId": 3047, + "astId": 3057, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "fuseIntervalStart", "offset": 0, @@ -1672,7 +1672,7 @@ "type": "t_uint256" }, { - "astId": 3051, + "astId": 3060, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "fuseIntervalEnd", "offset": 0, @@ -1680,7 +1680,7 @@ "type": "t_uint256" }, { - "astId": 3055, + "astId": 3064, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "__gap", "offset": 0, @@ -1688,7 +1688,7 @@ "type": "t_array(t_uint256)50_storage" }, { - "astId": 5366, + "astId": 5377, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "_deprecated_platformAddress", "offset": 0, @@ -1696,7 +1696,7 @@ "type": "t_address" }, { - "astId": 5369, + "astId": 5380, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "_deprecated_vaultAddress", "offset": 0, @@ -1704,7 +1704,7 @@ "type": "t_address" }, { - "astId": 5374, + "astId": 5385, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "assetToPToken", "offset": 0, @@ -1712,7 +1712,7 @@ "type": "t_mapping(t_address,t_address)" }, { - "astId": 5378, + "astId": 5389, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "assetsMapped", "offset": 0, @@ -1720,7 +1720,7 @@ "type": "t_array(t_address)dyn_storage" }, { - "astId": 5380, + "astId": 5391, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "_deprecated_rewardTokenAddress", "offset": 0, @@ -1728,7 +1728,7 @@ "type": "t_address" }, { - "astId": 5382, + "astId": 5393, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "_deprecated_rewardLiquidationThreshold", "offset": 0, @@ -1736,7 +1736,7 @@ "type": "t_uint256" }, { - "astId": 5385, + "astId": 5396, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "harvesterAddress", "offset": 0, @@ -1744,7 +1744,7 @@ "type": "t_address" }, { - "astId": 5389, + "astId": 5400, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "rewardTokenAddresses", "offset": 0, @@ -1752,7 +1752,7 @@ "type": "t_array(t_address)dyn_storage" }, { - "astId": 5393, + "astId": 5404, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "_reserved", "offset": 0, @@ -1760,7 +1760,7 @@ "type": "t_array(t_int256)98_storage" }, { - "astId": 2613, + "astId": 2625, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "__gap", "offset": 0, @@ -1802,7 +1802,7 @@ "label": "bytes32", "numberOfBytes": "32" }, - "t_enum(VALIDATOR_STATE)3524": { + "t_enum(VALIDATOR_STATE)3531": { "encoding": "inplace", "label": "enum ValidatorRegistrator.VALIDATOR_STATE", "numberOfBytes": "1" @@ -1819,12 +1819,12 @@ "numberOfBytes": "32", "value": "t_address" }, - "t_mapping(t_bytes32,t_enum(VALIDATOR_STATE)3524)": { + "t_mapping(t_bytes32,t_enum(VALIDATOR_STATE)3531)": { "encoding": "mapping", "key": "t_bytes32", "label": "mapping(bytes32 => enum ValidatorRegistrator.VALIDATOR_STATE)", "numberOfBytes": "32", - "value": "t_enum(VALIDATOR_STATE)3524" + "value": "t_enum(VALIDATOR_STATE)3531" }, "t_uint256": { "encoding": "inplace", diff --git a/contracts/deployments/holesky/solcInputs/02842452c275dc62641a0db2f51fdc73.json b/contracts/deployments/holesky/solcInputs/02842452c275dc62641a0db2f51fdc73.json new file mode 100644 index 0000000000..d3aa747a64 --- /dev/null +++ b/contracts/deployments/holesky/solcInputs/02842452c275dc62641a0db2f51fdc73.json @@ -0,0 +1,104 @@ +{ + "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/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/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/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" + }, + "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/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/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/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 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 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 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/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" + }, + "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/strategies/NativeStaking/FeeAccumulator.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { Address } from \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport { Governable } from \"../../governance/Governable.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 is Governable {\n /// @notice The address of the Native Staking Strategy\n address public immutable STRATEGY;\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 }\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\";\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\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_ADDRESS;\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 // For future use\n uint256[50] 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 _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 address _feeAccumulator,\n address _beaconChainDepositContract\n )\n InitializableAbstractStrategy(_baseConfig)\n ValidatorAccountant(\n _wethAddress,\n _baseConfig.vaultAddress,\n _beaconChainDepositContract,\n _ssvNetwork\n )\n {\n SSV_TOKEN_ADDRESS = _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 /// @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_TOKEN_ADDRESS).deposit{ value: ethRewards }();\n\n emit RewardTokenCollected(\n harvesterAddress,\n WETH_TOKEN_ADDRESS,\n ethRewards\n );\n IERC20(WETH_TOKEN_ADDRESS).safeTransfer(\n harvesterAddress,\n ethRewards\n );\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_TOKEN_ADDRESS, \"Unsupported asset\");\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_TOKEN_ADDRESS).balanceOf(\n address(this)\n );\n if (wethBalance > 0) {\n _deposit(WETH_TOKEN_ADDRESS, wethBalance);\n }\n }\n\n /// @notice Withdraw WETH from this contract. Used only if some WETH for is lingering on the contract. That\n /// can happen when:\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 _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 emit Withdrawal(_asset, address(0), _amount);\n IERC20(_asset).safeTransfer(_recipient, _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_TOKEN_ADDRESS).balanceOf(\n address(this)\n );\n if (wethBalance > 0) {\n _withdraw(vaultAddress, WETH_TOKEN_ADDRESS, wethBalance);\n }\n }\n\n function _abstractSetPToken(address _asset, address) internal override {}\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_TOKEN_ADDRESS, \"Unsupported asset\");\n\n balance =\n // add the ETH that has been staked in validators\n activeDepositedValidators *\n 32 ether +\n // add the WETH in the strategy from deposits that are still to be staked\n IERC20(WETH_TOKEN_ADDRESS).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_TOKEN_ADDRESS;\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_ADDRESS).approve(\n SSV_NETWORK_ADDRESS,\n type(uint256).max\n );\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 ||\n msg.sender == WETH_TOKEN_ADDRESS,\n \"eth not from allowed contracts\"\n );\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 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 MAX_STAKE = 32 ether;\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\n uint256[50] 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 constructor(\n address _wethAddress,\n address _vaultAddress,\n address _beaconChainDepositContract,\n address _ssvNetwork\n )\n ValidatorRegistrator(\n _wethAddress,\n _vaultAddress,\n _beaconChainDepositContract,\n _ssvNetwork\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 _fuseIntervalStart < 32 ether &&\n _fuseIntervalEnd < 32 ether &&\n _fuseIntervalEnd - _fuseIntervalStart >= 4 ether,\n \"incorrect fuse interval\"\n );\n\n emit FuseIntervalUpdated(_fuseIntervalStart, _fuseIntervalEnd);\n\n fuseIntervalStart = _fuseIntervalStart;\n fuseIntervalEnd = _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 returns (bool accountingValid)\n {\n // pause the accounting on failure\n accountingValid = _doAccounting(true);\n }\n\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 >= MAX_STAKE) {\n uint256 fullyWithdrawnValidators;\n // safe since MAX_STAKE is hardcoded to 32ETH\n unchecked {\n // explicitly cast to uint256 as we want to round to a whole number of validators\n fullyWithdrawnValidators = uint256(newSweptETH / MAX_STAKE);\n }\n activeDepositedValidators -= fullyWithdrawnValidators;\n\n uint256 wethToVault = MAX_STAKE * fullyWithdrawnValidators;\n IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: wethToVault }();\n IWETH9(WETH_TOKEN_ADDRESS).transfer(VAULT_ADDRESS, 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 < 32 ether, \"unexpected accounting\");\n\n // If no Beacon chain consensus rewards swept\n if (ethRemaining == 0) {\n // do nothing\n return accountingValid;\n }\n // Beacon chain consensus rewards swept (partial validator withdrawals)\n else if (ethRemaining < fuseIntervalStart) {\n // solhint-disable-next-line reentrancy\n consensusRewards += ethRemaining;\n emit AccountingConsensusRewards(ethRemaining);\n }\n // Beacon chain consensus rewards swept but also a slashed validator fully exited\n else if (ethRemaining > fuseIntervalEnd) {\n IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: ethRemaining }();\n IWETH9(WETH_TOKEN_ADDRESS).transfer(VAULT_ADDRESS, ethRemaining);\n activeDepositedValidators -= 1;\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 /// @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 plus one, minus one or unchanged with zero\n /// @param _wethToVaultAmount the amount of WETH to be sent to the Vault\n /// @param _consensusRewardsDelta adjust the accounted for consensus rewards up or down\n function manuallyFixAccounting(\n int256 _validatorsDelta,\n int256 _consensusRewardsDelta,\n uint256 _wethToVaultAmount\n ) external onlyStrategist whenPaused {\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(_wethToVaultAmount <= 32 ether, \"invalid wethToVaultAmount\");\n\n emit AccountingManuallyFixed(\n _validatorsDelta,\n _consensusRewardsDelta,\n _wethToVaultAmount\n );\n\n activeDepositedValidators = uint256(\n int256(activeDepositedValidators) + _validatorsDelta\n );\n consensusRewards = uint256(\n int256(consensusRewards) + _consensusRewardsDelta\n );\n if (_wethToVaultAmount > 0) {\n IWETH9(WETH_TOKEN_ADDRESS).transfer(\n VAULT_ADDRESS,\n _wethToVaultAmount\n );\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" + }, + "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 address of the Wrapped ETH (WETH) token contract\n address public immutable WETH_TOKEN_ADDRESS;\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_ADDRESS;\n /// @notice Address of the OETH Vault proxy contract\n address public immutable VAULT_ADDRESS;\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\n // For future use\n uint256[50] private __gap;\n\n enum VALIDATOR_STATE {\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 newAddress);\n event ETHStaked(bytes pubkey, uint256 amount, bytes withdrawal_credentials);\n event SSVValidatorRegistered(bytes pubkey, uint64[] operatorIds);\n event SSVValidatorExitInitiated(bytes pubkey, uint64[] operatorIds);\n event SSVValidatorExitCompleted(bytes pubkey, uint64[] operatorIds);\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 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 constructor(\n address _wethAddress,\n address _vaultAddress,\n address _beaconChainDepositContract,\n address _ssvNetwork\n ) {\n WETH_TOKEN_ADDRESS = _wethAddress;\n BEACON_CHAIN_DEPOSIT_CONTRACT = _beaconChainDepositContract;\n SSV_NETWORK_ADDRESS = _ssvNetwork;\n VAULT_ADDRESS = _vaultAddress;\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 emit RegistratorChanged(_address);\n validatorRegistrator = _address;\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 function stakeEth(ValidatorStakeData[] calldata validators)\n external\n onlyRegistrator\n whenNotPaused\n {\n uint256 requiredETH = validators.length * 32 ether;\n\n // Check there is enough WETH from the deposits sitting in this strategy contract\n require(\n requiredETH <= IWETH9(WETH_TOKEN_ADDRESS).balanceOf(address(this)),\n \"insufficient WETH\"\n );\n\n // Convert required ETH from WETH\n IWETH9(WETH_TOKEN_ADDRESS).withdraw(requiredETH);\n\n uint256 validatorsLength = validators.length;\n // For each validator\n for (uint256 i = 0; i < validatorsLength; ) {\n bytes32 pubkeyHash = keccak256(validators[i].pubkey);\n VALIDATOR_STATE currentState = validatorsStates[pubkeyHash];\n\n require(\n currentState == VALIDATOR_STATE.REGISTERED,\n \"Validator not registered\"\n );\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 withdrawal_credentials = abi.encodePacked(\n bytes1(0x01),\n bytes11(0),\n address(this)\n );\n IDepositContract(BEACON_CHAIN_DEPOSIT_CONTRACT).deposit{\n value: 32 ether\n }(\n validators[i].pubkey,\n withdrawal_credentials,\n validators[i].signature,\n validators[i].depositDataRoot\n );\n\n emit ETHStaked(\n validators[i].pubkey,\n 32 ether,\n withdrawal_credentials\n );\n\n validatorsStates[pubkeyHash] = VALIDATOR_STATE.STAKED;\n\n unchecked {\n ++i;\n }\n }\n // save gas by changing this storage variable only once rather each time in the loop.\n activeDepositedValidators += validatorsLength;\n }\n\n /// @notice Registers a new validator in the SSV Cluster.\n /// Only the registrator can call this function.\n function registerSsvValidator(\n bytes calldata publicKey,\n uint64[] calldata operatorIds,\n bytes calldata sharesData,\n uint256 amount,\n Cluster calldata cluster\n ) external onlyRegistrator whenNotPaused {\n ISSVNetwork(SSV_NETWORK_ADDRESS).registerValidator(\n publicKey,\n operatorIds,\n sharesData,\n amount,\n cluster\n );\n validatorsStates[keccak256(publicKey)] = VALIDATOR_STATE.REGISTERED;\n emit SSVValidatorRegistered(publicKey, operatorIds);\n }\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 function exitSsvValidator(\n bytes calldata publicKey,\n uint64[] calldata operatorIds\n ) external onlyRegistrator whenNotPaused {\n VALIDATOR_STATE currentState = validatorsStates[keccak256(publicKey)];\n require(currentState == VALIDATOR_STATE.STAKED, \"Validator not staked\");\n\n ISSVNetwork(SSV_NETWORK_ADDRESS).exitValidator(publicKey, operatorIds);\n emit SSVValidatorExitInitiated(publicKey, operatorIds);\n\n validatorsStates[keccak256(publicKey)] = VALIDATOR_STATE.EXITING;\n }\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 function removeSsvValidator(\n bytes calldata publicKey,\n uint64[] calldata operatorIds,\n Cluster calldata cluster\n ) external onlyRegistrator whenNotPaused {\n VALIDATOR_STATE currentState = validatorsStates[keccak256(publicKey)];\n require(\n currentState == VALIDATOR_STATE.EXITING,\n \"Validator not exiting\"\n );\n\n ISSVNetwork(SSV_NETWORK_ADDRESS).removeValidator(\n publicKey,\n operatorIds,\n cluster\n );\n emit SSVValidatorExitCompleted(publicKey, operatorIds);\n\n validatorsStates[keccak256(publicKey)] = VALIDATOR_STATE.EXIT_COMPLETE;\n }\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 cluster The SSV cluster details that must be derived from emitted events from the SSVNetwork contract.\n function depositSSV(\n uint64[] memory operatorIds,\n uint256 amount,\n Cluster memory cluster\n ) external onlyStrategist {\n ISSVNetwork(SSV_NETWORK_ADDRESS).deposit(\n address(this),\n operatorIds,\n amount,\n cluster\n );\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/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/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" + } + }, + "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 From fc48427a5acb235499913c7705af009a7b4a961c Mon Sep 17 00:00:00 2001 From: Domen Grabec Date: Sat, 11 May 2024 01:52:20 +0200 Subject: [PATCH 050/273] adjust the comment --- .../contracts/strategies/NativeStaking/ValidatorAccountant.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol b/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol index 8d8aaaaca1..31fd891951 100644 --- a/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol +++ b/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol @@ -180,7 +180,7 @@ abstract contract ValidatorAccountant is ValidatorRegistrator { } /// @notice Allow the Strategist to fix the accounting of this strategy and unpause. - /// @param _validatorsDelta adjust the active validators by plus one, minus one or unchanged with zero + /// @param _validatorsDelta adjust the active validators by up to plus three or minus three /// @param _consensusRewardsDelta adjust the accounted for consensus rewards up or down function manuallyFixAccounting( int256 _validatorsDelta, From 4b51655f3a548d0db41fa70638b8f52928f86dd2 Mon Sep 17 00:00:00 2001 From: Domen Grabec Date: Mon, 13 May 2024 02:57:16 +0200 Subject: [PATCH 051/273] add rate limit to calling manually fix accounting (#2057) * add rate limit to calling manually fix accounting * fix comment --- .../NativeStaking/ValidatorAccountant.sol | 13 ++++- contracts/test/strategies/nativeSSVStaking.js | 51 +++++++++++++++++++ 2 files changed, 63 insertions(+), 1 deletion(-) diff --git a/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol b/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol index 31fd891951..1014d0a546 100644 --- a/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol +++ b/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol @@ -10,6 +10,8 @@ import { IWETH9 } from "../../interfaces/IWETH9.sol"; /// Full withdrawals are from exited validators. /// @author Origin Protocol Inc abstract contract ValidatorAccountant is ValidatorRegistrator { + /// @notice The minimum amount of blocks that need to pass between two calls to manuallyFixAccounting + uint256 public constant MIN_FIX_ACCOUNTING_CADENCE = 7200; // 1 day /// @notice The maximum amount of ETH that can be staked by a validator /// @dev this can change in the future with EIP-7251, Increase the MAX_EFFECTIVE_BALANCE uint256 public constant MAX_STAKE = 32 ether; @@ -21,8 +23,10 @@ abstract contract ValidatorAccountant is ValidatorRegistrator { uint256 public fuseIntervalStart; /// @notice end of fuse interval uint256 public fuseIntervalEnd; + /// @notice last block number manuallyFixAccounting has been called + uint256 public lastFixAccountingBlockNumber; - uint256[50] private __gap; + uint256[49] private __gap; event FuseIntervalUpdated(uint256 start, uint256 end); event AccountingFullyWithdrawnValidator( @@ -186,6 +190,11 @@ abstract contract ValidatorAccountant is ValidatorRegistrator { int256 _validatorsDelta, int256 _consensusRewardsDelta ) external onlyStrategist whenPaused { + require( + lastFixAccountingBlockNumber + MIN_FIX_ACCOUNTING_CADENCE < + block.number, + "manuallyFixAccounting called too soon" + ); require( _validatorsDelta >= -3 && _validatorsDelta <= 3 && @@ -210,6 +219,8 @@ abstract contract ValidatorAccountant is ValidatorRegistrator { int256(consensusRewards) + _consensusRewardsDelta ); + lastFixAccountingBlockNumber = block.number; + // rerun the accounting to see if it has now been fixed. // Do not pause the accounting on failure as it is already paused require(_doAccounting(false), "fuse still blown"); diff --git a/contracts/test/strategies/nativeSSVStaking.js b/contracts/test/strategies/nativeSSVStaking.js index da1babcf5f..e96de92d3b 100644 --- a/contracts/test/strategies/nativeSSVStaking.js +++ b/contracts/test/strategies/nativeSSVStaking.js @@ -4,6 +4,7 @@ const { parseEther } = require("ethers").utils; const { setBalance, setStorageAt, + mine, } = require("@nomicfoundation/hardhat-network-helpers"); const { isCI } = require("../helpers"); @@ -12,6 +13,7 @@ const { shouldBehaveLikeHarvestable } = require("../behaviour/harvestable"); const { shouldBehaveLikeStrategy } = require("../behaviour/strategy"); const { MAX_UINT256 } = require("../../utils/constants"); const { impersonateAndFund } = require("../../utils/signers"); +const minFixAccountingCadence = 7200 + 1; const { createFixtureLoader, @@ -543,6 +545,7 @@ describe("Unit test: Native SSV Staking Strategy", function () { const { nativeStakingSSVStrategy, strategist } = fixture; await nativeStakingSSVStrategy.connect(strategist).pause(); + await mine(minFixAccountingCadence); await expect( nativeStakingSSVStrategy.connect(strategist).manuallyFixAccounting( @@ -563,6 +566,7 @@ describe("Unit test: Native SSV Staking Strategy", function () { const { nativeStakingSSVStrategy, strategist } = fixture; await nativeStakingSSVStrategy.connect(strategist).pause(); + await mine(minFixAccountingCadence); await expect( nativeStakingSSVStrategy.connect(strategist).manuallyFixAccounting( @@ -587,6 +591,7 @@ describe("Unit test: Native SSV Staking Strategy", function () { await setActiveDepositedValidators(10, nativeStakingSSVStrategy); await nativeStakingSSVStrategy.connect(strategist).pause(); + await mine(minFixAccountingCadence); const activeDepositedValidatorsBefore = await nativeStakingSSVStrategy.activeDepositedValidators(); @@ -619,6 +624,7 @@ describe("Unit test: Native SSV Staking Strategy", function () { await setActiveDepositedValidators(10000, nativeStakingSSVStrategy); await nativeStakingSSVStrategy.connect(strategist).pause(); + await mine(minFixAccountingCadence); const consensusRewardsDelta = parseEther(delta.toString()); const tx = await nativeStakingSSVStrategy @@ -647,6 +653,7 @@ describe("Unit test: Native SSV Staking Strategy", function () { .transfer(nativeStakingSSVStrategy.address, parseEther("5")); await nativeStakingSSVStrategy.connect(strategist).pause(); + await mine(minFixAccountingCadence); // unit test fixture sets OUSD governor as accounting governor const tx = await nativeStakingSSVStrategy .connect(strategist) @@ -662,6 +669,50 @@ describe("Unit test: Native SSV Staking Strategy", function () { parseEther("2.3") // consensusRewards ); }); + + it("Calling manually fix accounting too often should result in an error", async () => { + const { nativeStakingSSVStrategy, strategist, governor } = fixture; + + await nativeStakingSSVStrategy.connect(strategist).pause(); + await mine(minFixAccountingCadence); + await nativeStakingSSVStrategy + .connect(strategist) + .manuallyFixAccounting( + 0, //_validatorsDelta + parseEther("0") //_consensusRewardsDelta + ); + + await nativeStakingSSVStrategy.connect(strategist).pause(); + await mine(minFixAccountingCadence - 4); + await expect( + nativeStakingSSVStrategy.connect(strategist).manuallyFixAccounting( + 0, //_validatorsDelta + parseEther("0") //_consensusRewardsDelta + ) + ).to.be.revertedWith("manuallyFixAccounting called too soon"); + }); + + it("Calling manually fix accounting twice with enough blocks in between should pass", async () => { + const { nativeStakingSSVStrategy, strategist, governor } = fixture; + + await nativeStakingSSVStrategy.connect(strategist).pause(); + await mine(minFixAccountingCadence); + await nativeStakingSSVStrategy + .connect(strategist) + .manuallyFixAccounting( + 0, //_validatorsDelta + parseEther("0") //_consensusRewardsDelta + ); + + await nativeStakingSSVStrategy.connect(strategist).pause(); + await mine(minFixAccountingCadence); + await nativeStakingSSVStrategy + .connect(strategist) + .manuallyFixAccounting( + 0, //_validatorsDelta + parseEther("0") //_consensusRewardsDelta + ); + }); }); }); From 657b06412462ebbc178a5cbe6595b87dd2cf6bed Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Mon, 13 May 2024 14:10:22 +1000 Subject: [PATCH 052/273] Correct deployName in Native Staking deploy script --- contracts/deploy/mainnet/096_native_ssv_staking.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/deploy/mainnet/096_native_ssv_staking.js b/contracts/deploy/mainnet/096_native_ssv_staking.js index 63bfbdaaae..98b5d35b69 100644 --- a/contracts/deploy/mainnet/096_native_ssv_staking.js +++ b/contracts/deploy/mainnet/096_native_ssv_staking.js @@ -3,7 +3,7 @@ const addresses = require("../../utils/addresses"); module.exports = deploymentWithGovernanceProposal( { - deployName: "091_native_ssv_staking", + deployName: "096_native_ssv_staking", forceDeploy: false, //forceSkip: true, reduceQueueTime: true, From 769018aa8fe79c60fae936c5a012c463319cec9f Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Mon, 13 May 2024 14:30:35 +1000 Subject: [PATCH 053/273] Fix linter --- contracts/test/strategies/nativeSSVStaking.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/test/strategies/nativeSSVStaking.js b/contracts/test/strategies/nativeSSVStaking.js index e96de92d3b..691ff946d2 100644 --- a/contracts/test/strategies/nativeSSVStaking.js +++ b/contracts/test/strategies/nativeSSVStaking.js @@ -671,7 +671,7 @@ describe("Unit test: Native SSV Staking Strategy", function () { }); it("Calling manually fix accounting too often should result in an error", async () => { - const { nativeStakingSSVStrategy, strategist, governor } = fixture; + const { nativeStakingSSVStrategy, strategist } = fixture; await nativeStakingSSVStrategy.connect(strategist).pause(); await mine(minFixAccountingCadence); @@ -693,7 +693,7 @@ describe("Unit test: Native SSV Staking Strategy", function () { }); it("Calling manually fix accounting twice with enough blocks in between should pass", async () => { - const { nativeStakingSSVStrategy, strategist, governor } = fixture; + const { nativeStakingSSVStrategy, strategist } = fixture; await nativeStakingSSVStrategy.connect(strategist).pause(); await mine(minFixAccountingCadence); From b98e9def5e4db48c2bfbe1ddf969a37b5e274e7d Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Mon, 13 May 2024 14:31:11 +1000 Subject: [PATCH 054/273] Remove approveAssets on Swapper contract in 095_ogn_buyback script as it has already been done --- contracts/deploy/mainnet/095_ogn_buyback.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/deploy/mainnet/095_ogn_buyback.js b/contracts/deploy/mainnet/095_ogn_buyback.js index 10c1187ae0..02b66499fa 100644 --- a/contracts/deploy/mainnet/095_ogn_buyback.js +++ b/contracts/deploy/mainnet/095_ogn_buyback.js @@ -17,7 +17,7 @@ module.exports = deploymentWithGovernanceProposal( const cOETHBuybackProxy = await ethers.getContract("OETHBuybackProxy"); const cOUSDBuybackProxy = await ethers.getContract("BuybackProxy"); - const cSwapper = await ethers.getContract("Swapper1InchV5"); + // const cSwapper = await ethers.getContract("Swapper1InchV5"); // Deploy new OETHBuyback implementation const dOETHBuybackImpl = await deployWithConfirmation( @@ -45,7 +45,7 @@ module.exports = deploymentWithGovernanceProposal( true ); - await cSwapper.approveAssets([addresses.mainnet.OGN]); + // await cSwapper.approveAssets([addresses.mainnet.OGN]); if (!isFork) { // No Governance action on mainnet From 622a3b474884f0d740afb66631baa2060bc295b2 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Mon, 13 May 2024 14:59:38 +1000 Subject: [PATCH 055/273] Fix Holesky fork tests --- contracts/test/behaviour/ssvStrategy.js | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/contracts/test/behaviour/ssvStrategy.js b/contracts/test/behaviour/ssvStrategy.js index f11ef2cf02..5bf9f5fc3e 100644 --- a/contracts/test/behaviour/ssvStrategy.js +++ b/contracts/test/behaviour/ssvStrategy.js @@ -7,7 +7,6 @@ const { const hre = require("hardhat"); const { oethUnits } = require("../helpers"); -const addresses = require("../../utils/addresses"); const { impersonateAndFund } = require("../../utils/signers"); const { getClusterInfo } = require("../../utils/ssv"); const { parseEther } = require("ethers/lib/utils"); @@ -139,6 +138,7 @@ const shouldBehaveLikeAnSsvStrategy = (context) => { it("Should register and staked 32 ETH by validator registrator", async () => { const { + addresses, weth, ssv, nativeStakingSSVStrategy, @@ -153,7 +153,7 @@ const shouldBehaveLikeAnSsvStrategy = (context) => { const { cluster } = await getClusterInfo({ ownerAddress: nativeStakingSSVStrategy.address, operatorIds: testValidator.operatorIds, - chainId: 1, + chainId: hre.network.config.chainId, ssvNetwork: addresses.SSVNetwork, }); @@ -219,7 +219,7 @@ const shouldBehaveLikeAnSsvStrategy = (context) => { const { cluster } = await getClusterInfo({ ownerAddress: nativeStakingSSVStrategy.address, operatorIds: testValidator.operatorIds, - chainId: 1, + chainId: hre.network.config.chainId, ssvNetwork: addresses.SSVNetwork, }); @@ -348,6 +348,9 @@ const shouldBehaveLikeAnSsvStrategy = (context) => { const rewards = oethUnits("3"); const withdrawals = oethUnits("64"); + const expectedConsensusRewards = rewards.sub( + await nativeStakingSSVStrategy.consensusRewards() + ); const vaultWethBalanceBefore = await weth.balanceOf(oethVault.address); // simulate withdraw of 2 validators and consensus rewards @@ -366,7 +369,7 @@ const shouldBehaveLikeAnSsvStrategy = (context) => { await expect(tx) .to.emit(nativeStakingSSVStrategy, "AccountingConsensusRewards") - .withArgs(rewards); + .withArgs(expectedConsensusRewards); // check balances after expect( @@ -376,7 +379,7 @@ const shouldBehaveLikeAnSsvStrategy = (context) => { "checkBalance should decrease" ); expect(await nativeStakingSSVStrategy.consensusRewards()).to.equal( - consensusRewardsBefore.add(rewards), + consensusRewardsBefore.add(expectedConsensusRewards), "consensusRewards should increase" ); expect( From c25745d1fc2e58baf343a9995104c4b7576eff3c Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Mon, 13 May 2024 15:24:14 +1000 Subject: [PATCH 056/273] Fix mainnet fork tests --- contracts/test/strategies/nativeSsvStaking.fork-test.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/contracts/test/strategies/nativeSsvStaking.fork-test.js b/contracts/test/strategies/nativeSsvStaking.fork-test.js index 12b502c26d..4249ffeb66 100644 --- a/contracts/test/strategies/nativeSsvStaking.fork-test.js +++ b/contracts/test/strategies/nativeSsvStaking.fork-test.js @@ -21,14 +21,14 @@ describe("ForkTest: Native SSV Staking Strategy", function () { addresses: addresses.mainnet, testValidator: { publicKey: - "0x93d60259213f491a910ee8f6504d51ba5fc28085981eccd6c20ca646525c626013c75b04f061fbf3de839ac602c64698", + "0xaba6acd335d524a89fb89b9977584afdb23f34a6742547fa9ec1c656fbd2bfc0e7a234460328c2731828c9a43be06e25", operatorIds: [348, 352, 361, 377], sharesData: - "0x861fce88da51de578b2a3f9fa32b3c56499b1261d33f8adbb24932cc906edfd6383b63ac37bfd8b2e9f7087622c1f14b1651426316c741bd8470315d63393bbdc8a0a097f1ac728315fbf17b79b675e9c40605913fff64800a5c7c2057e30f44abed76d8ce797db6f03219e077a3d1fa3945f37d8eeb4c52aee99b4a5f606be50515d347405db37b37a063cd1cd315818521decd2e44878a1a53e84a4186ea3e896a29e0e34c68091a4575b5834e6bfa6c5987916ae49d77347ee7b2f7428f8489a07e54e9d05690f5f8acc2eeab46f44a0f39e5e0e41fde76d29e2660fb5349e00d264527f92d71cfa27a51d9285873908757f42f8f9e40a9c3ec5d9adc966a4dde82d0b87c48ffaebfe2bda73ff388197829d24eb2b18cc50dbae96473a95d819dc1dc99959811e832396eec4773701dbaf86d6449c8310f7fa9ed289675a0ba1be59881fe7b1e64d4485654bab3f9010e575773262ac65f7fa24663f090d413ca74572dac7df3cf06c1fdc226acfc1380441c2d9c4b31fbdd5ee12d83e2d36b9512f4e9c5f0b3607b51665479a9ce035ee952c9d743b5d7b3fa1acec222b447bf8e98397a6e79569a1487adff39f06bfa0a51b022d1798738b37a0801a1f97498c6c3633404f251c137b21e0eec92bcb7a4eb00cad9c826327f4712643035e4b79d14d3e5b0bcf791e6bbfa447f30d362570c26c29787d7c9360b3566b1e9c6eb3f785c96c6d3642a2332910fe3f0b78d4d18d7d4bbedd0b919c8a2853a0babd353c695960d4ec00727a3a91192b8b3a4d4e7cfd1620cdb4936afd91f5155c20bbe8a3dd96790d5e623f9cea53fa32ebe8f2f2572d5d99686ba735d824aaa74a56fd0fde9c219811cb79760410be3815ca95b75551608ee945b895a5c08b760b90aa4836128048b4fd19e0ed475c720d83a76af7e8c3e571f11b0fc540c788d7daea8bc923db44a6f8d208e0140a18d1c811029419d27b4ed994f0ec21c8f65df2f0c83cf5d0111694c18076e7441b0e0fa8e58da3a6c3b94e819550322765d70fbd4f053f2edcba3050cfe14d0efe7280c4a3990182a46cdf4a7f8cf20e0fc17d4fb5becb35908a04e19f5be2df7db81edf9cae016ac88769cb1a644189d84e35e18ff0d2fea6b02a406129487009311525199ffec581fd587521a239f6514e6e10aeef63e531cbe4c37f08592999ce3c3146e76e2793a974d49e0c7264c214133bd2049eacb8f09b3184130812b71fb0cd02d2f044f1d38ab34d1a9bed9940b5691f396c7e2ad25b6baf6ed14baa0f70ef3fd2d5cafd16c7775f6583971223eab2276b98e1998e87692e8474647bc135fab8d8ff7bbdd3d669856897cf7776b594f7cf49ac02870df621eca1919b39f9d28bddee92f3b5150e806b9fe9db01e6e1474d09239799c1265bdab86e8eda0f69cebf921af3ba852f5b64d2129bfa09155dc411165d66c0d750fa9fc07a6be3fdbce769bb494b84eff41319618c1611fe3f62b39066e81ee5ead615d7a576cc8fe68e8bb6ba1d4088810c701f0c1873df8cd02d5019589c095bb730a5625a3996c0b240aaf4484f2502d4aa377d462894557615a5d486339b4ad108ef6ffef0a26ba0136e3d969b4337954069aaeaa73e64757477f30d723ba38dc644f6e371088d9e2b1ff50ecbddad48198e525963fabda4e196c9ddf0d89abcdc3a3d395a96b22254242ce93804e4d6673265e7c4d56b1195aada97bbe9050e843bd56181a533fa03e01285ade0f715d0f9830b1f0ae7586d8485bf76ace561ea6c8c4c9497674d96182a9e289ddcc722814f14b8ce8a70bbb6dec40f84cde55e0d16d4ec043561d6a1d16790b5bc4f02ab9", + "0x859f01c8f609cb5cb91f0c98e9b39b077775f10302d0db0edc4ea65e692c97920d5169f6281845a956404c0ba90b88060b74aa3755347441a5729b90bf30a449fa568e21915d11733c7135602b2a3d1a4dce41218ecb0fdb1788ee7e48a9ebd4b4b34f62deea20e9212ce78040dcad2e6382c2f4d4c8b3515a840e1693574068e26c0d58f17dc47d30efe4393f2660dc988aba6166b67732e8df7d9a69d316f330779b2fa4d14712d3bb60436d912bab4464c7c31ae8d2a966d7829063821fc899cc3ec4a8c7098b042323eb9d9cc4d5e945c6d5e6d4eb1b2484163d4b8cd83eea4cc195a68320f023b4d2405cda5110a2eea2c12b70abd9b6bfb567a7850a95fe073a0485c787744efc8658789b0faaff0d942b3c7b89540f594d007936f23c3e7c79fabfe1e2c49199a3f374198e231ca391909ca05ee3c89a7292207131653f6f2f5f5d638d4789a8029001b93827f6f45ef062c9a9d1360a3aedae00fbb8c34495056bacc98c6cecfc1171c84a1e47f3bc328539dbbcd6c79c2aebf7833c684bd807cc8c4dfd6b660e64aece6adf659a969851cf976dead050e9d14aa9c358326c0c0f0cb747041830e124ec872fcf6f82e7f05024da9e6bad10319ca085a0d1519b04c60738043babc1f5a144655e6a28922c2734701c5c93b845996589b8fd246e1bcd97570951cdbed032eeb9c2ac49ac8aeb2e988b6a5513ddcef9ca9bd592c0bce7d38041b52e69e85cda5fd0b84f905c7212b299cf265ee603add20d6459e0841dd05524e96574eebb46473151ec10a08873f7075e15342852f9f16aeb8305211706632475c39ccd8da33969390d035f8a68324e7adced66a726f80532b425cc82dd52a2edc10989db0167317b472a0016215dae35b4c26b28c0ebcf56e115eb32231449812e9ce866a8c0b3128878d3878f5be0670051a8bf94807123c54e6ea2f51607e32c2fe1b132c905c81965dd6d2a7474aa40b65f18d34084a74ba9a21fbdfba3bfaf6b11175d85f03181d655fda086d8dbe2f03dfa2e1b7140b1d9dc68fc9e22f184ed278599d29f6660af128e4c548de6926912d920e35575db90338a1a840f8d8842685f5b459fda573eaf5c5180e3369fc50faa681941dbe7dec83ee9649f30c1a0eac1f8a42fb3083d9274f4c622e2aa1e74b70fa6c027b4f23e1f80bfc4f69248b4d0b3e0eee9372869f97eb89d8d155e469191c48834ad58dd831f1b73409d71fccb958b6582a4ac3f98bcffff2abd393cbe64d7397ada699ecc75301e3be9e9b4ee92a990202c6a5e5112de5ea9cd666f41cdac4611575c8efe2137d6132cd4d4eea0de159eab44588a88f887e4263f673fb365415df537c77a4aaaee12dceff022eafcb8e6973eec7e18eb65cfeefa845b79754ec52a9270f0a7e570b1dd2171e629d498f34e6371726fa8cfe6863f9263c5222a953a44612944183789ad1020de8da527bf850429558dda7896059476e497284512c946d7a57acda3c3ee722d280c0d0daf758d6be88db48e96e14124832c38aa6d0dd38baeb4f246b01d7b0beb55c3983fb182cbf630b778384cc13ab6216611bc1eab94ffe17bb1e829700c99ec28fae1a87eaefd9c8edc4cdf3b6f2b07d85e0d8090ddfb2df4280dacd13a1f30cf946f5606940dc3f75622159b1c6f84bfdbd4ba9fa0f1d522f52bc2049da53f0d06931d650ef1274eb0247844c36349617095f9734e89be683fd7bd5001b416d800c53ec8e8eb533c418a83e803daf6fdfd552ca745bb2b24d8abe899ea89572524343386a035b675e9d5eeae81aefb3a24397f36fe501c66b27d1c0e453fcc975c888d9d6d5a4ca0a4b32b41deebed70", signature: - "0x8522f6464ddc5550f70ed8cd58ed26961d8755111d5e967ee815730bc2e9ad24e7ca718fcf56f1af785bc25dfac719a615a4c4e029a352840edca0d78c9a46ef35202f42311918f70d8ddde9de25fe091889283b9778ea15403fe87dc5f7527e", + "0x90157a1c1b26384f0b4d41bec867d1a000f75e7b634ac7c4c6d8dfc0b0eaeb73bcc99586333d42df98c6b0a8c5ef0d8d071c68991afcd8fbbaa8b423e3632ee4fe0782bc03178a30a8bc6261f64f84a6c833fb96a0f29de1c34ede42c4a859b0", depositDataRoot: - "0xcbcd1da8a9ba0e30b2dd8a955591ac4a759bf5ee6f5295d72f5b89b1b175193b", + "0xdbe778a625c68446f3cc8b2009753a5e7dd7c37b8721ee98a796bb9179dfe8ac", }, }; }); From 4ca3136bb3380f2f6eae5d630daf0280a0a38630 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Mon, 13 May 2024 16:42:29 +1000 Subject: [PATCH 057/273] skip deploy 095_ogn_buyback for now --- contracts/deploy/mainnet/095_ogn_buyback.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/contracts/deploy/mainnet/095_ogn_buyback.js b/contracts/deploy/mainnet/095_ogn_buyback.js index 02b66499fa..fca4565902 100644 --- a/contracts/deploy/mainnet/095_ogn_buyback.js +++ b/contracts/deploy/mainnet/095_ogn_buyback.js @@ -8,7 +8,7 @@ const { module.exports = deploymentWithGovernanceProposal( { deployName: "095_ogn_buyback", - // forceSkip: true, + forceSkip: true, // onlyOnFork: true, // this is only executed in forked environment reduceQueueTime: true, // just to solve the issue of later active proposals failing proposalId: "", @@ -17,7 +17,7 @@ module.exports = deploymentWithGovernanceProposal( const cOETHBuybackProxy = await ethers.getContract("OETHBuybackProxy"); const cOUSDBuybackProxy = await ethers.getContract("BuybackProxy"); - // const cSwapper = await ethers.getContract("Swapper1InchV5"); + const cSwapper = await ethers.getContract("Swapper1InchV5"); // Deploy new OETHBuyback implementation const dOETHBuybackImpl = await deployWithConfirmation( @@ -45,7 +45,7 @@ module.exports = deploymentWithGovernanceProposal( true ); - // await cSwapper.approveAssets([addresses.mainnet.OGN]); + await cSwapper.approveAssets([addresses.mainnet.OGN]); if (!isFork) { // No Governance action on mainnet From 37c9d0ab094edac0c26585eedc3c061b375663b7 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Mon, 13 May 2024 16:44:42 +1000 Subject: [PATCH 058/273] fix some Slither errors --- .../contracts/strategies/NativeStaking/ValidatorAccountant.sol | 2 ++ 1 file changed, 2 insertions(+) diff --git a/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol b/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol index 1014d0a546..6e87e5e52b 100644 --- a/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol +++ b/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol @@ -129,6 +129,7 @@ abstract contract ValidatorAccountant is ValidatorRegistrator { uint256 wethToVault = MAX_STAKE * fullyWithdrawnValidators; IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: wethToVault }(); + // slither-disable-next-line unchecked-transfer IWETH9(WETH_TOKEN_ADDRESS).transfer(VAULT_ADDRESS, wethToVault); emit AccountingFullyWithdrawnValidator( @@ -156,6 +157,7 @@ abstract contract ValidatorAccountant is ValidatorRegistrator { // Beacon chain consensus rewards swept but also a slashed validator fully exited else if (ethRemaining > fuseIntervalEnd) { IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: ethRemaining }(); + // slither-disable-next-line unchecked-transfer IWETH9(WETH_TOKEN_ADDRESS).transfer(VAULT_ADDRESS, ethRemaining); activeDepositedValidators -= 1; From 193af2fd1189d916b2fe5d1b74fb17e7984d83f8 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Mon, 13 May 2024 16:56:50 +1000 Subject: [PATCH 059/273] Fix Slither warnings --- .../strategies/NativeStaking/ValidatorAccountant.sol | 3 +++ .../strategies/NativeStaking/ValidatorRegistrator.sol | 9 +++++++++ 2 files changed, 12 insertions(+) diff --git a/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol b/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol index 6e87e5e52b..d99982cc24 100644 --- a/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol +++ b/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol @@ -105,6 +105,7 @@ abstract contract ValidatorAccountant is ValidatorRegistrator { accountingValid = _doAccounting(true); } + // slither-disable-start reentrancy-eth function _doAccounting(bool pauseOnFail) internal returns (bool accountingValid) @@ -172,6 +173,8 @@ abstract contract ValidatorAccountant is ValidatorRegistrator { } } + // slither-disable-end reentrancy-eth + /// @dev pause any further accounting if required and return false function _failAccounting(bool pauseOnFail) internal diff --git a/contracts/contracts/strategies/NativeStaking/ValidatorRegistrator.sol b/contracts/contracts/strategies/NativeStaking/ValidatorRegistrator.sol index 6b51c2c39f..c8818530c0 100644 --- a/contracts/contracts/strategies/NativeStaking/ValidatorRegistrator.sol +++ b/contracts/contracts/strategies/NativeStaking/ValidatorRegistrator.sol @@ -98,6 +98,7 @@ abstract contract ValidatorRegistrator is Governable, Pausable { /// @param validators A list of validator data needed to stake. /// The `ValidatorStakeData` struct contains the pubkey, signature and depositDataRoot. /// Only the registrator can call this function. + // slither-disable-start reentrancy-eth function stakeEth(ValidatorStakeData[] calldata validators) external onlyRegistrator @@ -160,6 +161,8 @@ abstract contract ValidatorRegistrator is Governable, Pausable { activeDepositedValidators += validatorsLength; } + // slither-disable-end reentrancy-eth + /// @notice Registers a new validator in the SSV Cluster. /// Only the registrator can call this function. function registerSsvValidator( @@ -183,6 +186,7 @@ abstract contract ValidatorRegistrator is Governable, Pausable { /// @notice Exit a validator from the Beacon chain. /// The staked ETH will eventually swept to this native staking strategy. /// Only the registrator can call this function. + // slither-disable-start reentrancy-no-eth function exitSsvValidator( bytes calldata publicKey, uint64[] calldata operatorIds @@ -196,10 +200,13 @@ abstract contract ValidatorRegistrator is Governable, Pausable { validatorsStates[keccak256(publicKey)] = VALIDATOR_STATE.EXITING; } + // slither-disable-end reentrancy-no-eth + /// @notice Remove a validator from the SSV Cluster. /// Make sure `exitSsvValidator` is called before and the validate has exited the Beacon chain. /// If removed before the validator has exited the beacon chain will result in the validator being slashed. /// Only the registrator can call this function. + // slither-disable-start reentrancy-no-eth function removeSsvValidator( bytes calldata publicKey, uint64[] calldata operatorIds, @@ -221,6 +228,8 @@ abstract contract ValidatorRegistrator is Governable, Pausable { validatorsStates[keccak256(publicKey)] = VALIDATOR_STATE.EXIT_COMPLETE; } + // slither-disable-end reentrancy-no-eth + /// @notice Deposits more SSV Tokens to the SSV Network contract which is used to pay the SSV Operators. /// @dev A SSV cluster is defined by the SSVOwnerAddress and the set of operatorIds. /// uses "onlyStrategist" modifier so continuous front-running can't DOS our maintenance service From 6d5034a009eca5b382b090dc93424e2356a15fbc Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Mon, 13 May 2024 17:05:37 +1000 Subject: [PATCH 060/273] Upgrade the CI to use node.js 20.x --- .github/workflows/abi.yml | 2 +- .github/workflows/danger.yml | 4 ++-- .github/workflows/defi.yml | 16 ++++++++-------- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/.github/workflows/abi.yml b/.github/workflows/abi.yml index a82a56a427..ceafc32db9 100644 --- a/.github/workflows/abi.yml +++ b/.github/workflows/abi.yml @@ -19,7 +19,7 @@ jobs: - name: Use Node.js uses: actions/setup-node@v3 with: - node-version: "16.x" + node-version: "20.x" cache: "yarn" cache-dependency-path: contracts/yarn.lock diff --git a/.github/workflows/danger.yml b/.github/workflows/danger.yml index 815c190265..9aff239f04 100644 --- a/.github/workflows/danger.yml +++ b/.github/workflows/danger.yml @@ -9,10 +9,10 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@master - - name: Use Node.js 16x + - name: Use Node.js 20x uses: actions/setup-node@v3 with: - node-version: 16.x + node-version: 20.x cache: "yarn" - run: yarn install --frozen-lockfile - run: yarn danger ci diff --git a/.github/workflows/defi.yml b/.github/workflows/defi.yml index 38508e73a9..97dcdaf79a 100644 --- a/.github/workflows/defi.yml +++ b/.github/workflows/defi.yml @@ -23,7 +23,7 @@ jobs: - name: Use Node.js uses: actions/setup-node@v3 with: - node-version: "16.x" + node-version: "20.x" cache: "yarn" cache-dependency-path: contracts/yarn.lock @@ -51,7 +51,7 @@ jobs: - name: Use Node.js uses: actions/setup-node@v3 with: - node-version: "16.x" + node-version: "20.x" cache: "yarn" cache-dependency-path: contracts/yarn.lock @@ -74,7 +74,7 @@ jobs: - name: Use Node.js uses: actions/setup-node@v3 with: - node-version: "16.x" + node-version: "20.x" cache: "yarn" cache-dependency-path: contracts/yarn.lock @@ -113,7 +113,7 @@ jobs: - name: Use Node.js uses: actions/setup-node@v3 with: - node-version: "16.x" + node-version: "20.x" cache: "yarn" cache-dependency-path: contracts/yarn.lock @@ -153,7 +153,7 @@ jobs: - name: Use Node.js uses: actions/setup-node@v3 with: - node-version: "16.x" + node-version: "20.x" cache: "yarn" cache-dependency-path: contracts/yarn.lock @@ -193,7 +193,7 @@ jobs: - name: Use Node.js uses: actions/setup-node@v3 with: - node-version: "16.x" + node-version: "20.x" cache: "yarn" cache-dependency-path: contracts/yarn.lock @@ -233,7 +233,7 @@ jobs: - name: Use Node.js uses: actions/setup-node@v3 with: - node-version: "16.x" + node-version: "20.x" cache: "yarn" cache-dependency-path: contracts/yarn.lock @@ -279,7 +279,7 @@ jobs: - name: Use Node.js uses: actions/setup-node@v3 with: - node-version: "16.x" + node-version: "20.x" cache: "yarn" cache-dependency-path: contracts/yarn.lock From 848d578d620c43d6be70c5d610a3902bcfa5b3ff Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Mon, 13 May 2024 17:08:19 +1000 Subject: [PATCH 061/273] Fix CI --- .github/workflows/abi.yml | 2 +- .github/workflows/danger.yml | 2 +- .github/workflows/defi.yml | 16 ++++++++-------- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/abi.yml b/.github/workflows/abi.yml index ceafc32db9..18f8d9a6b7 100644 --- a/.github/workflows/abi.yml +++ b/.github/workflows/abi.yml @@ -17,7 +17,7 @@ jobs: - uses: actions/checkout@v3 - name: Use Node.js - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: "20.x" cache: "yarn" diff --git a/.github/workflows/danger.yml b/.github/workflows/danger.yml index 9aff239f04..a7916ee9a4 100644 --- a/.github/workflows/danger.yml +++ b/.github/workflows/danger.yml @@ -10,7 +10,7 @@ jobs: steps: - uses: actions/checkout@master - name: Use Node.js 20x - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: 20.x cache: "yarn" diff --git a/.github/workflows/defi.yml b/.github/workflows/defi.yml index 97dcdaf79a..6904af1f4b 100644 --- a/.github/workflows/defi.yml +++ b/.github/workflows/defi.yml @@ -21,7 +21,7 @@ jobs: - uses: actions/checkout@v3 - name: Use Node.js - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: "20.x" cache: "yarn" @@ -49,7 +49,7 @@ jobs: - uses: actions/checkout@v3 - name: Use Node.js - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: "20.x" cache: "yarn" @@ -72,7 +72,7 @@ jobs: - uses: actions/checkout@v3 - name: Use Node.js - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: "20.x" cache: "yarn" @@ -111,7 +111,7 @@ jobs: - uses: actions/checkout@v3 - name: Use Node.js - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: "20.x" cache: "yarn" @@ -151,7 +151,7 @@ jobs: - uses: actions/checkout@v3 - name: Use Node.js - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: "20.x" cache: "yarn" @@ -191,7 +191,7 @@ jobs: - uses: actions/checkout@v3 - name: Use Node.js - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: "20.x" cache: "yarn" @@ -231,7 +231,7 @@ jobs: - uses: actions/checkout@v3 - name: Use Node.js - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: "20.x" cache: "yarn" @@ -277,7 +277,7 @@ jobs: pip3 inspect - name: Use Node.js - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: "20.x" cache: "yarn" From 79d505870055d10300f9ebd90f6e4e23272f7222 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Mon, 13 May 2024 17:11:16 +1000 Subject: [PATCH 062/273] Fix CI --- .github/workflows/abi.yml | 2 +- .github/workflows/defi.yml | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/abi.yml b/.github/workflows/abi.yml index 18f8d9a6b7..ef6134488e 100644 --- a/.github/workflows/abi.yml +++ b/.github/workflows/abi.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest environment: master steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Use Node.js uses: actions/setup-node@v4 diff --git a/.github/workflows/defi.yml b/.github/workflows/defi.yml index 6904af1f4b..14f74800b8 100644 --- a/.github/workflows/defi.yml +++ b/.github/workflows/defi.yml @@ -18,7 +18,7 @@ jobs: name: "Contracts Linter" runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Use Node.js uses: actions/setup-node@v4 @@ -46,7 +46,7 @@ jobs: name: "Contracts Unit Tests" runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Use Node.js uses: actions/setup-node@v4 @@ -69,7 +69,7 @@ jobs: name: "Contracts Unit Coverage" runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Use Node.js uses: actions/setup-node@v4 @@ -108,7 +108,7 @@ jobs: CHUNK_ID: "${{matrix.chunk_id}}" MAX_CHUNKS: "4" steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Use Node.js uses: actions/setup-node@v4 @@ -148,7 +148,7 @@ jobs: PROVIDER_URL: ${{ secrets.PROVIDER_URL }} ARBITRUM_PROVIDER_URL: ${{ secrets.ARBITRUM_PROVIDER_URL }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Use Node.js uses: actions/setup-node@v4 @@ -188,7 +188,7 @@ jobs: PROVIDER_URL: ${{ secrets.PROVIDER_URL }} HOLESKY_PROVIDER_URL: ${{ secrets.HOLESKY_PROVIDER_URL }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Use Node.js uses: actions/setup-node@v4 @@ -228,7 +228,7 @@ jobs: - contracts-arb-forktest - contracts-hol-forktest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Use Node.js uses: actions/setup-node@v4 @@ -261,7 +261,7 @@ jobs: steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python 3.10 uses: actions/setup-python@v4 From 7b7ac39110a3d28c7d6173e137eeea712f43655b Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Mon, 13 May 2024 17:14:27 +1000 Subject: [PATCH 063/273] Upgrade to node.js 20 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e527d838e8..306b1025d5 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "test": "exit 0" }, "engines": { - "node": "16" + "node": "20" }, "devDependencies": { "danger": "^11.2.8" From 6b2be67da2e2cf64bacde59834da0717f6e02a3b Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Mon, 13 May 2024 17:19:45 +1000 Subject: [PATCH 064/273] Still upgrade the buyback contracts but not approveAssets on the swapper --- contracts/deploy/mainnet/095_ogn_buyback.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/contracts/deploy/mainnet/095_ogn_buyback.js b/contracts/deploy/mainnet/095_ogn_buyback.js index fca4565902..02b66499fa 100644 --- a/contracts/deploy/mainnet/095_ogn_buyback.js +++ b/contracts/deploy/mainnet/095_ogn_buyback.js @@ -8,7 +8,7 @@ const { module.exports = deploymentWithGovernanceProposal( { deployName: "095_ogn_buyback", - forceSkip: true, + // forceSkip: true, // onlyOnFork: true, // this is only executed in forked environment reduceQueueTime: true, // just to solve the issue of later active proposals failing proposalId: "", @@ -17,7 +17,7 @@ module.exports = deploymentWithGovernanceProposal( const cOETHBuybackProxy = await ethers.getContract("OETHBuybackProxy"); const cOUSDBuybackProxy = await ethers.getContract("BuybackProxy"); - const cSwapper = await ethers.getContract("Swapper1InchV5"); + // const cSwapper = await ethers.getContract("Swapper1InchV5"); // Deploy new OETHBuyback implementation const dOETHBuybackImpl = await deployWithConfirmation( @@ -45,7 +45,7 @@ module.exports = deploymentWithGovernanceProposal( true ); - await cSwapper.approveAssets([addresses.mainnet.OGN]); + // await cSwapper.approveAssets([addresses.mainnet.OGN]); if (!isFork) { // No Governance action on mainnet From 5f2f8f642e0bc4d315cb6f5bc37d1714fe71c112 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Mon, 13 May 2024 17:31:47 +1000 Subject: [PATCH 065/273] Upgrade actions so they don't use node.js 16 --- .github/workflows/defi.yml | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/.github/workflows/defi.yml b/.github/workflows/defi.yml index 14f74800b8..741ee1d39a 100644 --- a/.github/workflows/defi.yml +++ b/.github/workflows/defi.yml @@ -85,7 +85,7 @@ jobs: run: yarn run test:coverage working-directory: ./contracts - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: unit-test-coverage-${{ github.sha }} path: | @@ -117,7 +117,7 @@ jobs: cache: "yarn" cache-dependency-path: contracts/yarn.lock - - uses: actions/cache@v3 + - uses: actions/cache@v4 id: hardhat-cache with: path: contracts/cache @@ -131,7 +131,7 @@ jobs: - run: yarn run test:coverage:fork working-directory: ./contracts - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: fork-test-coverage-${{ github.sha }}-runner${{ matrix.chunk_id }} path: | @@ -157,7 +157,7 @@ jobs: cache: "yarn" cache-dependency-path: contracts/yarn.lock - - uses: actions/cache@v3 + - uses: actions/cache@v4 id: hardhat-cache with: path: contracts/cache @@ -171,7 +171,7 @@ jobs: - run: yarn run test:coverage:arb-fork working-directory: ./contracts - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: fork-test-arb-coverage-${{ github.sha }} path: | @@ -197,7 +197,7 @@ jobs: cache: "yarn" cache-dependency-path: contracts/yarn.lock - - uses: actions/cache@v3 + - uses: actions/cache@v4 id: hardhat-cache with: path: contracts/cache @@ -211,7 +211,7 @@ jobs: - run: yarn run test:coverage:hol-fork working-directory: ./contracts - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: fork-test-arb-coverage-${{ github.sha }} path: | @@ -237,7 +237,7 @@ jobs: cache: "yarn" cache-dependency-path: contracts/yarn.lock - - uses: actions/cache@v3 + - uses: actions/cache@v4 id: hardhat-cache with: path: contracts/cache @@ -249,9 +249,9 @@ jobs: working-directory: ./contracts - name: Download all reports - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 - - uses: codecov/codecov-action@v3 + - uses: codecov/codecov-action@v4 with: fail_ci_if_error: true @@ -264,7 +264,7 @@ jobs: - uses: actions/checkout@v4 - name: Set up Python 3.10 - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: '3.10' From 6baed9b7dbc9c8ab5a5d04e060172e3c1bce0ffa Mon Sep 17 00:00:00 2001 From: Domen Grabec Date: Mon, 13 May 2024 10:45:54 +0200 Subject: [PATCH 066/273] attempt to fix holesky fork run --- .github/workflows/defi.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/defi.yml b/.github/workflows/defi.yml index 741ee1d39a..aa84146c2c 100644 --- a/.github/workflows/defi.yml +++ b/.github/workflows/defi.yml @@ -213,7 +213,7 @@ jobs: - uses: actions/upload-artifact@v4 with: - name: fork-test-arb-coverage-${{ github.sha }} + name: fork-test-hol-coverage-${{ github.sha }} path: | ./contracts/coverage.json ./contracts/coverage/**/* From 9ce05e159fd2fcf5642127ded2e7a216ab5025dc Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Mon, 13 May 2024 20:21:19 +1000 Subject: [PATCH 067/273] Generated latest contract diagram --- .../docs/NativeStakingSSVStrategySquashed.svg | 82 +++++------ .../docs/NativeStakingSSVStrategyStorage.svg | 128 +++++++++--------- 2 files changed, 108 insertions(+), 102 deletions(-) diff --git a/contracts/docs/NativeStakingSSVStrategySquashed.svg b/contracts/docs/NativeStakingSSVStrategySquashed.svg index 13b0b7d2aa..fe01136eb4 100644 --- a/contracts/docs/NativeStakingSSVStrategySquashed.svg +++ b/contracts/docs/NativeStakingSSVStrategySquashed.svg @@ -4,50 +4,52 @@ - - + + UmlClassDiagram - + 284 - -NativeStakingSSVStrategy -../contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol - -Private: -   governorPosition: bytes32 <<Governable>> -   pendingGovernorPosition: bytes32 <<Governable>> -   reentryStatusPosition: bytes32 <<Governable>> -   _paused: bool <<Pausable>> -   __gap: uint256[50] <<ValidatorRegistrator>> -   __gap: uint256[50] <<ValidatorAccountant>> -   initialized: bool <<Initializable>> -   initializing: bool <<Initializable>> -   ______gap: uint256[50] <<Initializable>> -   _deprecated_platformAddress: address <<InitializableAbstractStrategy>> -   _deprecated_vaultAddress: address <<InitializableAbstractStrategy>> -   _deprecated_rewardTokenAddress: address <<InitializableAbstractStrategy>> -   _deprecated_rewardLiquidationThreshold: uint256 <<InitializableAbstractStrategy>> -   _reserved: int256[98] <<InitializableAbstractStrategy>> -   __gap: uint256[50] <<NativeStakingSSVStrategy>> -Internal: -   assetsMapped: address[] <<InitializableAbstractStrategy>> -Public: -   _NOT_ENTERED: uint256 <<Governable>> -   _ENTERED: uint256 <<Governable>> -   WETH_TOKEN_ADDRESS: address <<ValidatorRegistrator>> -   BEACON_CHAIN_DEPOSIT_CONTRACT: address <<ValidatorRegistrator>> -   SSV_NETWORK_ADDRESS: address <<ValidatorRegistrator>> -   VAULT_ADDRESS: address <<ValidatorRegistrator>> -   validatorRegistrator: address <<ValidatorRegistrator>> -   activeDepositedValidators: uint256 <<ValidatorRegistrator>> -   validatorsStates: mapping(bytes32=>VALIDATOR_STATE) <<ValidatorRegistrator>> -   MAX_STAKE: uint256 <<ValidatorAccountant>> -   consensusRewards: uint256 <<ValidatorAccountant>> -   fuseIntervalStart: uint256 <<ValidatorAccountant>> -   fuseIntervalEnd: uint256 <<ValidatorAccountant>> + +NativeStakingSSVStrategy +../contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol + +Private: +   governorPosition: bytes32 <<Governable>> +   pendingGovernorPosition: bytes32 <<Governable>> +   reentryStatusPosition: bytes32 <<Governable>> +   _paused: bool <<Pausable>> +   __gap: uint256[50] <<ValidatorRegistrator>> +   __gap: uint256[49] <<ValidatorAccountant>> +   initialized: bool <<Initializable>> +   initializing: bool <<Initializable>> +   ______gap: uint256[50] <<Initializable>> +   _deprecated_platformAddress: address <<InitializableAbstractStrategy>> +   _deprecated_vaultAddress: address <<InitializableAbstractStrategy>> +   _deprecated_rewardTokenAddress: address <<InitializableAbstractStrategy>> +   _deprecated_rewardLiquidationThreshold: uint256 <<InitializableAbstractStrategy>> +   _reserved: int256[98] <<InitializableAbstractStrategy>> +   __gap: uint256[50] <<NativeStakingSSVStrategy>> +Internal: +   assetsMapped: address[] <<InitializableAbstractStrategy>> +Public: +   _NOT_ENTERED: uint256 <<Governable>> +   _ENTERED: uint256 <<Governable>> +   WETH_TOKEN_ADDRESS: address <<ValidatorRegistrator>> +   BEACON_CHAIN_DEPOSIT_CONTRACT: address <<ValidatorRegistrator>> +   SSV_NETWORK_ADDRESS: address <<ValidatorRegistrator>> +   VAULT_ADDRESS: address <<ValidatorRegistrator>> +   validatorRegistrator: address <<ValidatorRegistrator>> +   activeDepositedValidators: uint256 <<ValidatorRegistrator>> +   validatorsStates: mapping(bytes32=>VALIDATOR_STATE) <<ValidatorRegistrator>> +   MIN_FIX_ACCOUNTING_CADENCE: uint256 <<ValidatorAccountant>> +   MAX_STAKE: uint256 <<ValidatorAccountant>> +   consensusRewards: uint256 <<ValidatorAccountant>> +   fuseIntervalStart: uint256 <<ValidatorAccountant>> +   fuseIntervalEnd: uint256 <<ValidatorAccountant>> +   lastFixAccountingBlockNumber: uint256 <<ValidatorAccountant>>   platformAddress: address <<InitializableAbstractStrategy>>   vaultAddress: address <<InitializableAbstractStrategy>>   assetToPToken: mapping(address=>address) <<InitializableAbstractStrategy>> diff --git a/contracts/docs/NativeStakingSSVStrategyStorage.svg b/contracts/docs/NativeStakingSSVStrategyStorage.svg index e5aad7e6a1..3d9f146ce8 100644 --- a/contracts/docs/NativeStakingSSVStrategyStorage.svg +++ b/contracts/docs/NativeStakingSSVStrategyStorage.svg @@ -4,34 +4,36 @@ - - + + StorageDiagram - + 3 - -NativeStakingSSVStrategy <<Contract>> - -slot + +NativeStakingSSVStrategy <<Contract>> + +slot + +0 -0 +1 -1 +2 -2 +3-52 -3-52 +53 -53 +54 -54 +55 -55 +56 -56-105 +57-105 106 @@ -56,28 +58,30 @@ 165-262 263-312 - -type: <inherited contract>.variable (bytes) + +type: <inherited contract>.variable (bytes) + +unallocated (11) + +address: ValidatorRegistrator.validatorRegistrator (20) + +bool: Pausable._paused (1) -unallocated (11) - -address: ValidatorRegistrator.validatorRegistrator (20) - -bool: Pausable._paused (1) +uint256: ValidatorRegistrator.activeDepositedValidators (32) -uint256: ValidatorRegistrator.activeDepositedValidators (32) +mapping(bytes32=>VALIDATOR_STATE): ValidatorRegistrator.validatorsStates (32) -mapping(bytes32=>VALIDATOR_STATE): ValidatorRegistrator.validatorsStates (32) +uint256[50]: ValidatorRegistrator.__gap (1600) -uint256[50]: ValidatorRegistrator.__gap (1600) +uint256: ValidatorAccountant.consensusRewards (32) -uint256: ValidatorAccountant.consensusRewards (32) +uint256: ValidatorAccountant.fuseIntervalStart (32) -uint256: ValidatorAccountant.fuseIntervalStart (32) +uint256: ValidatorAccountant.fuseIntervalEnd (32) -uint256: ValidatorAccountant.fuseIntervalEnd (32) +uint256: ValidatorAccountant.lastFixAccountingBlockNumber (32) -uint256[50]: ValidatorAccountant.__gap (1600) +uint256[49]: ValidatorAccountant.__gap (1568) unallocated (30) @@ -118,48 +122,48 @@ 1 - -address[]: assetsMapped <<Array>> -0x78fdc8d422c49ced035a9edf18d00d3c6a8d81df210f3e5e448e045e77b41e88 - -offset - -0 - -type: variable (bytes) - -unallocated (12) - -address (20) + +address[]: assetsMapped <<Array>> +0x78fdc8d422c49ced035a9edf18d00d3c6a8d81df210f3e5e448e045e77b41e88 + +offset + +0 + +type: variable (bytes) + +unallocated (12) + +address (20) -3:17->1 - - +3:18->1 + + 2 - -address[]: rewardTokenAddresses <<Array>> -0xe434dc35da084cf8d7e8186688ea2dacb53db7003d427af3abf351bd9d0a4e8d - -offset - -0 - -type: variable (bytes) - -unallocated (12) - -address (20) + +address[]: rewardTokenAddresses <<Array>> +0xe434dc35da084cf8d7e8186688ea2dacb53db7003d427af3abf351bd9d0a4e8d + +offset + +0 + +type: variable (bytes) + +unallocated (12) + +address (20) -3:22->2 - - +3:23->2 + + From 8c052d8fa2ecd8a56a08f0c5612ae3ac26fc91a5 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Mon, 13 May 2024 21:03:57 +1000 Subject: [PATCH 068/273] fix codecov upload --- .github/workflows/defi.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/defi.yml b/.github/workflows/defi.yml index aa84146c2c..a201b5035c 100644 --- a/.github/workflows/defi.yml +++ b/.github/workflows/defi.yml @@ -227,6 +227,8 @@ jobs: - contracts-forktest - contracts-arb-forktest - contracts-hol-forktest + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} steps: - uses: actions/checkout@v4 From 3687fbe9838f03d3c30f1cde96f3da24c51effed Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Tue, 14 May 2024 00:54:07 +1000 Subject: [PATCH 069/273] Fix OETH process diagram for native staking --- contracts/docs/plantuml/oethProcesses.png | Bin 434884 -> 433112 bytes contracts/docs/plantuml/oethProcesses.puml | 10 ++++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/contracts/docs/plantuml/oethProcesses.png b/contracts/docs/plantuml/oethProcesses.png index ded50a16e0421f48385dc5531959c3cbedfe682c..7aad421c47ad8aefdc51ba03892fb3c521593ec3 100644 GIT binary patch delta 339210 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 I?R!uB4_Kh<6951J delta 341206 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 ^Maot zKJk%NA8$;DDk?j=~4Nf zCA>$!3YH)LlI$BDoei*k7j4lEWteIr!X~p{GMmlZD6da-Y;lF^<}WUIpvtLnP8xR4 zL3eayJYM7Q)p1x&xy9nGav%9TW#tefBcsV3hn(4PCee-WMA*|uJo=B&AzX>qr*`wA z&y%Z36?Xz094qpi>FF2QV9}=kxDj$OJrBfgO_S6%%G9cMbIlu@P6bfzZJ0E1>+&-r zq5XoS+&+CGYkf`v^C#w3bLLro)mh~yx|n-$ewrJbjcNI=(f63;=)89_iYg{Xs(n%F zhcIn1f>sPFaURifh-a8jboBmej@KKtkgV(!%4K9o0x=+=wY7tdy0jW!BPr{HQZlGg z`l*wOUnv#uZQ+;(1j^j?xi$6Y3AyItco({DhrX+jj}WxA8YokB{*=*8KLqxJ)47nR zr_e8#{Iny4)0;1bMBDS*VX+39_dXcveCIAsoKl(Euzqm%OLCEYzjVOaNciR1!L#^~ zkmZT&m%GpI$U7PJM-)dq?c7b7)ynhI#E;w=l;BRQ$&B%B`!O+g8iuf3(#rd3wBYh& z0HCu#h-fNX4jr=~t{UNCjF{I%dYI2u1+Zx;%4uz-tE!IBgnu7?ufcWr$v2GoRAS~B zM)dI}0o1rXFI=j?cx4e5h@iQ=Mr9R zx@U)4;`)Z>A>vIK{AtZr>Cv~duHfQQt(0f;%RJiA8_RCBw-8(qanTCw{d-JY#u(?h z1)d37+mK@W_6nM5mkV!<2*-=@%hQ@IUrtC*K4!GnrMvfI$$*FN01-7gCXHai*ZK|j zlD8_vb{USM!Z_oNjk>k2h(!8k>tjWJDus62S}UokskcAz{Z!S5KgQfj9s^*o{+><6 zqoj~o@GbrWOb*RNlnot@Fq(NTL9eCPySC1_;P%I~KpKoTqv3wZns zR-8ZD3T@lGF*ZJ4bFz|=si~^R0JDLLqNb?jltH|R!U4vd*15F@zK#EJUjq7h}bRM z@7;lrkQgYMb>j3LE{qx29h6gU9VDa2Z$Ia{E`89cuETs=T&#Vp-X76uTt~Dr$dU-;WYdQx=B~=k%?%C?j)=gw zwLSd#^Ji34)Yg{S7xc6l`o3=zV$?y{*x0TgP*G6S)YY5)3Bp1`OjPK<^!nV6VnAr)EK0;}IL%*@QD7H{9)U)B5Y zA-@D&DuxS>ghc9mVnU6tvdCs#zW)9Y(d6oC7i;UHwgpemI~W)k9VT+hLS{rP*70xbpVt`M@L^;S{lyL4130DGR6|2psY;8g!J-8;4RqukWVF#&yG>w zAAc23!g`(Xu>}4sX9md59$Q{cj+~r4*Kk8zUS7VqxY)q~a`+EeCa|@(zK4OKckWNX z77-Eg+zR{t{a3SxD}zS+D}yY*e*H>&{$1`Gi}$w}Pggq!1qI9~tJ9#dCoLl4vqX#% zVPa|umebVO*tkFb$z40Ku>Fy390Y)6`R)%yZ-v^V+-8GlBbyC5Bh5z~pT`dn-pr2Z?JkBSK&~bYlpBo)LJvNF*bo8X{w6oW##=l*9G1qqo3L37qq`Xx*IUWQ^?ECT zwIZIH6b0}`%o@>O@bddUp^481e}+3rQJl9XPmi=jfI?fgp4ciX*mNR!`S z4Om-x!#Cqk)mtl{NeYIS8aF=MJ<0Tt6!i5=BS>1zo2Ne`FJnN>2v~H3A1|NR=oKVW zeZ{*d@Q=4ctyB5$_5FJt{`&hHuvw=&Q*|Um_pc8Dbae`D{Z%MtarSztd3kG+k^~&O zqB(6DG%80#jHFdnQMW#seZ>KNvIGHs+uXm(kfX38TtOkj)VC@ZvqkUgJ(H4>z7*Mm z9*x0!_U!TF$8>bYV8fY=9R^A9j24?jw#_(hR@ttNFx4J|gM*4g_w@?}L`ms6R0!H( z{V*w@Z`9Ojj+)2R^f{=22(lsznpi6OFn>v@CFUxx3#tircYRzLEk* zEW<7%i|P5`;2^~Q@}<+!tk*}f`$@8YZr+NdofxMq!raYDkH(7}j+OVx56FZ%!kPFj z=V@qYf`4XaW*(IB;TFWi5MSQR7WBhm=j8P3T%MQV38pvI2enUmlt$=pd_`2G4{XF(MbZJ;QM#H&gmi}T>rcH%bZ`oetm_k zR`9`}<3NUq7z?XVs}aTY)_ND~`T4oClT)c)EvPQT+3M{Vh)L! z($Ww7hFe<=b{1L*r)1a?i06xphAAbZMoI*OC?(3x=RYcu0`KbM4G{r8InQ@72GtJX z|2QCjzMn~`pPye$jE0hulBlStgoJ-Zh2y(-?<6H9?d(cDJP;-Hjg75rY+P2-Q>&r# zgKZ(x<@uqhsi|7!ijbTZxuSt46;&$O z)C~;+D|Ytw(lfO0HOj4gj5nrhNHTANa&%q80gMFCtOJ0%*fZ;~Uv_tNkY6SyCK^~c zIdSa+$s%1Ux|`?pbLVVLX0!0?(9lo~4UGv$5AieHLj=e_7A+;9 z$?e-A`fq7-S+8J8q^OT9fv+tZIXXH@``&b_@_SQvEbsJsj#F^xFk*b6Q>1%BaXDQk zPbkLg=TIR0B(J%^QRAl);u?1Ha1<5clMz3=|S%dP(I1G za1s?!JY2c$hpXv*63o$5yYcCW* zmSZ1^gjLf>Z&h=qGiN_{cPq3qsPu>>AO4?M?YsslQ%hU>7!&Ngy}dn~wUJs@GBPs6 zZ5+oAS{@z^${>2>e0P4{{#2>3XBUxnkn`c^&uAA;*7Fs%o0QEwM>Dr&Wn~YVNc*?v zn+=-NWm6--In+3PGl1e;YSQ`#W!Glr4%1?o!(Ho!;$5aEu5>Tg791x09w$$kybl#%+B_9 zVEdw#>QUR%oV~SCSt%(g-Rb|Airk+fVQFTTmYEs+tjl)hS8pP~#Ngb34FjmvrIC(~ zz;J5#_UYl~;qQL0hZkc;Ioo80rl!RuC8^sr7yCKJH=Z&sf&{6wnbQvnBJ z;^8YL9&*gr@IHF~x+mGKzMr?g0(Q%+sHmu*3eli|4GvB#B^A{rG$iwio19!{B=Y~Wi`|~D+!$zIXhmCHNchlTp|Kk4PcK0>Dk$k>EM7H5{BtSX?*;H z{YUL>ZKl)J^i??0($WQb-5XPiJfiKZu5VSUCH@<^{s*{DTIZ#Te}C?Bc4Rwc-#k99 z3N+3^QLinQ`v}(T+%{MGD!?$-RF%omG`F^I0IrIcz&RK+CmWcIb)5<&st*&On1IlS#3P2LJm!Q`2Kq?jH@}$yb45#7V0mu{8vm z6fUC%-TMY0;YU8xZ3_nP1i0t#uKhSp?8OS@q$8S-re8ywzm#kRE&M5Of2y0HBKoJJ;WrWx5>{F) zwkc{l7XgwmG&D3`0@IrZq#2yT%o_7~AqaxdwL4?DRh@ZAV1W`F3FR*54!|!08w+&k z*YRl?8S`5TDk>4x)fb>xwz69SQj@0*HRBTyjE{_vQ&RTbH33B=EOP5)HRp022Hi$~ z1qawSr(DZV==rw%AcxI!U48ZBs^cZ2H?Ccjvgv!=&;^(G?H)9QD@_onf`i-TrKNz! zYagtQZf|dQb00b)B>twmklKNsVh2a(+$wqXsCIn9!4=LIJS3ocGlHtEq6tim`-xoZOs5Q;4*)1p#|_zf!j5H0vIZ*9>~1A@KOw51aN*1H>bOs0LMo{d-MuOy`N@hXPqivIPB@~ zA7^K0t3}(n05Ci~K7INJdIZ z%G{jRL4jw~%IfMR-@jrm9MlLOymXVQ-i79?!2Z{gn>r%an@+gk^fAeq|W#`Uq0Km0sU2~fq z9c$=6yg2vhA2>sOgM`0@V`PoNAQgQQ2H23%EHC5zhtQzEWtxZGpZYl2sH$3Qe0(qt zD>`0_uOYbDyu8>1Rq3pDY3akv4FTV47HB7y5Y6HIaV)V`mB@~crI6uMi3{YpdXfCQ zpTFpn*=#!^(8=rmvMLbY)8D7TLAOJNl=vqxVg8S1*|nQubb7#KrTE!J=H9;K-6S-#r!v1!ZGFhbo)NdHOiRDnjSA&#e4E(zO(Zb4-bzP ztN3u$1-Jx2{g+}D%)4kNP&_$3&Ao^Ze#y%Vf<;XJ%#1&%?8NY)&xF^z!Aq+u zqPp~{SKX|t>1l3u`&?1R?qaKxI+HiB{MHXxJ;2VY740ck?)QX7wijImfPMi)kUoG| z`*ze-Y&Ry#fO3s%O`N<4T1`TM9V(!=kaAXNXb!A&Zg$(M#>IIErW9&R^MZywC4So% zWeWeL*(xzYRVO4ar8l9}5WT-qkt+1Yc7;E_1rXfK2|Yb-1+ z7q*5XeziCwt1>Jl(}vUw1rTSu(ABaJ%pID1Id!7fzYDewynHX@a{fmfu`NwVOq`#e zA8gjv(xM(zFTaJ0z{lZT^7zdyn63_GkK%ZOU;(*?Bvyl}L}!hXN?TQ>nxr0uZ`HGw z&pAF{t}_YHbtnN30|h_Xr8y=#NZe8j1ROLZ&x)3slf{<5e{ThEA@|+Q^A5lFYL6wDc?La4rcf0^+tXo+fVx{a01M5A$Qs3u??nvGdG(Vu+CGd1^xf)(l7Qn*4Y zfKqn#{TKhfLx6#fu2E*On2}RGmMTSJWVE_IUQ)1~p_uc9h;s-8O`4i00jiG_XY&U| z?fLi2xVVqm)FdP%fCI6ym5>R4>2Ysqc{9cW6m4p(3Y&H48xO-Y76}Z9V~BU|0Iu_r zon0b^>wCQ_P&!;(Ts%EJ6%-W07&V*jal!H4Tg3*|{ddx+ zvz7LE<&VFgnX}2fY$1!o;1pergf~^L7K^w`_XuU->uJ;vk0%HNBLfu`!^2Ru&e30|JRV=?icWWMwg(7v|>rK>Z&r z&}(jP<~^LS1YZsUJo~Bh-}nZTnAr6F``Wdhh0waf_h1Qt(g3WVe_A9g@o{lK2M4Vu zO3js(l>w6PYhH|;+fuN!WL|$A>v9Nm1n9CVGLoQPRj2L0)QmBRJFbum6fr9tSbSO* zL&hM~w=uagO>$$AAWS(k%DN%XzSgFEnq31QRm9dj*{&prH|pxS_%16&A8-Wc}^0dp_`6TWleL`3ydy91nn0bl980GXjyH}X+?d#XBZ908_j34$+P~7l| z!vabkNpLzIWTH$ZxB!3db-aFhDrbCVCK|9rNC}e=?NC?xt}H`4R859ASQdBxsw{(^ zkR4DDT4#aQn%~J-edNl@{QSAxvwja$T>Z0tDPADCH#Rl>7@3vgu~~a`7>-R83}Ab6 zEejU|35<#40FIE@U{f88^it7BM|R)Ei*;Hb{-aOBZAv@TKQ7G25-UU)5Iupo0^~0s zkxooN6SMVR7(^Vwckn&{Es4YNz!;c;N=o5AJ|f`352puSujAiHNF*B+0)a3PB?x|` z$jK=vl2cQIbe)~gfew!!%W4wg=Ekq9tDDh`-JqHTxLH2~l~l|`p0<}brM6v0aWOD7 zi%Uzx&w#4}+$V-e!UqqSESDhh|9Q3L^l;B81=x6cdU^_tL)Yo7iQCHm0*PhKDZt_c zs=_6;I6Ry6{mx&ZFL!XdfeaPun*Sg6|7ISb1%6L7rf1LIVc7T(g~1?S9X-86z_WZi8HmbxaVpZP$g}wpo}P4N)YN#ZmOJWDB5! zCtm6gVDS)uc?ySe!|H4K`T2lT?h22{$^kJOn4LhmrriZFSXD-b^nET6KjY&+ae%wW z^8FrA7BZA%d9w?Nx$Mm5o9^vzx3!6GP>Ww<&Q}=s5e%?FlR~a6G9Hce!|9ZPv57uc zSHnWZaW`n~bkgIr+#UK2Y$iH-Xb}fzi8sm{vZERX*drV(kw;Ip!|=fJYrxA-S{GcQ zXGVkRAaKG5FZ_R6Z!zuEO8JGCyL&EGJKV%7i30%eLst|QKE8No(}%Ypijyg|4k9`n z9wpTy7Y{t9M}nuNCBG27kX@e&myJWh zoKW*p&7_^!GxmTB>6hSrLBEE-bMDBsVlkk*HB@OYOGY~NwLKQHvbE*-R_y1Gt06(c zIn+He($e&y=Tn2pN{Xx7?F5B$31{JCixH~G1f|P)|EEAgznDHtD_QD}ovMLiQ)7uE zLZS<|NiOwFxO;|%PBJD*EW0{l&W9B>qbE|O7*Brrt&@nnF2{;hLHw<^$rbpUpC|8=h!*$ ztS_*zFwrc%nqvj3ec9JQ06w6LT~r`hvPXy5tvlS|#jz*_Jrb==t$GLI{>~j!9d=@r zKz2xBToxYoLk^t)WLG(+=1u@=?cpf`M6(%y}r`080-ujc;3xK%c~_KM($ zU_$-}=`YFb6na?pz2%@v!_}4Bu)n$zCcNSSjV-6^h{@4JV~w@(R38PFrCwnp?FT|$ z;^zR?5S0=Clk;5$X~Ja=fOTD5rZ83*Wug5DK}yP|fmRUxt>G9F5RQ3Swi$UOF~A!Z znII`MU>n?|ib=`U?cEK+PiPRnj(N$+t^Ii(O|b*K_&9c;$>{7tm3HAxha^XG9e5ES z+9t}~)FFFn&{Z5hXl%Kfy4n9h!RFyUkOtHC){J)Yt*8fQMeEgdzs@JO$x*eT1KYi4D z8ujkhJv2i5nvGOoZ=B5sT~-T~00Oa4qjo_~qzh3{q}}S72h?{oBsGm|DTHQ5C^ap%3!r<9iOWSJrsvNALFKeqxJ!VBj-JBV)YJ3!yST#Jw`N!R>3`%? zQ9_S^5`a@AfHnj~O08y~*(FJUY>>z6JfmR-Cg>mA;-_k6#JAV)9bZ~Q&7k6SEvBf^ zpYZWlzAzjpsIKnrVL-*LmW0X+v0?1&_qZ(&-YVNmDvb!_+b5FCcHlAnmu?kh4phW=aW5BDGkSUY*q`PD40-EHo_Nt2uO#cjk#U>&!00M zxEdoh&}Bh)-!#NgZOp~N!SUqD6Gld=Qf$)=W!HZDwsv#Ad1nNTPv3dN}VGV{oYO%Qt>qbM$aopIh9(UU4|J zuD-rBwvhS7i`h15pzic2QaL|3T!-gIA)&_LkuNNkKR;d+DgvD);^!>=#TmOL@IXDb zhko_e1BIt|qslST9D^U3qn<6T58SMmoSbJ;eiM_?AeY+SwA>jf8mZM9FJ-`^i1Y&l z)?a;O^xs<<+;tm#fEAaRSk-2Jd_L*O8WH}e-wCuA&>bI5J!H0cPWHa#KJ@hVZRdk` zVd3>ory=rX#l=IxH_6EAnY4o`*rd|E9xo9;*jW%p6!jAX#y8;;@pVT+r0e;C^W!A<+r-C5v@- zbd+@LJGxlX&82h4G~~k|+u26z zINES!TwXRPLzP7f><=bwjQoB*eKi;0yyAQQV!qUyEpir-j7Nj=hf!O;DA#?@q-lT5ffRUOlc!cRHx}>x=9XsnA5D?a? zBNj>*_*1p{3sK@PFh%2HlwM5cT{6&3-I1qDdKa=9zyrz*%=VyVl>$T&EZ%cKts59efO zD|`nd2Q#y?@o%YRWMx-ZRzMvB5_iKFEf|c~pfAbQ^;Sf&UN3 zV9CnQm(h|G5NPQ5&TLMA0hguzbsZpUMhFkur~mlTHUte7C#$9XF**MlSW$-NoBV;~ zjHV9!%R(%T^&*FTLwqYME4lCDv~+ZPhliJm#ro3=3p#m;Bje)*CnLlKH%} zThf@BQlk?Q0sTfpG5f=P;M52H`NOoY<3&74fa%7AM0~E|S2i|Ou>FAirX8yOoj*A) zpyO)1U}J*^&8|It5VG%#Vy9tY36JpajEmuxP>vlNOduI^R^+uv8lGz`C_;ca=be-J zX5`UaK3R{tlFPk>i54L$`;nnS?<{N1zKnc7C_KZ2n}G8^%({vFb|oT<8{vPlSXeJ_ z*r5V53%IOXp}*RFm_MA2*47H`R-B+GNw2gd-uACKUSdH>BI5jU^i0d0D*0FMJU!nf z;%@&F5m~0bA6~8ofm;G-up+W5+6t>FW`*_QiJ^rXu$!H)t{bsBG7S1>7!736#tPt2 za(79>-`ft%R`g9y{(dvYz^Y;Q!g)=J7fjv|MDig$EJ=?|`mvsN278$eHyOE3WtlzibIH)n;q#<#2r8PUzj>!hzo|M{x8qX^ z>terE(ZIbR@+{Yadx}?5S*%gG(KY?CGTC zZM*v)#6m6tlWwu{Tyoo*J#4jnJGB#)(^2g4h#t)}Fwinx+Z)(-0o-@}zRbAz-!4K7 z4xd!RP{gK>FOd&|?>cF5#Myn7P7&vNY>a@^)BV)~$fZ8NQY>Ahm8sBA^x++J!u#0! zIIB5IOw(fyapAfW-x6I!t?0ormXp!{M}Roc?)i=L1jrm$?c$+bdw2IK-?{Eejz&RC zLqj+R-go3Z#b$6Zm{f<(m^D5pK#~TgZutW+xk98ppCGTHgvl&PA`!j?odro9I4|KX z&&=GgUS^hBPi-YU7(4lWTKGLATHqY$)umc)4)Je#azb$(P~S} z$D8MDF#E&d2$I%1aBm)V^(@52Njo8Z=sZ~k(51EhN5wK?^uj6QugIClx*b>3mKGdO zrRSnKyYTYT2B+H-p=V(X(Rv>!WuZ&S9`6wqvC3wuz*oP+Fb5TbNM2{KzrSEqVG)~i z!f8;|3RRW(azbLy9fyUH2(te_^5jm=P3 z7kcKp*a*P!1OB<=r_6d7>5nmx=i!D}00fkBuxZjbyKOqyEx($4(532yj}>Ok(Rbcn zNc0`Y)&t13X6$@hj1f^tuUu5)>kE>qTZ&V^&IA zsg>l2IZ!I#WJuZc1v`f92s~5!M-(c2ZFO+^@8Jm~Bw<0p&RAZ6WiO<7&q1b;6;ap3 z#Kg#`!tv0Qbs1y?K(=sgJV7LgaS^c4?Y^VDhJR1Y92K7(nvK;Ve}AdKT5YgPd(p4D z(nJusbNjZig98tJ(D&+tv8OA-TtHT^IkQ-HC_X;MCFxsg{p@ZtL(fDa^m!|a$Ct$K(Ytn@%)E7VHz*L|xvP#DGL z;k{AkJY80EZYwlyQ6UI4nkz&E0^-mkI24fu*a9RzG&Evl(h0d8SO~1l&3lK3G49)LrVIp#IMP zcBElBaa%XtM+_=X`bCYpzd9 zXntOe8bV5eRBOm7sJs_`lmY^kwKhQcBX}0an<2n3i+1UK)*0c53y3xtkCwh<=f%E6 zbe1K_%xnW7K1HH!@Y)4Ss>dzp=uC%|KD<987JG2b{DPkf3p?%?-o<~QY7|11dSuh^ zkUGzA#L!|sVqpOgITcYGH8HVcs8cmno=#Svut$gdnHl-L=Rn_34q8add_7$E=RT-- zm;4!LQ2%d+15)ho&H=-=v$M;+%5`l4GpU9*(`Bgxk2NMbS|SppPlB3Mqa;MJws7E@ zDJq-}3_i(P**FG%6@;N3zfs!__O4atc3=M5&bS^2%}+qdz*aLuTb1TW6mc0q+LVjI z%ut%H)~%9{ke}XiJOU1=S?FMYf~kO37DeB<;jQs&5PZXOVs& zPet%JbAVBdKUWRN)X*YeX+3CvJ6QWi^Ah6Xf^o_LlwmO}pci>s?*Zm75n#xx#15Xw}cAq`l5cm#3Eh(hB>V7M+0nkI7g`W+r?poz@MUHK3405E%R!5=y!NMq7v| z#n+n%e3K7hd~Z*;hC~v(%HBhgKExbQ`6z| z6QgBhc-4Lz_MZU6!Mx&|H*YK~p6}d%bIc?oJEPHjHeC9M@&9+iKy z)Q!(H=GYU?Wvf_JRkJQ!7{F_BA9>-!yMR=6PE5XGE-fxJEX;R0*_&C#nNQhlzHiRF zd3Vf?Y>qQm)2xYg$Y{N!w8v^+xa{`5r2du8E*z0`&PkPr&uY#vS|8<25)#ccDa9pf z>C>qh;&OlfX;L`)h@kA>l26eO+w`Gy{(OnhU9*^-s$}&xp_&;e+r40uJ%4+*){v{Dbzvkp7Jiz}!fVnGw^xy5r!;gC;VMD$3`q z4w7r@?6g~JwUk3RCsfwqZe(hzFY2~wglGM2ivpLg!oAw0>Pl zX=y!rF&j4ylm=BET`OwCUc70uALJxbj#m3OEnB&AyF;dXRYG38i#;yFqes3V-7zrE zr#8x_bgGJ8EHjoA9X&EQZ)|Tta>{6D+ko9b$7cRn^k3D4jd#vNBjUT?fvv+%Grnu^ zUvj&@;qu-en2RO|?!Bxr5p0i(yk?YSKtYMAXT>+XQXpe@t|_S9x9`T*2WVha@$Q}T z(0$Fh!jA6d9&~C=MJvY^ulyho=TgyWyGulFSlXjm#m`o;tJQc1v`7<;Z?V5y3ipKQG%CT6(lpRR~Sm)wl!`Ua6JwsdAy9`r;lvUV;p$GQ4H zYo2InV@9&`cPlqHH%Up(+M+!V1kEyDE&9xn?BpcfkYW_s#}U|Upt4ux>T24Ir|+}* z9@Iia85PAa_S3x^Otq5P?Sm5P*2qHER`S zL-BEc&4!MQK~-`eQh~QLk{cjfWy6Q(SuiuY|FTiJvro}%>PU4euVgoLE#SDf(?#@O4l$8{HY;+` zYq8xWAeTfm3GPKL60JIY#$RC;e1}ku{X>P!_p{bbVLTa_n{z?#?yai@l$Cbl{gfx; z{S@6x;o%vRUL(q7mjx+}X%D#82g&WuK2gOx-t$-|gnO)oUQ#obrL7N=b4%jigjHiqJ$zx33 zVw^DUDJDS_Thd;Ohic6M0Y%8XO;f;g^+cVcU%CVyIVPf&>r`88;*1A-Jv*LKNXgcG z|9iwnj>hy;OUBv+?Ww<@{@(dH6G%Vg+tAg*pwdqZE?;<>wKj97IS?Mu9&~>EJ(#tvgUVDvKJM znL+K?QKzux-zhUv>=;aRieQ|~RP^AE9cSkMBWxH4;fw*hu=O|dA`5~F_={NM?>j6H$5Ybm_ zh!!iv(2%h2+3stOe2=&?yru7lcGQ29mx-(lsH3#Il>dlRFC83|-KAs%503jcCoeF& z*CAYBuYR1yI|fiOUiW?fR0hKID8nX$nE1QJq%RtaW*(6ZA4iZ7>o0al|%*zXl z7Bq$)N*0qgpY9{H2%vZR4uhps3-im{rJ+BvPDMwKGRI3uV>xvRReTGvg`%hDeCiaG zL*E=f=G}PVjS0O-=~JSU60#yE4E9^6t)38ZNZy9%i$D|3F9g}6ox^?XOip(7(xbu> zPEZrpe#&#x(Q-XI5^5-=2g)j?@r9EzRa@`isS>nCk}g)Z8=^s;=zTPJecz3^=RAut zs|Eu=uWrIen5)8UMFhqN8ERrTh|H5s(iRQ(*h0 zdbpe!?-^s0%V}w86YY(>_vXvT-{{Tx1*9>TWq|mI(Zzd*M zIyr3(yLRJ-^r1(m1D`~l5qr@EgRFq0BrDa!>d`RLc$;&|k8oLed;)#L>LC5#_;ml6 z(&6%4C>XcCtgO@&3i@2tSGN4O-sDH*@I!%s>e`i5gO_rHtt`tXk+Z>kG3hCnnp;D;~PHsHmM^D$$C2tVUos7#gcY(bp&!^!1C} z&-i+_;68gSmvjAbPa}T%ufdknw5VDk!}O!Rs$maEED`Y@W5gqOE?1itP*V0mJZpN|Cxpzs`yBpas zZaN&+UoG8rRdnbY-??`-(nW&~%9f40yI(iV{G*0UR|PFGuIS%aTXD9c`&$29ca$>! zfuMgxo;?D78!Q1QXGf#c2jMvvk_JbJ6DOED3j3mUMg)19=0R^wI6B5cGxPcfdMCl0 zza;jCq1|PPU>ab5!W+E}2)wN9jLx)geQqs&d)4nkS@q@X z*QbM!2&*)U1SSIWCs2g`!ug){(`Bk$jo6<6D!-f+Qsn=(McP$4ZJ6KBj&ySu!YOeXVo>O<@2Yv-Q|*EoV}^@ zt%gO|dvLVX`WV5tuT%5+e}&KBO`O^{WcyR)#@@^4pet}z&EVUW{f&>dN0Nx-CmN6N zxaHOsUG+70&(P>bcw3dsr%`|N>%ZuAJG&hz6WS%R6Ced8RHB$F+blwi*#zR>Hy=Ut zzD{YbJ#E9;uLI@crx)i^f6a~^%CyXQx{@EtDacO}?prvtqOYF&akEW=r zQ&UGTFX>52nsr|+H0*oWX1?^BT|dB%qgBvum?6G?^yG|=M6te}9U?0|{mv6j?e(-R zYn+2pT-6LY)f(%MRoE@3?zq;e%<^s0LW9LCDPbOm1Qe&t?vr4Mx5;kuMw3Z5Th6^L26%_e zM?adp&U_3&>#Ofl*w(@#tM1~-;fdQa$L)DJ8CWZ?T+wglQO z9@jx_H-oFgi#uUq^%y@EJE`clbgxrc-{)Ekh!qtVTPWG&CMWM}2>EA3L|t;>gdDe~sc5=bGB@%j+E9KdIfoJeS(= zvnXL!xf&4Q+WB?^!qA%aoohA?>9a`_-1$#@UuaM2wlq`d{d4lTLgXvJCGCu|Tm3Hw z|JVtW)=l6q!!KW+qZ1`ACl@Kfw>MM_vUypn4S%blHVnP^Q)?w#_yvSLMh`2L8r{A( zd~YPawzNDW)K{-K9p+c@GLDjr#;FSm5J6GHCVs-g^j! zUcP)uio;7_4VIamJ!|I7mX9AX1rMK6<>{E#y)AoCfaC1$HPknH%9nPzgTN~d*&K_B zPeH*X7=djx90)%duzKa~7}XDg#ITyXLEx))%d0dnGcW}dHkdQJE9Pr7Jf?md1}>Su z;4gE(kRq)HQFHm2v2V`;OfDrJH#Iii)Bkeb=u^$%fk{KZ6brEHAlD0WBtv{fOgsY4 zoRM|8ro=W&jQQgepRuST3Sj#sUJ@aQp=n##)(I>fpI^Df*;bziZVL_J3OtL##Qni@ zx*ZaQ)b@CtRK@K5U(#Km5?f*7lsHiV&Aj40_qn%v;9Kc+t=g1xP4FKson?FW)44-i zS+ks|a6tZ1qpa9E^StHIV(I!-<(rctyN#Y7zxn6{I}Cr40@a zzW2%JN0;(Qv;1%6)(Njs2&sf%t11YT*BXS9AyAub%)YA5h>{6*lWV+6d0 z#4ILCoY-w3`?WCZ(%tsLx3~IzMJGq!gm|mGJ^g<74J2;8zJ&OJAn2S|x*XGVd9i&u z$2N!PwSIC@S(n;}RMO{*B}N=`ciB%I?5c#wtEzOKeM;S8t;BxuZK_1|Q;X-jE39d7 z?OHqOBIJ}<-;{*&joA*^b>#I{VD4jlR{LAQQdpc>T3eUMG_O5F%k)`)Vy4})Z`&~W zvWn4U8%G*?jQe>=NlDFg)U#J~3)1<<-mz~!GTkB7v=2onR)@o^G1&v50j1ct%+&qco2?GQk$tZ-75vG|yG@qO7M%siTk zzJV1UlkCEA&wwdZ<_G^e9_A){F+be93Ps=#n<>9KFkImne7Ar_(wCEK+fkII5v)n% zxR|6>$j`DYMyzbPv=d5?+fO@Qr|#nQV{S@<1I-FG46~tG^Ac1GhCnJxJUS|lbqInG zVqx*Z_z(l0t?wS6!~M~G<5m6XS6PQKEKKPepYhnsUU>0P#S62<_f5N>|+_{cbN$A`vM|ooL1(7M#VBcrz zReQwR>{x|w>F}$B?@414mx)~y=w(Ev-K^qt@_qcK>yHWdGgWYHGB5_m1iX*N6)V?TevR6&mHa z%LoYEwRls`1uquP7^9)jnXgL32nrZ&+g}4rd4kQ{A)xm9KAT z)X0ddtpacL#X?#1yc#fmdD+WLwX!0~Y=LywBlOKyYlD9i4k}dVXX4bNPPs{Y{kn|8 zR2I@3c=+P%4`&$0_bBf$GKRCa|7A+c57>a9RolaEnQhlbR3KF=G(o8Vdd_O^w9a=6 zJxT8$xTsbeDQY>v;Y!CrKD&!^dQw3r((A!BW3a}B*im^7Q!o3n07e3JtMP10i$ zwIWe5WXyD$adzJwS_Cl~AESCComMIwh}u}-z(TiK3m8jf1r5_2P91pN)!O>Pzc?|h zaQM@+0E&iD`PTlJ>e5`JYsnF|l;X?}5{(TVUczcyCHpgILEk$pUGA>$SzvkZj9uhB z`i#?zoz%n9Wt6!NN=*=7XzRK5zcCL_iLD@(uARa}pAoJ`9cdQUjEdsPZ~5}&sFl@* zn1cRqe9t?J0^Vl6dDl`?T3Be`{7Qk1?<%Kc6)mf1$wv0zurN2rEEW6Xeevg-0`GKx zJaaXfW(brqU9(qjDEb3m|K;Mc-ay4f@@9~4;1*5qG+d5SZ^q8Ok$T}mO!MOtiiA;V z5F0n)dOthc_OrpuV#*cCo&_IcJnOHsnQm(@urrg05WM!%q+R%gpuvjGhfWWDRhO{3 zMGO5LAJGvX%f%*GK2SdLeaLJ7Sjno!zD~>Z_N!7Q&nmjN-;^|+dr*&yet}W3gEAaU zU%kMA(z|pSOLY4Nzc{w@F%5m}V}6anMESCj`f3V}oBn;12l@<`vQ=Nd&;J_OT}rsx zz0KT@sZuCu>D%I0^etXuj<K8RO;56qN1wO($5Xw9V~`8!)NgDJkd#Z*2~t6bk`BJs+$h~B@T7Q z)2GdOa@85HHQP9Xe0@K3X2r(7zO#pU>`M=;?|{ma>k%^9VWAFeeRo~N4e74>`rdJQ zE{+?&l_xiFbZ&i7EPjAKw0iXv4nJL$HX`T2&hvWB+=v^bagFiD*5>S z((|ePi= z;-G-=?j2U{%F2(R-AeD%v7M1F)mPXz`1qXL@#D@(ja{xCmj<$i{A;OIwAY&I&l(%y zwIj%bdZhli@a?lHrgTDwQ3l&+Dh4 zq{Q_?b*R)QV>WLuJE1>&v9s6bIXG84scpPSaBuFLI)3}Y7rK4=OxXm3VSNwCsc zsY(jQ1?9$U6mPS!2I(CL_LARi@gVcF@}A2Z`AY_M&F(AfYJaj2Ch{@{n+u|HUOVIs zILd@Hj-7zjl+8eQ77r&U=QgvV5y`w0TP$^M`^%0zUVZYJj0-JJc8R$3_qW5H4N0Lx z4iOG#S|l^b)rK@+|fb(l+%ydIjqiJazfMR&=vNSQCbCiYq*O?zBi8j_~6s{ zCN-S8$-bApVYNW3;5*-US8ExALvn`KiVEwOa}*dTjg4NOGVN`Q;6^D0^9%E?e4RCY zuK!CDZo+1dS__-n9t0$#EazAFU_+lR`%?JGyDDVxaJYk-O7Mi=Kb5ibFkjGj_ABM_ zG(CZvg=+eKhHmVH|=p!IpsRNyX%B6<92qh zb{2W3q~r=c7)?GbXLeE-vGuY$e;#{W(anlUT1??Xo`7zhdC3i5(KS3gT4_yhvut7R znsM)5S9doN3QIza*nSL?57AE4fjODHP|$)EVy*CJ(l~YU5C*72LP8=V8)2QuX9EFz zzBN*OK`PwJ*ta1KpcK#;s5Nv!K=4iIxqPV*Bcpa zbWqS1Y!|F9JnFd8Bz#^?4W(3W%-^5=y>^>m8)q_M$_q03+4Is$Yi+{TTnP{Pj}JR< zdP`gs5cI*Z9@$}+`8fCFhl{Xwz_o&T9RbU+jk?Lo1G%}mq;KS$xywWzRaW)@@BrM5 zj*dp1yUt)Wedy3J2oIjlH))@8hdMcAT{G>DYiL{#eh;}2t`%ng1E;@1qxiWGw~>yH zLtDiN&ok@(~UNwtw?fz*+q7nJx{=WRc+-W*JTE?RQ9&KJ_j!Wg`(4y+&cPY~F!~h$1Vm`y~oUhc04e zJp>oXc(^7}a2z+t$))7FSv9`S7)5^lQlHm%Y0S0ESWUrfY;=zLz^sgcrpm)lhY@vl ztLA(zr})T7?9Ly^F4WHBdm+hjSH0e2QImv)$5w}LO?(RL*V6kUxh-kds>2_5`p&*X zoI9tVu9>Y}9L|Z5GF3!xE`qU{hX_}zU^K@UF!^ul>oFdle)sMk8KW2)fDbX!c#%R= z8BmGQFrY#aG}>J#%o83QjGF$I;Zs-zQU z@*JX@H!HvwF!Yiw({}2aMMQhjnQ1ahg}ik}dLv?DF8Iqj=AQWYV%0Z34PL(nTeZ@+ zZYq7z5At%6$FyAQk|?zZ#|~dyGqUznKS1Paiq1J#A67{LN0640u_*TQn>3gHh~n#K znOQi5uC|vy9Sk_XF3QT#FuC2zI`y<-Y&*x*=`#mM;+b7s29_E{5JyvEjS~|}I7A*9 zNFGD-ZP%O?gC!v5mm69PbJ}Z5Z&~WHwH4o&VzIHEr<1aGWkqZ$y{Rkp$T@{Ow`oE~ z@eU`|J@#x`xj=fM%{Q+Pl9ZU9FYN(ow`fdd6cTf6dOc?DD=jS@TI1&Q1FjtvWjOkI zqpnV-rZM~I>jDU0$>a(O44ibG#_o)hz#S_NBs zoj*I!HtMRmxuvd;Z|S_9H{>pD$B$la9No#dK8YHX9L|Zw9#7!f{>+@>O)c|9KO<4i_*3mZ-hC(SFigXsg@25dj=+aL#coyWi^*uohV z6&0g2i^mrBbaBfX0ekv7>lwFuF$QDbF4)$QWL5v*+jjD!Y^P!Z2bYM6et{s<7*N>^ zxzQgV9$3{2>1TF9(kQicD_Af!%4WEuzHGMnw&%x-H9iMWTbhV=i1O0|{QTDNTnh_x z!C>&UYYS2HS=J_d4nOB|DS}G?tk*RLz$eb-md$zi&>0YVuh;(8G75U=+^DSJcjoR+ z>V?+9gVY$Vz1ddT9`!(9iwb*QOvNt-GMW18QPP=5I2>izlmqFV(6 z1C^*5a#pa!xG4Qv5_4IvmY}zG$DX^0%jw-2_&4l)#l7{!JNRhD^rAa=XKxt$!i8N$ zn@jH=NPU74{p=!G)tFgWY}ghLll41&;?4y8us!ym67huury|8DFWDelMc4tZE-CPt z!~6DL5)juL=p26bXGPM-+qp=|a}TVovh*3ZKJB9DyY%{ZE)1NHC>lBZ%==ku^mzR- z@ut~Y1$Sj9llgQ_HH8&EF1Z*bvgBu;Kc7p|?xXXoFHwYzlhCXI;>Yl@4LS?{F5EgD`WNe6vB zZ)j5mU}`TSvY*!vP0|di60QU<{n>^8{8a)O^XKmdLa1AYjTV@0g&&&PY_BiMEcMaT zS~rZR{nj#{=_d=>liUYRJ-B*b22xh$sgJ9&1ohHAVlAuYZjwhDDWh~Ss}@c>vO{h8 z)*~z|_%eFIT<*tfZ%>~iX*~(Y2hSb4Hw8~86aG20mT)c<*>xVJ(ej}~1iV|gUAv|% zc$D=1IXAI(HjXO!Q`^V?a;xCeo$*?i`)PemI&cqsQCwU-P#!9787Pr@{EeuuEJlV6 zwnZnPl0#>{h7lmSR8Y^~&+nW7et!!2XUG~1r+s-i1G6)R4~~cU%a)%f+SllkO36rZ`V>Q8i3HJ`Q@%WC_vk?-U~)y~!K$ro|00(Z0U>0~U*|GIx)ERx3i@1=RU$qL(Bf-Mq-sQ5Zg3tSJU-YyjmUaMTP4#Gc zfzKO`?n7H@8`We7Ot7>7A_oS8p&7eRyDjN2^pQY)kFGKvfhN3>*6PHdowtxxFZqwP z#YPgKz8RJI{u?x9p?SwYv+Tv21NR9S98-q(SXX_X}Oa~vv0ACOoTEcKmVhbaIVOC%Tkdx z6B+S{GoSMhTR74S)UI<7o4sY9&YJFbjdi{8>w(_DTL!v-o`JsY;IgbSsyZ|{2q=*~ zHu^me1k+l&eNRjAj&n1wa7sOZt^4~Y7x*8qRRNMP14N$AGvWmh0FI@a+ka}AZdi!XMdDKBvB7Y~s>~m4AY%NJg9CPU@ z-jcc&9|Vz`!}8FtySEG9AWz}3$Wa|FEsvS8F+|Mn>;z#x%&Dq0&Jhq2Dk&;j+y+ON zmwSps#Z~!-AJ5|U7{(AMmz=x)+Wb_F(Lg~;zV)e7S#i%940lL+Nf87e?)X^sP_w)z z!oEkH)>mz2cX(=lif~DG`Q9mMS$0rSYbdtSsX0LRc5P*-rGxE&WGQ|z;Mz6f^tv76 zkJsA+)1pherjXC-*xVn zXI1m%>K))eD&@C)&H5C9kfj__EKX5#6f0Rb)%5V;RI}n00?gxAtLfQ_Wo{Q2%;sIa zZh!v5@rO8Lnt-5iTzveZd5ko3pY&{tO5Q#i4f*Six?#hf-OsJx+;4^>FAq6+zJb)} zFU`i71ph4mkPr(~(-YVWc& z)v~10`)Vjrr(FQ=@yhm7^Kb+hYs z5#|kNcrJobNllk_PPDC9G^_sQ%MEMS%1hsb1zjc5P{r?5NKEEJEdzs*mwb`RX0PC< z`0=Hm5itTY_4ErD3ea&>I0K&pFBJ%v6kfvT9h9PH5jQb>vi^Y;IIV>jI9IO3Cbrll z8kftLO;{QNiYZaL3ePm01NquP#4Y8QfXr4iWEX*1_u zW2dbEyeHuBEZ-8aQ5WJ5`Q3P}SzJ!r`&iDwEmc4B#4UfJ4IA2k8_<`F(M{I!G6@L{ zy*vjK=iiIBG%Bw{zUE?Q=ap@Tl{lQC#+Q`@Db6bnP_Lylx(_9VhlisthhP|&_NLfg z>4QFx3JOA)feYjU{LD}+_(ptqUJyBS|Gwx>)r`T~p2ii2VM{>tTgS60{smY*vz+Y*!_S&KWt z?c91xM}he`?|l){yZ8M3X&tFY72S^8Ra9QV@9ES|iAR<`5fz+IDpvQhd(}Dcii(Qf zz-E+{D+l{KEU8r3m){vP6;jOG^|Wizo}DT;-wCJ|5{~CVW|(?ACknb3F|N(Z793>p zzM$Uczq^Y0Nkyl#SLE8S{uc|&%hjFz3Kj`D9_1-rOuDo(&(x=XcP4a z@#Fb(b4ZckihP~HU=0}@qp?l-=y~I zA{12r2~%4IBU(=%V%3a>iiJJJPKN_!nlnpYKY3EoeS)UEd$+G)od#i`I?be4 z$NcO|Rq~lVnOPk6s^j1T%UL6M8ttn6$FUNk)mr#3Uj?Hw|9> z#OWq&*>NVYz^7%ea?1%>uSAiJypt{A$OnnL*)(Q#pvFmctgO4hghwm}Y+b zFunvV@e3l~=M2s*la+Vd&Hs59$SPfO{T{=!yOo(2FWdPSX?L2WR9BLz=J($mPd;R> znfh!hy`ayVK_HBlQKZZN4)N?hH(QyURUButIJ1;d9#yjZdAE*D2@IU|>}-VSiD&HW z__CK>DHgw@K)27n;tw-uTL%ZjT-R-Qd%wwfCK7O-tE4!7HsB+Ov6p^)wA^mk z420~tGdfil+qkeu!M3>?)MR=b%}(OJLZGlwXKU*LUESvyv&N&xVQFt=GVY78_xhjN z{NNraAG_J~C4goe1P8~WMTadc4#GMGWfN>vpu|*CdR|qf6<`lU3QsZY-*M|LS2EDo zUrSkg)gZ?yRf|_pP*6nV9>9=I)-X7!>mk558TaqAHg7rpdX?~I}|Sy=BP7j(>%Mn zx~^Ym4ewaojI{=@K8m|eWZHY1+x{-NtjdiJ33w;O?upvBFwmivGQ4)1bE3F&;nSz+ zk|`)E!r~-c)(wlhP(3Q%wttMQ%473J-|eVuS5Y?cqxtJB-m;)Qt{rYir{f z1I@O_kjsa8!@~8G0CFdF%6O60%f6+iY}8rR)B|n4_11!m=Uf<~qT74CE`7HN_GB3O zFs^?Iz&em0M+vy-VHT{eMcKUB+&(E%98TO>`tI#j8&p*baZpr9iOPetw9gIMw74C4 zjO%Yhj)^<>&HQ{xn=cv<*i)9M*hC%Oh??jj?b-)wrp z74dYusNp@>6lw|Y$7V9Wm-%1(9F7pi#&+#VX?wq(SjWc)(Qyg*1=FiMYu5B>C2LaY z*h3QaG2fF7a2;coC8PZh{CjumK%MJO?<EPxrk})5~+Gr^7#0 zFLk4!U6gw=I#<5Jl7%0ezXe~LikgFKY1L3%*MvXXuT^aT+kPa+;rrk)}e~qyFur| z$j2G_Zwf>p&>}SPetLh2JJ1FuB?ZYE@kK9QU=ywgTwv3Kz%bpT(Uum#ThNeze^mLQ z-BfX1PvQGWvitu&)mb=ESdR ztL63AS>pCb<-iNP-9D{_zx=2PMwJ0bB160S`*j5G#gv!84updv4B$3dhUs+4&sOL zb6l2(%Xz=2*pJp|AGF=|4thGQ0YIQ=>3XpXl0%XIHEged^#Z{qG@427N_tOs?M6Eq5f-BL}r8<%r5yxwZ80R&Lqlq965U0xv&ffgRBB)c+ZeA zeOE?#i?xtd6fQ2VIyt*IU*Tk#Hr+*GN6=MDFjBzI1~-_QKd^3iwMuj%_5Q@D(r2gQ zj})wrMuSd~y8Ju?*R&OW^u1b5A3xsa@A@P+_J+a8&B?j3!=#%PaF4hNx)1yZFx2!J zcn4nUiqw-wt}sMr)2n&->FbiQ$1e>-5Ag&RX1`$L3=$jXZ6;u;Y9Tx{rye=1C1c8J zfA)7;dvNISSs?g+bnHq>tQ#KMYq)RU{s>z{VtOwx*?1PpoE4UUW_3uKL|~jPs6dT} zw{M$ZZxHNA(U`#=Dsq&Do&moAu!!izC$6ylCp-GCaWF3mzQr$MRhOPO+$h%*R>!CnjBM#N(* zjM{CAB{guO>kZPar6kxPL;3iq0qdg&KY;xjF&Z0e*3!ifKbh{EGWtXpb1AUgKXIZ9 zIFO_el3uvBgqY`VxSb-zCFM|*pKpRnZ0;5&re(1V(V~UpjrQ^9_2x*Q4pv0@%i6VG zBQi5y-#7Jgr^lq_?4t*ShYQZh&(A-4qY5n~xC*=89xYn6G>jkzY;i4ZM@=jNM0C zR4ptR{uCb@alM;w-;Fp_&q1|4{ed6z#CmIR>fp)`e$2|utUrYqQPtkMX_I<%7bF)7 z?pj(}DBgUy<%p64(amG|htGHtaG`S4W&9m%vGyKQ=PHulw=o-z%42N8VH3>bF#?ss*{Gk??{?})p74?tyqKs)9uUsyI_unWo|#SStHZbd3tQd!d8vB z4cD?Ax`=m=F&BfQ8$YLLl|4ek#viyPqzz@q$SVHEJ zeY1oLo`|_~r~Xw9UD|h-*7;~7I7)KiDZSw1 zI0<5(3 zM}7XE;dB(t2A+CY)M5JyHmqo0I06$W9vZ<8Dn+u zE0n}fFU}h*O*9O6$dGjSa^M7U;vR@2&>_1P$lR`=z-MvpZ^2E&fJ4o0l6#vBj|G0)Bu|rs$XUkJ zBjp4Ii_aE)XNB}EAxtY3wZKM;JDAYiKnl8e2=Fbi<>pz0eo{a{z>OOM6^Jq#@6pCO zs^yLpHqi44ox|PP?MC~m2*bVvEoV!VI8l4h-}X-dfw5gE2wXLU!2kImg^c%52vR#C zB19jL%fhL|n7aiD@xMTrzPn-%Y9$SKj9a4uLuQKUo^#>J$QBegVslu?-C5@5wb_nT zb&XiYvF20NeSs#G^H*-Yd5cyeAt(<~0*}LU@8z0?h9zvA3rS{Yl5IJ*@sBu5;@`PO z*bHIf;o^xztD23T-IDBzfav59#;H%7zQWdrV`wy1Ha78gb>SNk5y{TQem^!k+Kn zzt*NizVH|G!LDssc>c>*ublg;b@9&D(X}ZQ{OAE}y{+3o1Qh~CtX=}W zaX+ZhOc6ZzsBr&AshU(~Ea!RK&@fhYo<{qQvO2~UU5_c#W};MmVR9cP6N!dlIC696 z%wfHt;69GMV_twF(i-FaK%(a<*a?9J!q~ltys9$x6pnF^As=;4B@(lG5_H$KC85)_ zyA6_&VobdGJKES>_Vo1a)v>qFSife)kz>bJu(H|=|2P?c4~PUZ+AO@!pTLd$YDTy| zb+`ZcPUeJ9%2ag}{fn0@sjjWH^p`_LhrAgvCni#9u_yLNs~>oUEL9b^cPM9YfSAD2 z={<=F30mg9=m05g-_Epj=HKz}(fZy%i4{hyUrwNw*x{Tu_vfoOi2rex$ef+dAoqNd zJ_skLMd{h+u6Z&MKOP?p4E#E~b_w|5KAk_5cf_C4JGtFg8G|y;EWtU`*=BDzBijAH z@>-_zXDl8Y462zro}{>gXwt7#bEFIGtrK?@S-g(adtKqOfKybl0 zV)qt=ZTo^}cWHWQ_p|-{D#@Cr7mFG5mls^wtFM0}V%PA<2x-0Fru5fCLHx@swkFlI zCV?i!qDCO+m(AU9a7^s2LDvny1bsFt44?2H)d4hrF=KiUW1>Mpz*5<_i_pBrd4yRn zN_T*4aQQHx#DWKW9DwTfZC(HvVq#*5q)?MdI3@=NFH0pXO--BOl>lJUQU@efcChc4 zJa(Lt>xicT#$jK3R8$l!{Q*2sAtzN(P%5rb^nRUlst22qfya27pBEIw+`j$s)2CU} zr_be(*rR>mfAK%p6OVNYtZ-Hpp)v^RlT^)v2jhG6p(%*?ljcFi_&1~#VW(HWe!V`Z z5CPHF#-^%AMp_yJIHfnXt*OAWF-%qJj`afDqa}}B+8Rr^;8)_0x;!xVQ1I{IT^z1J z!2r>NJu4AME8Y@WcJABMqsaq3NkxP4cV_Wcpzhv@bgA%G9qVQ8<`Wv zc!sEXbH_3BSImr6qGExA7l+U7+iQKV`uNnw({7JPUy3dJJi7M5gBDg+GAKY~K6QWp z?&Iz4Ur`*;Hhr>|JP{bvEcFDEO;JU9HM^V{^~Jdc_K_LSp2Ru7TH8K-vbh>f)2pI@ zJcAV#a5Vw+W|QUm%zL?Wug2!gK5rv?HD)<3=1QMn!JRu`)LE{sG-#X8-#?o;9FhF z3vX&w6_wk=*cE~{pi0}4jXKk3%!qGy#nQpQ0-;wC!q~}UP*(z@q3dYhtU-3A5p(v=hVBqZSJxQ|`}aCjU$Ps?uZz)q7zAro;est!|v zXed7Ooq$B7e2eVE5KW5~mr?94P0}t8W$5cp{=${f&KL@4>O%7NHH1}M z=J&Xyqz1IONt!vX)4BlAJK3GSWZ5z&7@YZH9dbNCy+1VcllSar=Lv)rd#hlwIY|(o z_~ZuZEK4+qI%l>!F9?yb=}lbjMrkI*cT1K zeA5A~s0vEEee!|Soi|kb!A}V07lpA1&U0L6_3i zl^X;FN2Y}eCTT2~d>DUL++_Qtm%Vl~*_G_AX{e$Qs1Xy4wjI~x!sHT~UKf4-em=;S z#u-MF^DkC11HHVU(ibm8Hg6`^53G4H5gwjVf;_a@<+IH;(v0HE1Wm3T6L)TRe*+b!Q~}zh1Zb$rv=Bu$IFZT z;Opllv zuI%{Fsss2P-m1Or)t@n(g!)LAKY&MR7ZseFd3ltAhU7%Vku1Y{Iez|xd-qO&cY=^$AD#_=s}!9OB^K!To2hYK$58hc)WtUkco*2p{J*3Wz~TWK*2~+BXq7a z7yWyz5R*t=vU45yLa}a271`jh$$DE`yM>QWX=Hn!FrP{QupeFr9EunDTxboTC0pfl zKRq4eGtB2eACk!jv_GCTlA3IYVAN%vjLr;FRwY!k4e0CMAb2l5`2)cYYdbUg0=2Ss z-a0XM1^TKqJr);n2??m`geecacT6Wc>&`464!8b$qr3V7d(Uc*6P<`CYP;J!+4vHA z15NJy##R*+40X2$;6}B_4fXs;s5_>xM#$XfEZ*0T0zjD5KZ}> zP^GzdJ)X5rkKTb*wbihSHB?|+53NWp2Fka zqX4UOMhR{J#Ex>oWZ}=O8}~nIA+pa0Y4#$_!pe!`1=MbAT`h{0SlTmH{tQSaD$a>$ zrQX`_u?JcnsB^2oa$#AV6!8-gc|x-DS^oA(5N1u*o^xOGKd)YZ1gKCPs&le zl=dGID5H3bPCUoqt%9IjE|Ur&SsB|F?-DhH*nQ!WF}~oB$vS&vYV`T_ntFN(X=a<^ z5g+0Wmj&lYZgU^bBr^L1H*Q=LtRMMXVD`8A;G#W6UsLmG*QQgHUCz!AGq1y-+L5AK zx^U0P>Wu-wK1{picW5Q6{S$M zCY3NxG=Ly}SH~fF-`cuf$O7}Svu0ho#N|BO6ZB&A-w6T;>+P-g*B7?cYnh4ZNPfOIfwvYSfX1o9Ec zU?(+W_21Pcx~bg{eCtVp6xh0tFxFhM1Su8P7p3~|2G{P-FI(0--WaTl{6COc!5X(& z7hWbdS}|7{)fy8*C)^;iJSzR)T2Rx-Qk=G9{HllFxFKd(YdrDe|CJ4%qGorogbXCR zaMTysp84#zebG;8BTx?KcD1(ohj&mBshy&Z2r*u;%b``%mR(@Pl+(e{X(EI@okcmB^xcIM7Wo|OSyE743jNc$4-y~ zWN3Rd@vVtVEKZPeD z@!t2eOAIJ%oNmwJO<7b7De*;+LPbSI7|19)@dQK^QP}rVp7-L!+oS)(uJd0D7` z^bEYRJv0lOZ73AXP8Zdzynp=7{bk}{SlnwV0g;h%#`&|8)p$iG%LvGvipr;u(sOq5 z^Do%Lm@l`qU!vS0Nsne79us2<+W7MV)JHaUcHTecog_*L$1p8j-A`Y>SKP(WA06q z6JDZ_Z=l70{VJg%b3vA3A;&vXLLb z+9IA$kbj~b0$UGw(}FrlAm&u7C1_GD{Qs#uv<$?tZLWn)=%a?})2I@dX{HrLLs7cz^t79RJ35Mh$M&ZIkkMV7J zGc+ZyT-l5M+2O3|ogNf9%Fe3ybs}sDjui{_l+t43^8rmk9GE1o^hV$s_X8$@YQ67OT43>OktRo~echM7gRVYv zw+RK625;I$p-!My+`}(#v(l22g)p@TRD%Jk{8T(VVi=q=(rWtpl{Bw!3nCT*Q1S?h zMxJU3nRv6x)a9A)k9{X5s(0?$yClM zrsVp%I%mudA$nlv*a}mfy9ZWxD@2WhpBE;gQMf_6BeN-Ua`q!^P1v#vs+kY^7Iy9s0`DIaJ z`0FLkotvw-tQ;6Nwg3Z?y8Meu&(D~?X8q3*VCE1dXM7y5tP>ozx5jy+I3hRK@KY?X zbA=L!CBfWJ8bF1ij)&z#Ftyd#*o?k|)IF`U5GU*f3vJt)B%CY#zV&r2!;nEs=}3(# zs+Spl5?f$dBeZ~pgNu_hhUk+xI3X_egj~M)Q@h zd5-;cL17e(gVY9WT)OwhR)^O8jV+?OcMlx0w(f6e=C4kzj-7v*@BS;lS)Di2$eOx` za(VnZpe&OzC(fjbBt(dMO71v-UICdDg$diovs2W<`#+8jjbPy4rhY?MY=m=BZSAf# zJuOMkYF4_e65cDVjmd3wITdrW4{s)9m$el!o2JdoY&>Y*_c=*NVs!okSPyt^s>n*x z%dmsuw3z<%==rfpqN;D!;|aMDUh$C7vc+}I8-;|PVF(n{^2CA#K?d1dJZ^Y++{+sg zl;G#bL|FHith3d^!te+ac=co86n%&xgkWseoDhqRdV)dUxx`)!(Vu2(OYn<{l~tvO zojW%iy&1V?BeSY={}(dXd^WtYblWF6SxIaCxU8&@w6qV58(P{IFq0vk61P=VT6^7E zA#G|}$sQv0%F5+yLlc}k3K@nG>1H9LC5AuJw~E@lmHFPgxZZ!m`$#v#s9QA5qVl)9 zTJ)u9xZ7T#nu@u9dR8AjGx={!3f%N)Rm)DKcr1Z1Gi$-Hh4Qkm$qY%C~rv9?ht! zG3$IAhe_H-shpwifMdP`FE2#B^y9X({mj=s)|+;nV++U3dEH!65}7&1jZZF=yA9PP z@N3D%JF`4}s^l>%@e((eX5$HYqUEzxjc3t<&kSNon`2{rH8xSRM6!QwyL3*pS+RI-K>2T0i|kf`;ymPS`ySel zrZw1fW@#A~60)28^cADI5h*E3m}M`nE+)2)ytVDgcBE+pFwdJeJU|3(<_W)+S@qj4qFv$LUUPGrk_kDjqzyEslC}ytfy}Vw} z*K;ufFG-prCnO}Czj(3f=z6Imk#P@ugJome#Q$yfH?I}z$kS{Z-rwGhp6B97tj|+6~R$eeE9hw5 zScaJj(EFyGQfe!ubn!-dx(1&yR}o}%mVM*FO;yg!mGnu7-%wxQym_F%9MX2XuWBy& zLNZ=N+3OAK94TKgpF1es+LpF#G(=1;c-73@WJ@qPNBh!DbPugdGaVZV(vDVG(>8yn znNvOG`rhag$_6p&H)7@gla?d!NRA1bF6E0?Hf=i(;%yT6{@ z?wi{Sr;o#jn^h!?Hb>LPoEj1ioqP`42{=CtRho`loH|u?F@1;W1J$*eSu*ZhG{VLn z9oQYoI#P0JY;Rkm9_Fn~6h#B|!Y!HJv0f&M^_k$XNc{-&c|JTUbzVtJKf+Rg&dR(33&oE-Nkl z_U&6nW+o!a0n^?3+SljzA9KTjhPUEhg#CukDP^$5$=$e2L#0J4I(W{8a(qF*O!Tl&)g&f z`>9Fww$^0`zvnJ%NRX+;6Irc1-Cahhz@f7>C|e`;VE9lv7D>dGgBcWh;#IEUFCPaj z&Idg_(^u%3uWZjn-#RcekYw{StJ<{#=9{G=!V$EzB`fhy4&%}qJ& z==sxm^3x26ls|ZuymMJ9b?TzMeXK2pj_@#F6*cf>@PheQ{D`uYyJV)MpT`Xh3X_u$ zMn*$bE1L9k9oiz+*MZASLwu28?!lzq53n2=JvUn6ooEzC985@I)!^=Y$W!RH-jz7uM&36+boAfjM9{quh^T zzr2wv-p81rk_=QtJ^Ob-%FoCz-?^1jS3&9h-{c&!msxLKf5Z2itSZN{q%)-VzKo@J zo;J7N!q!n9d37_Y5miKj;-ApO;OIpgXQs_Syhya>y5E2Q9kY|(o*s<60oJUQyrDx) z`xA{qnfb;Yzlvn05VTqMMw_3bHDE9phqEyO7NrWkE-XB6H=Y~yOeq=JMi#ugImB)9 zd;g#gqt}=&&kMK^lOOl5eC-LidRP+s6m@(D>j_0^z0BSYyR{m`*_O`oBXwsZ{XFwX z`c;b<6e1kB954WF)}>71=sjBdzYLO6Zj`DsgHIOR(TQ!2ulqW3Yv2RLcsGu6xnpoi ziD_P>7Vy&TOy%S4f`%8R@8`=nImz>EaNEoIkW0J|MEuMz|6b=zlsUBaKEC$&1TkvO zX*2E3^=)lyh*0mjja`Ry)nFG?tHcmG@afB!ZD*?fDlUEscL}9Wfq|{CvgqXgKzXI{ zW$|*g!sQ7pRPqpEe)t~~-tkL~w?dVN=Fap9$Se-$oKdhu>h0?@Yv1apLpf5(lON>zcOi|q z%Wm*3hghn!qhrg3w%wwP3uE>7>tDJ6BnI!N^PNgrIfZ$}WGWX83b*wgZE|}IsjVAU z3a;D?J=ul+FUm^3k<;Uy?X5M7j}k}~gOdkp5Fz-un2Z0i_{dsIraLK6HZ? zVw!0mcd)_JWU%Xr^|w0e(4f5vP0dmIXRjrl85`y>gwnr#v;TaPbd>0v=f`3m*&%)U z=@dJS_hUE<1=hb=bmQP)T3%#E{1;zti{9P4ekb;N^9#E_g4>7EfYO@WoI~XX(b9q= zFe91l5x^$@i7-ckQq={`&soB5M$22plEM6X@&3Kq=rHZmr`3@*t=;mU!-WqAt?aO3 z^*sJ4w*I}Jhy2LbB?WzQgALNkub${8mATne^>2>2o}PA#T^^N0ya7A`B*J-UaJ3%` zv=A6a?J=R~-+mdeP)#)@ipt0Hqwun66FZpu4HhnH!Loaz=r%m_%x`I0?KkVJzC~V? znaxdhT~<*rh8zvoRtl6@%MmOmWdF;2;1?i^2x_VIYftf`sr5NA=u%reT!Vjh7m7T1 z8U-)RO(NMvTgzeNBDiWU?=&Mv>u^=-W;-4gsl%ai_l^Zb_KXg%#|;yZ9{*)g2yMOa zsjRfLsJ2B_t}(RmluM z)%U#*w3H{r`T0df(t~9SNv|M5hxeyM6zxBVl6q(>wNeF?kwdss_zC%V+*kK#+tr5W z-JsK@XF9^iMA)a}-EhXtY-ReHNcz~Yw&6H2=5h1pC9FkU(bwkm+M$tEVklx96bH5s&R;T-=i~RiO5?) z?G=eMd)0<8S>tWzPTZW3N`H{D3)7NuIdm0=>cMK1jZelNXkFMF;u^m1=M%40I07Zx6F;0-u2(B52}7U#}3(Y4&=$~nR( zKyvi|0OX%$umNl3CYq*xuNwNUZ#h%7=QQEXvUq3P8h7r(;nKZ#ic&_{y~<=mnlj=S z7mc2jMu|4-o+m#INAz62wz#U%9<55$wMw5+$y@vS+V|?z!wV;|E{5t^%&{VYeZVZp zAOGPA5UFza=$8trFS9w4h$2)S^7sF#Izs1PWe&CXdiD92SV^54v48$o2@+lA%x3!( zoM2Xc?MO>b&AHtEf9Mgp_4r!>f-Ms65>Vt7-XGlX<%_}L!$M3*OlG(}>*T7KvOH*TGX7+d;Z7(LUT-^L?9>Mda@;e5}$R~a}T*)e2 zw#{H-&i^neNw;x=(YZj2U2a$di=>)PRihtQ(m%wJ-+mxBtNO}aG(0Qf4f%PtAV6O7 zWN%xOt|}C9CIoPilcv3L?2*W7|AnAPBVJ^ZxcvAXLU`}CXdClU~&B<+aO9N9ZSF4_mF+h zC7KHul!CpQV+SsL@CD2fx~0bIP6;K1=n~jX`uBv>$5u}0rl)wbr@WnZbyqYiYutJK zl|Wbxt>7F90=3>Uiwrphv!eef;s4v?eAj^Q_U8@6BmBlP; z@@I3C!x)Y!!K5Y_^N^H75*cJJlo^S9s_F%1haTcLI6u287W zf&~HTfg zLjf%9HIrLl6~8UN^F?*17xPDhNXJP@#drtZ$T}ygE@H?q7 z*q>v5K^vGjcbA=UUO&1S8Yz@PHOak)t&fH&3|Oh!tK8Li}3JbF)Ec=(&oahhbks8?ecPeSn*ZgWi6OtEohy^ zOBfr(FezFNLj$_ACxM$~XU3YURq^q+)(ySNb3d+|XdrE=(-1Z;r?bM$((?T1UPdUt z`G#~M+x@_5G(My!9qSN#F+SOmiSbQZ0MV6xf?KN$sojc4?IV?`7ci~dyN!2(jT~P^ zIDxnT%3Jl$r1wqi^7tdSw6eaMUAyREf4qWbZU<+^{6x0P&X7Cb_AUCDC3aBb)Xq=U zCU#A4-En83nrkVcm^iRYW&l=!{`?T(pmyK+#uiU8Y3Z}fNUlAjXt$pXmMdo2(XsaL z$Zl07ya9dSwv0aDw6C<+nb;{qD||Y>Ng9oz842f*=NspC*iG&JYc_f6RA@FmhZq%y z=V=Rzwh8&Vh}4D+r@?_qIrXj$)ppWNIM zA|khXpavgP>@S*@=pi{iK1;bX_}a=VEB+vMT16Ph{ox)F>vzgOW~tu6pg<3O_j{JN z1GJ=54Cep-qU@30mVKJZe(x^qoHwsQ@O6Y+t*s@!%GQ!<81Fo;9Nk11o!$2Lw7~O4 z!=u5vN$?wZ`?hzm=x@2MCOK0eDNIMqTJ`h-bKU{hwtzJelrI2D;FC0O7IZE|ULpjC zfY9J`zRJI$p&{lF)UTrVODNoma+VGI28fXqqqoH9{zA9;ZQb>on}a>umwP;aag~vC z&C{i-ef(42ouxr{>Kt;}b>rr=rl4s!TFwNh+KBrSY|WuFc`Ypt7xb5(Vf0ltn}Vjj zK?i7@T>$0kl@SI*-fJ<@#p}9it_p3P`fyvxNl%!pr_{zCfu)I&yxa;mRG`P z5p~W|$rIpPF>OEB*Tc0XjSgmVP-rOsk|j$PED+@J_w@xR<@Sze(ISknJ%yma{;V+G z7+|~w)0u~Y@TWXBIuvVEs5)N)4-FZoA~#C-m$X!z?KjKr8yKVA@$)01E>=8`FxI>| z{$#XTmaQb64(&5*30$>%y7AbP!?emHo_oFfk31O}Zxr+|%P;ta=w z&%!y#IqRS&&0hD!zV}q-owY_7bzuUJxi;zh(+eTaQN$p0iCR29zxc z;z!Nw@A0JiJ`d90Fk6fpPOqOg`&u5uv=xkREM|)|eF_zxbE>^inSm?J98r^CtZ7X! z%ubxW4ih9aEEv>u}__}2!(a)X7R~I)@Eu^2xmb{lyI=Dje#A}FL zqZ*OkK-jV2q2=qi54?60ZSVvn^A?bgcJI~S`}`$WllSXCKfL%=#V$CVUCW4tzZOcC zGBasWKh>cHCIPg#s3@fb9Z&B?;H52IJdKMBH=)6XMeQ}V)o0*YYVv8JhTJNhPAw|@ zxC(1)8JObHfa*Om4C;o&SJM-!LCfi-3DWM%Nci2v1%?VpzfCs!5;8y(cE{n@;*KApE7fjclXp z1%y9)k+@N!i_s~ZAQ;9A-i31ZVOblOfTN}cZ*Z^AtV$cnL-$x(RrV87_DlN3S~EGs zn-=C&e5Na(X9qk5G4jKQloZ#@ZHk#UODK0I^g_g}m}z2BXG!(XWpVkl-TjSeQ)>4l z=%`77Ct;ZQ*8P>s^?x=jxeYuyW)^s-o&lEO5|wbw`|=Pf6zH7!7A$~_W_oL@m{#Mi zz0_NzO zYWFoxIZT`3!LiV}*E{2B+S%2oYcdYf%+!Xh#k8hrK458`;*kCGIaW8tQCxrPw@Bfh z*&~btwu8Sy@GyraiQ^eeV>S=xA85*8X+&7+8yOvV$l+t+<4v1F;E(szxSyu&nE1<= zFaBWv`daY;3~~%+MZR&FeeKSw-4iO-7I%RZ-E+wf5sV#T>JOs~_UxUf7Dh7v?-s2M z(U|IjhjSUpwUb%x~nnLRWQTbMfFG;zo@|v%tau<=(^vR%Ip)60> zV8>Brk#^_K@@u5$B+4h9il4tA>CbewTXbCira;r@fQ8!?XL!u^OX7T;vH^A;;a#~t z^P_x;(LEmFGA(hz)oxMm`*;))c#p4p5Bs4YZKceO+YRvES+%!F*NIc&_vW=bIh1YEX%=v@ zJ~_W7Uv^ZqGMB-uAOBZv)vsSBi~TgeFzxA}issRbrIH*SN}1ZkTY0*_m03|%M(U@= zZ?C}*oU$nH*LUGm6D6^3-PhjU`ijq&EIFc=iQf-h3}f20(x{}kxaw4MZJ1RQ$3;GP zaC;T`Q@)>~oDa(^l4~#*l$E_R1rK171e$dX`|Nff-F$K3eY>k7?@0YF%@bxBG&OVl7>=(Owt@)9^sD7CIgWwMWxodO7AgCn%G1;T4`!VQi_V>$*=g&gR9lomw&e8 z{%ZA=T6p`Dpjd>d*W7zi(yn@VBu8m#yPN~nXxG(h4%}SD;C=pwpwK$W3FBA8r^P*- zT`!fUhaKb_PfvaC1M#}&Vw_fP2UndXx)%uFTCm8##LRy8wxnXpgBbFDz7$*1Ow!3} zODGEf)4)dqgknJzyr%p%v6FjAYTd-1xg^LDHGRL7CV2o8+I+GFUG#l8^<55uM;`yv z6|;oU=f{LEUoCKt>W>u_bu|>qCL!MJwN_%XaM%*Xi#Ngkq+9km_bG{z_s`9yWkkl zG=(h+3M0q?!N-Sng*d2Jv2emp<^@|8D?hmsjP~UH$Y1^PmU1IWE``3$`T|Z zexRSB6h;zXTL+tU;YM*_M3-hiQ0s$_URdeLlDxpk|8?mm(L1xdo`5;ONt;3$_Kdr` z&3aeP-7RPIZEV;=3CgK(Bm$)pJihJn=+`{MF^F~2_@CzoD)_!~7)>4)J$&X&LPkaogMn5W zlGT@p#j_+VEnCeubWm5?j+`?wGi!kvN8Sh?Ql4_&TbSeKy;D(D^+@&V4_KH##HZ}S zJFNfsggZ=c1GvbdaLWaD%R%iJVP1)23t~&Spghe}In>ck)nBl{zr3{c>~9lSG^c$C zr?*_bq{Y_3hfs}LV7CZ_VZ&q-LJ8G+U}c(R0E6LVX=xciQ**Wim~fk=3P-lBYatdu z{zK}kHVEK+V6}Gj>Q(&&f42YF)dCdkEXkoMfBNhzp{O&G=y^nLc1>{LN7MIbC!ppm zm>BA-o_Cu@iXZv@x^@kQ1|e{PMyq7(7NQCr7&G02Eo>DmKamCk1hZ+rh!ANlPYvr&A0)Z;kwmvb7-ml7(lC8)m3VEtSVv!eKiQ|S+Ujx%Sg3xBkB&CQD-RB~pi+$~6wAreX7kX! zV#>8d`p}!Rn{XEwZVR7~>Mbv&RP2GdD;$Zx+>xn=b3fWKL#qUkFsly1s$^?6*Lt1! zo6gMn#FVG^4*Iez7#BaI`E($1jYsY$w$^M4p*oGf$XE0SQ#!XVH)%Xlk0G=?QDKES zncefxNM?EgT0$HyOM+NgBTkkkCI+nq2Ca?JVP*09i|rl?8q)>`BrNg^CB_a0Jl?GG z_O*6N2?OqjWk!M;0)&=`P7yKMA%155YX5++H|=I;e*ZluK+LnliQ;?9zOh-^`CD>A zZBOo4M`~QVCNFPv_-?+!H+5NFVgs6*GEpb$yrjus436Urxx}VS(fo_Gz$Z7i;sy8n z+fBr9xu0>kVHW#XYvXe2lh1#jZ68oHV6$x?O1|M9B(i^d?qC^l-22_Fru?3<(KC&7 zg>R44<43;LpKt6K?=763{LV189krS>qf4oTr-aqcI>$Y&tWwI(X&aLi;7(TeWR0>z zgl1X!SPw7H+&AF%f-Obsx=s+{7pXZ>^WsmeIkTR>;G#oEKRWtYKiGEE@r&J5b8`EOu z&I`al1so6Cbm|x7u5SXUR9jlqZw;g1pnH@~kgCdqvYSC=m z<#146!8vEI(YRko0kLrHH5FU|2kiSRzXb*c+1jQDu-4C)sGwdHU3DycThY@Uxpv+H zH+3Awulm^4Zhlr(^`^GA@955Jsb8;h7d|*}<56;Qe=j(Bb~I&1-}9!wU>c&QuaD9{ zC&TH6UQbDwhLTe4h4zH0`O>CEskx2@;k_GaJE^TR4fM-7I`JeHPmbC!p(a!wvT`zUvV3GVR+`#l$Z*v(yA z7nNpx{(O-9u$4LJ9tAYaKURD1QR&^^?B!m@Quy}JnISZH$8h~Z;lG@RYo~3J@Iq3$ z{@X)`nmjvBtEg;H^jkYeNT*Ko(D|mDf%anSmBs@W@=Am%p1PhSZG5CJT~9e)grQFK z*>^wAdhn?JSgNIi#vc=yKrv;q`z)CX8om_{e8|Yfa)}(+ha&e~H7QU#c%ysiAARKy z4_nWjOCReAP&@T5OFQTK^_-5*?A7^1{%!uzqLBWNlsZEz%zB9a%8R2kHHUcdjsS_= z#|M~{+=5ym+pQ*l(Mn@(F?|EVgzXcnvR2ntP?)wwrTqRzIu(mN0;r80<%%Z)=M&rK zlP4MRuUmuEm_l9(ktmv7SPwCui)cR}P5N&s^DhP80~Rk3ew=?V55Z2nPF#M6Yibd! z_BylL6EEu`txzAfl&J>yOX8tB2-ZL(CMqlXAOw-W6iz0`@KQdep|&C>imSZaXsi8H zfen zJ+Ay&1JK~sxFRIw=xS$YnNx0Qli$L&zE5qA2+EQZa?$6G1kM8(?yh- zqCF!1>BRlHt`<{p8$&V&BIdFi!r->*w}76n6$_$%Cbdps>sC5x@((5+iZmbL{pT)R zSiC+pJ$-0+*umZ&*`C;>Zb8t|L0IQO2iX1CB!8y4EXeFYDyyoIAgQjQ!99ES>=`rW z&w{%E%C$V=6m&_@kLTY8>Td1Oi`bky=Qd|voZ++YhQd1VI}xPYR-qxJ7{8`6kz&<4 zUfZa1BoB184yJ<;a}D=n=XzQpc2j!iYtyhW_Zv50KQ;EvN42#(*}8sL+j0+`M8{o@ z{dhLpn(nP6s8sLc`NO$m50p+f;P}crM<7%Uuzq87Pk%?9m8ofU6l*~k-= z2nz+Mr%x~H1sQYk06+MN)Lf^N8-2moDYT=1hLe6c`~sFOqY0io7I{65$&XpfZlZ>th`*9g(5!U!IYy{XmJ`32NhZDa@3kJ?wY%<}`umwkCF~>E^I;hR*iziRyC#zSHzz0Xl)f zn23moi8Ih*90!@1_#pEoq8h8y4T+_*m4;sCLD~g9nW$Lq_}FmveLB2$8g@U7iOJ|m zxM`S;cLB47*=7^c#))rSyp^_o_3GU#wcSlBXBS%V*&%~ zah!ATaTDk9xL}ptk&f;q`K$Zd#Or0uC>EKLl1*egKvBk)1ZRQCe4Lo*75qCi^fNd` zmdM;+YRh|$jIydK8LOIY*0N;g1Guk{=K=Rhu7T1im$jf5eln|-$E25dAQ=r!e$)lT zN^x;NkG%cBBotRkw>nNs<^F2DsPO7N}8|d>px9e&olC=^!s$2Eeina00^xiC#(SxoCK)Xl;{Z)8rm%MaMdJMQYsz>l z#c`lZBPTFS=E6)y{$HF*@t0c&xZDB)-**9^O?WANWwRF%2XQ7NBb=@HHcBxjI?O29 zs#afkRQpirsFTAKZn=%7!~JJI=hhyv$5@PfN-8a4zq};i2b^B9UdjMd#@)o;_b&|Y zI_y3BSfz9CNB|k(mk{b=!ZF{?ibdf_{QW@6qI8|PFe0Q1{RX4o{H+Nf{bzLfD-f1T z$8Ls(c7FM?VJspmI~&f1_P_&{-8hA}2zX`$u36;RyhUtc%>&|_vgA@V9E!puPkNwp zfcFJ(X-muXglh?9&kytll0jn1j#jtO0QR)q9k0^9$zCTdZA9As`*&Ks5{3iIl%CYq z>yPkl8S=S7cE0HB{(JT2Uod7XOY^ky3x7cts}EOTuDXYdw7$)KA$;+%2#HJozK6gk z|BsgX~F|8C<`GeP45nR99#I=B{~we+ow0WL?m~hj+%W!_1o9JppYnIt#z41U-$3!i zUz5k(4?7=x6rJCueEsn`NqBMxedd%Y-(+WVK)pC^+!q{#_5sf_av|Av&`D&o8l^oQB`K|aoc z8=H$UP4@|Hatt$V0=k+U!{E71FHXRS`SVu=#Csfuh zaisFvwdvOPA3KlI9&+B;o4RBFQ1HG(#7f+M45?Gim#;sA8la=IGtu-Un`iQo{zF(r zUu1C^3yDX5-gmH#&9innr>51K{mVe+8L^G60|)H#I5&!yc%Kfm!#(fU2n$EhGsqHP z5DQYWW^$n=7=cqv3XN#`q)D8TQ6mC{y0oa785uRBQn-5eV%?J~{F>*#W{p5pJtfxu zj{i&Av`lo2;IES%BQZ7?ibjqV%mkvj!?=a?0`wbES5lhBac;ubVf(lKYfl{AQTq^+ z0(6tzbzZb~UVZ4YjpJBVkB&_(`$PhPc+IrJc^X?Lrb#x%3l&c#HJA+Sak#7>ct|bN z?fOc81(@{{wz9PkJ8j}-&YTIkZ{AFNvAmdhoG)KOx%ZdP{>%TZA7G!PKTJ%t!VDOb z`rSz+C~}Q$^yfmiMU4D{Ym+A(8$$F{-==xUkeGdsa#&MyqiN9!IOwG5i}`0~X2OnZ z;YxWz25_+w)%x-GvsC`P%@nby?RjwLRI-c1hy^0$Yh!O=qG(NFxBT)evdC5aWB#al zh_1R8saKI12YIBJ9g@8>gLru*w%5cDPMgJZb853`(z|w7;^FMh13>7pSUB&KAYW+K zI9mrdKdhYLDp*@v8}-CLF0LKvIx5^#raWEA{$+4{FM#deKmN@L$|rm@SedWU{r9mAF>zu2 z!LbLM?E2uh<4F4L%mK5*W(SFkPh!y|=i{GuiqodcW#i?2m?v>|o(}J?lNxgD#QEh* ztgg-GB#8Dc_z8~RIG+*q)@>v4%dNrLAwSMI@}c74a6Z;Qm``mp@Ci_(E7-SyM2K>p zID{cDF8ym9z0r!%*wF#^{_4>_ltQaluZ~^BIVpBt4nOg_n9M2hpGza)=V2=A@=dCX=q-$t2g2&ny{-<=pbFxi^gT8NwWM@_zh*+T#QdG5@ltw+iQBHXq{ z&{27$8Ydbts>;gJAaYW*o_HMJXB9L|o@t&$FSNHeHrJ>#@Rd-ITcEpZXt06RXYv~4 zenA9`-sQ!M<3PYo3IL0PhM2c&0?)Rk#lamaXBdOdeTBG_x5F0@Vi;ZB3P6bF;U7x@ zhtjt#M=Bw(^B$D~~T9CQ!(bKxeW4 z&KBrI-~|Y9mN>&eGqg$}<3hWR{X5buS;!>qmZA?DaA^5?__v??OY*lVmwpT1!C9{V ztk#y}U?R3j8Gt(hk|G*T|2~p;A}t~B;CK7BU{gi>k^4yALbwy$$AN@;UN~_?Sce6x z_x^q|6m3`XtT!+-;`pEZ7#45UrUF@@Rz8l($r(YD2_rhVSqAvO|A%Gr))YPN@D0FB zXvJ>qz0U!NB}V1?%V9-~H4ZWv><}dk`Q8>H0tpKT`6_U#LS+t(xk;wpH}(e&ZQ<|J zuof|5qGZbmqQ!-W?@Z7^4+lI7$wg04AM1z0Uj*)WeyaFRP`Gkx|H5Buf0$Hyvyt#s z6!O7L8r-hi&KHwYQ>8a-P>+|`0`vB#h$l_nxOsCKVh6xVQst28ao=q`${DZ_Bqd;S zIG99V181eiW zR%48p=y+m&oB=U-rKv>kL}>R9zCqyK$rAd?caJ_CJ!w0r)(T{(0;H1iGAqg1-sFU{ zMeOG>LqdBaPN$CPWz5_alV=5|j`Z*TSDk*;msSX3+z|0B&q|z&Q$bz%ed@cLKW--S zVj>NNrl1)4g;5|3HEvZ^41Bu2SA?h@TY_PPVpaF#;HnRA{5*|6=J>m}W<|R%d=-Wy z>*&66cpD=FXbX^jidANQW#u50tiJx1(nK&xw(mvS0MxLLUwU|Xb!I$?r=!fnNfT<{ zwA6eMfk%iCISONzwzgn6`1!j9kc*Q0C}?Tk^8HKXv5v_>C)of@nUe7wqAOw~S5000 zWD5-C)B2M73LfXW;F;K4N)mm_+5fG!C4Mi?a>fxTzy0mQms!ZX$< z#1Qf-$AquHnyN^Q<>xj!4?2PA(*MkPkHMAVGg1DzOxL(9iEfi9 zAzy}6{mm$PO8?_<@dp+*TpL`U!OiGoMRUWgmz?Bm|Kd~c*Mxg35T zyY~GHPL62zoW{sMae}5cGLT)EP-}m!eJ|Tz?v#$DCH$W=?KyciQRkhKYY>}P6Lh*Z z>oDsZEPeA9r0L7|nBo%1>%m)apwSQ-gdDXbgUs9F2C}~W*AGdiDmJtDYG3-AP_N3}#fx9+ za&tkyJDmWdcm2+WhBaFp-pdcXR(^c;({m6nibL+}s*^>@#HE6^`|WQGrSruUv-!eE zAv9c;xV(gdw5Z2)`c^5azg0IkCIX z{Zo5j!EIW}=mTanu6J8oXRLhu$=E{v==xGxciyY8L#PVGN~D-0bDXy$^~AHWk!S>Z zQAI_(Z#eFe+96o=5knusY!Z`Pkwl@&ZC|iQS=oEZrdq>%i;6xB~(;8LdI)9|U#dFS1WmQZEd-_$H{t>Esvq zd@O}0E0GrP`U5_ghu?W3TW#!1MO~^}BhW}0D`a-acC^Wq=I5KYXuf*fL#OTYa;sOV zW$bh)P?IeW{dWAo0DWb-#JaaRw~l{nd5=6A3aoxJkQkE6-d{U@bjPKE$0w8Jt@mxc zc+@G5&b}^9Xuo8&ZASNp;7^8CtxSiD6mjb9&9Dxz)HL0)F$esCJhaSV`1z)`+)|FP zjYP_S-E)0$YwhcW7Dh%dAn=9LpY`~t_A9SB#hC$?Ov=`a`?fkC z9a`8vjZs!fUz9|lo&nn&&g=}wt&WJQX)Fu?7s*`Ww58?!uNX_xns3!-eE3t;q}dD8VXDAf0%~`x1+U0+0=VQD>__x8e}f6Q-9BK7^)Od zp=M@hdt9^Arq((;JTj|D>uhlqsJ0PT)bfq$nA2F6l@d_IF5e$y)$laSN6+-KLAx&| zdv}>KkoheTMo7zO?bG&h@?PQWA2R=F$`te@m{9N#TLyB+ZXXCbSLdYdpiIT-eGJgA zzdsU$`6aB3SNp%cyS=f}v>wkHd)A1S)No%h%)=uKKab19yy&huF_^Jy=$_u0(V@lN z-QKhL+nf}t9Ty@mSBm^KkD{yIZcEmC9n1GnmTe;v_P1Ijn}hT^mAL6Dl5S@!PMl__#6pufJUQ!s127M%zQoB{VeX7y>-* zw^~fD%Caa{R!90%U0Y$b5B|P;Fk5)x{f01o|D?Lm@>^@$6~*zWU0T~Q#ej)`vd81G zzOI*lA0;48zViI-)oDvjPJQ_}rPcDf$!0&*#S5i+L+UyfLXIS`Xqik?@hAC#8mWTX z+QZGyx<<;*bIYCe21z{DW5kxGw!+BBxhk{iGsX;dHS@)f1eV-)$}7*iJlgTW;tcUB z)p^tdZ1!(`Tg6PqcC`!SmH3CgU97x#Nz2v?7JJ?W?Jf*>1#REQ?j__DZ&i&$S3|ky z+7lHYtR(on_ptf`j6)V@2g(ihQ=iD!b;pWts!IxM!@#V!?f`Frr>e^P&w%fluT1yg zbUN8cb>Eo(o6QEA-CXr-@$pe(;(UO6>+Hys`pQS$=Aad6D8|iicf_WR`SNLX(o%m8 z+bO%`v#ge`E@?Z?&q(epI##odQ9Q4sX`^7@{=Y~j*6ZRx^2)zY_x-x#nXQlL545;t z$fQ-Bil@^vW8p3wwYcOyb`E@dctBvqwzE$q5Z4}=(lwBou??Z{A`dXe%2i{4tS9Nv zU(2-VV))1oLl&Oj`|5gknX|3>Y2)CecpAk~boKcZw&ZA8bADl4@GkSs$@>dR<+}6a zbSuJ*N8=8@HSMSsEg$R}4+ftD-^kh~74n9mrs`h4+`Hep#--iUxtAP`?v1m3OsLVi zMv<{4rSdgFfALm}(tVq>4+cr}BbYdOrcuX zw^-V(F{!|5PrlMCLl{QLyf*G)6mflQwzNJqjfMF_5^F=V^!5_W5@QiWV%e7 z*pbQ+VY`5Dr9o9MnB?>7?n%h0?a*=PDG0nrtR&2x$J-^KA2HeMXb}Ik<~$5wb@YdX z)2b>_l;-_;0hAzh?FZNI$ZY-$X3=zRem1Gg*p0a6%@&c;xU5>=wwY85Yz{8L-Vt!r zE4P-A@!s=Af05d0Ma!=8qL&TKP-4&zl%m_q)^mLfVzm`rPFp@6SD0rrJ%VVy*vYVa zoRk#pR$5XrHpr`E)c)E4kK&~lU$$9^p!wL}hl@dG$u3Uq1*LI`oA15vXbuS*7gO%O zuZX8d*46ri$}P|~9Gx#KOOdyV(_rg>iP9ZgkwOeTXkZyr7fLiH@fd}%7JNV`)uTr( zYpd3`Cg4F4Zr(Zmeu7QLHBa_Z%H?|Y`4&xesDG!61}~I224epWv*3|OOiWd6Ugf(9 zzg}4N(?19wSvxj#&R>t9(G zZRV}my2!5Q!TKeR|b$Uk^?W%edx%|MZ0iGDEVBD=OLjC|ct5(C}Sllse} zUG0i>5$8XVula|5)#(xgvo*+gEP%e+ZzeI`Eus*^Xj77roze z#m1)xhG?hkP!K@hxUa(k3j+!eR zk%IH;>UR5{1_W)vA`#qgDM?B8);-N{Os;Ck_Z`ZXmboU}9Gkmc%R1%pV>p2!mITK0 zC~FTW^X79HzY`Z&*W?98JjV@&39he5eV%b42HXV3u>$sMRF}P_sAE6n7VqLO%?Vk> zG+Mju<0a$rw~_(zr^^s@s&90x@FjosmjUvFDmcz>0)y)89a)m z*h=|}={s(lrFW)1z3jHzt>gB`&R@Z@#*T~p-IbdVC{GGgrK!i(UUq-MBe31jaHWL( zq|R#B{0DCIubL0~fBQ1pw`Ki$weCb0rCdzW2WJR(Fl=ns^dye=)}6-^!=Yd^_PpEH zHBx^3P0@+&Blb7HK^tWzeLu{3sJo%zBxpq)w_CCAtDUzl{IJw5wEhTP+$es;l~_pa z_hV%tQw|MEo;t{hHg7_HFgsJz{71nhJA~8+#Y>^Rq&(wtl;XQ3F^q+d_8| zSEsvYN#RGp@apYrvfcJWfb}vV}%s!blyNvfw z3cws}c!^;mRsT&x9I^S$3%X~90%y!!antYH>FnQz8&yt6H;!bRT;=nOVDN@0pVNNe z<_2@n=>`Lr4UJ7`znk01dGaU?f4iRX4THsomTM^~xCYMl4@Bccr*^ zV(qz(tGCKk)Yad@Ep$Jl=gt%$TOpgV{zIayW0%*pe2L#~Vhq>}a|yVt+gOtt3{|f` z>o2oN+5{t<9;kjMSaJNxQmIZo#!x{qQM?JOocVNQrd;TI1w{Z&qdn`}hcv0613Ww= zYOTBpR{RK`Kp?Su5a7Ye>gqy`?YOOaDA3~h{N;7R(QCza_<5M$3HcdUROz&_-^izk zG5Z36+@7h^jvV3Z^B)m0=SzOaK^M!9?6yg)IkJox+TH$m`{3XpeDF=|FhqiZY52nL zS^}~*ZxIvL4sy0TT{kpGBmd=IAt5nQMZf5e_2%0g*qP1#M7MXALMi1+adEM1SI&p3 zDmcvD|6KkY!JBV=9nEsHpR5=19cv)a>MA7Rn^Fd?A>y=&{9-#7pid7c2H z_jE6ad2lC+j#!PzSGV#;kXHmrU49|B&aj{jBDn?}s)2JjRId>wW-zvdhp`p-$8p+- zA2V3`Q1KViYoCC+sX*(wFJjnG$iogWqO~I12Vrg7?K%yzHB{=)!+dxGDu|lcYAM%j z($ATi+wkZIyfe450@kVq{^{#y1qJ3~BZEvH9&v+hm_W%K`d-9Sp=>0+SMhkv?DDj> zgu2mAyU(^J5b81u5rc^yMsG;+-cv9fhDD-}y|@;8NVGL*bq5``@(4wW91M}QgQ(B* zOjc$lXiEhkggGUTTGuDeE(3LzqDh->ee_P(#^SJ-|;fp?c0%xomEdn ztE#EJcv+lVW08&RLQO?1KrpV0FmU3@`6}KzAOb zr|XQ%m|VrwqW1K@SAI#WQ;ULE^U}duGn5+WsE#f%Yhl}l+3L=mC$jTa_|Eo!iG~=_ zbV0$F!a{^t+vZly3q$t;6Z;a1gf%o^9@W=D=c4Gb!4K(T7+29%l~#CXXSc)sL|FY# zKAF<)HY!sIifA>BF5PUmiutQ)?WbDB^0g4x5jmC5wMOy^e=S0rBAfH4{B+~ZVoXY0 zyk@i}+}S+(^*F^&Cwr9W|65rg#3_N=TB0(GS7F^Li=q_^h+f?!=N^6U<_GNwFrZlf zjsWfFWT8pY?39q(7x{J?4%qN*ilARNqNb&%^SAD>3tcId!5_k&rm|xb`E^%KPOM6# zlu1JPaebO)(_0ZzS^Q2w<8I zzfT=y$vf}Z08b!X=_q81s;gHIKb_klX6M-cU;1xv*3jQCB%#~ciW)wpe*PJB*9)?j zOf=VOv&KgPJa9E`ld1A-G|6QW$8|zFbWJ^RQ*R;}*SOHH&Am`6aOhl*WOwY&t5yf& zLJ07W&FxKH!&Ck^H@|NUM&c(KO5Srpg8ygsNByqzX?M}Xv2tlj7amvs+r};mA74k9 zqhu3fK&?*R`R_2}EvXdk=9#c-+63RLwo<|^SjyF3!rSk#*T>Vj&JVM@yxtPBqv_SZ z!%<`YED46LBrO&2pSld_t8|UHw5_a8vE-!xXpEDSyku0qdT+Ys7W$%vj!-Jeby|Oc8MzV7DKVNIoARP1e(%I%K*I2xNi6QHdwAoVPmnnV zMNC{YJr@HM7=16i&xng3z?FG7QM~0#yDOh=Ow8MWCxouEXcwItYV~NRlN<9knf0u}Dj~bI0?d9gq`H2=Q`nJpho@8jx!s zdGu0M$7t|doqGzj)I z=CP1}X;MG?D-e8Pub)W^JCfSO3ci6v?WPzyz>*#O@ZLfuvBuh^uAy^*gz|MwZ!q$L zdwM=po#`jpp>eF+TO1zrKVpM+tC{1to@!@md_e9mWW11U6r0vUPfvVP7SC@Wgr;}Y~SxwCdAf~<**NT>f(`iSjHz09>)5F&8 z{(-*_w;-61GY_6nfL&T%Mq#ej#~UguDzbeSoF5|pB8qW^tw}aaEtRKb86a-L!=Qlb z2TbFRll-tyYa^!{(>UB<_kf-!O<0zPn4n*5_7>W1^2zduh{;%fhb3}E(}j5yhEM18 z2h;i;_-O6DxfQH)YU9{BHc~MuH@e&|FpZszh+f(9m=IRmhGXpVcK`)L{{H)K%wde{ zOqZ(j{j3~h^!Y3$@qmGx^hTgQio+vsA00d3$@`w5(jOEpj+`H#L%K0^!ROI`=voA~ z!iEp4ufoNp{PnHQ@o%P1uU3~htDUyU`?K#`ckual`6hQheR>9DGAg{Tx-}A?Y9zLC zz<$si#AN`NW%hDhvn2C!|D5I$M3Qf}9Oh8+7g>5Ot(Uclsc)~88117*bMvu!iLmj| z4=Ht4Z3#Hj4QWYx9Q)th4T;$9<<(D&skw~ZL!=UFM>nW8?&qCS9E*I+*#K3q9<0T8 zzR&`YKEAkE6WK_Z;*ze~v!d059-nJeHGhH#J3+zcxKKWP=zYc|!2bI6rlXG@nHH@N zv>QSmummp?Q@JAh^0_cts8Ui1CF-j*xP;Y{Uf=~j8x}IBaJ$E zKA^h55B3-Z6YU&g!y%u7*Eh@|*n(Ie9JWQ@rb(hthLM|6G)X}<9qd_ussSg^#fvcz z)W^qf=*l@yjG(!-pr0~bpEKaxn&*D(vqs`Y63^t}e^bhe4>YO_0))HzUD(6d0t$|L zxz3`kM?^bfYbgL_Fk~3XKaBHvSrLC(tWV_PJg)lB5tO3bxZaECRAo-S*_PbkPZ`R6 zw0-A_>u7lNQu;o-7Z-10@_>F#$^>ZrMD-C*8-8!_13tb6&ZIc*kT8;1bPqz5-MjW~ z$06;43jZ}BYp8#u`IwE)?;XcK_-v%LqY*>l1j!VJGv?;4C>@q9TNc?kA?#z$!~|x= zCX+lQ6xPw&#W1osD4{}izi>$OFv@FqLxbkDZ=V~xGB1z#xi=A?At@jbhWOOQlZG1K zM{~{-qq!X8gQF9*7NldC|4&Z*uUgyKNQba~U#$g6z^_`)tdUI)tJnVm$3f0jwI6GG z6u=?Fi&&iZ+*>jBik(PLVz)(` zpTPQcqN0+w_(Pb^10f{q<&Ct|e^?Gwz{nytAlmkL*d~#VLU&G8uluqm42yLC{{6C? zJp1l)z-<@W#LW4gAzbbR@e6U;iI1knY64N&nb>jqM8o^YsHmUCq8zR0gz}b)kzZQ< zp)>V{lJdaqtG8YKsg{;%`}ZUCz%b{cwd}h?h>ARQN?2Up+#YKUw}H?3M%}sK@^M@= zQaNOWbe4V=VG}D&jE@eqmr|G?D3tWm;mTZ~$NntcUcq;X6|o)lu`qNK44lt7Cky>i zzC*XUZTt3jVT!r;Pk}ym?(A7NZ|_{>(t|;c{UwvQx*cM+^||M6A_VKsowyQ%LBFer zY)*EBqOP;E6RFY6Ap$N4lzsd5A;N;R)F?;bCCcg1(NSit(j($JJi#*~2s2xD;FF!W(rn3-wDC0%c%nwukF=o@JL=9%Cq#0P=lbqY`ljotDJ zPV<$IPh#N4M^val1qTt_-O>zeUFXJo#P}GppiRP~qodjD$}#3WB{W~F4(EF&NsIw6X_1z-L#o${&nVR8X^S^5XUXogUVGej*Po9i{u3Vc*c;b3H zy<^9YfHFMbnL3l*=g;>Ikjg8E6WI8$$v9nXOlU3N|Bt!14y!6{+r}9kbw)+T4iqd<2~j!(Yz0IFl-eK` zD7g^?WE0C6F%gv#X$k3uO>NLYL`oW@MMN5ul>W}ewq~Aq-{biGj_>%MKj!dJVz0IC zb>G)@US~iyg7%tUD{(8Py2X7#!B=}g-}pw1#X;R4X5R+z(D-N%dlLsf6%h_fsCwKf-VX55(o;l~TKKeP_O%|K$xd4bU@Ju$JpMk}4a zeZR3tD`EkLNTi)fA&??*NlA>K8(ae!OleYnj>5>}!&m*k z-FFa@ueqBq4ged)F|&dK0t8a!u#JHig}@b$p{kz=8$84UDsTXVAbUw!_wv*0-*kavRa3*X3fY?G$==2NKh**Pe8?on-F%-TxU)XG4deaxpd`9*wGsx3Z%Ii z@XvjWl+3`$Ko}*<*s>x#+x{E8jD7yjdvBQRD1dIAF5 z-F*NymJj?xfz-BQW*?KC`t1BveSLB=l78ck6`$_XZoH@qR^}NafvgF^l`)St%us^9 zE@u9gKbcHn)BV(Sl9vwGD+C1v9TsR6*m5WRdyI&bg0xWJEM_ntjhhmYzpEamzQI_2_hP{O%F90reY@cSVld=mOd!!NwVn*u*Rw@DztAl zf-#hwl;rjiCgU*H?0)xd{h~-AMzF=YxEctxZs{YD{uB122hdx;r9CM()!n!iS?H(@ zkIIs?SNMN_#paOknOREd%NV$iTtFoykCUcvWA}`AL?Np=k)m67M9y#dND`D1wX%m& zOzK2Gt4t05`Bv*Y9EBrw^kVFNGLj}4dpI1%QZ8Bg^N#LG0JsG|Ynuf=QJb6@Tn$o4 z>+3D6^pmNu!3QGBdoS?v@Vume)Bb*N_IDx^lNQ&`&fqe`knMsn9$6ioO2?HBx(iRa zLNy0^Fq{pTv3Hw=uvuFocLZl5kV3>OsH>^nSzck7^!701{2D?ag(92g%xSdcVAha= zlzhBnB>$x^l>S{1E?^rRta$@TU^JE8MgO93>5z2>cle6S(X+vzvn zRF!gQIUu(guPYQjz1^`=l*Z2&P(Oq2*VWlcK67%%xOemWyY@pPZUnj>c8vG;|03XD zf)*84hyasgV|RQmD=ajA_xvi3>_?tJ^j#SYhKBg5=PaXfF;FGJcuD>`1%=HzY1(l< zWAdo2Jfn!bapb-gWbJ5gY1!1pf6;vr;=hAclW)9KUv*1$EV6F`}W>v z7dx6!`At7WKtNP%MQJx)XTsnT6+id-0m>tU>~`(yelxRLf&pxTzYPnUwdCkgW!8H? zmQq_c2aoJ4g6C!=4F6HVp!5h5p+NetK(eYi(sjH*s6nHUFAzL02HY);lPBQ>Ow^jT zB38HNU|vOa^rGV0{!30lB9J$=7A4nRdt*81KY;tYy-#66;)(dhGh%FB zcRjNH1p4*>E(lXQ`#*hZ&-CvYShzft?rH_^4f4)^bv*!QFt|OcH*k`%cj=+}5``wa z5AP2ECi>&Jm}aUu(OMF5L3qt)^~3@J>#ydkD|C)Qx3D(+9vL0SupF3)oI-MiLhTIA zb@wr`Gbu2k=}m3pU}JMe$cqLi2$D!U5wRSz-(mf5 z{*CwQB}>X`zJ9}9BB0eN;fIM681>hml6dYFK`i>RBe-84yk04duxEiHYcJE%Xcw8| zId?ynBhtqrBVK0E>DDj_7#wteIwe60KxQHen35Kh1T4?@H^7{A0JT(a#=sjK2tB$1 z2fh*p36eWVIsxHF&gX(V35TVEgSJB6wD&hbz;{oVPfHGdeM9zZkK>94VA{v zgibQH<(n`FPYEovJ5Y$Z`hRI#_?7J6e(mY(3)_k|AcybqWx^jpSklruZO$5`0%#W6 zB-&k)dP@AQT$*ukn7oRI`?E(5lQ&M@k%jMnKujSAAp!N5^?xP{w=3BE2%6TX1gO_! z+Dok_1GdqTlp_Gd~t@(!EtXH}2Y1Pm+*xxHb`+uCvS-A>j^?cbudJ%{nkL z55fz?IFM%2aJX9WKKWZ){rzjQ+u05y5QDYy3~c8RSh`%O>{t@0=(`3Ag_`ICI@e}? z;Ml4kwID9eKk*seoljE`nT615hTVMEOZ4_OH$U|8QKZRV|L&^8^mY2LeBN4k6j^}V z3_RU+GyFf<9Tl$r4`PP^>Y)3d6FWQxH>;DDU}d%&U};4BdrzYsGzES9^s+13q#)+- z--Hgx&GMD_run*hwS)gQgg7R3$tVXNZvMOdkq@rWx{ zA0CFXs3SW9_~A}fzXCT^MVzddzo{6%Q?ONNao}Kb`L(`(FL?Yes)xll9zUFQI&leShIp48j{{&s><1;0{#Q%gC86ubx?T^RAUhl6xo`{j8%G^^O+kR$u;(ds?T zaTu!PSD&1iK&~O}{mb8JS>(${e$iLmo8ar2M~wz<@`H;~JIibj;?1us5t&K8tF$Gm z987(mM96AV2~{~S|Iq)|#!7K@xYFnqCUxq|;J;9Z#j17>UF}~?qB(z;tB`6H!b#+q zef~dCf|ba3{p!KD{TJN3pYHfSG?3qKZT3Ie?zr%GTB&Wm9hj_E%1VEF?%h*Izddc0 z8j^QZWq-dgy7`#QvH8UJf|0yc?H7}&y5lX=I%m>S%LfED^J{$iQY5HNiil=T4)SXl zl@Tt7hh(Q2v8P_N_}LGy{-LL%$+kQ^-m}KlkLA$ zKC}BKv+5K=uHcNH(9;F;+xegDb0eiX&`lMH*e9e0qX-pRm+?)h?^yLKj zyepRJH>Suwa^A7c;NfEdY0o;T#&ECP7@^884tVYi5kHL6h#7NEQd|1%CDGFlRegDx zmgcl7z*olpz5gEit;}IePQ(_ zotcekz0_?_>C3|Dv{}pooP0bODzDg%*4Pdo8}ht)#GL|U5W1>AU!7`Jyw)r)}f;M%d(z?O28vEAH?>Zjx7jVFN z6)e_*zn(V18M$ft-3J|O#n|Lzb8Bm94LI6KS$uRI`oSP2+DCdn&o1i+NDodLNh2*T zHtMbKh;LldMWs0ePZfh1yMHVafUo#M7(U#8Do>%xtuYlhW{L{jUFOo zxN0x|WKy$%AB0|!=IJz*ke3xJz-aB$r4$)dM(af2U&VcWLo+9>`Aq8EqZITcc%@Dd9lp^zQWN9F zcAEEZ`*eR)(^+xU=cxN!UiBiON%N-<8wDHGh6S8j)L&{$p9u_Wd@?c|QPy7&bDz@D zIZ(`Y%&EAw*L|qYnomhKPG`l3t%mmX{bH>KuflxHUq0VWtRBz1w>dj-)o@e3$I?E!mPK0>^ur)PAq+}@-+yz?|}2^(h(--0eNzT;i$F`fcS<@dK3x|CCE z(pW39v+ZjW7wZqXTS=|*&`zJVig=sUI5t3gF*!p2?RSG%+u}4>ZtCehn`#*dbYJGS ztFwx=yDWGzF44rOnjZ>Ax(+pO)2;~zV!Br7{C$VcutN|KAmO}l_*34NaqTp_!?b?- zpE-(8DnE#d@4`D<^q6 zTx9^E(4OixJ9jQcn+9^o=-62Ik^3HQ0Rf7+_a~>*+88+rP$pOOH!WF_o_fOLRXlID zRP4e!O6_o2>pntBwt;RxUh@0Wlit#{_io-yui&wA@T7fzjdYF{br=6BGGyU1Ia^tpTrM+rB*^9I}(%TvBo7x4h_g3VT@@ z!3dqgO6Om-?M69;56l1iZL-(bP+?fE8xm8C;6v@1R)W2yRmQL^cTio zckKP?JhvNp*uL6)D%7cg`*EtKD~vOSncFtg_uy-H zQ?bc0n;hnT@J-qF{XAk8XD4>{-<{(5z%)o zAB+7?Pk#RB<+76RG1v5py8dYC#@J_XE-Z#6nzXGbZ9zfbi$Q!s7P!C=|4QQ-@#Co3<{54O{YQcNwY+?vzjod8 z!>ebElNDy+Ns>50JHOx_+yLRnWNo=A*o=1fMp*0B&e^S-NQBd@eqqlsYE2!Cw#x!% zm=3hSzlK&EA$QK>+zdUx#iw@-2Gd2G%9YjsWtWiCw(Bh8|6UNCZY`$_lVC}T?Onj7 zW+N!rSXkZ)csy7)XW3k)d#i`|qB$Jft>>#k=zl6`*->g7dE39Px;gi~HmJ_{QP-2T z^~`@*-aYqV#Lg1m-mvW-+ve9@Q{2??$c!5OBKiB6zx2v%kK1vx#0kr1KR?tT&-5Lv zhLcFgy_^O#$j=)nTjH=yVVBJ*YWx-!X~vqGWj-1k zgoJQ72I{?Sj^D_|b;BA=i?`0{&AoU!GoZ(n#%u4VwtV#)DZZs^yLD!}sNtTeyAyd^{9H}9 z#7Bu90aG?@DKChm);+aDFixoQ@?=d8%H`RHv9NZ=<(*X4p9Pz{sSygTV!R)h) zLdbe+=~MzUiE@3gc=tlBn30hI_(D)n5HaE47L=8jw+53@5x0KRygXcUzBTJF+~3LZ z5s1j=FIv<{r}{-Y-zDxEmH1y>7=S&p(_#BiXML&#yO=58JgrQ-)G+=vvJM%E7!7K| z0QKQs!G-_>wxnS|iypmrP71a6)`;-z*in+3dmh@#gNGuO17E?HE%NwF`Pfbka~eBq zZla&Qg{r|3Z*gT>^jxFbVse(UTF7w(OPASX5$V_Qs*#)PGrGoOt;|a_USv0bd1xC( z8|sv@>Mrp`1qDOdfk0;&6(vk)nv#sFpFZ8Fy1>Q5<5_RCRJjGSD@pMGX*3#!3X!hU@4^kTR`6>rTS6=`?-(8#4`K`s z<3>Nxd8F522do(wARKDXoeTPSeT}H`V{h+WXI|a{=R=jUZ1Lha#5zFXULaHKCrh=z z86thWM^#0I)({dK`)SfvtKdmRMFj?Q0R6Hz^)@oC9xdL%U{k2-X@eVd4xE8c*im`yeRGbw%;ks?fg5cC>Va5Sy-sb zv;y0y^;oK^s%lgjPSSKuM5v7!qSL{KmEnk`fQq{|0+e42*AW7uWx+1OK8eW|FblX! zZBcx3F07`%wLnK(d*O}y0U?@T;Vfq)!E2!-h=y04L7WIbE(ZqYG7aJt2_7E)14%Fs9=rpWIJ5aeEg$mR>gsGk z1u`$e5L7qC36oqvmzdUau38n^5rvmPee#uGh%tPKNQW1gJ~U%rt`zGwE~Q{F;2tPI zA(D|hub!Ngxv!kVuxB20Cs;QabO=jHjl&qG>@wH`*c(K4J?+K>r{L2^0p7=RjjY7= z#|=cqHZk;){eVWUl`!AjhX(1JMwQU(ImxVg9h;bAt#w|@QZ z$!m=mClP%+cS{KDgQbk(Gk4v@3lD*-V~=lz_oDmD+}wgiN`5l@0%(t-@Nf;QECTgC zOq&cp^!9Go>Hqv0rL&S=5hU^vCnC5RYj$0Z4WV-@`SO`y9R|5NJyEiU@D?m75yOg4 zBO^_)Q|7)@5rLt(yUgR-r(h7}6Q8g&T&ok9*AGe;c`QH_O_~NOT)lb~WuR)pz197o z1t@xpm%7jLoNHu2Ui}lV=8qnxgiC3tA9iyX3V2vtv7YyBTl@R2Hg$CC)~(`Z@2-?m zx!tc}qy#p)$d==`pX3D)FflQB%Z(wxlhr1qi3%((%HOb?82NN}8;`0ti0f}-EnlZ4 zdnY_I*zeFTV#@CF<;yT<@l-ELRM58&`YYBC2UxkoUn=w+n?%U6`UO{ryY-*I*>P|K z2fva|XW@ASA4vF=)SS+(xTKGl&FZ~ritUVn^D=a|Ja7su?|7@bG|nY3P&7F3J4hxbkrPlsg1^qlZ5t2f5GWc`YUHnKMTSOrAT@h z{lhI_@)-J8{EZe`LK!ZA_W<5_uy9Nhr|`iD_)6VVDGv+#QeAFWloOB zg_7q*MN!y+{OtN~n{UStv}k(++4*Ptkp{ZmsCiOPsB$2(XzcCmU?v$}#fKp$v8EzM zSC*Um)i5jWDYF#PlaP^-0X4I1N~DnE0@xw_R9K)r;!-#+R37(uk>+YHiKIL0eDwWs zx?aR)rLuA(504@Kpr-9*aQ?`=Gor$7*%&V9UEuk(T=^adOxPGR6q&EhUTV#PpDJ&n zqQ6SwQu{F&K&GdUFA&H$HCP5SdTD8C*|GLb*>2<>XjpN%BiQ4Oue6u1@5y7wnB)?_ zw{PEqTMD`%sCY%G!my!{kg$1qYcUuq@%_j|iWd|S0Y^a$o`6*!T3horAb2d89UB}* z*P^Cd`SqNhtTQepo*ux#sPAQsD%mtuv^;j-OU!QKim)q{cTcAA8o z?%3TaWskdw8-P7s^y}5J5>Yq*LW6>dVvr`rJylT@GLhXUPUSb&)#hLZ4!&$3VAQ;M zyzUlC0XU;4i6sPrj<=)20*_O&nlk)TmW`Rg^DDnV@1j+#)q@tceAi!2WK5S8m zV=KHg+aCG&*nfDvSaX$-{t@`I={0|^P+Z6|&s>~c%(VrVkx%RyVU{3AoD76m73MvG z9nUVEWMj{mn3%z)Z&!GZ3i6iY2vMW*TQjU|6pkLPsy#dc?^YCT$0HjB$*Wr3!JiQL zSp4F9lp;0>csl4GNl*?uHm!goOgZo%_{gXOE75kqfJrj}EEwB`1d^b=O1T%T+(D@WRg0c@<+j{og3%>f;Q9mWMMj4~XDr{HVw%ry(3B~M+ zY_I;@6g5iX_9DLm`e?omwJl1%iJ7mKgvhSffWXbyH=6qnPpPA!@Od zi#AYI@2tD)G+S6QO>GjC85Dz$zBfVe4l*&qnx0f_C}bL} znB5L*T}O&K02P4E@UEA?WLt>EQ8zIV%@KEOp5l)!M*@fd3qx-jz{j^)JM9B1OT3C7 z@GtYp%Hd}$V+O#Wartre)lXFe4l7(jKb)M@gpw^h*CShjK=q2C9|+%(q)i}bbfHf4^(T$ zV#{MJYZf~*r6^+6e*~pGXHw+Sz9vE8zO%INr`DYRDI^VlwL4FPK^saamSKksH}H@% z+Pw>1FqPPO@%>A*WgGT6Lh+c>os1!4=Z@Lu)bT#8(O+aRI$TFkWkGAGO$G}r-U08s zD_J0tf>I_%xK$b~!2T=0%>G#DS&lv_b!%hF#Xzklyophg9`~@^@g+0NjC*b`MinF~o89-7zMPfS_*+F~-F~O2y$-ja<7G9(G zIHa{~!&iWDjh7uY!TJPRmjE$(w}!#GRy@{Wa?G)J?##xpI{V*NdwWv#Q?SveZas6PibUM;BDtG=mK@%Zm&!psgca+Dr*eV-ZgSUaK@ zgSFC?tgLC>=`j+62vmnf4pq*!65TB>gW7a3I^=F81;|mtbOGGQc+|+H!+W=?mZ>$^u zuO$?_*ty|suFm8b+rLl{5vm$EmF6y58yY2d_%Iq~FY${{gB90~72GC^TiRWPW0zPq z>4|$-d;iKxoJd|+hZ8SIZfTPDqet(1drfmpX5jfKDH8Gg4#RvOb6)Fzee5I|z67p1 zsQcl^!vw*LOUeWZ86VtBjM`}B)sSxORY}2VBr&K9!DjDn=52Lb`W-$lVaEyTZgiT! zSqK{HFSF-*OIpfDS(}@u^b*O{6<~{ zlUj-u;V-;w`SNwL4!e*5>F@8K(cm;;YdzNuCf|SjQR2U6_Pn$qw!f{@SZiyG>OuGQ z>Lb6|8y61mePULDLep*g@9DgzMdiU;B(jUv0Go4aXemyYnYkTu9 zem-U-Bx7o|`}2nS$#i<7{fLgDaS{xqgoP8a*6?0HZ;(j;ZsiB07}0_AjDG5j^y}52 zg2o!dK`wrw#J^~+mza_4AGbZOT=|uqsEwJ??^i0q^i0dj0YKAWDE&WfHhuAp@`n%q z_SZaj0^(B}JxUn{mxssckm=f?2M`7OEKJ*jV7cOtJZZOu07Q~5s>ZjiZ) z+Qt9erO8)q%_1hw%p4iKxAUOX&f+E91hR8Eh!0VZR|nf>2-t`zGA5C%bY@1+B^0Y5y1Ze^4vy)9iheiCjNSZ~L{u90yRBb=TljrTI3t8Jz^#$z zA(E16!Wwy;ITPq@XFPV~UcRc;ZWxqtn`aN-@@V=OIdkcK-{}&K>li~VN}g@z)`4-x z6_h8X>rvmL#KG;H8l&_D10^xj6^*wuM|a2^++Ij+XI5VYKyp zfjm_jV={GJ`_#z6Dxu;*H)%GGiT!c>O5XJw*m?{)(v-QS;*_a1{rm?!0{)t{mN>u| zs?L(xv;ZGM)Ig;vH&?+{PBUDkD@xGLZe-E`qrZMLi-@W6V$CXcBWKyROCQWhrarTt9>=C1P0zsN8 z(B&u{bWbE&isY*3j7y^rYLhh+4wgARcraJL^6j-7<%o)_inKpul{t7lwRTJ(bJrAx z!IKk)`4RCwoYnmyM^KU!4Xc4>oe;nU88q;hdw)R{; zgG&rNBuljDpYEzEvK_qqsiNaU+}Xg{vnGxgs73Ad_K6toUH33WI{GY;Tje7~KVf|t zxf6R&)+Sg_PR-`LaYLkh&^>ak5O-~Uay4~XqH#@-LAfJ_j50Lii0<4nA6?7}XuYYq z!S=_FJ;$`VBqZ`tE9Mt`cGj;(7uZ^H=PF!R@L;>)C~7}gdh@9MX8QpX$J1hH2HU#2 z26B^jX}%E&A&&HFxLdX)F^7(m0Dy(y}0wtSjq?d`RD$7(WcT7rB&NO$=@W`JPc9lh3x>R&JnBjOh1?`u(;M&HTc}je;o<4_w92?PgV?`4 znq73EX-)iXnz4emeo({;hL}PJdu!I4b0Nt6JVI|s>zQp}H&(d4i)Qrc-IjBc{(B|^ zpK^3HGFqR6TfKd zt(Aq9oZJ-^6CHwyev}SJD z;Sv^!VU4t@(O>k_Crg_eT{dNoR&BPnrh~xZE;5ge>w>i(gGe~_B%o0+-6i{wsKWRV z`-3&5bN3Zklq|@a`gpECdinH(dURS{gq+J*EgRn&jTT{9bJ9#$2@$Hg)W? zd6FnJ_32@eAPIp?jn!%LNQ1KFwRb!lPo{E8p8o4DhEShBnTd7EX=o%MiMPzG$jR%*ix(quBj-~6Kb0?9 z_g8PKB5}%py1L2R)y*JxDdub~-P$J_T=Xtqu(`K()LU4_^I=eG#!b#%J|pP5o9@^g zkc8%OQK)776WRfZR+=RvXoD?aAb~(wiI_w8%%Uj&+AnrcYlDh z6m{usPK?;5*fl*RL_2KHzcq%CGB)ug{4Y1@fMx zzWj{>+tnL8>U%$p$I9j&a%!Rv=6i)Md8q;p{`>bXai;(Lk@FeBhh_qz2j^ya1D|4f zm-05CF~0cLj}R4dZy|pt$gU*Do%> z9)6)9Lj3P01;=?DCO+pPF>{Ngq$EFoPj7n^407O}^;fq7AeyyerfWHE?glTs97XgsqPlnyUS4i)CzQ8X$;;0t z*0QjyRsX4%H(Ll;zY1Ro`2BTKmre-<8rA-`$rfi>wFM+H-W-9cJ?8I@ZYFbXe%Tdd zS=qhAq^3l&>N?K>iQc2!Rn8(9V1xB-miLHDk9XTW!_(uZpz8&3A?X>0>ed&DixT!@ ziPGL>Ko(iq*hc#M4M7Y@PfyRdTQDB=5WWRy9FfjVnb7U^5~CYczp1IQfea!f=HRz6 zg4WS3!vN}53Y;t)TJ;lF*M1*8-n(ozS)fVEj*JQ>?p+v^h={l;2>vwTC|Qh9 zwQvBoM3hz%ZMb`zQfsI1=FKk~8W?D?5SQmB0+>SqT!NUB44wk$NxK`;>3sERmI~YV zY(bvaAAiJRn%uMR`E@p#luI2dNxR5sq4f*m<)AeUnuOq4V6us#^I`At?YH%UCyG3D z01BT&t6G~ARq9wQGahN&4vs<==J+;iR<5i@51SfJ#ac8RVTn^`|5Q)w1*#B<|xe%R9!O^Iu{q^lGJ7*H`1d^$a4!FLTL_}px|5sTNE537{*`dS(A#Ca)#{)mTLZ9 zB+Vic7%tR&xgc}w-~V`Bpi|Mp<-V83E5cNBPW~=zR8{z>@rk5mcyN^Q?FiLp#L*{{ zu18#rgzTL$1tX^`+K;}PZAFzm|BC8ZlxR#%3={)TDzKcwdYqc{|1eYfd4@QY*4iBs8 z?xe&KXL5jy%6@q_yT%4daiwCZ=bACXhea816L4tiCy%>)6+nY((!n3l#FL{ z>*(kJvg@c*>1d!ph&!_5si_>BpJ2Z|IU?Ma6?(#>N8O)-TcOqT%#ia3??is}{Y!GfFH#?+%zsbv z6r&2Mm1>>mF$x5V(`g!JE*VTH3JK@q60l(P9>?EKM*g4#fNPfr!PD`1pzWM%1wMo2 zR(QYkm459Mb};@eQO$}fwc2L|=kN2oAV+1z{K%@2IX|*3pZ1Y>`znPrUtZ=rs9I&* zm{HShtL+Fkz-T`Ofsheygn?)02a$-w48@FKIY#^N-Ue`d`~!qZtaJyqZg;KSh$(AZq$}MCG3-2b;9Iv@}Fl@0t`6$=I8|%=UAPvq=GEKa{_N}*SPS+ zM&EcL^Zv*Dhvb~O5-*g#@1ZwUX&JW0s+j8i-Uf^`*@RN5amVy>po;8h3j}Y}CguIAUPzdzIVigqqwjCIHmSfx0^TR-+bFWTx8n(Hu>KX3ZR}vTg_S-Qp zqm}d!_BCl&Fcd-Dih@bJb>GPjL%ix8h4N6-V?XU5926dlf8=&DY%Z8NWv8%?j7-md zF}fHsvj^qmw1SybHRR6Uyvp=K?Yx9N29J{odT@kegNuoit4oIrYn^V!< z1Em~Zhn?{1{+np%!UnnCAxbHCIDiUwl;@f` z^<1>G#pcF1aqhJd?{!4FEvPOrSA@W9k zfl-0Yz{fnAf&S$o(=-!AYt!i?@Jof}_wv}Ff#ter%SyB29LJgUTR1oPbZw)1w3hnO zkn!U^WG1YV2f6NaM!sOYj!VnqTK#kFaFiMa$b?@&C++z5bw*W@ z+tf2a$W-HPH7|vhbN%{L6`{(GGzG6c^?#(=x$*YEi{)s#8SDJ{j}~;`c~(SGMgnef zsHk_xM)2+N1rZLGv_Xx)f9wz|s(DVnTvP7wq6KQw>EDSoy zppmaens;&qZ&VRBK`4r${p{)LG742Fv^o;~oa9zf&0i|XPFBQ5INEL(Wgfu7Tld|o ztt&f`-3zXqR{HH%Wiltmzm5yd)k5n^3f%*j|wtVayBu}^OdTSbg%>4 zizVP+J&;`o+N|5+yp8}c`9uQkz&3j#M%}*8#U;05L+vVcupuvf0gE|Q=?PFm3H~;RR5v)2iZKh~AkHTClP8O1mwWRQ(vj**-tO(Cl|Cy;uNvFo$Y6c* z93$})$-%68d!kPXH2B&bkG3Q^PLu8K4qZj=C*{0I^3yt%xVk4+2fGaAvUk>(B(jC< zAv8M@oOJk;U20{L#%~9)W9;NuRM-m+Z~V39XnDyY+9dYoZObl zE<~FAn$Mx|wfr%Nfy!iOSk&K}vonT>F#L(LbY*rI|M)$RxaYH$&E%P}{7l~B`~OCM zBK}7by8dAWh4K^MddlxDCD_q+f>r;9_Kp$53O)`0h%+Al0Honk^kU1|hP~f0X*C&! z-YjaH2PJ*hmR|-uG`)WnBIf?5VL`T3DP?j@TJZdvdx8YaY~CLgCEi{A1O_hJ$%5V= zuxG3oBZ&#%=QVOrGbE7De!if@jGTcnHRI%?Xpc%Cd2n)axOm|DTxr|Rifzn3n1%R? z(GR+}bnuUkjL6RSwKYBFS)WbLZ9`v8JxGP>5P){hSG6{QbB4B{yssv^o;In6B48SdIpvk z?R=THuD`@r<|}4jI8^0RDC~^OBmVRC@v$+68b+S!Xou%z7e$Rh4Wvm|_K{3N9M37a zbyY=_1MVk55AnWK*xiDW@$Gx}__l5(u@@ee@6$t;L#31jD~?)QT52W?uS<2;9ebf| zGPzQhgBa_`bZ`)9B`SfZ1K9Hd(8yK3i3 z(3PHKV);Lye7>-iyg5DQu!can?(!3e?Qv@*;mpA{b&)?tEox1lfM;M& z(CO@V@KFlQO@66|TclR=ZwBlHDduX?*GQ&y<@yOms9QVTp&3s}l~)9w&8?D=ISE|U zwD$9K{bdo0j~7%KLlXnD3p=Bnr-pr9T*|$uiqM>nk9rvQ^hPb`J*zO8eh0tEUD5S# zaMky%Ax==gt4VdydXv_=s++=iPjcT z@^y3+T_+`~RcH6%bz9J9s2)vDSq?e^30>laf98$L&2GdU5{Tu zc3p}Th7yY2Xu<6&&L(?e>?UXNs_0aki1qDkR90Tf^d_TdFY4W2 zbSh}!O^p)DbFOdd^uelzD$4R1aMSqOk8_5c`hL?j=NA1jvmZ2YVYEAQmUyg6oArlB zSNyCMM9T||9xeX;=n=bF#!`le{aDId8=?G(og+het#Op0RY1gWw4K=1icITa?e6|n z5Si;Zxr!-s-3o?`N>(oV{CAaB_WTNpq{Md{l7A8&2&T;?`M&%enf<0DXO`yLa3NW> zEt_;9F_U8fSK_C@&YiAJ75z%cEwLTWMSa{j8^h<-_cPCS)FiY;&TmCRocA2sjqkF~ zjC~w79~O`9-!lE^_RuXN|MnK&%d;4k&PQK`F^_F*7Q0(#L%m005HP5F%L}^A6Nrsi zSnkU;W!kqc^_fsuR<(&o9bbSY1Tnx+JxQNpIp+D1L_cRnD&JzGV*$kNW4Jwj{QBAUhP}k!PDg6na+-oOtsu^!(D$>-f`j>Hw}O|n|J%7Zxxruj zeg2H1mdQ5ys%;~;S{6nQ*VbbT23NER(eARr1>u{Do;i-%p0`Q>X9KyCh@Y0y*C@c8 zZ_vy?M2p|))wn-7U6^UHu%Nankl6%x3G#>}|AKs)|MCuV0F%38%if1mQDbgzVo8(%fHz}47vo^wU^zV zA$DQuwmzU4A>FEfyBo2f!H;G4`EF#0HBJHT{XiY_ndYzTsizDN|MJ_nR|uRLGazU) zy9eprb~H>N7OnWh2Mf1Hr_eV`Y&{UCpzL@ZhQVG8E()Q+ZK4%%%)W-M-m8W!`U%+P| z7r@{Zhe3A+IXZAlZ&Yb294pYB+E}oZ`^Yf?y>sUVyKBm!bg5mqPV%^m8d}Ij0J%SX zN|~M-*QIp?zj9*FefcufL(;Nyvl4V&0tKK*lTd#jW8`Gbz6%#ZBRwSv%W$OXuHCqG zYx|9rCrfH$G~)JJ!Pbk=+%(UyJj4lTIdF2`n2e`?-so@y7J{hA$CnBrrNX^LP3*XC zM}5EstnYFf$LiGvp>#f0wH`B|BW1iWn?$#&onp3!aW0H4WVYCmSC{zo>)4+rD;_@l zK<2O)+1C=Cm2|4ECP-l;U~oo_gF0CStnwkp|OA~UA$YB1#XU2JHWJ-q5l3yV5BJ6?~pRfK6mfcnJ|Wd(=KUg+o4Vb zeDV}Pl7yE!0`~wcd1|n1h^NNt$kS?uZ9u?16ocB`)#jI$mc|oMDe7m01AT*7)ye9D z?VN%bHuGbe0!3PM(@D%MfY};jL&9wZ<{TfH={FAB$?&w-@%(KTapxb_l*dONo4(;r zj9$P0lj%*cDkJy-uSMz^^)3&73bzry*Ui^AlQv|i37UeB)i`{VW1i3{(L^PG2Y=Eo zJeO>C6Bu^7DGC{9Au1*CBn&a7$Ga2y%P>ekBBl-TX4;M1V$cg&swtps|v4YpP-#2rNqOx)4<^ z(L19T>j)Jsv2)|by*{hJkjs1hIySK%1n~YuV9Y>}8W7CHM|^rQFGMOa?pka0O*Ywy zV^y}cw#0Z3-96L$!U5`XTbY%%D?Fw73x2hvuQ8pmKO<>RsCNo7QwmfI3fzbU{i4LX zHbXhQCc~x&%*&OD6)4AY}M>Y4SunvX9si>A};h`H<`!lQn(m;MC!1Ah1;a-o7go7qwh*2<1S~K=pY$$Ntr-BS(n>Tpe{S{A1vyBKMscve z3~!|1J$T+xg$zA8YK^%}-Q^W-<@S{RqZcD3DtacUVWvYXTxvVNlSl_$zKXZ4oy#U4 zPx=(j*dwQ|x4w8$S@-C1`qS4#siHdc_kF~4dSn(bTH;IdJex3>A-NB_k4X}5v9ZE1 zT(1=|rZF8XJsdj&hr#Yv*X7{j;QN-%UvW;Z0Q^eQKL;5 zi0YjNV2zhHP(rSY)HZ{Wu2+M6D;j6vqWa@hgAI>ObX6F7w%lrSjog8l%iAKmo|m`D zVcf)~v#pI#$9aj3=uNkSapbAdp*`yoK^M+xWN=aE84Nt1&9P+!@_Ts1g<44bQ zOkFrmTg&^;5wpDP>dr$YUt)NqzKvaHxg3+yA zI{_dU6xT;XPV9u3DTagCWb`!0Z%g(FP7M^x!W8xX-Me)RTWe7I&$R+MeI^&2%VAq+ zrnPkwqcYXvye0|p^ML^$G3vHZ4E<%OWFhKt*os*)N!vN zq}pv6=u}2=pBvG$155tZ(_S`}&X+0#Cm(Bl>{-XNaTS?CUzf_KyWWCFYKn0u(=T;w zbQ&M&qgn+U5~KZkBHJFH629T?=(L=qS{2>p-6a9n zYtI4JN9d=vh?GiY$}r3>yos^@dfEsd$Y77d>9ronbRTRP;zdiqv`jW1>wa zKdaj9+gNL%9#FvEy>q8RL4W*|!8^xwLTm2^4~HNtL1|93!^UHZ+#=9I@lNjax*hz& zFawLa^Ms{rMY)nJ|M^=rZnfOV@NzW|bblkv&Z`k^|KK{$p)k{NEe0(~StdRNlUegy zfM7AHIc!Ua)m)aL%&!_V&{VU?Ba1+i4gJm3i`lny9H%ZXSgC7w5$6Doo5qsGq)=)v zj2qKTbup-{G0B=5>%wf;GrBl0FO@bF9=r)4xw1W@3sjCY$YI=ATYCa%XQaxw_H9t< zK9w|XDl^_KB;nn`Ei-e4?yt@$*s{k-FD-wuhP4^vOyG>2V!y&$e=%41DT$#y^4p$8 zhaEg_H&7(zA)uS-GEhT{Z58v_!M*X4w}{l)4KcY!&b1)5Ofb#8xrf1Q+;;2gIr z=03~TzB~Hyk${Wr8aEDn$>Jl15#M{GGNrE`4mDEpR80SSc$DxIg;5?tdW1C`2pOn? zynO8m8ym>rVfa;p;YiP{*x3~xhEBb8*W~wsGm9#TV3GFcWav>zp$S(xh2_}o7odR8 z6woNgujNP5VL05XBMCt6I?J)u&_=f@!Ht9b0&;PN7Sg&HBaJTB9oT}Dl*yT^!sd`Y^Ne@TR}+f*8w*Lrf&hqzwywRo-Rsn;Zl-7@SAo%+zwDok z-eA9lLxJ?}o(zwRj9JTx$Uh&-41d`~%_)4h)1d4(pDll^uHo9UWgfGGpe+cULt9Wn z(XL?HiY;2vacz!}>0}=l$1ad``}+$7>TiP(`?c5cr>|Oc;vn^+a_-QUWAN`8T;V+5 z_O<7yan6+|9Y$|}X+UX9lvVG1}Gbl!UV63VWHKwB!LwXMb3R-!2) z%|~z_-ELAdN4X&t-mzoH`t|P+)h%jji5MptwEGV@W}X2fC(yhrD*Y5J*qCjFf4@b) zXe)gh2NuW_NGC5JR)hmURgj#^=s=t5x|uGOcK1+lHKo<$r|&9wLHV_}52k0E-Kd4qB;n$fSi*9)>1W>E%H<#S!s2jsgTKm`3vSkiqfEp&-`HRfl zXd$>&Xq5C;l2#&j=dbR7_5ngGMn(n(#-gV6TaCs>`eZFW7Vfz|7YSA~Uel34-w_9pemhLZ4eL`*qK5$CcH~QoG&pv8 z2CdySXT#O4Cp+3ej_md(oLem#JPTb_7OMHtBK9|_Bu?THU>70EnG5mQ-E=XPK!GjE zhL!o3j*bvh1Ads%fJ9VQdkKatsLnvMeXAiRMxSO(+Gjt1{v1Uey0TTKQs5=QgE`6D z*LQng4Mr-#!NDd7gNJ)=g3}@zG66LOrila3Afejcd1c0v$EQ8&s822As<9JC@{VhU|7SaXNId?#5&}LL^@Q`N+_x! z3oR@y(fE>PU8h^p;}K(Y6X6ch7mg9=L_vUNeEt~p>Co4vZ8$p`SSkhmS`h@zd5Tj<|^UO|~44IjI8>HcD6a!lAO8wToEU z!Y%tWYDGtlS1gsPi7nPw&)*~{sGSzxFpR)sSrGiA*oO008qA(M*grJ%FxN$Cc(gyF zi7HBGhLeGKezyAvH{Ntinzrxx1rCXWRVcxzsJYq0NYSgP0RCv3 zl5E=0+1$L-q*hqLno639gt9qGVFlkweCTrwW~VDHzb?tas^Ef~d-r+CjJ5B>Lj#3# zpQlgVfat=*aymmXO~tuyyyE#UYW5PN(mH90eN{cb6itasssA6w{yU!P|NkGy8_)Jo z5iMy^5>lkh2Fc1Ena^k;PBJ^jqit2n9-)k^(4b>$kfM^4QN~gB2$4O%*TEwm(+$CUIGkRr12>%xfZq=z~rT@{G3#x6;=`T*%N3ZUx6*n9ml#O|}!;bM?=j+5C(~w(HkLB+9QI7SH73M8b&81i)WIOG4pa%*zbK9BRD016JBU4@<-{C zi)wxI;Tt>4^(%=KW85L5hYlVjyIY)!NS()?s_6?5GW&_i0UGHFgw*colqlR#mc!>w z5Paq`BC{%OID!Zdm2!y=40Nk_U{SdgIq}8;rY2jFsHS85Wzph3N@cSDK-z(RWF&7# zG@%~JHE{hfX;I!6@XQj4gHP`I6Jh3U_o`fU!I;S}-ROOji~q?Jbuq}7r0m+y9lLdF z{l^@qtsPgC5$-4UY87o_V$uT$4l%x1}^rE1sdCUc4l{)X|5sNH3O5P2tAX_ z(Gr8wapq?hh!9gyr(@S=Dq>iTEsnI1o7ACiZcT>GokS-mD{Dhn7XtxGQF}nfLO$`M zSTIi*@c;me%FENxf*KR!Y34i6H@?9IV&R5vxCDji$p|{VvQl*4zAtCoK)mQ9c^0US zT!Kahq|^|zpBse3Wc5+;v>jbHzkVGZ8@CWWyXtHlEp?9Zd_7ExMizKotf`B|MG@~ z^9?lF4(wJfO;y);H76^eTI-=^8U3<>YKry)v*eS>e{Bo0B~qGwRzzN26!O62Ql!b5 zbS;G^&XZdsoLWRDzpT1*^7@55yW zJ`d1JY-wrc9O)zmxfrfasTmnxRHV5ytG89kTUqfJ+%P=Km#!@e2Om+&H_x5ZX*@V#Gy0K{wpR*5^1=HN&&t-apjO3;*cySMAmm zQ{m5gxmK7xi{75=XLleB?<~?TIzL|#q9m8mwlf<>_m9kfAaqsJml3HN zu1RT|7!g^Y6GQ1Xo2rW6%;DpEmq$s_B)iYy|ACKg0{|9z0ZJ&FEAv5vE5 z#D$82SbCGgHu5iAmB26|pGw*jdTZ+$8yg!8Q9$$s8ZeIlRH#c=?R-8UggA>#*KskA z2Iu5Ns@D?#o2#Fwj9mP?LieY~hkB z-m?ThWf|2g31;Q%p5NN}XGm@o6|F2RjHT4&BKZUIFceJ)HGo=;yj+eRW%s{$@#2#w zyJpR?Qzv_lG70nkiWcLsL|2zY`~u~%ibhVB$R{Dx3=H(#P37&>1dNB*2cEb`Rdl!^ zM`>F--CQ)QX7B5Pv7e|HNdp|&_6@U-c-AAlV>z7K_*~5h#z>2_9A+k#-4IuJdE?Z+yVRu+EdLMUD72D2T2>e9tU-n3UO}cwc_93T1%S;pk9`UX zdaLd-@ZIC+(f69(yPO8L?0!nUCi+xnw280IOUpUOf?ol;B!Y1{^B#@d?y?vbjzAiu zgE(~6EbqsJZylXVOn?NSa`N6%DM!~y zyXuY(gnQ=lN@Ry>N}spQ8Y+5f-tXM@t*E5g(=GTIuR6_jJUp;#lk<50Mt;4$HCe>r zvdSc5V%x}A&)2(nrLO5WHp|y%STBnF#In`Z|B*o%j;|u8iGfj;?(E$!Ucc7Mbb5Tj zW)#y{O@rThMwwx1byTCVK2oe={u{HPW0*PH-LJdLexM zc6%I+N7>V_y}CZoL*-;T+l^>*3??ntx2Sl{Yd_TWRl77D>BMT2mG!~rbGQv(^=rL6 zkCBVPyNSZ${)(*b35^66t_dI9jXyg?Oq7H=sr^cetkxAUBYsH;XlBOF*Z#emaEQh% zeIwO2`?A?$YRB=O3pzTnU%xKJdfew9R+aIT=&1M*`8cGnBFbl-&@DH)#9F64?osZW zjdFX(u>nk;Pu<-G81$&rRV%&uHDUa8PZxI4d;LPp)@{-+aOkMu-PYP&@1gM^TOd3} zp5pJ6LkdvZu(SXX@MFkfM4C+U*~Z=US%pszQJIq9j@yKJjdCpA5dI@g?5K zsB5xXJkoNYjiQ-#b1lcWZe#hJ7~6Dgl-jI$p36_{3Qi&{$@`SczwzqzxgG(?B`OJ( zE-xxV#AfG*+V9#)cV)P2Y@UWoUTM<#+hYRf{_@V_#|;Y}oyP~UwN=OpHBZdezs;nC z%Q$liDth+|=<<5(e)i~5n#64v+(4h^A4<@sw5czooT?q^m$}*IpEY>YSa5IT=U&C* z%~6EUI<*Xk$s0q7WsajCcrO?lO*q^3R7QHn0%S_GtV%a|f@^bWUhI9^4K<3^(pP|? zW~g?MmDs)J_*6!MX;X7jLqGsKmy1NGs-_;L?N(1Kzss}%Z51!edWjA5nIeQf?Jz-9 z0T(96<07lKE&!}XHhXY_?Kd>-ZA7j8Hh(60tYJLjR8$Qf@x>SCz6+^K^7Frc`LZ6E z`qerA`iY%8r+(ub_A!Q;wzwty#>nU(u&&%IPA_iRtzSHwc}w5i8QsdSc3yx}wTc%0 zvZB|nS8_?t$s5?1(!`$|bY*u26voZX&49n_vK&&%K4Y*Fiaez4>@lN91I-5WT7Rv% zu@Un0L|BE6xFj3ph(YFEUATCSa4X_{)Sb?q`+-=yh}g#pXYyNNPe~1q|JR#G1s@w)hKZ6(7o;FXWLanWZ;Me)^p@0gTcV%2@AmFa0!8s(KVnk0NSVIO=O}N zKnhXhAshjDc?6X62qneDc3Fs|?>&5|G!_qiIw{BBTOXkgSY$Zp!Gj0W;1kGW_|arc zfszAXTeWBRZj6{yO|40{K9rpdX+5D-53D_Y_7fIVL2Eo1V$`#4+f<^ZYijg7y_HZn ztJ)rhM6a@!EhfsgbInedkrl_5{Ey2+EBFR-ZyULzLDdD>5?Ib)4E0=>+-%qk?2l zg63171WKkP@eX@2nFg>C&uB|Kk~sqc0@SnU?>%N=?iz4VUw{tA?H9k#ZrdDmIFgoW z+ruSd{x^4DfS00Io$KTQw4okR?&{hTzEuN;@g4bp-8#v`XZNXTTS%X_zh7)H5hSqu z6Wg+Xe_va)=@3g`$sm8slWIYamREPdBf}}IK91(pua7Ky;_jmAF)t}9TEW7~%9_@} zKO9tFkca~-FwjdH#)RAX2t`+)H+7fH%~{DQ`MRd&9R@7CiYkAt%%w0`v1HXpqPXJO z{cTs~UNg=LzpqWP>s+%z>Y{SEgn}03eXuz9&W|dKt8;T&XilODk_wX(_aj5&uDUsd zN;*Y4H@dq|&|hU2o8?fi>FNe$rKf(rldWJjtIdtIptPk>`BN@?dGNOOq>edq`Nq;g zKcAHeMEGcWd$`!NmxhHJAav;>TNRuHaC^q%{f2T85)(+}_(h6uPyE$=I={ zJe~!ZVCo@c=MhwOF)qxzb&u=V&f!vH!sQKYsN{;iq(;{C^UkaB@ku)VxaYVW&WNMC zHfMGuA-7A7tZm9BhFc=M+@P@bVXT-;KGF%ZVWljyypkefpt$$AU*FImZxALO@#T-c zqg-FQWqn_d*(X}JP2nzIg7@7H-uFF&l*(t89oT!~J~|!>`!70}ec{&1N$c|+oX65N z`fhj0x(`Rx>G~)mSbeqcO47FOO+VzlK1|CyvNg!Wgr~Y{kF&0`QJG-#_rSL&+~`Do z!EzUu>g(6+-izh#-oBmw;>A&|7kI?1T-77}PEsxOnQ0bk;;h5>yBXsAOMAwC8hTD< z-=k^;#)XE2^mWzpn~fG74RgM7c|u@~?78ghn(9<*f)vw*O z(;#Qgy{%ieZuR0&!@yTPJv}hzL$NxU3mzZL(K0aj4v9nfd6Z^AjgUhKoL^7aQwmO* zMGF_MxT*0#X?Yl5nLePVa}Ex9HZ8aM&LJ}p=POuP9&x*H(A}i)N<`(F=+^c7G7X(C z!zr2DcdqHQO~EU22m>|o$EkoY!v<909FrFg^f%{YPkjq>-~r;Bm{WeV%jf*hrEgC> zNvf7w-f#Blwc~{hFNN24wpiDs&nd+^%u~=6XpeoOq2-VfvfIHEbD_6|?!kD0>ryen z?uWcr|1>A?ZmMa6*-qW5RiW&%l3Su1BD@7WN5<04>X-HMJ=IPbrks=UD{JRBge{VV zrTc+PxTlKR+GWZ=-{w(uos*5S8#zn2k+q-ZNz&as$dRF*?fE#;;cL;ln_0??|;N5;n+O+Ws$~mm#7kaEk_n zE#z)M;k}gsK+k$deE6L^-=MQHH_x=H%|sg8?c28zs~B3wRKA%9!p`HFvKGCY$V1w* z0zp=;}-4%fXe6Y`!bz|C73ke5?U;AeS#S&9O zy|GE;0q)@CUG5K>8&_|)N4OJwPXOMu;(N#=SyncaMIGiN3@_Ew%Y-pn%4NiTq5J`6 z4=M)Tj2!}rtgYi;iiZogCEeLP?@0e4Gotg{NYiU>`m6p3!4)hq)hy-h{A$;iy4*LC z)UdGNlc%^i5a$vdi;&SEGj8m4dVA5DVKu+856%2s#V4L*{CuE$>=+{>ls`|`?0wZ< zLxUSZ;n`2?)r8;6tfRiXiX?SL?o{Y7hf`U?o0(daeu%ZWoEO*LbA4U~U;4)tg zZ7u~bjs{dNWSi5rO~JM0#VfA0BIX;yMW}s$$2a|hOc8@;m&tMLzLR{(Cvbe;vxj<; z(xTlTDS4AW2CAc=-*6onzDFm2V=>#F2#%Mpvc7!QEvDo=B$vvn*3*>9?`WrS^6BU0 z`YZ8hc-|10`qj-A;)L<@Yu<~Y>&IoCM8?l=B7gO>{FFE}LoXCAEH95CYgA&YNZs%m zR7X@))RilTpf%7>JtG9A1iy7+enl@`_V9-fw=g1|K1T*yIVZbjk~T-C`unH4xbY^L zHi3ijTP%%v#RLt653LX)(JhCF-{_W#XnEAoP^yRL2;tD89JJFwqDlAElWcC$Zq>oA zOOa|kz63gdr7szJ*0X?Tov^avnb1oKk4IZIyi&<7d2bQLoN z&wlT~+^yk!bz5BD+~yFo{c)iqiGccG3zk&Oo7P=IF+FxSa9f=TF8Th2Rkj6>6=)J* zoN+?s5M^}~BcaCo%i3i87xj_>@krfB#*TMKS~9J#GdAiHvyd2}q;I(!7A9i&PU|=@ z9DX(69+^H7M(QD(DZJUib{&LYf zwTxZMG1=dVtHXCYuVL2Qzy5O6p_=%61qEE(_Wtzu&pNm!l4|I-#0AUt|3X}{-c}tBrg3c$4 z`absCi?kK$LDyTbPnAY#D!?kYB&_4)1k*4!J}z$Cx*?CMm})^x8sBJ5+P-7*%ebu4 z_s~0cWvR{~z?N|D|O{77hzWE#|In+O!ElywG7W zX6DGo_mUG6FWqlvmIf~rpQ0b!lO}SC z*|mEx>T7m~uX@6q{}I!@Dw$x+`Z#alqD6JiKa~+b>{f_qc2?G%+o$@xS*FkbxJ?rR z{rvn;hr{8oZmjgfP;^)xk8;SaxfaR!oLp_g%I(MQRSdi}a%Kf7S0*fMq$rOd8oh5D>HBFheu zxbuCQ`K_Yypqy{*NkvH*S(AS-wIOht2AG!L3YOt)JN9w@ffCGkzG^24pilMmzY?g(|Hs@Efpx@R zb8!U*-r=0Xit(Kv^;bUsUl79=e|_Ag>1Cs3qY07E5*><`RSt=E2u5bI1)!9Ke@EyL z6OTElaPP*}>#w75q#|#Y{7@z;a)?X>V$uraLn6Pz-+fd*Ny!|XASj!{;|K!tRaCBq za0>`@nc9)87uVW(c4uQ=`=*Oc83mHH^7EEIeWAN?G@4~T&qi)lt;<6d9?Tc=QNKKq zmM`91$2>b{%t&zC?r@li;Xh*}+)8SKbCZ8!4gNFl^?M`<h`0il=pu^kg9 zFqeD%sne$`qls3vto=A9r%W8vRCkA2Jf2>JCMD*<1J4Qc#2DT38Jgg|%YiM$J+sE- z5%mTriep-k*Z{$8c<>&}5PA@ftH{$(t{FRZiU=JvF{y`snO(qO$dAg0Jg(QTPr*W? z(zhec;s8aft7f-M`)7rl#8zv&z09lF@~7I=$%|Lqn$+&TQJ*;(Nu&_L9TtWZ7j%?9 z<8OftFdTsu0Qd14z^O0KkBQ}MEGl>R-rxH-684pNSUbVLC$)cL>(?fycG0X{#z*Yb zBA};@OCe1Y&mam7G@{01P&qki9T%ATyxqHZ_tfA-$sVY(pkE@BW5nEr$kmhA@klXH zz$6Zu@}c43{_Z;CPQAb2`*&^f*U3KvU;@}VNmZX=YZw|G)jxI&j(+7ZF)e}KXra83 z_C$1Oz;qk|vV+%IIU!%TTH6;va5vZ%NuO^#vNGI>xPF9FKfY&6@=~{dT`1)C>(jQ& z|41Ij%=BUH&ekNXn0fQ&^{_2ki@0J%9Z@lk1VCm6Z+KJc7{VSRLJx- zN@=tO{1cfjqxJdX~?sUYd<7-AI#n;r<;^l~lbU{QW;f%HR;qE@T+BdaFxQ@ir&u}^axO8T4 zaFAG&!)=FZ+pnHm2X8de8clCxu1Uc{wZVY_DaZ)0USuUPSfOVb-e>uf=Wx<{P{HC6 zjXHX~=K&TXxl+s4-NQp|9XXt6ML%#j&&;s^C1rvdxmuf_u4SiJ0|Q~x?UQ}%KhhS0 zEcgp&-Y;#)Q4CQ=Y{|i@#ZnRy28vOEfq{;D@o*p&0qbR)Wv^^@7a<-BYboQ{j{cwY zFOxG#93BwFa8qE++Epw21A;C(Cps!?6;C8wYgXmwQ+ z2!9ZIRE=`|1R^1SapI3mej%G33z(0te(n6*F7$bSF_#W0;k(92u<~u;B{SA6Ups%>!~vnpNl8hm zx)}_-*TAu=Z6wY(pli-@-|SLxpdg1o-Yu_DP8u}Dr5MIsf;S?ceLx}xRrcb<(eV6O ziNVFop9O3!Zsq6xJYE^}`vAY5j6>CEvV;$c7XsI^S{k(j$I?0}=OMtj7?XVE%9R2e zbfqcJ)Y>CLL;1e&y~vv!r=*!GSheD`0qR@^QSf8iHv0WTZUdM^^!9ryrOs&0vGe-p zbL@cRy?OHnf_HLUQ(c{Lsu#D{0NPiN5lGUv-QqLaO`kA;O#LNdD+355{<9}*ua7rG zX8lndUNMW(F|p&3V^2M%YbjFsu%$H77|2TQ+^JfXn7D$fIJmkZyL#3P(+cK^e?5_A z?vg-_qxCJpZJlV}7qCisgdX-zyYGZeGi*jRz~JcY*=7m3kW$AlTCUuM2}3HR3W|(lDduxQym@M z-5^s&{PgW+vs0%k9-GRwwR*aJOx<6aOUAbxR&1jR2(7lRL8a7#d+$2XZ=Ztd$EI%d zAO)&oafI#NjaJjQ()285TuT?Q?W`LPYim~^VF(iNR8c8jRB1K9<1uhn#BK;?351x4 zyl;2oa#gjIMo0q!C&s?PRRdd+4OZz^!+SDDMhqk`t)wl;g8152{2SEj1dLa)94eXb z9?c!_nKzw>`D?QS44X6e<}IhUv!|nRnPy?)OSRREhF1WfJyDCVb}l&WIyt&g(->UGfiWGETcQFM0BgH#em8RCi7@ zm?Xt~@aaw$n_+8&=-DG%rd9e~K<)q?kr}Zz9srE zOuc88AMJh&`h*T@`RQY!PGCrH4lwlci;k!H-hI=INS ziGFrOQ-`=`|Bas^S<8GML$Ov*X6s2uy#9`fPAM8GpxY`SAHAh@Sle zm-^Z+kSYzlsYnpLHBjP57My#WCNXuPo5%gpi$5ZM_u@mH_RPxrBX>|Mzo$?K|J!pp zed?1i+qK1lBz@1k3CCwo!F(6VcFm1Zzjhbdezo#1jM>v)Vfw1S;p6?3yAl`3?scjP zb>1yE?~!`IAvmWma?PZ>F%r@n4aCmne04Xk{i>jRlwjPO9rKK>R%-awm)cC4P9kGP z(~DO>fdeI&|5jL&?+^gWv8BfWeu3U{W2g%-80&p`WD_cuB$qWdE)h`Os?r&<$MRkL zcTHtZ?WAzQ+(Li<$!Jq2yN;wh`w+s`y7A5Ym@KyG=c>4b>}f9h`w)9g7cH71&0E4%DYqZAcZ&HO~7yra&TQv$UqA3o0e=1YyZ^BZ}=cO#+$C0xLs9CeY-@> zdqTeuV4{bKnVI$IhxmkYeXS>-2N|I|J~*dAS!9Mdco-{6S#x5<$=aSg;>abz>?2&t zNVI%ysoP@4i-;IRYynKm#15c#37RiT%Rz&7DG&a4Eih@d(`C>W8#=` z9SS!~b@6f_>IV;sg#?$|*rw*4vyPyzyL@>f_w0omW9LBeD)fUVfaoLotqQQGwrzS3 z(7MV9-AYUIpPy1C)f*{RzEv#11VFOm^NU8P|CY$E7Tz{i)xX#<;K81YVgj8h7EuA& zo0}(xA^oc>3n13;MZ5#@s@S5196#d=G2RBIX6BXLXUu)$B%iKiFL0`xE&}jiR{s3@ zVs^Z`wzfTJt-iiKI8(RVlR<)*vZ=9jDRU=5=>dKlusO}FA!LMjKLUjiBqQ>f_fx<7 zq)@6KJxV@S=zttXvAv(=H@z#2B^4r^#Yz(~J2lMW0J3|?^L+@fW?ffvU(Wl3SUZ2( zJWr3{vli7qz|E`W1wA$9@#R$T(y7*1Q&CnH?a*x{U#(-`-nf>n&!Ift^JLW*k@cbi zn*cd7Ttd5un)livuOA&3R8Sd9Yt64)?`zX`(Q)q?)uGRiQ_RIY19(05$xTUHAWl)O zmQxelF5B;MD<(+cPA*c=w#GhW007mTH7mQ|X#&NJkl4Fb51i6<7D9eqj_jg&(s}m1 ziOKmVWLhNaTr((>%>$j1F+UYFvIGujgyt_Kc6&|l)Yhb`)2L5At^fIA9v2x1iQ!2K zhkb{dLn-Fx`OzIMVqxL%H+CJ4LCb^c$>H3&BPuGBFqDBBjg|tJN`^ny48aPGo4h$^ zD&JTonnq{Y>dEpM;!T~*V>=p-_{8P&yR&oVk~{_dHSujFqi3+XTRQvahriaYwczXz zsG8l>%<1#?gg(t>lbBNIp4Y|2h8iknpKss3MM!0CYya8s;Fz9X9HVEec3F0Y%l?al zkKdh0`@}%xw1>yr6xpr0pC9Qi{*3u_Dmu;^DmESVO+KaW#Ky0&5LCv=ODh?7<3=Ah zHoYnBj8r>8s8Z8=pJvn_Kc%hE&#&xv#qF7gw8x}^x_a5uTitASJ;rLrSyq?m7h>WK z1MkHvn_LT)okALtVsTgSy?9*shAR^zeljx$Fvb!?bWFbC$aEvO3|! zHw8I0MQiKF7+{6SE17ZBL2<@;xd!ESokW%0NMBn5RWb1RN~G6;DaLZ8PvW#L-dKG2 zA?yz^5j}s%3#*Vuc&DP|x zhwT&+`jXw$5NNc}%OhCgeB(t9=uVqZ80x-c)ShZ zWaT8W;iLZRINJ6>(*Xka>UJ8VxA%O3+q9q|@;0^Mrsza>Ppvb$JGg+IBVTCAkq#BL zwv0AMwzM63sc#AjV$#!f%Shs$>g1Hz`5=x~wlvX2VfMVG&X@(ZJ#5jT=vzr;jw^KB zUa5EBT6Ps<;vg=I@EkLZ&dKojx;#Gq*qPwkR**=mcz9D|rO;-%rK)y+L6EpTZ+i>4 z5vewm`SYr>n@oisPcb734tLGk<7Fwl%5a%iRA^)Nw~pb#BS#7Yjk|cm!(B$!TH8Lp zIx&8z@TS+t^K3Zm+RTJ-&t$Ln4q(j%8n$_j9*s?C}`4#qr8#G?M|3zv>c8cu}B zo_|=JU;5&9@@~-SNYBcOo7m5Q;Hmx!^?XtLA+sLbLiw>zoCZr;Be5A;r|F>A>m;d< z2Es%70_rs<9nTR~@2k@JhTB9boDR0Bfyq17w?lgon7qozb;%F(I?GuGJL?`6%xv4m zt?a_)rLGy#s@uD1O+lmVkCO1}%@flCEc(RB^3>Frh-^VIj#??+h*!yFb|xp@20T0a z#XyN?{9L5t8B0sN1(D(`n3PRE10@SZuSWi{;<4EBV2cFmY`JaiZDg_QLj9GT~-i4mV zyoD!YtA@rWfXMjy9Ju#Pwv|Vn3GvWPa}0=UX=!1>h#*pwNP6V_l0W-Y`d=^K6;oKP zau@;_DaRjQA=|9qk6AW{|MfyMJ1!~|1p$O(P9RT;uwhxcy7wSxRf3Y!?~Q`z1RhTs zeFD9t!fCLgQhIxw4h{|N|GwJb zTti&D@Q1M<1eZ{6Sv=(ki@5z+j5K9!8<6Cei$ABJ$G%NaLCq!7ls8~X)<&P`$<4KV zszPWaDO%Jqex_B<bl| zivbD7q@7l0hzR`^dNzcOqPK}8p8Wk{Rw-sE9VkOPI;m3Ic@=oy(xpoy5AEN7@kIO< zSNQRfkX`utb@Sx?Jq^(NJ+3%J!Im__03QF1O)J`50|(= zJfY+6<&{6L{LUQJ&sqMG^Ygt*+xhKd_b}-j!^`p76pR6`UnJOv*caHOI#2F8cCbFS zeB;G!Y~wr7J+}NICQrjSPj~P6NUpfO{;-@JAK)2apfMBV)rS0l$lE^MIWdmhWgr-% zEyNnBiiD3i0+1^zDgdLF35O&ws-B$m3i<|rILfbRrv)PKmAx415}xf!@N7945Qd{o)X&6ZXV%*3natz94Yn0oT!d2i1@IBa?c2 zelZe<6KH=y@`qJc&sX=AcyR?*7(w5+GN!l%5HjNCR)}~YbmCZ!z-u>E$=z7>t*gtm zHW?`b?r(=<7TJ2%-#C(OTE=!Isa^A7*3>;|{tY$K(hvc2T_! z{^AXBU?$E20OGcIH3>V>7*xgVQC)p~#ZHKI(I-vT8F@T|>yzy!R8O#i;yj}FA4{Mn zMn`WE7Vhf_4_nfVJd%?qo7&ngU?IU`C&^GDO0(g1!Uc3&Eb-QW=o}EWF;@ zY0vD?;%4Kn(RA)x8S$~tfYM|jrrLHhcrk5NO9I)2l6>k7J%YkZ@9!}R^W?`@0@$T` zmKT$#OG*U!`O9}5J%0Q+-bx%WAmbYwL>L)1az;dCsqlR z>;PWN&yNt#C*`lt%cK+fZsUE3?cIy1wh0Sq;cAJr0Ouhq+>J%?Gbt2rdEZTZJ^93( zMX`dD!rEqQ=H*r=jLuitZ5a=RclNo`8y`R3d-G-{pZ13fBU;kqe&Od$e)&2QsK5_R z01lBT9ugvMRm)Yg!8flgo z@E;ZA&f#v^?VL>>eH9u<+uF81kThX?79c7^a@!atX15x}rEro1o-ERr@7%cqpr)nT ziSx&qhkih^Tq>XtMH~-_m`F+jb3Y3V9%>8-RsqqXbxa;F4j=eiYW%&2Vdjwc8WB|} z8=-2n&uOZs*P|Qzs7B%C)GLfMTbiX_>9Js4v66QCgJQMq{Qb7PD!YXYH$C9yZA}7A zmzlSE4YD0+WZm1!-%$RWn_IG)06CYtUC7`vFnUaeJzQL1;Qvv7eAEpSF=V^6|J7-$ zm$bGD!ECW-PX&tiJys*CDa!9~laUmN;kcrB475tB%hi5i%klbFTW&Nms) z^kz_o!>luF?yg!v?A}}ncDlTM*t|bL04`HEH-}GBDh07|r26s? z=ZM5r)~acb~{p z8lk;d{XSy__pjEN_|+TVvbkLp6Or5T@r4|ZuVHR)PP+dj;t&C z1)nOD^*6Ln>Pcv*Rh$v)`%|%}FsRwSYu<%@cY7wq_}0sQQi|p*Gy+tno6;JU#cX%q z{q$Pm)g*2X3y&Vp1L0hOPNJf-u95qJArULuhtreNMY2Vf7RCu87{wBwLz)Zr!h zPY-*q-;t)d*X{pbi5@&_t#LFNM1|rl+gCjFfPE#&xK4q`msj?1pa<{G6vceuIWnJ| z6%=gp_iebovU3aqJpxH5B%x2nO3#=P9z<$M1=Y|-uN(jv+{CoD2&$cLv9eFpKDsOT zT}=&)qJO7Veuw7ym(z5mkF<^-1ahZOp5!gJ`MK1td;K=4Os~?Z7A7fy7M(Re#wXP! zrWM!fV)=a1_u{r>O<9B}kwC2a^y!oG=zUqTZE^IhPd;AN@(6|^li>Oky!?^jG+*Nv z(T;4&cVbluZIvrj-$WO24tMuDQ zp%tg4rVh0>d}-w$ciw%%f(%4SZ2lK*@td{yr64>+QS&SMZ|z%FJ$xc!qIrBU%F`-B zhSJvZCu~9*tp1K6wjici^aQDVfY@yzlNMu2rryk`m;N2I z!|f478`86)S-{?)#wH&uD%Af`3Xy+&k7oY${cWa2j^Cy5AF5zKg)pnsFa5N&BzRQd z+QB=dc&-DL0w<|sn>+Pon3eE;en|7;E}Xs!u$C!eo1y@)Zkazsek)w0)64+*qVe#l z>i@@gDHxUqY5tEki}+KVHHWWBRx|MBpLiL9Ot)S-NYRq}j}mK&{<$JDMgM$InKkvY znJJ{_FEQ$2mg`x<)D}#C!jwo2&XEJ9GnwVr6pc@CQ5Wr%Ucff}YiP~*pIhKQjrr$^ zb4}imRUM8f({ysLf>4|qX)^;=-X9e3Z+_(0!(qP8DKr{P+VsOAM`Dp%9x1rLLPc}5 zW}f9Y_FCt3qcnH@f5}caJa}u@72E!Y?qr;UX`q5n4Q+RtBvQ+EVPa8~i=>1yWLm`= zcg#(q{UX-zH+%i`-M>1ML6`ik)MDzt+B2Mo&m)x-fDTY&(q^RS=$P)9=;MH?(zi)2 zrmwqB`u{Rj!B{Zusv=EQ@$vEK`7x3gF>auaWqvVl&nvf+B;D7sEvn2_%9JKt?hgRE zMEn6SDU6&!4R2~;p>JTYqkZ4LeY=8pV63;L$|V|&79Vd0O$WMf29z)N?rkUy3JvXO zX!wMGg1K9eEzs%e;^J8t6a}XdTDWcmYqriHeddd(i%4FUC1=jvh~M1pM}4hF49sdK z+?#gjKKcqZ1p2DTa1`DcqvHD(usIKj{bSsZqJ|2f$E#N*sC`Gu$W%>!{+K%}DMxnz z(t-j8L7Asc@rYgYe=>z1YR_ytM48E4v{OsY@VLeBLS(>l6kFTbO(6-9lET8mJ9a!w zPfsW0eR&|i{zU&&UF`(ZQSVp413sKTfBaasxv!(L8}3iLiGJwwu-#WBF-!)HnI!2y z?~)WbOCw~N#IxNXa#Yx0=*#T+2gvbaC!QdL2M#*8ta7_A}AD>3Udhp=ow6y+r z!Nl$hFJ|mFBrS&ItGS3z(2Mv(z7~H!IyxWy;Hy`rCE=0<1qBc|A<1HSC&qJ~EsMLO z+Xf+S+F)5U?eOnDT@5Ag3xESZfBvM@W;V69?sXk=G}_5LGDxTS?;|5TD3XYbM1S04 zT<|(OI~%XeOZM%FUHbafm@%!;N%p}vJ+n^6ceXV&AWMPUPB+sw-rwI}v*Zt7Z!MZ{ z{WNp#@RL?no9!p`>L!$=Sy& zZRNM0WXf$1;UL6u;dj4-Ni<-f^OWb2v^*+W=O7nqEowB36qypQB=D z<~^gAoIbF~O*RXsRYwxMlwxtFpm{d2MQ)mNmAa&i+x^Om@_CC_?O#WWM&FZErKZ>@viJmnAy;DJp11|WZ%Gdn$5qI$f~m;qA$;6j1-@f9I^)ZROJxTBC9!% zEFgYuqS@p_CAZ_BTL@QlD}Pjlex!sW;pm$0KA-=(7sv9c{X?3|{}J{9EYMMP+@9la z)Ak&=b6Vn6RB~hAzITbm)3&@4vH#u?GVrZl_9_DdHGfNzeqZrDE7_1Kaly$+DTM7< zmckkIrS)3`(KjCjzXa2_bzdu?hGVGV*9Sl${#(5_XM~i=t?%2yA##sKqEZU);o6YU zPHN>hiydCT`Z~erRe@LB(rnr<-}#hg^gj!rr$DegdDB={ivG)*!dnMORlxQPB$`gS=h^t_%k3gbIJ(i&&NI;#5Kz zw9<6iQ7#p!6gKkOeYs%Ac$#62r#mx;dFsH1L?zCTLDlqWXsJwwu1!(Od9cRYN!>nK zfcL!`T_0n{Zh8doAj$#1wlmKph)pD_X;5BM&>aIIFW>-Qp?yAnqaB)(}V0h{;3kyoE z|DGWUPLSHy`jEOK%|%B3$e3*{F>;NBVo?m@kotAXwm)DL0X;d2+1szrWb9K*`Uh+w zgD^s@R{72K#%H?j?Mb}a6zRHMTx*R4QaBQt-iqaF^c{m>;6W%WF*@$%zzF`^)HJE7 zStdqm?vvddI9-07eD`Vl^ZMBd<}N&_MX~fU<~bS-aSal9`c|7yJ)Xonh#n+twhl;Jdk$bm)hA^pB z3XE*E6wm}+@a;yPz#}LzBkgngyRs(z+F!ZlZ2=M?Vqna@gZAuM$Ud8FgMFx5_V=_W zA@Rw!hBna`On6N|)uO-xhd!2I_fji=d}fF#a!-*aoy8(#|++Pmg7quJfQI?k$AY|fnVaZUSnKi(9tr$_1fP`J=e zS=RWE^@Y-IiHlWvBTc4V0ty6VlY@2gp?q)pR%$*Nz69IDYdNBLj7Cd#frpiVD|zHw zzTlo6ke&PVRgmE@K6i;HBVgu-5}_PHyprFon0Rl;p@>@Jsm1WsVkHup7W}?enJ0^u zXn(-AeSu4nsy0FKHe=LG;2XrR#Z9h>L$(DxWSe~7zI>VKd03uOn-N-@;O~1z zSX8v*%kFfbEW=HIPuu&hX%ZP1+%g?l*fx8GKYO;MKvm%ipFh8TAZ*9(6Ntr%iYh!p zrfMBMbLMuODAElXWAWPB0pa0R3WfBt)1M!4G)ec96H4HY`JYP)C4)9+nZA0)g^nS} zVuZ*0fe)5X^rPW-=nm61-@!N8Mku&u_AR=hzT735V_j)!KilMmZxCaZ4@`CbBF$vz z)I2S*fGVjP<|vez#)+g2YQsM=%y7~YBl-3kdyXu`&R4{d1XXo>x=x<5@nkZsfPYlU z{2v>iq4}Blwk?3zgT3 z^<8TTCl)z(rX8?pK03T_a07{tke@VNYiar8WN(!hFyBvx1Tb?LT9cv*?cIB$-6nd* zXpq;f*#oDgr$KgOn2@QFWyQlbodv~-=j{ALSLql3WK7F3mrq@2|1{mbKEXu>A;)1B zR3y~;_K+8hu>Zn-?LdJEKwr-EL%5TYKyoAFxamN8xq@!zP{qKPqhLoQ{-u zyPN_FjmfCYd;v*p(Z~LPE+Ju(WGgedI`gu}&@vQ$|<{pTCY#+vZCBgex*~-pg4m&pw2v(6XlQ{+ZvB zz2Azx;UQcaY(F1AdsapK{dCpOT8GJa`voC~=P&Jg1U(?+6>UzC1QyBN`gZ_A9Zwo7 zj7bbq?m?hm+Z=S2jXZjp@q4!qjd9<-+t__)5kxhdrzZ<&9D9&Xp(YDZ>1fZ!i~r>v|@9qi({-dXlm6iGP=zrX(fetWHc z1N2Du?%m_@9zyZ0x44^?Glx#)6YajO#8aKw$*LBy$MQyCU{<{`c|j1|A-Jr z{-)+;PkRcb8?A8p=XTf+IM%N>^7Mt$+6?|3`bG^^(-wg-a6*h`^w(hwVu* zV8`m+r<5@8V8x0R;fF!X9pnIojaiZ${Cb+Ei*!I(Pv`0QXAU(j=&SgJo)f?vgck#T||^AY>f?G7?*=ui&OCzJwbNsmA(xbpwNkrbMk=g%lt6+@RkM*Nig7sY7VSrLwb*yT>Qk%{iQ>W87>v&HmKY-EYe0j> z&d!d&9lE6h%o0VxWQVM0Axjd_mc?qOCmP+>&L&=g*$~ zjZ#!9DB5=Gi1Oy>?*_GyA_Xh4vsY*>=C0KD+)QNm zNeT(YCkqRaPm{c(m^~iQh$H>l$S4X7)IrgaJKRhT1O>M)G>MoDWEL75*C7=gW?RHb z?AyEd2=vT<1RcV6Myv=U<4|$=VDmsu5S{55YIFX)&r-|Nr=f~S2Py=WP;HKrPX99V z*o{jjh8#vVX=rG`R3ayI6F8q@<*oPu4!36zcqexjy?wh}MF~?ZcRiWH3kxnn9*F6{ z>S6v>!He*D8&3fdJEf+gq(sh25osg%)0zTbz5`(tdA@rh7(rbY-3DVV*N{qRyDs|S zSS+-8+%fxlt&pQlXlV~^hZM>Uo0(O4cO57 zWy@{{2gkSV*{}R**_C2ZA8F+5oPp;i^}z(tyIsL&LCHqGN;Uh02bAi)4!V!l(#>k# zkj@x@70klu6;)6~?|%+A;!p6Ui@q3rpLr!>X@)AhTf_F= zkEYc(OjgaRDK9VYAlx~Ue44(%4`dwbCvBB-mEp6_7s2nVq7mJb{qk45@B>c!J zJJZjeS8MezZ%=07KMu%%JME+cGFa&urh>N}x3x{JN8DXyvQ~Q?<`0n`xqjFWq0PR2 z{d#*Otx?~035H}O)3$K?VOo`?rKC->63lfW*XzHMmPqeDo0}oT2yEc8J8XdDYHMrL zbFOCIcoNaLPtt&Vielg>mbt;ZP8KzA6^trU5VQ0*lA`goVT(L(Ym4y3?6PA$%kaSap5BNonaAaP zFD5TYKkD$!^^^Y}W8WQ*<^KO)r_<@Ap|V;y4JASekk8B!6n~&ZDDIk$P0Z6ormFwbrdl$1I{+R z`UcLrzPxc`p}Dy^xSF72jyHUaf0ygIO2nc&oBNgZ5-u*m`i(8qnC&8-Aee2J=gGKo zY*@)dw?%CU>XVDynKNHO^db~x#G|Nxrk1O$Hh`_pVRLhB4UO>V?8DEm%nwzyp~W%D z8%<-rZE+QE@G*9-U;hb+sqYB$DzO6-b8g!nAel`N^z4sU4r>|6=YI1=4plpX63L+h zDY(ZM&V_P(t!h?mU$|6!^oySo5)VymMA!_7_yS1q@|^vwXs}^TAL5jgseOrgt!6?xSt^q^z*I8|AnjsIHAxtHnUf`9+qMey|B;c$^%)eeilBcmfu@k4 zpZP;ucw2}r5T38>mAG-*4FUY0Z{Oo+g+7X)GMn>!QM2hyot-_CN#{45()1br$R(?rJ9nR$ z>aJb44F58Cx=2l!bMGp7ej7fTT#~_-x<68vilnZ#`Fp+SR+CwCz0KC=t1M+zIkkrE z)!cFe;fmJ>e223yn0=X?5InWp;ECVp&fu@DXWrO1d<_~LC!C6(*$2I`qtrdFT_?9t zk&!jwZ~hM7ou4T-MybC3-fwf}HFJbty>{)6zrXYIu41#a^Z_o3)2}{cdh=_4HKMk9 zs5J$jTz%V#>3;ax#J8)r3tH5s%=gjcfgAwzR5i7u=fY*(*o1^QO5@JT3JApCy7k_$ zH7T1R;M<4DULr4N>GehJMAu-sFrA0mU&Ii~@pRl09b#0eA9bJB#(C8Cpnprq5bwwK z;%(VAI7xV0uW7n~9@k4ycP#NuFMJiOq*HonJldxU4XF;Ks7{tNU7+gf==Y&4vTr z=z~@AViesqD_g7L3u|rNh_o|%QXX#HCOBAfF3Iop?D&T6Bc03#n;$63FJxM|zTt0p zA1vgoEiNkRX^ubIE3^^Gb6Mvp`bi5{w^XVmu563B#E6l6Id(}z)$Zu=@aKgti$r+| z>6M~ZItXSP9kAt++Hon>5`!y&d01dmQ7O2p4LsorhUeBExDR zjJK#t|2p^6ng$C&E-gxaWY)-#*C0>-SJUS!Z5nH8^&}+gl$6wZcg&^tm)~4hTU%R~ zHFWItou}R1HC`L$PWE{GZ9>R{rBo2JEc)uDb&?SUcEiyo+qPPssLy|#6X||Pvd6N+ zywJOtu1Wd!`Q;Q0IVIASc2h(v?&};1&S&KYZQhW#*l9D>?QL7!3T{GBU=`W{TyyQb@GvC^ z{`_5CiD6+!EiLU3exkaJoqfZ~t-`{~I&*S!T|5!2hFjJ^S-H5jb_Wm7zFJ`KrHv=g z5REx5C>H<%@1uw+Q|c2p_jI>>e1G_nE6sOjk?wZwe+P(D&}0jCGRM9S3_mE5&KxUDmV9juGd3p!T>Ez`l-&xq1Cy zhh@#<_{Soql|3wz>}(ibukD1-Be1TI1Zg>=8d?=2l-OrBRi9RuMq3P(@TBp>ktf055tNAw{kLmDZX%`zhp_RG3 z|H}=5GWSR3%2kz>x9L>U5T&AnG|3JyBSjK7EojO1=oMI<~CN+^kHQMQgI{;~%V zE!7qb&G*3y{i3~&{aRt`*H^sBBD{lwCLU6ilC`0^Fd2k?50SVgc34A83wlDh86vo+A0h`- zt7HAu#%v2K?j!MO;c^uX4H4*jwyFVIMo=Ft6F|5?XcIV7fiPLo7)ID<5{;G^6*W{m zxnbb+sZ(%ccyhig$O8I?1=G;x515mfdQsFsZ(rY$p`ra=Zu&Yp25G1Fv8Jb|V_zz= zm6esD9FB~LU|YVNmkIUb*XDz8nOqHG^W&%MZz3V4bt6CV}z#J1gc z&k?|GkT(LJUKaX>^gtM+Uhs}?(oUdm=Mjx;?GHQZTi|r$)>YgYpDEEV{||RYqbjRU zQSRQ>_`m1S**D+0#;_um(sTD!Fikv8dBSL<)rn5$2*7?Q;tMslb!)|HdW6+CM76&} zpE;uf_cAHHcN5x0631t--ESyIi3u5Re36IyjZge_Au8IMO_7m?C?f`ry;NxWEVTO1 zg{z|y6F+}CHrVJ^oZnYPqH^Kl&Ry>wdq_!* z8ceqSIYp;yberN^{WPO&5jeT~gG-A52gh~YM|+O7pQy9)SiY6lZgj*v$cB5%{lvag zz7Nc~dsJUm2b()Rf+Y+_Z<>`6U%njr`|mkl7nBi5K7IZAK)4*cfRmEGzP+;9yFv3u z=q>PY*G?rUX6Z~jN>7dB$-@3V7b?9--|g0xPZqA+G03%#GCVpu<}`Uj$9UydV`F3G zxKAA6E?%dm?|6x{d=s9v!kb4Am&ve%dEk|sJtDP!P-~l zH{UwPH9p?w(Ia}wdY(kDwm@mGP15B0RSCLTiE!ilY$c5(b8OZwY=5`&nsfVoV~B5o zEAg@vPRR)&n`Ij)#zH>w@rLUs`>GzSTF1IFE=F(>N|@G~ypodlsnru#Dre|+KaC|? z;(aUhO(FptZZi*Q_K*Gp>ZcsorzpRFq4PPZ&r&tnWwX8L_&t-DG}Zl$*e$4xway31H^a{4?LXG7fXQg$)T zfkGFI30CcVt4(E2g5PYk<<9pphmX?12<2Q9Qh;?N_0s2 zj#QE%_{#iH=?+qUg%e}5-3^r~S>CF|kLP#ftk zWGU6ZzPM|N+wn8+cO}kU5Vgu2`tp^*hprD|tYGBh&`dkks%0Ag^JUoe#x`9aIlR9f5qk4LJPbAqq z@QGy*0uzGkLO(nXOY@4ou9xKL9;WAMy9lMlLQUa+m%XA}&PdD8I?W*ke-JmQWRAv794*YbPk)I41 zV5Qz<3`4K)j!ta}v;eNXMWy;N)8>}} zQM6CoS>4^;Tc)?e##p}gc*>*3-1(2Uiovir#RSOW;^qqJ3q(J|ep`E6yn@%I_DX&9 zN3u#v?Ju&6MYohBKG9uoPi-&1xir&@95MIg{%{hUUI>U$ZWX9`VL%3?;(nGe*3<&8 z--Ugnj-u7;tnv9ME75e(PI6}(>oztwTbP;k4p;fe7)b;^{#q`X9mMKmOxQKewYP5% z=4Zl($jElAj#i&nT49|yuE2MDL-*-Z4{PovHPP%JFu9c#8;eiB*ddeYw2<#sK**)g zSGf>KZFe$N*!6UljXMnfCc2b9uUOt9xnp2i6HkP_qrES2z zPqbPRLfX}gkdQUWk&Fu;O;v|a8M(%N>PU0EJa5!>54v?s!y+Sd@6(<*|I4|vD`IMe zG4uJjUB9O{QBavV>ceBwRMq(r9Cj}s;|!y2^qsw;vDO8G-saj`J|c9R()SUCX_@}7 zDthDlDGStznY@On+g0l7a^Y#4&^9!a_@1%td)Z?mH}}%0@%Y-Ka{Y z84A$NlmCIgnweUYhaR~*e>Odw{xkfKzy9IPr#S!buT8taOV?COr?skQ%V?OQfUdrh zEpR}9dCE0)>KXU5n&9)|n64^!I2I`})qZ~~rDjTxAX!sixqfyIRsNy6vPP2rRsD1O z9v_*fa;DEWX39x#s{dG3`(Lonb+K^!usp@i^qjNyn2pv%mR4esdHeOPg z6Hxfr3x5pnb(8sYgL^X5g>XrV>Uw|pYaLxZwENxg_>1eK?X9hP`sW*NFS|*ar=I^0 z)H(Jlf(TV^8|;i@Sd~W>VNx^Uzg+Z~bE5m9jJoW=B~43jA5q9}Kg4c6G;GJrS(})E z)^g8(;!9oHz85YKeOtx8q@1qI$ZaqUkIdE3^3l-rOV5y;`^VzfLi-miT7>Bq`OoDc z)pI)CWQt{0rS3cvejejK(k7tt;kq%`A-ec*?{Ce&7 z?IU}IHde*I|2O<6;GPT-Gv=;#&52w_@jA~Ja1_ItE9)o_>JO@-?+(ol{;QXr`kwVZ?_SJ^L4bNic+!} zlQM+_O1ub(r9Urxav*kLA+<0+|I4dVLx2NUuKbQm&@eqP17&sKg-y|0M+Y|Il~`L_ zH>5inFs6PhK|&5TXU>Rh+cxabUVzi#P~C9rJ!54>meUgAZ#&++?ZwgnEQZ=0t=d%i zNY38K5>Rhhr0+bo{M;99@gaLh{qHQdwzRbEu<*`wq^}SE?YBRi&m_Vgk1*a*{B&1C zX_6oBdD~9Tl`G4=bKf3o5Iv#e0r)#=m4 z95&+Q5v$?rSN=z3JY9cXVBKeWrbmSu+h|r=-;fm>BS=>XGSt;vJ6Y-zYd6Smt#q

DXiQX%25op@-zgu|rsO}d+EdprE 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

u`(Hepoz56};e1atRAdC9 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� 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 diff --git a/contracts/docs/plantuml/oethProcesses.puml b/contracts/docs/plantuml/oethProcesses.puml index b97837a856..43a39e8f8f 100644 --- a/contracts/docs/plantuml/oethProcesses.puml +++ b/contracts/docs/plantuml/oethProcesses.puml @@ -68,7 +68,7 @@ activate api return status,\nvalidatorRegistration,\nshareData note right : validatorRegistration contains the pubkey, operatorIds and cluster details -reg -> nativeStrat : registerSsvValidator(\npublicKey,\noperatorIds,\nsharesData,\namount,\ncluster,\nwithdrawal_credentials,\nsignature,\ndepositDataRoot) +reg -> nativeStrat : registerSsvValidator(\npublicKey,\noperatorIds,\nsharesData,\namount,\ncluster) activate nativeStrat note right cluster data: @@ -85,16 +85,22 @@ activate ssv note right: transfer SSV tokens\nfrom NodeDelegator\nto SSV Network return return +return -nativeStrat -> weth : withdraw(\namount) +reg -> nativeStrat : stake([\npubkey,\nwithdrawal_credentials,\nsignature,\ndepositDataRoot]) +activate nativeStrat +nativeStrat -> weth : withdraw(32 ETH * number of validators) activate weth note right : WETH burned for ETH return ETH +loop for each validator + nativeStrat -> dep : stake(\npubkey,\nwithdrawal_credentials,\nsignature,\ndepositDataRoot) activate dep note left : 32 ETH from Native Staking Strategy\nis sent to Beacon Deposit return +end return note over val : Pending Deposit From 6df4f5f7e59b0f74598c83041436ca92d86f616b Mon Sep 17 00:00:00 2001 From: Domen Grabec Date: Mon, 13 May 2024 16:57:57 +0200 Subject: [PATCH 070/273] add a withdrawal event when withdrawing WETH to vault (#2059) --- .../NativeStaking/NativeStakingSSVStrategy.sol | 4 ++++ .../strategies/NativeStaking/ValidatorAccountant.sol | 12 +++++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol b/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol index c15629be71..76737fc398 100644 --- a/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol +++ b/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol @@ -261,4 +261,8 @@ contract NativeStakingSSVStrategy is "eth not from allowed contracts" ); } + + function wethWithdrawnToVault(uint256 _amount) internal override { + emit Withdrawal(WETH_TOKEN_ADDRESS, address(0), _amount); + } } diff --git a/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol b/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol index d99982cc24..996a28bfa7 100644 --- a/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol +++ b/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol @@ -132,7 +132,8 @@ abstract contract ValidatorAccountant is ValidatorRegistrator { IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: wethToVault }(); // slither-disable-next-line unchecked-transfer IWETH9(WETH_TOKEN_ADDRESS).transfer(VAULT_ADDRESS, wethToVault); - + wethWithdrawnToVault(wethToVault); + emit AccountingFullyWithdrawnValidator( fullyWithdrawnValidators, activeDepositedValidators, @@ -162,6 +163,8 @@ abstract contract ValidatorAccountant is ValidatorRegistrator { IWETH9(WETH_TOKEN_ADDRESS).transfer(VAULT_ADDRESS, ethRemaining); activeDepositedValidators -= 1; + wethWithdrawnToVault(ethRemaining); + emit AccountingValidatorSlashed( activeDepositedValidators, ethRemaining @@ -233,4 +236,11 @@ abstract contract ValidatorAccountant is ValidatorRegistrator { // unpause since doAccounting was successful _unpause(); } + + /*************************************** + Abstract + ****************************************/ + + /// @dev allows for NativeStakingSSVStrategy contract to emit Withdrawal event + function wethWithdrawnToVault(uint256 _amount) internal virtual; } From 614b11eaf025d5d5fd8bfb2dd19416ce4f1af419 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Tue, 14 May 2024 01:01:06 +1000 Subject: [PATCH 071/273] Regenerated latest native staking diagram --- .../docs/NativeStakingSSVStrategySquashed.svg | 125 +++++++++--------- 1 file changed, 63 insertions(+), 62 deletions(-) diff --git a/contracts/docs/NativeStakingSSVStrategySquashed.svg b/contracts/docs/NativeStakingSSVStrategySquashed.svg index fe01136eb4..ebfd5bec6c 100644 --- a/contracts/docs/NativeStakingSSVStrategySquashed.svg +++ b/contracts/docs/NativeStakingSSVStrategySquashed.svg @@ -4,72 +4,73 @@ - - + + UmlClassDiagram - + 284 - -NativeStakingSSVStrategy -../contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol - -Private: -   governorPosition: bytes32 <<Governable>> -   pendingGovernorPosition: bytes32 <<Governable>> -   reentryStatusPosition: bytes32 <<Governable>> -   _paused: bool <<Pausable>> -   __gap: uint256[50] <<ValidatorRegistrator>> -   __gap: uint256[49] <<ValidatorAccountant>> -   initialized: bool <<Initializable>> -   initializing: bool <<Initializable>> -   ______gap: uint256[50] <<Initializable>> -   _deprecated_platformAddress: address <<InitializableAbstractStrategy>> -   _deprecated_vaultAddress: address <<InitializableAbstractStrategy>> -   _deprecated_rewardTokenAddress: address <<InitializableAbstractStrategy>> -   _deprecated_rewardLiquidationThreshold: uint256 <<InitializableAbstractStrategy>> -   _reserved: int256[98] <<InitializableAbstractStrategy>> -   __gap: uint256[50] <<NativeStakingSSVStrategy>> -Internal: -   assetsMapped: address[] <<InitializableAbstractStrategy>> -Public: -   _NOT_ENTERED: uint256 <<Governable>> -   _ENTERED: uint256 <<Governable>> -   WETH_TOKEN_ADDRESS: address <<ValidatorRegistrator>> -   BEACON_CHAIN_DEPOSIT_CONTRACT: address <<ValidatorRegistrator>> -   SSV_NETWORK_ADDRESS: address <<ValidatorRegistrator>> -   VAULT_ADDRESS: address <<ValidatorRegistrator>> -   validatorRegistrator: address <<ValidatorRegistrator>> -   activeDepositedValidators: uint256 <<ValidatorRegistrator>> -   validatorsStates: mapping(bytes32=>VALIDATOR_STATE) <<ValidatorRegistrator>> -   MIN_FIX_ACCOUNTING_CADENCE: uint256 <<ValidatorAccountant>> -   MAX_STAKE: uint256 <<ValidatorAccountant>> -   consensusRewards: uint256 <<ValidatorAccountant>> -   fuseIntervalStart: uint256 <<ValidatorAccountant>> -   fuseIntervalEnd: uint256 <<ValidatorAccountant>> -   lastFixAccountingBlockNumber: uint256 <<ValidatorAccountant>> -   platformAddress: address <<InitializableAbstractStrategy>> -   vaultAddress: address <<InitializableAbstractStrategy>> -   assetToPToken: mapping(address=>address) <<InitializableAbstractStrategy>> -   harvesterAddress: address <<InitializableAbstractStrategy>> -   rewardTokenAddresses: address[] <<InitializableAbstractStrategy>> -   SSV_TOKEN_ADDRESS: address <<NativeStakingSSVStrategy>> -   FEE_ACCUMULATOR_ADDRESS: address <<NativeStakingSSVStrategy>> - -Internal: -    _governor(): (governorOut: address) <<Governable>> -    _pendingGovernor(): (pendingGovernor: address) <<Governable>> -    _setGovernor(newGovernor: address) <<Governable>> -    _setPendingGovernor(newGovernor: address) <<Governable>> -    _changeGovernor(_newGovernor: address) <<Governable>> -    _msgSender(): address <<Context>> -    _msgData(): bytes <<Context>> -    _pause() <<whenNotPaused>> <<Pausable>> -    _unpause() <<whenPaused>> <<Pausable>> -    _doAccounting(pauseOnFail: bool): (accountingValid: bool) <<ValidatorAccountant>> -    _failAccounting(pauseOnFail: bool): (accountingValid: bool) <<ValidatorAccountant>> + +NativeStakingSSVStrategy +../contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol + +Private: +   governorPosition: bytes32 <<Governable>> +   pendingGovernorPosition: bytes32 <<Governable>> +   reentryStatusPosition: bytes32 <<Governable>> +   _paused: bool <<Pausable>> +   __gap: uint256[50] <<ValidatorRegistrator>> +   __gap: uint256[49] <<ValidatorAccountant>> +   initialized: bool <<Initializable>> +   initializing: bool <<Initializable>> +   ______gap: uint256[50] <<Initializable>> +   _deprecated_platformAddress: address <<InitializableAbstractStrategy>> +   _deprecated_vaultAddress: address <<InitializableAbstractStrategy>> +   _deprecated_rewardTokenAddress: address <<InitializableAbstractStrategy>> +   _deprecated_rewardLiquidationThreshold: uint256 <<InitializableAbstractStrategy>> +   _reserved: int256[98] <<InitializableAbstractStrategy>> +   __gap: uint256[50] <<NativeStakingSSVStrategy>> +Internal: +   assetsMapped: address[] <<InitializableAbstractStrategy>> +Public: +   _NOT_ENTERED: uint256 <<Governable>> +   _ENTERED: uint256 <<Governable>> +   WETH_TOKEN_ADDRESS: address <<ValidatorRegistrator>> +   BEACON_CHAIN_DEPOSIT_CONTRACT: address <<ValidatorRegistrator>> +   SSV_NETWORK_ADDRESS: address <<ValidatorRegistrator>> +   VAULT_ADDRESS: address <<ValidatorRegistrator>> +   validatorRegistrator: address <<ValidatorRegistrator>> +   activeDepositedValidators: uint256 <<ValidatorRegistrator>> +   validatorsStates: mapping(bytes32=>VALIDATOR_STATE) <<ValidatorRegistrator>> +   MIN_FIX_ACCOUNTING_CADENCE: uint256 <<ValidatorAccountant>> +   MAX_STAKE: uint256 <<ValidatorAccountant>> +   consensusRewards: uint256 <<ValidatorAccountant>> +   fuseIntervalStart: uint256 <<ValidatorAccountant>> +   fuseIntervalEnd: uint256 <<ValidatorAccountant>> +   lastFixAccountingBlockNumber: uint256 <<ValidatorAccountant>> +   platformAddress: address <<InitializableAbstractStrategy>> +   vaultAddress: address <<InitializableAbstractStrategy>> +   assetToPToken: mapping(address=>address) <<InitializableAbstractStrategy>> +   harvesterAddress: address <<InitializableAbstractStrategy>> +   rewardTokenAddresses: address[] <<InitializableAbstractStrategy>> +   SSV_TOKEN_ADDRESS: address <<NativeStakingSSVStrategy>> +   FEE_ACCUMULATOR_ADDRESS: address <<NativeStakingSSVStrategy>> + +Internal: +    _governor(): (governorOut: address) <<Governable>> +    _pendingGovernor(): (pendingGovernor: address) <<Governable>> +    _setGovernor(newGovernor: address) <<Governable>> +    _setPendingGovernor(newGovernor: address) <<Governable>> +    _changeGovernor(_newGovernor: address) <<Governable>> +    _msgSender(): address <<Context>> +    _msgData(): bytes <<Context>> +    _pause() <<whenNotPaused>> <<Pausable>> +    _unpause() <<whenPaused>> <<Pausable>> +    _doAccounting(pauseOnFail: bool): (accountingValid: bool) <<ValidatorAccountant>> +    _failAccounting(pauseOnFail: bool): (accountingValid: bool) <<ValidatorAccountant>> +    wethWithdrawnToVault(_amount: uint256) <<NativeStakingSSVStrategy>>    _initialize(_rewardTokenAddresses: address[], _assets: address[], _pTokens: address[]) <<InitializableAbstractStrategy>>    _collectRewardTokens() <<whenNotPaused>> <<NativeStakingSSVStrategy>>    _setPTokenAddress(_asset: address, _pToken: address) <<InitializableAbstractStrategy>> From 8be6f903448b8c1b4e7eea60304d8822e15ea807 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Wed, 15 May 2024 16:59:36 +1000 Subject: [PATCH 072/273] Changed vault mint to call to Dripper.collect --- contracts/contracts/interfaces/IDripper.sol | 17 + contracts/contracts/interfaces/IVault.sol | 3 + contracts/contracts/vault/VaultAdmin.sol | 9 + contracts/contracts/vault/VaultCore.sol | 3 + contracts/contracts/vault/VaultStorage.sol | 6 +- contracts/deploy/deployActions.js | 34 +- .../deploy/mainnet/097_withdraw_queue.js | 64 +++ contracts/docs/OETHVaultAdminSquashed.svg | 252 ++++----- contracts/docs/OETHVaultCoreSquashed.svg | 279 +++++----- contracts/docs/OETHVaultHierarchy.svg | 436 ++++++++------- contracts/docs/OETHVaultStorage.svg | 498 ++++++++++-------- contracts/docs/VaultAdminSquashed.svg | 252 ++++----- contracts/docs/VaultCoreSquashed.svg | 253 ++++----- contracts/docs/VaultHierarchy.svg | 376 ++++++------- contracts/docs/VaultStorage.svg | 494 +++++++++-------- contracts/test/vault/index.js | 22 +- 16 files changed, 1653 insertions(+), 1345 deletions(-) create mode 100644 contracts/contracts/interfaces/IDripper.sol create mode 100644 contracts/deploy/mainnet/097_withdraw_queue.js diff --git a/contracts/contracts/interfaces/IDripper.sol b/contracts/contracts/interfaces/IDripper.sol new file mode 100644 index 0000000000..c5d68bcee1 --- /dev/null +++ b/contracts/contracts/interfaces/IDripper.sol @@ -0,0 +1,17 @@ +// 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; +} diff --git a/contracts/contracts/interfaces/IVault.sol b/contracts/contracts/interfaces/IVault.sol index 1650382ff7..78afee24d8 100644 --- a/contracts/contracts/interfaces/IVault.sol +++ b/contracts/contracts/interfaces/IVault.sol @@ -34,6 +34,7 @@ interface IVault { uint256 _fromAssetAmount, uint256 _toAssetAmount ); + event DripperChanged(address indexed _dripper); // Governable.sol function transferGovernance(address _newGovernor) external; @@ -199,6 +200,8 @@ interface IVault { function netOusdMintedForStrategy() external view returns (int256); + function setDripper(address _dripper) external; + function weth() external view returns (address); function cacheWETHAssetIndex() external; diff --git a/contracts/contracts/vault/VaultAdmin.sol b/contracts/contracts/vault/VaultAdmin.sol index 5d4adcf2e1..877690adb0 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 ****************************************/ diff --git a/contracts/contracts/vault/VaultCore.sol b/contracts/contracts/vault/VaultCore.sol index 814dcda9e5..49db513fc6 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,8 @@ contract VaultCore is VaultInitializer { // Rebase must happen before any transfers occur. if (priceAdjustedDeposit >= rebaseThreshold && !rebasePaused) { + // Stream any harvested rewards that are available + IDripper(dripper).collect(); _rebase(); } diff --git a/contracts/contracts/vault/VaultStorage.sol b/contracts/contracts/vault/VaultStorage.sol index 6687400048..866fa85ded 100644 --- a/contracts/contracts/vault/VaultStorage.sol +++ b/contracts/contracts/vault/VaultStorage.sol @@ -52,6 +52,7 @@ contract VaultStorage is Initializable, Governable { uint256 _fromAssetAmount, uint256 _toAssetAmount ); + event DripperChanged(address indexed _dripper); // Assets supported by the Vault, i.e. Stablecoins enum UnitConversion { @@ -165,8 +166,11 @@ contract VaultStorage is Initializable, Governable { } SwapConfig internal swapConfig = SwapConfig(address(0), 0); + /// @notice Address of the Dripper contract that streams harvested rewards to the Vault + address public dripper; + // For future use - uint256[50] private __gap; + uint256[49] 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 68fa8be117..37122d48c0 100644 --- a/contracts/deploy/deployActions.js +++ b/contracts/deploy/deployActions.js @@ -711,6 +711,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", [ @@ -727,8 +728,21 @@ const deployOUSDDripper = 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 deployOETHDripper = async () => { @@ -736,6 +750,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", [ @@ -753,8 +768,23 @@ const deployOETHDripper = 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 deployDrippers = async () => { diff --git a/contracts/deploy/mainnet/097_withdraw_queue.js b/contracts/deploy/mainnet/097_withdraw_queue.js new file mode 100644 index 0000000000..b82f01f7f3 --- /dev/null +++ b/contracts/deploy/mainnet/097_withdraw_queue.js @@ -0,0 +1,64 @@ +const addresses = require("../../utils/addresses"); +const { deploymentWithGovernanceProposal } = require("../../utils/deploy"); + +module.exports = deploymentWithGovernanceProposal( + { + deployName: "097_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", + [], + 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("OETHVault", cVaultProxy.address); + const cDripperProxy = await ethers.getContract("DripperProxy"); + + // Governance Actions + // ---------------- + return { + name: "Upgrade OETH Vault to support queued withdrawals", + actions: [ + // 1. Upgrade the OETH Vault proxy to the new core vault implementation + { + contract: cVaultProxy, + signature: "upgradeTo(address)", + args: [dVaultCore.address], + }, + // 2. set OETH Vault proxy to the new admin vault implementation + { + contract: cVault, + signature: "setAdminImpl(address)", + args: [dVaultAdmin.address], + }, + // 3. Set the Dripper contract + { + contract: cVault, + signature: "setDripper(address)", + args: [cDripperProxy.address], + }, + ], + }; + } +); diff --git a/contracts/docs/OETHVaultAdminSquashed.svg b/contracts/docs/OETHVaultAdminSquashed.svg index 3a14885577..ce910a472d 100644 --- a/contracts/docs/OETHVaultAdminSquashed.svg +++ b/contracts/docs/OETHVaultAdminSquashed.svg @@ -4,132 +4,136 @@ - - + + UmlClassDiagram - - + + -200 - -OETHVaultAdmin -../contracts/vault/OETHVaultAdmin.sol - -Private: -   initialized: bool <<Initializable>> -   initializing: bool <<Initializable>> -   ______gap: uint256[50] <<Initializable>> -   governorPosition: bytes32 <<Governable>> -   pendingGovernorPosition: bytes32 <<Governable>> -   reentryStatusPosition: bytes32 <<Governable>> -   _deprecated_rebaseHooksAddr: address <<VaultStorage>> -   _deprecated_uniswapAddr: address <<VaultStorage>> -   _deprecated_swapTokens: address[] <<VaultStorage>> -Internal: -   assets: mapping(address=>Asset) <<VaultStorage>> -   allAssets: address[] <<VaultStorage>> -   strategies: mapping(address=>Strategy) <<VaultStorage>> -   allStrategies: address[] <<VaultStorage>> -   oUSD: OUSD <<VaultStorage>> -   swapConfig: SwapConfig <<VaultStorage>> -Public: -   _NOT_ENTERED: uint256 <<Governable>> -   _ENTERED: uint256 <<Governable>> -   priceProvider: address <<VaultStorage>> -   rebasePaused: bool <<VaultStorage>> -   capitalPaused: bool <<VaultStorage>> -   redeemFeeBps: uint256 <<VaultStorage>> -   vaultBuffer: uint256 <<VaultStorage>> -   autoAllocateThreshold: uint256 <<VaultStorage>> -   rebaseThreshold: uint256 <<VaultStorage>> -   adminImplPosition: bytes32 <<VaultStorage>> -   strategistAddr: address <<VaultStorage>> -   assetDefaultStrategies: mapping(address=>address) <<VaultStorage>> -   maxSupplyDiff: uint256 <<VaultStorage>> -   trusteeAddress: address <<VaultStorage>> -   trusteeFeeBps: uint256 <<VaultStorage>> -   MINT_MINIMUM_UNIT_PRICE: uint256 <<VaultStorage>> -   ousdMetaStrategy: address <<VaultStorage>> -   netOusdMintedForStrategy: int256 <<VaultStorage>> -   netOusdMintForStrategyThreshold: uint256 <<VaultStorage>> -   MIN_UNIT_PRICE_DRIFT: uint256 <<VaultStorage>> -   MAX_UNIT_PRICE_DRIFT: uint256 <<VaultStorage>> - -Internal: -    _governor(): (governorOut: address) <<Governable>> -    _pendingGovernor(): (pendingGovernor: address) <<Governable>> -    _setGovernor(newGovernor: address) <<Governable>> -    _setPendingGovernor(newGovernor: address) <<Governable>> -    _changeGovernor(_newGovernor: address) <<Governable>> -    _depositToStrategy(_strategyToAddress: address, _assets: address[], _amounts: uint256[]) <<VaultAdmin>> -    _withdrawFromStrategy(_recipient: address, _strategyFromAddress: address, _assets: address[], _amounts: uint256[]) <<VaultAdmin>> -    _cacheDecimals(token: address) <<VaultAdmin>> -External: -    transferGovernance(_newGovernor: address) <<onlyGovernor>> <<Governable>> -    claimGovernance() <<Governable>> -    setAdminImpl(newImpl: address) <<onlyGovernor>> <<VaultStorage>> -    setPriceProvider(_priceProvider: address) <<onlyGovernor>> <<VaultAdmin>> -    setRedeemFeeBps(_redeemFeeBps: uint256) <<onlyGovernor>> <<VaultAdmin>> -    setVaultBuffer(_vaultBuffer: uint256) <<onlyGovernorOrStrategist>> <<VaultAdmin>> -    setAutoAllocateThreshold(_threshold: uint256) <<onlyGovernor>> <<VaultAdmin>> -    setRebaseThreshold(_threshold: uint256) <<onlyGovernor>> <<VaultAdmin>> -    setStrategistAddr(_address: address) <<onlyGovernor>> <<VaultAdmin>> -    setAssetDefaultStrategy(_asset: address, _strategy: address) <<onlyGovernorOrStrategist>> <<VaultAdmin>> -    setNetOusdMintForStrategyThreshold(_threshold: uint256) <<onlyGovernor>> <<VaultAdmin>> -    swapCollateral(_fromAsset: address, _toAsset: address, _fromAssetAmount: uint256, _minToAssetAmount: uint256, _data: bytes): (toAssetAmount: uint256) <<nonReentrant, onlyGovernorOrStrategist>> <<VaultAdmin>> -    setSwapper(_swapperAddr: address) <<onlyGovernor>> <<VaultAdmin>> -    swapper(): (swapper_: address) <<VaultAdmin>> -    setSwapAllowedUndervalue(_basis: uint16) <<onlyGovernor>> <<VaultAdmin>> -    allowedSwapUndervalue(): (value: uint256) <<VaultAdmin>> -    setOracleSlippage(_asset: address, _allowedOracleSlippageBps: uint16) <<onlyGovernor>> <<VaultAdmin>> -    supportAsset(_asset: address, _unitConversion: uint8) <<onlyGovernor>> <<VaultAdmin>> -    cacheDecimals(_asset: address) <<onlyGovernor>> <<VaultAdmin>> -    approveStrategy(_addr: address) <<onlyGovernor>> <<VaultAdmin>> -    removeStrategy(_addr: address) <<onlyGovernor>> <<VaultAdmin>> -    depositToStrategy(_strategyToAddress: address, _assets: address[], _amounts: uint256[]) <<onlyGovernorOrStrategist, nonReentrant>> <<VaultAdmin>> -    withdrawFromStrategy(_strategyFromAddress: address, _assets: address[], _amounts: uint256[]) <<onlyGovernorOrStrategist, nonReentrant>> <<VaultAdmin>> -    setMaxSupplyDiff(_maxSupplyDiff: uint256) <<onlyGovernor>> <<VaultAdmin>> -    setTrusteeAddress(_address: address) <<onlyGovernor>> <<VaultAdmin>> -    setTrusteeFeeBps(_basis: uint256) <<onlyGovernor>> <<VaultAdmin>> -    setOusdMetaStrategy(_ousdMetaStrategy: address) <<onlyGovernor>> <<VaultAdmin>> -    pauseRebase() <<onlyGovernorOrStrategist>> <<VaultAdmin>> -    unpauseRebase() <<onlyGovernorOrStrategist>> <<VaultAdmin>> -    pauseCapital() <<onlyGovernorOrStrategist>> <<VaultAdmin>> -    unpauseCapital() <<onlyGovernorOrStrategist>> <<VaultAdmin>> -    transferToken(_asset: address, _amount: uint256) <<onlyGovernor>> <<VaultAdmin>> -    withdrawAllFromStrategy(_strategyAddr: address) <<onlyGovernorOrStrategist>> <<VaultAdmin>> -    withdrawAllFromStrategies() <<onlyGovernorOrStrategist>> <<VaultAdmin>> -Public: -    <<event>> PendingGovernorshipTransfer(previousGovernor: address, newGovernor: address) <<Governable>> -    <<event>> GovernorshipTransferred(previousGovernor: address, newGovernor: address) <<Governable>> -    <<event>> AssetSupported(_asset: address) <<VaultStorage>> -    <<event>> AssetDefaultStrategyUpdated(_asset: address, _strategy: address) <<VaultStorage>> -    <<event>> AssetAllocated(_asset: address, _strategy: address, _amount: uint256) <<VaultStorage>> -    <<event>> StrategyApproved(_addr: address) <<VaultStorage>> -    <<event>> StrategyRemoved(_addr: address) <<VaultStorage>> -    <<event>> Mint(_addr: address, _value: uint256) <<VaultStorage>> -    <<event>> Redeem(_addr: address, _value: uint256) <<VaultStorage>> -    <<event>> CapitalPaused() <<VaultStorage>> -    <<event>> CapitalUnpaused() <<VaultStorage>> -    <<event>> RebasePaused() <<VaultStorage>> -    <<event>> RebaseUnpaused() <<VaultStorage>> -    <<event>> VaultBufferUpdated(_vaultBuffer: uint256) <<VaultStorage>> -    <<event>> OusdMetaStrategyUpdated(_ousdMetaStrategy: address) <<VaultStorage>> -    <<event>> RedeemFeeUpdated(_redeemFeeBps: uint256) <<VaultStorage>> -    <<event>> PriceProviderUpdated(_priceProvider: address) <<VaultStorage>> -    <<event>> AllocateThresholdUpdated(_threshold: uint256) <<VaultStorage>> -    <<event>> RebaseThresholdUpdated(_threshold: uint256) <<VaultStorage>> -    <<event>> StrategistUpdated(_address: address) <<VaultStorage>> -    <<event>> MaxSupplyDiffChanged(maxSupplyDiff: uint256) <<VaultStorage>> -    <<event>> YieldDistribution(_to: address, _yield: uint256, _fee: uint256) <<VaultStorage>> -    <<event>> TrusteeFeeBpsChanged(_basis: uint256) <<VaultStorage>> -    <<event>> TrusteeAddressChanged(_address: address) <<VaultStorage>> -    <<event>> NetOusdMintForStrategyThresholdChanged(_threshold: uint256) <<VaultStorage>> -    <<event>> SwapperChanged(_address: address) <<VaultStorage>> -    <<event>> SwapAllowedUndervalueChanged(_basis: uint256) <<VaultStorage>> -    <<event>> SwapSlippageChanged(_asset: address, _basis: uint256) <<VaultStorage>> -    <<event>> Swapped(_fromAsset: address, _toAsset: address, _fromAssetAmount: uint256, _toAssetAmount: uint256) <<VaultStorage>> +219 + +OETHVaultAdmin +../contracts/vault/OETHVaultAdmin.sol + +Private: +   initialized: bool <<Initializable>> +   initializing: bool <<Initializable>> +   ______gap: uint256[50] <<Initializable>> +   governorPosition: bytes32 <<Governable>> +   pendingGovernorPosition: bytes32 <<Governable>> +   reentryStatusPosition: bytes32 <<Governable>> +   _deprecated_rebaseHooksAddr: address <<VaultStorage>> +   _deprecated_uniswapAddr: address <<VaultStorage>> +   _deprecated_swapTokens: address[] <<VaultStorage>> +   __gap: uint256[49] <<VaultStorage>> +Internal: +   assets: mapping(address=>Asset) <<VaultStorage>> +   allAssets: address[] <<VaultStorage>> +   strategies: mapping(address=>Strategy) <<VaultStorage>> +   allStrategies: address[] <<VaultStorage>> +   oUSD: OUSD <<VaultStorage>> +   swapConfig: SwapConfig <<VaultStorage>> +Public: +   _NOT_ENTERED: uint256 <<Governable>> +   _ENTERED: uint256 <<Governable>> +   priceProvider: address <<VaultStorage>> +   rebasePaused: bool <<VaultStorage>> +   capitalPaused: bool <<VaultStorage>> +   redeemFeeBps: uint256 <<VaultStorage>> +   vaultBuffer: uint256 <<VaultStorage>> +   autoAllocateThreshold: uint256 <<VaultStorage>> +   rebaseThreshold: uint256 <<VaultStorage>> +   adminImplPosition: bytes32 <<VaultStorage>> +   strategistAddr: address <<VaultStorage>> +   assetDefaultStrategies: mapping(address=>address) <<VaultStorage>> +   maxSupplyDiff: uint256 <<VaultStorage>> +   trusteeAddress: address <<VaultStorage>> +   trusteeFeeBps: uint256 <<VaultStorage>> +   MINT_MINIMUM_UNIT_PRICE: uint256 <<VaultStorage>> +   ousdMetaStrategy: address <<VaultStorage>> +   netOusdMintedForStrategy: int256 <<VaultStorage>> +   netOusdMintForStrategyThreshold: uint256 <<VaultStorage>> +   MIN_UNIT_PRICE_DRIFT: uint256 <<VaultStorage>> +   MAX_UNIT_PRICE_DRIFT: uint256 <<VaultStorage>> +   dripper: address <<VaultStorage>> + +Internal: +    _governor(): (governorOut: address) <<Governable>> +    _pendingGovernor(): (pendingGovernor: address) <<Governable>> +    _setGovernor(newGovernor: address) <<Governable>> +    _setPendingGovernor(newGovernor: address) <<Governable>> +    _changeGovernor(_newGovernor: address) <<Governable>> +    _depositToStrategy(_strategyToAddress: address, _assets: address[], _amounts: uint256[]) <<VaultAdmin>> +    _withdrawFromStrategy(_recipient: address, _strategyFromAddress: address, _assets: address[], _amounts: uint256[]) <<VaultAdmin>> +    _cacheDecimals(token: address) <<VaultAdmin>> +External: +    transferGovernance(_newGovernor: address) <<onlyGovernor>> <<Governable>> +    claimGovernance() <<Governable>> +    setAdminImpl(newImpl: address) <<onlyGovernor>> <<VaultStorage>> +    setPriceProvider(_priceProvider: address) <<onlyGovernor>> <<VaultAdmin>> +    setRedeemFeeBps(_redeemFeeBps: uint256) <<onlyGovernor>> <<VaultAdmin>> +    setVaultBuffer(_vaultBuffer: uint256) <<onlyGovernorOrStrategist>> <<VaultAdmin>> +    setAutoAllocateThreshold(_threshold: uint256) <<onlyGovernor>> <<VaultAdmin>> +    setRebaseThreshold(_threshold: uint256) <<onlyGovernor>> <<VaultAdmin>> +    setStrategistAddr(_address: address) <<onlyGovernor>> <<VaultAdmin>> +    setAssetDefaultStrategy(_asset: address, _strategy: address) <<onlyGovernorOrStrategist>> <<VaultAdmin>> +    setDripper(_dripper: address) <<onlyGovernor>> <<VaultAdmin>> +    setNetOusdMintForStrategyThreshold(_threshold: uint256) <<onlyGovernor>> <<VaultAdmin>> +    swapCollateral(_fromAsset: address, _toAsset: address, _fromAssetAmount: uint256, _minToAssetAmount: uint256, _data: bytes): (toAssetAmount: uint256) <<nonReentrant, onlyGovernorOrStrategist>> <<VaultAdmin>> +    setSwapper(_swapperAddr: address) <<onlyGovernor>> <<VaultAdmin>> +    swapper(): (swapper_: address) <<VaultAdmin>> +    setSwapAllowedUndervalue(_basis: uint16) <<onlyGovernor>> <<VaultAdmin>> +    allowedSwapUndervalue(): (value: uint256) <<VaultAdmin>> +    setOracleSlippage(_asset: address, _allowedOracleSlippageBps: uint16) <<onlyGovernor>> <<VaultAdmin>> +    supportAsset(_asset: address, _unitConversion: uint8) <<onlyGovernor>> <<VaultAdmin>> +    cacheDecimals(_asset: address) <<onlyGovernor>> <<VaultAdmin>> +    approveStrategy(_addr: address) <<onlyGovernor>> <<VaultAdmin>> +    removeStrategy(_addr: address) <<onlyGovernor>> <<VaultAdmin>> +    depositToStrategy(_strategyToAddress: address, _assets: address[], _amounts: uint256[]) <<onlyGovernorOrStrategist, nonReentrant>> <<VaultAdmin>> +    withdrawFromStrategy(_strategyFromAddress: address, _assets: address[], _amounts: uint256[]) <<onlyGovernorOrStrategist, nonReentrant>> <<VaultAdmin>> +    setMaxSupplyDiff(_maxSupplyDiff: uint256) <<onlyGovernor>> <<VaultAdmin>> +    setTrusteeAddress(_address: address) <<onlyGovernor>> <<VaultAdmin>> +    setTrusteeFeeBps(_basis: uint256) <<onlyGovernor>> <<VaultAdmin>> +    setOusdMetaStrategy(_ousdMetaStrategy: address) <<onlyGovernor>> <<VaultAdmin>> +    pauseRebase() <<onlyGovernorOrStrategist>> <<VaultAdmin>> +    unpauseRebase() <<onlyGovernorOrStrategist>> <<VaultAdmin>> +    pauseCapital() <<onlyGovernorOrStrategist>> <<VaultAdmin>> +    unpauseCapital() <<onlyGovernorOrStrategist>> <<VaultAdmin>> +    transferToken(_asset: address, _amount: uint256) <<onlyGovernor>> <<VaultAdmin>> +    withdrawAllFromStrategy(_strategyAddr: address) <<onlyGovernorOrStrategist>> <<VaultAdmin>> +    withdrawAllFromStrategies() <<onlyGovernorOrStrategist>> <<VaultAdmin>> +Public: +    <<event>> PendingGovernorshipTransfer(previousGovernor: address, newGovernor: address) <<Governable>> +    <<event>> GovernorshipTransferred(previousGovernor: address, newGovernor: address) <<Governable>> +    <<event>> AssetSupported(_asset: address) <<VaultStorage>> +    <<event>> AssetDefaultStrategyUpdated(_asset: address, _strategy: address) <<VaultStorage>> +    <<event>> AssetAllocated(_asset: address, _strategy: address, _amount: uint256) <<VaultStorage>> +    <<event>> StrategyApproved(_addr: address) <<VaultStorage>> +    <<event>> StrategyRemoved(_addr: address) <<VaultStorage>> +    <<event>> Mint(_addr: address, _value: uint256) <<VaultStorage>> +    <<event>> Redeem(_addr: address, _value: uint256) <<VaultStorage>> +    <<event>> CapitalPaused() <<VaultStorage>> +    <<event>> CapitalUnpaused() <<VaultStorage>> +    <<event>> RebasePaused() <<VaultStorage>> +    <<event>> RebaseUnpaused() <<VaultStorage>> +    <<event>> VaultBufferUpdated(_vaultBuffer: uint256) <<VaultStorage>> +    <<event>> OusdMetaStrategyUpdated(_ousdMetaStrategy: address) <<VaultStorage>> +    <<event>> RedeemFeeUpdated(_redeemFeeBps: uint256) <<VaultStorage>> +    <<event>> PriceProviderUpdated(_priceProvider: address) <<VaultStorage>> +    <<event>> AllocateThresholdUpdated(_threshold: uint256) <<VaultStorage>> +    <<event>> RebaseThresholdUpdated(_threshold: uint256) <<VaultStorage>> +    <<event>> StrategistUpdated(_address: address) <<VaultStorage>> +    <<event>> MaxSupplyDiffChanged(maxSupplyDiff: uint256) <<VaultStorage>> +    <<event>> YieldDistribution(_to: address, _yield: uint256, _fee: uint256) <<VaultStorage>> +    <<event>> TrusteeFeeBpsChanged(_basis: uint256) <<VaultStorage>> +    <<event>> TrusteeAddressChanged(_address: address) <<VaultStorage>> +    <<event>> NetOusdMintForStrategyThresholdChanged(_threshold: uint256) <<VaultStorage>> +    <<event>> SwapperChanged(_address: address) <<VaultStorage>> +    <<event>> SwapAllowedUndervalueChanged(_basis: uint256) <<VaultStorage>> +    <<event>> SwapSlippageChanged(_asset: address, _basis: uint256) <<VaultStorage>> +    <<event>> Swapped(_fromAsset: address, _toAsset: address, _fromAssetAmount: uint256, _toAssetAmount: uint256) <<VaultStorage>> +    <<event>> DripperChanged(_dripper: address) <<VaultStorage>>    <<modifier>> initializer() <<Initializable>>    <<modifier>> onlyGovernor() <<Governable>>    <<modifier>> nonReentrant() <<Governable>> diff --git a/contracts/docs/OETHVaultCoreSquashed.svg b/contracts/docs/OETHVaultCoreSquashed.svg index e2dbd8c5ef..364df560e0 100644 --- a/contracts/docs/OETHVaultCoreSquashed.svg +++ b/contracts/docs/OETHVaultCoreSquashed.svg @@ -4,143 +4,152 @@ - - + + UmlClassDiagram - - + + -201 - -OETHVaultCore -../contracts/vault/OETHVaultCore.sol - -Private: -   initialized: bool <<Initializable>> -   initializing: bool <<Initializable>> -   ______gap: uint256[50] <<Initializable>> -   governorPosition: bytes32 <<Governable>> -   pendingGovernorPosition: bytes32 <<Governable>> -   reentryStatusPosition: bytes32 <<Governable>> -   _deprecated_rebaseHooksAddr: address <<VaultStorage>> -   _deprecated_uniswapAddr: address <<VaultStorage>> -   _deprecated_swapTokens: address[] <<VaultStorage>> -Internal: -   assets: mapping(address=>Asset) <<VaultStorage>> -   allAssets: address[] <<VaultStorage>> -   strategies: mapping(address=>Strategy) <<VaultStorage>> -   allStrategies: address[] <<VaultStorage>> -   oUSD: OUSD <<VaultStorage>> -   swapConfig: SwapConfig <<VaultStorage>> -   MAX_INT: uint256 <<VaultCore>> -   MAX_UINT: uint256 <<VaultCore>> -Public: -   _NOT_ENTERED: uint256 <<Governable>> -   _ENTERED: uint256 <<Governable>> -   priceProvider: address <<VaultStorage>> -   rebasePaused: bool <<VaultStorage>> -   capitalPaused: bool <<VaultStorage>> -   redeemFeeBps: uint256 <<VaultStorage>> -   vaultBuffer: uint256 <<VaultStorage>> -   autoAllocateThreshold: uint256 <<VaultStorage>> -   rebaseThreshold: uint256 <<VaultStorage>> -   adminImplPosition: bytes32 <<VaultStorage>> -   strategistAddr: address <<VaultStorage>> -   assetDefaultStrategies: mapping(address=>address) <<VaultStorage>> -   maxSupplyDiff: uint256 <<VaultStorage>> -   trusteeAddress: address <<VaultStorage>> -   trusteeFeeBps: uint256 <<VaultStorage>> -   MINT_MINIMUM_UNIT_PRICE: uint256 <<VaultStorage>> -   ousdMetaStrategy: address <<VaultStorage>> -   netOusdMintedForStrategy: int256 <<VaultStorage>> -   netOusdMintForStrategyThreshold: uint256 <<VaultStorage>> -   MIN_UNIT_PRICE_DRIFT: uint256 <<VaultStorage>> -   MAX_UNIT_PRICE_DRIFT: uint256 <<VaultStorage>> - -Private: -    abs(x: int256): uint256 <<VaultCore>> -Internal: -    _governor(): (governorOut: address) <<Governable>> -    _pendingGovernor(): (pendingGovernor: address) <<Governable>> -    _setGovernor(newGovernor: address) <<Governable>> -    _setPendingGovernor(newGovernor: address) <<Governable>> -    _changeGovernor(_newGovernor: address) <<Governable>> -    _redeem(_amount: uint256, _minimumUnitAmount: uint256) <<VaultCore>> -    _allocate() <<VaultCore>> -    _rebase(): uint256 <<whenNotRebasePaused>> <<VaultCore>> -    _totalValue(): (value: uint256) <<VaultCore>> -    _totalValueInVault(): (value: uint256) <<VaultCore>> -    _totalValueInStrategies(): (value: uint256) <<VaultCore>> -    _totalValueInStrategy(_strategyAddr: address): (value: uint256) <<VaultCore>> -    _checkBalance(_asset: address): (balance: uint256) <<VaultCore>> -    _calculateRedeemOutputs(_amount: uint256): (outputs: uint256[]) <<VaultCore>> -    _toUnits(_raw: uint256, _asset: address): uint256 <<VaultCore>> -    _toUnitPrice(_asset: address, isMint: bool): (price: uint256) <<VaultCore>> -    _getDecimals(_asset: address): (decimals: uint256) <<VaultCore>> -External: -    <<payable>> null() <<VaultCore>> -    transferGovernance(_newGovernor: address) <<onlyGovernor>> <<Governable>> -    claimGovernance() <<Governable>> -    setAdminImpl(newImpl: address) <<onlyGovernor>> <<VaultStorage>> -    initialize(_priceProvider: address, _oToken: address) <<onlyGovernor, initializer>> <<VaultInitializer>> -    mint(_asset: address, _amount: uint256, _minimumOusdAmount: uint256) <<whenNotCapitalPaused, nonReentrant>> <<VaultCore>> -    mintForStrategy(_amount: uint256) <<whenNotCapitalPaused, onlyOusdMetaStrategy>> <<VaultCore>> -    redeem(_amount: uint256, _minimumUnitAmount: uint256) <<whenNotCapitalPaused, nonReentrant>> <<VaultCore>> -    burnForStrategy(_amount: uint256) <<whenNotCapitalPaused, onlyOusdMetaStrategy>> <<VaultCore>> -    redeemAll(_minimumUnitAmount: uint256) <<whenNotCapitalPaused, nonReentrant>> <<VaultCore>> -    allocate() <<whenNotCapitalPaused, nonReentrant>> <<VaultCore>> -    rebase() <<nonReentrant>> <<VaultCore>> -    totalValue(): (value: uint256) <<VaultCore>> -    checkBalance(_asset: address): uint256 <<VaultCore>> -    calculateRedeemOutputs(_amount: uint256): uint256[] <<VaultCore>> -    priceUnitMint(asset: address): (price: uint256) <<VaultCore>> -    priceUnitRedeem(asset: address): (price: uint256) <<VaultCore>> -    getAllAssets(): address[] <<VaultCore>> -    getStrategyCount(): uint256 <<VaultCore>> -    getAllStrategies(): address[] <<VaultCore>> -    isSupportedAsset(_asset: address): bool <<VaultCore>> -Public: -    <<event>> PendingGovernorshipTransfer(previousGovernor: address, newGovernor: address) <<Governable>> -    <<event>> GovernorshipTransferred(previousGovernor: address, newGovernor: address) <<Governable>> -    <<event>> AssetSupported(_asset: address) <<VaultStorage>> -    <<event>> AssetDefaultStrategyUpdated(_asset: address, _strategy: address) <<VaultStorage>> -    <<event>> AssetAllocated(_asset: address, _strategy: address, _amount: uint256) <<VaultStorage>> -    <<event>> StrategyApproved(_addr: address) <<VaultStorage>> -    <<event>> StrategyRemoved(_addr: address) <<VaultStorage>> -    <<event>> Mint(_addr: address, _value: uint256) <<VaultStorage>> -    <<event>> Redeem(_addr: address, _value: uint256) <<VaultStorage>> -    <<event>> CapitalPaused() <<VaultStorage>> -    <<event>> CapitalUnpaused() <<VaultStorage>> -    <<event>> RebasePaused() <<VaultStorage>> -    <<event>> RebaseUnpaused() <<VaultStorage>> -    <<event>> VaultBufferUpdated(_vaultBuffer: uint256) <<VaultStorage>> -    <<event>> OusdMetaStrategyUpdated(_ousdMetaStrategy: address) <<VaultStorage>> -    <<event>> RedeemFeeUpdated(_redeemFeeBps: uint256) <<VaultStorage>> -    <<event>> PriceProviderUpdated(_priceProvider: address) <<VaultStorage>> -    <<event>> AllocateThresholdUpdated(_threshold: uint256) <<VaultStorage>> -    <<event>> RebaseThresholdUpdated(_threshold: uint256) <<VaultStorage>> -    <<event>> StrategistUpdated(_address: address) <<VaultStorage>> -    <<event>> MaxSupplyDiffChanged(maxSupplyDiff: uint256) <<VaultStorage>> -    <<event>> YieldDistribution(_to: address, _yield: uint256, _fee: uint256) <<VaultStorage>> -    <<event>> TrusteeFeeBpsChanged(_basis: uint256) <<VaultStorage>> -    <<event>> TrusteeAddressChanged(_address: address) <<VaultStorage>> -    <<event>> NetOusdMintForStrategyThresholdChanged(_threshold: uint256) <<VaultStorage>> -    <<event>> SwapperChanged(_address: address) <<VaultStorage>> -    <<event>> SwapAllowedUndervalueChanged(_basis: uint256) <<VaultStorage>> -    <<event>> SwapSlippageChanged(_asset: address, _basis: uint256) <<VaultStorage>> -    <<event>> Swapped(_fromAsset: address, _toAsset: address, _fromAssetAmount: uint256, _toAssetAmount: uint256) <<VaultStorage>> -    <<modifier>> initializer() <<Initializable>> -    <<modifier>> onlyGovernor() <<Governable>> -    <<modifier>> nonReentrant() <<Governable>> -    <<modifier>> whenNotRebasePaused() <<VaultCore>> -    <<modifier>> whenNotCapitalPaused() <<VaultCore>> -    <<modifier>> onlyOusdMetaStrategy() <<VaultCore>> -    constructor() <<Governable>> -    governor(): address <<Governable>> -    isGovernor(): bool <<Governable>> -    getAssetCount(): uint256 <<VaultCore>> -    getAssetConfig(_asset: address): (config: Asset) <<VaultCore>> +220 + +OETHVaultCore +../contracts/vault/OETHVaultCore.sol + +Private: +   initialized: bool <<Initializable>> +   initializing: bool <<Initializable>> +   ______gap: uint256[50] <<Initializable>> +   governorPosition: bytes32 <<Governable>> +   pendingGovernorPosition: bytes32 <<Governable>> +   reentryStatusPosition: bytes32 <<Governable>> +   _deprecated_rebaseHooksAddr: address <<VaultStorage>> +   _deprecated_uniswapAddr: address <<VaultStorage>> +   _deprecated_swapTokens: address[] <<VaultStorage>> +   __gap: uint256[49] <<VaultStorage>> +Internal: +   assets: mapping(address=>Asset) <<VaultStorage>> +   allAssets: address[] <<VaultStorage>> +   strategies: mapping(address=>Strategy) <<VaultStorage>> +   allStrategies: address[] <<VaultStorage>> +   oUSD: OUSD <<VaultStorage>> +   swapConfig: SwapConfig <<VaultStorage>> +   MAX_INT: uint256 <<VaultCore>> +   MAX_UINT: uint256 <<VaultCore>> +Public: +   _NOT_ENTERED: uint256 <<Governable>> +   _ENTERED: uint256 <<Governable>> +   priceProvider: address <<VaultStorage>> +   rebasePaused: bool <<VaultStorage>> +   capitalPaused: bool <<VaultStorage>> +   redeemFeeBps: uint256 <<VaultStorage>> +   vaultBuffer: uint256 <<VaultStorage>> +   autoAllocateThreshold: uint256 <<VaultStorage>> +   rebaseThreshold: uint256 <<VaultStorage>> +   adminImplPosition: bytes32 <<VaultStorage>> +   strategistAddr: address <<VaultStorage>> +   assetDefaultStrategies: mapping(address=>address) <<VaultStorage>> +   maxSupplyDiff: uint256 <<VaultStorage>> +   trusteeAddress: address <<VaultStorage>> +   trusteeFeeBps: uint256 <<VaultStorage>> +   MINT_MINIMUM_UNIT_PRICE: uint256 <<VaultStorage>> +   ousdMetaStrategy: address <<VaultStorage>> +   netOusdMintedForStrategy: int256 <<VaultStorage>> +   netOusdMintForStrategyThreshold: uint256 <<VaultStorage>> +   MIN_UNIT_PRICE_DRIFT: uint256 <<VaultStorage>> +   MAX_UNIT_PRICE_DRIFT: uint256 <<VaultStorage>> +   dripper: address <<VaultStorage>> +   weth: address <<OETHVaultCore>> +   wethAssetIndex: uint256 <<OETHVaultCore>> + +Private: +    abs(x: int256): uint256 <<VaultCore>> +Internal: +    _governor(): (governorOut: address) <<Governable>> +    _pendingGovernor(): (pendingGovernor: address) <<Governable>> +    _setGovernor(newGovernor: address) <<Governable>> +    _setPendingGovernor(newGovernor: address) <<Governable>> +    _changeGovernor(_newGovernor: address) <<Governable>> +    _mint(_asset: address, _amount: uint256, _minimumOusdAmount: uint256) <<OETHVaultCore>> +    _redeem(_amount: uint256, _minimumUnitAmount: uint256) <<OETHVaultCore>> +    _postRedeem(_amount: uint256) <<VaultCore>> +    _allocate() <<VaultCore>> +    _rebase(): uint256 <<whenNotRebasePaused>> <<VaultCore>> +    _totalValue(): (value: uint256) <<VaultCore>> +    _totalValueInVault(): (value: uint256) <<VaultCore>> +    _totalValueInStrategies(): (value: uint256) <<VaultCore>> +    _totalValueInStrategy(_strategyAddr: address): (value: uint256) <<VaultCore>> +    _checkBalance(_asset: address): (balance: uint256) <<VaultCore>> +    _calculateRedeemOutputs(_amount: uint256): (outputs: uint256[]) <<OETHVaultCore>> +    _toUnits(_raw: uint256, _asset: address): uint256 <<VaultCore>> +    _toUnitPrice(_asset: address, isMint: bool): (price: uint256) <<VaultCore>> +    _getDecimals(_asset: address): (decimals: uint256) <<VaultCore>> +External: +    transferGovernance(_newGovernor: address) <<onlyGovernor>> <<Governable>> +    claimGovernance() <<Governable>> +    setAdminImpl(newImpl: address) <<onlyGovernor>> <<VaultStorage>> +    initialize(_priceProvider: address, _oToken: address) <<onlyGovernor, initializer>> <<VaultInitializer>> +    mint(_asset: address, _amount: uint256, _minimumOusdAmount: uint256) <<whenNotCapitalPaused, nonReentrant>> <<VaultCore>> +    mintForStrategy(_amount: uint256) <<whenNotCapitalPaused, onlyOusdMetaStrategy>> <<VaultCore>> +    redeem(_amount: uint256, _minimumUnitAmount: uint256) <<whenNotCapitalPaused, nonReentrant>> <<VaultCore>> +    burnForStrategy(_amount: uint256) <<whenNotCapitalPaused, onlyOusdMetaStrategy>> <<VaultCore>> +    redeemAll(_minimumUnitAmount: uint256) <<whenNotCapitalPaused, nonReentrant>> <<VaultCore>> +    allocate() <<whenNotCapitalPaused, nonReentrant>> <<VaultCore>> +    rebase() <<nonReentrant>> <<VaultCore>> +    totalValue(): (value: uint256) <<VaultCore>> +    checkBalance(_asset: address): uint256 <<VaultCore>> +    calculateRedeemOutputs(_amount: uint256): uint256[] <<VaultCore>> +    priceUnitMint(asset: address): (price: uint256) <<VaultCore>> +    priceUnitRedeem(asset: address): (price: uint256) <<VaultCore>> +    getAllAssets(): address[] <<VaultCore>> +    getStrategyCount(): uint256 <<VaultCore>> +    getAllStrategies(): address[] <<VaultCore>> +    isSupportedAsset(_asset: address): bool <<VaultCore>> +    null() <<VaultCore>> +    cacheWETHAssetIndex() <<onlyGovernor>> <<OETHVaultCore>> +Public: +    <<event>> PendingGovernorshipTransfer(previousGovernor: address, newGovernor: address) <<Governable>> +    <<event>> GovernorshipTransferred(previousGovernor: address, newGovernor: address) <<Governable>> +    <<event>> AssetSupported(_asset: address) <<VaultStorage>> +    <<event>> AssetDefaultStrategyUpdated(_asset: address, _strategy: address) <<VaultStorage>> +    <<event>> AssetAllocated(_asset: address, _strategy: address, _amount: uint256) <<VaultStorage>> +    <<event>> StrategyApproved(_addr: address) <<VaultStorage>> +    <<event>> StrategyRemoved(_addr: address) <<VaultStorage>> +    <<event>> Mint(_addr: address, _value: uint256) <<VaultStorage>> +    <<event>> Redeem(_addr: address, _value: uint256) <<VaultStorage>> +    <<event>> CapitalPaused() <<VaultStorage>> +    <<event>> CapitalUnpaused() <<VaultStorage>> +    <<event>> RebasePaused() <<VaultStorage>> +    <<event>> RebaseUnpaused() <<VaultStorage>> +    <<event>> VaultBufferUpdated(_vaultBuffer: uint256) <<VaultStorage>> +    <<event>> OusdMetaStrategyUpdated(_ousdMetaStrategy: address) <<VaultStorage>> +    <<event>> RedeemFeeUpdated(_redeemFeeBps: uint256) <<VaultStorage>> +    <<event>> PriceProviderUpdated(_priceProvider: address) <<VaultStorage>> +    <<event>> AllocateThresholdUpdated(_threshold: uint256) <<VaultStorage>> +    <<event>> RebaseThresholdUpdated(_threshold: uint256) <<VaultStorage>> +    <<event>> StrategistUpdated(_address: address) <<VaultStorage>> +    <<event>> MaxSupplyDiffChanged(maxSupplyDiff: uint256) <<VaultStorage>> +    <<event>> YieldDistribution(_to: address, _yield: uint256, _fee: uint256) <<VaultStorage>> +    <<event>> TrusteeFeeBpsChanged(_basis: uint256) <<VaultStorage>> +    <<event>> TrusteeAddressChanged(_address: address) <<VaultStorage>> +    <<event>> NetOusdMintForStrategyThresholdChanged(_threshold: uint256) <<VaultStorage>> +    <<event>> SwapperChanged(_address: address) <<VaultStorage>> +    <<event>> SwapAllowedUndervalueChanged(_basis: uint256) <<VaultStorage>> +    <<event>> SwapSlippageChanged(_asset: address, _basis: uint256) <<VaultStorage>> +    <<event>> Swapped(_fromAsset: address, _toAsset: address, _fromAssetAmount: uint256, _toAssetAmount: uint256) <<VaultStorage>> +    <<event>> DripperChanged(_dripper: address) <<VaultStorage>> +    <<modifier>> initializer() <<Initializable>> +    <<modifier>> onlyGovernor() <<Governable>> +    <<modifier>> nonReentrant() <<Governable>> +    <<modifier>> whenNotRebasePaused() <<VaultCore>> +    <<modifier>> whenNotCapitalPaused() <<VaultCore>> +    <<modifier>> onlyOusdMetaStrategy() <<VaultCore>> +    constructor() <<Governable>> +    governor(): address <<Governable>> +    isGovernor(): bool <<Governable>> +    getAssetCount(): uint256 <<VaultCore>> +    getAssetConfig(_asset: address): (config: Asset) <<VaultCore>> +    constructor(_weth: address) <<OETHVaultCore>> diff --git a/contracts/docs/OETHVaultHierarchy.svg b/contracts/docs/OETHVaultHierarchy.svg index 6e3546cc1d..c49d1de411 100644 --- a/contracts/docs/OETHVaultHierarchy.svg +++ b/contracts/docs/OETHVaultHierarchy.svg @@ -4,268 +4,294 @@ - + UmlClassDiagram - + 20 - -Governable -../contracts/governance/Governable.sol + +Governable +../contracts/governance/Governable.sol - + -42 - -<<Interface>> -IGetExchangeRateToken -../contracts/interfaces/IGetExchangeRateToken.sol +40 + +<<Interface>> +IDripper +../contracts/interfaces/IDripper.sol - + -48 - -<<Interface>> -IOracle -../contracts/interfaces/IOracle.sol +44 + +<<Interface>> +IGetExchangeRateToken +../contracts/interfaces/IGetExchangeRateToken.sol - + -52 - -<<Interface>> -IStrategy -../contracts/interfaces/IStrategy.sol +51 + +<<Interface>> +IOracle +../contracts/interfaces/IOracle.sol - + -53 - -<<Interface>> -ISwapper -../contracts/interfaces/ISwapper.sol +57 + +<<Interface>> +IStrategy +../contracts/interfaces/IStrategy.sol - + -55 - -<<Interface>> -IVault -../contracts/interfaces/IVault.sol +58 + +<<Interface>> +ISwapper +../contracts/interfaces/ISwapper.sol - - -207 - -VaultStorage -../contracts/vault/VaultStorage.sol + + +61 + +<<Interface>> +IVault +../contracts/interfaces/IVault.sol + + + +226 + +VaultStorage +../contracts/vault/VaultStorage.sol - + -55->207 - - +61->226 + + - - -186 - -OUSD -../contracts/token/OUSD.sol + + +205 + +OUSD +../contracts/token/OUSD.sol - + -186->20 - - +205->20 + + - - -194 - -<<Abstract>> -Initializable -../contracts/utils/Initializable.sol + + +213 + +<<Abstract>> +Initializable +../contracts/utils/Initializable.sol - + -186->194 - - +205->213 + + - - -197 - -<<Abstract>> -InitializableERC20Detailed -../contracts/utils/InitializableERC20Detailed.sol + + +216 + +<<Abstract>> +InitializableERC20Detailed +../contracts/utils/InitializableERC20Detailed.sol - + -186->197 - - - - - -392 - -<<Interface>> -IERC20 -../node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol - - +205->216 + + + + + +695 + +<<Interface>> +IERC20 +../node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol + + -197->392 - - +216->695 + + - - -200 - -OETHVaultAdmin -../contracts/vault/OETHVaultAdmin.sol + + +219 + +OETHVaultAdmin +../contracts/vault/OETHVaultAdmin.sol - - -204 - -VaultAdmin -../contracts/vault/VaultAdmin.sol + + +223 + +VaultAdmin +../contracts/vault/VaultAdmin.sol - + -200->204 - - +219->223 + + - - -201 - -OETHVaultCore -../contracts/vault/OETHVaultCore.sol + + +220 + +OETHVaultCore +../contracts/vault/OETHVaultCore.sol - - -205 - -VaultCore -../contracts/vault/VaultCore.sol + + +220->57 + + - + + +224 + +VaultCore +../contracts/vault/VaultCore.sol + + -201->205 - - +220->224 + + - - -204->48 - - + + +220->695 + + - - -204->52 - - + + +223->51 + + - + -204->53 - - +223->57 + + - + -204->55 - - +223->58 + + - - -204->207 - - + + +223->61 + + - + -204->392 - - +223->226 + + - - -205->42 - - + + +223->695 + + - + -205->48 - - - - - -205->52 - - - - - -206 - -VaultInitializer -../contracts/vault/VaultInitializer.sol +224->40 + + - - -205->206 - - - - - -205->392 - - + + +224->44 + + - + -206->186 - - +224->51 + + - + -206->207 - - +224->57 + + - - -207->20 - - + + +225 + +VaultInitializer +../contracts/vault/VaultInitializer.sol - + + +224->225 + + + + + +224->695 + + + + -207->186 - - +225->205 + + - - -207->194 - - + + +225->226 + + + + + +226->20 + + + + + +226->205 + + + + + +226->213 + + diff --git a/contracts/docs/OETHVaultStorage.svg b/contracts/docs/OETHVaultStorage.svg index c950373509..48115ee9f1 100644 --- a/contracts/docs/OETHVaultStorage.svg +++ b/contracts/docs/OETHVaultStorage.svg @@ -4,262 +4,312 @@ - - + + StorageDiagram - - + + -6 - -OETHVaultCore <<Contract>> - -slot - -0 - -1-50 - -51 - -52 - -53 - -54 - -55 - -56 - -57 - -58 - -59 - -60 - -61 - -62 - -63 - -64 - -65 - -66 - -67 - -68 - -69 - -70 - -71 - -72 - -type: <inherited contract>.variable (bytes) - -unallocated (30) - -bool: Initializable.initializing (1) - -bool: Initializable.initialized (1) - -uint256[50]: Initializable.______gap (1600) - -mapping(address=>Asset): VaultStorage.assets (32) - -address[]: VaultStorage.allAssets (32) - -mapping(address=>Strategy): VaultStorage.strategies (32) - -address[]: VaultStorage.allStrategies (32) - -unallocated (10) - -bool: VaultStorage.capitalPaused (1) - -bool: VaultStorage.rebasePaused (1) - -address: VaultStorage.priceProvider (20) - -uint256: VaultStorage.redeemFeeBps (32) - -uint256: VaultStorage.vaultBuffer (32) - -uint256: VaultStorage.autoAllocateThreshold (32) - -uint256: VaultStorage.rebaseThreshold (32) - -unallocated (12) - -OUSD: VaultStorage.oUSD (20) - -unallocated (12) - -address: VaultStorage._deprecated_rebaseHooksAddr (20) - -unallocated (12) - -address: VaultStorage._deprecated_uniswapAddr (20) - -unallocated (12) - -address: VaultStorage.strategistAddr (20) - -mapping(address=>address): VaultStorage.assetDefaultStrategies (32) - -uint256: VaultStorage.maxSupplyDiff (32) - -unallocated (12) - -address: VaultStorage.trusteeAddress (20) - -uint256: VaultStorage.trusteeFeeBps (32) - -address[]: VaultStorage._deprecated_swapTokens (32) - -unallocated (12) - -address: VaultStorage.ousdMetaStrategy (20) - -int256: VaultStorage.netOusdMintedForStrategy (32) - -uint256: VaultStorage.netOusdMintForStrategyThreshold (32) - -SwapConfig: VaultStorage.swapConfig (32) +7 + +OETHVaultCore <<Contract>> + +slot + +0 + +1-50 + +51 + +52 + +53 + +54 + +55 + +56 + +57 + +58 + +59 + +60 + +61 + +62 + +63 + +64 + +65 + +66 + +67 + +68 + +69 + +70 + +71 + +72 + +73 + +74-122 + +123 + +type: <inherited contract>.variable (bytes) + +unallocated (30) + +bool: Initializable.initializing (1) + +bool: Initializable.initialized (1) + +uint256[50]: Initializable.______gap (1600) + +mapping(address=>Asset): VaultStorage.assets (32) + +address[]: VaultStorage.allAssets (32) + +mapping(address=>Strategy): VaultStorage.strategies (32) + +address[]: VaultStorage.allStrategies (32) + +unallocated (10) + +bool: VaultStorage.capitalPaused (1) + +bool: VaultStorage.rebasePaused (1) + +address: VaultStorage.priceProvider (20) + +uint256: VaultStorage.redeemFeeBps (32) + +uint256: VaultStorage.vaultBuffer (32) + +uint256: VaultStorage.autoAllocateThreshold (32) + +uint256: VaultStorage.rebaseThreshold (32) + +unallocated (12) + +OUSD: VaultStorage.oUSD (20) + +unallocated (12) + +address: VaultStorage._deprecated_rebaseHooksAddr (20) + +unallocated (12) + +address: VaultStorage._deprecated_uniswapAddr (20) + +unallocated (12) + +address: VaultStorage.strategistAddr (20) + +mapping(address=>address): VaultStorage.assetDefaultStrategies (32) + +uint256: VaultStorage.maxSupplyDiff (32) + +unallocated (12) + +address: VaultStorage.trusteeAddress (20) + +uint256: VaultStorage.trusteeFeeBps (32) + +address[]: VaultStorage._deprecated_swapTokens (32) + +unallocated (12) + +address: VaultStorage.ousdMetaStrategy (20) + +int256: VaultStorage.netOusdMintedForStrategy (32) + +uint256: VaultStorage.netOusdMintForStrategyThreshold (32) + +SwapConfig: VaultStorage.swapConfig (32) + +unallocated (12) + +address: VaultStorage.dripper (20) + +uint256[49]: VaultStorage.__gap (1568) + +uint256: wethAssetIndex (32) 1 - -Asset <<Struct>> - -offset - -0 - -type: variable (bytes) - -unallocated (27) - -uint16: allowedOracleSlippageBps (2) - -uint8: decimals (1) - -UnitConversion: unitConversion (1) - -bool: isSupported (1) + +Asset <<Struct>> + +offset + +0 + +type: variable (bytes) + +unallocated (27) + +uint16: allowedOracleSlippageBps (2) + +uint8: decimals (1) + +UnitConversion: unitConversion (1) + +bool: isSupported (1) - + -6:8->1 - - +7:8->1 + + 2 - -address[]: allAssets <<Array>> -0x46bddb1178e94d7f2892ff5f366840eb658911794f2c3a44c450aa2c505186c1 - -offset - -0 - -type: variable (bytes) - -unallocated (12) - -address (20) + +address[]: allAssets <<Array>> +0x46bddb1178e94d7f2892ff5f366840eb658911794f2c3a44c450aa2c505186c1 + +offset + +0 + +type: variable (bytes) + +unallocated (12) + +address (20) - + -6:10->2 - - +7:10->2 + + 3 - -Strategy <<Struct>> - -offset - -0 - -1 - -type: variable (bytes) - -unallocated (31) - -bool: isSupported (1) - -uint256: _deprecated (32) + +Strategy <<Struct>> + +offset + +0 + +1 + +type: variable (bytes) + +unallocated (31) + +bool: isSupported (1) + +uint256: _deprecated (32) - + -6:13->3 - - +7:13->3 + + 4 - -address[]: allStrategies <<Array>> -0x4a11f94e20a93c79f6ec743a1954ec4fc2c08429ae2122118bf234b2185c81b8 - -offset - -0 - -type: variable (bytes) - -unallocated (12) - -address (20) + +address[]: allStrategies <<Array>> +0x4a11f94e20a93c79f6ec743a1954ec4fc2c08429ae2122118bf234b2185c81b8 + +offset + +0 + +type: variable (bytes) + +unallocated (12) + +address (20) - + -6:15->4 - - +7:15->4 + + 5 - -SwapConfig <<Struct>> - -slot - -72 - -type: variable (bytes) - -unallocated (10) - -uint16: allowedUndervalueBps (2) - -address: swapper (20) + +SwapConfig <<Struct>> + +slot + +72 + +type: variable (bytes) + +unallocated (10) + +uint16: allowedUndervalueBps (2) + +address: swapper (20) - + -6:37->5 - - +7:37->5 + + + + + +6 + +uint256[49]: __gap <<Array>> + +slot + +74 + +75 + +76-120 + +121 + +122 + +type: variable (bytes) + +uint256 (32) + +uint256 (32) + +---- (1440) + +uint256 (32) + +uint256 (32) + + + +7:44->6 + + diff --git a/contracts/docs/VaultAdminSquashed.svg b/contracts/docs/VaultAdminSquashed.svg index 939e2c043f..8dbca545e8 100644 --- a/contracts/docs/VaultAdminSquashed.svg +++ b/contracts/docs/VaultAdminSquashed.svg @@ -4,132 +4,136 @@ - - + + UmlClassDiagram - - + + -204 - -VaultAdmin -../contracts/vault/VaultAdmin.sol - -Private: -   initialized: bool <<Initializable>> -   initializing: bool <<Initializable>> -   ______gap: uint256[50] <<Initializable>> -   governorPosition: bytes32 <<Governable>> -   pendingGovernorPosition: bytes32 <<Governable>> -   reentryStatusPosition: bytes32 <<Governable>> -   _deprecated_rebaseHooksAddr: address <<VaultStorage>> -   _deprecated_uniswapAddr: address <<VaultStorage>> -   _deprecated_swapTokens: address[] <<VaultStorage>> -Internal: -   assets: mapping(address=>Asset) <<VaultStorage>> -   allAssets: address[] <<VaultStorage>> -   strategies: mapping(address=>Strategy) <<VaultStorage>> -   allStrategies: address[] <<VaultStorage>> -   oUSD: OUSD <<VaultStorage>> -   swapConfig: SwapConfig <<VaultStorage>> -Public: -   _NOT_ENTERED: uint256 <<Governable>> -   _ENTERED: uint256 <<Governable>> -   priceProvider: address <<VaultStorage>> -   rebasePaused: bool <<VaultStorage>> -   capitalPaused: bool <<VaultStorage>> -   redeemFeeBps: uint256 <<VaultStorage>> -   vaultBuffer: uint256 <<VaultStorage>> -   autoAllocateThreshold: uint256 <<VaultStorage>> -   rebaseThreshold: uint256 <<VaultStorage>> -   adminImplPosition: bytes32 <<VaultStorage>> -   strategistAddr: address <<VaultStorage>> -   assetDefaultStrategies: mapping(address=>address) <<VaultStorage>> -   maxSupplyDiff: uint256 <<VaultStorage>> -   trusteeAddress: address <<VaultStorage>> -   trusteeFeeBps: uint256 <<VaultStorage>> -   MINT_MINIMUM_UNIT_PRICE: uint256 <<VaultStorage>> -   ousdMetaStrategy: address <<VaultStorage>> -   netOusdMintedForStrategy: int256 <<VaultStorage>> -   netOusdMintForStrategyThreshold: uint256 <<VaultStorage>> -   MIN_UNIT_PRICE_DRIFT: uint256 <<VaultStorage>> -   MAX_UNIT_PRICE_DRIFT: uint256 <<VaultStorage>> - -Internal: -    _governor(): (governorOut: address) <<Governable>> -    _pendingGovernor(): (pendingGovernor: address) <<Governable>> -    _setGovernor(newGovernor: address) <<Governable>> -    _setPendingGovernor(newGovernor: address) <<Governable>> -    _changeGovernor(_newGovernor: address) <<Governable>> -    _depositToStrategy(_strategyToAddress: address, _assets: address[], _amounts: uint256[]) <<VaultAdmin>> -    _withdrawFromStrategy(_recipient: address, _strategyFromAddress: address, _assets: address[], _amounts: uint256[]) <<VaultAdmin>> -    _cacheDecimals(token: address) <<VaultAdmin>> -External: -    transferGovernance(_newGovernor: address) <<onlyGovernor>> <<Governable>> -    claimGovernance() <<Governable>> -    setAdminImpl(newImpl: address) <<onlyGovernor>> <<VaultStorage>> -    setPriceProvider(_priceProvider: address) <<onlyGovernor>> <<VaultAdmin>> -    setRedeemFeeBps(_redeemFeeBps: uint256) <<onlyGovernor>> <<VaultAdmin>> -    setVaultBuffer(_vaultBuffer: uint256) <<onlyGovernorOrStrategist>> <<VaultAdmin>> -    setAutoAllocateThreshold(_threshold: uint256) <<onlyGovernor>> <<VaultAdmin>> -    setRebaseThreshold(_threshold: uint256) <<onlyGovernor>> <<VaultAdmin>> -    setStrategistAddr(_address: address) <<onlyGovernor>> <<VaultAdmin>> -    setAssetDefaultStrategy(_asset: address, _strategy: address) <<onlyGovernorOrStrategist>> <<VaultAdmin>> -    setNetOusdMintForStrategyThreshold(_threshold: uint256) <<onlyGovernor>> <<VaultAdmin>> -    swapCollateral(_fromAsset: address, _toAsset: address, _fromAssetAmount: uint256, _minToAssetAmount: uint256, _data: bytes): (toAssetAmount: uint256) <<nonReentrant, onlyGovernorOrStrategist>> <<VaultAdmin>> -    setSwapper(_swapperAddr: address) <<onlyGovernor>> <<VaultAdmin>> -    swapper(): (swapper_: address) <<VaultAdmin>> -    setSwapAllowedUndervalue(_basis: uint16) <<onlyGovernor>> <<VaultAdmin>> -    allowedSwapUndervalue(): (value: uint256) <<VaultAdmin>> -    setOracleSlippage(_asset: address, _allowedOracleSlippageBps: uint16) <<onlyGovernor>> <<VaultAdmin>> -    supportAsset(_asset: address, _unitConversion: uint8) <<onlyGovernor>> <<VaultAdmin>> -    cacheDecimals(_asset: address) <<onlyGovernor>> <<VaultAdmin>> -    approveStrategy(_addr: address) <<onlyGovernor>> <<VaultAdmin>> -    removeStrategy(_addr: address) <<onlyGovernor>> <<VaultAdmin>> -    depositToStrategy(_strategyToAddress: address, _assets: address[], _amounts: uint256[]) <<onlyGovernorOrStrategist, nonReentrant>> <<VaultAdmin>> -    withdrawFromStrategy(_strategyFromAddress: address, _assets: address[], _amounts: uint256[]) <<onlyGovernorOrStrategist, nonReentrant>> <<VaultAdmin>> -    setMaxSupplyDiff(_maxSupplyDiff: uint256) <<onlyGovernor>> <<VaultAdmin>> -    setTrusteeAddress(_address: address) <<onlyGovernor>> <<VaultAdmin>> -    setTrusteeFeeBps(_basis: uint256) <<onlyGovernor>> <<VaultAdmin>> -    setOusdMetaStrategy(_ousdMetaStrategy: address) <<onlyGovernor>> <<VaultAdmin>> -    pauseRebase() <<onlyGovernorOrStrategist>> <<VaultAdmin>> -    unpauseRebase() <<onlyGovernorOrStrategist>> <<VaultAdmin>> -    pauseCapital() <<onlyGovernorOrStrategist>> <<VaultAdmin>> -    unpauseCapital() <<onlyGovernorOrStrategist>> <<VaultAdmin>> -    transferToken(_asset: address, _amount: uint256) <<onlyGovernor>> <<VaultAdmin>> -    withdrawAllFromStrategy(_strategyAddr: address) <<onlyGovernorOrStrategist>> <<VaultAdmin>> -    withdrawAllFromStrategies() <<onlyGovernorOrStrategist>> <<VaultAdmin>> -Public: -    <<event>> PendingGovernorshipTransfer(previousGovernor: address, newGovernor: address) <<Governable>> -    <<event>> GovernorshipTransferred(previousGovernor: address, newGovernor: address) <<Governable>> -    <<event>> AssetSupported(_asset: address) <<VaultStorage>> -    <<event>> AssetDefaultStrategyUpdated(_asset: address, _strategy: address) <<VaultStorage>> -    <<event>> AssetAllocated(_asset: address, _strategy: address, _amount: uint256) <<VaultStorage>> -    <<event>> StrategyApproved(_addr: address) <<VaultStorage>> -    <<event>> StrategyRemoved(_addr: address) <<VaultStorage>> -    <<event>> Mint(_addr: address, _value: uint256) <<VaultStorage>> -    <<event>> Redeem(_addr: address, _value: uint256) <<VaultStorage>> -    <<event>> CapitalPaused() <<VaultStorage>> -    <<event>> CapitalUnpaused() <<VaultStorage>> -    <<event>> RebasePaused() <<VaultStorage>> -    <<event>> RebaseUnpaused() <<VaultStorage>> -    <<event>> VaultBufferUpdated(_vaultBuffer: uint256) <<VaultStorage>> -    <<event>> OusdMetaStrategyUpdated(_ousdMetaStrategy: address) <<VaultStorage>> -    <<event>> RedeemFeeUpdated(_redeemFeeBps: uint256) <<VaultStorage>> -    <<event>> PriceProviderUpdated(_priceProvider: address) <<VaultStorage>> -    <<event>> AllocateThresholdUpdated(_threshold: uint256) <<VaultStorage>> -    <<event>> RebaseThresholdUpdated(_threshold: uint256) <<VaultStorage>> -    <<event>> StrategistUpdated(_address: address) <<VaultStorage>> -    <<event>> MaxSupplyDiffChanged(maxSupplyDiff: uint256) <<VaultStorage>> -    <<event>> YieldDistribution(_to: address, _yield: uint256, _fee: uint256) <<VaultStorage>> -    <<event>> TrusteeFeeBpsChanged(_basis: uint256) <<VaultStorage>> -    <<event>> TrusteeAddressChanged(_address: address) <<VaultStorage>> -    <<event>> NetOusdMintForStrategyThresholdChanged(_threshold: uint256) <<VaultStorage>> -    <<event>> SwapperChanged(_address: address) <<VaultStorage>> -    <<event>> SwapAllowedUndervalueChanged(_basis: uint256) <<VaultStorage>> -    <<event>> SwapSlippageChanged(_asset: address, _basis: uint256) <<VaultStorage>> -    <<event>> Swapped(_fromAsset: address, _toAsset: address, _fromAssetAmount: uint256, _toAssetAmount: uint256) <<VaultStorage>> +223 + +VaultAdmin +../contracts/vault/VaultAdmin.sol + +Private: +   initialized: bool <<Initializable>> +   initializing: bool <<Initializable>> +   ______gap: uint256[50] <<Initializable>> +   governorPosition: bytes32 <<Governable>> +   pendingGovernorPosition: bytes32 <<Governable>> +   reentryStatusPosition: bytes32 <<Governable>> +   _deprecated_rebaseHooksAddr: address <<VaultStorage>> +   _deprecated_uniswapAddr: address <<VaultStorage>> +   _deprecated_swapTokens: address[] <<VaultStorage>> +   __gap: uint256[49] <<VaultStorage>> +Internal: +   assets: mapping(address=>Asset) <<VaultStorage>> +   allAssets: address[] <<VaultStorage>> +   strategies: mapping(address=>Strategy) <<VaultStorage>> +   allStrategies: address[] <<VaultStorage>> +   oUSD: OUSD <<VaultStorage>> +   swapConfig: SwapConfig <<VaultStorage>> +Public: +   _NOT_ENTERED: uint256 <<Governable>> +   _ENTERED: uint256 <<Governable>> +   priceProvider: address <<VaultStorage>> +   rebasePaused: bool <<VaultStorage>> +   capitalPaused: bool <<VaultStorage>> +   redeemFeeBps: uint256 <<VaultStorage>> +   vaultBuffer: uint256 <<VaultStorage>> +   autoAllocateThreshold: uint256 <<VaultStorage>> +   rebaseThreshold: uint256 <<VaultStorage>> +   adminImplPosition: bytes32 <<VaultStorage>> +   strategistAddr: address <<VaultStorage>> +   assetDefaultStrategies: mapping(address=>address) <<VaultStorage>> +   maxSupplyDiff: uint256 <<VaultStorage>> +   trusteeAddress: address <<VaultStorage>> +   trusteeFeeBps: uint256 <<VaultStorage>> +   MINT_MINIMUM_UNIT_PRICE: uint256 <<VaultStorage>> +   ousdMetaStrategy: address <<VaultStorage>> +   netOusdMintedForStrategy: int256 <<VaultStorage>> +   netOusdMintForStrategyThreshold: uint256 <<VaultStorage>> +   MIN_UNIT_PRICE_DRIFT: uint256 <<VaultStorage>> +   MAX_UNIT_PRICE_DRIFT: uint256 <<VaultStorage>> +   dripper: address <<VaultStorage>> + +Internal: +    _governor(): (governorOut: address) <<Governable>> +    _pendingGovernor(): (pendingGovernor: address) <<Governable>> +    _setGovernor(newGovernor: address) <<Governable>> +    _setPendingGovernor(newGovernor: address) <<Governable>> +    _changeGovernor(_newGovernor: address) <<Governable>> +    _depositToStrategy(_strategyToAddress: address, _assets: address[], _amounts: uint256[]) <<VaultAdmin>> +    _withdrawFromStrategy(_recipient: address, _strategyFromAddress: address, _assets: address[], _amounts: uint256[]) <<VaultAdmin>> +    _cacheDecimals(token: address) <<VaultAdmin>> +External: +    transferGovernance(_newGovernor: address) <<onlyGovernor>> <<Governable>> +    claimGovernance() <<Governable>> +    setAdminImpl(newImpl: address) <<onlyGovernor>> <<VaultStorage>> +    setPriceProvider(_priceProvider: address) <<onlyGovernor>> <<VaultAdmin>> +    setRedeemFeeBps(_redeemFeeBps: uint256) <<onlyGovernor>> <<VaultAdmin>> +    setVaultBuffer(_vaultBuffer: uint256) <<onlyGovernorOrStrategist>> <<VaultAdmin>> +    setAutoAllocateThreshold(_threshold: uint256) <<onlyGovernor>> <<VaultAdmin>> +    setRebaseThreshold(_threshold: uint256) <<onlyGovernor>> <<VaultAdmin>> +    setStrategistAddr(_address: address) <<onlyGovernor>> <<VaultAdmin>> +    setAssetDefaultStrategy(_asset: address, _strategy: address) <<onlyGovernorOrStrategist>> <<VaultAdmin>> +    setDripper(_dripper: address) <<onlyGovernor>> <<VaultAdmin>> +    setNetOusdMintForStrategyThreshold(_threshold: uint256) <<onlyGovernor>> <<VaultAdmin>> +    swapCollateral(_fromAsset: address, _toAsset: address, _fromAssetAmount: uint256, _minToAssetAmount: uint256, _data: bytes): (toAssetAmount: uint256) <<nonReentrant, onlyGovernorOrStrategist>> <<VaultAdmin>> +    setSwapper(_swapperAddr: address) <<onlyGovernor>> <<VaultAdmin>> +    swapper(): (swapper_: address) <<VaultAdmin>> +    setSwapAllowedUndervalue(_basis: uint16) <<onlyGovernor>> <<VaultAdmin>> +    allowedSwapUndervalue(): (value: uint256) <<VaultAdmin>> +    setOracleSlippage(_asset: address, _allowedOracleSlippageBps: uint16) <<onlyGovernor>> <<VaultAdmin>> +    supportAsset(_asset: address, _unitConversion: uint8) <<onlyGovernor>> <<VaultAdmin>> +    cacheDecimals(_asset: address) <<onlyGovernor>> <<VaultAdmin>> +    approveStrategy(_addr: address) <<onlyGovernor>> <<VaultAdmin>> +    removeStrategy(_addr: address) <<onlyGovernor>> <<VaultAdmin>> +    depositToStrategy(_strategyToAddress: address, _assets: address[], _amounts: uint256[]) <<onlyGovernorOrStrategist, nonReentrant>> <<VaultAdmin>> +    withdrawFromStrategy(_strategyFromAddress: address, _assets: address[], _amounts: uint256[]) <<onlyGovernorOrStrategist, nonReentrant>> <<VaultAdmin>> +    setMaxSupplyDiff(_maxSupplyDiff: uint256) <<onlyGovernor>> <<VaultAdmin>> +    setTrusteeAddress(_address: address) <<onlyGovernor>> <<VaultAdmin>> +    setTrusteeFeeBps(_basis: uint256) <<onlyGovernor>> <<VaultAdmin>> +    setOusdMetaStrategy(_ousdMetaStrategy: address) <<onlyGovernor>> <<VaultAdmin>> +    pauseRebase() <<onlyGovernorOrStrategist>> <<VaultAdmin>> +    unpauseRebase() <<onlyGovernorOrStrategist>> <<VaultAdmin>> +    pauseCapital() <<onlyGovernorOrStrategist>> <<VaultAdmin>> +    unpauseCapital() <<onlyGovernorOrStrategist>> <<VaultAdmin>> +    transferToken(_asset: address, _amount: uint256) <<onlyGovernor>> <<VaultAdmin>> +    withdrawAllFromStrategy(_strategyAddr: address) <<onlyGovernorOrStrategist>> <<VaultAdmin>> +    withdrawAllFromStrategies() <<onlyGovernorOrStrategist>> <<VaultAdmin>> +Public: +    <<event>> PendingGovernorshipTransfer(previousGovernor: address, newGovernor: address) <<Governable>> +    <<event>> GovernorshipTransferred(previousGovernor: address, newGovernor: address) <<Governable>> +    <<event>> AssetSupported(_asset: address) <<VaultStorage>> +    <<event>> AssetDefaultStrategyUpdated(_asset: address, _strategy: address) <<VaultStorage>> +    <<event>> AssetAllocated(_asset: address, _strategy: address, _amount: uint256) <<VaultStorage>> +    <<event>> StrategyApproved(_addr: address) <<VaultStorage>> +    <<event>> StrategyRemoved(_addr: address) <<VaultStorage>> +    <<event>> Mint(_addr: address, _value: uint256) <<VaultStorage>> +    <<event>> Redeem(_addr: address, _value: uint256) <<VaultStorage>> +    <<event>> CapitalPaused() <<VaultStorage>> +    <<event>> CapitalUnpaused() <<VaultStorage>> +    <<event>> RebasePaused() <<VaultStorage>> +    <<event>> RebaseUnpaused() <<VaultStorage>> +    <<event>> VaultBufferUpdated(_vaultBuffer: uint256) <<VaultStorage>> +    <<event>> OusdMetaStrategyUpdated(_ousdMetaStrategy: address) <<VaultStorage>> +    <<event>> RedeemFeeUpdated(_redeemFeeBps: uint256) <<VaultStorage>> +    <<event>> PriceProviderUpdated(_priceProvider: address) <<VaultStorage>> +    <<event>> AllocateThresholdUpdated(_threshold: uint256) <<VaultStorage>> +    <<event>> RebaseThresholdUpdated(_threshold: uint256) <<VaultStorage>> +    <<event>> StrategistUpdated(_address: address) <<VaultStorage>> +    <<event>> MaxSupplyDiffChanged(maxSupplyDiff: uint256) <<VaultStorage>> +    <<event>> YieldDistribution(_to: address, _yield: uint256, _fee: uint256) <<VaultStorage>> +    <<event>> TrusteeFeeBpsChanged(_basis: uint256) <<VaultStorage>> +    <<event>> TrusteeAddressChanged(_address: address) <<VaultStorage>> +    <<event>> NetOusdMintForStrategyThresholdChanged(_threshold: uint256) <<VaultStorage>> +    <<event>> SwapperChanged(_address: address) <<VaultStorage>> +    <<event>> SwapAllowedUndervalueChanged(_basis: uint256) <<VaultStorage>> +    <<event>> SwapSlippageChanged(_asset: address, _basis: uint256) <<VaultStorage>> +    <<event>> Swapped(_fromAsset: address, _toAsset: address, _fromAssetAmount: uint256, _toAssetAmount: uint256) <<VaultStorage>> +    <<event>> DripperChanged(_dripper: address) <<VaultStorage>>    <<modifier>> initializer() <<Initializable>>    <<modifier>> onlyGovernor() <<Governable>>    <<modifier>> nonReentrant() <<Governable>> diff --git a/contracts/docs/VaultCoreSquashed.svg b/contracts/docs/VaultCoreSquashed.svg index 64e07ea5fe..fc45807ee1 100644 --- a/contracts/docs/VaultCoreSquashed.svg +++ b/contracts/docs/VaultCoreSquashed.svg @@ -4,132 +4,137 @@ - - + + UmlClassDiagram - - + + -205 - -VaultCore -../contracts/vault/VaultCore.sol - -Private: -   initialized: bool <<Initializable>> -   initializing: bool <<Initializable>> -   ______gap: uint256[50] <<Initializable>> -   governorPosition: bytes32 <<Governable>> -   pendingGovernorPosition: bytes32 <<Governable>> -   reentryStatusPosition: bytes32 <<Governable>> -   _deprecated_rebaseHooksAddr: address <<VaultStorage>> -   _deprecated_uniswapAddr: address <<VaultStorage>> -   _deprecated_swapTokens: address[] <<VaultStorage>> -Internal: -   assets: mapping(address=>Asset) <<VaultStorage>> -   allAssets: address[] <<VaultStorage>> -   strategies: mapping(address=>Strategy) <<VaultStorage>> -   allStrategies: address[] <<VaultStorage>> -   oUSD: OUSD <<VaultStorage>> -   swapConfig: SwapConfig <<VaultStorage>> -   MAX_INT: uint256 <<VaultCore>> -   MAX_UINT: uint256 <<VaultCore>> -Public: -   _NOT_ENTERED: uint256 <<Governable>> -   _ENTERED: uint256 <<Governable>> -   priceProvider: address <<VaultStorage>> -   rebasePaused: bool <<VaultStorage>> -   capitalPaused: bool <<VaultStorage>> -   redeemFeeBps: uint256 <<VaultStorage>> -   vaultBuffer: uint256 <<VaultStorage>> -   autoAllocateThreshold: uint256 <<VaultStorage>> -   rebaseThreshold: uint256 <<VaultStorage>> -   adminImplPosition: bytes32 <<VaultStorage>> -   strategistAddr: address <<VaultStorage>> -   assetDefaultStrategies: mapping(address=>address) <<VaultStorage>> -   maxSupplyDiff: uint256 <<VaultStorage>> -   trusteeAddress: address <<VaultStorage>> -   trusteeFeeBps: uint256 <<VaultStorage>> -   MINT_MINIMUM_UNIT_PRICE: uint256 <<VaultStorage>> -   ousdMetaStrategy: address <<VaultStorage>> -   netOusdMintedForStrategy: int256 <<VaultStorage>> -   netOusdMintForStrategyThreshold: uint256 <<VaultStorage>> -   MIN_UNIT_PRICE_DRIFT: uint256 <<VaultStorage>> -   MAX_UNIT_PRICE_DRIFT: uint256 <<VaultStorage>> - -Private: -    abs(x: int256): uint256 <<VaultCore>> -Internal: -    _governor(): (governorOut: address) <<Governable>> -    _pendingGovernor(): (pendingGovernor: address) <<Governable>> -    _setGovernor(newGovernor: address) <<Governable>> -    _setPendingGovernor(newGovernor: address) <<Governable>> -    _changeGovernor(_newGovernor: address) <<Governable>> -    _redeem(_amount: uint256, _minimumUnitAmount: uint256) <<VaultCore>> -    _allocate() <<VaultCore>> -    _rebase(): uint256 <<whenNotRebasePaused>> <<VaultCore>> -    _totalValue(): (value: uint256) <<VaultCore>> -    _totalValueInVault(): (value: uint256) <<VaultCore>> -    _totalValueInStrategies(): (value: uint256) <<VaultCore>> -    _totalValueInStrategy(_strategyAddr: address): (value: uint256) <<VaultCore>> -    _checkBalance(_asset: address): (balance: uint256) <<VaultCore>> -    _calculateRedeemOutputs(_amount: uint256): (outputs: uint256[]) <<VaultCore>> -    _toUnits(_raw: uint256, _asset: address): uint256 <<VaultCore>> -    _toUnitPrice(_asset: address, isMint: bool): (price: uint256) <<VaultCore>> -    _getDecimals(_asset: address): (decimals: uint256) <<VaultCore>> -External: -    <<payable>> null() <<VaultCore>> -    transferGovernance(_newGovernor: address) <<onlyGovernor>> <<Governable>> -    claimGovernance() <<Governable>> -    setAdminImpl(newImpl: address) <<onlyGovernor>> <<VaultStorage>> -    initialize(_priceProvider: address, _oToken: address) <<onlyGovernor, initializer>> <<VaultInitializer>> -    mint(_asset: address, _amount: uint256, _minimumOusdAmount: uint256) <<whenNotCapitalPaused, nonReentrant>> <<VaultCore>> -    mintForStrategy(_amount: uint256) <<whenNotCapitalPaused, onlyOusdMetaStrategy>> <<VaultCore>> -    redeem(_amount: uint256, _minimumUnitAmount: uint256) <<whenNotCapitalPaused, nonReentrant>> <<VaultCore>> -    burnForStrategy(_amount: uint256) <<whenNotCapitalPaused, onlyOusdMetaStrategy>> <<VaultCore>> -    redeemAll(_minimumUnitAmount: uint256) <<whenNotCapitalPaused, nonReentrant>> <<VaultCore>> -    allocate() <<whenNotCapitalPaused, nonReentrant>> <<VaultCore>> -    rebase() <<nonReentrant>> <<VaultCore>> -    totalValue(): (value: uint256) <<VaultCore>> -    checkBalance(_asset: address): uint256 <<VaultCore>> -    calculateRedeemOutputs(_amount: uint256): uint256[] <<VaultCore>> -    priceUnitMint(asset: address): (price: uint256) <<VaultCore>> -    priceUnitRedeem(asset: address): (price: uint256) <<VaultCore>> -    getAllAssets(): address[] <<VaultCore>> -    getStrategyCount(): uint256 <<VaultCore>> -    getAllStrategies(): address[] <<VaultCore>> -    isSupportedAsset(_asset: address): bool <<VaultCore>> -Public: -    <<event>> PendingGovernorshipTransfer(previousGovernor: address, newGovernor: address) <<Governable>> -    <<event>> GovernorshipTransferred(previousGovernor: address, newGovernor: address) <<Governable>> -    <<event>> AssetSupported(_asset: address) <<VaultStorage>> -    <<event>> AssetDefaultStrategyUpdated(_asset: address, _strategy: address) <<VaultStorage>> -    <<event>> AssetAllocated(_asset: address, _strategy: address, _amount: uint256) <<VaultStorage>> -    <<event>> StrategyApproved(_addr: address) <<VaultStorage>> -    <<event>> StrategyRemoved(_addr: address) <<VaultStorage>> -    <<event>> Mint(_addr: address, _value: uint256) <<VaultStorage>> -    <<event>> Redeem(_addr: address, _value: uint256) <<VaultStorage>> -    <<event>> CapitalPaused() <<VaultStorage>> -    <<event>> CapitalUnpaused() <<VaultStorage>> -    <<event>> RebasePaused() <<VaultStorage>> -    <<event>> RebaseUnpaused() <<VaultStorage>> -    <<event>> VaultBufferUpdated(_vaultBuffer: uint256) <<VaultStorage>> -    <<event>> OusdMetaStrategyUpdated(_ousdMetaStrategy: address) <<VaultStorage>> -    <<event>> RedeemFeeUpdated(_redeemFeeBps: uint256) <<VaultStorage>> -    <<event>> PriceProviderUpdated(_priceProvider: address) <<VaultStorage>> -    <<event>> AllocateThresholdUpdated(_threshold: uint256) <<VaultStorage>> -    <<event>> RebaseThresholdUpdated(_threshold: uint256) <<VaultStorage>> -    <<event>> StrategistUpdated(_address: address) <<VaultStorage>> -    <<event>> MaxSupplyDiffChanged(maxSupplyDiff: uint256) <<VaultStorage>> -    <<event>> YieldDistribution(_to: address, _yield: uint256, _fee: uint256) <<VaultStorage>> -    <<event>> TrusteeFeeBpsChanged(_basis: uint256) <<VaultStorage>> -    <<event>> TrusteeAddressChanged(_address: address) <<VaultStorage>> -    <<event>> NetOusdMintForStrategyThresholdChanged(_threshold: uint256) <<VaultStorage>> -    <<event>> SwapperChanged(_address: address) <<VaultStorage>> -    <<event>> SwapAllowedUndervalueChanged(_basis: uint256) <<VaultStorage>> -    <<event>> SwapSlippageChanged(_asset: address, _basis: uint256) <<VaultStorage>> -    <<event>> Swapped(_fromAsset: address, _toAsset: address, _fromAssetAmount: uint256, _toAssetAmount: uint256) <<VaultStorage>> +224 + +VaultCore +../contracts/vault/VaultCore.sol + +Private: +   initialized: bool <<Initializable>> +   initializing: bool <<Initializable>> +   ______gap: uint256[50] <<Initializable>> +   governorPosition: bytes32 <<Governable>> +   pendingGovernorPosition: bytes32 <<Governable>> +   reentryStatusPosition: bytes32 <<Governable>> +   _deprecated_rebaseHooksAddr: address <<VaultStorage>> +   _deprecated_uniswapAddr: address <<VaultStorage>> +   _deprecated_swapTokens: address[] <<VaultStorage>> +   __gap: uint256[49] <<VaultStorage>> +Internal: +   assets: mapping(address=>Asset) <<VaultStorage>> +   allAssets: address[] <<VaultStorage>> +   strategies: mapping(address=>Strategy) <<VaultStorage>> +   allStrategies: address[] <<VaultStorage>> +   oUSD: OUSD <<VaultStorage>> +   swapConfig: SwapConfig <<VaultStorage>> +   MAX_INT: uint256 <<VaultCore>> +   MAX_UINT: uint256 <<VaultCore>> +Public: +   _NOT_ENTERED: uint256 <<Governable>> +   _ENTERED: uint256 <<Governable>> +   priceProvider: address <<VaultStorage>> +   rebasePaused: bool <<VaultStorage>> +   capitalPaused: bool <<VaultStorage>> +   redeemFeeBps: uint256 <<VaultStorage>> +   vaultBuffer: uint256 <<VaultStorage>> +   autoAllocateThreshold: uint256 <<VaultStorage>> +   rebaseThreshold: uint256 <<VaultStorage>> +   adminImplPosition: bytes32 <<VaultStorage>> +   strategistAddr: address <<VaultStorage>> +   assetDefaultStrategies: mapping(address=>address) <<VaultStorage>> +   maxSupplyDiff: uint256 <<VaultStorage>> +   trusteeAddress: address <<VaultStorage>> +   trusteeFeeBps: uint256 <<VaultStorage>> +   MINT_MINIMUM_UNIT_PRICE: uint256 <<VaultStorage>> +   ousdMetaStrategy: address <<VaultStorage>> +   netOusdMintedForStrategy: int256 <<VaultStorage>> +   netOusdMintForStrategyThreshold: uint256 <<VaultStorage>> +   MIN_UNIT_PRICE_DRIFT: uint256 <<VaultStorage>> +   MAX_UNIT_PRICE_DRIFT: uint256 <<VaultStorage>> +   dripper: address <<VaultStorage>> + +Private: +    abs(x: int256): uint256 <<VaultCore>> +Internal: +    _governor(): (governorOut: address) <<Governable>> +    _pendingGovernor(): (pendingGovernor: address) <<Governable>> +    _setGovernor(newGovernor: address) <<Governable>> +    _setPendingGovernor(newGovernor: address) <<Governable>> +    _changeGovernor(_newGovernor: address) <<Governable>> +    _mint(_asset: address, _amount: uint256, _minimumOusdAmount: uint256) <<VaultCore>> +    _redeem(_amount: uint256, _minimumUnitAmount: uint256) <<VaultCore>> +    _postRedeem(_amount: uint256) <<VaultCore>> +    _allocate() <<VaultCore>> +    _rebase(): uint256 <<whenNotRebasePaused>> <<VaultCore>> +    _totalValue(): (value: uint256) <<VaultCore>> +    _totalValueInVault(): (value: uint256) <<VaultCore>> +    _totalValueInStrategies(): (value: uint256) <<VaultCore>> +    _totalValueInStrategy(_strategyAddr: address): (value: uint256) <<VaultCore>> +    _checkBalance(_asset: address): (balance: uint256) <<VaultCore>> +    _calculateRedeemOutputs(_amount: uint256): (outputs: uint256[]) <<VaultCore>> +    _toUnits(_raw: uint256, _asset: address): uint256 <<VaultCore>> +    _toUnitPrice(_asset: address, isMint: bool): (price: uint256) <<VaultCore>> +    _getDecimals(_asset: address): (decimals: uint256) <<VaultCore>> +External: +    transferGovernance(_newGovernor: address) <<onlyGovernor>> <<Governable>> +    claimGovernance() <<Governable>> +    setAdminImpl(newImpl: address) <<onlyGovernor>> <<VaultStorage>> +    initialize(_priceProvider: address, _oToken: address) <<onlyGovernor, initializer>> <<VaultInitializer>> +    mint(_asset: address, _amount: uint256, _minimumOusdAmount: uint256) <<whenNotCapitalPaused, nonReentrant>> <<VaultCore>> +    mintForStrategy(_amount: uint256) <<whenNotCapitalPaused, onlyOusdMetaStrategy>> <<VaultCore>> +    redeem(_amount: uint256, _minimumUnitAmount: uint256) <<whenNotCapitalPaused, nonReentrant>> <<VaultCore>> +    burnForStrategy(_amount: uint256) <<whenNotCapitalPaused, onlyOusdMetaStrategy>> <<VaultCore>> +    redeemAll(_minimumUnitAmount: uint256) <<whenNotCapitalPaused, nonReentrant>> <<VaultCore>> +    allocate() <<whenNotCapitalPaused, nonReentrant>> <<VaultCore>> +    rebase() <<nonReentrant>> <<VaultCore>> +    totalValue(): (value: uint256) <<VaultCore>> +    checkBalance(_asset: address): uint256 <<VaultCore>> +    calculateRedeemOutputs(_amount: uint256): uint256[] <<VaultCore>> +    priceUnitMint(asset: address): (price: uint256) <<VaultCore>> +    priceUnitRedeem(asset: address): (price: uint256) <<VaultCore>> +    getAllAssets(): address[] <<VaultCore>> +    getStrategyCount(): uint256 <<VaultCore>> +    getAllStrategies(): address[] <<VaultCore>> +    isSupportedAsset(_asset: address): bool <<VaultCore>> +    null() <<VaultCore>> +Public: +    <<event>> PendingGovernorshipTransfer(previousGovernor: address, newGovernor: address) <<Governable>> +    <<event>> GovernorshipTransferred(previousGovernor: address, newGovernor: address) <<Governable>> +    <<event>> AssetSupported(_asset: address) <<VaultStorage>> +    <<event>> AssetDefaultStrategyUpdated(_asset: address, _strategy: address) <<VaultStorage>> +    <<event>> AssetAllocated(_asset: address, _strategy: address, _amount: uint256) <<VaultStorage>> +    <<event>> StrategyApproved(_addr: address) <<VaultStorage>> +    <<event>> StrategyRemoved(_addr: address) <<VaultStorage>> +    <<event>> Mint(_addr: address, _value: uint256) <<VaultStorage>> +    <<event>> Redeem(_addr: address, _value: uint256) <<VaultStorage>> +    <<event>> CapitalPaused() <<VaultStorage>> +    <<event>> CapitalUnpaused() <<VaultStorage>> +    <<event>> RebasePaused() <<VaultStorage>> +    <<event>> RebaseUnpaused() <<VaultStorage>> +    <<event>> VaultBufferUpdated(_vaultBuffer: uint256) <<VaultStorage>> +    <<event>> OusdMetaStrategyUpdated(_ousdMetaStrategy: address) <<VaultStorage>> +    <<event>> RedeemFeeUpdated(_redeemFeeBps: uint256) <<VaultStorage>> +    <<event>> PriceProviderUpdated(_priceProvider: address) <<VaultStorage>> +    <<event>> AllocateThresholdUpdated(_threshold: uint256) <<VaultStorage>> +    <<event>> RebaseThresholdUpdated(_threshold: uint256) <<VaultStorage>> +    <<event>> StrategistUpdated(_address: address) <<VaultStorage>> +    <<event>> MaxSupplyDiffChanged(maxSupplyDiff: uint256) <<VaultStorage>> +    <<event>> YieldDistribution(_to: address, _yield: uint256, _fee: uint256) <<VaultStorage>> +    <<event>> TrusteeFeeBpsChanged(_basis: uint256) <<VaultStorage>> +    <<event>> TrusteeAddressChanged(_address: address) <<VaultStorage>> +    <<event>> NetOusdMintForStrategyThresholdChanged(_threshold: uint256) <<VaultStorage>> +    <<event>> SwapperChanged(_address: address) <<VaultStorage>> +    <<event>> SwapAllowedUndervalueChanged(_basis: uint256) <<VaultStorage>> +    <<event>> SwapSlippageChanged(_asset: address, _basis: uint256) <<VaultStorage>> +    <<event>> Swapped(_fromAsset: address, _toAsset: address, _fromAssetAmount: uint256, _toAssetAmount: uint256) <<VaultStorage>> +    <<event>> DripperChanged(_dripper: address) <<VaultStorage>>    <<modifier>> initializer() <<Initializable>>    <<modifier>> onlyGovernor() <<Governable>>    <<modifier>> nonReentrant() <<Governable>> diff --git a/contracts/docs/VaultHierarchy.svg b/contracts/docs/VaultHierarchy.svg index 626d89b4bb..207092a151 100644 --- a/contracts/docs/VaultHierarchy.svg +++ b/contracts/docs/VaultHierarchy.svg @@ -4,242 +4,256 @@ - + UmlClassDiagram - + 20 - -Governable -../contracts/governance/Governable.sol + +Governable +../contracts/governance/Governable.sol - + -42 - -<<Interface>> -IGetExchangeRateToken -../contracts/interfaces/IGetExchangeRateToken.sol +40 + +<<Interface>> +IDripper +../contracts/interfaces/IDripper.sol - + -48 - -<<Interface>> -IOracle -../contracts/interfaces/IOracle.sol +44 + +<<Interface>> +IGetExchangeRateToken +../contracts/interfaces/IGetExchangeRateToken.sol - + -52 - -<<Interface>> -IStrategy -../contracts/interfaces/IStrategy.sol +51 + +<<Interface>> +IOracle +../contracts/interfaces/IOracle.sol - + -53 - -<<Interface>> -ISwapper -../contracts/interfaces/ISwapper.sol +57 + +<<Interface>> +IStrategy +../contracts/interfaces/IStrategy.sol - + -55 - -<<Interface>> -IVault -../contracts/interfaces/IVault.sol +58 + +<<Interface>> +ISwapper +../contracts/interfaces/ISwapper.sol - - -207 - -VaultStorage -../contracts/vault/VaultStorage.sol + + +61 + +<<Interface>> +IVault +../contracts/interfaces/IVault.sol - + + +226 + +VaultStorage +../contracts/vault/VaultStorage.sol + + -55->207 - - +61->226 + + - - -186 - -OUSD -../contracts/token/OUSD.sol + + +205 + +OUSD +../contracts/token/OUSD.sol - + -186->20 - - +205->20 + + - - -194 - -<<Abstract>> -Initializable -../contracts/utils/Initializable.sol + + +213 + +<<Abstract>> +Initializable +../contracts/utils/Initializable.sol - + -186->194 - - +205->213 + + - - -197 - -<<Abstract>> -InitializableERC20Detailed -../contracts/utils/InitializableERC20Detailed.sol + + +216 + +<<Abstract>> +InitializableERC20Detailed +../contracts/utils/InitializableERC20Detailed.sol - + -186->197 - - - - - -392 - -<<Interface>> -IERC20 -../node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol - - +205->216 + + + + + +695 + +<<Interface>> +IERC20 +../node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol + + -197->392 - - +216->695 + + - - -204 - -VaultAdmin -../contracts/vault/VaultAdmin.sol + + +223 + +VaultAdmin +../contracts/vault/VaultAdmin.sol - + -204->48 - - +223->51 + + - + -204->52 - - +223->57 + + - + -204->53 - - +223->58 + + - + -204->55 - - +223->61 + + - + -204->207 - - +223->226 + + - + -204->392 - - +223->695 + + - - -205 - -VaultCore -../contracts/vault/VaultCore.sol + + +224 + +VaultCore +../contracts/vault/VaultCore.sol + + + +224->40 + + + + + +224->44 + + - + -205->42 - - +224->51 + + - + -205->48 - - +224->57 + + - - -205->52 - - - - - -206 - -VaultInitializer -../contracts/vault/VaultInitializer.sol + + +225 + +VaultInitializer +../contracts/vault/VaultInitializer.sol - + -205->206 - - - - - -205->392 - - +224->225 + + - - -206->186 - - + + +224->695 + + - - -206->207 - - + + +225->205 + + - - -207->20 - - + + +225->226 + + - + -207->186 - - +226->20 + + - - -207->194 - - + + +226->205 + + + + + +226->213 + + diff --git a/contracts/docs/VaultStorage.svg b/contracts/docs/VaultStorage.svg index bb504649df..8ae11c03cc 100644 --- a/contracts/docs/VaultStorage.svg +++ b/contracts/docs/VaultStorage.svg @@ -4,262 +4,308 @@ - - + + StorageDiagram - - + + -6 - -VaultCore <<Contract>> - -slot - -0 - -1-50 - -51 - -52 - -53 - -54 - -55 - -56 - -57 - -58 - -59 - -60 - -61 - -62 - -63 - -64 - -65 - -66 - -67 - -68 - -69 - -70 - -71 - -72 - -type: <inherited contract>.variable (bytes) - -unallocated (30) - -bool: Initializable.initializing (1) - -bool: Initializable.initialized (1) - -uint256[50]: Initializable.______gap (1600) - -mapping(address=>Asset): VaultStorage.assets (32) - -address[]: VaultStorage.allAssets (32) - -mapping(address=>Strategy): VaultStorage.strategies (32) - -address[]: VaultStorage.allStrategies (32) - -unallocated (10) - -bool: VaultStorage.capitalPaused (1) - -bool: VaultStorage.rebasePaused (1) - -address: VaultStorage.priceProvider (20) - -uint256: VaultStorage.redeemFeeBps (32) - -uint256: VaultStorage.vaultBuffer (32) - -uint256: VaultStorage.autoAllocateThreshold (32) - -uint256: VaultStorage.rebaseThreshold (32) - -unallocated (12) - -OUSD: VaultStorage.oUSD (20) - -unallocated (12) - -address: VaultStorage._deprecated_rebaseHooksAddr (20) - -unallocated (12) - -address: VaultStorage._deprecated_uniswapAddr (20) - -unallocated (12) - -address: VaultStorage.strategistAddr (20) - -mapping(address=>address): VaultStorage.assetDefaultStrategies (32) - -uint256: VaultStorage.maxSupplyDiff (32) - -unallocated (12) - -address: VaultStorage.trusteeAddress (20) - -uint256: VaultStorage.trusteeFeeBps (32) - -address[]: VaultStorage._deprecated_swapTokens (32) - -unallocated (12) - -address: VaultStorage.ousdMetaStrategy (20) - -int256: VaultStorage.netOusdMintedForStrategy (32) - -uint256: VaultStorage.netOusdMintForStrategyThreshold (32) - -SwapConfig: VaultStorage.swapConfig (32) +7 + +VaultCore <<Contract>> + +slot + +0 + +1-50 + +51 + +52 + +53 + +54 + +55 + +56 + +57 + +58 + +59 + +60 + +61 + +62 + +63 + +64 + +65 + +66 + +67 + +68 + +69 + +70 + +71 + +72 + +73 + +74-122 + +type: <inherited contract>.variable (bytes) + +unallocated (30) + +bool: Initializable.initializing (1) + +bool: Initializable.initialized (1) + +uint256[50]: Initializable.______gap (1600) + +mapping(address=>Asset): VaultStorage.assets (32) + +address[]: VaultStorage.allAssets (32) + +mapping(address=>Strategy): VaultStorage.strategies (32) + +address[]: VaultStorage.allStrategies (32) + +unallocated (10) + +bool: VaultStorage.capitalPaused (1) + +bool: VaultStorage.rebasePaused (1) + +address: VaultStorage.priceProvider (20) + +uint256: VaultStorage.redeemFeeBps (32) + +uint256: VaultStorage.vaultBuffer (32) + +uint256: VaultStorage.autoAllocateThreshold (32) + +uint256: VaultStorage.rebaseThreshold (32) + +unallocated (12) + +OUSD: VaultStorage.oUSD (20) + +unallocated (12) + +address: VaultStorage._deprecated_rebaseHooksAddr (20) + +unallocated (12) + +address: VaultStorage._deprecated_uniswapAddr (20) + +unallocated (12) + +address: VaultStorage.strategistAddr (20) + +mapping(address=>address): VaultStorage.assetDefaultStrategies (32) + +uint256: VaultStorage.maxSupplyDiff (32) + +unallocated (12) + +address: VaultStorage.trusteeAddress (20) + +uint256: VaultStorage.trusteeFeeBps (32) + +address[]: VaultStorage._deprecated_swapTokens (32) + +unallocated (12) + +address: VaultStorage.ousdMetaStrategy (20) + +int256: VaultStorage.netOusdMintedForStrategy (32) + +uint256: VaultStorage.netOusdMintForStrategyThreshold (32) + +SwapConfig: VaultStorage.swapConfig (32) + +unallocated (12) + +address: VaultStorage.dripper (20) + +uint256[49]: VaultStorage.__gap (1568) 1 - -Asset <<Struct>> - -offset - -0 - -type: variable (bytes) - -unallocated (27) - -uint16: allowedOracleSlippageBps (2) - -uint8: decimals (1) - -UnitConversion: unitConversion (1) - -bool: isSupported (1) + +Asset <<Struct>> + +offset + +0 + +type: variable (bytes) + +unallocated (27) + +uint16: allowedOracleSlippageBps (2) + +uint8: decimals (1) + +UnitConversion: unitConversion (1) + +bool: isSupported (1) - + -6:8->1 - - +7:8->1 + + 2 - -address[]: allAssets <<Array>> -0x46bddb1178e94d7f2892ff5f366840eb658911794f2c3a44c450aa2c505186c1 - -offset - -0 - -type: variable (bytes) - -unallocated (12) - -address (20) + +address[]: allAssets <<Array>> +0x46bddb1178e94d7f2892ff5f366840eb658911794f2c3a44c450aa2c505186c1 + +offset + +0 + +type: variable (bytes) + +unallocated (12) + +address (20) - + -6:10->2 - - +7:10->2 + + 3 - -Strategy <<Struct>> - -offset - -0 - -1 - -type: variable (bytes) - -unallocated (31) - -bool: isSupported (1) - -uint256: _deprecated (32) + +Strategy <<Struct>> + +offset + +0 + +1 + +type: variable (bytes) + +unallocated (31) + +bool: isSupported (1) + +uint256: _deprecated (32) - + -6:13->3 - - +7:13->3 + + 4 - -address[]: allStrategies <<Array>> -0x4a11f94e20a93c79f6ec743a1954ec4fc2c08429ae2122118bf234b2185c81b8 - -offset - -0 - -type: variable (bytes) - -unallocated (12) - -address (20) + +address[]: allStrategies <<Array>> +0x4a11f94e20a93c79f6ec743a1954ec4fc2c08429ae2122118bf234b2185c81b8 + +offset + +0 + +type: variable (bytes) + +unallocated (12) + +address (20) - + -6:15->4 - - +7:15->4 + + 5 - -SwapConfig <<Struct>> - -slot - -72 - -type: variable (bytes) - -unallocated (10) - -uint16: allowedUndervalueBps (2) - -address: swapper (20) + +SwapConfig <<Struct>> + +slot + +72 + +type: variable (bytes) + +unallocated (10) + +uint16: allowedUndervalueBps (2) + +address: swapper (20) - + -6:37->5 - - +7:37->5 + + + + + +6 + +uint256[49]: __gap <<Array>> + +slot + +74 + +75 + +76-120 + +121 + +122 + +type: variable (bytes) + +uint256 (32) + +uint256 (32) + +---- (1440) + +uint256 (32) + +uint256 (32) + + + +7:44->6 + + diff --git a/contracts/test/vault/index.js b/contracts/test/vault/index.js index 816674198b..a056d26627 100644 --- a/contracts/test/vault/index.js +++ b/contracts/test/vault/index.js @@ -1,6 +1,6 @@ const { expect } = require("chai"); const hre = require("hardhat"); -const { utils } = require("ethers"); +const { utils, Wallet } = require("ethers"); const { loadDefaultFixture } = require("../_fixture"); const { @@ -361,6 +361,26 @@ describe("Vault", function () { ); }); + it("Should allow governor to change the dripper", async () => { + const { vault, governor } = fixture; + + const newDripper = Wallet.createRandom().address; + + const tx = await vault.connect(governor).setDripper(newDripper); + + await expect(tx).to.emit(vault, "DripperChanged").withArgs(newDripper); + }); + + it("Should not allow non-governor to change the dripper", async () => { + const { vault } = fixture; + + const newDripper = Wallet.createRandom().address; + + const tx = vault.setDripper(newDripper); + + await expect(tx).to.be.revertedWith("Caller is not the Governor"); + }); + it("Should allow governor to change Strategist address", async () => { const { vault, governor, josh } = fixture; From c8288b7751e6652365184d146d28d1f0b9eda0e7 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Thu, 16 May 2024 16:33:52 +1000 Subject: [PATCH 073/273] Added more vault mint fork tests --- contracts/test/vault/oeth-vault.fork-test.js | 51 +++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/contracts/test/vault/oeth-vault.fork-test.js b/contracts/test/vault/oeth-vault.fork-test.js index 59177c0cbf..023b1e6e0a 100644 --- a/contracts/test/vault/oeth-vault.fork-test.js +++ b/contracts/test/vault/oeth-vault.fork-test.js @@ -5,6 +5,7 @@ const addresses = require("../../utils/addresses"); const { createFixtureLoader, oethDefaultFixture } = require("../_fixture"); const { isCI, oethUnits } = require("../helpers"); const { impersonateAndFund } = require("../../utils/signers"); +const { logTxDetails } = require("../../utils/txLogger"); const { shouldHaveRewardTokensConfigured, } = require("../behaviour/reward-tokens.fork"); @@ -69,7 +70,7 @@ describe("ForkTest: OETH Vault", function () { oethWhaleSigner = await impersonateAndFund(oethWhaleAddress); }); - it("should mint with WETH", async () => { + it("should mint with WETH and no allocation", async () => { const { oethVault, weth, josh } = fixture; const amount = parseUnits("1", 18); @@ -81,6 +82,54 @@ describe("ForkTest: OETH Vault", function () { .connect(josh) .mint(weth.address, amount, minOeth); + await logTxDetails(tx, "mint"); + + await expect(tx) + .to.emit(oethVault, "Mint") + .withArgs(josh.address, amount); + }); + + it("should mint with WETH and auto allocate", async () => { + const { oethVault, weth, josh } = fixture; + + const amount = parseUnits("11", 18); + const minOeth = parseUnits("8", 18); + + await weth.connect(josh).approve(oethVault.address, amount); + + const tx = await oethVault + .connect(josh) + .mint(weth.address, amount, minOeth); + + await logTxDetails(tx, "mint"); + + await expect(tx) + .to.emit(oethVault, "Mint") + .withArgs(josh.address, amount); + }); + + it("should mint with WETH and allocate to strategy", async () => { + const { oethVault, nativeStakingSSVStrategy, weth, josh, strategist } = + fixture; + + oethVault + .connect(strategist) + .setAssetDefaultStrategy( + weth.address, + nativeStakingSSVStrategy.address + ); + + const amount = parseUnits("11", 18); + const minOeth = parseUnits("8", 18); + + await weth.connect(josh).approve(oethVault.address, amount); + + const tx = await oethVault + .connect(josh) + .mint(weth.address, amount, minOeth); + + await logTxDetails(tx, "mint"); + await expect(tx) .to.emit(oethVault, "Mint") .withArgs(josh.address, amount); From 63a11f72ac26fe2b496eeb89b676d8a08246e97a Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Thu, 16 May 2024 21:54:09 +1000 Subject: [PATCH 074/273] first implementation of the withdrawal queue --- contracts/contracts/interfaces/IVault.sol | 3 + .../NativeStakingSSVStrategy.sol | 4 + .../NativeStaking/ValidatorAccountant.sol | 2 +- contracts/contracts/vault/OETHVaultAdmin.sol | 27 + contracts/contracts/vault/OETHVaultCore.sol | 156 ++++- contracts/contracts/vault/VaultAdmin.sol | 10 +- contracts/contracts/vault/VaultCore.sol | 9 +- contracts/contracts/vault/VaultStorage.sol | 42 +- contracts/docs/OETHVaultAdminSquashed.svg | 259 ++++---- contracts/docs/OETHVaultCoreSquashed.svg | 270 +++++---- contracts/docs/OETHVaultHierarchy.svg | 306 +++------- contracts/docs/OETHVaultStorage.svg | 562 ++++++++++-------- contracts/docs/VaultAdminSquashed.svg | 259 ++++---- contracts/docs/VaultCoreSquashed.svg | 259 ++++---- contracts/docs/VaultHierarchy.svg | 266 +++------ contracts/docs/VaultStorage.svg | 554 +++++++++-------- contracts/docs/generate.sh | 4 +- 17 files changed, 1563 insertions(+), 1429 deletions(-) diff --git a/contracts/contracts/interfaces/IVault.sol b/contracts/contracts/interfaces/IVault.sol index 78afee24d8..d4ca96748f 100644 --- a/contracts/contracts/interfaces/IVault.sol +++ b/contracts/contracts/interfaces/IVault.sol @@ -211,4 +211,7 @@ interface IVault { function initialize(address, address) external; function setAdminImpl(address) external; + + // This is an OETH specific function + function addWithdrawalQueueLiquidity() external; } diff --git a/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol b/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol index 76737fc398..dbd74528be 100644 --- a/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol +++ b/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol @@ -6,6 +6,7 @@ import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.s import { InitializableAbstractStrategy } from "../../utils/InitializableAbstractStrategy.sol"; import { IWETH9 } from "../../interfaces/IWETH9.sol"; +import { IVault } from "../../interfaces/IVault.sol"; import { FeeAccumulator } from "./FeeAccumulator.sol"; import { ValidatorAccountant } from "./ValidatorAccountant.sol"; @@ -264,5 +265,8 @@ contract NativeStakingSSVStrategy is function wethWithdrawnToVault(uint256 _amount) internal override { emit Withdrawal(WETH_TOKEN_ADDRESS, address(0), _amount); + + // Add WETH to the withdraw queue if there is a shortfall + IVault(vaultAddress).addWithdrawalQueueLiquidity(); } } diff --git a/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol b/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol index 996a28bfa7..a5ca5771a5 100644 --- a/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol +++ b/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol @@ -133,7 +133,7 @@ abstract contract ValidatorAccountant is ValidatorRegistrator { // slither-disable-next-line unchecked-transfer IWETH9(WETH_TOKEN_ADDRESS).transfer(VAULT_ADDRESS, wethToVault); wethWithdrawnToVault(wethToVault); - + emit AccountingFullyWithdrawnValidator( fullyWithdrawnValidators, activeDepositedValidators, diff --git a/contracts/contracts/vault/OETHVaultAdmin.sol b/contracts/contracts/vault/OETHVaultAdmin.sol index aa16a98d79..0b028bd6a6 100644 --- a/contracts/contracts/vault/OETHVaultAdmin.sol +++ b/contracts/contracts/vault/OETHVaultAdmin.sol @@ -2,11 +2,38 @@ pragma solidity ^0.8.0; import { VaultAdmin } from "./VaultAdmin.sol"; +import { IVault } from "../interfaces/IVault.sol"; /** * @title OETH VaultAdmin Contract * @author Origin Protocol Inc */ contract OETHVaultAdmin is VaultAdmin { + 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(); + } } diff --git a/contracts/contracts/vault/OETHVaultCore.sol b/contracts/contracts/vault/OETHVaultCore.sol index d8f2260a5e..3fd9dfa9f8 100644 --- a/contracts/contracts/vault/OETHVaultCore.sol +++ b/contracts/contracts/vault/OETHVaultCore.sol @@ -65,6 +65,9 @@ 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(); @@ -125,7 +128,8 @@ contract OETHVaultCore is VaultCore { "Redeem amount lower than minimum" ); - if (IERC20(weth).balanceOf(address(this)) >= amountMinusFee) { + // If there is any WETH in the Vault available after accounting for the withdrawal queue + if (_wethAvailable() >= amountMinusFee) { // Use Vault funds first if sufficient IERC20(weth).safeTransfer(msg.sender, amountMinusFee); } else { @@ -145,4 +149,154 @@ contract OETHVaultCore is VaultCore { _postRedeem(_amount); } + + /** + * @notice Request an asynchronous withdrawal of the underlying asset. eg WETH + * @param _amount Amount of oTokens to burn. eg OETH + */ + function requestWithdrawal(uint256 _amount) + external + whenNotCapitalPaused + nonReentrant + returns (uint256 requestId, uint256 queued) + { + // Check the user has enough OETH to burn + require(oUSD.balanceOf(msg.sender) >= _amount, "Insufficient OETH"); + + // burn the user's oTokens + oUSD.burn(msg.sender, _amount); + + requestId = withdrawalQueueMetadata.nextWithdrawalIndex; + queued = withdrawalQueueMetadata.queued + _amount; + + // store the next withdrawal request + withdrawalQueueMetadata.nextWithdrawalIndex = uint128(requestId + 1); + withdrawalQueueMetadata.queued = uint128(queued); + + emit WithdrawalRequested(msg.sender, requestId, _amount, queued); + + withdrawalRequests[requestId] = WithdrawalRequest({ + withdrawer: msg.sender, + claimed: false, + amount: uint128(_amount), + queued: uint128(queued) + }); + } + + function claimWithdrawal(uint256 requestId) + external + whenNotCapitalPaused + nonReentrant + { + // Check if there's enough liquidity to cover the withdrawal request + WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata; + WithdrawalRequest memory request = withdrawalRequests[requestId]; + + require(request.queued <= queue.claimable, "pending liquidity"); + require(request.claimed == false, "already claimed"); + require(request.withdrawer == msg.sender, "not requester"); + + // Store the updated claimed amount + withdrawalQueueMetadata.claimed = queue.claimed + request.amount; + // Store the request as claimed + withdrawalRequests[requestId].claimed = true; + + emit WithdrawalClaimed(msg.sender, requestId, request.amount); + + // transfer WETH from the vault to the withdrawer + IERC20(weth).safeTransfer(msg.sender, request.amount); + } + + /// @notice Adds any unallocated WETH to the withdrawal queue if there is a funding shortfall. + /// @dev is called from the Native Staking strategy when validator withdrawals are processed. + function addWithdrawalQueueLiquidity() external { + _addWithdrawalQueueLiquidity(); + } + + /// @dev Adds WETH to the withdrawal queue if there is a funding shortfall. + function _addWithdrawalQueueLiquidity() internal { + WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata; + + // Check if the claimable WETH is less than the queued amount + uint256 queueShortfall = queue.queued - queue.claimable; + + // No need to get WETH balance if all the withdrawal requests are claimable + if (queueShortfall > 0) { + uint256 wethBalance = IERC20(weth).balanceOf(address(this)); + + // TODO do we also need to look for WETH in the default strategy? + + // Of the claimable withdrawal requests, how much is unclaimed? + uint256 unclaimed = queue.claimable - queue.claimed; + if (wethBalance > unclaimed) { + uint256 unallocatedWeth = wethBalance - unclaimed; + + // the new claimable amount is the smaller of the queue shortfall or unallocated weth + uint256 addedClaimable = queueShortfall < unallocatedWeth + ? queueShortfall + : unallocatedWeth; + uint256 newClaimable = queue.claimable + addedClaimable; + + // Store the new claimable amount back to storage + withdrawalQueueMetadata.claimable = uint128(newClaimable); + + // emit a WithdrawalClaimable event + emit WithdrawalClaimable(newClaimable, addedClaimable); + } + } + } + + /*************************************** + View Functions + ****************************************/ + + function _wethAvailable() internal view returns (uint256 wethAvailable) { + WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata; + + // Check if the claimable WETH is less than the queued amount + uint256 queueShortfall = queue.queued - queue.claimable; + uint256 wethBalance = IERC20(weth).balanceOf(address(this)); + // Of the claimable withdrawal requests, how much is unclaimed? + uint256 unclaimed = queue.claimable - queue.claimed; + + if (wethBalance > queueShortfall + unclaimed) { + wethAvailable = wethBalance - queueShortfall - unclaimed; + } + } + + 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 + return balance + queue.claimed - queue.queued; + } + } + + function _allocate() internal override { + // Add any unallocated WETH to the withdrawal queue first + _addWithdrawalQueueLiquidity(); + + super._allocate(); + } + + function _totalValueInVault() + internal + view + override + returns (uint256 value) + { + value = super._totalValueInVault(); + + WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata; + // Need to remove WETH that is reserved for the withdrawal queue + // reserver for the withdrawal queue = cumulative queued total - total claimed + value = value + queue.claimed - queue.queued; + } } diff --git a/contracts/contracts/vault/VaultAdmin.sol b/contracts/contracts/vault/VaultAdmin.sol index 877690adb0..01ed10c165 100644 --- a/contracts/contracts/vault/VaultAdmin.sol +++ b/contracts/contracts/vault/VaultAdmin.sol @@ -489,7 +489,7 @@ contract VaultAdmin is VaultStorage { address _strategyFromAddress, address[] calldata _assets, uint256[] calldata _amounts - ) internal { + ) internal virtual { require( strategies[_strategyFromAddress].isSupported, "Invalid from Strategy" @@ -613,6 +613,10 @@ contract VaultAdmin is VaultStorage { external onlyGovernorOrStrategist { + _withdrawAllFromStrategy(_strategyAddr); + } + + function _withdrawAllFromStrategy(address _strategyAddr) internal virtual { require( strategies[_strategyAddr].isSupported, "Strategy is not supported" @@ -625,6 +629,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 49db513fc6..446907e73f 100644 --- a/contracts/contracts/vault/VaultCore.sol +++ b/contracts/contracts/vault/VaultCore.sol @@ -289,7 +289,7 @@ contract VaultCore is VaultInitializer { /** * @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; @@ -417,7 +417,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 866fa85ded..dc09905d8f 100644 --- a/contracts/contracts/vault/VaultStorage.sol +++ b/contracts/contracts/vault/VaultStorage.sol @@ -53,6 +53,18 @@ contract VaultStorage is Initializable, Governable { uint256 _toAssetAmount ); event DripperChanged(address indexed _dripper); + event WithdrawalRequested( + address indexed _withdrawer, + uint256 indexed _requestId, + uint256 _amount, + uint256 _queued + ); + event WithdrawalClaimed( + address indexed _withdrawer, + uint256 indexed _requestId, + uint256 _amount + ); + event WithdrawalClaimable(uint256 _claimable, uint256 _newClaimable); // Assets supported by the Vault, i.e. Stablecoins enum UnitConversion { @@ -169,8 +181,36 @@ contract VaultStorage is Initializable, Governable { /// @notice Address of the Dripper contract that streams harvested rewards to the Vault address public dripper; + /// Withdrawal Queue Storage ///// + + struct WithdrawalQueueMetadata { + // cumulative total of all withdrawal requests included the ones that have already bene claimed + uint128 queued; + // cumulative total of all the requests that can be claimed included the ones that have already bene 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; + } + + WithdrawalQueueMetadata public withdrawalQueueMetadata; + + struct WithdrawalRequest { + address withdrawer; + bool claimed; + // Amount of oTokens to redeem + 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; + } + + // Mapping of withdrawal requests indexes to the user withdrawal request data + mapping(uint256 => WithdrawalRequest) public withdrawalRequests; + // For future use - uint256[49] private __gap; + uint256[46] private __gap; /** * @notice set the implementation for the admin, this needs to be in a base class else we cannot set it diff --git a/contracts/docs/OETHVaultAdminSquashed.svg b/contracts/docs/OETHVaultAdminSquashed.svg index ce910a472d..c16d0b3d6c 100644 --- a/contracts/docs/OETHVaultAdminSquashed.svg +++ b/contracts/docs/OETHVaultAdminSquashed.svg @@ -4,136 +4,143 @@ - - + + UmlClassDiagram - + 219 - -OETHVaultAdmin -../contracts/vault/OETHVaultAdmin.sol - -Private: -   initialized: bool <<Initializable>> -   initializing: bool <<Initializable>> -   ______gap: uint256[50] <<Initializable>> -   governorPosition: bytes32 <<Governable>> -   pendingGovernorPosition: bytes32 <<Governable>> -   reentryStatusPosition: bytes32 <<Governable>> -   _deprecated_rebaseHooksAddr: address <<VaultStorage>> -   _deprecated_uniswapAddr: address <<VaultStorage>> -   _deprecated_swapTokens: address[] <<VaultStorage>> -   __gap: uint256[49] <<VaultStorage>> -Internal: -   assets: mapping(address=>Asset) <<VaultStorage>> -   allAssets: address[] <<VaultStorage>> -   strategies: mapping(address=>Strategy) <<VaultStorage>> -   allStrategies: address[] <<VaultStorage>> -   oUSD: OUSD <<VaultStorage>> -   swapConfig: SwapConfig <<VaultStorage>> -Public: -   _NOT_ENTERED: uint256 <<Governable>> -   _ENTERED: uint256 <<Governable>> -   priceProvider: address <<VaultStorage>> -   rebasePaused: bool <<VaultStorage>> -   capitalPaused: bool <<VaultStorage>> -   redeemFeeBps: uint256 <<VaultStorage>> -   vaultBuffer: uint256 <<VaultStorage>> -   autoAllocateThreshold: uint256 <<VaultStorage>> -   rebaseThreshold: uint256 <<VaultStorage>> -   adminImplPosition: bytes32 <<VaultStorage>> -   strategistAddr: address <<VaultStorage>> -   assetDefaultStrategies: mapping(address=>address) <<VaultStorage>> -   maxSupplyDiff: uint256 <<VaultStorage>> -   trusteeAddress: address <<VaultStorage>> -   trusteeFeeBps: uint256 <<VaultStorage>> -   MINT_MINIMUM_UNIT_PRICE: uint256 <<VaultStorage>> -   ousdMetaStrategy: address <<VaultStorage>> -   netOusdMintedForStrategy: int256 <<VaultStorage>> -   netOusdMintForStrategyThreshold: uint256 <<VaultStorage>> -   MIN_UNIT_PRICE_DRIFT: uint256 <<VaultStorage>> -   MAX_UNIT_PRICE_DRIFT: uint256 <<VaultStorage>> -   dripper: address <<VaultStorage>> - -Internal: -    _governor(): (governorOut: address) <<Governable>> -    _pendingGovernor(): (pendingGovernor: address) <<Governable>> -    _setGovernor(newGovernor: address) <<Governable>> -    _setPendingGovernor(newGovernor: address) <<Governable>> -    _changeGovernor(_newGovernor: address) <<Governable>> -    _depositToStrategy(_strategyToAddress: address, _assets: address[], _amounts: uint256[]) <<VaultAdmin>> -    _withdrawFromStrategy(_recipient: address, _strategyFromAddress: address, _assets: address[], _amounts: uint256[]) <<VaultAdmin>> -    _cacheDecimals(token: address) <<VaultAdmin>> -External: -    transferGovernance(_newGovernor: address) <<onlyGovernor>> <<Governable>> -    claimGovernance() <<Governable>> -    setAdminImpl(newImpl: address) <<onlyGovernor>> <<VaultStorage>> -    setPriceProvider(_priceProvider: address) <<onlyGovernor>> <<VaultAdmin>> -    setRedeemFeeBps(_redeemFeeBps: uint256) <<onlyGovernor>> <<VaultAdmin>> -    setVaultBuffer(_vaultBuffer: uint256) <<onlyGovernorOrStrategist>> <<VaultAdmin>> -    setAutoAllocateThreshold(_threshold: uint256) <<onlyGovernor>> <<VaultAdmin>> -    setRebaseThreshold(_threshold: uint256) <<onlyGovernor>> <<VaultAdmin>> -    setStrategistAddr(_address: address) <<onlyGovernor>> <<VaultAdmin>> -    setAssetDefaultStrategy(_asset: address, _strategy: address) <<onlyGovernorOrStrategist>> <<VaultAdmin>> -    setDripper(_dripper: address) <<onlyGovernor>> <<VaultAdmin>> -    setNetOusdMintForStrategyThreshold(_threshold: uint256) <<onlyGovernor>> <<VaultAdmin>> -    swapCollateral(_fromAsset: address, _toAsset: address, _fromAssetAmount: uint256, _minToAssetAmount: uint256, _data: bytes): (toAssetAmount: uint256) <<nonReentrant, onlyGovernorOrStrategist>> <<VaultAdmin>> -    setSwapper(_swapperAddr: address) <<onlyGovernor>> <<VaultAdmin>> -    swapper(): (swapper_: address) <<VaultAdmin>> -    setSwapAllowedUndervalue(_basis: uint16) <<onlyGovernor>> <<VaultAdmin>> -    allowedSwapUndervalue(): (value: uint256) <<VaultAdmin>> -    setOracleSlippage(_asset: address, _allowedOracleSlippageBps: uint16) <<onlyGovernor>> <<VaultAdmin>> -    supportAsset(_asset: address, _unitConversion: uint8) <<onlyGovernor>> <<VaultAdmin>> -    cacheDecimals(_asset: address) <<onlyGovernor>> <<VaultAdmin>> -    approveStrategy(_addr: address) <<onlyGovernor>> <<VaultAdmin>> -    removeStrategy(_addr: address) <<onlyGovernor>> <<VaultAdmin>> -    depositToStrategy(_strategyToAddress: address, _assets: address[], _amounts: uint256[]) <<onlyGovernorOrStrategist, nonReentrant>> <<VaultAdmin>> -    withdrawFromStrategy(_strategyFromAddress: address, _assets: address[], _amounts: uint256[]) <<onlyGovernorOrStrategist, nonReentrant>> <<VaultAdmin>> -    setMaxSupplyDiff(_maxSupplyDiff: uint256) <<onlyGovernor>> <<VaultAdmin>> -    setTrusteeAddress(_address: address) <<onlyGovernor>> <<VaultAdmin>> -    setTrusteeFeeBps(_basis: uint256) <<onlyGovernor>> <<VaultAdmin>> -    setOusdMetaStrategy(_ousdMetaStrategy: address) <<onlyGovernor>> <<VaultAdmin>> -    pauseRebase() <<onlyGovernorOrStrategist>> <<VaultAdmin>> -    unpauseRebase() <<onlyGovernorOrStrategist>> <<VaultAdmin>> -    pauseCapital() <<onlyGovernorOrStrategist>> <<VaultAdmin>> -    unpauseCapital() <<onlyGovernorOrStrategist>> <<VaultAdmin>> -    transferToken(_asset: address, _amount: uint256) <<onlyGovernor>> <<VaultAdmin>> -    withdrawAllFromStrategy(_strategyAddr: address) <<onlyGovernorOrStrategist>> <<VaultAdmin>> -    withdrawAllFromStrategies() <<onlyGovernorOrStrategist>> <<VaultAdmin>> -Public: -    <<event>> PendingGovernorshipTransfer(previousGovernor: address, newGovernor: address) <<Governable>> -    <<event>> GovernorshipTransferred(previousGovernor: address, newGovernor: address) <<Governable>> -    <<event>> AssetSupported(_asset: address) <<VaultStorage>> -    <<event>> AssetDefaultStrategyUpdated(_asset: address, _strategy: address) <<VaultStorage>> -    <<event>> AssetAllocated(_asset: address, _strategy: address, _amount: uint256) <<VaultStorage>> -    <<event>> StrategyApproved(_addr: address) <<VaultStorage>> -    <<event>> StrategyRemoved(_addr: address) <<VaultStorage>> -    <<event>> Mint(_addr: address, _value: uint256) <<VaultStorage>> -    <<event>> Redeem(_addr: address, _value: uint256) <<VaultStorage>> -    <<event>> CapitalPaused() <<VaultStorage>> -    <<event>> CapitalUnpaused() <<VaultStorage>> -    <<event>> RebasePaused() <<VaultStorage>> -    <<event>> RebaseUnpaused() <<VaultStorage>> -    <<event>> VaultBufferUpdated(_vaultBuffer: uint256) <<VaultStorage>> -    <<event>> OusdMetaStrategyUpdated(_ousdMetaStrategy: address) <<VaultStorage>> -    <<event>> RedeemFeeUpdated(_redeemFeeBps: uint256) <<VaultStorage>> -    <<event>> PriceProviderUpdated(_priceProvider: address) <<VaultStorage>> -    <<event>> AllocateThresholdUpdated(_threshold: uint256) <<VaultStorage>> -    <<event>> RebaseThresholdUpdated(_threshold: uint256) <<VaultStorage>> -    <<event>> StrategistUpdated(_address: address) <<VaultStorage>> -    <<event>> MaxSupplyDiffChanged(maxSupplyDiff: uint256) <<VaultStorage>> -    <<event>> YieldDistribution(_to: address, _yield: uint256, _fee: uint256) <<VaultStorage>> -    <<event>> TrusteeFeeBpsChanged(_basis: uint256) <<VaultStorage>> -    <<event>> TrusteeAddressChanged(_address: address) <<VaultStorage>> -    <<event>> NetOusdMintForStrategyThresholdChanged(_threshold: uint256) <<VaultStorage>> -    <<event>> SwapperChanged(_address: address) <<VaultStorage>> -    <<event>> SwapAllowedUndervalueChanged(_basis: uint256) <<VaultStorage>> -    <<event>> SwapSlippageChanged(_asset: address, _basis: uint256) <<VaultStorage>> -    <<event>> Swapped(_fromAsset: address, _toAsset: address, _fromAssetAmount: uint256, _toAssetAmount: uint256) <<VaultStorage>> -    <<event>> DripperChanged(_dripper: address) <<VaultStorage>> + +OETHVaultAdmin +../contracts/vault/OETHVaultAdmin.sol + +Private: +   initialized: bool <<Initializable>> +   initializing: bool <<Initializable>> +   ______gap: uint256[50] <<Initializable>> +   governorPosition: bytes32 <<Governable>> +   pendingGovernorPosition: bytes32 <<Governable>> +   reentryStatusPosition: bytes32 <<Governable>> +   _deprecated_rebaseHooksAddr: address <<VaultStorage>> +   _deprecated_uniswapAddr: address <<VaultStorage>> +   _deprecated_swapTokens: address[] <<VaultStorage>> +   __gap: uint256[46] <<VaultStorage>> +Internal: +   assets: mapping(address=>Asset) <<VaultStorage>> +   allAssets: address[] <<VaultStorage>> +   strategies: mapping(address=>Strategy) <<VaultStorage>> +   allStrategies: address[] <<VaultStorage>> +   oUSD: OUSD <<VaultStorage>> +   swapConfig: SwapConfig <<VaultStorage>> +Public: +   _NOT_ENTERED: uint256 <<Governable>> +   _ENTERED: uint256 <<Governable>> +   priceProvider: address <<VaultStorage>> +   rebasePaused: bool <<VaultStorage>> +   capitalPaused: bool <<VaultStorage>> +   redeemFeeBps: uint256 <<VaultStorage>> +   vaultBuffer: uint256 <<VaultStorage>> +   autoAllocateThreshold: uint256 <<VaultStorage>> +   rebaseThreshold: uint256 <<VaultStorage>> +   adminImplPosition: bytes32 <<VaultStorage>> +   strategistAddr: address <<VaultStorage>> +   assetDefaultStrategies: mapping(address=>address) <<VaultStorage>> +   maxSupplyDiff: uint256 <<VaultStorage>> +   trusteeAddress: address <<VaultStorage>> +   trusteeFeeBps: uint256 <<VaultStorage>> +   MINT_MINIMUM_UNIT_PRICE: uint256 <<VaultStorage>> +   ousdMetaStrategy: address <<VaultStorage>> +   netOusdMintedForStrategy: int256 <<VaultStorage>> +   netOusdMintForStrategyThreshold: uint256 <<VaultStorage>> +   MIN_UNIT_PRICE_DRIFT: uint256 <<VaultStorage>> +   MAX_UNIT_PRICE_DRIFT: uint256 <<VaultStorage>> +   dripper: address <<VaultStorage>> +   withdrawalQueueMetadata: WithdrawalQueueMetadata <<VaultStorage>> +   withdrawalRequests: mapping(uint256=>WithdrawalRequest) <<VaultStorage>> + +Internal: +    _governor(): (governorOut: address) <<Governable>> +    _pendingGovernor(): (pendingGovernor: address) <<Governable>> +    _setGovernor(newGovernor: address) <<Governable>> +    _setPendingGovernor(newGovernor: address) <<Governable>> +    _changeGovernor(_newGovernor: address) <<Governable>> +    _depositToStrategy(_strategyToAddress: address, _assets: address[], _amounts: uint256[]) <<VaultAdmin>> +    _withdrawFromStrategy(_recipient: address, _strategyFromAddress: address, _assets: address[], _amounts: uint256[]) <<OETHVaultAdmin>> +    _withdrawAllFromStrategy(_strategyAddr: address) <<OETHVaultAdmin>> +    _withdrawAllFromStrategies() <<OETHVaultAdmin>> +    _cacheDecimals(token: address) <<VaultAdmin>> +External: +    transferGovernance(_newGovernor: address) <<onlyGovernor>> <<Governable>> +    claimGovernance() <<Governable>> +    setAdminImpl(newImpl: address) <<onlyGovernor>> <<VaultStorage>> +    setPriceProvider(_priceProvider: address) <<onlyGovernor>> <<VaultAdmin>> +    setRedeemFeeBps(_redeemFeeBps: uint256) <<onlyGovernor>> <<VaultAdmin>> +    setVaultBuffer(_vaultBuffer: uint256) <<onlyGovernorOrStrategist>> <<VaultAdmin>> +    setAutoAllocateThreshold(_threshold: uint256) <<onlyGovernor>> <<VaultAdmin>> +    setRebaseThreshold(_threshold: uint256) <<onlyGovernor>> <<VaultAdmin>> +    setStrategistAddr(_address: address) <<onlyGovernor>> <<VaultAdmin>> +    setAssetDefaultStrategy(_asset: address, _strategy: address) <<onlyGovernorOrStrategist>> <<VaultAdmin>> +    setNetOusdMintForStrategyThreshold(_threshold: uint256) <<onlyGovernor>> <<VaultAdmin>> +    setDripper(_dripper: address) <<onlyGovernor>> <<VaultAdmin>> +    swapCollateral(_fromAsset: address, _toAsset: address, _fromAssetAmount: uint256, _minToAssetAmount: uint256, _data: bytes): (toAssetAmount: uint256) <<nonReentrant, onlyGovernorOrStrategist>> <<VaultAdmin>> +    setSwapper(_swapperAddr: address) <<onlyGovernor>> <<VaultAdmin>> +    swapper(): (swapper_: address) <<VaultAdmin>> +    setSwapAllowedUndervalue(_basis: uint16) <<onlyGovernor>> <<VaultAdmin>> +    allowedSwapUndervalue(): (value: uint256) <<VaultAdmin>> +    setOracleSlippage(_asset: address, _allowedOracleSlippageBps: uint16) <<onlyGovernor>> <<VaultAdmin>> +    supportAsset(_asset: address, _unitConversion: uint8) <<onlyGovernor>> <<VaultAdmin>> +    cacheDecimals(_asset: address) <<onlyGovernor>> <<VaultAdmin>> +    approveStrategy(_addr: address) <<onlyGovernor>> <<VaultAdmin>> +    removeStrategy(_addr: address) <<onlyGovernor>> <<VaultAdmin>> +    depositToStrategy(_strategyToAddress: address, _assets: address[], _amounts: uint256[]) <<onlyGovernorOrStrategist, nonReentrant>> <<VaultAdmin>> +    withdrawFromStrategy(_strategyFromAddress: address, _assets: address[], _amounts: uint256[]) <<onlyGovernorOrStrategist, nonReentrant>> <<VaultAdmin>> +    setMaxSupplyDiff(_maxSupplyDiff: uint256) <<onlyGovernor>> <<VaultAdmin>> +    setTrusteeAddress(_address: address) <<onlyGovernor>> <<VaultAdmin>> +    setTrusteeFeeBps(_basis: uint256) <<onlyGovernor>> <<VaultAdmin>> +    setOusdMetaStrategy(_ousdMetaStrategy: address) <<onlyGovernor>> <<VaultAdmin>> +    pauseRebase() <<onlyGovernorOrStrategist>> <<VaultAdmin>> +    unpauseRebase() <<onlyGovernorOrStrategist>> <<VaultAdmin>> +    pauseCapital() <<onlyGovernorOrStrategist>> <<VaultAdmin>> +    unpauseCapital() <<onlyGovernorOrStrategist>> <<VaultAdmin>> +    transferToken(_asset: address, _amount: uint256) <<onlyGovernor>> <<VaultAdmin>> +    withdrawAllFromStrategy(_strategyAddr: address) <<onlyGovernorOrStrategist>> <<VaultAdmin>> +    withdrawAllFromStrategies() <<onlyGovernorOrStrategist>> <<VaultAdmin>> +Public: +    <<event>> PendingGovernorshipTransfer(previousGovernor: address, newGovernor: address) <<Governable>> +    <<event>> GovernorshipTransferred(previousGovernor: address, newGovernor: address) <<Governable>> +    <<event>> AssetSupported(_asset: address) <<VaultStorage>> +    <<event>> AssetDefaultStrategyUpdated(_asset: address, _strategy: address) <<VaultStorage>> +    <<event>> AssetAllocated(_asset: address, _strategy: address, _amount: uint256) <<VaultStorage>> +    <<event>> StrategyApproved(_addr: address) <<VaultStorage>> +    <<event>> StrategyRemoved(_addr: address) <<VaultStorage>> +    <<event>> Mint(_addr: address, _value: uint256) <<VaultStorage>> +    <<event>> Redeem(_addr: address, _value: uint256) <<VaultStorage>> +    <<event>> CapitalPaused() <<VaultStorage>> +    <<event>> CapitalUnpaused() <<VaultStorage>> +    <<event>> RebasePaused() <<VaultStorage>> +    <<event>> RebaseUnpaused() <<VaultStorage>> +    <<event>> VaultBufferUpdated(_vaultBuffer: uint256) <<VaultStorage>> +    <<event>> OusdMetaStrategyUpdated(_ousdMetaStrategy: address) <<VaultStorage>> +    <<event>> RedeemFeeUpdated(_redeemFeeBps: uint256) <<VaultStorage>> +    <<event>> PriceProviderUpdated(_priceProvider: address) <<VaultStorage>> +    <<event>> AllocateThresholdUpdated(_threshold: uint256) <<VaultStorage>> +    <<event>> RebaseThresholdUpdated(_threshold: uint256) <<VaultStorage>> +    <<event>> StrategistUpdated(_address: address) <<VaultStorage>> +    <<event>> MaxSupplyDiffChanged(maxSupplyDiff: uint256) <<VaultStorage>> +    <<event>> YieldDistribution(_to: address, _yield: uint256, _fee: uint256) <<VaultStorage>> +    <<event>> TrusteeFeeBpsChanged(_basis: uint256) <<VaultStorage>> +    <<event>> TrusteeAddressChanged(_address: address) <<VaultStorage>> +    <<event>> NetOusdMintForStrategyThresholdChanged(_threshold: uint256) <<VaultStorage>> +    <<event>> SwapperChanged(_address: address) <<VaultStorage>> +    <<event>> SwapAllowedUndervalueChanged(_basis: uint256) <<VaultStorage>> +    <<event>> SwapSlippageChanged(_asset: address, _basis: uint256) <<VaultStorage>> +    <<event>> Swapped(_fromAsset: address, _toAsset: address, _fromAssetAmount: uint256, _toAssetAmount: uint256) <<VaultStorage>> +    <<event>> DripperChanged(_dripper: address) <<VaultStorage>> +    <<event>> WithdrawalRequested(_withdrawer: address, _requestId: uint256, _amount: uint256, _queued: uint256) <<VaultStorage>> +    <<event>> WithdrawalClaimed(_withdrawer: address, _requestId: uint256, _amount: uint256) <<VaultStorage>> +    <<event>> WithdrawalClaimable(_claimable: uint256, _newClaimable: uint256) <<VaultStorage>>    <<modifier>> initializer() <<Initializable>>    <<modifier>> onlyGovernor() <<Governable>>    <<modifier>> nonReentrant() <<Governable>> diff --git a/contracts/docs/OETHVaultCoreSquashed.svg b/contracts/docs/OETHVaultCoreSquashed.svg index 364df560e0..b73f9cf9ff 100644 --- a/contracts/docs/OETHVaultCoreSquashed.svg +++ b/contracts/docs/OETHVaultCoreSquashed.svg @@ -4,140 +4,150 @@ - - + + UmlClassDiagram - + 220 - -OETHVaultCore -../contracts/vault/OETHVaultCore.sol - -Private: -   initialized: bool <<Initializable>> -   initializing: bool <<Initializable>> -   ______gap: uint256[50] <<Initializable>> -   governorPosition: bytes32 <<Governable>> -   pendingGovernorPosition: bytes32 <<Governable>> -   reentryStatusPosition: bytes32 <<Governable>> -   _deprecated_rebaseHooksAddr: address <<VaultStorage>> -   _deprecated_uniswapAddr: address <<VaultStorage>> -   _deprecated_swapTokens: address[] <<VaultStorage>> -   __gap: uint256[49] <<VaultStorage>> -Internal: -   assets: mapping(address=>Asset) <<VaultStorage>> -   allAssets: address[] <<VaultStorage>> -   strategies: mapping(address=>Strategy) <<VaultStorage>> -   allStrategies: address[] <<VaultStorage>> -   oUSD: OUSD <<VaultStorage>> -   swapConfig: SwapConfig <<VaultStorage>> -   MAX_INT: uint256 <<VaultCore>> -   MAX_UINT: uint256 <<VaultCore>> -Public: -   _NOT_ENTERED: uint256 <<Governable>> -   _ENTERED: uint256 <<Governable>> -   priceProvider: address <<VaultStorage>> -   rebasePaused: bool <<VaultStorage>> -   capitalPaused: bool <<VaultStorage>> -   redeemFeeBps: uint256 <<VaultStorage>> -   vaultBuffer: uint256 <<VaultStorage>> -   autoAllocateThreshold: uint256 <<VaultStorage>> -   rebaseThreshold: uint256 <<VaultStorage>> -   adminImplPosition: bytes32 <<VaultStorage>> -   strategistAddr: address <<VaultStorage>> -   assetDefaultStrategies: mapping(address=>address) <<VaultStorage>> -   maxSupplyDiff: uint256 <<VaultStorage>> -   trusteeAddress: address <<VaultStorage>> -   trusteeFeeBps: uint256 <<VaultStorage>> -   MINT_MINIMUM_UNIT_PRICE: uint256 <<VaultStorage>> -   ousdMetaStrategy: address <<VaultStorage>> -   netOusdMintedForStrategy: int256 <<VaultStorage>> -   netOusdMintForStrategyThreshold: uint256 <<VaultStorage>> -   MIN_UNIT_PRICE_DRIFT: uint256 <<VaultStorage>> -   MAX_UNIT_PRICE_DRIFT: uint256 <<VaultStorage>> -   dripper: address <<VaultStorage>> -   weth: address <<OETHVaultCore>> -   wethAssetIndex: uint256 <<OETHVaultCore>> - -Private: -    abs(x: int256): uint256 <<VaultCore>> -Internal: -    _governor(): (governorOut: address) <<Governable>> -    _pendingGovernor(): (pendingGovernor: address) <<Governable>> -    _setGovernor(newGovernor: address) <<Governable>> -    _setPendingGovernor(newGovernor: address) <<Governable>> -    _changeGovernor(_newGovernor: address) <<Governable>> -    _mint(_asset: address, _amount: uint256, _minimumOusdAmount: uint256) <<OETHVaultCore>> -    _redeem(_amount: uint256, _minimumUnitAmount: uint256) <<OETHVaultCore>> -    _postRedeem(_amount: uint256) <<VaultCore>> -    _allocate() <<VaultCore>> -    _rebase(): uint256 <<whenNotRebasePaused>> <<VaultCore>> -    _totalValue(): (value: uint256) <<VaultCore>> -    _totalValueInVault(): (value: uint256) <<VaultCore>> -    _totalValueInStrategies(): (value: uint256) <<VaultCore>> -    _totalValueInStrategy(_strategyAddr: address): (value: uint256) <<VaultCore>> -    _checkBalance(_asset: address): (balance: uint256) <<VaultCore>> -    _calculateRedeemOutputs(_amount: uint256): (outputs: uint256[]) <<OETHVaultCore>> -    _toUnits(_raw: uint256, _asset: address): uint256 <<VaultCore>> -    _toUnitPrice(_asset: address, isMint: bool): (price: uint256) <<VaultCore>> -    _getDecimals(_asset: address): (decimals: uint256) <<VaultCore>> -External: -    transferGovernance(_newGovernor: address) <<onlyGovernor>> <<Governable>> -    claimGovernance() <<Governable>> -    setAdminImpl(newImpl: address) <<onlyGovernor>> <<VaultStorage>> -    initialize(_priceProvider: address, _oToken: address) <<onlyGovernor, initializer>> <<VaultInitializer>> -    mint(_asset: address, _amount: uint256, _minimumOusdAmount: uint256) <<whenNotCapitalPaused, nonReentrant>> <<VaultCore>> -    mintForStrategy(_amount: uint256) <<whenNotCapitalPaused, onlyOusdMetaStrategy>> <<VaultCore>> -    redeem(_amount: uint256, _minimumUnitAmount: uint256) <<whenNotCapitalPaused, nonReentrant>> <<VaultCore>> -    burnForStrategy(_amount: uint256) <<whenNotCapitalPaused, onlyOusdMetaStrategy>> <<VaultCore>> -    redeemAll(_minimumUnitAmount: uint256) <<whenNotCapitalPaused, nonReentrant>> <<VaultCore>> -    allocate() <<whenNotCapitalPaused, nonReentrant>> <<VaultCore>> -    rebase() <<nonReentrant>> <<VaultCore>> -    totalValue(): (value: uint256) <<VaultCore>> -    checkBalance(_asset: address): uint256 <<VaultCore>> -    calculateRedeemOutputs(_amount: uint256): uint256[] <<VaultCore>> -    priceUnitMint(asset: address): (price: uint256) <<VaultCore>> -    priceUnitRedeem(asset: address): (price: uint256) <<VaultCore>> -    getAllAssets(): address[] <<VaultCore>> -    getStrategyCount(): uint256 <<VaultCore>> -    getAllStrategies(): address[] <<VaultCore>> -    isSupportedAsset(_asset: address): bool <<VaultCore>> -    null() <<VaultCore>> -    cacheWETHAssetIndex() <<onlyGovernor>> <<OETHVaultCore>> -Public: -    <<event>> PendingGovernorshipTransfer(previousGovernor: address, newGovernor: address) <<Governable>> -    <<event>> GovernorshipTransferred(previousGovernor: address, newGovernor: address) <<Governable>> -    <<event>> AssetSupported(_asset: address) <<VaultStorage>> -    <<event>> AssetDefaultStrategyUpdated(_asset: address, _strategy: address) <<VaultStorage>> -    <<event>> AssetAllocated(_asset: address, _strategy: address, _amount: uint256) <<VaultStorage>> -    <<event>> StrategyApproved(_addr: address) <<VaultStorage>> -    <<event>> StrategyRemoved(_addr: address) <<VaultStorage>> -    <<event>> Mint(_addr: address, _value: uint256) <<VaultStorage>> -    <<event>> Redeem(_addr: address, _value: uint256) <<VaultStorage>> -    <<event>> CapitalPaused() <<VaultStorage>> -    <<event>> CapitalUnpaused() <<VaultStorage>> -    <<event>> RebasePaused() <<VaultStorage>> -    <<event>> RebaseUnpaused() <<VaultStorage>> -    <<event>> VaultBufferUpdated(_vaultBuffer: uint256) <<VaultStorage>> -    <<event>> OusdMetaStrategyUpdated(_ousdMetaStrategy: address) <<VaultStorage>> -    <<event>> RedeemFeeUpdated(_redeemFeeBps: uint256) <<VaultStorage>> -    <<event>> PriceProviderUpdated(_priceProvider: address) <<VaultStorage>> -    <<event>> AllocateThresholdUpdated(_threshold: uint256) <<VaultStorage>> -    <<event>> RebaseThresholdUpdated(_threshold: uint256) <<VaultStorage>> -    <<event>> StrategistUpdated(_address: address) <<VaultStorage>> -    <<event>> MaxSupplyDiffChanged(maxSupplyDiff: uint256) <<VaultStorage>> -    <<event>> YieldDistribution(_to: address, _yield: uint256, _fee: uint256) <<VaultStorage>> -    <<event>> TrusteeFeeBpsChanged(_basis: uint256) <<VaultStorage>> -    <<event>> TrusteeAddressChanged(_address: address) <<VaultStorage>> -    <<event>> NetOusdMintForStrategyThresholdChanged(_threshold: uint256) <<VaultStorage>> -    <<event>> SwapperChanged(_address: address) <<VaultStorage>> -    <<event>> SwapAllowedUndervalueChanged(_basis: uint256) <<VaultStorage>> -    <<event>> SwapSlippageChanged(_asset: address, _basis: uint256) <<VaultStorage>> -    <<event>> Swapped(_fromAsset: address, _toAsset: address, _fromAssetAmount: uint256, _toAssetAmount: uint256) <<VaultStorage>> -    <<event>> DripperChanged(_dripper: address) <<VaultStorage>> + +OETHVaultCore +../contracts/vault/OETHVaultCore.sol + +Private: +   initialized: bool <<Initializable>> +   initializing: bool <<Initializable>> +   ______gap: uint256[50] <<Initializable>> +   governorPosition: bytes32 <<Governable>> +   pendingGovernorPosition: bytes32 <<Governable>> +   reentryStatusPosition: bytes32 <<Governable>> +   _deprecated_rebaseHooksAddr: address <<VaultStorage>> +   _deprecated_uniswapAddr: address <<VaultStorage>> +   _deprecated_swapTokens: address[] <<VaultStorage>> +   __gap: uint256[46] <<VaultStorage>> +Internal: +   assets: mapping(address=>Asset) <<VaultStorage>> +   allAssets: address[] <<VaultStorage>> +   strategies: mapping(address=>Strategy) <<VaultStorage>> +   allStrategies: address[] <<VaultStorage>> +   oUSD: OUSD <<VaultStorage>> +   swapConfig: SwapConfig <<VaultStorage>> +   MAX_INT: uint256 <<VaultCore>> +   MAX_UINT: uint256 <<VaultCore>> +Public: +   _NOT_ENTERED: uint256 <<Governable>> +   _ENTERED: uint256 <<Governable>> +   priceProvider: address <<VaultStorage>> +   rebasePaused: bool <<VaultStorage>> +   capitalPaused: bool <<VaultStorage>> +   redeemFeeBps: uint256 <<VaultStorage>> +   vaultBuffer: uint256 <<VaultStorage>> +   autoAllocateThreshold: uint256 <<VaultStorage>> +   rebaseThreshold: uint256 <<VaultStorage>> +   adminImplPosition: bytes32 <<VaultStorage>> +   strategistAddr: address <<VaultStorage>> +   assetDefaultStrategies: mapping(address=>address) <<VaultStorage>> +   maxSupplyDiff: uint256 <<VaultStorage>> +   trusteeAddress: address <<VaultStorage>> +   trusteeFeeBps: uint256 <<VaultStorage>> +   MINT_MINIMUM_UNIT_PRICE: uint256 <<VaultStorage>> +   ousdMetaStrategy: address <<VaultStorage>> +   netOusdMintedForStrategy: int256 <<VaultStorage>> +   netOusdMintForStrategyThreshold: uint256 <<VaultStorage>> +   MIN_UNIT_PRICE_DRIFT: uint256 <<VaultStorage>> +   MAX_UNIT_PRICE_DRIFT: uint256 <<VaultStorage>> +   dripper: address <<VaultStorage>> +   withdrawalQueueMetadata: WithdrawalQueueMetadata <<VaultStorage>> +   withdrawalRequests: mapping(uint256=>WithdrawalRequest) <<VaultStorage>> +   weth: address <<OETHVaultCore>> +   wethAssetIndex: uint256 <<OETHVaultCore>> + +Private: +    abs(x: int256): uint256 <<VaultCore>> +Internal: +    _governor(): (governorOut: address) <<Governable>> +    _pendingGovernor(): (pendingGovernor: address) <<Governable>> +    _setGovernor(newGovernor: address) <<Governable>> +    _setPendingGovernor(newGovernor: address) <<Governable>> +    _changeGovernor(_newGovernor: address) <<Governable>> +    _mint(_asset: address, _amount: uint256, _minimumOusdAmount: uint256) <<OETHVaultCore>> +    _redeem(_amount: uint256, _minimumUnitAmount: uint256) <<OETHVaultCore>> +    _postRedeem(_amount: uint256) <<VaultCore>> +    _allocate() <<OETHVaultCore>> +    _rebase(): uint256 <<whenNotRebasePaused>> <<VaultCore>> +    _totalValue(): (value: uint256) <<VaultCore>> +    _totalValueInVault(): (value: uint256) <<OETHVaultCore>> +    _totalValueInStrategies(): (value: uint256) <<VaultCore>> +    _totalValueInStrategy(_strategyAddr: address): (value: uint256) <<VaultCore>> +    _checkBalance(_asset: address): (balance: uint256) <<OETHVaultCore>> +    _calculateRedeemOutputs(_amount: uint256): (outputs: uint256[]) <<OETHVaultCore>> +    _toUnits(_raw: uint256, _asset: address): uint256 <<VaultCore>> +    _toUnitPrice(_asset: address, isMint: bool): (price: uint256) <<VaultCore>> +    _getDecimals(_asset: address): (decimals: uint256) <<VaultCore>> +    _addWithdrawalQueueLiquidity() <<OETHVaultCore>> +    _wethAvailable(): (wethAvailable: uint256) <<OETHVaultCore>> +External: +    transferGovernance(_newGovernor: address) <<onlyGovernor>> <<Governable>> +    claimGovernance() <<Governable>> +    setAdminImpl(newImpl: address) <<onlyGovernor>> <<VaultStorage>> +    initialize(_priceProvider: address, _oToken: address) <<onlyGovernor, initializer>> <<VaultInitializer>> +    mint(_asset: address, _amount: uint256, _minimumOusdAmount: uint256) <<whenNotCapitalPaused, nonReentrant>> <<VaultCore>> +    mintForStrategy(_amount: uint256) <<whenNotCapitalPaused, onlyOusdMetaStrategy>> <<VaultCore>> +    redeem(_amount: uint256, _minimumUnitAmount: uint256) <<whenNotCapitalPaused, nonReentrant>> <<VaultCore>> +    burnForStrategy(_amount: uint256) <<whenNotCapitalPaused, onlyOusdMetaStrategy>> <<VaultCore>> +    redeemAll(_minimumUnitAmount: uint256) <<whenNotCapitalPaused, nonReentrant>> <<VaultCore>> +    allocate() <<whenNotCapitalPaused, nonReentrant>> <<VaultCore>> +    rebase() <<nonReentrant>> <<VaultCore>> +    totalValue(): (value: uint256) <<VaultCore>> +    checkBalance(_asset: address): uint256 <<VaultCore>> +    calculateRedeemOutputs(_amount: uint256): uint256[] <<VaultCore>> +    priceUnitMint(asset: address): (price: uint256) <<VaultCore>> +    priceUnitRedeem(asset: address): (price: uint256) <<VaultCore>> +    getAllAssets(): address[] <<VaultCore>> +    getStrategyCount(): uint256 <<VaultCore>> +    getAllStrategies(): address[] <<VaultCore>> +    isSupportedAsset(_asset: address): bool <<VaultCore>> +    null() <<VaultCore>> +    cacheWETHAssetIndex() <<onlyGovernor>> <<OETHVaultCore>> +    requestWithdrawal(_amount: uint256): (requestId: uint256, queued: uint256) <<whenNotCapitalPaused, nonReentrant>> <<OETHVaultCore>> +    claimWithdrawal(requestId: uint256) <<whenNotCapitalPaused, nonReentrant>> <<OETHVaultCore>> +    addWithdrawalQueueLiquidity() <<OETHVaultCore>> +Public: +    <<event>> PendingGovernorshipTransfer(previousGovernor: address, newGovernor: address) <<Governable>> +    <<event>> GovernorshipTransferred(previousGovernor: address, newGovernor: address) <<Governable>> +    <<event>> AssetSupported(_asset: address) <<VaultStorage>> +    <<event>> AssetDefaultStrategyUpdated(_asset: address, _strategy: address) <<VaultStorage>> +    <<event>> AssetAllocated(_asset: address, _strategy: address, _amount: uint256) <<VaultStorage>> +    <<event>> StrategyApproved(_addr: address) <<VaultStorage>> +    <<event>> StrategyRemoved(_addr: address) <<VaultStorage>> +    <<event>> Mint(_addr: address, _value: uint256) <<VaultStorage>> +    <<event>> Redeem(_addr: address, _value: uint256) <<VaultStorage>> +    <<event>> CapitalPaused() <<VaultStorage>> +    <<event>> CapitalUnpaused() <<VaultStorage>> +    <<event>> RebasePaused() <<VaultStorage>> +    <<event>> RebaseUnpaused() <<VaultStorage>> +    <<event>> VaultBufferUpdated(_vaultBuffer: uint256) <<VaultStorage>> +    <<event>> OusdMetaStrategyUpdated(_ousdMetaStrategy: address) <<VaultStorage>> +    <<event>> RedeemFeeUpdated(_redeemFeeBps: uint256) <<VaultStorage>> +    <<event>> PriceProviderUpdated(_priceProvider: address) <<VaultStorage>> +    <<event>> AllocateThresholdUpdated(_threshold: uint256) <<VaultStorage>> +    <<event>> RebaseThresholdUpdated(_threshold: uint256) <<VaultStorage>> +    <<event>> StrategistUpdated(_address: address) <<VaultStorage>> +    <<event>> MaxSupplyDiffChanged(maxSupplyDiff: uint256) <<VaultStorage>> +    <<event>> YieldDistribution(_to: address, _yield: uint256, _fee: uint256) <<VaultStorage>> +    <<event>> TrusteeFeeBpsChanged(_basis: uint256) <<VaultStorage>> +    <<event>> TrusteeAddressChanged(_address: address) <<VaultStorage>> +    <<event>> NetOusdMintForStrategyThresholdChanged(_threshold: uint256) <<VaultStorage>> +    <<event>> SwapperChanged(_address: address) <<VaultStorage>> +    <<event>> SwapAllowedUndervalueChanged(_basis: uint256) <<VaultStorage>> +    <<event>> SwapSlippageChanged(_asset: address, _basis: uint256) <<VaultStorage>> +    <<event>> Swapped(_fromAsset: address, _toAsset: address, _fromAssetAmount: uint256, _toAssetAmount: uint256) <<VaultStorage>> +    <<event>> DripperChanged(_dripper: address) <<VaultStorage>> +    <<event>> WithdrawalRequested(_withdrawer: address, _requestId: uint256, _amount: uint256, _queued: uint256) <<VaultStorage>> +    <<event>> WithdrawalClaimed(_withdrawer: address, _requestId: uint256, _amount: uint256) <<VaultStorage>> +    <<event>> WithdrawalClaimable(_claimable: uint256, _newClaimable: uint256) <<VaultStorage>>    <<modifier>> initializer() <<Initializable>>    <<modifier>> onlyGovernor() <<Governable>>    <<modifier>> nonReentrant() <<Governable>> diff --git a/contracts/docs/OETHVaultHierarchy.svg b/contracts/docs/OETHVaultHierarchy.svg index c49d1de411..3c78b58525 100644 --- a/contracts/docs/OETHVaultHierarchy.svg +++ b/contracts/docs/OETHVaultHierarchy.svg @@ -4,294 +4,154 @@ - - + + UmlClassDiagram - + 20 - -Governable -../contracts/governance/Governable.sol - - - -40 - -<<Interface>> -IDripper -../contracts/interfaces/IDripper.sol - - - -44 - -<<Interface>> -IGetExchangeRateToken -../contracts/interfaces/IGetExchangeRateToken.sol - - - -51 - -<<Interface>> -IOracle -../contracts/interfaces/IOracle.sol - - - -57 - -<<Interface>> -IStrategy -../contracts/interfaces/IStrategy.sol - - - -58 - -<<Interface>> -ISwapper -../contracts/interfaces/ISwapper.sol - - - -61 - -<<Interface>> -IVault -../contracts/interfaces/IVault.sol - - - -226 - -VaultStorage -../contracts/vault/VaultStorage.sol - - - -61->226 - - + +Governable +../contracts/governance/Governable.sol - + 205 - -OUSD -../contracts/token/OUSD.sol + +OUSD +../contracts/token/OUSD.sol - + 205->20 - - + + - + 213 - -<<Abstract>> -Initializable -../contracts/utils/Initializable.sol + +<<Abstract>> +Initializable +../contracts/utils/Initializable.sol - + 205->213 - - + + - + 216 - -<<Abstract>> -InitializableERC20Detailed -../contracts/utils/InitializableERC20Detailed.sol + +<<Abstract>> +InitializableERC20Detailed +../contracts/utils/InitializableERC20Detailed.sol - + 205->216 - - - - - -695 - -<<Interface>> -IERC20 -../node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol - - - -216->695 - - + + - + 219 - -OETHVaultAdmin -../contracts/vault/OETHVaultAdmin.sol + +OETHVaultAdmin +../contracts/vault/OETHVaultAdmin.sol - + 223 - -VaultAdmin -../contracts/vault/VaultAdmin.sol + +VaultAdmin +../contracts/vault/VaultAdmin.sol - + 219->223 - - + + - + 220 - -OETHVaultCore -../contracts/vault/OETHVaultCore.sol - - - -220->57 - - + +OETHVaultCore +../contracts/vault/OETHVaultCore.sol - + 224 - -VaultCore -../contracts/vault/VaultCore.sol + +VaultCore +../contracts/vault/VaultCore.sol - + 220->224 - - + + - - -220->695 - - - - - -223->51 - - - - - -223->57 - - - - - -223->58 - - - - - -223->61 - - + + +226 + +VaultStorage +../contracts/vault/VaultStorage.sol - + 223->226 - - - - - -223->695 - - - - - -224->40 - - - - - -224->44 - - - - - -224->51 - - - - - -224->57 - - + + - + 225 - -VaultInitializer -../contracts/vault/VaultInitializer.sol + +VaultInitializer +../contracts/vault/VaultInitializer.sol - + 224->225 - - - - - -224->695 - - + + - + 225->205 - - + + - + 225->226 - - + + - + 226->20 - - + + - + 226->205 - - + + - + 226->213 - - + + diff --git a/contracts/docs/OETHVaultStorage.svg b/contracts/docs/OETHVaultStorage.svg index 48115ee9f1..6b7fb8f27f 100644 --- a/contracts/docs/OETHVaultStorage.svg +++ b/contracts/docs/OETHVaultStorage.svg @@ -4,290 +4,356 @@ - - + + StorageDiagram - - + + -7 - -OETHVaultCore <<Contract>> - -slot - -0 - -1-50 - -51 - -52 - -53 - -54 - -55 - -56 - -57 - -58 - -59 - -60 - -61 - -62 - -63 - -64 - -65 - -66 - -67 - -68 - -69 - -70 - -71 - -72 - -73 - -74-122 - -123 - -type: <inherited contract>.variable (bytes) - -unallocated (30) - -bool: Initializable.initializing (1) - -bool: Initializable.initialized (1) - -uint256[50]: Initializable.______gap (1600) - -mapping(address=>Asset): VaultStorage.assets (32) - -address[]: VaultStorage.allAssets (32) - -mapping(address=>Strategy): VaultStorage.strategies (32) - -address[]: VaultStorage.allStrategies (32) - -unallocated (10) - -bool: VaultStorage.capitalPaused (1) - -bool: VaultStorage.rebasePaused (1) - -address: VaultStorage.priceProvider (20) - -uint256: VaultStorage.redeemFeeBps (32) - -uint256: VaultStorage.vaultBuffer (32) - -uint256: VaultStorage.autoAllocateThreshold (32) - -uint256: VaultStorage.rebaseThreshold (32) - -unallocated (12) - -OUSD: VaultStorage.oUSD (20) - -unallocated (12) - -address: VaultStorage._deprecated_rebaseHooksAddr (20) - -unallocated (12) - -address: VaultStorage._deprecated_uniswapAddr (20) - -unallocated (12) - -address: VaultStorage.strategistAddr (20) - -mapping(address=>address): VaultStorage.assetDefaultStrategies (32) - -uint256: VaultStorage.maxSupplyDiff (32) - -unallocated (12) - -address: VaultStorage.trusteeAddress (20) - -uint256: VaultStorage.trusteeFeeBps (32) - -address[]: VaultStorage._deprecated_swapTokens (32) - -unallocated (12) - -address: VaultStorage.ousdMetaStrategy (20) - -int256: VaultStorage.netOusdMintedForStrategy (32) - -uint256: VaultStorage.netOusdMintForStrategyThreshold (32) - -SwapConfig: VaultStorage.swapConfig (32) - -unallocated (12) - -address: VaultStorage.dripper (20) - -uint256[49]: VaultStorage.__gap (1568) - -uint256: wethAssetIndex (32) +9 + +OETHVaultCore <<Contract>> + +slot + +0 + +1-50 + +51 + +52 + +53 + +54 + +55 + +56 + +57 + +58 + +59 + +60 + +61 + +62 + +63 + +64 + +65 + +66 + +67 + +68 + +69 + +70 + +71 + +72 + +73 + +74-75 + +76 + +77-122 + +123 + +type: <inherited contract>.variable (bytes) + +unallocated (30) + +bool: Initializable.initializing (1) + +bool: Initializable.initialized (1) + +uint256[50]: Initializable.______gap (1600) + +mapping(address=>Asset): VaultStorage.assets (32) + +address[]: VaultStorage.allAssets (32) + +mapping(address=>Strategy): VaultStorage.strategies (32) + +address[]: VaultStorage.allStrategies (32) + +unallocated (10) + +bool: VaultStorage.capitalPaused (1) + +bool: VaultStorage.rebasePaused (1) + +address: VaultStorage.priceProvider (20) + +uint256: VaultStorage.redeemFeeBps (32) + +uint256: VaultStorage.vaultBuffer (32) + +uint256: VaultStorage.autoAllocateThreshold (32) + +uint256: VaultStorage.rebaseThreshold (32) + +unallocated (12) + +OUSD: VaultStorage.oUSD (20) + +unallocated (12) + +address: VaultStorage._deprecated_rebaseHooksAddr (20) + +unallocated (12) + +address: VaultStorage._deprecated_uniswapAddr (20) + +unallocated (12) + +address: VaultStorage.strategistAddr (20) + +mapping(address=>address): VaultStorage.assetDefaultStrategies (32) + +uint256: VaultStorage.maxSupplyDiff (32) + +unallocated (12) + +address: VaultStorage.trusteeAddress (20) + +uint256: VaultStorage.trusteeFeeBps (32) + +address[]: VaultStorage._deprecated_swapTokens (32) + +unallocated (12) + +address: VaultStorage.ousdMetaStrategy (20) + +int256: VaultStorage.netOusdMintedForStrategy (32) + +uint256: VaultStorage.netOusdMintForStrategyThreshold (32) + +SwapConfig: VaultStorage.swapConfig (32) + +unallocated (12) + +address: VaultStorage.dripper (20) + +WithdrawalQueueMetadata: VaultStorage.withdrawalQueueMetadata (64) + +mapping(uint256=>WithdrawalRequest): VaultStorage.withdrawalRequests (32) + +uint256[46]: VaultStorage.__gap (1472) + +uint256: wethAssetIndex (32) 1 - -Asset <<Struct>> - -offset - -0 - -type: variable (bytes) - -unallocated (27) - -uint16: allowedOracleSlippageBps (2) - -uint8: decimals (1) - -UnitConversion: unitConversion (1) - -bool: isSupported (1) + +Asset <<Struct>> + +offset + +0 + +type: variable (bytes) + +unallocated (27) + +uint16: allowedOracleSlippageBps (2) + +uint8: decimals (1) + +UnitConversion: unitConversion (1) + +bool: isSupported (1) - + -7:8->1 - - +9:8->1 + + 2 - -address[]: allAssets <<Array>> -0x46bddb1178e94d7f2892ff5f366840eb658911794f2c3a44c450aa2c505186c1 - -offset - -0 - -type: variable (bytes) - -unallocated (12) - -address (20) + +address[]: allAssets <<Array>> +0x46bddb1178e94d7f2892ff5f366840eb658911794f2c3a44c450aa2c505186c1 + +offset + +0 + +type: variable (bytes) + +unallocated (12) + +address (20) - + -7:10->2 - - +9:10->2 + + 3 - -Strategy <<Struct>> - -offset - -0 - -1 - -type: variable (bytes) - -unallocated (31) - -bool: isSupported (1) - -uint256: _deprecated (32) + +Strategy <<Struct>> + +offset + +0 + +1 + +type: variable (bytes) + +unallocated (31) + +bool: isSupported (1) + +uint256: _deprecated (32) - + -7:13->3 - - +9:13->3 + + 4 - -address[]: allStrategies <<Array>> -0x4a11f94e20a93c79f6ec743a1954ec4fc2c08429ae2122118bf234b2185c81b8 - -offset - -0 - -type: variable (bytes) - -unallocated (12) - -address (20) + +address[]: allStrategies <<Array>> +0x4a11f94e20a93c79f6ec743a1954ec4fc2c08429ae2122118bf234b2185c81b8 + +offset + +0 + +type: variable (bytes) + +unallocated (12) + +address (20) - + -7:15->4 - - +9:15->4 + + 5 - -SwapConfig <<Struct>> - -slot - -72 - -type: variable (bytes) - -unallocated (10) - -uint16: allowedUndervalueBps (2) - -address: swapper (20) + +SwapConfig <<Struct>> + +slot + +72 + +type: variable (bytes) + +unallocated (10) + +uint16: allowedUndervalueBps (2) + +address: swapper (20) - + -7:37->5 - - +9:37->5 + + 6 + +WithdrawalQueueMetadata <<Struct>> + +slot + +74 + +75 + +type: variable (bytes) + +uint128: claimable (16) + +uint128: queued (16) + +uint128: nextWithdrawalIndex (16) + +uint128: claimed (16) + + + +9:43->6 + + + + + +7 + +WithdrawalRequest <<Struct>> + +offset + +0 + +1 + +type: variable (bytes) + +unallocated (11) + +bool: claimed (1) + +address: withdrawer (20) + +uint128: queued (16) + +uint128: amount (16) + + + +9:48->7 + + + + + +8 -uint256[49]: __gap <<Array>> +uint256[46]: __gap <<Array>> slot -74 +77 -75 +78 -76-120 +79-120 121 @@ -299,17 +365,17 @@ uint256 (32) ----- (1440) +---- (1344) uint256 (32) uint256 (32) - - -7:44->6 - - + + +9:54->8 + + diff --git a/contracts/docs/VaultAdminSquashed.svg b/contracts/docs/VaultAdminSquashed.svg index 8dbca545e8..97415e45e7 100644 --- a/contracts/docs/VaultAdminSquashed.svg +++ b/contracts/docs/VaultAdminSquashed.svg @@ -4,136 +4,143 @@ - - + + UmlClassDiagram - + 223 - -VaultAdmin -../contracts/vault/VaultAdmin.sol - -Private: -   initialized: bool <<Initializable>> -   initializing: bool <<Initializable>> -   ______gap: uint256[50] <<Initializable>> -   governorPosition: bytes32 <<Governable>> -   pendingGovernorPosition: bytes32 <<Governable>> -   reentryStatusPosition: bytes32 <<Governable>> -   _deprecated_rebaseHooksAddr: address <<VaultStorage>> -   _deprecated_uniswapAddr: address <<VaultStorage>> -   _deprecated_swapTokens: address[] <<VaultStorage>> -   __gap: uint256[49] <<VaultStorage>> -Internal: -   assets: mapping(address=>Asset) <<VaultStorage>> -   allAssets: address[] <<VaultStorage>> -   strategies: mapping(address=>Strategy) <<VaultStorage>> -   allStrategies: address[] <<VaultStorage>> -   oUSD: OUSD <<VaultStorage>> -   swapConfig: SwapConfig <<VaultStorage>> -Public: -   _NOT_ENTERED: uint256 <<Governable>> -   _ENTERED: uint256 <<Governable>> -   priceProvider: address <<VaultStorage>> -   rebasePaused: bool <<VaultStorage>> -   capitalPaused: bool <<VaultStorage>> -   redeemFeeBps: uint256 <<VaultStorage>> -   vaultBuffer: uint256 <<VaultStorage>> -   autoAllocateThreshold: uint256 <<VaultStorage>> -   rebaseThreshold: uint256 <<VaultStorage>> -   adminImplPosition: bytes32 <<VaultStorage>> -   strategistAddr: address <<VaultStorage>> -   assetDefaultStrategies: mapping(address=>address) <<VaultStorage>> -   maxSupplyDiff: uint256 <<VaultStorage>> -   trusteeAddress: address <<VaultStorage>> -   trusteeFeeBps: uint256 <<VaultStorage>> -   MINT_MINIMUM_UNIT_PRICE: uint256 <<VaultStorage>> -   ousdMetaStrategy: address <<VaultStorage>> -   netOusdMintedForStrategy: int256 <<VaultStorage>> -   netOusdMintForStrategyThreshold: uint256 <<VaultStorage>> -   MIN_UNIT_PRICE_DRIFT: uint256 <<VaultStorage>> -   MAX_UNIT_PRICE_DRIFT: uint256 <<VaultStorage>> -   dripper: address <<VaultStorage>> - -Internal: -    _governor(): (governorOut: address) <<Governable>> -    _pendingGovernor(): (pendingGovernor: address) <<Governable>> -    _setGovernor(newGovernor: address) <<Governable>> -    _setPendingGovernor(newGovernor: address) <<Governable>> -    _changeGovernor(_newGovernor: address) <<Governable>> -    _depositToStrategy(_strategyToAddress: address, _assets: address[], _amounts: uint256[]) <<VaultAdmin>> -    _withdrawFromStrategy(_recipient: address, _strategyFromAddress: address, _assets: address[], _amounts: uint256[]) <<VaultAdmin>> -    _cacheDecimals(token: address) <<VaultAdmin>> -External: -    transferGovernance(_newGovernor: address) <<onlyGovernor>> <<Governable>> -    claimGovernance() <<Governable>> -    setAdminImpl(newImpl: address) <<onlyGovernor>> <<VaultStorage>> -    setPriceProvider(_priceProvider: address) <<onlyGovernor>> <<VaultAdmin>> -    setRedeemFeeBps(_redeemFeeBps: uint256) <<onlyGovernor>> <<VaultAdmin>> -    setVaultBuffer(_vaultBuffer: uint256) <<onlyGovernorOrStrategist>> <<VaultAdmin>> -    setAutoAllocateThreshold(_threshold: uint256) <<onlyGovernor>> <<VaultAdmin>> -    setRebaseThreshold(_threshold: uint256) <<onlyGovernor>> <<VaultAdmin>> -    setStrategistAddr(_address: address) <<onlyGovernor>> <<VaultAdmin>> -    setAssetDefaultStrategy(_asset: address, _strategy: address) <<onlyGovernorOrStrategist>> <<VaultAdmin>> -    setDripper(_dripper: address) <<onlyGovernor>> <<VaultAdmin>> -    setNetOusdMintForStrategyThreshold(_threshold: uint256) <<onlyGovernor>> <<VaultAdmin>> -    swapCollateral(_fromAsset: address, _toAsset: address, _fromAssetAmount: uint256, _minToAssetAmount: uint256, _data: bytes): (toAssetAmount: uint256) <<nonReentrant, onlyGovernorOrStrategist>> <<VaultAdmin>> -    setSwapper(_swapperAddr: address) <<onlyGovernor>> <<VaultAdmin>> -    swapper(): (swapper_: address) <<VaultAdmin>> -    setSwapAllowedUndervalue(_basis: uint16) <<onlyGovernor>> <<VaultAdmin>> -    allowedSwapUndervalue(): (value: uint256) <<VaultAdmin>> -    setOracleSlippage(_asset: address, _allowedOracleSlippageBps: uint16) <<onlyGovernor>> <<VaultAdmin>> -    supportAsset(_asset: address, _unitConversion: uint8) <<onlyGovernor>> <<VaultAdmin>> -    cacheDecimals(_asset: address) <<onlyGovernor>> <<VaultAdmin>> -    approveStrategy(_addr: address) <<onlyGovernor>> <<VaultAdmin>> -    removeStrategy(_addr: address) <<onlyGovernor>> <<VaultAdmin>> -    depositToStrategy(_strategyToAddress: address, _assets: address[], _amounts: uint256[]) <<onlyGovernorOrStrategist, nonReentrant>> <<VaultAdmin>> -    withdrawFromStrategy(_strategyFromAddress: address, _assets: address[], _amounts: uint256[]) <<onlyGovernorOrStrategist, nonReentrant>> <<VaultAdmin>> -    setMaxSupplyDiff(_maxSupplyDiff: uint256) <<onlyGovernor>> <<VaultAdmin>> -    setTrusteeAddress(_address: address) <<onlyGovernor>> <<VaultAdmin>> -    setTrusteeFeeBps(_basis: uint256) <<onlyGovernor>> <<VaultAdmin>> -    setOusdMetaStrategy(_ousdMetaStrategy: address) <<onlyGovernor>> <<VaultAdmin>> -    pauseRebase() <<onlyGovernorOrStrategist>> <<VaultAdmin>> -    unpauseRebase() <<onlyGovernorOrStrategist>> <<VaultAdmin>> -    pauseCapital() <<onlyGovernorOrStrategist>> <<VaultAdmin>> -    unpauseCapital() <<onlyGovernorOrStrategist>> <<VaultAdmin>> -    transferToken(_asset: address, _amount: uint256) <<onlyGovernor>> <<VaultAdmin>> -    withdrawAllFromStrategy(_strategyAddr: address) <<onlyGovernorOrStrategist>> <<VaultAdmin>> -    withdrawAllFromStrategies() <<onlyGovernorOrStrategist>> <<VaultAdmin>> -Public: -    <<event>> PendingGovernorshipTransfer(previousGovernor: address, newGovernor: address) <<Governable>> -    <<event>> GovernorshipTransferred(previousGovernor: address, newGovernor: address) <<Governable>> -    <<event>> AssetSupported(_asset: address) <<VaultStorage>> -    <<event>> AssetDefaultStrategyUpdated(_asset: address, _strategy: address) <<VaultStorage>> -    <<event>> AssetAllocated(_asset: address, _strategy: address, _amount: uint256) <<VaultStorage>> -    <<event>> StrategyApproved(_addr: address) <<VaultStorage>> -    <<event>> StrategyRemoved(_addr: address) <<VaultStorage>> -    <<event>> Mint(_addr: address, _value: uint256) <<VaultStorage>> -    <<event>> Redeem(_addr: address, _value: uint256) <<VaultStorage>> -    <<event>> CapitalPaused() <<VaultStorage>> -    <<event>> CapitalUnpaused() <<VaultStorage>> -    <<event>> RebasePaused() <<VaultStorage>> -    <<event>> RebaseUnpaused() <<VaultStorage>> -    <<event>> VaultBufferUpdated(_vaultBuffer: uint256) <<VaultStorage>> -    <<event>> OusdMetaStrategyUpdated(_ousdMetaStrategy: address) <<VaultStorage>> -    <<event>> RedeemFeeUpdated(_redeemFeeBps: uint256) <<VaultStorage>> -    <<event>> PriceProviderUpdated(_priceProvider: address) <<VaultStorage>> -    <<event>> AllocateThresholdUpdated(_threshold: uint256) <<VaultStorage>> -    <<event>> RebaseThresholdUpdated(_threshold: uint256) <<VaultStorage>> -    <<event>> StrategistUpdated(_address: address) <<VaultStorage>> -    <<event>> MaxSupplyDiffChanged(maxSupplyDiff: uint256) <<VaultStorage>> -    <<event>> YieldDistribution(_to: address, _yield: uint256, _fee: uint256) <<VaultStorage>> -    <<event>> TrusteeFeeBpsChanged(_basis: uint256) <<VaultStorage>> -    <<event>> TrusteeAddressChanged(_address: address) <<VaultStorage>> -    <<event>> NetOusdMintForStrategyThresholdChanged(_threshold: uint256) <<VaultStorage>> -    <<event>> SwapperChanged(_address: address) <<VaultStorage>> -    <<event>> SwapAllowedUndervalueChanged(_basis: uint256) <<VaultStorage>> -    <<event>> SwapSlippageChanged(_asset: address, _basis: uint256) <<VaultStorage>> -    <<event>> Swapped(_fromAsset: address, _toAsset: address, _fromAssetAmount: uint256, _toAssetAmount: uint256) <<VaultStorage>> -    <<event>> DripperChanged(_dripper: address) <<VaultStorage>> + +VaultAdmin +../contracts/vault/VaultAdmin.sol + +Private: +   initialized: bool <<Initializable>> +   initializing: bool <<Initializable>> +   ______gap: uint256[50] <<Initializable>> +   governorPosition: bytes32 <<Governable>> +   pendingGovernorPosition: bytes32 <<Governable>> +   reentryStatusPosition: bytes32 <<Governable>> +   _deprecated_rebaseHooksAddr: address <<VaultStorage>> +   _deprecated_uniswapAddr: address <<VaultStorage>> +   _deprecated_swapTokens: address[] <<VaultStorage>> +   __gap: uint256[46] <<VaultStorage>> +Internal: +   assets: mapping(address=>Asset) <<VaultStorage>> +   allAssets: address[] <<VaultStorage>> +   strategies: mapping(address=>Strategy) <<VaultStorage>> +   allStrategies: address[] <<VaultStorage>> +   oUSD: OUSD <<VaultStorage>> +   swapConfig: SwapConfig <<VaultStorage>> +Public: +   _NOT_ENTERED: uint256 <<Governable>> +   _ENTERED: uint256 <<Governable>> +   priceProvider: address <<VaultStorage>> +   rebasePaused: bool <<VaultStorage>> +   capitalPaused: bool <<VaultStorage>> +   redeemFeeBps: uint256 <<VaultStorage>> +   vaultBuffer: uint256 <<VaultStorage>> +   autoAllocateThreshold: uint256 <<VaultStorage>> +   rebaseThreshold: uint256 <<VaultStorage>> +   adminImplPosition: bytes32 <<VaultStorage>> +   strategistAddr: address <<VaultStorage>> +   assetDefaultStrategies: mapping(address=>address) <<VaultStorage>> +   maxSupplyDiff: uint256 <<VaultStorage>> +   trusteeAddress: address <<VaultStorage>> +   trusteeFeeBps: uint256 <<VaultStorage>> +   MINT_MINIMUM_UNIT_PRICE: uint256 <<VaultStorage>> +   ousdMetaStrategy: address <<VaultStorage>> +   netOusdMintedForStrategy: int256 <<VaultStorage>> +   netOusdMintForStrategyThreshold: uint256 <<VaultStorage>> +   MIN_UNIT_PRICE_DRIFT: uint256 <<VaultStorage>> +   MAX_UNIT_PRICE_DRIFT: uint256 <<VaultStorage>> +   dripper: address <<VaultStorage>> +   withdrawalQueueMetadata: WithdrawalQueueMetadata <<VaultStorage>> +   withdrawalRequests: mapping(uint256=>WithdrawalRequest) <<VaultStorage>> + +Internal: +    _governor(): (governorOut: address) <<Governable>> +    _pendingGovernor(): (pendingGovernor: address) <<Governable>> +    _setGovernor(newGovernor: address) <<Governable>> +    _setPendingGovernor(newGovernor: address) <<Governable>> +    _changeGovernor(_newGovernor: address) <<Governable>> +    _depositToStrategy(_strategyToAddress: address, _assets: address[], _amounts: uint256[]) <<VaultAdmin>> +    _withdrawFromStrategy(_recipient: address, _strategyFromAddress: address, _assets: address[], _amounts: uint256[]) <<VaultAdmin>> +    _withdrawAllFromStrategy(_strategyAddr: address) <<VaultAdmin>> +    _withdrawAllFromStrategies() <<VaultAdmin>> +    _cacheDecimals(token: address) <<VaultAdmin>> +External: +    transferGovernance(_newGovernor: address) <<onlyGovernor>> <<Governable>> +    claimGovernance() <<Governable>> +    setAdminImpl(newImpl: address) <<onlyGovernor>> <<VaultStorage>> +    setPriceProvider(_priceProvider: address) <<onlyGovernor>> <<VaultAdmin>> +    setRedeemFeeBps(_redeemFeeBps: uint256) <<onlyGovernor>> <<VaultAdmin>> +    setVaultBuffer(_vaultBuffer: uint256) <<onlyGovernorOrStrategist>> <<VaultAdmin>> +    setAutoAllocateThreshold(_threshold: uint256) <<onlyGovernor>> <<VaultAdmin>> +    setRebaseThreshold(_threshold: uint256) <<onlyGovernor>> <<VaultAdmin>> +    setStrategistAddr(_address: address) <<onlyGovernor>> <<VaultAdmin>> +    setAssetDefaultStrategy(_asset: address, _strategy: address) <<onlyGovernorOrStrategist>> <<VaultAdmin>> +    setNetOusdMintForStrategyThreshold(_threshold: uint256) <<onlyGovernor>> <<VaultAdmin>> +    setDripper(_dripper: address) <<onlyGovernor>> <<VaultAdmin>> +    swapCollateral(_fromAsset: address, _toAsset: address, _fromAssetAmount: uint256, _minToAssetAmount: uint256, _data: bytes): (toAssetAmount: uint256) <<nonReentrant, onlyGovernorOrStrategist>> <<VaultAdmin>> +    setSwapper(_swapperAddr: address) <<onlyGovernor>> <<VaultAdmin>> +    swapper(): (swapper_: address) <<VaultAdmin>> +    setSwapAllowedUndervalue(_basis: uint16) <<onlyGovernor>> <<VaultAdmin>> +    allowedSwapUndervalue(): (value: uint256) <<VaultAdmin>> +    setOracleSlippage(_asset: address, _allowedOracleSlippageBps: uint16) <<onlyGovernor>> <<VaultAdmin>> +    supportAsset(_asset: address, _unitConversion: uint8) <<onlyGovernor>> <<VaultAdmin>> +    cacheDecimals(_asset: address) <<onlyGovernor>> <<VaultAdmin>> +    approveStrategy(_addr: address) <<onlyGovernor>> <<VaultAdmin>> +    removeStrategy(_addr: address) <<onlyGovernor>> <<VaultAdmin>> +    depositToStrategy(_strategyToAddress: address, _assets: address[], _amounts: uint256[]) <<onlyGovernorOrStrategist, nonReentrant>> <<VaultAdmin>> +    withdrawFromStrategy(_strategyFromAddress: address, _assets: address[], _amounts: uint256[]) <<onlyGovernorOrStrategist, nonReentrant>> <<VaultAdmin>> +    setMaxSupplyDiff(_maxSupplyDiff: uint256) <<onlyGovernor>> <<VaultAdmin>> +    setTrusteeAddress(_address: address) <<onlyGovernor>> <<VaultAdmin>> +    setTrusteeFeeBps(_basis: uint256) <<onlyGovernor>> <<VaultAdmin>> +    setOusdMetaStrategy(_ousdMetaStrategy: address) <<onlyGovernor>> <<VaultAdmin>> +    pauseRebase() <<onlyGovernorOrStrategist>> <<VaultAdmin>> +    unpauseRebase() <<onlyGovernorOrStrategist>> <<VaultAdmin>> +    pauseCapital() <<onlyGovernorOrStrategist>> <<VaultAdmin>> +    unpauseCapital() <<onlyGovernorOrStrategist>> <<VaultAdmin>> +    transferToken(_asset: address, _amount: uint256) <<onlyGovernor>> <<VaultAdmin>> +    withdrawAllFromStrategy(_strategyAddr: address) <<onlyGovernorOrStrategist>> <<VaultAdmin>> +    withdrawAllFromStrategies() <<onlyGovernorOrStrategist>> <<VaultAdmin>> +Public: +    <<event>> PendingGovernorshipTransfer(previousGovernor: address, newGovernor: address) <<Governable>> +    <<event>> GovernorshipTransferred(previousGovernor: address, newGovernor: address) <<Governable>> +    <<event>> AssetSupported(_asset: address) <<VaultStorage>> +    <<event>> AssetDefaultStrategyUpdated(_asset: address, _strategy: address) <<VaultStorage>> +    <<event>> AssetAllocated(_asset: address, _strategy: address, _amount: uint256) <<VaultStorage>> +    <<event>> StrategyApproved(_addr: address) <<VaultStorage>> +    <<event>> StrategyRemoved(_addr: address) <<VaultStorage>> +    <<event>> Mint(_addr: address, _value: uint256) <<VaultStorage>> +    <<event>> Redeem(_addr: address, _value: uint256) <<VaultStorage>> +    <<event>> CapitalPaused() <<VaultStorage>> +    <<event>> CapitalUnpaused() <<VaultStorage>> +    <<event>> RebasePaused() <<VaultStorage>> +    <<event>> RebaseUnpaused() <<VaultStorage>> +    <<event>> VaultBufferUpdated(_vaultBuffer: uint256) <<VaultStorage>> +    <<event>> OusdMetaStrategyUpdated(_ousdMetaStrategy: address) <<VaultStorage>> +    <<event>> RedeemFeeUpdated(_redeemFeeBps: uint256) <<VaultStorage>> +    <<event>> PriceProviderUpdated(_priceProvider: address) <<VaultStorage>> +    <<event>> AllocateThresholdUpdated(_threshold: uint256) <<VaultStorage>> +    <<event>> RebaseThresholdUpdated(_threshold: uint256) <<VaultStorage>> +    <<event>> StrategistUpdated(_address: address) <<VaultStorage>> +    <<event>> MaxSupplyDiffChanged(maxSupplyDiff: uint256) <<VaultStorage>> +    <<event>> YieldDistribution(_to: address, _yield: uint256, _fee: uint256) <<VaultStorage>> +    <<event>> TrusteeFeeBpsChanged(_basis: uint256) <<VaultStorage>> +    <<event>> TrusteeAddressChanged(_address: address) <<VaultStorage>> +    <<event>> NetOusdMintForStrategyThresholdChanged(_threshold: uint256) <<VaultStorage>> +    <<event>> SwapperChanged(_address: address) <<VaultStorage>> +    <<event>> SwapAllowedUndervalueChanged(_basis: uint256) <<VaultStorage>> +    <<event>> SwapSlippageChanged(_asset: address, _basis: uint256) <<VaultStorage>> +    <<event>> Swapped(_fromAsset: address, _toAsset: address, _fromAssetAmount: uint256, _toAssetAmount: uint256) <<VaultStorage>> +    <<event>> DripperChanged(_dripper: address) <<VaultStorage>> +    <<event>> WithdrawalRequested(_withdrawer: address, _requestId: uint256, _amount: uint256, _queued: uint256) <<VaultStorage>> +    <<event>> WithdrawalClaimed(_withdrawer: address, _requestId: uint256, _amount: uint256) <<VaultStorage>> +    <<event>> WithdrawalClaimable(_claimable: uint256, _newClaimable: uint256) <<VaultStorage>>    <<modifier>> initializer() <<Initializable>>    <<modifier>> onlyGovernor() <<Governable>>    <<modifier>> nonReentrant() <<Governable>> diff --git a/contracts/docs/VaultCoreSquashed.svg b/contracts/docs/VaultCoreSquashed.svg index fc45807ee1..86049bb13a 100644 --- a/contracts/docs/VaultCoreSquashed.svg +++ b/contracts/docs/VaultCoreSquashed.svg @@ -4,137 +4,142 @@ - - + + UmlClassDiagram - + 224 - -VaultCore -../contracts/vault/VaultCore.sol - -Private: -   initialized: bool <<Initializable>> -   initializing: bool <<Initializable>> -   ______gap: uint256[50] <<Initializable>> -   governorPosition: bytes32 <<Governable>> -   pendingGovernorPosition: bytes32 <<Governable>> -   reentryStatusPosition: bytes32 <<Governable>> -   _deprecated_rebaseHooksAddr: address <<VaultStorage>> -   _deprecated_uniswapAddr: address <<VaultStorage>> -   _deprecated_swapTokens: address[] <<VaultStorage>> -   __gap: uint256[49] <<VaultStorage>> -Internal: -   assets: mapping(address=>Asset) <<VaultStorage>> -   allAssets: address[] <<VaultStorage>> -   strategies: mapping(address=>Strategy) <<VaultStorage>> -   allStrategies: address[] <<VaultStorage>> -   oUSD: OUSD <<VaultStorage>> -   swapConfig: SwapConfig <<VaultStorage>> -   MAX_INT: uint256 <<VaultCore>> -   MAX_UINT: uint256 <<VaultCore>> -Public: -   _NOT_ENTERED: uint256 <<Governable>> -   _ENTERED: uint256 <<Governable>> -   priceProvider: address <<VaultStorage>> -   rebasePaused: bool <<VaultStorage>> -   capitalPaused: bool <<VaultStorage>> -   redeemFeeBps: uint256 <<VaultStorage>> -   vaultBuffer: uint256 <<VaultStorage>> -   autoAllocateThreshold: uint256 <<VaultStorage>> -   rebaseThreshold: uint256 <<VaultStorage>> -   adminImplPosition: bytes32 <<VaultStorage>> -   strategistAddr: address <<VaultStorage>> -   assetDefaultStrategies: mapping(address=>address) <<VaultStorage>> -   maxSupplyDiff: uint256 <<VaultStorage>> -   trusteeAddress: address <<VaultStorage>> -   trusteeFeeBps: uint256 <<VaultStorage>> -   MINT_MINIMUM_UNIT_PRICE: uint256 <<VaultStorage>> -   ousdMetaStrategy: address <<VaultStorage>> -   netOusdMintedForStrategy: int256 <<VaultStorage>> -   netOusdMintForStrategyThreshold: uint256 <<VaultStorage>> -   MIN_UNIT_PRICE_DRIFT: uint256 <<VaultStorage>> -   MAX_UNIT_PRICE_DRIFT: uint256 <<VaultStorage>> -   dripper: address <<VaultStorage>> - -Private: -    abs(x: int256): uint256 <<VaultCore>> -Internal: -    _governor(): (governorOut: address) <<Governable>> -    _pendingGovernor(): (pendingGovernor: address) <<Governable>> -    _setGovernor(newGovernor: address) <<Governable>> -    _setPendingGovernor(newGovernor: address) <<Governable>> -    _changeGovernor(_newGovernor: address) <<Governable>> -    _mint(_asset: address, _amount: uint256, _minimumOusdAmount: uint256) <<VaultCore>> -    _redeem(_amount: uint256, _minimumUnitAmount: uint256) <<VaultCore>> -    _postRedeem(_amount: uint256) <<VaultCore>> -    _allocate() <<VaultCore>> -    _rebase(): uint256 <<whenNotRebasePaused>> <<VaultCore>> -    _totalValue(): (value: uint256) <<VaultCore>> -    _totalValueInVault(): (value: uint256) <<VaultCore>> -    _totalValueInStrategies(): (value: uint256) <<VaultCore>> -    _totalValueInStrategy(_strategyAddr: address): (value: uint256) <<VaultCore>> -    _checkBalance(_asset: address): (balance: uint256) <<VaultCore>> -    _calculateRedeemOutputs(_amount: uint256): (outputs: uint256[]) <<VaultCore>> -    _toUnits(_raw: uint256, _asset: address): uint256 <<VaultCore>> -    _toUnitPrice(_asset: address, isMint: bool): (price: uint256) <<VaultCore>> -    _getDecimals(_asset: address): (decimals: uint256) <<VaultCore>> -External: -    transferGovernance(_newGovernor: address) <<onlyGovernor>> <<Governable>> -    claimGovernance() <<Governable>> -    setAdminImpl(newImpl: address) <<onlyGovernor>> <<VaultStorage>> -    initialize(_priceProvider: address, _oToken: address) <<onlyGovernor, initializer>> <<VaultInitializer>> -    mint(_asset: address, _amount: uint256, _minimumOusdAmount: uint256) <<whenNotCapitalPaused, nonReentrant>> <<VaultCore>> -    mintForStrategy(_amount: uint256) <<whenNotCapitalPaused, onlyOusdMetaStrategy>> <<VaultCore>> -    redeem(_amount: uint256, _minimumUnitAmount: uint256) <<whenNotCapitalPaused, nonReentrant>> <<VaultCore>> -    burnForStrategy(_amount: uint256) <<whenNotCapitalPaused, onlyOusdMetaStrategy>> <<VaultCore>> -    redeemAll(_minimumUnitAmount: uint256) <<whenNotCapitalPaused, nonReentrant>> <<VaultCore>> -    allocate() <<whenNotCapitalPaused, nonReentrant>> <<VaultCore>> -    rebase() <<nonReentrant>> <<VaultCore>> -    totalValue(): (value: uint256) <<VaultCore>> -    checkBalance(_asset: address): uint256 <<VaultCore>> -    calculateRedeemOutputs(_amount: uint256): uint256[] <<VaultCore>> -    priceUnitMint(asset: address): (price: uint256) <<VaultCore>> -    priceUnitRedeem(asset: address): (price: uint256) <<VaultCore>> -    getAllAssets(): address[] <<VaultCore>> -    getStrategyCount(): uint256 <<VaultCore>> -    getAllStrategies(): address[] <<VaultCore>> -    isSupportedAsset(_asset: address): bool <<VaultCore>> -    null() <<VaultCore>> -Public: -    <<event>> PendingGovernorshipTransfer(previousGovernor: address, newGovernor: address) <<Governable>> -    <<event>> GovernorshipTransferred(previousGovernor: address, newGovernor: address) <<Governable>> -    <<event>> AssetSupported(_asset: address) <<VaultStorage>> -    <<event>> AssetDefaultStrategyUpdated(_asset: address, _strategy: address) <<VaultStorage>> -    <<event>> AssetAllocated(_asset: address, _strategy: address, _amount: uint256) <<VaultStorage>> -    <<event>> StrategyApproved(_addr: address) <<VaultStorage>> -    <<event>> StrategyRemoved(_addr: address) <<VaultStorage>> -    <<event>> Mint(_addr: address, _value: uint256) <<VaultStorage>> -    <<event>> Redeem(_addr: address, _value: uint256) <<VaultStorage>> -    <<event>> CapitalPaused() <<VaultStorage>> -    <<event>> CapitalUnpaused() <<VaultStorage>> -    <<event>> RebasePaused() <<VaultStorage>> -    <<event>> RebaseUnpaused() <<VaultStorage>> -    <<event>> VaultBufferUpdated(_vaultBuffer: uint256) <<VaultStorage>> -    <<event>> OusdMetaStrategyUpdated(_ousdMetaStrategy: address) <<VaultStorage>> -    <<event>> RedeemFeeUpdated(_redeemFeeBps: uint256) <<VaultStorage>> -    <<event>> PriceProviderUpdated(_priceProvider: address) <<VaultStorage>> -    <<event>> AllocateThresholdUpdated(_threshold: uint256) <<VaultStorage>> -    <<event>> RebaseThresholdUpdated(_threshold: uint256) <<VaultStorage>> -    <<event>> StrategistUpdated(_address: address) <<VaultStorage>> -    <<event>> MaxSupplyDiffChanged(maxSupplyDiff: uint256) <<VaultStorage>> -    <<event>> YieldDistribution(_to: address, _yield: uint256, _fee: uint256) <<VaultStorage>> -    <<event>> TrusteeFeeBpsChanged(_basis: uint256) <<VaultStorage>> -    <<event>> TrusteeAddressChanged(_address: address) <<VaultStorage>> -    <<event>> NetOusdMintForStrategyThresholdChanged(_threshold: uint256) <<VaultStorage>> -    <<event>> SwapperChanged(_address: address) <<VaultStorage>> -    <<event>> SwapAllowedUndervalueChanged(_basis: uint256) <<VaultStorage>> -    <<event>> SwapSlippageChanged(_asset: address, _basis: uint256) <<VaultStorage>> -    <<event>> Swapped(_fromAsset: address, _toAsset: address, _fromAssetAmount: uint256, _toAssetAmount: uint256) <<VaultStorage>> -    <<event>> DripperChanged(_dripper: address) <<VaultStorage>> + +VaultCore +../contracts/vault/VaultCore.sol + +Private: +   initialized: bool <<Initializable>> +   initializing: bool <<Initializable>> +   ______gap: uint256[50] <<Initializable>> +   governorPosition: bytes32 <<Governable>> +   pendingGovernorPosition: bytes32 <<Governable>> +   reentryStatusPosition: bytes32 <<Governable>> +   _deprecated_rebaseHooksAddr: address <<VaultStorage>> +   _deprecated_uniswapAddr: address <<VaultStorage>> +   _deprecated_swapTokens: address[] <<VaultStorage>> +   __gap: uint256[46] <<VaultStorage>> +Internal: +   assets: mapping(address=>Asset) <<VaultStorage>> +   allAssets: address[] <<VaultStorage>> +   strategies: mapping(address=>Strategy) <<VaultStorage>> +   allStrategies: address[] <<VaultStorage>> +   oUSD: OUSD <<VaultStorage>> +   swapConfig: SwapConfig <<VaultStorage>> +   MAX_INT: uint256 <<VaultCore>> +   MAX_UINT: uint256 <<VaultCore>> +Public: +   _NOT_ENTERED: uint256 <<Governable>> +   _ENTERED: uint256 <<Governable>> +   priceProvider: address <<VaultStorage>> +   rebasePaused: bool <<VaultStorage>> +   capitalPaused: bool <<VaultStorage>> +   redeemFeeBps: uint256 <<VaultStorage>> +   vaultBuffer: uint256 <<VaultStorage>> +   autoAllocateThreshold: uint256 <<VaultStorage>> +   rebaseThreshold: uint256 <<VaultStorage>> +   adminImplPosition: bytes32 <<VaultStorage>> +   strategistAddr: address <<VaultStorage>> +   assetDefaultStrategies: mapping(address=>address) <<VaultStorage>> +   maxSupplyDiff: uint256 <<VaultStorage>> +   trusteeAddress: address <<VaultStorage>> +   trusteeFeeBps: uint256 <<VaultStorage>> +   MINT_MINIMUM_UNIT_PRICE: uint256 <<VaultStorage>> +   ousdMetaStrategy: address <<VaultStorage>> +   netOusdMintedForStrategy: int256 <<VaultStorage>> +   netOusdMintForStrategyThreshold: uint256 <<VaultStorage>> +   MIN_UNIT_PRICE_DRIFT: uint256 <<VaultStorage>> +   MAX_UNIT_PRICE_DRIFT: uint256 <<VaultStorage>> +   dripper: address <<VaultStorage>> +   withdrawalQueueMetadata: WithdrawalQueueMetadata <<VaultStorage>> +   withdrawalRequests: mapping(uint256=>WithdrawalRequest) <<VaultStorage>> + +Private: +    abs(x: int256): uint256 <<VaultCore>> +Internal: +    _governor(): (governorOut: address) <<Governable>> +    _pendingGovernor(): (pendingGovernor: address) <<Governable>> +    _setGovernor(newGovernor: address) <<Governable>> +    _setPendingGovernor(newGovernor: address) <<Governable>> +    _changeGovernor(_newGovernor: address) <<Governable>> +    _mint(_asset: address, _amount: uint256, _minimumOusdAmount: uint256) <<VaultCore>> +    _redeem(_amount: uint256, _minimumUnitAmount: uint256) <<VaultCore>> +    _postRedeem(_amount: uint256) <<VaultCore>> +    _allocate() <<VaultCore>> +    _rebase(): uint256 <<whenNotRebasePaused>> <<VaultCore>> +    _totalValue(): (value: uint256) <<VaultCore>> +    _totalValueInVault(): (value: uint256) <<VaultCore>> +    _totalValueInStrategies(): (value: uint256) <<VaultCore>> +    _totalValueInStrategy(_strategyAddr: address): (value: uint256) <<VaultCore>> +    _checkBalance(_asset: address): (balance: uint256) <<VaultCore>> +    _calculateRedeemOutputs(_amount: uint256): (outputs: uint256[]) <<VaultCore>> +    _toUnits(_raw: uint256, _asset: address): uint256 <<VaultCore>> +    _toUnitPrice(_asset: address, isMint: bool): (price: uint256) <<VaultCore>> +    _getDecimals(_asset: address): (decimals: uint256) <<VaultCore>> +External: +    transferGovernance(_newGovernor: address) <<onlyGovernor>> <<Governable>> +    claimGovernance() <<Governable>> +    setAdminImpl(newImpl: address) <<onlyGovernor>> <<VaultStorage>> +    initialize(_priceProvider: address, _oToken: address) <<onlyGovernor, initializer>> <<VaultInitializer>> +    mint(_asset: address, _amount: uint256, _minimumOusdAmount: uint256) <<whenNotCapitalPaused, nonReentrant>> <<VaultCore>> +    mintForStrategy(_amount: uint256) <<whenNotCapitalPaused, onlyOusdMetaStrategy>> <<VaultCore>> +    redeem(_amount: uint256, _minimumUnitAmount: uint256) <<whenNotCapitalPaused, nonReentrant>> <<VaultCore>> +    burnForStrategy(_amount: uint256) <<whenNotCapitalPaused, onlyOusdMetaStrategy>> <<VaultCore>> +    redeemAll(_minimumUnitAmount: uint256) <<whenNotCapitalPaused, nonReentrant>> <<VaultCore>> +    allocate() <<whenNotCapitalPaused, nonReentrant>> <<VaultCore>> +    rebase() <<nonReentrant>> <<VaultCore>> +    totalValue(): (value: uint256) <<VaultCore>> +    checkBalance(_asset: address): uint256 <<VaultCore>> +    calculateRedeemOutputs(_amount: uint256): uint256[] <<VaultCore>> +    priceUnitMint(asset: address): (price: uint256) <<VaultCore>> +    priceUnitRedeem(asset: address): (price: uint256) <<VaultCore>> +    getAllAssets(): address[] <<VaultCore>> +    getStrategyCount(): uint256 <<VaultCore>> +    getAllStrategies(): address[] <<VaultCore>> +    isSupportedAsset(_asset: address): bool <<VaultCore>> +    null() <<VaultCore>> +Public: +    <<event>> PendingGovernorshipTransfer(previousGovernor: address, newGovernor: address) <<Governable>> +    <<event>> GovernorshipTransferred(previousGovernor: address, newGovernor: address) <<Governable>> +    <<event>> AssetSupported(_asset: address) <<VaultStorage>> +    <<event>> AssetDefaultStrategyUpdated(_asset: address, _strategy: address) <<VaultStorage>> +    <<event>> AssetAllocated(_asset: address, _strategy: address, _amount: uint256) <<VaultStorage>> +    <<event>> StrategyApproved(_addr: address) <<VaultStorage>> +    <<event>> StrategyRemoved(_addr: address) <<VaultStorage>> +    <<event>> Mint(_addr: address, _value: uint256) <<VaultStorage>> +    <<event>> Redeem(_addr: address, _value: uint256) <<VaultStorage>> +    <<event>> CapitalPaused() <<VaultStorage>> +    <<event>> CapitalUnpaused() <<VaultStorage>> +    <<event>> RebasePaused() <<VaultStorage>> +    <<event>> RebaseUnpaused() <<VaultStorage>> +    <<event>> VaultBufferUpdated(_vaultBuffer: uint256) <<VaultStorage>> +    <<event>> OusdMetaStrategyUpdated(_ousdMetaStrategy: address) <<VaultStorage>> +    <<event>> RedeemFeeUpdated(_redeemFeeBps: uint256) <<VaultStorage>> +    <<event>> PriceProviderUpdated(_priceProvider: address) <<VaultStorage>> +    <<event>> AllocateThresholdUpdated(_threshold: uint256) <<VaultStorage>> +    <<event>> RebaseThresholdUpdated(_threshold: uint256) <<VaultStorage>> +    <<event>> StrategistUpdated(_address: address) <<VaultStorage>> +    <<event>> MaxSupplyDiffChanged(maxSupplyDiff: uint256) <<VaultStorage>> +    <<event>> YieldDistribution(_to: address, _yield: uint256, _fee: uint256) <<VaultStorage>> +    <<event>> TrusteeFeeBpsChanged(_basis: uint256) <<VaultStorage>> +    <<event>> TrusteeAddressChanged(_address: address) <<VaultStorage>> +    <<event>> NetOusdMintForStrategyThresholdChanged(_threshold: uint256) <<VaultStorage>> +    <<event>> SwapperChanged(_address: address) <<VaultStorage>> +    <<event>> SwapAllowedUndervalueChanged(_basis: uint256) <<VaultStorage>> +    <<event>> SwapSlippageChanged(_asset: address, _basis: uint256) <<VaultStorage>> +    <<event>> Swapped(_fromAsset: address, _toAsset: address, _fromAssetAmount: uint256, _toAssetAmount: uint256) <<VaultStorage>> +    <<event>> DripperChanged(_dripper: address) <<VaultStorage>> +    <<event>> WithdrawalRequested(_withdrawer: address, _requestId: uint256, _amount: uint256, _queued: uint256) <<VaultStorage>> +    <<event>> WithdrawalClaimed(_withdrawer: address, _requestId: uint256, _amount: uint256) <<VaultStorage>> +    <<event>> WithdrawalClaimable(_claimable: uint256, _newClaimable: uint256) <<VaultStorage>>    <<modifier>> initializer() <<Initializable>>    <<modifier>> onlyGovernor() <<Governable>>    <<modifier>> nonReentrant() <<Governable>> diff --git a/contracts/docs/VaultHierarchy.svg b/contracts/docs/VaultHierarchy.svg index 207092a151..9b58831412 100644 --- a/contracts/docs/VaultHierarchy.svg +++ b/contracts/docs/VaultHierarchy.svg @@ -4,256 +4,128 @@ - - + + UmlClassDiagram - + 20 - -Governable -../contracts/governance/Governable.sol - - - -40 - -<<Interface>> -IDripper -../contracts/interfaces/IDripper.sol - - - -44 - -<<Interface>> -IGetExchangeRateToken -../contracts/interfaces/IGetExchangeRateToken.sol - - - -51 - -<<Interface>> -IOracle -../contracts/interfaces/IOracle.sol - - - -57 - -<<Interface>> -IStrategy -../contracts/interfaces/IStrategy.sol - - - -58 - -<<Interface>> -ISwapper -../contracts/interfaces/ISwapper.sol - - - -61 - -<<Interface>> -IVault -../contracts/interfaces/IVault.sol - - - -226 - -VaultStorage -../contracts/vault/VaultStorage.sol - - - -61->226 - - + +Governable +../contracts/governance/Governable.sol - + 205 - -OUSD -../contracts/token/OUSD.sol + +OUSD +../contracts/token/OUSD.sol - + 205->20 - - + + - + 213 - -<<Abstract>> -Initializable -../contracts/utils/Initializable.sol + +<<Abstract>> +Initializable +../contracts/utils/Initializable.sol - + 205->213 - - + + - + 216 - -<<Abstract>> -InitializableERC20Detailed -../contracts/utils/InitializableERC20Detailed.sol + +<<Abstract>> +InitializableERC20Detailed +../contracts/utils/InitializableERC20Detailed.sol - + 205->216 - - - - - -695 - -<<Interface>> -IERC20 -../node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol - - - -216->695 - - + + - + 223 - -VaultAdmin -../contracts/vault/VaultAdmin.sol - - - -223->51 - - - - - -223->57 - - - - - -223->58 - - + +VaultAdmin +../contracts/vault/VaultAdmin.sol - - -223->61 - - + + +226 + +VaultStorage +../contracts/vault/VaultStorage.sol - + 223->226 - - - - - -223->695 - - + + - + 224 - -VaultCore -../contracts/vault/VaultCore.sol - - - -224->40 - - - - - -224->44 - - - - - -224->51 - - - - - -224->57 - - + +VaultCore +../contracts/vault/VaultCore.sol - + 225 - -VaultInitializer -../contracts/vault/VaultInitializer.sol + +VaultInitializer +../contracts/vault/VaultInitializer.sol - + 224->225 - - - - - -224->695 - - + + - + 225->205 - - + + - + 225->226 - - + + - + 226->20 - - + + - + 226->205 - - + + - + 226->213 - - + + diff --git a/contracts/docs/VaultStorage.svg b/contracts/docs/VaultStorage.svg index 8ae11c03cc..b30a623ee0 100644 --- a/contracts/docs/VaultStorage.svg +++ b/contracts/docs/VaultStorage.svg @@ -4,286 +4,352 @@ - - + + StorageDiagram - - + + -7 - -VaultCore <<Contract>> - -slot - -0 - -1-50 - -51 - -52 - -53 - -54 - -55 - -56 - -57 - -58 - -59 - -60 - -61 - -62 - -63 - -64 - -65 - -66 - -67 - -68 - -69 - -70 - -71 - -72 - -73 - -74-122 - -type: <inherited contract>.variable (bytes) - -unallocated (30) - -bool: Initializable.initializing (1) - -bool: Initializable.initialized (1) - -uint256[50]: Initializable.______gap (1600) - -mapping(address=>Asset): VaultStorage.assets (32) - -address[]: VaultStorage.allAssets (32) - -mapping(address=>Strategy): VaultStorage.strategies (32) - -address[]: VaultStorage.allStrategies (32) - -unallocated (10) - -bool: VaultStorage.capitalPaused (1) - -bool: VaultStorage.rebasePaused (1) - -address: VaultStorage.priceProvider (20) - -uint256: VaultStorage.redeemFeeBps (32) - -uint256: VaultStorage.vaultBuffer (32) - -uint256: VaultStorage.autoAllocateThreshold (32) - -uint256: VaultStorage.rebaseThreshold (32) - -unallocated (12) - -OUSD: VaultStorage.oUSD (20) - -unallocated (12) - -address: VaultStorage._deprecated_rebaseHooksAddr (20) - -unallocated (12) - -address: VaultStorage._deprecated_uniswapAddr (20) - -unallocated (12) - -address: VaultStorage.strategistAddr (20) - -mapping(address=>address): VaultStorage.assetDefaultStrategies (32) - -uint256: VaultStorage.maxSupplyDiff (32) - -unallocated (12) - -address: VaultStorage.trusteeAddress (20) - -uint256: VaultStorage.trusteeFeeBps (32) - -address[]: VaultStorage._deprecated_swapTokens (32) - -unallocated (12) - -address: VaultStorage.ousdMetaStrategy (20) - -int256: VaultStorage.netOusdMintedForStrategy (32) - -uint256: VaultStorage.netOusdMintForStrategyThreshold (32) - -SwapConfig: VaultStorage.swapConfig (32) - -unallocated (12) - -address: VaultStorage.dripper (20) - -uint256[49]: VaultStorage.__gap (1568) +9 + +VaultCore <<Contract>> + +slot + +0 + +1-50 + +51 + +52 + +53 + +54 + +55 + +56 + +57 + +58 + +59 + +60 + +61 + +62 + +63 + +64 + +65 + +66 + +67 + +68 + +69 + +70 + +71 + +72 + +73 + +74-75 + +76 + +77-122 + +type: <inherited contract>.variable (bytes) + +unallocated (30) + +bool: Initializable.initializing (1) + +bool: Initializable.initialized (1) + +uint256[50]: Initializable.______gap (1600) + +mapping(address=>Asset): VaultStorage.assets (32) + +address[]: VaultStorage.allAssets (32) + +mapping(address=>Strategy): VaultStorage.strategies (32) + +address[]: VaultStorage.allStrategies (32) + +unallocated (10) + +bool: VaultStorage.capitalPaused (1) + +bool: VaultStorage.rebasePaused (1) + +address: VaultStorage.priceProvider (20) + +uint256: VaultStorage.redeemFeeBps (32) + +uint256: VaultStorage.vaultBuffer (32) + +uint256: VaultStorage.autoAllocateThreshold (32) + +uint256: VaultStorage.rebaseThreshold (32) + +unallocated (12) + +OUSD: VaultStorage.oUSD (20) + +unallocated (12) + +address: VaultStorage._deprecated_rebaseHooksAddr (20) + +unallocated (12) + +address: VaultStorage._deprecated_uniswapAddr (20) + +unallocated (12) + +address: VaultStorage.strategistAddr (20) + +mapping(address=>address): VaultStorage.assetDefaultStrategies (32) + +uint256: VaultStorage.maxSupplyDiff (32) + +unallocated (12) + +address: VaultStorage.trusteeAddress (20) + +uint256: VaultStorage.trusteeFeeBps (32) + +address[]: VaultStorage._deprecated_swapTokens (32) + +unallocated (12) + +address: VaultStorage.ousdMetaStrategy (20) + +int256: VaultStorage.netOusdMintedForStrategy (32) + +uint256: VaultStorage.netOusdMintForStrategyThreshold (32) + +SwapConfig: VaultStorage.swapConfig (32) + +unallocated (12) + +address: VaultStorage.dripper (20) + +WithdrawalQueueMetadata: VaultStorage.withdrawalQueueMetadata (64) + +mapping(uint256=>WithdrawalRequest): VaultStorage.withdrawalRequests (32) + +uint256[46]: VaultStorage.__gap (1472) 1 - -Asset <<Struct>> - -offset - -0 - -type: variable (bytes) - -unallocated (27) - -uint16: allowedOracleSlippageBps (2) - -uint8: decimals (1) - -UnitConversion: unitConversion (1) - -bool: isSupported (1) + +Asset <<Struct>> + +offset + +0 + +type: variable (bytes) + +unallocated (27) + +uint16: allowedOracleSlippageBps (2) + +uint8: decimals (1) + +UnitConversion: unitConversion (1) + +bool: isSupported (1) - + -7:8->1 - - +9:8->1 + + 2 - -address[]: allAssets <<Array>> -0x46bddb1178e94d7f2892ff5f366840eb658911794f2c3a44c450aa2c505186c1 - -offset - -0 - -type: variable (bytes) - -unallocated (12) - -address (20) + +address[]: allAssets <<Array>> +0x46bddb1178e94d7f2892ff5f366840eb658911794f2c3a44c450aa2c505186c1 + +offset + +0 + +type: variable (bytes) + +unallocated (12) + +address (20) - + -7:10->2 - - +9:10->2 + + 3 - -Strategy <<Struct>> - -offset - -0 - -1 - -type: variable (bytes) - -unallocated (31) - -bool: isSupported (1) - -uint256: _deprecated (32) + +Strategy <<Struct>> + +offset + +0 + +1 + +type: variable (bytes) + +unallocated (31) + +bool: isSupported (1) + +uint256: _deprecated (32) - + -7:13->3 - - +9:13->3 + + 4 - -address[]: allStrategies <<Array>> -0x4a11f94e20a93c79f6ec743a1954ec4fc2c08429ae2122118bf234b2185c81b8 - -offset - -0 - -type: variable (bytes) - -unallocated (12) - -address (20) + +address[]: allStrategies <<Array>> +0x4a11f94e20a93c79f6ec743a1954ec4fc2c08429ae2122118bf234b2185c81b8 + +offset + +0 + +type: variable (bytes) + +unallocated (12) + +address (20) - + -7:15->4 - - +9:15->4 + + 5 - -SwapConfig <<Struct>> - -slot - -72 - -type: variable (bytes) - -unallocated (10) - -uint16: allowedUndervalueBps (2) - -address: swapper (20) + +SwapConfig <<Struct>> + +slot + +72 + +type: variable (bytes) + +unallocated (10) + +uint16: allowedUndervalueBps (2) + +address: swapper (20) - + -7:37->5 - - +9:37->5 + + 6 + +WithdrawalQueueMetadata <<Struct>> + +slot + +74 + +75 + +type: variable (bytes) + +uint128: claimable (16) + +uint128: queued (16) + +uint128: nextWithdrawalIndex (16) + +uint128: claimed (16) + + + +9:43->6 + + + + + +7 + +WithdrawalRequest <<Struct>> + +offset + +0 + +1 + +type: variable (bytes) + +unallocated (11) + +bool: claimed (1) + +address: withdrawer (20) + +uint128: queued (16) + +uint128: amount (16) + + + +9:48->7 + + + + + +8 -uint256[49]: __gap <<Array>> +uint256[46]: __gap <<Array>> slot -74 +77 -75 +78 -76-120 +79-120 121 @@ -295,17 +361,17 @@ uint256 (32) ----- (1440) +---- (1344) uint256 (32) uint256 (32) - - -7:44->6 - - + + +9:54->8 + + diff --git a/contracts/docs/generate.sh b/contracts/docs/generate.sh index ed02d52347..ecd15f8c69 100644 --- a/contracts/docs/generate.sh +++ b/contracts/docs/generate.sh @@ -129,12 +129,12 @@ sol2uml .. -s -d 0 -b WOETH -o WOETHSquashed.svg sol2uml storage .. -c WOETH -o WOETHStorage.svg # contracts/vault -sol2uml .. -v -hv -hf -he -hs -hl -b VaultCore,VaultAdmin -o VaultHierarchy.svg +sol2uml .. -v -hv -hf -he -hs -hl -hi -b VaultCore,VaultAdmin -o VaultHierarchy.svg sol2uml .. -s -d 0 -b VaultCore -o VaultCoreSquashed.svg sol2uml .. -s -d 0 -b VaultAdmin -o VaultAdminSquashed.svg sol2uml storage .. -c VaultCore -o VaultStorage.svg --hideExpand ______gap,_deprecated_swapTokens -sol2uml .. -v -hv -hf -he -hs -hl -b OETHVaultCore,OETHVaultAdmin -o OETHVaultHierarchy.svg +sol2uml .. -v -hv -hf -he -hs -hl -hi -b OETHVaultCore,OETHVaultAdmin -o OETHVaultHierarchy.svg sol2uml .. -s -d 0 -b OETHVaultCore -o OETHVaultCoreSquashed.svg sol2uml .. -s -d 0 -b OETHVaultAdmin -o OETHVaultAdminSquashed.svg sol2uml storage .. -c OETHVaultCore -o OETHVaultStorage.svg --hideExpand ______gap,_deprecated_swapTokens From abe0e9c885fc885e60f7fdeb9c3c05f3645a98e5 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Thu, 16 May 2024 22:25:40 +1000 Subject: [PATCH 075/273] Fix Slither --- contracts/contracts/vault/VaultCore.sol | 6 ++++-- contracts/contracts/vault/VaultStorage.sol | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/contracts/contracts/vault/VaultCore.sol b/contracts/contracts/vault/VaultCore.sol index 446907e73f..b126d0917f 100644 --- a/contracts/contracts/vault/VaultCore.sol +++ b/contracts/contracts/vault/VaultCore.sol @@ -90,8 +90,10 @@ contract VaultCore is VaultInitializer { // Rebase must happen before any transfers occur. if (priceAdjustedDeposit >= rebaseThreshold && !rebasePaused) { - // Stream any harvested rewards that are available - IDripper(dripper).collect(); + if (dripper != address(0)) { + // Stream any harvested rewards that are available + IDripper(dripper).collect(); + } _rebase(); } diff --git a/contracts/contracts/vault/VaultStorage.sol b/contracts/contracts/vault/VaultStorage.sol index dc09905d8f..f325dc7695 100644 --- a/contracts/contracts/vault/VaultStorage.sol +++ b/contracts/contracts/vault/VaultStorage.sol @@ -179,7 +179,8 @@ contract VaultStorage is Initializable, Governable { SwapConfig internal swapConfig = SwapConfig(address(0), 0); /// @notice Address of the Dripper contract that streams harvested rewards to the Vault - address public dripper; + // the initialization is just for Slither. The vault is proxied so needs to be initialized and not set in the implementation + address public dripper = address(0); /// Withdrawal Queue Storage ///// From cfe6a8148dbbc6c3ef385f32a50b48f7dba64b5e Mon Sep 17 00:00:00 2001 From: Domen Grabec Date: Thu, 16 May 2024 17:31:17 +0200 Subject: [PATCH 076/273] add a util contract that is able to recalculate a valid deposit data root with an invalid signature --- .../contracts/utils/DepositContractUtils.sol | 40 +++++++++++++++++++ contracts/deploy/mainnet/000_mock.js | 6 +++ contracts/test/_fixture.js | 3 ++ contracts/test/strategies/nativeSSVStaking.js | 11 +++++ 4 files changed, 60 insertions(+) create mode 100644 contracts/contracts/utils/DepositContractUtils.sol diff --git a/contracts/contracts/utils/DepositContractUtils.sol b/contracts/contracts/utils/DepositContractUtils.sol new file mode 100644 index 0000000000..05154132e0 --- /dev/null +++ b/contracts/contracts/utils/DepositContractUtils.sol @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +contract DepositContractUtils { + + function calculateDepositDataRoot( + bytes calldata pubkey, + bytes calldata withdrawal_credentials, + bytes calldata signature + ) public pure returns(bytes32 node){ + uint deposit_amount = 32 ether / 1 gwei; + bytes memory amount = to_little_endian_64(uint64(deposit_amount)); + + // Compute deposit data root (`DepositData` hash tree root) + bytes32 pubkey_root = sha256(abi.encodePacked(pubkey, bytes16(0))); + bytes32 signature_root = sha256(abi.encodePacked( + sha256(abi.encodePacked(signature[:64])), + sha256(abi.encodePacked(signature[64:], bytes32(0))) + )); + node = sha256(abi.encodePacked( + sha256(abi.encodePacked(pubkey_root, withdrawal_credentials)), + sha256(abi.encodePacked(amount, bytes24(0), signature_root)) + )); + } + + function to_little_endian_64(uint64 value) internal pure returns (bytes memory ret) { + ret = new bytes(8); + bytes8 bytesValue = bytes8(value); + // Byteswapping during copying to bytes. + ret[0] = bytesValue[7]; + ret[1] = bytesValue[6]; + ret[2] = bytesValue[5]; + ret[3] = bytesValue[4]; + ret[4] = bytesValue[3]; + ret[5] = bytesValue[2]; + ret[6] = bytesValue[1]; + ret[7] = bytesValue[0]; + } + +} diff --git a/contracts/deploy/mainnet/000_mock.js b/contracts/deploy/mainnet/000_mock.js index bc77bd2839..1de8037eb4 100644 --- a/contracts/deploy/mainnet/000_mock.js +++ b/contracts/deploy/mainnet/000_mock.js @@ -82,6 +82,12 @@ const deployMocks = async ({ getNamedAccounts, deployments }) => { from: deployerAddr, }); + await deploy("DepositContractUtils", { + args: [], + contract: "DepositContractUtils", + from: deployerAddr, + }); + await deploy("MockCUSDC", { args: [ (await ethers.getContract("MockUSDC")).address, diff --git a/contracts/test/_fixture.js b/contracts/test/_fixture.js index 0583a6e100..9c87c52f43 100644 --- a/contracts/test/_fixture.js +++ b/contracts/test/_fixture.js @@ -351,6 +351,7 @@ const defaultFixture = deployments.createFixture(async () => { cvx, cvxBooster, cvxRewardPool, + depositContractUtils, LUSDMetaStrategy, oethDripper, oethZapper, @@ -550,6 +551,7 @@ const defaultFixture = deployments.createFixture(async () => { threePoolGauge = await ethers.getContract("MockCurveGauge"); cvxBooster = await ethers.getContract("MockBooster"); cvxRewardPool = await ethers.getContract("MockRewardPool"); + depositContractUtils = await ethers.getContract("DepositContractUtils"); adai = await ethers.getContract("MockADAI"); aaveToken = await ethers.getContract("MockAAVEToken"); @@ -741,6 +743,7 @@ const defaultFixture = deployments.createFixture(async () => { cvx, cvxBooster, cvxRewardPool, + depositContractUtils, aaveStrategy, aaveToken, diff --git a/contracts/test/strategies/nativeSSVStaking.js b/contracts/test/strategies/nativeSSVStaking.js index 691ff946d2..01634d2f09 100644 --- a/contracts/test/strategies/nativeSSVStaking.js +++ b/contracts/test/strategies/nativeSSVStaking.js @@ -873,6 +873,17 @@ describe("Unit test: Native SSV Staking Strategy", function () { }); } }); + + it.skip("Deposit alternate deposit_data_root ", async () => { + const { depositContractUtils } = fixture; + + const newDepositDataRoot = await depositContractUtils.calculateDepositDataRoot( + "0x9254b0fba5173550bcf0950031533e816150167577c15636922406977bafa09ed1a1cc72a148030db977d7091d31c1fa", + "0x010000000000000000000000cf4a9e80ddb173cc17128a361b98b9a140e3932e", + "0x9144bddd6d969571dd058d9656c9da32cf4b8556e18a16362383d02a93bd0901f100874f7f795165a2162badceb5466811f5cfbce8be21d02a87af1898cbe53f5d160d46cbc0863d8e6e28d5f0becf4804cf728b39d0bae69540df896ce97b8b", + ); + console.log(`the new newDepositDataRoot is: ${newDepositDataRoot}`) + }); }); const setActiveDepositedValidators = async ( From 3a35b5505b08fb144adf817a6610796f8a83e518 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Fri, 17 May 2024 11:23:33 +1000 Subject: [PATCH 077/273] Slither fixes Added Natspec --- contracts/contracts/vault/OETHVaultCore.sol | 14 ++++++++++++++ contracts/contracts/vault/VaultStorage.sol | 5 +++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/contracts/contracts/vault/OETHVaultCore.sol b/contracts/contracts/vault/OETHVaultCore.sol index 3fd9dfa9f8..baa8344d69 100644 --- a/contracts/contracts/vault/OETHVaultCore.sol +++ b/contracts/contracts/vault/OETHVaultCore.sol @@ -40,6 +40,7 @@ contract OETHVaultCore is VaultCore { } // @inheritdoc VaultCore + // slither-disable-start reentrancy-no-eth function _mint( address _asset, uint256 _amount, @@ -74,6 +75,8 @@ contract OETHVaultCore is VaultCore { } } + // slither-disable-end reentrancy-no-eth + // @inheritdoc VaultCore function _calculateRedeemOutputs(uint256 _amount) internal @@ -153,6 +156,9 @@ contract OETHVaultCore is VaultCore { /** * @notice Request an asynchronous withdrawal of the underlying asset. eg WETH * @param _amount Amount of oTokens to burn. eg OETH + * @param requestId Unique ID for the withdrawal request + * @param queued Cumulative total of all WETH queued including already claimed requests. + * This request can be claimed once the withdrawal queue's claimable amount is greater than or equal this request's queued amount. */ function requestWithdrawal(uint256 _amount) external @@ -183,10 +189,16 @@ contract OETHVaultCore is VaultCore { }); } + /** + * @notice Claim a previously requested withdrawal once it is claimable. + * @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) { // Check if there's enough liquidity to cover the withdrawal request WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata; @@ -205,6 +217,8 @@ contract OETHVaultCore is VaultCore { // transfer WETH from the vault to the withdrawer IERC20(weth).safeTransfer(msg.sender, request.amount); + + return request.amount; } /// @notice Adds any unallocated WETH to the withdrawal queue if there is a funding shortfall. diff --git a/contracts/contracts/vault/VaultStorage.sol b/contracts/contracts/vault/VaultStorage.sol index f325dc7695..941803f511 100644 --- a/contracts/contracts/vault/VaultStorage.sol +++ b/contracts/contracts/vault/VaultStorage.sol @@ -179,8 +179,9 @@ contract VaultStorage is Initializable, Governable { SwapConfig internal swapConfig = SwapConfig(address(0), 0); /// @notice Address of the Dripper contract that streams harvested rewards to the Vault - // the initialization is just for Slither. The vault is proxied so needs to be initialized and not set in the implementation - address public dripper = address(0); + /// @dev The vault is proxied so needs to be set with setDripper against the proxy contract. + // slither-disable-next-line uninitialized-state constable-states + address public dripper; /// Withdrawal Queue Storage ///// From 28ae4539f24774fbf3a49d5f382a99abb7809caf Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Fri, 17 May 2024 11:38:34 +1000 Subject: [PATCH 078/273] Fix linter --- contracts/contracts/vault/OETHVaultCore.sol | 3 ++- contracts/contracts/vault/VaultStorage.sol | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/contracts/contracts/vault/OETHVaultCore.sol b/contracts/contracts/vault/OETHVaultCore.sol index baa8344d69..54f74d1367 100644 --- a/contracts/contracts/vault/OETHVaultCore.sol +++ b/contracts/contracts/vault/OETHVaultCore.sol @@ -158,7 +158,8 @@ contract OETHVaultCore is VaultCore { * @param _amount Amount of oTokens to burn. eg OETH * @param requestId Unique ID for the withdrawal request * @param queued Cumulative total of all WETH queued including already claimed requests. - * This request can be claimed once the withdrawal queue's claimable amount is greater than or equal this request's queued amount. + * This request can be claimed once the withdrawal queue's claimable amount + * is greater than or equal this request's queued amount. */ function requestWithdrawal(uint256 _amount) external diff --git a/contracts/contracts/vault/VaultStorage.sol b/contracts/contracts/vault/VaultStorage.sol index 941803f511..bf5924439b 100644 --- a/contracts/contracts/vault/VaultStorage.sol +++ b/contracts/contracts/vault/VaultStorage.sol @@ -180,7 +180,7 @@ contract VaultStorage is Initializable, Governable { /// @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-next-line uninitialized-state constable-states + // slither-disable-next-line uninitialized-state address public dripper; /// Withdrawal Queue Storage ///// From ad492ccff0bec117778bfec41a2774245bbac812 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Fri, 17 May 2024 11:39:13 +1000 Subject: [PATCH 079/273] Updated contract diagram --- contracts/docs/plantuml/oethContracts.png | Bin 79801 -> 57944 bytes contracts/docs/plantuml/oethContracts.puml | 109 ++++++++++++--------- 2 files changed, 61 insertions(+), 48 deletions(-) diff --git a/contracts/docs/plantuml/oethContracts.png b/contracts/docs/plantuml/oethContracts.png index e7df706f4537dd9d58c1e15ca283a72d1ebd4f75..3b4126372722ac2e041ecbcbe30c33c73da82185 100644 GIT binary patch literal 57944 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

SzGL}J8ta$IZl8wuLq}j?+XUxYMPqB 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 diff --git a/contracts/docs/plantuml/oethContracts.puml b/contracts/docs/plantuml/oethContracts.puml index e71ad1a73b..ebb9ae5c8a 100644 --- a/contracts/docs/plantuml/oethContracts.puml +++ b/contracts/docs/plantuml/oethContracts.puml @@ -8,9 +8,9 @@ legend blue - Origin -' green - new -' orange - changed -white - 3rd Party +green - new +orange - changed +' white - 3rd Party end legend title "Origin Ether Contract Dependencies" @@ -19,6 +19,16 @@ object "OETHZapper" as zap <> #$originColor { assets: ETH } + + +' object "ARM Router" as router <><> #$newColor { +' } + +object "OETH ARM" as arm <><> #$newColor { + assets: WETH, OETH +} + + object "OETHDripper" as drip <><> #$originColor { asset: WETH } @@ -37,7 +47,7 @@ object "OETH" as oeth <><> #$originColor { name: Origin Ether } -object "OETH Vault" as oethv <><> #$originColor { +object "OETH Vault" as oethv <><> #$changedColor { asset: WETH } @@ -53,7 +63,7 @@ object "ConvexEthMetaStrategy" as cvxStrat <><> #$originColor { Rewards: CRV, CVX } -object "NativeStakingStrategy" as nativeStrat <><> #$originColor { +object "NativeStakingStrategy" as nativeStrat <><> #$changedColor { assets: WETH, ETH Rewards: ETH, SSV } @@ -74,35 +84,35 @@ object "FeeAccumulator" as feeAcc <><> #$originColor { ' pairs: CRV/ETH, CVX/ETH ' } -' Curve -object "Gauge" as gauge <> { - asset: OETHCRV-f - symbol: OETHCRV-f-gauge - name: Curve.fi OETHCRV-f Gauge Deposit -} -object "StableSwap" as crvPool <> { - assets: [ETH, OETH] - symbol: OETHCRV-f - name: Curve.fi Factory Pool: OETH -} -' Convex -object "Booster" as cvxBoost <> { -} -object "BaseRewardPool" as cvxPool <> { -} -' object "DepositToken" as cvxPoolLp <> { -' symbol: cvxOUSD3CRV-f -' name: Origin Dollar Convex Deposit +' ' Curve +' object "Gauge" as gauge <> { +' asset: OETHCRV-f +' symbol: OETHCRV-f-gauge +' name: Curve.fi OETHCRV-f Gauge Deposit +' } +' object "StableSwap" as crvPool <> { +' assets: [ETH, OETH] +' symbol: OETHCRV-f +' name: Curve.fi Factory Pool: OETH +' } +' ' Convex +' object "Booster" as cvxBoost <> { +' } +' object "BaseRewardPool" as cvxPool <> { +' } +' ' object "DepositToken" as cvxPoolLp <> { +' ' symbol: cvxOUSD3CRV-f +' ' name: Origin Dollar Convex Deposit +' ' } + +' ' SSV +' object "SSV Network" as ssvNet <> #$thirdPartyColor { +' assets: ETH, SSV ' } -' SSV -object "SSV Network" as ssvNet <> #$thirdPartyColor { -assets: ETH, SSV -} - -object "Deposit" as bDep <> #$thirdPartyColor { -assets: ETH -} +' object "Deposit" as bDep <> #$thirdPartyColor { +' assets: ETH +' } ' ' Assets @@ -126,8 +136,11 @@ zap ..> oeth zap ..> oethv ' zap .....> weth +' router ..> arm +arm ..> oethv + ' drip .....> weth -oethv <. drip +oethv <.> drip ' checker ..> oeth ' checker ..> oethv @@ -152,21 +165,21 @@ oeth <... cvxStrat harv <..> nativeStrat oethv <...> nativeStrat nativeStrat <.> feeAcc -nativeStrat ..> ssvNet -nativeStrat ..> bDep - -cvxStrat ..> crvPool -cvxStrat ...> cvxPool -' cvxStrat ...> weth -' cvxStrat ...> cvx -' cvxStrat ...> crv -' cvxPool ..> cvxPoolLp -' cvxPool ..> crv -gauge <. cvxPool -crvPool <.. gauge -oeth <... crvPool -cvxStrat ..> cvxBoost -cvxBoost ..> cvxPool +' nativeStrat ..> ssvNet +' nativeStrat ..> bDep + +' cvxStrat ..> crvPool +' cvxStrat ...> cvxPool +' ' cvxStrat ...> weth +' ' cvxStrat ...> cvx +' ' cvxStrat ...> crv +' ' cvxPool ..> cvxPoolLp +' ' cvxPool ..> crv +' gauge <. cvxPool +' crvPool <.. gauge +' oeth <... crvPool +' cvxStrat ..> cvxBoost +' cvxBoost ..> cvxPool ' ' Vault to Assets ' oethv ....> weth From e8c15b53e628d03370e5fd0a92df134abb14dbd5 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Wed, 22 May 2024 14:33:09 +1000 Subject: [PATCH 080/273] Prettier native staking test --- contracts/test/strategies/nativeSSVStaking.js | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/contracts/test/strategies/nativeSSVStaking.js b/contracts/test/strategies/nativeSSVStaking.js index 01634d2f09..d7419dd089 100644 --- a/contracts/test/strategies/nativeSSVStaking.js +++ b/contracts/test/strategies/nativeSSVStaking.js @@ -877,12 +877,13 @@ describe("Unit test: Native SSV Staking Strategy", function () { it.skip("Deposit alternate deposit_data_root ", async () => { const { depositContractUtils } = fixture; - const newDepositDataRoot = await depositContractUtils.calculateDepositDataRoot( - "0x9254b0fba5173550bcf0950031533e816150167577c15636922406977bafa09ed1a1cc72a148030db977d7091d31c1fa", - "0x010000000000000000000000cf4a9e80ddb173cc17128a361b98b9a140e3932e", - "0x9144bddd6d969571dd058d9656c9da32cf4b8556e18a16362383d02a93bd0901f100874f7f795165a2162badceb5466811f5cfbce8be21d02a87af1898cbe53f5d160d46cbc0863d8e6e28d5f0becf4804cf728b39d0bae69540df896ce97b8b", - ); - console.log(`the new newDepositDataRoot is: ${newDepositDataRoot}`) + const newDepositDataRoot = + await depositContractUtils.calculateDepositDataRoot( + "0x9254b0fba5173550bcf0950031533e816150167577c15636922406977bafa09ed1a1cc72a148030db977d7091d31c1fa", + "0x010000000000000000000000cf4a9e80ddb173cc17128a361b98b9a140e3932e", + "0x9144bddd6d969571dd058d9656c9da32cf4b8556e18a16362383d02a93bd0901f100874f7f795165a2162badceb5466811f5cfbce8be21d02a87af1898cbe53f5d160d46cbc0863d8e6e28d5f0becf4804cf728b39d0bae69540df896ce97b8b" + ); + console.log(`the new newDepositDataRoot is: ${newDepositDataRoot}`); }); }); From acad4b99cda760d6011c39c3fdb573036e1dea2f Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Wed, 22 May 2024 14:50:05 +1000 Subject: [PATCH 081/273] Renamed native staking deploy script --- .../{096_native_ssv_staking.js => 097_native_ssv_staking.js} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename contracts/deploy/mainnet/{096_native_ssv_staking.js => 097_native_ssv_staking.js} (99%) diff --git a/contracts/deploy/mainnet/096_native_ssv_staking.js b/contracts/deploy/mainnet/097_native_ssv_staking.js similarity index 99% rename from contracts/deploy/mainnet/096_native_ssv_staking.js rename to contracts/deploy/mainnet/097_native_ssv_staking.js index 98b5d35b69..bbdcb794b2 100644 --- a/contracts/deploy/mainnet/096_native_ssv_staking.js +++ b/contracts/deploy/mainnet/097_native_ssv_staking.js @@ -3,7 +3,7 @@ const addresses = require("../../utils/addresses"); module.exports = deploymentWithGovernanceProposal( { - deployName: "096_native_ssv_staking", + deployName: "097_native_ssv_staking", forceDeploy: false, //forceSkip: true, reduceQueueTime: true, From 638bf30e4b382b40619593832b04fb4d7369df85 Mon Sep 17 00:00:00 2001 From: Domen Grabec Date: Wed, 22 May 2024 07:01:29 +0200 Subject: [PATCH 082/273] Fix event values (#2060) * add withdrawal events to the tests * add WETH accounting * add better documentation * add sending WETH to the Vault back to fix manual accounting function * actually wrap the ETH to WETH before sending it to the Vault when manually fixing accounting * add withdrawal event to manually fix accounting * fix bugs and add tests with WETH accounting * add test to verify correct deposits * Gas changes to Native Staking's depositAll --------- Co-authored-by: Nicholas Addison --- .../NativeStakingSSVStrategy.sol | 59 +++++- .../NativeStaking/ValidatorAccountant.sol | 37 +++- .../NativeStaking/ValidatorRegistrator.sol | 8 + contracts/test/behaviour/ssvStrategy.js | 69 +++++-- contracts/test/strategies/nativeSSVStaking.js | 172 ++++++++++++++++-- 5 files changed, 305 insertions(+), 40 deletions(-) diff --git a/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol b/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol index 76737fc398..35ea29debf 100644 --- a/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol +++ b/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol @@ -3,6 +3,7 @@ pragma solidity ^0.8.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import "@openzeppelin/contracts/utils/math/Math.sol"; import { InitializableAbstractStrategy } from "../../utils/InitializableAbstractStrategy.sol"; import { IWETH9 } from "../../interfaces/IWETH9.sol"; @@ -18,6 +19,26 @@ struct ValidatorStakeData { /// @title Native Staking SSV Strategy /// @notice Strategy to deploy funds into DVT validators powered by the SSV Network /// @author Origin Protocol Inc +/// @dev This contract handles WETH and ETH and in some operations interchanges between the two. Any WETH that +/// is on the contract across multiple blocks (and not just transitory within a transaction) is considered an +/// asset. Meaning deposits increase the balance of the asset and withdrawal decrease it. As opposed to all +/// our other strategies the WETH doesn't immediately get deposited into an underlying strategy and can be present +/// across multiple blocks waiting to be unwrapped to ETH and staked to validators. This separation of WETH and ETH is +/// required since the rewards (reward token) is also in ETH. +/// +/// To simplify the accounting of WETH there is another difference in behavior compared to the other strategies. +/// To withdraw WETH asset - exit message is posted to validators and the ETH hits this contract with multiple days +/// delay. In order to simplify the WETH accounting upon detection of such an event the ValidatorAccountant +/// immediately wraps ETH to WETH and sends it to the Vault. +/// +/// On the other hand any ETH on the contract (across multiple blocks) is there either: +/// - as a result of already accounted for consensus rewards +/// - as a result of not yet accounted for consensus rewards +/// - as a results of not yet accounted for full validator withdrawals (or validator slashes) +/// +/// Even though the strategy assets and rewards are a very similar asset the consensus layer rewards and the +/// execution layer rewards are considered rewards and those are dripped to the Vault over a configurable time +/// interval and not immediately. contract NativeStakingSSVStrategy is ValidatorAccountant, InitializableAbstractStrategy @@ -33,8 +54,20 @@ contract NativeStakingSSVStrategy is /// (rewards for arranging transactions in a way that benefits the validator). address payable public immutable FEE_ACCUMULATOR_ADDRESS; + /// @dev This contract receives WETH as the deposit asset, but unlike other strategies doesn't immediately + /// deposit it to an underlying platform. Rather a special privilege account stakes it to the validators. + /// For that reason calling WETH.balanceOf(this) in a deposit function can contain WETH that has just been + /// deposited and also WETH that has previously been deposited. To keep a correct count we need to keep track + /// of WETH that has already been accounted for. + /// This value represents the amount of WETH balance of this contract that has already been accounted for by the + /// deposit events. + /// It is important to note that this variable is not concerned with WETH that is a result of full/partial + /// withdrawal of the validators. It is strictly concerned with WETH that has been deposited and is waiting to + /// be staked. + uint256 depositedWethAccountedFor; + // For future use - uint256[50] private __gap; + uint256[49] private __gap; /// @param _baseConfig Base strategy config with platformAddress (ERC-4626 Vault contract), eg sfrxETH or sDAI, /// and vaultAddress (OToken Vault contract), eg VaultProxy or OETHVaultProxy @@ -126,6 +159,7 @@ contract NativeStakingSSVStrategy is nonReentrant { require(_asset == WETH_TOKEN_ADDRESS, "Unsupported asset"); + depositedWethAccountedFor += _amount; _deposit(_asset, _amount); } @@ -154,8 +188,12 @@ contract NativeStakingSSVStrategy is uint256 wethBalance = IERC20(WETH_TOKEN_ADDRESS).balanceOf( address(this) ); - if (wethBalance > 0) { - _deposit(WETH_TOKEN_ADDRESS, wethBalance); + uint256 newWeth = wethBalance - depositedWethAccountedFor; + + if (newWeth > 0) { + depositedWethAccountedFor = wethBalance; + + _deposit(WETH_TOKEN_ADDRESS, newWeth); } } @@ -262,7 +300,20 @@ contract NativeStakingSSVStrategy is ); } - function wethWithdrawnToVault(uint256 _amount) internal override { + function _wethWithdrawnToVault(uint256 _amount) internal override { emit Withdrawal(WETH_TOKEN_ADDRESS, address(0), _amount); } + + function _wethWithdrawnAndStaked(uint256 _amount) internal override { + /* In an ideal world we wouldn't need to reduce the deduction amount when the + * depositedWethAccountedFor is smaller than the _amount. + * + * The reason this is required is that a malicious actor could sent WETH direclty + * to this contract and that would circumvent the increase of depositedWethAccountedFor + * property. When the ETH would be staked the depositedWethAccountedFor amount could + * be deducted so much that it would be negative. + */ + uint256 deductAmount = Math.min(_amount, depositedWethAccountedFor); + depositedWethAccountedFor -= deductAmount; + } } diff --git a/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol b/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol index 996a28bfa7..02d5b42500 100644 --- a/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol +++ b/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol @@ -42,7 +42,8 @@ abstract contract ValidatorAccountant is ValidatorRegistrator { event AccountingManuallyFixed( int256 validatorsDelta, - int256 consensusRewardsDelta + int256 consensusRewardsDelta, + uint256 wethToVault ); /// @param _wethAddress Address of the Erc20 WETH Token contract @@ -132,8 +133,8 @@ abstract contract ValidatorAccountant is ValidatorRegistrator { IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: wethToVault }(); // slither-disable-next-line unchecked-transfer IWETH9(WETH_TOKEN_ADDRESS).transfer(VAULT_ADDRESS, wethToVault); - wethWithdrawnToVault(wethToVault); - + _wethWithdrawnToVault(wethToVault); + emit AccountingFullyWithdrawnValidator( fullyWithdrawnValidators, activeDepositedValidators, @@ -163,7 +164,7 @@ abstract contract ValidatorAccountant is ValidatorRegistrator { IWETH9(WETH_TOKEN_ADDRESS).transfer(VAULT_ADDRESS, ethRemaining); activeDepositedValidators -= 1; - wethWithdrawnToVault(ethRemaining); + _wethWithdrawnToVault(ethRemaining); emit AccountingValidatorSlashed( activeDepositedValidators, @@ -194,9 +195,16 @@ abstract contract ValidatorAccountant is ValidatorRegistrator { /// @notice Allow the Strategist to fix the accounting of this strategy and unpause. /// @param _validatorsDelta adjust the active validators by up to plus three or minus three /// @param _consensusRewardsDelta adjust the accounted for consensus rewards up or down + /// @param _ethToVaultAmount the amount of ETH that gets wrapped into WETH and sent to the Vault + /// @dev There is a case when a validator(s) gets slashed so much that the eth swept from + /// the beacon chain enters the fuse area and there are no consensus rewards on the contract + /// to "dip into"/use. To increase the amount of unaccounted ETH over the fuse end interval + /// we need to reduce the amount of active deposited validators and immediately send WETH + /// to the vault, so it doesn't interfere with further accounting. function manuallyFixAccounting( int256 _validatorsDelta, - int256 _consensusRewardsDelta + int256 _consensusRewardsDelta, + uint256 _ethToVaultAmount ) external onlyStrategist whenPaused { require( lastFixAccountingBlockNumber + MIN_FIX_ACCOUNTING_CADENCE < @@ -217,8 +225,13 @@ abstract contract ValidatorAccountant is ValidatorRegistrator { int256(consensusRewards) + _consensusRewardsDelta >= 0, "invalid consensusRewardsDelta" ); + require(_ethToVaultAmount <= 32 ether * 3, "invalid wethToVaultAmount"); - emit AccountingManuallyFixed(_validatorsDelta, _consensusRewardsDelta); + emit AccountingManuallyFixed( + _validatorsDelta, + _consensusRewardsDelta, + _ethToVaultAmount + ); activeDepositedValidators = uint256( int256(activeDepositedValidators) + _validatorsDelta @@ -226,8 +239,16 @@ abstract contract ValidatorAccountant is ValidatorRegistrator { consensusRewards = uint256( int256(consensusRewards) + _consensusRewardsDelta ); - lastFixAccountingBlockNumber = block.number; + if (_ethToVaultAmount > 0) { + IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: _ethToVaultAmount }(); + // slither-disable-next-line unchecked-transfer + IWETH9(WETH_TOKEN_ADDRESS).transfer( + VAULT_ADDRESS, + _ethToVaultAmount + ); + _wethWithdrawnToVault(_ethToVaultAmount); + } // rerun the accounting to see if it has now been fixed. // Do not pause the accounting on failure as it is already paused @@ -242,5 +263,5 @@ abstract contract ValidatorAccountant is ValidatorRegistrator { ****************************************/ /// @dev allows for NativeStakingSSVStrategy contract to emit Withdrawal event - function wethWithdrawnToVault(uint256 _amount) internal virtual; + function _wethWithdrawnToVault(uint256 _amount) internal virtual; } diff --git a/contracts/contracts/strategies/NativeStaking/ValidatorRegistrator.sol b/contracts/contracts/strategies/NativeStaking/ValidatorRegistrator.sol index c8818530c0..23d07e2e4e 100644 --- a/contracts/contracts/strategies/NativeStaking/ValidatorRegistrator.sol +++ b/contracts/contracts/strategies/NativeStaking/ValidatorRegistrator.sol @@ -114,6 +114,7 @@ abstract contract ValidatorRegistrator is Governable, Pausable { // Convert required ETH from WETH IWETH9(WETH_TOKEN_ADDRESS).withdraw(requiredETH); + _wethWithdrawnAndStaked(requiredETH); uint256 validatorsLength = validators.length; // For each validator @@ -247,4 +248,11 @@ abstract contract ValidatorRegistrator is Governable, Pausable { cluster ); } + + /*************************************** + Abstract + ****************************************/ + + /// @dev allows for NativeStakingSSVStrategy contract know how much WETH had been staked + function _wethWithdrawnAndStaked(uint256 _amount) internal virtual; } diff --git a/contracts/test/behaviour/ssvStrategy.js b/contracts/test/behaviour/ssvStrategy.js index 5bf9f5fc3e..44b4c7949b 100644 --- a/contracts/test/behaviour/ssvStrategy.js +++ b/contracts/test/behaviour/ssvStrategy.js @@ -127,16 +127,23 @@ const shouldBehaveLikeAnSsvStrategy = (context) => { }); describe("Validator operations", function () { - beforeEach(async () => { - const { weth, domen, nativeStakingSSVStrategy } = await context(); + const depositToStrategy = async (amount) => { + const { weth, domen, nativeStakingSSVStrategy, oethVault, strategist } = + await context(); - // Add 32 WETH to the strategy so it can be staked - await weth - .connect(domen) - .transfer(nativeStakingSSVStrategy.address, oethUnits("32")); - }); + // Add 32 WETH to the strategy via a Vualt deposit + await weth.connect(domen).transfer(oethVault.address, amount); + + return await oethVault + .connect(strategist) + .depositToStrategy( + nativeStakingSSVStrategy.address, + [weth.address], + [amount] + ); + }; - it("Should register and staked 32 ETH by validator registrator", async () => { + const registerAndStakeEth = async () => { const { addresses, weth, @@ -157,8 +164,6 @@ const shouldBehaveLikeAnSsvStrategy = (context) => { ssvNetwork: addresses.SSVNetwork, }); - const stakeAmount = oethUnits("32"); - await setERC20TokenBalance( nativeStakingSSVStrategy.address, ssv, @@ -166,6 +171,8 @@ const shouldBehaveLikeAnSsvStrategy = (context) => { hre ); + const stakeAmount = oethUnits("32"); + // Register a new validator with the SSV Network const regTx = await nativeStakingSSVStrategy .connect(validatorRegistrator) @@ -180,7 +187,7 @@ const shouldBehaveLikeAnSsvStrategy = (context) => { .to.emit(nativeStakingSSVStrategy, "SSVValidatorRegistered") .withArgs(testValidator.publicKey, testValidator.operatorIds); - // Stake 32 ETH to the new validator + // Stake stakeAmount ETH to the new validator const stakeTx = await nativeStakingSSVStrategy .connect(validatorRegistrator) .stakeEth([ @@ -195,7 +202,7 @@ const shouldBehaveLikeAnSsvStrategy = (context) => { .to.emit(nativeStakingSSVStrategy, "ETHStaked") .withNamedArgs({ pubkey: testValidator.publicKey, - amount: stakeAmount, + amount: oethUnits("32"), }); expect(await weth.balanceOf(nativeStakingSSVStrategy.address)).to.equal( @@ -204,6 +211,43 @@ const shouldBehaveLikeAnSsvStrategy = (context) => { "strategy WETH not decreased" ) ); + }; + + it("Should register and stake 32 ETH by validator registrator", async () => { + await depositToStrategy(oethUnits("32")); + await registerAndStakeEth(); + }); + + it("Should emit correct values in deposit event", async () => { + const { weth, nativeStakingSSVStrategy } = await context(); + + await depositToStrategy(oethUnits("40")); + // at least 8 WETH has remained on the contract and a deposit all + // event should emit a correct amount + await registerAndStakeEth(); + + /* deposit to strategy calls depositAll on the strategy contract after sending the WETH + * to it. The event should contain only the amount of newly deposited WETH and not include + * the pre-exiting WETH. + */ + const tx = await depositToStrategy(parseEther("10")); + + await expect(tx) + .to.emit(nativeStakingSSVStrategy, "Deposit") + .withArgs(weth.address, AddressZero, parseEther("10")); + }); + + it("Should register and stake 32 ETH even if half supplied by a 3rd party", async () => { + const { weth, domen, nativeStakingSSVStrategy } = await context(); + + await depositToStrategy(oethUnits("16")); + // A malicious actor is sending WETH directly to the native staking contract hoping to + // mess up the accounting. + await weth + .connect(domen) + .transfer(nativeStakingSSVStrategy.address, oethUnits("16")); + + await registerAndStakeEth(); }); it("Should exit and remove validator by validator registrator", async () => { @@ -215,6 +259,7 @@ const shouldBehaveLikeAnSsvStrategy = (context) => { addresses, testValidator, } = await context(); + await depositToStrategy(oethUnits("32")); const { cluster } = await getClusterInfo({ ownerAddress: nativeStakingSSVStrategy.address, diff --git a/contracts/test/strategies/nativeSSVStaking.js b/contracts/test/strategies/nativeSSVStaking.js index d7419dd089..f3cff0d0aa 100644 --- a/contracts/test/strategies/nativeSSVStaking.js +++ b/contracts/test/strategies/nativeSSVStaking.js @@ -13,6 +13,7 @@ const { shouldBehaveLikeHarvestable } = require("../behaviour/harvestable"); const { shouldBehaveLikeStrategy } = require("../behaviour/strategy"); const { MAX_UINT256 } = require("../../utils/constants"); const { impersonateAndFund } = require("../../utils/signers"); +const { zero } = require("../../utils/addresses"); const minFixAccountingCadence = 7200 + 1; const { @@ -447,7 +448,7 @@ describe("Unit test: Native SSV Staking Strategy", function () { } consensus rewards, ${expectedValidatorsFullWithdrawals} withdraws${ fuseBlown ? ", fuse blown" : "" }${slashDetected ? ", slash detected" : ""}.`, async () => { - const { nativeStakingSSVStrategy, governor } = fixture; + const { nativeStakingSSVStrategy, governor, weth } = fixture; // setup state if (ethBalance.gt(0)) { @@ -477,6 +478,9 @@ describe("Unit test: Native SSV Staking Strategy", function () { } if (expectedValidatorsFullWithdrawals > 0) { + const ethWithdrawnToVault = parseEther("32").mul( + expectedValidatorsFullWithdrawals + ); await expect(tx) .to.emit( nativeStakingSSVStrategy, @@ -485,8 +489,12 @@ describe("Unit test: Native SSV Staking Strategy", function () { .withArgs( expectedValidatorsFullWithdrawals, 30 - expectedValidatorsFullWithdrawals, - parseEther("32").mul(expectedValidatorsFullWithdrawals) + ethWithdrawnToVault ); + + await expect(tx) + .to.emit(nativeStakingSSVStrategy, "Withdrawal") + .withArgs(weth.address, zero, ethWithdrawnToVault); } else { await expect(tx).to.not.emit( nativeStakingSSVStrategy, @@ -501,11 +509,22 @@ describe("Unit test: Native SSV Staking Strategy", function () { } if (slashDetected) { + const fullExitEthWithdrawnToVault = parseEther("32").mul( + expectedValidatorsFullWithdrawals + ); + const slashedEthRemaining = ethBalance.sub( + fullExitEthWithdrawnToVault + ); + await expect(tx) .to.emit(nativeStakingSSVStrategy, "AccountingValidatorSlashed") .withNamedArgs({ remainingValidators: 30 - expectedValidatorsFullWithdrawals - 1, }); + + await expect(tx) + .to.emit(nativeStakingSSVStrategy, "Withdrawal") + .withArgs(weth.address, zero, slashedEthRemaining); } else { await expect(tx).to.not.emit( nativeStakingSSVStrategy, @@ -524,7 +543,8 @@ describe("Unit test: Native SSV Staking Strategy", function () { await expect( nativeStakingSSVStrategy.connect(governor).manuallyFixAccounting( 1, //_validatorsDelta - parseEther("2") //_consensusRewardsDelta + parseEther("2"), //_consensusRewardsDelta, + parseEther("2") //_ethToVault ) ).to.be.revertedWith("Caller is not the Strategist"); }); @@ -536,7 +556,8 @@ describe("Unit test: Native SSV Staking Strategy", function () { await expect( nativeStakingSSVStrategy.connect(strategist).manuallyFixAccounting( 1, //_validatorsDelta - parseEther("2") //_consensusRewardsDelta + parseEther("2"), //_consensusRewardsDelta + parseEther("2") //_ethToVault ) ).to.be.revertedWith("Pausable: not paused"); }); @@ -550,14 +571,16 @@ describe("Unit test: Native SSV Staking Strategy", function () { await expect( nativeStakingSSVStrategy.connect(strategist).manuallyFixAccounting( -4, //_validatorsDelta - 0 //_consensusRewardsDelta + 0, //_consensusRewardsDelta, + 0 //_ethToVault ) ).to.be.revertedWith("invalid validatorsDelta"); await expect( nativeStakingSSVStrategy.connect(strategist).manuallyFixAccounting( 4, //_validatorsDelta - 0 //_consensusRewardsDelta + 0, //_consensusRewardsDelta + 0 //_ethToVault ) ).to.be.revertedWith("invalid validatorsDelta"); }); @@ -571,18 +594,35 @@ describe("Unit test: Native SSV Staking Strategy", function () { await expect( nativeStakingSSVStrategy.connect(strategist).manuallyFixAccounting( 0, //_validatorsDelta - parseEther("-333") //_consensusRewardsDelta + parseEther("-333"), //_consensusRewardsDelta + 0 //_ethToVault ) ).to.be.revertedWith("invalid consensusRewardsDelta"); await expect( nativeStakingSSVStrategy.connect(strategist).manuallyFixAccounting( 0, //_validatorsDelta - parseEther("333") //_consensusRewardsDelta + parseEther("333"), //_consensusRewardsDelta + 0 //_ethToVault ) ).to.be.revertedWith("invalid consensusRewardsDelta"); }); + it("WETH to Vault amount should not be > 96 for fix accounting function", async () => { + const { nativeStakingSSVStrategy, strategist } = fixture; + + await nativeStakingSSVStrategy.connect(strategist).pause(); + await mine(minFixAccountingCadence); + + await expect( + nativeStakingSSVStrategy.connect(strategist).manuallyFixAccounting( + 0, //_validatorsDelta + 0, //_consensusRewardsDelta + parseEther("97") //_ethToVault + ) + ).to.be.revertedWith("invalid wethToVaultAmount"); + }); + describe("Should allow strategist to recover paused contract", async () => { for (const validatorsDelta of [-3, -2, -1, 0, 1, 2, 3]) { it(`by changing validators by ${validatorsDelta}`, async () => { @@ -592,12 +632,13 @@ describe("Unit test: Native SSV Staking Strategy", function () { await nativeStakingSSVStrategy.connect(strategist).pause(); await mine(minFixAccountingCadence); + const activeDepositedValidatorsBefore = await nativeStakingSSVStrategy.activeDepositedValidators(); const tx = await nativeStakingSSVStrategy .connect(strategist) - .manuallyFixAccounting(validatorsDelta, 0); + .manuallyFixAccounting(validatorsDelta, 0, 0); expect(tx) .to.emit(nativeStakingSSVStrategy, "AccountingManuallyFixed") @@ -629,7 +670,7 @@ describe("Unit test: Native SSV Staking Strategy", function () { const tx = await nativeStakingSSVStrategy .connect(strategist) - .manuallyFixAccounting(0, consensusRewardsDelta); + .manuallyFixAccounting(0, consensusRewardsDelta, 0); expect(tx) .to.emit(nativeStakingSSVStrategy, "AccountingManuallyFixed") @@ -644,6 +685,99 @@ describe("Unit test: Native SSV Staking Strategy", function () { }); } + for (const eth of [0, 1, 26, 32, 63, 65, 95]) { + it(`by sending ${eth} ETH wrapped to WETH to the vault`, async () => { + const { nativeStakingSSVStrategy, strategist } = fixture; + + const wethToVaultBn = parseEther(`${eth}`); + + // add a bit more ETH so we don't completely empty the contract + await setBalance( + nativeStakingSSVStrategy.address, + wethToVaultBn.add(parseEther("2")) + ); + + await nativeStakingSSVStrategy.connect(strategist).pause(); + await mine(minFixAccountingCadence); + const ethBefore = await nativeStakingSSVStrategy.provider.getBalance( + nativeStakingSSVStrategy.address + ); + + const tx = await nativeStakingSSVStrategy + .connect(strategist) + .manuallyFixAccounting(0, 0, wethToVaultBn); + + expect(tx) + .to.emit(nativeStakingSSVStrategy, "AccountingManuallyFixed") + .withArgs(0, 0, wethToVaultBn); + + expect( + await nativeStakingSSVStrategy.provider.getBalance( + nativeStakingSSVStrategy.address + ) + ).to.equal( + ethBefore.sub(wethToVaultBn), + "consensus rewards not updated" + ); + + expect(await nativeStakingSSVStrategy.consensusRewards()).to.equal( + await nativeStakingSSVStrategy.provider.getBalance( + nativeStakingSSVStrategy.address + ), + "consensus rewards matches eth balance" + ); + }); + } + + it("by marking a validator as withdrawn when severely slashed and sent its funds to the vault", async () => { + const { nativeStakingSSVStrategy, governor, strategist, weth } = + fixture; + + // setup initial state + await nativeStakingSSVStrategy.connect(strategist).pause(); + await mine(minFixAccountingCadence); + // setup 1 validator so one can be deducted later in the test + await nativeStakingSSVStrategy + .connect(strategist) + .manuallyFixAccounting( + 1, //_validatorsDelta + 0, //_consensusRewardsDeltaDelta + 0 //_ethToVault + ); + + // a validator has been slashed and penalized by 8 ETH + await setBalance(nativeStakingSSVStrategy.address, parseEther("24")); + + // run the accounting + const tx = await nativeStakingSSVStrategy + .connect(governor) + .doAccounting(); + // fuse blown contract paused + await expect(tx).to.emit(nativeStakingSSVStrategy, "Paused"); + await mine(minFixAccountingCadence); + + // unit test fixture sets OUSD governor as accounting governor + const tx2 = await nativeStakingSSVStrategy + .connect(strategist) + .manuallyFixAccounting( + -1, //_validatorsDelta + 0, //_consensusRewardsDeltaDelta + parseEther("24") //_ethToVault + ); + + expect(tx2) + .to.emit(nativeStakingSSVStrategy, "AccountingManuallyFixed") + .withArgs( + -1, // validatorsDelta + 0, // consensusRewards + parseEther("24") + ); + + expect(tx2) + .to.emit(nativeStakingSSVStrategy, "Withdrawal") + .withArgs(weth.address, zero, parseEther("24")); + }); + it("by changing all three manuallyFixAccounting delta values", async () => { const { nativeStakingSSVStrategy, strategist, josh, weth } = fixture; @@ -659,14 +793,16 @@ describe("Unit test: Native SSV Staking Strategy", function () { .connect(strategist) .manuallyFixAccounting( 1, //_validatorsDelta - parseEther("2.3") //_consensusRewardsDeltaDelta + parseEther("2.3"), //_consensusRewardsDeltaDelta + parseEther("2.2") //_ethToVault ); expect(tx) .to.emit(nativeStakingSSVStrategy, "AccountingManuallyFixed") .withArgs( 1, // validatorsDelta - parseEther("2.3") // consensusRewards + parseEther("2.3"), // consensusRewards + parseEther("2.2") ); }); @@ -679,7 +815,8 @@ describe("Unit test: Native SSV Staking Strategy", function () { .connect(strategist) .manuallyFixAccounting( 0, //_validatorsDelta - parseEther("0") //_consensusRewardsDelta + 0, //_consensusRewardsDelta + 0 //_ethToVault ); await nativeStakingSSVStrategy.connect(strategist).pause(); @@ -687,7 +824,8 @@ describe("Unit test: Native SSV Staking Strategy", function () { await expect( nativeStakingSSVStrategy.connect(strategist).manuallyFixAccounting( 0, //_validatorsDelta - parseEther("0") //_consensusRewardsDelta + 0, //_consensusRewardsDelta + 0 //_ethToVault ) ).to.be.revertedWith("manuallyFixAccounting called too soon"); }); @@ -701,7 +839,8 @@ describe("Unit test: Native SSV Staking Strategy", function () { .connect(strategist) .manuallyFixAccounting( 0, //_validatorsDelta - parseEther("0") //_consensusRewardsDelta + 0, //_consensusRewardsDelta + 0 //_ethToVault ); await nativeStakingSSVStrategy.connect(strategist).pause(); @@ -710,7 +849,8 @@ describe("Unit test: Native SSV Staking Strategy", function () { .connect(strategist) .manuallyFixAccounting( 0, //_validatorsDelta - parseEther("0") //_consensusRewardsDelta + 0, //_consensusRewardsDelta + 0 //_ethToVault ); }); }); From b4e9c3f8027fd6f4096619f88477ad6546eb2bf5 Mon Sep 17 00:00:00 2001 From: Nick Addison Date: Wed, 22 May 2024 17:24:14 +1000 Subject: [PATCH 083/273] Deploy latest Native Staking Strategy to Holesky (#2073) * Deployed new NativeStakingSSVStrategy * Generated latest Native Staking Strategy diagrams --- .../NativeStakingSSVStrategy.sol | 2 +- .../deploy/holesky/009_upgrade_strategy.js | 18 + .../deployments/holesky/.migrations.json | 3 +- .../holesky/NativeStakingSSVStrategy.json | 180 +++-- .../279a9fe8a2da81dca55abd3c6ec521f8.json | 689 ++++++++++++++++++ .../docs/NativeStakingSSVStrategySquashed.svg | 128 ++-- .../docs/NativeStakingSSVStrategyStorage.svg | 200 ++--- contracts/test/behaviour/ssvStrategy.js | 2 +- 8 files changed, 1004 insertions(+), 218 deletions(-) create mode 100644 contracts/deploy/holesky/009_upgrade_strategy.js create mode 100644 contracts/deployments/holesky/solcInputs/279a9fe8a2da81dca55abd3c6ec521f8.json diff --git a/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol b/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol index 35ea29debf..a26b110f29 100644 --- a/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol +++ b/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol @@ -64,7 +64,7 @@ contract NativeStakingSSVStrategy is /// It is important to note that this variable is not concerned with WETH that is a result of full/partial /// withdrawal of the validators. It is strictly concerned with WETH that has been deposited and is waiting to /// be staked. - uint256 depositedWethAccountedFor; + uint256 public depositedWethAccountedFor; // For future use uint256[49] private __gap; diff --git a/contracts/deploy/holesky/009_upgrade_strategy.js b/contracts/deploy/holesky/009_upgrade_strategy.js new file mode 100644 index 0000000000..bc019c3858 --- /dev/null +++ b/contracts/deploy/holesky/009_upgrade_strategy.js @@ -0,0 +1,18 @@ +const { upgradeNativeStakingSSVStrategy } = require("../deployActions"); + +const mainExport = async () => { + console.log("Running 009 deployment on Holesky..."); + + console.log("Upgrading native staking strategy"); + await upgradeNativeStakingSSVStrategy(); + + console.log("Running 009 deployment done"); + return true; +}; + +mainExport.id = "009_upgrade_strategy"; +mainExport.tags = []; +mainExport.dependencies = []; +mainExport.skip = () => false; + +module.exports = mainExport; diff --git a/contracts/deployments/holesky/.migrations.json b/contracts/deployments/holesky/.migrations.json index d184f8298b..4335e20f75 100644 --- a/contracts/deployments/holesky/.migrations.json +++ b/contracts/deployments/holesky/.migrations.json @@ -6,5 +6,6 @@ "005_deploy_new_harvester": 1714998707, "006_update_registrator": 1715184342, "007_upgrade_strategy": 1715251466, - "008_upgrade_strategy": 1715341541 + "008_upgrade_strategy": 1715341541, + "009_upgrade_strategy": 1716360052 } \ No newline at end of file diff --git a/contracts/deployments/holesky/NativeStakingSSVStrategy.json b/contracts/deployments/holesky/NativeStakingSSVStrategy.json index d4dc37f2d3..f466e3a4fb 100644 --- a/contracts/deployments/holesky/NativeStakingSSVStrategy.json +++ b/contracts/deployments/holesky/NativeStakingSSVStrategy.json @@ -1,5 +1,5 @@ { - "address": "0x52a825Fe934303f0c1b33Aee00A830ce984BAadB", + "address": "0xa48dE0659EA8d9CFC293F47FD0d74d644690EB4B", "abi": [ { "inputs": [ @@ -499,6 +499,19 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "MIN_FIX_ACCOUNTING_CADENCE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "SSV_NETWORK_ADDRESS", @@ -704,6 +717,19 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [], + "name": "depositedWethAccountedFor", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "doAccounting", @@ -836,6 +862,19 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "lastFixAccountingBlockNumber", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -850,7 +889,7 @@ }, { "internalType": "uint256", - "name": "_wethToVaultAmount", + "name": "_ethToVaultAmount", "type": "uint256" } ], @@ -1276,34 +1315,34 @@ "type": "receive" } ], - "transactionHash": "0xb602601e65659bec956b861609b760722c3801a76375aa64020d6c951ef5e791", + "transactionHash": "0x8ca768edbc9a7d1fc3fcd31ced7c70f27cba30f49f1916f6a7f68934956feb76", "receipt": { "to": null, "from": "0x1b94CA50D3Ad9f8368851F8526132272d1a5028C", - "contractAddress": "0x52a825Fe934303f0c1b33Aee00A830ce984BAadB", - "transactionIndex": 28, - "gasUsed": "4091194", - "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000800000000000000000000000004000000000004000000000000002000000000080000000040000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000010000000000010000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000", - "blockHash": "0x3e35a66d156ee4f1ea266be3771b244e6952db22d5290cb8f87f0d7cb40eaf22", - "transactionHash": "0xb602601e65659bec956b861609b760722c3801a76375aa64020d6c951ef5e791", + "contractAddress": "0xa48dE0659EA8d9CFC293F47FD0d74d644690EB4B", + "transactionIndex": 8, + "gasUsed": "4205791", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000002004000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000010000000000000000000000000000000000000000020000000000000000008000000000000000000000000000000000000000000000000", + "blockHash": "0x1a290a506c0cf9148a26e778adacf7bd59da033eede5b446f4f2a8b0ce51f393", + "transactionHash": "0x8ca768edbc9a7d1fc3fcd31ced7c70f27cba30f49f1916f6a7f68934956feb76", "logs": [ { - "transactionIndex": 28, - "blockNumber": 1515917, - "transactionHash": "0xb602601e65659bec956b861609b760722c3801a76375aa64020d6c951ef5e791", - "address": "0x52a825Fe934303f0c1b33Aee00A830ce984BAadB", + "transactionIndex": 8, + "blockNumber": 1589658, + "transactionHash": "0x8ca768edbc9a7d1fc3fcd31ced7c70f27cba30f49f1916f6a7f68934956feb76", + "address": "0xa48dE0659EA8d9CFC293F47FD0d74d644690EB4B", "topics": [ "0xc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000001b94ca50d3ad9f8368851f8526132272d1a5028c" ], "data": "0x", - "logIndex": 363, - "blockHash": "0x3e35a66d156ee4f1ea266be3771b244e6952db22d5290cb8f87f0d7cb40eaf22" + "logIndex": 12, + "blockHash": "0x1a290a506c0cf9148a26e778adacf7bd59da033eede5b446f4f2a8b0ce51f393" } ], - "blockNumber": 1515917, - "cumulativeGasUsed": "15703993", + "blockNumber": 1589658, + "cumulativeGasUsed": "4985268", "status": 1, "byzantium": true }, @@ -1318,14 +1357,15 @@ "0x65a289f4BF934c964C942eFF6E6F83b6481BE550", "0x4242424242424242424242424242424242424242" ], - "numDeployments": 3, - "solcInputHash": "02842452c275dc62641a0db2f51fdc73", - "metadata": "{\"compiler\":{\"version\":\"0.8.7+commit.e28d00a7\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"platformAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"vaultAddress\",\"type\":\"address\"}],\"internalType\":\"struct InitializableAbstractStrategy.BaseStrategyConfig\",\"name\":\"_baseConfig\",\"type\":\"tuple\"},{\"internalType\":\"address\",\"name\":\"_wethAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_ssvToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_ssvNetwork\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_feeAccumulator\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_beaconChainDepositContract\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"AccountingConsensusRewards\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"noOfValidators\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"remainingValidators\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"wethSentToVault\",\"type\":\"uint256\"}],\"name\":\"AccountingFullyWithdrawnValidator\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"validatorsDelta\",\"type\":\"int256\"},{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"consensusRewardsDelta\",\"type\":\"int256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"wethToVault\",\"type\":\"uint256\"}],\"name\":\"AccountingManuallyFixed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"remainingValidators\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"wethSentToVault\",\"type\":\"uint256\"}],\"name\":\"AccountingValidatorSlashed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"Deposit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"pubkey\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"withdrawal_credentials\",\"type\":\"bytes\"}],\"name\":\"ETHStaked\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"start\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"end\",\"type\":\"uint256\"}],\"name\":\"FuseIntervalUpdated\",\"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\":\"address\",\"name\":\"_oldHarvesterAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_newHarvesterAddress\",\"type\":\"address\"}],\"name\":\"HarvesterAddressesUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"}],\"name\":\"PTokenAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"}],\"name\":\"PTokenRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Paused\",\"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\":\"newAddress\",\"type\":\"address\"}],\"name\":\"RegistratorChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"_oldAddresses\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"_newAddresses\",\"type\":\"address[]\"}],\"name\":\"RewardTokenAddressesUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"rewardToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"RewardTokenCollected\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"pubkey\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"}],\"name\":\"SSVValidatorExitCompleted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"pubkey\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"}],\"name\":\"SSVValidatorExitInitiated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"pubkey\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"}],\"name\":\"SSVValidatorRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Unpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"Withdrawal\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"BEACON_CHAIN_DEPOSIT_CONTRACT\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_ACCUMULATOR_ADDRESS\",\"outputs\":[{\"internalType\":\"address payable\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MAX_STAKE\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"SSV_NETWORK_ADDRESS\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"SSV_TOKEN_ADDRESS\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"VAULT_ADDRESS\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"WETH_TOKEN_ADDRESS\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"activeDepositedValidators\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"assetToPToken\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"}],\"name\":\"checkBalance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"claimGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"collectRewardTokens\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"consensusRewards\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"depositAll\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"validatorCount\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"networkFeeIndex\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"index\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"active\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"internalType\":\"struct Cluster\",\"name\":\"cluster\",\"type\":\"tuple\"}],\"name\":\"depositSSV\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"doAccounting\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"accountingValid\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"publicKey\",\"type\":\"bytes\"},{\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"}],\"name\":\"exitSsvValidator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fuseIntervalEnd\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fuseIntervalStart\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRewardTokenAddresses\",\"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\":\"harvesterAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"_rewardTokenAddresses\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"_assets\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"_pTokens\",\"type\":\"address[]\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isGovernor\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"int256\",\"name\":\"_validatorsDelta\",\"type\":\"int256\"},{\"internalType\":\"int256\",\"name\":\"_consensusRewardsDelta\",\"type\":\"int256\"},{\"internalType\":\"uint256\",\"name\":\"_wethToVaultAmount\",\"type\":\"uint256\"}],\"name\":\"manuallyFixAccounting\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"paused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"platformAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"publicKey\",\"type\":\"bytes\"},{\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"},{\"internalType\":\"bytes\",\"name\":\"sharesData\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"validatorCount\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"networkFeeIndex\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"index\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"active\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"internalType\":\"struct Cluster\",\"name\":\"cluster\",\"type\":\"tuple\"}],\"name\":\"registerSsvValidator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_assetIndex\",\"type\":\"uint256\"}],\"name\":\"removePToken\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"publicKey\",\"type\":\"bytes\"},{\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"validatorCount\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"networkFeeIndex\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"index\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"active\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"internalType\":\"struct Cluster\",\"name\":\"cluster\",\"type\":\"tuple\"}],\"name\":\"removeSsvValidator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"rewardTokenAddresses\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"safeApproveAllTokens\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_fuseIntervalStart\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_fuseIntervalEnd\",\"type\":\"uint256\"}],\"name\":\"setFuseInterval\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_harvesterAddress\",\"type\":\"address\"}],\"name\":\"setHarvesterAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"}],\"name\":\"setPTokenAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"setRegistrator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"_rewardTokenAddresses\",\"type\":\"address[]\"}],\"name\":\"setRewardTokenAddresses\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"pubkey\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"depositDataRoot\",\"type\":\"bytes32\"}],\"internalType\":\"struct ValidatorStakeData[]\",\"name\":\"validators\",\"type\":\"tuple[]\"}],\"name\":\"stakeEth\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"}],\"name\":\"supportsAsset\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"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\":\"validatorRegistrator\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"validatorsStates\",\"outputs\":[{\"internalType\":\"enum ValidatorRegistrator.VALIDATOR_STATE\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"vaultAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"withdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdrawAll\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"author\":\"Origin Protocol Inc\",\"kind\":\"dev\",\"methods\":{\"checkBalance(address)\":{\"params\":{\"_asset\":\"Address of weth asset\"},\"returns\":{\"balance\":\" Total value of (W)ETH\"}},\"constructor\":{\"params\":{\"_baseConfig\":\"Base strategy config with platformAddress (ERC-4626 Vault contract), eg sfrxETH or sDAI, and vaultAddress (OToken Vault contract), eg VaultProxy or OETHVaultProxy\",\"_beaconChainDepositContract\":\"Address of the beacon chain deposit contract\",\"_feeAccumulator\":\"Address of the fee accumulator receiving execution layer validator rewards\",\"_ssvNetwork\":\"Address of the SSV Network contract\",\"_ssvToken\":\"Address of the Erc20 SSV Token contract\",\"_wethAddress\":\"Address of the Erc20 WETH Token contract\"}},\"deposit(address,uint256)\":{\"params\":{\"_amount\":\"Amount of assets that were transferred to the strategy by the vault.\",\"_asset\":\"Address of asset to deposit. Has to be WETH.\"}},\"depositSSV(uint64[],uint256,(uint32,uint64,uint64,bool,uint256))\":{\"details\":\"A SSV cluster is defined by the SSVOwnerAddress and the set of operatorIds. uses \\\"onlyStrategist\\\" modifier so continuous front-running can't DOS our maintenance service that tries to top up SSV tokens.\",\"params\":{\"cluster\":\"The SSV cluster details that must be derived from emitted events from the SSVNetwork contract.\"}},\"doAccounting()\":{\"details\":\"This function could in theory be permission-less but lets allow only the Registrator (Defender Action) to call it for now.\",\"returns\":{\"accountingValid\":\"true if accounting was successful, false if fuse is blown\"}},\"getRewardTokenAddresses()\":{\"returns\":{\"_0\":\"address[] the reward token addresses.\"}},\"initialize(address[],address[],address[])\":{\"params\":{\"_assets\":\"Addresses of initial supported assets\",\"_pTokens\":\"Platform Token corresponding addresses\",\"_rewardTokenAddresses\":\"Address of reward token for platform\"}},\"manuallyFixAccounting(int256,int256,uint256)\":{\"params\":{\"_consensusRewardsDelta\":\"adjust the accounted for consensus rewards up or down\",\"_validatorsDelta\":\"adjust the active validators by plus one, minus one or unchanged with zero\",\"_wethToVaultAmount\":\"the amount of WETH to be sent to the Vault\"}},\"paused()\":{\"details\":\"Returns true if the contract is paused, and false otherwise.\"},\"removePToken(uint256)\":{\"params\":{\"_assetIndex\":\"Index of the asset to be removed\"}},\"setHarvesterAddress(address)\":{\"params\":{\"_harvesterAddress\":\"Address of the harvester contract.\"}},\"setPTokenAddress(address,address)\":{\"params\":{\"_asset\":\"Address for the asset\",\"_pToken\":\"Address for the corresponding platform token\"}},\"setRewardTokenAddresses(address[])\":{\"params\":{\"_rewardTokenAddresses\":\"Array of reward token addresses\"}},\"stakeEth((bytes,bytes,bytes32)[])\":{\"params\":{\"validators\":\"A list of validator data needed to stake. The `ValidatorStakeData` struct contains the pubkey, signature and depositDataRoot. Only the registrator can call this function.\"}},\"supportsAsset(address)\":{\"params\":{\"_asset\":\"The address of the asset token.\"}},\"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\"}},\"withdraw(address,address,uint256)\":{\"params\":{\"_amount\":\"Amount of WETH to withdraw\",\"_asset\":\"WETH to withdraw\",\"_recipient\":\"Address to receive withdrawn assets\"}}},\"stateVariables\":{\"FEE_ACCUMULATOR_ADDRESS\":{\"details\":\"this address will receive Execution layer rewards - These are rewards earned for executing transactions on the Ethereum network as part of block proposals. They include priority fees (fees paid by users for their transactions to be included) and MEV rewards (rewards for arranging transactions in a way that benefits the validator).\"}},\"title\":\"Native Staking SSV Strategy\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"BEACON_CHAIN_DEPOSIT_CONTRACT()\":{\"notice\":\"The address of the beacon chain deposit contract\"},\"FEE_ACCUMULATOR_ADDRESS()\":{\"notice\":\"Fee collector address\"},\"MAX_STAKE()\":{\"notice\":\"The maximum amount of ETH that can be staked by a validator\"},\"SSV_NETWORK_ADDRESS()\":{\"notice\":\"The address of the SSV Network contract used to interface with\"},\"SSV_TOKEN_ADDRESS()\":{\"notice\":\"SSV ERC20 token that serves as a payment for operating SSV validators\"},\"VAULT_ADDRESS()\":{\"notice\":\"Address of the OETH Vault proxy contract\"},\"WETH_TOKEN_ADDRESS()\":{\"notice\":\"The address of the Wrapped ETH (WETH) token contract\"},\"activeDepositedValidators()\":{\"notice\":\"The number of validators that have 32 (!) ETH actively deposited. When a new deposit to a validator happens this number increases, when a validator exit is detected this number decreases.\"},\"assetToPToken(address)\":{\"notice\":\"asset => pToken (Platform Specific Token Address)\"},\"checkBalance(address)\":{\"notice\":\"Returns the total value of (W)ETH that is staked to the validators and WETH deposits that are still to be staked. This does not include ETH from consensus rewards sitting in this strategy or ETH from MEV rewards in the FeeAccumulator. These rewards are harvested and sent to the Dripper so will eventually be sent to the Vault as WETH.\"},\"claimGovernance()\":{\"notice\":\"Claim Governance of the contract to a new account (`newGovernor`). Can only be called by the new Governor.\"},\"collectRewardTokens()\":{\"notice\":\"Collect accumulated reward token and send to Vault.\"},\"consensusRewards()\":{\"notice\":\"Keeps track of the total consensus rewards swept from the beacon chain\"},\"deposit(address,uint256)\":{\"notice\":\"Unlike other strategies, this does not deposit assets into the underlying platform. It just checks the asset is WETH and emits the Deposit event. To deposit WETH into validators `registerSsvValidator` and `stakeEth` must be used. Will NOT revert if the strategy is paused from an accounting failure.\"},\"depositAll()\":{\"notice\":\"Unlike other strategies, this does not deposit assets into the underlying platform. It just emits the Deposit event. To deposit WETH into validators `registerSsvValidator` and `stakeEth` must be used. Will NOT revert if the strategy is paused from an accounting failure.\"},\"depositSSV(uint64[],uint256,(uint32,uint64,uint64,bool,uint256))\":{\"notice\":\"Deposits more SSV Tokens to the SSV Network contract which is used to pay the SSV Operators.\"},\"doAccounting()\":{\"notice\":\"This notion page offers a good explanation of how the accounting functions https://www.notion.so/originprotocol/Limited-simplified-native-staking-accounting-67a217c8420d40678eb943b9da0ee77d In short, after dividing by 32, if the ETH remaining on the contract falls between 0 and fuseIntervalStart, the accounting function will treat that ETH as Beacon chain consensus rewards. On the contrary, if after dividing by 32, the ETH remaining on the contract falls between fuseIntervalEnd and 32, the accounting function will treat that as a validator slashing.Perform the accounting attributing beacon chain ETH to either full or partial withdrawals. Returns true when accounting is valid and fuse isn't \\\"blown\\\". Returns false when fuse is blown.\"},\"exitSsvValidator(bytes,uint64[])\":{\"notice\":\"Exit a validator from the Beacon chain. The staked ETH will eventually swept to this native staking strategy. Only the registrator can call this function.\"},\"fuseIntervalEnd()\":{\"notice\":\"end of fuse interval\"},\"fuseIntervalStart()\":{\"notice\":\"start of fuse interval\"},\"getRewardTokenAddresses()\":{\"notice\":\"Get the reward token addresses.\"},\"governor()\":{\"notice\":\"Returns the address of the current Governor.\"},\"harvesterAddress()\":{\"notice\":\"Address of the Harvester contract allowed to collect reward tokens\"},\"initialize(address[],address[],address[])\":{\"notice\":\"initialize function, to set up initial internal state\"},\"isGovernor()\":{\"notice\":\"Returns true if the caller is the current Governor.\"},\"manuallyFixAccounting(int256,int256,uint256)\":{\"notice\":\"Allow the Strategist to fix the accounting of this strategy and unpause.\"},\"platformAddress()\":{\"notice\":\"Address of the underlying platform\"},\"registerSsvValidator(bytes,uint64[],bytes,uint256,(uint32,uint64,uint64,bool,uint256))\":{\"notice\":\"Registers a new validator in the SSV Cluster. Only the registrator can call this function.\"},\"removePToken(uint256)\":{\"notice\":\"Remove a supported asset by passing its index. This method can only be called by the system Governor\"},\"removeSsvValidator(bytes,uint64[],(uint32,uint64,uint64,bool,uint256))\":{\"notice\":\"Remove a validator from the SSV Cluster. Make sure `exitSsvValidator` is called before and the validate has exited the Beacon chain. If removed before the validator has exited the beacon chain will result in the validator being slashed. Only the registrator can call this function.\"},\"rewardTokenAddresses(uint256)\":{\"notice\":\"Address of the reward tokens. eg CRV, BAL, CVX, AURA\"},\"safeApproveAllTokens()\":{\"notice\":\"Approves the SSV Network contract to transfer SSV tokens for deposits\"},\"setFuseInterval(uint256,uint256)\":{\"notice\":\"set fuse interval values\"},\"setHarvesterAddress(address)\":{\"notice\":\"Set the Harvester contract that can collect rewards.\"},\"setPTokenAddress(address,address)\":{\"notice\":\"Provide support for asset by passing its pToken address. This method can only be called by the system Governor\"},\"setRegistrator(address)\":{\"notice\":\"Set the address of the registrator which can register, exit and remove validators\"},\"setRewardTokenAddresses(address[])\":{\"notice\":\"Set the reward token addresses. Any old addresses will be overwritten.\"},\"stakeEth((bytes,bytes,bytes32)[])\":{\"notice\":\"Stakes WETH to the node validators\"},\"supportsAsset(address)\":{\"notice\":\"Returns bool indicating whether asset is supported by strategy.\"},\"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 strategy contracts, i.e. mistaken sends.\"},\"validatorRegistrator()\":{\"notice\":\"Address of the registrator - allowed to register, exit and remove validators\"},\"validatorsStates(bytes32)\":{\"notice\":\"State of the validators keccak256(pubKey) => state\"},\"vaultAddress()\":{\"notice\":\"Address of the OToken vault\"},\"withdraw(address,address,uint256)\":{\"notice\":\"Withdraw WETH from this contract. Used only if some WETH for is lingering on the contract. That can happen when: - the deposit was not a multiple of 32 WETH - someone sent WETH directly to this contract Will NOT revert if the strategy is paused from an accounting failure.\"},\"withdrawAll()\":{\"notice\":\"transfer all WETH deposits back to the vault. This does not withdraw from the validators. That has to be done separately with the `exitSsvValidator` and `removeSsvValidator` operations. This does not withdraw any execution rewards from the FeeAccumulator or consensus rewards in this strategy. Any ETH in this strategy that was swept from a full validator withdrawal will not be withdrawn. ETH from full validator withdrawals is sent to the Vault using `doAccounting`. Will NOT revert if the strategy is paused from an accounting failure.\"}},\"notice\":\"Strategy to deploy funds into DVT validators powered by the SSV Network\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol\":\"NativeStakingSSVStrategy\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"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\",\"keccak256\":\"0xe68ed7fb8766ed1e888291f881e36b616037f852b37d96877045319ad298ba87\",\"license\":\"MIT\"},\"@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/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\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"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/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\",\"keccak256\":\"0x598f90bdbc854250bbd5991426bfb43367207e64e33109c41aa8b54323fd8d8e\",\"license\":\"MIT\"},\"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 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 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 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\",\"keccak256\":\"0xbef02bd5257e61dec0a6be4b1531064a7fdfeb4043885443a1902fb5d1b23e1b\",\"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/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/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\",\"keccak256\":\"0x05b7dce6c24d3cd4e48b5c6346d86e5e40ecc3291bcdf3f3ef091c98fc826519\",\"license\":\"MIT\"},\"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\\nimport { Governable } from \\\"../../governance/Governable.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 is Governable {\\n /// @notice The address of the Native Staking Strategy\\n address public immutable STRATEGY;\\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 }\\n\\n /**\\n * @dev Accept ETH\\n */\\n receive() external payable {}\\n}\\n\",\"keccak256\":\"0xb8fda3b87dc5d6f8aee4bf1d015a585211e5b5a319dfa4b0f4770e3f5a2d5939\",\"license\":\"MIT\"},\"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\\\";\\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\\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_ADDRESS;\\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 // For future use\\n uint256[50] 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 _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 address _feeAccumulator,\\n address _beaconChainDepositContract\\n )\\n InitializableAbstractStrategy(_baseConfig)\\n ValidatorAccountant(\\n _wethAddress,\\n _baseConfig.vaultAddress,\\n _beaconChainDepositContract,\\n _ssvNetwork\\n )\\n {\\n SSV_TOKEN_ADDRESS = _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 /// @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_TOKEN_ADDRESS).deposit{ value: ethRewards }();\\n\\n emit RewardTokenCollected(\\n harvesterAddress,\\n WETH_TOKEN_ADDRESS,\\n ethRewards\\n );\\n IERC20(WETH_TOKEN_ADDRESS).safeTransfer(\\n harvesterAddress,\\n ethRewards\\n );\\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_TOKEN_ADDRESS, \\\"Unsupported asset\\\");\\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_TOKEN_ADDRESS).balanceOf(\\n address(this)\\n );\\n if (wethBalance > 0) {\\n _deposit(WETH_TOKEN_ADDRESS, wethBalance);\\n }\\n }\\n\\n /// @notice Withdraw WETH from this contract. Used only if some WETH for is lingering on the contract. That\\n /// can happen when:\\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 _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 emit Withdrawal(_asset, address(0), _amount);\\n IERC20(_asset).safeTransfer(_recipient, _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_TOKEN_ADDRESS).balanceOf(\\n address(this)\\n );\\n if (wethBalance > 0) {\\n _withdraw(vaultAddress, WETH_TOKEN_ADDRESS, wethBalance);\\n }\\n }\\n\\n function _abstractSetPToken(address _asset, address) internal override {}\\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_TOKEN_ADDRESS, \\\"Unsupported asset\\\");\\n\\n balance =\\n // add the ETH that has been staked in validators\\n activeDepositedValidators *\\n 32 ether +\\n // add the WETH in the strategy from deposits that are still to be staked\\n IERC20(WETH_TOKEN_ADDRESS).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_TOKEN_ADDRESS;\\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_ADDRESS).approve(\\n SSV_NETWORK_ADDRESS,\\n type(uint256).max\\n );\\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 ||\\n msg.sender == WETH_TOKEN_ADDRESS,\\n \\\"eth not from allowed contracts\\\"\\n );\\n }\\n}\\n\",\"keccak256\":\"0x9ba7e5cc1fbf9e4a8559d9872dcdf8959b4f3ef9d9a2ff8e0f74c36ec9efb4fe\",\"license\":\"MIT\"},\"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 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 MAX_STAKE = 32 ether;\\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\\n uint256[50] 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 constructor(\\n address _wethAddress,\\n address _vaultAddress,\\n address _beaconChainDepositContract,\\n address _ssvNetwork\\n )\\n ValidatorRegistrator(\\n _wethAddress,\\n _vaultAddress,\\n _beaconChainDepositContract,\\n _ssvNetwork\\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 _fuseIntervalStart < 32 ether &&\\n _fuseIntervalEnd < 32 ether &&\\n _fuseIntervalEnd - _fuseIntervalStart >= 4 ether,\\n \\\"incorrect fuse interval\\\"\\n );\\n\\n emit FuseIntervalUpdated(_fuseIntervalStart, _fuseIntervalEnd);\\n\\n fuseIntervalStart = _fuseIntervalStart;\\n fuseIntervalEnd = _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 returns (bool accountingValid)\\n {\\n // pause the accounting on failure\\n accountingValid = _doAccounting(true);\\n }\\n\\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 >= MAX_STAKE) {\\n uint256 fullyWithdrawnValidators;\\n // safe since MAX_STAKE is hardcoded to 32ETH\\n unchecked {\\n // explicitly cast to uint256 as we want to round to a whole number of validators\\n fullyWithdrawnValidators = uint256(newSweptETH / MAX_STAKE);\\n }\\n activeDepositedValidators -= fullyWithdrawnValidators;\\n\\n uint256 wethToVault = MAX_STAKE * fullyWithdrawnValidators;\\n IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: wethToVault }();\\n IWETH9(WETH_TOKEN_ADDRESS).transfer(VAULT_ADDRESS, 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 < 32 ether, \\\"unexpected accounting\\\");\\n\\n // If no Beacon chain consensus rewards swept\\n if (ethRemaining == 0) {\\n // do nothing\\n return accountingValid;\\n }\\n // Beacon chain consensus rewards swept (partial validator withdrawals)\\n else if (ethRemaining < fuseIntervalStart) {\\n // solhint-disable-next-line reentrancy\\n consensusRewards += ethRemaining;\\n emit AccountingConsensusRewards(ethRemaining);\\n }\\n // Beacon chain consensus rewards swept but also a slashed validator fully exited\\n else if (ethRemaining > fuseIntervalEnd) {\\n IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: ethRemaining }();\\n IWETH9(WETH_TOKEN_ADDRESS).transfer(VAULT_ADDRESS, ethRemaining);\\n activeDepositedValidators -= 1;\\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 /// @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 plus one, minus one or unchanged with zero\\n /// @param _wethToVaultAmount the amount of WETH to be sent to the Vault\\n /// @param _consensusRewardsDelta adjust the accounted for consensus rewards up or down\\n function manuallyFixAccounting(\\n int256 _validatorsDelta,\\n int256 _consensusRewardsDelta,\\n uint256 _wethToVaultAmount\\n ) external onlyStrategist whenPaused {\\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(_wethToVaultAmount <= 32 ether, \\\"invalid wethToVaultAmount\\\");\\n\\n emit AccountingManuallyFixed(\\n _validatorsDelta,\\n _consensusRewardsDelta,\\n _wethToVaultAmount\\n );\\n\\n activeDepositedValidators = uint256(\\n int256(activeDepositedValidators) + _validatorsDelta\\n );\\n consensusRewards = uint256(\\n int256(consensusRewards) + _consensusRewardsDelta\\n );\\n if (_wethToVaultAmount > 0) {\\n IWETH9(WETH_TOKEN_ADDRESS).transfer(\\n VAULT_ADDRESS,\\n _wethToVaultAmount\\n );\\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\",\"keccak256\":\"0xc2887e7aa41c2d7f435c7c18364c261564866a896939caa735a6dfeaeba34bbe\",\"license\":\"MIT\"},\"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 address of the Wrapped ETH (WETH) token contract\\n address public immutable WETH_TOKEN_ADDRESS;\\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_ADDRESS;\\n /// @notice Address of the OETH Vault proxy contract\\n address public immutable VAULT_ADDRESS;\\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\\n // For future use\\n uint256[50] private __gap;\\n\\n enum VALIDATOR_STATE {\\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 newAddress);\\n event ETHStaked(bytes pubkey, uint256 amount, bytes withdrawal_credentials);\\n event SSVValidatorRegistered(bytes pubkey, uint64[] operatorIds);\\n event SSVValidatorExitInitiated(bytes pubkey, uint64[] operatorIds);\\n event SSVValidatorExitCompleted(bytes pubkey, uint64[] operatorIds);\\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 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 constructor(\\n address _wethAddress,\\n address _vaultAddress,\\n address _beaconChainDepositContract,\\n address _ssvNetwork\\n ) {\\n WETH_TOKEN_ADDRESS = _wethAddress;\\n BEACON_CHAIN_DEPOSIT_CONTRACT = _beaconChainDepositContract;\\n SSV_NETWORK_ADDRESS = _ssvNetwork;\\n VAULT_ADDRESS = _vaultAddress;\\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 emit RegistratorChanged(_address);\\n validatorRegistrator = _address;\\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 function stakeEth(ValidatorStakeData[] calldata validators)\\n external\\n onlyRegistrator\\n whenNotPaused\\n {\\n uint256 requiredETH = validators.length * 32 ether;\\n\\n // Check there is enough WETH from the deposits sitting in this strategy contract\\n require(\\n requiredETH <= IWETH9(WETH_TOKEN_ADDRESS).balanceOf(address(this)),\\n \\\"insufficient WETH\\\"\\n );\\n\\n // Convert required ETH from WETH\\n IWETH9(WETH_TOKEN_ADDRESS).withdraw(requiredETH);\\n\\n uint256 validatorsLength = validators.length;\\n // For each validator\\n for (uint256 i = 0; i < validatorsLength; ) {\\n bytes32 pubkeyHash = keccak256(validators[i].pubkey);\\n VALIDATOR_STATE currentState = validatorsStates[pubkeyHash];\\n\\n require(\\n currentState == VALIDATOR_STATE.REGISTERED,\\n \\\"Validator not registered\\\"\\n );\\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 withdrawal_credentials = abi.encodePacked(\\n bytes1(0x01),\\n bytes11(0),\\n address(this)\\n );\\n IDepositContract(BEACON_CHAIN_DEPOSIT_CONTRACT).deposit{\\n value: 32 ether\\n }(\\n validators[i].pubkey,\\n withdrawal_credentials,\\n validators[i].signature,\\n validators[i].depositDataRoot\\n );\\n\\n emit ETHStaked(\\n validators[i].pubkey,\\n 32 ether,\\n withdrawal_credentials\\n );\\n\\n validatorsStates[pubkeyHash] = VALIDATOR_STATE.STAKED;\\n\\n unchecked {\\n ++i;\\n }\\n }\\n // save gas by changing this storage variable only once rather each time in the loop.\\n activeDepositedValidators += validatorsLength;\\n }\\n\\n /// @notice Registers a new validator in the SSV Cluster.\\n /// Only the registrator can call this function.\\n function registerSsvValidator(\\n bytes calldata publicKey,\\n uint64[] calldata operatorIds,\\n bytes calldata sharesData,\\n uint256 amount,\\n Cluster calldata cluster\\n ) external onlyRegistrator whenNotPaused {\\n ISSVNetwork(SSV_NETWORK_ADDRESS).registerValidator(\\n publicKey,\\n operatorIds,\\n sharesData,\\n amount,\\n cluster\\n );\\n validatorsStates[keccak256(publicKey)] = VALIDATOR_STATE.REGISTERED;\\n emit SSVValidatorRegistered(publicKey, operatorIds);\\n }\\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 function exitSsvValidator(\\n bytes calldata publicKey,\\n uint64[] calldata operatorIds\\n ) external onlyRegistrator whenNotPaused {\\n VALIDATOR_STATE currentState = validatorsStates[keccak256(publicKey)];\\n require(currentState == VALIDATOR_STATE.STAKED, \\\"Validator not staked\\\");\\n\\n ISSVNetwork(SSV_NETWORK_ADDRESS).exitValidator(publicKey, operatorIds);\\n emit SSVValidatorExitInitiated(publicKey, operatorIds);\\n\\n validatorsStates[keccak256(publicKey)] = VALIDATOR_STATE.EXITING;\\n }\\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 function removeSsvValidator(\\n bytes calldata publicKey,\\n uint64[] calldata operatorIds,\\n Cluster calldata cluster\\n ) external onlyRegistrator whenNotPaused {\\n VALIDATOR_STATE currentState = validatorsStates[keccak256(publicKey)];\\n require(\\n currentState == VALIDATOR_STATE.EXITING,\\n \\\"Validator not exiting\\\"\\n );\\n\\n ISSVNetwork(SSV_NETWORK_ADDRESS).removeValidator(\\n publicKey,\\n operatorIds,\\n cluster\\n );\\n emit SSVValidatorExitCompleted(publicKey, operatorIds);\\n\\n validatorsStates[keccak256(publicKey)] = VALIDATOR_STATE.EXIT_COMPLETE;\\n }\\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 cluster The SSV cluster details that must be derived from emitted events from the SSVNetwork contract.\\n function depositSSV(\\n uint64[] memory operatorIds,\\n uint256 amount,\\n Cluster memory cluster\\n ) external onlyStrategist {\\n ISSVNetwork(SSV_NETWORK_ADDRESS).deposit(\\n address(this),\\n operatorIds,\\n amount,\\n cluster\\n );\\n }\\n}\\n\",\"keccak256\":\"0x51ec570f03257b9c9dfb7a4204ebd66c9e7b36584da8831aace7a8b90c627394\",\"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/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\",\"keccak256\":\"0x5e17bb3db9f9e1014b7c5c836547f8fa81e02af7568c0bb8f2a2e0e7c2192db4\",\"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/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": "0x6101806040523480156200001257600080fd5b5060405162004c5738038062004c57833981016040819052620000359162000138565b8585876020015183868383838362000053336200010860201b60201c565b60008051602062004c37833981519152546040516001600160a01b03909116906000907fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a908290a36033805460ff191690556001600160601b0319606094851b811660805291841b821660a052831b811660c05290821b811660e0528651821b811661010052602090960151811b86166101205298891b851661014052505050509190931b1661016052506200021392505050565b60008051602062004c3783398151915255565b80516001600160a01b03811681146200013357600080fd5b919050565b60008060008060008086880360e08112156200015357600080fd5b60408112156200016257600080fd5b50604080519081016001600160401b03811182821017156200019457634e487b7160e01b600052604160045260246000fd5b604052620001a2886200011b565b8152620001b2602089016200011b565b60208201529550620001c7604088016200011b565b9450620001d7606088016200011b565b9350620001e7608088016200011b565b9250620001f760a088016200011b565b91506200020760c088016200011b565b90509295509295509295565b60805160601c60a05160601c60c05160601c60e05160601c6101005160601c6101205160601c6101405160601c6101605160601c61488e620003a9600039600081816102a70152818161096e0152612db101526000818161057d015261230401526000818161045101528181610d41015281816118c801528181611a410152818161266301526128eb0152600061093a0152600081816106ec01528181610b09015281816117f601528181611a9101528181611d740152818161330801526135590152600081816109b701528181610bdf015281816116c8015281816122d4015281816123ec01526127e10152600081816108a6015261140a0152600081816102d9015281816104db015281816107bd01528181610a7001528181610db601528181610f850152818161100d015281816111bc01528181611297015281816119b201528181611a6201528181611da30152818161297601528181612a0501528181612eb601528181612f3b01528181612faf0152818161328201528181613337015281816134d30152613588015261488e6000f3fe6080604052600436106102975760003560e01c8063853828b61161015a578063c2e1e3f4116100c1578063d9f00ec71161007a578063d9f00ec714610908578063dbe55e5614610928578063dd505df61461095c578063de5f626814610990578063f1188e40146109a5578063f6ca71b0146109d957600080fd5b8063c2e1e3f414610842578063c7af335214610862578063c98517c514610877578063cceab75014610894578063d38bfff4146108c8578063d9caed12146108e857600080fd5b80639da0e462116101135780639da0e4621461074e578063a4f98af41461078b578063aa388af6146107a0578063ab12edf5146107ed578063ad1728cb1461080d578063bb1b918d1461082257600080fd5b8063853828b61461068057806387bae867146106955780638d7c0e46146106ba5780639092c31c146106da5780639136616a1461070e57806396d538bb1461072e57600080fd5b80635c975abb116101fe5780636e811d38116101b75780636e811d38146105d55780636ef38795146105f557806371a735f3146106155780637b2d9b2c14610635578063842f5c46146106555780638456cb591461066b57600080fd5b80635c975abb146105125780635d36b190146105365780635f5152261461054b5780636093d3801461056b57806366e3667e1461059f57806367c7066c146105b557600080fd5b8063430bf08a11610250578063430bf08a1461043f578063435356d11461047357806347e7ef2414610493578063484be812146104b3578063579a7e1a146104c95780635a063f63146104fd57600080fd5b80630c340a24146103535780630ed57b3a146103855780630fc3b4c4146103a55780631072cbea146103db57806322495dc8146103fb5780633c8649591461041b57600080fd5b3661034e57336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614806102fb5750336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016145b61034c5760405162461bcd60e51b815260206004820152601e60248201527f657468206e6f742066726f6d20616c6c6f77656420636f6e747261637473000060448201526064015b60405180910390fd5b005b600080fd5b34801561035f57600080fd5b506103686109fb565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561039157600080fd5b5061034c6103a0366004613c31565b610a18565b3480156103b157600080fd5b506103686103c0366004613bf7565b609f602052600090815260409020546001600160a01b031681565b3480156103e757600080fd5b5061034c6103f6366004613cab565b610a4a565b34801561040757600080fd5b5061034c610416366004613d9f565b610b07565b34801561042757600080fd5b5061043160695481565b60405190815260200161037c565b34801561044b57600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b34801561047f57600080fd5b5061034c61048e366004613d18565b610c51565b34801561049f57600080fd5b5061034c6104ae366004613cab565b610d36565b3480156104bf57600080fd5b50610431606a5481565b3480156104d557600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b34801561050957600080fd5b5061034c610e3c565b34801561051e57600080fd5b5060335460ff165b604051901515815260200161037c565b34801561054257600080fd5b5061034c610edb565b34801561055757600080fd5b50610431610566366004613bf7565b610f81565b34801561057757600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b3480156105ab57600080fd5b5061043160345481565b3480156105c157600080fd5b5060a354610368906001600160a01b031681565b3480156105e157600080fd5b5061034c6105f0366004613bf7565b6110b5565b34801561060157600080fd5b5061034c610610366004613cd7565b61113d565b34801561062157600080fd5b5061034c610630366004613fad565b6115d1565b34801561064157600080fd5b50610368610650366004613e75565b6117ca565b34801561066157600080fd5b5061043160685481565b34801561067757600080fd5b5061034c6117f4565b34801561068c57600080fd5b5061034c6118bd565b3480156106a157600080fd5b506033546103689061010090046001600160a01b031681565b3480156106c657600080fd5b5061034c6106d536600461402e565b611a8f565b3480156106e657600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b34801561071a57600080fd5b5061034c610729366004613e75565b611e77565b34801561073a57600080fd5b5061034c610749366004613cd7565b612042565b34801561075a57600080fd5b5061077e610769366004613e75565b60356020526000908152604090205460ff1681565b60405161037c9190614499565b34801561079757600080fd5b50610526612162565b3480156107ac57600080fd5b506105266107bb366004613bf7565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0390811691161490565b3480156107f957600080fd5b5061034c610808366004614073565b6121c1565b34801561081957600080fd5b5061034c6122bd565b34801561082e57600080fd5b5061034c61083d366004613ef9565b612383565b34801561084e57600080fd5b5061034c61085d366004613bf7565b6124f6565b34801561086e57600080fd5b50610526612583565b34801561088357600080fd5b506104316801bc16d674ec80000081565b3480156108a057600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b3480156108d457600080fd5b5061034c6108e3366004613bf7565b6125b4565b3480156108f457600080fd5b5061034c610903366004613c6a565b612658565b34801561091457600080fd5b5061034c610923366004613e8e565b6126eb565b34801561093457600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b34801561096857600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b34801561099c57600080fd5b5061034c6128e0565b3480156109b157600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b3480156109e557600080fd5b506109ee612a2a565b60405161037c919061426f565b6000610a136000805160206148398339815191525490565b905090565b610a20612583565b610a3c5760405162461bcd60e51b81526004016103439061450b565b610a468282612a8c565b5050565b610a52612583565b610a6e5760405162461bcd60e51b81526004016103439061450b565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b039081169083161415610aeb5760405162461bcd60e51b815260206004820152601f60248201527f43616e6e6f74207472616e7366657220737570706f72746564206173736574006044820152606401610343565b610a46610af66109fb565b6001600160a01b0384169083612beb565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b158015610b6057600080fd5b505afa158015610b74573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b989190613c14565b6001600160a01b0316336001600160a01b031614610bc85760405162461bcd60e51b8152600401610343906145cb565b60405163bc26e7e560e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063bc26e7e590610c1a9030908790879087906004016141bf565b600060405180830381600087803b158015610c3457600080fd5b505af1158015610c48573d6000803e3d6000fd5b50505050505050565b610c59612583565b610c755760405162461bcd60e51b81526004016103439061450b565b600054610100900460ff1680610c8e575060005460ff16155b610cf15760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610343565b600054610100900460ff16158015610d13576000805461ffff19166101011790555b610d1e848484612c3d565b8015610d30576000805461ff00191690555b50505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610d7e5760405162461bcd60e51b8152600401610343906144d4565b60008051602061481983398151915280546002811415610db05760405162461bcd60e51b8152600401610343906145a3565b600282557f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316846001600160a01b031614610e295760405162461bcd60e51b8152602060048201526011602482015270155b9cdd5c1c1bdc9d195908185cdcd95d607a1b6044820152606401610343565b610e338484612cf8565b50600190555050565b60a3546001600160a01b03163314610e965760405162461bcd60e51b815260206004820152601b60248201527f43616c6c6572206973206e6f74207468652048617276657374657200000000006044820152606401610343565b60008051602061481983398151915280546002811415610ec85760405162461bcd60e51b8152600401610343906145a3565b60028255610ed4612d8a565b5060019055565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b031614610f765760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b6064820152608401610343565b610f7f33612fd8565b565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b031614610ff85760405162461bcd60e51b8152602060048201526011602482015270155b9cdd5c1c1bdc9d195908185cdcd95d607a1b6044820152606401610343565b6040516370a0823160e01b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b15801561105757600080fd5b505afa15801561106b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061108f919061405a565b6034546110a5906801bc16d674ec80000061470a565b6110af91906146f2565b92915050565b6110bd612583565b6110d95760405162461bcd60e51b81526004016103439061450b565b6040516001600160a01b03821681527f83f29c79feb71f8fba9d0fbc4ba5f0982a28b6b1e868b3fc50e6400d100bca0f9060200160405180910390a1603380546001600160a01b0390921661010002610100600160a81b0319909216919091179055565b60335461010090046001600160a01b0316331461116c5760405162461bcd60e51b81526004016103439061456c565b60335460ff161561118f5760405162461bcd60e51b815260040161034390614542565b60006111a4826801bc16d674ec80000061470a565b6040516370a0823160e01b81523060048201529091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b15801561120657600080fd5b505afa15801561121a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061123e919061405a565b8111156112815760405162461bcd60e51b81526020600482015260116024820152700d2dce6eaccccd2c6d2cadce840ae8aa89607b1b6044820152606401610343565b604051632e1a7d4d60e01b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b1580156112e357600080fd5b505af11580156112f7573d6000803e3d6000fd5b5084925060009150505b818110156115b357600085858381811061131d5761131d6147c9565b905060200281019061132f9190614648565b6113399080614602565b604051611347929190614193565b6040805191829003909120600081815260356020529182205490925060ff16908160038111156113795761137961479d565b146113c65760405162461bcd60e51b815260206004820152601860248201527f56616c696461746f72206e6f74207265676973746572656400000000000000006044820152606401610343565b60408051600160f81b60208201526000602182018190526bffffffffffffffffffffffff193060601b16602c830152910160405160208183030381529060405290507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663228951186801bc16d674ec8000008a8a88818110611453576114536147c9565b90506020028101906114659190614648565b61146f9080614602565b858d8d8b818110611482576114826147c9565b90506020028101906114949190614648565b6114a2906020810190614602565b8f8f8d8181106114b4576114b46147c9565b90506020028101906114c69190614648565b604001356040518863ffffffff1660e01b81526004016114eb9695949392919061441e565b6000604051808303818588803b15801561150457600080fd5b505af1158015611518573d6000803e3d6000fd5b50505050507ffeb31a79d38edb1b090d516e4df3e273651179c6f2c2ec53a9a22ae015b70ba9888886818110611550576115506147c9565b90506020028101906115629190614648565b61156c9080614602565b6801bc16d674ec80000084604051611587949392919061446d565b60405180910390a150506000908152603560205260409020805460ff1916600190811790915501611301565b5080603460008282546115c691906146f2565b909155505050505050565b60335461010090046001600160a01b031633146116005760405162461bcd60e51b81526004016103439061456c565b60335460ff16156116235760405162461bcd60e51b815260040161034390614542565b6000603560008787604051611639929190614193565b604080519182900390912082526020820192909252016000205460ff169050600281600381111561166c5761166c61479d565b146116b15760405162461bcd60e51b815260206004820152601560248201527456616c696461746f72206e6f742065786974696e6760581b6044820152606401610343565b6040516312b3fc1960e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906312b3fc199061170590899089908990899089906004016143dd565b600060405180830381600087803b15801561171f57600080fd5b505af1158015611733573d6000803e3d6000fd5b505050507ff72821b8777f002ccdf6326f1242d9e0f762eb077668b67bebe640535378066d8686868660405161176c9493929190614354565b60405180910390a1600360356000888860405161178a929190614193565b60408051918290039091208252602082019290925201600020805460ff191660018360038111156117bd576117bd61479d565b0217905550505050505050565b60a481815481106117da57600080fd5b6000918252602090912001546001600160a01b0316905081565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b15801561184d57600080fd5b505afa158015611861573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118859190613c14565b6001600160a01b0316336001600160a01b0316146118b55760405162461bcd60e51b8152600401610343906145cb565b610f7f613099565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016148061190c57506118f76109fb565b6001600160a01b0316336001600160a01b0316145b6119645760405162461bcd60e51b815260206004820152602360248201527f43616c6c6572206973206e6f7420746865205661756c74206f7220476f7665726044820152623737b960e91b6064820152608401610343565b600080516020614819833981519152805460028114156119965760405162461bcd60e51b8152600401610343906145a3565b600282556040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b1580156119fc57600080fd5b505afa158015611a10573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a34919061405a565b90508015611a8757611a877f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000008361310e565b505060019055565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b158015611ae857600080fd5b505afa158015611afc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b209190613c14565b6001600160a01b0316336001600160a01b031614611b505760405162461bcd60e51b8152600401610343906145cb565b60335460ff16611b995760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610343565b6002198312158015611bac575060038313155b8015611bc65750600083603454611bc391906146b1565b12155b611c125760405162461bcd60e51b815260206004820152601760248201527f696e76616c69642076616c696461746f727344656c74610000000000000000006044820152606401610343565b6811ff6cf0fd15afffff198212158015611c3557506811ff6cf0fd15b000008213155b8015611c4f5750600082606854611c4c91906146b1565b12155b611c9b5760405162461bcd60e51b815260206004820152601d60248201527f696e76616c696420636f6e73656e7375735265776172647344656c74610000006044820152606401610343565b6801bc16d674ec800000811115611cf45760405162461bcd60e51b815260206004820152601960248201527f696e76616c69642077657468546f5661756c74416d6f756e74000000000000006044820152606401610343565b60408051848152602081018490529081018290527f80d022717ea022455c5886b8dd8a29c037570aae58aeb4d7b136d7a10ec2e4319060600160405180910390a182603454611d4391906146b1565b603455606854611d549083906146b1565b6068558015611e215760405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018390527f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb90604401602060405180830381600087803b158015611de757600080fd5b505af1158015611dfb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e1f9190613e58565b505b611e2b6000613206565b611e6a5760405162461bcd60e51b815260206004820152601060248201526f333ab9b29039ba34b63610313637bbb760811b6044820152606401610343565b611e72613672565b505050565b611e7f612583565b611e9b5760405162461bcd60e51b81526004016103439061450b565b60a0548110611edc5760405162461bcd60e51b815260206004820152600d60248201526c092dcecc2d8d2c840d2dcc8caf609b1b6044820152606401610343565b600060a08281548110611ef157611ef16147c9565b60009182526020808320909101546001600160a01b03908116808452609f90925260409092205460a05491935090911690611f2e90600190614729565b831015611fb05760a08054611f4590600190614729565b81548110611f5557611f556147c9565b60009182526020909120015460a080546001600160a01b039092169185908110611f8157611f816147c9565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505b60a0805480611fc157611fc16147b3565b60008281526020808220600019908401810180546001600160a01b031990811690915593019093556001600160a01b03858116808352609f855260409283902080549094169093559051908416815290917f16b7600acff27e39a8a96056b3d533045298de927507f5c1d97e4accde60488c910160405180910390a2505050565b61204a612583565b6120665760405162461bcd60e51b81526004016103439061450b565b8060005b81811015612119576000848483818110612086576120866147c9565b905060200201602081019061209b9190613bf7565b6001600160a01b031614156121095760405162461bcd60e51b815260206004820152602e60248201527f43616e206e6f742073657420616e20656d70747920616464726573732061732060448201526d30903932bbb0b932103a37b5b2b760911b6064820152608401610343565b6121128161476c565b905061206a565b507f04c0b9649497d316554306e53678d5f5f5dbc3a06f97dec13ff4cfe98b986bbc60a4848460405161214e939291906142bc565b60405180910390a1610d3060a48484613950565b60335460009061010090046001600160a01b031633146121945760405162461bcd60e51b81526004016103439061456c565b60335460ff16156121b75760405162461bcd60e51b815260040161034390614542565b610a136001613206565b6121c9612583565b6121e55760405162461bcd60e51b81526004016103439061450b565b80821080156121fc57506801bc16d674ec80000082105b801561221057506801bc16d674ec80000081105b801561222d5750673782dace9d90000061222a8383614729565b10155b6122795760405162461bcd60e51b815260206004820152601760248201527f696e636f7272656374206675736520696e74657276616c0000000000000000006044820152606401610343565b60408051838152602081018390527fcb8d24e46eb3c402bf344ee60a6576cba9ef2f59ea1af3b311520704924e901a910160405180910390a1606991909155606a55565b60405163095ea7b360e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015260001960248301527f0000000000000000000000000000000000000000000000000000000000000000169063095ea7b390604401602060405180830381600087803b15801561234857600080fd5b505af115801561235c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123809190613e58565b50565b60335461010090046001600160a01b031633146123b25760405162461bcd60e51b81526004016103439061456c565b60335460ff16156123d55760405162461bcd60e51b815260040161034390614542565b6040516301ba3ee760e21b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906306e8fb9c9061242f908b908b908b908b908b908b908b908b9060040161437b565b600060405180830381600087803b15801561244957600080fd5b505af115801561245d573d6000803e3d6000fd5b505050506000603560008a8a604051612477929190614193565b60408051918290039091208252602082019290925201600020805460ff191660018360038111156124aa576124aa61479d565b02179055507f75c4a66b2c6c28cf46db7131182a812e4fbbb2f0591377aa83a737909a9b68c3888888886040516124e49493929190614354565b60405180910390a15050505050505050565b6124fe612583565b61251a5760405162461bcd60e51b81526004016103439061450b565b60a354604080516001600160a01b03928316815291831660208301527fe48386b84419f4d36e0f96c10cc3510b6fb1a33795620c5098b22472bbe90796910160405180910390a160a380546001600160a01b0319166001600160a01b0392909216919091179055565b600061259b6000805160206148398339815191525490565b6001600160a01b0316336001600160a01b031614905090565b6125bc612583565b6125d85760405162461bcd60e51b81526004016103439061450b565b612600817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b03166126206000805160206148398339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146126a05760405162461bcd60e51b8152600401610343906144d4565b600080516020614819833981519152805460028114156126d25760405162461bcd60e51b8152600401610343906145a3565b600282556126e185858561310e565b5060019055505050565b60335461010090046001600160a01b0316331461271a5760405162461bcd60e51b81526004016103439061456c565b60335460ff161561273d5760405162461bcd60e51b815260040161034390614542565b6000603560008686604051612753929190614193565b604080519182900390912082526020820192909252016000205460ff16905060018160038111156127865761278661479d565b146127ca5760405162461bcd60e51b815260206004820152601460248201527315985b1a59185d1bdc881b9bdd081cdd185ad95960621b6044820152606401610343565b604051633877322b60e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690633877322b9061281c908890889088908890600401614354565b600060405180830381600087803b15801561283657600080fd5b505af115801561284a573d6000803e3d6000fd5b505050507ff8821da16f5ed966b41e0343c3eff9903af782d74f99f1689dd9d4562b6545b3858585856040516128839493929190614354565b60405180910390a160026035600087876040516128a1929190614193565b60408051918290039091208252602082019290925201600020805460ff191660018360038111156128d4576128d461479d565b02179055505050505050565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146129285760405162461bcd60e51b8152600401610343906144d4565b6000805160206148198339815191528054600281141561295a5760405162461bcd60e51b8152600401610343906145a3565b600282556040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b1580156129c057600080fd5b505afa1580156129d4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129f8919061405a565b90508015611a8757611a877f000000000000000000000000000000000000000000000000000000000000000082612cf8565b606060a4805480602002602001604051908101604052809291908181526020018280548015612a8257602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612a64575b5050505050905090565b6001600160a01b038281166000908152609f60205260409020541615612ae95760405162461bcd60e51b81526020600482015260126024820152711c151bdad95b88185b1c9958591e481cd95d60721b6044820152606401610343565b6001600160a01b03821615801590612b0957506001600160a01b03811615155b612b495760405162461bcd60e51b8152602060048201526011602482015270496e76616c69642061646472657373657360781b6044820152606401610343565b6001600160a01b038281166000818152609f6020908152604080832080549587166001600160a01b0319968716811790915560a0805460018101825594527f78fdc8d422c49ced035a9edf18d00d3c6a8d81df210f3e5e448e045e77b41e8890930180549095168417909455925190815290917fef6485b84315f9b1483beffa32aae9a0596890395e3d7521f1c5fbb51790e765910160405180910390a25050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052611e729084906136ec565b8251612c509060a49060208601906139b3565b50815181518114612c9a5760405162461bcd60e51b8152602060048201526014602482015273496e76616c696420696e7075742061727261797360601b6044820152606401610343565b60005b81811015612cf157612ce1848281518110612cba57612cba6147c9565b6020026020010151848381518110612cd457612cd46147c9565b6020026020010151612a8c565b612cea8161476c565b9050612c9d565b5050505050565b60008111612d415760405162461bcd60e51b81526020600482015260166024820152754d757374206465706f73697420736f6d657468696e6760501b6044820152606401610343565b6040805160008152602081018390526001600160a01b038416917f5548c837ab068cf56a2c2479df0882a4922fd203edb7517321831d95078c5f62910160405180910390a25050565b60335460ff1615612dad5760405162461bcd60e51b815260040161034390614542565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663e52253816040518163ffffffff1660e01b8152600401602060405180830381600087803b158015612e0a57600080fd5b505af1158015612e1e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e42919061405a565b9050600060685482612e5491906146f2565b905080471015612ea65760405162461bcd60e51b815260206004820152601860248201527f696e73756666696369656e74206574682062616c616e636500000000000000006044820152606401610343565b8015610a465760006068819055507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b158015612f0f57600080fd5b505af1158015612f23573d6000803e3d6000fd5b505060a354604080516001600160a01b0392831681527f0000000000000000000000000000000000000000000000000000000000000000909216602083015281018590527ff6c07a063ed4e63808eb8da7112d46dbcd38de2b40a73dbcc9353c5a94c7235393506060019150612f969050565b60405180910390a160a354610a46906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116911683612beb565b6001600160a01b03811661302e5760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f7220697320616464726573732830290000000000006044820152606401610343565b806001600160a01b031661304e6000805160206148398339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a36123808160008051602061483983398151915255565b60335460ff16156130bc5760405162461bcd60e51b815260040161034390614542565b6033805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586130f13390565b6040516001600160a01b03909116815260200160405180910390a1565b6000811161315e5760405162461bcd60e51b815260206004820152601760248201527f4d75737420776974686472617720736f6d657468696e670000000000000000006044820152606401610343565b6001600160a01b0383166131ad5760405162461bcd60e51b8152602060048201526016602482015275135d5cdd081cdc1958da599e481c9958da5c1a595b9d60521b6044820152606401610343565b6040805160008152602081018390526001600160a01b038416917f2717ead6b9200dd235aad468c9809ea400fe33ac69b5bfaa6d3e90fc922b6398910160405180910390a2611e726001600160a01b0383168483612beb565b600060685447101561321b576110af826137be565b60006068544761322b9190614729565b9050600191506801bc16d674ec80000081106133ff5760006801bc16d674ec8000008204905080603460008282546132639190614729565b909155506000905061327e826801bc16d674ec80000061470a565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b1580156132db57600080fd5b505af11580156132ef573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb92506044019050602060405180830381600087803b15801561337f57600080fd5b505af1158015613393573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133b79190613e58565b5060345460408051848152602081019290925281018290527fbe7040030ff7b347853214bf49820c6d455fedf58f3815f85c7bc5216993682b9060600160405180910390a150505b60006068544761340f9190614729565b90506801bc16d674ec80000081106134615760405162461bcd60e51b8152602060048201526015602482015274756e6578706563746564206163636f756e74696e6760581b6044820152606401610343565b8061346d575050919050565b6069548110156134c757806068600082825461348991906146f2565b90915550506040518181527f7a745a2c63a535068f52ceca27debd5297bbad5f7f37ec53d044a59d0362445d906020015b60405180910390a161366b565b606a5481111561365a577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b15801561352c57600080fd5b505af1158015613540573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb92506044019050602060405180830381600087803b1580156135d057600080fd5b505af11580156135e4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136089190613e58565b5060016034600082825461361c9190614729565b909155505060345460408051918252602082018390527f6aa7e30787b26429ced603a7aba8b19c4b5d5bcf29a3257da953c8d53bcaa3a691016134ba565b613663846137be565b949350505050565b5050919050565b60335460ff166136bb5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610343565b6033805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa336130f1565b6000613741826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166137d69092919063ffffffff16565b805190915015611e72578080602001905181019061375f9190613e58565b611e725760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610343565b600081156137ce576137ce613099565b506000919050565b60606137e584846000856137ef565b90505b9392505050565b6060824710156138505760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610343565b843b61389e5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610343565b600080866001600160a01b031685876040516138ba91906141a3565b60006040518083038185875af1925050503d80600081146138f7576040519150601f19603f3d011682016040523d82523d6000602084013e6138fc565b606091505b509150915061390c828286613917565b979650505050505050565b606083156139265750816137e8565b8251156139365782518084602001fd5b8160405162461bcd60e51b815260040161034391906144c1565b8280548282559060005260206000209081019282156139a3579160200282015b828111156139a35781546001600160a01b0319166001600160a01b03843516178255602090920191600190910190613970565b506139af929150613a08565b5090565b8280548282559060005260206000209081019282156139a3579160200282015b828111156139a357825182546001600160a01b0319166001600160a01b039091161782556020909201916001909101906139d3565b5b808211156139af5760008155600101613a09565b60008083601f840112613a2f57600080fd5b5081356001600160401b03811115613a4657600080fd5b6020830191508360208260051b8501011115613a6157600080fd5b9250929050565b600082601f830112613a7957600080fd5b81356020613a8e613a898361468e565b61465e565b80838252828201915082860187848660051b8901011115613aae57600080fd5b60005b85811015613ad6578135613ac4816147f5565b84529284019290840190600101613ab1565b5090979650505050505050565b60008083601f840112613af557600080fd5b5081356001600160401b03811115613b0c57600080fd5b602083019150836020828501011115613a6157600080fd5b600060a08284031215613b3657600080fd5b50919050565b600060a08284031215613b4e57600080fd5b60405160a081018181106001600160401b0382111715613b7057613b706147df565b604052905080613b7f83613bc7565b8152613b8d60208401613be0565b6020820152613b9e60408401613be0565b60408201526060830135613bb18161480a565b6060820152608092830135920191909152919050565b803563ffffffff81168114613bdb57600080fd5b919050565b80356001600160401b0381168114613bdb57600080fd5b600060208284031215613c0957600080fd5b81356137e8816147f5565b600060208284031215613c2657600080fd5b81516137e8816147f5565b60008060408385031215613c4457600080fd5b8235613c4f816147f5565b91506020830135613c5f816147f5565b809150509250929050565b600080600060608486031215613c7f57600080fd5b8335613c8a816147f5565b92506020840135613c9a816147f5565b929592945050506040919091013590565b60008060408385031215613cbe57600080fd5b8235613cc9816147f5565b946020939093013593505050565b60008060208385031215613cea57600080fd5b82356001600160401b03811115613d0057600080fd5b613d0c85828601613a1d565b90969095509350505050565b600080600060608486031215613d2d57600080fd5b83356001600160401b0380821115613d4457600080fd5b613d5087838801613a68565b94506020860135915080821115613d6657600080fd5b613d7287838801613a68565b93506040860135915080821115613d8857600080fd5b50613d9586828701613a68565b9150509250925092565b600080600060e08486031215613db457600080fd5b83356001600160401b03811115613dca57600080fd5b8401601f81018613613ddb57600080fd5b80356020613deb613a898361468e565b8083825282820191508285018a848660051b8801011115613e0b57600080fd5b600095505b84861015613e3557613e2181613be0565b835260019590950194918301918301613e10565b509650508601359350613e4f915086905060408601613b3c565b90509250925092565b600060208284031215613e6a57600080fd5b81516137e88161480a565b600060208284031215613e8757600080fd5b5035919050565b60008060008060408587031215613ea457600080fd5b84356001600160401b0380821115613ebb57600080fd5b613ec788838901613ae3565b90965094506020870135915080821115613ee057600080fd5b50613eed87828801613a1d565b95989497509550505050565b600080600080600080600080610120898b031215613f1657600080fd5b88356001600160401b0380821115613f2d57600080fd5b613f398c838d01613ae3565b909a50985060208b0135915080821115613f5257600080fd5b613f5e8c838d01613a1d565b909850965060408b0135915080821115613f7757600080fd5b50613f848b828c01613ae3565b90955093505060608901359150613f9e8a60808b01613b24565b90509295985092959890939650565b600080600080600060e08688031215613fc557600080fd5b85356001600160401b0380821115613fdc57600080fd5b613fe889838a01613ae3565b9097509550602088013591508082111561400157600080fd5b5061400e88828901613a1d565b909450925061402290508760408801613b24565b90509295509295909350565b60008060006060848603121561404357600080fd5b505081359360208301359350604090920135919050565b60006020828403121561406c57600080fd5b5051919050565b6000806040838503121561408657600080fd5b50508035926020909101359150565b8183526000602080850194508260005b858110156140d1576001600160401b036140be83613be0565b16875295820195908201906001016140a5565b509495945050505050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6000815180845261411d816020860160208601614740565b601f01601f19169290920160200192915050565b63ffffffff61413f82613bc7565b16825261414e60208201613be0565b6001600160401b0380821660208501528061416b60408501613be0565b166040850152505060608101356141818161480a565b15156060830152608090810135910152565b8183823760009101908152919050565b600082516141b5818460208701614740565b9190910192915050565b6001600160a01b03851681526101006020808301829052855191830182905260009161012084019187810191845b818110156142125783516001600160401b0316855293820193928201926001016141ed565b505082935086604086015263ffffffff865116606086015280860151925050506001600160401b0380821660808501528060408601511660a085015250506060830151151560c0830152608083015160e083015295945050505050565b6020808252825182820181905260009190848201906040850190845b818110156142b05783516001600160a01b03168352928401929184019160010161428b565b50909695505050505050565b6000604082016040835280865480835260608501915087600052602092508260002060005b828110156143065781546001600160a01b0316845292840192600191820191016142e1565b505050838103828501528481528590820160005b8681101561434857823561432d816147f5565b6001600160a01b03168252918301919083019060010161431a565b50979650505050505050565b6040815260006143686040830186886140dc565b828103602084015261390c818587614095565b60006101208083526143908184018b8d6140dc565b905082810360208401526143a581898b614095565b905082810360408401526143ba8187896140dc565b9150508360608301526143d06080830184614131565b9998505050505050505050565b60e0815260006143f160e0830187896140dc565b8281036020840152614404818688614095565b9150506144146040830184614131565b9695505050505050565b60808152600061443260808301888a6140dc565b82810360208401526144448188614105565b905082810360408401526144598186886140dc565b915050826060830152979650505050505050565b6060815260006144816060830186886140dc565b846020840152828103604084015261390c8185614105565b60208101600483106144bb57634e487b7160e01b600052602160045260246000fd5b91905290565b6020815260006137e86020830184614105565b60208082526017908201527f43616c6c6572206973206e6f7420746865205661756c74000000000000000000604082015260600190565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b60208082526010908201526f14185d5cd8589b194e881c185d5cd95960821b604082015260600190565b6020808252601d908201527f43616c6c6572206973206e6f7420746865205265676973747261746f72000000604082015260600190565b6020808252600e908201526d1499595b9d1c985b9d0818d85b1b60921b604082015260600190565b6020808252601c908201527f43616c6c6572206973206e6f7420746865205374726174656769737400000000604082015260600190565b6000808335601e1984360301811261461957600080fd5b8301803591506001600160401b0382111561463357600080fd5b602001915036819003821315613a6157600080fd5b60008235605e198336030181126141b557600080fd5b604051601f8201601f191681016001600160401b0381118282101715614686576146866147df565b604052919050565b60006001600160401b038211156146a7576146a76147df565b5060051b60200190565b600080821280156001600160ff1b03849003851316156146d3576146d3614787565b600160ff1b83900384128116156146ec576146ec614787565b50500190565b6000821982111561470557614705614787565b500190565b600081600019048311821515161561472457614724614787565b500290565b60008282101561473b5761473b614787565b500390565b60005b8381101561475b578181015183820152602001614743565b83811115610d305750506000910152565b600060001982141561478057614780614787565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b038116811461238057600080fd5b801515811461238057600080fdfe53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac45357bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa2646970667358221220cb53a48aebce08cd91f08713d34b94e51baee827b032c246ff83f59c6d6e39d364736f6c634300080700337bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a", - "deployedBytecode": "0x6080604052600436106102975760003560e01c8063853828b61161015a578063c2e1e3f4116100c1578063d9f00ec71161007a578063d9f00ec714610908578063dbe55e5614610928578063dd505df61461095c578063de5f626814610990578063f1188e40146109a5578063f6ca71b0146109d957600080fd5b8063c2e1e3f414610842578063c7af335214610862578063c98517c514610877578063cceab75014610894578063d38bfff4146108c8578063d9caed12146108e857600080fd5b80639da0e462116101135780639da0e4621461074e578063a4f98af41461078b578063aa388af6146107a0578063ab12edf5146107ed578063ad1728cb1461080d578063bb1b918d1461082257600080fd5b8063853828b61461068057806387bae867146106955780638d7c0e46146106ba5780639092c31c146106da5780639136616a1461070e57806396d538bb1461072e57600080fd5b80635c975abb116101fe5780636e811d38116101b75780636e811d38146105d55780636ef38795146105f557806371a735f3146106155780637b2d9b2c14610635578063842f5c46146106555780638456cb591461066b57600080fd5b80635c975abb146105125780635d36b190146105365780635f5152261461054b5780636093d3801461056b57806366e3667e1461059f57806367c7066c146105b557600080fd5b8063430bf08a11610250578063430bf08a1461043f578063435356d11461047357806347e7ef2414610493578063484be812146104b3578063579a7e1a146104c95780635a063f63146104fd57600080fd5b80630c340a24146103535780630ed57b3a146103855780630fc3b4c4146103a55780631072cbea146103db57806322495dc8146103fb5780633c8649591461041b57600080fd5b3661034e57336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614806102fb5750336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016145b61034c5760405162461bcd60e51b815260206004820152601e60248201527f657468206e6f742066726f6d20616c6c6f77656420636f6e747261637473000060448201526064015b60405180910390fd5b005b600080fd5b34801561035f57600080fd5b506103686109fb565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561039157600080fd5b5061034c6103a0366004613c31565b610a18565b3480156103b157600080fd5b506103686103c0366004613bf7565b609f602052600090815260409020546001600160a01b031681565b3480156103e757600080fd5b5061034c6103f6366004613cab565b610a4a565b34801561040757600080fd5b5061034c610416366004613d9f565b610b07565b34801561042757600080fd5b5061043160695481565b60405190815260200161037c565b34801561044b57600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b34801561047f57600080fd5b5061034c61048e366004613d18565b610c51565b34801561049f57600080fd5b5061034c6104ae366004613cab565b610d36565b3480156104bf57600080fd5b50610431606a5481565b3480156104d557600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b34801561050957600080fd5b5061034c610e3c565b34801561051e57600080fd5b5060335460ff165b604051901515815260200161037c565b34801561054257600080fd5b5061034c610edb565b34801561055757600080fd5b50610431610566366004613bf7565b610f81565b34801561057757600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b3480156105ab57600080fd5b5061043160345481565b3480156105c157600080fd5b5060a354610368906001600160a01b031681565b3480156105e157600080fd5b5061034c6105f0366004613bf7565b6110b5565b34801561060157600080fd5b5061034c610610366004613cd7565b61113d565b34801561062157600080fd5b5061034c610630366004613fad565b6115d1565b34801561064157600080fd5b50610368610650366004613e75565b6117ca565b34801561066157600080fd5b5061043160685481565b34801561067757600080fd5b5061034c6117f4565b34801561068c57600080fd5b5061034c6118bd565b3480156106a157600080fd5b506033546103689061010090046001600160a01b031681565b3480156106c657600080fd5b5061034c6106d536600461402e565b611a8f565b3480156106e657600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b34801561071a57600080fd5b5061034c610729366004613e75565b611e77565b34801561073a57600080fd5b5061034c610749366004613cd7565b612042565b34801561075a57600080fd5b5061077e610769366004613e75565b60356020526000908152604090205460ff1681565b60405161037c9190614499565b34801561079757600080fd5b50610526612162565b3480156107ac57600080fd5b506105266107bb366004613bf7565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0390811691161490565b3480156107f957600080fd5b5061034c610808366004614073565b6121c1565b34801561081957600080fd5b5061034c6122bd565b34801561082e57600080fd5b5061034c61083d366004613ef9565b612383565b34801561084e57600080fd5b5061034c61085d366004613bf7565b6124f6565b34801561086e57600080fd5b50610526612583565b34801561088357600080fd5b506104316801bc16d674ec80000081565b3480156108a057600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b3480156108d457600080fd5b5061034c6108e3366004613bf7565b6125b4565b3480156108f457600080fd5b5061034c610903366004613c6a565b612658565b34801561091457600080fd5b5061034c610923366004613e8e565b6126eb565b34801561093457600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b34801561096857600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b34801561099c57600080fd5b5061034c6128e0565b3480156109b157600080fd5b506103687f000000000000000000000000000000000000000000000000000000000000000081565b3480156109e557600080fd5b506109ee612a2a565b60405161037c919061426f565b6000610a136000805160206148398339815191525490565b905090565b610a20612583565b610a3c5760405162461bcd60e51b81526004016103439061450b565b610a468282612a8c565b5050565b610a52612583565b610a6e5760405162461bcd60e51b81526004016103439061450b565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b039081169083161415610aeb5760405162461bcd60e51b815260206004820152601f60248201527f43616e6e6f74207472616e7366657220737570706f72746564206173736574006044820152606401610343565b610a46610af66109fb565b6001600160a01b0384169083612beb565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b158015610b6057600080fd5b505afa158015610b74573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b989190613c14565b6001600160a01b0316336001600160a01b031614610bc85760405162461bcd60e51b8152600401610343906145cb565b60405163bc26e7e560e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063bc26e7e590610c1a9030908790879087906004016141bf565b600060405180830381600087803b158015610c3457600080fd5b505af1158015610c48573d6000803e3d6000fd5b50505050505050565b610c59612583565b610c755760405162461bcd60e51b81526004016103439061450b565b600054610100900460ff1680610c8e575060005460ff16155b610cf15760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610343565b600054610100900460ff16158015610d13576000805461ffff19166101011790555b610d1e848484612c3d565b8015610d30576000805461ff00191690555b50505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610d7e5760405162461bcd60e51b8152600401610343906144d4565b60008051602061481983398151915280546002811415610db05760405162461bcd60e51b8152600401610343906145a3565b600282557f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316846001600160a01b031614610e295760405162461bcd60e51b8152602060048201526011602482015270155b9cdd5c1c1bdc9d195908185cdcd95d607a1b6044820152606401610343565b610e338484612cf8565b50600190555050565b60a3546001600160a01b03163314610e965760405162461bcd60e51b815260206004820152601b60248201527f43616c6c6572206973206e6f74207468652048617276657374657200000000006044820152606401610343565b60008051602061481983398151915280546002811415610ec85760405162461bcd60e51b8152600401610343906145a3565b60028255610ed4612d8a565b5060019055565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b031614610f765760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b6064820152608401610343565b610f7f33612fd8565b565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b031614610ff85760405162461bcd60e51b8152602060048201526011602482015270155b9cdd5c1c1bdc9d195908185cdcd95d607a1b6044820152606401610343565b6040516370a0823160e01b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b15801561105757600080fd5b505afa15801561106b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061108f919061405a565b6034546110a5906801bc16d674ec80000061470a565b6110af91906146f2565b92915050565b6110bd612583565b6110d95760405162461bcd60e51b81526004016103439061450b565b6040516001600160a01b03821681527f83f29c79feb71f8fba9d0fbc4ba5f0982a28b6b1e868b3fc50e6400d100bca0f9060200160405180910390a1603380546001600160a01b0390921661010002610100600160a81b0319909216919091179055565b60335461010090046001600160a01b0316331461116c5760405162461bcd60e51b81526004016103439061456c565b60335460ff161561118f5760405162461bcd60e51b815260040161034390614542565b60006111a4826801bc16d674ec80000061470a565b6040516370a0823160e01b81523060048201529091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b15801561120657600080fd5b505afa15801561121a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061123e919061405a565b8111156112815760405162461bcd60e51b81526020600482015260116024820152700d2dce6eaccccd2c6d2cadce840ae8aa89607b1b6044820152606401610343565b604051632e1a7d4d60e01b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b1580156112e357600080fd5b505af11580156112f7573d6000803e3d6000fd5b5084925060009150505b818110156115b357600085858381811061131d5761131d6147c9565b905060200281019061132f9190614648565b6113399080614602565b604051611347929190614193565b6040805191829003909120600081815260356020529182205490925060ff16908160038111156113795761137961479d565b146113c65760405162461bcd60e51b815260206004820152601860248201527f56616c696461746f72206e6f74207265676973746572656400000000000000006044820152606401610343565b60408051600160f81b60208201526000602182018190526bffffffffffffffffffffffff193060601b16602c830152910160405160208183030381529060405290507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663228951186801bc16d674ec8000008a8a88818110611453576114536147c9565b90506020028101906114659190614648565b61146f9080614602565b858d8d8b818110611482576114826147c9565b90506020028101906114949190614648565b6114a2906020810190614602565b8f8f8d8181106114b4576114b46147c9565b90506020028101906114c69190614648565b604001356040518863ffffffff1660e01b81526004016114eb9695949392919061441e565b6000604051808303818588803b15801561150457600080fd5b505af1158015611518573d6000803e3d6000fd5b50505050507ffeb31a79d38edb1b090d516e4df3e273651179c6f2c2ec53a9a22ae015b70ba9888886818110611550576115506147c9565b90506020028101906115629190614648565b61156c9080614602565b6801bc16d674ec80000084604051611587949392919061446d565b60405180910390a150506000908152603560205260409020805460ff1916600190811790915501611301565b5080603460008282546115c691906146f2565b909155505050505050565b60335461010090046001600160a01b031633146116005760405162461bcd60e51b81526004016103439061456c565b60335460ff16156116235760405162461bcd60e51b815260040161034390614542565b6000603560008787604051611639929190614193565b604080519182900390912082526020820192909252016000205460ff169050600281600381111561166c5761166c61479d565b146116b15760405162461bcd60e51b815260206004820152601560248201527456616c696461746f72206e6f742065786974696e6760581b6044820152606401610343565b6040516312b3fc1960e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906312b3fc199061170590899089908990899089906004016143dd565b600060405180830381600087803b15801561171f57600080fd5b505af1158015611733573d6000803e3d6000fd5b505050507ff72821b8777f002ccdf6326f1242d9e0f762eb077668b67bebe640535378066d8686868660405161176c9493929190614354565b60405180910390a1600360356000888860405161178a929190614193565b60408051918290039091208252602082019290925201600020805460ff191660018360038111156117bd576117bd61479d565b0217905550505050505050565b60a481815481106117da57600080fd5b6000918252602090912001546001600160a01b0316905081565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b15801561184d57600080fd5b505afa158015611861573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118859190613c14565b6001600160a01b0316336001600160a01b0316146118b55760405162461bcd60e51b8152600401610343906145cb565b610f7f613099565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016148061190c57506118f76109fb565b6001600160a01b0316336001600160a01b0316145b6119645760405162461bcd60e51b815260206004820152602360248201527f43616c6c6572206973206e6f7420746865205661756c74206f7220476f7665726044820152623737b960e91b6064820152608401610343565b600080516020614819833981519152805460028114156119965760405162461bcd60e51b8152600401610343906145a3565b600282556040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b1580156119fc57600080fd5b505afa158015611a10573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a34919061405a565b90508015611a8757611a877f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000008361310e565b505060019055565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b158015611ae857600080fd5b505afa158015611afc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b209190613c14565b6001600160a01b0316336001600160a01b031614611b505760405162461bcd60e51b8152600401610343906145cb565b60335460ff16611b995760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610343565b6002198312158015611bac575060038313155b8015611bc65750600083603454611bc391906146b1565b12155b611c125760405162461bcd60e51b815260206004820152601760248201527f696e76616c69642076616c696461746f727344656c74610000000000000000006044820152606401610343565b6811ff6cf0fd15afffff198212158015611c3557506811ff6cf0fd15b000008213155b8015611c4f5750600082606854611c4c91906146b1565b12155b611c9b5760405162461bcd60e51b815260206004820152601d60248201527f696e76616c696420636f6e73656e7375735265776172647344656c74610000006044820152606401610343565b6801bc16d674ec800000811115611cf45760405162461bcd60e51b815260206004820152601960248201527f696e76616c69642077657468546f5661756c74416d6f756e74000000000000006044820152606401610343565b60408051848152602081018490529081018290527f80d022717ea022455c5886b8dd8a29c037570aae58aeb4d7b136d7a10ec2e4319060600160405180910390a182603454611d4391906146b1565b603455606854611d549083906146b1565b6068558015611e215760405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018390527f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb90604401602060405180830381600087803b158015611de757600080fd5b505af1158015611dfb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e1f9190613e58565b505b611e2b6000613206565b611e6a5760405162461bcd60e51b815260206004820152601060248201526f333ab9b29039ba34b63610313637bbb760811b6044820152606401610343565b611e72613672565b505050565b611e7f612583565b611e9b5760405162461bcd60e51b81526004016103439061450b565b60a0548110611edc5760405162461bcd60e51b815260206004820152600d60248201526c092dcecc2d8d2c840d2dcc8caf609b1b6044820152606401610343565b600060a08281548110611ef157611ef16147c9565b60009182526020808320909101546001600160a01b03908116808452609f90925260409092205460a05491935090911690611f2e90600190614729565b831015611fb05760a08054611f4590600190614729565b81548110611f5557611f556147c9565b60009182526020909120015460a080546001600160a01b039092169185908110611f8157611f816147c9565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505b60a0805480611fc157611fc16147b3565b60008281526020808220600019908401810180546001600160a01b031990811690915593019093556001600160a01b03858116808352609f855260409283902080549094169093559051908416815290917f16b7600acff27e39a8a96056b3d533045298de927507f5c1d97e4accde60488c910160405180910390a2505050565b61204a612583565b6120665760405162461bcd60e51b81526004016103439061450b565b8060005b81811015612119576000848483818110612086576120866147c9565b905060200201602081019061209b9190613bf7565b6001600160a01b031614156121095760405162461bcd60e51b815260206004820152602e60248201527f43616e206e6f742073657420616e20656d70747920616464726573732061732060448201526d30903932bbb0b932103a37b5b2b760911b6064820152608401610343565b6121128161476c565b905061206a565b507f04c0b9649497d316554306e53678d5f5f5dbc3a06f97dec13ff4cfe98b986bbc60a4848460405161214e939291906142bc565b60405180910390a1610d3060a48484613950565b60335460009061010090046001600160a01b031633146121945760405162461bcd60e51b81526004016103439061456c565b60335460ff16156121b75760405162461bcd60e51b815260040161034390614542565b610a136001613206565b6121c9612583565b6121e55760405162461bcd60e51b81526004016103439061450b565b80821080156121fc57506801bc16d674ec80000082105b801561221057506801bc16d674ec80000081105b801561222d5750673782dace9d90000061222a8383614729565b10155b6122795760405162461bcd60e51b815260206004820152601760248201527f696e636f7272656374206675736520696e74657276616c0000000000000000006044820152606401610343565b60408051838152602081018390527fcb8d24e46eb3c402bf344ee60a6576cba9ef2f59ea1af3b311520704924e901a910160405180910390a1606991909155606a55565b60405163095ea7b360e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015260001960248301527f0000000000000000000000000000000000000000000000000000000000000000169063095ea7b390604401602060405180830381600087803b15801561234857600080fd5b505af115801561235c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123809190613e58565b50565b60335461010090046001600160a01b031633146123b25760405162461bcd60e51b81526004016103439061456c565b60335460ff16156123d55760405162461bcd60e51b815260040161034390614542565b6040516301ba3ee760e21b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906306e8fb9c9061242f908b908b908b908b908b908b908b908b9060040161437b565b600060405180830381600087803b15801561244957600080fd5b505af115801561245d573d6000803e3d6000fd5b505050506000603560008a8a604051612477929190614193565b60408051918290039091208252602082019290925201600020805460ff191660018360038111156124aa576124aa61479d565b02179055507f75c4a66b2c6c28cf46db7131182a812e4fbbb2f0591377aa83a737909a9b68c3888888886040516124e49493929190614354565b60405180910390a15050505050505050565b6124fe612583565b61251a5760405162461bcd60e51b81526004016103439061450b565b60a354604080516001600160a01b03928316815291831660208301527fe48386b84419f4d36e0f96c10cc3510b6fb1a33795620c5098b22472bbe90796910160405180910390a160a380546001600160a01b0319166001600160a01b0392909216919091179055565b600061259b6000805160206148398339815191525490565b6001600160a01b0316336001600160a01b031614905090565b6125bc612583565b6125d85760405162461bcd60e51b81526004016103439061450b565b612600817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b03166126206000805160206148398339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146126a05760405162461bcd60e51b8152600401610343906144d4565b600080516020614819833981519152805460028114156126d25760405162461bcd60e51b8152600401610343906145a3565b600282556126e185858561310e565b5060019055505050565b60335461010090046001600160a01b0316331461271a5760405162461bcd60e51b81526004016103439061456c565b60335460ff161561273d5760405162461bcd60e51b815260040161034390614542565b6000603560008686604051612753929190614193565b604080519182900390912082526020820192909252016000205460ff16905060018160038111156127865761278661479d565b146127ca5760405162461bcd60e51b815260206004820152601460248201527315985b1a59185d1bdc881b9bdd081cdd185ad95960621b6044820152606401610343565b604051633877322b60e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690633877322b9061281c908890889088908890600401614354565b600060405180830381600087803b15801561283657600080fd5b505af115801561284a573d6000803e3d6000fd5b505050507ff8821da16f5ed966b41e0343c3eff9903af782d74f99f1689dd9d4562b6545b3858585856040516128839493929190614354565b60405180910390a160026035600087876040516128a1929190614193565b60408051918290039091208252602082019290925201600020805460ff191660018360038111156128d4576128d461479d565b02179055505050505050565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146129285760405162461bcd60e51b8152600401610343906144d4565b6000805160206148198339815191528054600281141561295a5760405162461bcd60e51b8152600401610343906145a3565b600282556040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b1580156129c057600080fd5b505afa1580156129d4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129f8919061405a565b90508015611a8757611a877f000000000000000000000000000000000000000000000000000000000000000082612cf8565b606060a4805480602002602001604051908101604052809291908181526020018280548015612a8257602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612a64575b5050505050905090565b6001600160a01b038281166000908152609f60205260409020541615612ae95760405162461bcd60e51b81526020600482015260126024820152711c151bdad95b88185b1c9958591e481cd95d60721b6044820152606401610343565b6001600160a01b03821615801590612b0957506001600160a01b03811615155b612b495760405162461bcd60e51b8152602060048201526011602482015270496e76616c69642061646472657373657360781b6044820152606401610343565b6001600160a01b038281166000818152609f6020908152604080832080549587166001600160a01b0319968716811790915560a0805460018101825594527f78fdc8d422c49ced035a9edf18d00d3c6a8d81df210f3e5e448e045e77b41e8890930180549095168417909455925190815290917fef6485b84315f9b1483beffa32aae9a0596890395e3d7521f1c5fbb51790e765910160405180910390a25050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052611e729084906136ec565b8251612c509060a49060208601906139b3565b50815181518114612c9a5760405162461bcd60e51b8152602060048201526014602482015273496e76616c696420696e7075742061727261797360601b6044820152606401610343565b60005b81811015612cf157612ce1848281518110612cba57612cba6147c9565b6020026020010151848381518110612cd457612cd46147c9565b6020026020010151612a8c565b612cea8161476c565b9050612c9d565b5050505050565b60008111612d415760405162461bcd60e51b81526020600482015260166024820152754d757374206465706f73697420736f6d657468696e6760501b6044820152606401610343565b6040805160008152602081018390526001600160a01b038416917f5548c837ab068cf56a2c2479df0882a4922fd203edb7517321831d95078c5f62910160405180910390a25050565b60335460ff1615612dad5760405162461bcd60e51b815260040161034390614542565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663e52253816040518163ffffffff1660e01b8152600401602060405180830381600087803b158015612e0a57600080fd5b505af1158015612e1e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e42919061405a565b9050600060685482612e5491906146f2565b905080471015612ea65760405162461bcd60e51b815260206004820152601860248201527f696e73756666696369656e74206574682062616c616e636500000000000000006044820152606401610343565b8015610a465760006068819055507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b158015612f0f57600080fd5b505af1158015612f23573d6000803e3d6000fd5b505060a354604080516001600160a01b0392831681527f0000000000000000000000000000000000000000000000000000000000000000909216602083015281018590527ff6c07a063ed4e63808eb8da7112d46dbcd38de2b40a73dbcc9353c5a94c7235393506060019150612f969050565b60405180910390a160a354610a46906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116911683612beb565b6001600160a01b03811661302e5760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f7220697320616464726573732830290000000000006044820152606401610343565b806001600160a01b031661304e6000805160206148398339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a36123808160008051602061483983398151915255565b60335460ff16156130bc5760405162461bcd60e51b815260040161034390614542565b6033805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586130f13390565b6040516001600160a01b03909116815260200160405180910390a1565b6000811161315e5760405162461bcd60e51b815260206004820152601760248201527f4d75737420776974686472617720736f6d657468696e670000000000000000006044820152606401610343565b6001600160a01b0383166131ad5760405162461bcd60e51b8152602060048201526016602482015275135d5cdd081cdc1958da599e481c9958da5c1a595b9d60521b6044820152606401610343565b6040805160008152602081018390526001600160a01b038416917f2717ead6b9200dd235aad468c9809ea400fe33ac69b5bfaa6d3e90fc922b6398910160405180910390a2611e726001600160a01b0383168483612beb565b600060685447101561321b576110af826137be565b60006068544761322b9190614729565b9050600191506801bc16d674ec80000081106133ff5760006801bc16d674ec8000008204905080603460008282546132639190614729565b909155506000905061327e826801bc16d674ec80000061470a565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b1580156132db57600080fd5b505af11580156132ef573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb92506044019050602060405180830381600087803b15801561337f57600080fd5b505af1158015613393573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133b79190613e58565b5060345460408051848152602081019290925281018290527fbe7040030ff7b347853214bf49820c6d455fedf58f3815f85c7bc5216993682b9060600160405180910390a150505b60006068544761340f9190614729565b90506801bc16d674ec80000081106134615760405162461bcd60e51b8152602060048201526015602482015274756e6578706563746564206163636f756e74696e6760581b6044820152606401610343565b8061346d575050919050565b6069548110156134c757806068600082825461348991906146f2565b90915550506040518181527f7a745a2c63a535068f52ceca27debd5297bbad5f7f37ec53d044a59d0362445d906020015b60405180910390a161366b565b606a5481111561365a577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b15801561352c57600080fd5b505af1158015613540573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb92506044019050602060405180830381600087803b1580156135d057600080fd5b505af11580156135e4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136089190613e58565b5060016034600082825461361c9190614729565b909155505060345460408051918252602082018390527f6aa7e30787b26429ced603a7aba8b19c4b5d5bcf29a3257da953c8d53bcaa3a691016134ba565b613663846137be565b949350505050565b5050919050565b60335460ff166136bb5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610343565b6033805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa336130f1565b6000613741826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166137d69092919063ffffffff16565b805190915015611e72578080602001905181019061375f9190613e58565b611e725760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610343565b600081156137ce576137ce613099565b506000919050565b60606137e584846000856137ef565b90505b9392505050565b6060824710156138505760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610343565b843b61389e5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610343565b600080866001600160a01b031685876040516138ba91906141a3565b60006040518083038185875af1925050503d80600081146138f7576040519150601f19603f3d011682016040523d82523d6000602084013e6138fc565b606091505b509150915061390c828286613917565b979650505050505050565b606083156139265750816137e8565b8251156139365782518084602001fd5b8160405162461bcd60e51b815260040161034391906144c1565b8280548282559060005260206000209081019282156139a3579160200282015b828111156139a35781546001600160a01b0319166001600160a01b03843516178255602090920191600190910190613970565b506139af929150613a08565b5090565b8280548282559060005260206000209081019282156139a3579160200282015b828111156139a357825182546001600160a01b0319166001600160a01b039091161782556020909201916001909101906139d3565b5b808211156139af5760008155600101613a09565b60008083601f840112613a2f57600080fd5b5081356001600160401b03811115613a4657600080fd5b6020830191508360208260051b8501011115613a6157600080fd5b9250929050565b600082601f830112613a7957600080fd5b81356020613a8e613a898361468e565b61465e565b80838252828201915082860187848660051b8901011115613aae57600080fd5b60005b85811015613ad6578135613ac4816147f5565b84529284019290840190600101613ab1565b5090979650505050505050565b60008083601f840112613af557600080fd5b5081356001600160401b03811115613b0c57600080fd5b602083019150836020828501011115613a6157600080fd5b600060a08284031215613b3657600080fd5b50919050565b600060a08284031215613b4e57600080fd5b60405160a081018181106001600160401b0382111715613b7057613b706147df565b604052905080613b7f83613bc7565b8152613b8d60208401613be0565b6020820152613b9e60408401613be0565b60408201526060830135613bb18161480a565b6060820152608092830135920191909152919050565b803563ffffffff81168114613bdb57600080fd5b919050565b80356001600160401b0381168114613bdb57600080fd5b600060208284031215613c0957600080fd5b81356137e8816147f5565b600060208284031215613c2657600080fd5b81516137e8816147f5565b60008060408385031215613c4457600080fd5b8235613c4f816147f5565b91506020830135613c5f816147f5565b809150509250929050565b600080600060608486031215613c7f57600080fd5b8335613c8a816147f5565b92506020840135613c9a816147f5565b929592945050506040919091013590565b60008060408385031215613cbe57600080fd5b8235613cc9816147f5565b946020939093013593505050565b60008060208385031215613cea57600080fd5b82356001600160401b03811115613d0057600080fd5b613d0c85828601613a1d565b90969095509350505050565b600080600060608486031215613d2d57600080fd5b83356001600160401b0380821115613d4457600080fd5b613d5087838801613a68565b94506020860135915080821115613d6657600080fd5b613d7287838801613a68565b93506040860135915080821115613d8857600080fd5b50613d9586828701613a68565b9150509250925092565b600080600060e08486031215613db457600080fd5b83356001600160401b03811115613dca57600080fd5b8401601f81018613613ddb57600080fd5b80356020613deb613a898361468e565b8083825282820191508285018a848660051b8801011115613e0b57600080fd5b600095505b84861015613e3557613e2181613be0565b835260019590950194918301918301613e10565b509650508601359350613e4f915086905060408601613b3c565b90509250925092565b600060208284031215613e6a57600080fd5b81516137e88161480a565b600060208284031215613e8757600080fd5b5035919050565b60008060008060408587031215613ea457600080fd5b84356001600160401b0380821115613ebb57600080fd5b613ec788838901613ae3565b90965094506020870135915080821115613ee057600080fd5b50613eed87828801613a1d565b95989497509550505050565b600080600080600080600080610120898b031215613f1657600080fd5b88356001600160401b0380821115613f2d57600080fd5b613f398c838d01613ae3565b909a50985060208b0135915080821115613f5257600080fd5b613f5e8c838d01613a1d565b909850965060408b0135915080821115613f7757600080fd5b50613f848b828c01613ae3565b90955093505060608901359150613f9e8a60808b01613b24565b90509295985092959890939650565b600080600080600060e08688031215613fc557600080fd5b85356001600160401b0380821115613fdc57600080fd5b613fe889838a01613ae3565b9097509550602088013591508082111561400157600080fd5b5061400e88828901613a1d565b909450925061402290508760408801613b24565b90509295509295909350565b60008060006060848603121561404357600080fd5b505081359360208301359350604090920135919050565b60006020828403121561406c57600080fd5b5051919050565b6000806040838503121561408657600080fd5b50508035926020909101359150565b8183526000602080850194508260005b858110156140d1576001600160401b036140be83613be0565b16875295820195908201906001016140a5565b509495945050505050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6000815180845261411d816020860160208601614740565b601f01601f19169290920160200192915050565b63ffffffff61413f82613bc7565b16825261414e60208201613be0565b6001600160401b0380821660208501528061416b60408501613be0565b166040850152505060608101356141818161480a565b15156060830152608090810135910152565b8183823760009101908152919050565b600082516141b5818460208701614740565b9190910192915050565b6001600160a01b03851681526101006020808301829052855191830182905260009161012084019187810191845b818110156142125783516001600160401b0316855293820193928201926001016141ed565b505082935086604086015263ffffffff865116606086015280860151925050506001600160401b0380821660808501528060408601511660a085015250506060830151151560c0830152608083015160e083015295945050505050565b6020808252825182820181905260009190848201906040850190845b818110156142b05783516001600160a01b03168352928401929184019160010161428b565b50909695505050505050565b6000604082016040835280865480835260608501915087600052602092508260002060005b828110156143065781546001600160a01b0316845292840192600191820191016142e1565b505050838103828501528481528590820160005b8681101561434857823561432d816147f5565b6001600160a01b03168252918301919083019060010161431a565b50979650505050505050565b6040815260006143686040830186886140dc565b828103602084015261390c818587614095565b60006101208083526143908184018b8d6140dc565b905082810360208401526143a581898b614095565b905082810360408401526143ba8187896140dc565b9150508360608301526143d06080830184614131565b9998505050505050505050565b60e0815260006143f160e0830187896140dc565b8281036020840152614404818688614095565b9150506144146040830184614131565b9695505050505050565b60808152600061443260808301888a6140dc565b82810360208401526144448188614105565b905082810360408401526144598186886140dc565b915050826060830152979650505050505050565b6060815260006144816060830186886140dc565b846020840152828103604084015261390c8185614105565b60208101600483106144bb57634e487b7160e01b600052602160045260246000fd5b91905290565b6020815260006137e86020830184614105565b60208082526017908201527f43616c6c6572206973206e6f7420746865205661756c74000000000000000000604082015260600190565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b60208082526010908201526f14185d5cd8589b194e881c185d5cd95960821b604082015260600190565b6020808252601d908201527f43616c6c6572206973206e6f7420746865205265676973747261746f72000000604082015260600190565b6020808252600e908201526d1499595b9d1c985b9d0818d85b1b60921b604082015260600190565b6020808252601c908201527f43616c6c6572206973206e6f7420746865205374726174656769737400000000604082015260600190565b6000808335601e1984360301811261461957600080fd5b8301803591506001600160401b0382111561463357600080fd5b602001915036819003821315613a6157600080fd5b60008235605e198336030181126141b557600080fd5b604051601f8201601f191681016001600160401b0381118282101715614686576146866147df565b604052919050565b60006001600160401b038211156146a7576146a76147df565b5060051b60200190565b600080821280156001600160ff1b03849003851316156146d3576146d3614787565b600160ff1b83900384128116156146ec576146ec614787565b50500190565b6000821982111561470557614705614787565b500190565b600081600019048311821515161561472457614724614787565b500290565b60008282101561473b5761473b614787565b500390565b60005b8381101561475b578181015183820152602001614743565b83811115610d305750506000910152565b600060001982141561478057614780614787565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b038116811461238057600080fd5b801515811461238057600080fdfe53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac45357bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa2646970667358221220cb53a48aebce08cd91f08713d34b94e51baee827b032c246ff83f59c6d6e39d364736f6c63430008070033", + "numDeployments": 4, + "solcInputHash": "279a9fe8a2da81dca55abd3c6ec521f8", + "metadata": "{\"compiler\":{\"version\":\"0.8.7+commit.e28d00a7\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"platformAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"vaultAddress\",\"type\":\"address\"}],\"internalType\":\"struct InitializableAbstractStrategy.BaseStrategyConfig\",\"name\":\"_baseConfig\",\"type\":\"tuple\"},{\"internalType\":\"address\",\"name\":\"_wethAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_ssvToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_ssvNetwork\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_feeAccumulator\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_beaconChainDepositContract\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"AccountingConsensusRewards\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"noOfValidators\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"remainingValidators\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"wethSentToVault\",\"type\":\"uint256\"}],\"name\":\"AccountingFullyWithdrawnValidator\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"validatorsDelta\",\"type\":\"int256\"},{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"consensusRewardsDelta\",\"type\":\"int256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"wethToVault\",\"type\":\"uint256\"}],\"name\":\"AccountingManuallyFixed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"remainingValidators\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"wethSentToVault\",\"type\":\"uint256\"}],\"name\":\"AccountingValidatorSlashed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"Deposit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"pubkey\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"withdrawal_credentials\",\"type\":\"bytes\"}],\"name\":\"ETHStaked\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"start\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"end\",\"type\":\"uint256\"}],\"name\":\"FuseIntervalUpdated\",\"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\":\"address\",\"name\":\"_oldHarvesterAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_newHarvesterAddress\",\"type\":\"address\"}],\"name\":\"HarvesterAddressesUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"}],\"name\":\"PTokenAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"}],\"name\":\"PTokenRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Paused\",\"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\":\"newAddress\",\"type\":\"address\"}],\"name\":\"RegistratorChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"_oldAddresses\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"_newAddresses\",\"type\":\"address[]\"}],\"name\":\"RewardTokenAddressesUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"rewardToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"RewardTokenCollected\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"pubkey\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"}],\"name\":\"SSVValidatorExitCompleted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"pubkey\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"}],\"name\":\"SSVValidatorExitInitiated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"pubkey\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"}],\"name\":\"SSVValidatorRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Unpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"Withdrawal\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"BEACON_CHAIN_DEPOSIT_CONTRACT\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_ACCUMULATOR_ADDRESS\",\"outputs\":[{\"internalType\":\"address payable\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MAX_STAKE\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MIN_FIX_ACCOUNTING_CADENCE\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"SSV_NETWORK_ADDRESS\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"SSV_TOKEN_ADDRESS\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"VAULT_ADDRESS\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"WETH_TOKEN_ADDRESS\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"activeDepositedValidators\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"assetToPToken\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"}],\"name\":\"checkBalance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"claimGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"collectRewardTokens\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"consensusRewards\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"depositAll\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"validatorCount\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"networkFeeIndex\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"index\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"active\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"internalType\":\"struct Cluster\",\"name\":\"cluster\",\"type\":\"tuple\"}],\"name\":\"depositSSV\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"depositedWethAccountedFor\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"doAccounting\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"accountingValid\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"publicKey\",\"type\":\"bytes\"},{\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"}],\"name\":\"exitSsvValidator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fuseIntervalEnd\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fuseIntervalStart\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRewardTokenAddresses\",\"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\":\"harvesterAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"_rewardTokenAddresses\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"_assets\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"_pTokens\",\"type\":\"address[]\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isGovernor\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastFixAccountingBlockNumber\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"int256\",\"name\":\"_validatorsDelta\",\"type\":\"int256\"},{\"internalType\":\"int256\",\"name\":\"_consensusRewardsDelta\",\"type\":\"int256\"},{\"internalType\":\"uint256\",\"name\":\"_ethToVaultAmount\",\"type\":\"uint256\"}],\"name\":\"manuallyFixAccounting\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"paused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"platformAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"publicKey\",\"type\":\"bytes\"},{\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"},{\"internalType\":\"bytes\",\"name\":\"sharesData\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"validatorCount\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"networkFeeIndex\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"index\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"active\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"internalType\":\"struct Cluster\",\"name\":\"cluster\",\"type\":\"tuple\"}],\"name\":\"registerSsvValidator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_assetIndex\",\"type\":\"uint256\"}],\"name\":\"removePToken\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"publicKey\",\"type\":\"bytes\"},{\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"validatorCount\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"networkFeeIndex\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"index\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"active\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"internalType\":\"struct Cluster\",\"name\":\"cluster\",\"type\":\"tuple\"}],\"name\":\"removeSsvValidator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"rewardTokenAddresses\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"safeApproveAllTokens\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_fuseIntervalStart\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_fuseIntervalEnd\",\"type\":\"uint256\"}],\"name\":\"setFuseInterval\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_harvesterAddress\",\"type\":\"address\"}],\"name\":\"setHarvesterAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"}],\"name\":\"setPTokenAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"setRegistrator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"_rewardTokenAddresses\",\"type\":\"address[]\"}],\"name\":\"setRewardTokenAddresses\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"pubkey\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"depositDataRoot\",\"type\":\"bytes32\"}],\"internalType\":\"struct ValidatorStakeData[]\",\"name\":\"validators\",\"type\":\"tuple[]\"}],\"name\":\"stakeEth\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"}],\"name\":\"supportsAsset\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"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\":\"validatorRegistrator\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"validatorsStates\",\"outputs\":[{\"internalType\":\"enum ValidatorRegistrator.VALIDATOR_STATE\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"vaultAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"withdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdrawAll\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"author\":\"Origin Protocol Inc\",\"details\":\"This contract handles WETH and ETH and in some operations interchanges between the two. Any WETH that is on the contract across multiple blocks (and not just transitory within a transaction) is considered an asset. Meaning deposits increase the balance of the asset and withdrawal decrease it. As opposed to all our other strategies the WETH doesn't immediately get deposited into an underlying strategy and can be present across multiple blocks waiting to be unwrapped to ETH and staked to validators. This separation of WETH and ETH is required since the rewards (reward token) is also in ETH. To simplify the accounting of WETH there is another difference in behavior compared to the other strategies. To withdraw WETH asset - exit message is posted to validators and the ETH hits this contract with multiple days delay. In order to simplify the WETH accounting upon detection of such an event the ValidatorAccountant immediately wraps ETH to WETH and sends it to the Vault. On the other hand any ETH on the contract (across multiple blocks) is there either: - as a result of already accounted for consensus rewards - as a result of not yet accounted for consensus rewards - as a results of not yet accounted for full validator withdrawals (or validator slashes) Even though the strategy assets and rewards are a very similar asset the consensus layer rewards and the execution layer rewards are considered rewards and those are dripped to the Vault over a configurable time interval and not immediately.\",\"kind\":\"dev\",\"methods\":{\"checkBalance(address)\":{\"params\":{\"_asset\":\"Address of weth asset\"},\"returns\":{\"balance\":\" Total value of (W)ETH\"}},\"constructor\":{\"params\":{\"_baseConfig\":\"Base strategy config with platformAddress (ERC-4626 Vault contract), eg sfrxETH or sDAI, and vaultAddress (OToken Vault contract), eg VaultProxy or OETHVaultProxy\",\"_beaconChainDepositContract\":\"Address of the beacon chain deposit contract\",\"_feeAccumulator\":\"Address of the fee accumulator receiving execution layer validator rewards\",\"_ssvNetwork\":\"Address of the SSV Network contract\",\"_ssvToken\":\"Address of the Erc20 SSV Token contract\",\"_wethAddress\":\"Address of the Erc20 WETH Token contract\"}},\"deposit(address,uint256)\":{\"params\":{\"_amount\":\"Amount of assets that were transferred to the strategy by the vault.\",\"_asset\":\"Address of asset to deposit. Has to be WETH.\"}},\"depositSSV(uint64[],uint256,(uint32,uint64,uint64,bool,uint256))\":{\"details\":\"A SSV cluster is defined by the SSVOwnerAddress and the set of operatorIds. uses \\\"onlyStrategist\\\" modifier so continuous front-running can't DOS our maintenance service that tries to top up SSV tokens.\",\"params\":{\"cluster\":\"The SSV cluster details that must be derived from emitted events from the SSVNetwork contract.\"}},\"doAccounting()\":{\"details\":\"This function could in theory be permission-less but lets allow only the Registrator (Defender Action) to call it for now.\",\"returns\":{\"accountingValid\":\"true if accounting was successful, false if fuse is blown\"}},\"getRewardTokenAddresses()\":{\"returns\":{\"_0\":\"address[] the reward token addresses.\"}},\"initialize(address[],address[],address[])\":{\"params\":{\"_assets\":\"Addresses of initial supported assets\",\"_pTokens\":\"Platform Token corresponding addresses\",\"_rewardTokenAddresses\":\"Address of reward token for platform\"}},\"manuallyFixAccounting(int256,int256,uint256)\":{\"details\":\"There is a case when a validator(s) gets slashed so much that the eth swept from the beacon chain enters the fuse area and there are no consensus rewards on the contract to \\\"dip into\\\"/use. To increase the amount of unaccounted ETH over the fuse end interval we need to reduce the amount of active deposited validators and immediately send WETH to the vault, so it doesn't interfere with further accounting.\",\"params\":{\"_consensusRewardsDelta\":\"adjust the accounted for consensus rewards up or down\",\"_ethToVaultAmount\":\"the amount of ETH that gets wrapped into WETH and sent to the Vault\",\"_validatorsDelta\":\"adjust the active validators by up to plus three or minus three\"}},\"paused()\":{\"details\":\"Returns true if the contract is paused, and false otherwise.\"},\"removePToken(uint256)\":{\"params\":{\"_assetIndex\":\"Index of the asset to be removed\"}},\"setHarvesterAddress(address)\":{\"params\":{\"_harvesterAddress\":\"Address of the harvester contract.\"}},\"setPTokenAddress(address,address)\":{\"params\":{\"_asset\":\"Address for the asset\",\"_pToken\":\"Address for the corresponding platform token\"}},\"setRewardTokenAddresses(address[])\":{\"params\":{\"_rewardTokenAddresses\":\"Array of reward token addresses\"}},\"stakeEth((bytes,bytes,bytes32)[])\":{\"params\":{\"validators\":\"A list of validator data needed to stake. The `ValidatorStakeData` struct contains the pubkey, signature and depositDataRoot. Only the registrator can call this function.\"}},\"supportsAsset(address)\":{\"params\":{\"_asset\":\"The address of the asset token.\"}},\"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\"}},\"withdraw(address,address,uint256)\":{\"params\":{\"_amount\":\"Amount of WETH to withdraw\",\"_asset\":\"WETH to withdraw\",\"_recipient\":\"Address to receive withdrawn assets\"}}},\"stateVariables\":{\"FEE_ACCUMULATOR_ADDRESS\":{\"details\":\"this address will receive Execution layer rewards - These are rewards earned for executing transactions on the Ethereum network as part of block proposals. They include priority fees (fees paid by users for their transactions to be included) and MEV rewards (rewards for arranging transactions in a way that benefits the validator).\"},\"depositedWethAccountedFor\":{\"details\":\"This contract receives WETH as the deposit asset, but unlike other strategies doesn't immediately deposit it to an underlying platform. Rather a special privilege account stakes it to the validators. For that reason calling WETH.balanceOf(this) in a deposit function can contain WETH that has just been deposited and also WETH that has previously been deposited. To keep a correct count we need to keep track of WETH that has already been accounted for. This value represents the amount of WETH balance of this contract that has already been accounted for by the deposit events. It is important to note that this variable is not concerned with WETH that is a result of full/partial withdrawal of the validators. It is strictly concerned with WETH that has been deposited and is waiting to be staked.\"}},\"title\":\"Native Staking SSV Strategy\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"BEACON_CHAIN_DEPOSIT_CONTRACT()\":{\"notice\":\"The address of the beacon chain deposit contract\"},\"FEE_ACCUMULATOR_ADDRESS()\":{\"notice\":\"Fee collector address\"},\"MAX_STAKE()\":{\"notice\":\"The maximum amount of ETH that can be staked by a validator\"},\"MIN_FIX_ACCOUNTING_CADENCE()\":{\"notice\":\"The minimum amount of blocks that need to pass between two calls to manuallyFixAccounting\"},\"SSV_NETWORK_ADDRESS()\":{\"notice\":\"The address of the SSV Network contract used to interface with\"},\"SSV_TOKEN_ADDRESS()\":{\"notice\":\"SSV ERC20 token that serves as a payment for operating SSV validators\"},\"VAULT_ADDRESS()\":{\"notice\":\"Address of the OETH Vault proxy contract\"},\"WETH_TOKEN_ADDRESS()\":{\"notice\":\"The address of the Wrapped ETH (WETH) token contract\"},\"activeDepositedValidators()\":{\"notice\":\"The number of validators that have 32 (!) ETH actively deposited. When a new deposit to a validator happens this number increases, when a validator exit is detected this number decreases.\"},\"assetToPToken(address)\":{\"notice\":\"asset => pToken (Platform Specific Token Address)\"},\"checkBalance(address)\":{\"notice\":\"Returns the total value of (W)ETH that is staked to the validators and WETH deposits that are still to be staked. This does not include ETH from consensus rewards sitting in this strategy or ETH from MEV rewards in the FeeAccumulator. These rewards are harvested and sent to the Dripper so will eventually be sent to the Vault as WETH.\"},\"claimGovernance()\":{\"notice\":\"Claim Governance of the contract to a new account (`newGovernor`). Can only be called by the new Governor.\"},\"collectRewardTokens()\":{\"notice\":\"Collect accumulated reward token and send to Vault.\"},\"consensusRewards()\":{\"notice\":\"Keeps track of the total consensus rewards swept from the beacon chain\"},\"deposit(address,uint256)\":{\"notice\":\"Unlike other strategies, this does not deposit assets into the underlying platform. It just checks the asset is WETH and emits the Deposit event. To deposit WETH into validators `registerSsvValidator` and `stakeEth` must be used. Will NOT revert if the strategy is paused from an accounting failure.\"},\"depositAll()\":{\"notice\":\"Unlike other strategies, this does not deposit assets into the underlying platform. It just emits the Deposit event. To deposit WETH into validators `registerSsvValidator` and `stakeEth` must be used. Will NOT revert if the strategy is paused from an accounting failure.\"},\"depositSSV(uint64[],uint256,(uint32,uint64,uint64,bool,uint256))\":{\"notice\":\"Deposits more SSV Tokens to the SSV Network contract which is used to pay the SSV Operators.\"},\"doAccounting()\":{\"notice\":\"This notion page offers a good explanation of how the accounting functions https://www.notion.so/originprotocol/Limited-simplified-native-staking-accounting-67a217c8420d40678eb943b9da0ee77d In short, after dividing by 32, if the ETH remaining on the contract falls between 0 and fuseIntervalStart, the accounting function will treat that ETH as Beacon chain consensus rewards. On the contrary, if after dividing by 32, the ETH remaining on the contract falls between fuseIntervalEnd and 32, the accounting function will treat that as a validator slashing.Perform the accounting attributing beacon chain ETH to either full or partial withdrawals. Returns true when accounting is valid and fuse isn't \\\"blown\\\". Returns false when fuse is blown.\"},\"exitSsvValidator(bytes,uint64[])\":{\"notice\":\"Exit a validator from the Beacon chain. The staked ETH will eventually swept to this native staking strategy. Only the registrator can call this function.\"},\"fuseIntervalEnd()\":{\"notice\":\"end of fuse interval\"},\"fuseIntervalStart()\":{\"notice\":\"start of fuse interval\"},\"getRewardTokenAddresses()\":{\"notice\":\"Get the reward token addresses.\"},\"governor()\":{\"notice\":\"Returns the address of the current Governor.\"},\"harvesterAddress()\":{\"notice\":\"Address of the Harvester contract allowed to collect reward tokens\"},\"initialize(address[],address[],address[])\":{\"notice\":\"initialize function, to set up initial internal state\"},\"isGovernor()\":{\"notice\":\"Returns true if the caller is the current Governor.\"},\"lastFixAccountingBlockNumber()\":{\"notice\":\"last block number manuallyFixAccounting has been called\"},\"manuallyFixAccounting(int256,int256,uint256)\":{\"notice\":\"Allow the Strategist to fix the accounting of this strategy and unpause.\"},\"platformAddress()\":{\"notice\":\"Address of the underlying platform\"},\"registerSsvValidator(bytes,uint64[],bytes,uint256,(uint32,uint64,uint64,bool,uint256))\":{\"notice\":\"Registers a new validator in the SSV Cluster. Only the registrator can call this function.\"},\"removePToken(uint256)\":{\"notice\":\"Remove a supported asset by passing its index. This method can only be called by the system Governor\"},\"removeSsvValidator(bytes,uint64[],(uint32,uint64,uint64,bool,uint256))\":{\"notice\":\"Remove a validator from the SSV Cluster. Make sure `exitSsvValidator` is called before and the validate has exited the Beacon chain. If removed before the validator has exited the beacon chain will result in the validator being slashed. Only the registrator can call this function.\"},\"rewardTokenAddresses(uint256)\":{\"notice\":\"Address of the reward tokens. eg CRV, BAL, CVX, AURA\"},\"safeApproveAllTokens()\":{\"notice\":\"Approves the SSV Network contract to transfer SSV tokens for deposits\"},\"setFuseInterval(uint256,uint256)\":{\"notice\":\"set fuse interval values\"},\"setHarvesterAddress(address)\":{\"notice\":\"Set the Harvester contract that can collect rewards.\"},\"setPTokenAddress(address,address)\":{\"notice\":\"Provide support for asset by passing its pToken address. This method can only be called by the system Governor\"},\"setRegistrator(address)\":{\"notice\":\"Set the address of the registrator which can register, exit and remove validators\"},\"setRewardTokenAddresses(address[])\":{\"notice\":\"Set the reward token addresses. Any old addresses will be overwritten.\"},\"stakeEth((bytes,bytes,bytes32)[])\":{\"notice\":\"Stakes WETH to the node validators\"},\"supportsAsset(address)\":{\"notice\":\"Returns bool indicating whether asset is supported by strategy.\"},\"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 strategy contracts, i.e. mistaken sends.\"},\"validatorRegistrator()\":{\"notice\":\"Address of the registrator - allowed to register, exit and remove validators\"},\"validatorsStates(bytes32)\":{\"notice\":\"State of the validators keccak256(pubKey) => state\"},\"vaultAddress()\":{\"notice\":\"Address of the OToken vault\"},\"withdraw(address,address,uint256)\":{\"notice\":\"Withdraw WETH from this contract. Used only if some WETH for is lingering on the contract. That can happen when: - the deposit was not a multiple of 32 WETH - someone sent WETH directly to this contract Will NOT revert if the strategy is paused from an accounting failure.\"},\"withdrawAll()\":{\"notice\":\"transfer all WETH deposits back to the vault. This does not withdraw from the validators. That has to be done separately with the `exitSsvValidator` and `removeSsvValidator` operations. This does not withdraw any execution rewards from the FeeAccumulator or consensus rewards in this strategy. Any ETH in this strategy that was swept from a full validator withdrawal will not be withdrawn. ETH from full validator withdrawals is sent to the Vault using `doAccounting`. Will NOT revert if the strategy is paused from an accounting failure.\"}},\"notice\":\"Strategy to deploy funds into DVT validators powered by the SSV Network\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol\":\"NativeStakingSSVStrategy\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"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\",\"keccak256\":\"0xe68ed7fb8766ed1e888291f881e36b616037f852b37d96877045319ad298ba87\",\"license\":\"MIT\"},\"@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/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\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@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\",\"keccak256\":\"0xfaad496c1c944b6259b7dc70b4865eb1775d6402bc0c81b38a0b24d9f525ae37\",\"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/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\",\"keccak256\":\"0x598f90bdbc854250bbd5991426bfb43367207e64e33109c41aa8b54323fd8d8e\",\"license\":\"MIT\"},\"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 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 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 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\",\"keccak256\":\"0xbef02bd5257e61dec0a6be4b1531064a7fdfeb4043885443a1902fb5d1b23e1b\",\"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/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 function removeAsset(address _asset) external;\\n}\\n\",\"keccak256\":\"0xa03ba17b6224bec26290794760fc807e017260406037b4f812970701888e72c8\",\"license\":\"MIT\"},\"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\",\"keccak256\":\"0x05b7dce6c24d3cd4e48b5c6346d86e5e40ecc3291bcdf3f3ef091c98fc826519\",\"license\":\"MIT\"},\"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\\nimport { Governable } from \\\"../../governance/Governable.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 is Governable {\\n /// @notice The address of the Native Staking Strategy\\n address public immutable STRATEGY;\\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 }\\n\\n /**\\n * @dev Accept ETH\\n */\\n receive() external payable {}\\n}\\n\",\"keccak256\":\"0xb8fda3b87dc5d6f8aee4bf1d015a585211e5b5a319dfa4b0f4770e3f5a2d5939\",\"license\":\"MIT\"},\"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_ADDRESS;\\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 _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 address _feeAccumulator,\\n address _beaconChainDepositContract\\n )\\n InitializableAbstractStrategy(_baseConfig)\\n ValidatorAccountant(\\n _wethAddress,\\n _baseConfig.vaultAddress,\\n _beaconChainDepositContract,\\n _ssvNetwork\\n )\\n {\\n SSV_TOKEN_ADDRESS = _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 /// @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_TOKEN_ADDRESS).deposit{ value: ethRewards }();\\n\\n emit RewardTokenCollected(\\n harvesterAddress,\\n WETH_TOKEN_ADDRESS,\\n ethRewards\\n );\\n IERC20(WETH_TOKEN_ADDRESS).safeTransfer(\\n harvesterAddress,\\n ethRewards\\n );\\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_TOKEN_ADDRESS, \\\"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_TOKEN_ADDRESS).balanceOf(\\n address(this)\\n );\\n uint256 newWeth = wethBalance - depositedWethAccountedFor;\\n\\n if (newWeth > 0) {\\n depositedWethAccountedFor = wethBalance;\\n\\n _deposit(WETH_TOKEN_ADDRESS, newWeth);\\n }\\n }\\n\\n /// @notice Withdraw WETH from this contract. Used only if some WETH for is lingering on the contract. That\\n /// can happen when:\\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 _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 emit Withdrawal(_asset, address(0), _amount);\\n IERC20(_asset).safeTransfer(_recipient, _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_TOKEN_ADDRESS).balanceOf(\\n address(this)\\n );\\n if (wethBalance > 0) {\\n _withdraw(vaultAddress, WETH_TOKEN_ADDRESS, wethBalance);\\n }\\n }\\n\\n function _abstractSetPToken(address _asset, address) internal override {}\\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_TOKEN_ADDRESS, \\\"Unsupported asset\\\");\\n\\n balance =\\n // add the ETH that has been staked in validators\\n activeDepositedValidators *\\n 32 ether +\\n // add the WETH in the strategy from deposits that are still to be staked\\n IERC20(WETH_TOKEN_ADDRESS).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_TOKEN_ADDRESS;\\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_ADDRESS).approve(\\n SSV_NETWORK_ADDRESS,\\n type(uint256).max\\n );\\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 ||\\n msg.sender == WETH_TOKEN_ADDRESS,\\n \\\"eth not from allowed contracts\\\"\\n );\\n }\\n\\n function _wethWithdrawnToVault(uint256 _amount) internal override {\\n emit Withdrawal(WETH_TOKEN_ADDRESS, address(0), _amount);\\n }\\n\\n function _wethWithdrawnAndStaked(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 direclty\\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\",\"keccak256\":\"0x937ce31cd4b90ad532fdde874dc02eaf0a29a800c2c2292d2d6cb71afa75f32d\",\"license\":\"MIT\"},\"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 /// @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 MAX_STAKE = 32 ether;\\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 constructor(\\n address _wethAddress,\\n address _vaultAddress,\\n address _beaconChainDepositContract,\\n address _ssvNetwork\\n )\\n ValidatorRegistrator(\\n _wethAddress,\\n _vaultAddress,\\n _beaconChainDepositContract,\\n _ssvNetwork\\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 _fuseIntervalStart < 32 ether &&\\n _fuseIntervalEnd < 32 ether &&\\n _fuseIntervalEnd - _fuseIntervalStart >= 4 ether,\\n \\\"incorrect fuse interval\\\"\\n );\\n\\n emit FuseIntervalUpdated(_fuseIntervalStart, _fuseIntervalEnd);\\n\\n fuseIntervalStart = _fuseIntervalStart;\\n fuseIntervalEnd = _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 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 >= MAX_STAKE) {\\n uint256 fullyWithdrawnValidators;\\n // safe since MAX_STAKE is hardcoded to 32ETH\\n unchecked {\\n // explicitly cast to uint256 as we want to round to a whole number of validators\\n fullyWithdrawnValidators = uint256(newSweptETH / MAX_STAKE);\\n }\\n activeDepositedValidators -= fullyWithdrawnValidators;\\n\\n uint256 wethToVault = MAX_STAKE * fullyWithdrawnValidators;\\n IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: wethToVault }();\\n // slither-disable-next-line unchecked-transfer\\n IWETH9(WETH_TOKEN_ADDRESS).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 < 32 ether, \\\"unexpected accounting\\\");\\n\\n // If no Beacon chain consensus rewards swept\\n if (ethRemaining == 0) {\\n // do nothing\\n return accountingValid;\\n }\\n // Beacon chain consensus rewards swept (partial validator withdrawals)\\n else if (ethRemaining < fuseIntervalStart) {\\n // solhint-disable-next-line reentrancy\\n consensusRewards += ethRemaining;\\n emit AccountingConsensusRewards(ethRemaining);\\n }\\n // Beacon chain consensus rewards swept but also a slashed validator fully exited\\n else if (ethRemaining > fuseIntervalEnd) {\\n IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: ethRemaining }();\\n // slither-disable-next-line unchecked-transfer\\n IWETH9(WETH_TOKEN_ADDRESS).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 {\\n require(\\n lastFixAccountingBlockNumber + MIN_FIX_ACCOUNTING_CADENCE <\\n block.number,\\n \\\"manuallyFixAccounting 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 emit AccountingManuallyFixed(\\n _validatorsDelta,\\n _consensusRewardsDelta,\\n _ethToVaultAmount\\n );\\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_TOKEN_ADDRESS).deposit{ value: _ethToVaultAmount }();\\n // slither-disable-next-line unchecked-transfer\\n IWETH9(WETH_TOKEN_ADDRESS).transfer(\\n VAULT_ADDRESS,\\n _ethToVaultAmount\\n );\\n _wethWithdrawnToVault(_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 Withdrawal event\\n function _wethWithdrawnToVault(uint256 _amount) internal virtual;\\n}\\n\",\"keccak256\":\"0x0adba45b3fa66233c9e9bc0575ca388ebcd027cba2546278c5887065b95da708\",\"license\":\"MIT\"},\"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 address of the Wrapped ETH (WETH) token contract\\n address public immutable WETH_TOKEN_ADDRESS;\\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_ADDRESS;\\n /// @notice Address of the OETH Vault proxy contract\\n address public immutable VAULT_ADDRESS;\\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\\n // For future use\\n uint256[50] private __gap;\\n\\n enum VALIDATOR_STATE {\\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 newAddress);\\n event ETHStaked(bytes pubkey, uint256 amount, bytes withdrawal_credentials);\\n event SSVValidatorRegistered(bytes pubkey, uint64[] operatorIds);\\n event SSVValidatorExitInitiated(bytes pubkey, uint64[] operatorIds);\\n event SSVValidatorExitCompleted(bytes pubkey, uint64[] operatorIds);\\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 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 constructor(\\n address _wethAddress,\\n address _vaultAddress,\\n address _beaconChainDepositContract,\\n address _ssvNetwork\\n ) {\\n WETH_TOKEN_ADDRESS = _wethAddress;\\n BEACON_CHAIN_DEPOSIT_CONTRACT = _beaconChainDepositContract;\\n SSV_NETWORK_ADDRESS = _ssvNetwork;\\n VAULT_ADDRESS = _vaultAddress;\\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 emit RegistratorChanged(_address);\\n validatorRegistrator = _address;\\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 {\\n uint256 requiredETH = validators.length * 32 ether;\\n\\n // Check there is enough WETH from the deposits sitting in this strategy contract\\n require(\\n requiredETH <= IWETH9(WETH_TOKEN_ADDRESS).balanceOf(address(this)),\\n \\\"insufficient WETH\\\"\\n );\\n\\n // Convert required ETH from WETH\\n IWETH9(WETH_TOKEN_ADDRESS).withdraw(requiredETH);\\n _wethWithdrawnAndStaked(requiredETH);\\n\\n uint256 validatorsLength = validators.length;\\n // For each validator\\n for (uint256 i = 0; i < validatorsLength; ) {\\n bytes32 pubkeyHash = keccak256(validators[i].pubkey);\\n VALIDATOR_STATE currentState = validatorsStates[pubkeyHash];\\n\\n require(\\n currentState == VALIDATOR_STATE.REGISTERED,\\n \\\"Validator not registered\\\"\\n );\\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 withdrawal_credentials = abi.encodePacked(\\n bytes1(0x01),\\n bytes11(0),\\n address(this)\\n );\\n IDepositContract(BEACON_CHAIN_DEPOSIT_CONTRACT).deposit{\\n value: 32 ether\\n }(\\n validators[i].pubkey,\\n withdrawal_credentials,\\n validators[i].signature,\\n validators[i].depositDataRoot\\n );\\n\\n emit ETHStaked(\\n validators[i].pubkey,\\n 32 ether,\\n withdrawal_credentials\\n );\\n\\n validatorsStates[pubkeyHash] = VALIDATOR_STATE.STAKED;\\n\\n unchecked {\\n ++i;\\n }\\n }\\n // save gas by changing this storage variable only once rather each time in the loop.\\n activeDepositedValidators += validatorsLength;\\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 function registerSsvValidator(\\n bytes calldata publicKey,\\n uint64[] calldata operatorIds,\\n bytes calldata sharesData,\\n uint256 amount,\\n Cluster calldata cluster\\n ) external onlyRegistrator whenNotPaused {\\n ISSVNetwork(SSV_NETWORK_ADDRESS).registerValidator(\\n publicKey,\\n operatorIds,\\n sharesData,\\n amount,\\n cluster\\n );\\n validatorsStates[keccak256(publicKey)] = VALIDATOR_STATE.REGISTERED;\\n emit SSVValidatorRegistered(publicKey, operatorIds);\\n }\\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 // slither-disable-start reentrancy-no-eth\\n function exitSsvValidator(\\n bytes calldata publicKey,\\n uint64[] calldata operatorIds\\n ) external onlyRegistrator whenNotPaused {\\n VALIDATOR_STATE currentState = validatorsStates[keccak256(publicKey)];\\n require(currentState == VALIDATOR_STATE.STAKED, \\\"Validator not staked\\\");\\n\\n ISSVNetwork(SSV_NETWORK_ADDRESS).exitValidator(publicKey, operatorIds);\\n emit SSVValidatorExitInitiated(publicKey, operatorIds);\\n\\n validatorsStates[keccak256(publicKey)] = VALIDATOR_STATE.EXITING;\\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 // 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 VALIDATOR_STATE currentState = validatorsStates[keccak256(publicKey)];\\n require(\\n currentState == VALIDATOR_STATE.EXITING,\\n \\\"Validator not exiting\\\"\\n );\\n\\n ISSVNetwork(SSV_NETWORK_ADDRESS).removeValidator(\\n publicKey,\\n operatorIds,\\n cluster\\n );\\n emit SSVValidatorExitCompleted(publicKey, operatorIds);\\n\\n validatorsStates[keccak256(publicKey)] = VALIDATOR_STATE.EXIT_COMPLETE;\\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 cluster The SSV cluster details that must be derived from emitted events from the SSVNetwork contract.\\n function depositSSV(\\n uint64[] memory operatorIds,\\n uint256 amount,\\n Cluster memory cluster\\n ) external onlyStrategist {\\n ISSVNetwork(SSV_NETWORK_ADDRESS).deposit(\\n address(this),\\n operatorIds,\\n amount,\\n cluster\\n );\\n }\\n\\n /***************************************\\n Abstract\\n ****************************************/\\n\\n /// @dev allows for NativeStakingSSVStrategy contract know how much WETH had been staked\\n function _wethWithdrawnAndStaked(uint256 _amount) internal virtual;\\n}\\n\",\"keccak256\":\"0xb9a6e9b02ff8437f5389df287438f14cfea6dc27739942f278ef224d579474fb\",\"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/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\",\"keccak256\":\"0x5e17bb3db9f9e1014b7c5c836547f8fa81e02af7568c0bb8f2a2e0e7c2192db4\",\"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/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\\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\":\"0xcbdb87104749e20c8411bc2acbfa0b7d48e876e3f4e1c46c9a7b00fcdb9722d9\",\"license\":\"MIT\"}},\"version\":1}", + "bytecode": "0x6101806040523480156200001257600080fd5b5060405162004e7a38038062004e7a833981016040819052620000359162000138565b8585876020015183868383838362000053336200010860201b60201c565b60008051602062004e5a833981519152546040516001600160a01b03909116906000907fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a908290a36033805460ff191690556001600160601b0319606094851b811660805291841b821660a052831b811660c05290821b811660e0528651821b811661010052602090960151811b86166101205298891b851661014052505050509190931b1661016052506200021392505050565b60008051602062004e5a83398151915255565b80516001600160a01b03811681146200013357600080fd5b919050565b60008060008060008086880360e08112156200015357600080fd5b60408112156200016257600080fd5b50604080519081016001600160401b03811182821017156200019457634e487b7160e01b600052604160045260246000fd5b604052620001a2886200011b565b8152620001b2602089016200011b565b60208201529550620001c7604088016200011b565b9450620001d7606088016200011b565b9350620001e7608088016200011b565b9250620001f760a088016200011b565b91506200020760c088016200011b565b90509295509295509295565b60805160601c60a05160601c60c05160601c60e05160601c6101005160601c6101205160601c6101405160601c6101605160601c614aa3620003b7600039600081816102f8015281816109ec0152612f750152600081816105ce01526124a50152600081816104a201528181610dd50152818161197c01528181611af5015281816128040152612a8c015260006109b801526000818161075301528181610b9d015281816118aa01528181611b4501528181611f090152818161356101526137bb015260008181610a4b01528181610c730152818161177c015281816124750152818161258d015261298201526000818161090d01526114be01526000818161032a0152818161052c0152818161082401528181610b0401528181610e4a01528181611032015281816110ba015281816112690152818161134401528181611a6601528181611b1601528181611e8301528181611f3801528181612b1701528181612bbf0152818161307a015281816130ff0152818161317301528181613410015281816134db015281816135900152818161373501526137ea0152614aa36000f3fe6080604052600436106102e85760003560e01c8063853828b611610190578063c7af3352116100dc578063d9f00ec711610095578063de5f62681161006f578063de5f626814610a0e578063e752923914610a23578063f1188e4014610a39578063f6ca71b014610a6d57600080fd5b8063d9f00ec714610986578063dbe55e56146109a6578063dd505df6146109da57600080fd5b8063c7af3352146108c9578063c98517c5146108de578063cceab750146108fb578063d059f6ef1461092f578063d38bfff414610946578063d9caed121461096657600080fd5b80639da0e46211610149578063ab12edf511610123578063ab12edf514610854578063ad1728cb14610874578063bb1b918d14610889578063c2e1e3f4146108a957600080fd5b80639da0e462146107b5578063a4f98af4146107f2578063aa388af61461080757600080fd5b8063853828b6146106e757806387bae867146106fc5780638d7c0e46146107215780639092c31c146107415780639136616a1461077557806396d538bb1461079557600080fd5b80635c975abb1161024f57806367c7066c1161020857806371a735f3116101e257806371a735f31461067c5780637b2d9b2c1461069c578063842f5c46146106bc5780638456cb59146106d257600080fd5b806367c7066c1461061c5780636e811d381461063c5780636ef387951461065c57600080fd5b80635c975abb146105635780635d36b190146105875780635f5152261461059c5780636093d380146105bc57806363092383146105f057806366e3667e1461060657600080fd5b8063430bf08a116102a1578063430bf08a14610490578063435356d1146104c457806347e7ef24146104e4578063484be81214610504578063579a7e1a1461051a5780635a063f631461054e57600080fd5b80630c340a24146103a45780630ed57b3a146103d65780630fc3b4c4146103f65780631072cbea1461042c57806322495dc81461044c5780633c8649591461046c57600080fd5b3661039f57336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016148061034c5750336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016145b61039d5760405162461bcd60e51b815260206004820152601e60248201527f657468206e6f742066726f6d20616c6c6f77656420636f6e747261637473000060448201526064015b60405180910390fd5b005b600080fd5b3480156103b057600080fd5b506103b9610a8f565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156103e257600080fd5b5061039d6103f1366004613e46565b610aac565b34801561040257600080fd5b506103b9610411366004613e0c565b609f602052600090815260409020546001600160a01b031681565b34801561043857600080fd5b5061039d610447366004613ec0565b610ade565b34801561045857600080fd5b5061039d610467366004613fb4565b610b9b565b34801561047857600080fd5b5061048260695481565b6040519081526020016103cd565b34801561049c57600080fd5b506103b97f000000000000000000000000000000000000000000000000000000000000000081565b3480156104d057600080fd5b5061039d6104df366004613f2d565b610ce5565b3480156104f057600080fd5b5061039d6104ff366004613ec0565b610dca565b34801561051057600080fd5b50610482606a5481565b34801561052657600080fd5b506103b97f000000000000000000000000000000000000000000000000000000000000000081565b34801561055a57600080fd5b5061039d610ee9565b34801561056f57600080fd5b5060335460ff165b60405190151581526020016103cd565b34801561059357600080fd5b5061039d610f88565b3480156105a857600080fd5b506104826105b7366004613e0c565b61102e565b3480156105c857600080fd5b506103b97f000000000000000000000000000000000000000000000000000000000000000081565b3480156105fc57600080fd5b50610482611c2081565b34801561061257600080fd5b5061048260345481565b34801561062857600080fd5b5060a3546103b9906001600160a01b031681565b34801561064857600080fd5b5061039d610657366004613e0c565b611162565b34801561066857600080fd5b5061039d610677366004613eec565b6111ea565b34801561068857600080fd5b5061039d6106973660046141c2565b611685565b3480156106a857600080fd5b506103b96106b736600461408a565b61187e565b3480156106c857600080fd5b5061048260685481565b3480156106de57600080fd5b5061039d6118a8565b3480156106f357600080fd5b5061039d611971565b34801561070857600080fd5b506033546103b99061010090046001600160a01b031681565b34801561072d57600080fd5b5061039d61073c366004614243565b611b43565b34801561074d57600080fd5b506103b97f000000000000000000000000000000000000000000000000000000000000000081565b34801561078157600080fd5b5061039d61079036600461408a565b612018565b3480156107a157600080fd5b5061039d6107b0366004613eec565b6121e3565b3480156107c157600080fd5b506107e56107d036600461408a565b60356020526000908152604090205460ff1681565b6040516103cd91906146ae565b3480156107fe57600080fd5b50610577612303565b34801561081357600080fd5b50610577610822366004613e0c565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0390811691161490565b34801561086057600080fd5b5061039d61086f366004614288565b612362565b34801561088057600080fd5b5061039d61245e565b34801561089557600080fd5b5061039d6108a436600461410e565b612524565b3480156108b557600080fd5b5061039d6108c4366004613e0c565b612697565b3480156108d557600080fd5b50610577612724565b3480156108ea57600080fd5b506104826801bc16d674ec80000081565b34801561090757600080fd5b506103b97f000000000000000000000000000000000000000000000000000000000000000081565b34801561093b57600080fd5b506104826101075481565b34801561095257600080fd5b5061039d610961366004613e0c565b612755565b34801561097257600080fd5b5061039d610981366004613e7f565b6127f9565b34801561099257600080fd5b5061039d6109a13660046140a3565b61288c565b3480156109b257600080fd5b506103b97f000000000000000000000000000000000000000000000000000000000000000081565b3480156109e657600080fd5b506103b97f000000000000000000000000000000000000000000000000000000000000000081565b348015610a1a57600080fd5b5061039d612a81565b348015610a2f57600080fd5b50610482606b5481565b348015610a4557600080fd5b506103b97f000000000000000000000000000000000000000000000000000000000000000081565b348015610a7957600080fd5b50610a82612bee565b6040516103cd9190614484565b6000610aa7600080516020614a4e8339815191525490565b905090565b610ab4612724565b610ad05760405162461bcd60e51b815260040161039490614720565b610ada8282612c50565b5050565b610ae6612724565b610b025760405162461bcd60e51b815260040161039490614720565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b039081169083161415610b7f5760405162461bcd60e51b815260206004820152601f60248201527f43616e6e6f74207472616e7366657220737570706f72746564206173736574006044820152606401610394565b610ada610b8a610a8f565b6001600160a01b0384169083612daf565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b158015610bf457600080fd5b505afa158015610c08573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c2c9190613e29565b6001600160a01b0316336001600160a01b031614610c5c5760405162461bcd60e51b8152600401610394906147e0565b60405163bc26e7e560e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063bc26e7e590610cae9030908790879087906004016143d4565b600060405180830381600087803b158015610cc857600080fd5b505af1158015610cdc573d6000803e3d6000fd5b50505050505050565b610ced612724565b610d095760405162461bcd60e51b815260040161039490614720565b600054610100900460ff1680610d22575060005460ff16155b610d855760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610394565b600054610100900460ff16158015610da7576000805461ffff19166101011790555b610db2848484612e01565b8015610dc4576000805461ff00191690555b50505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610e125760405162461bcd60e51b8152600401610394906146e9565b600080516020614a2e83398151915280546002811415610e445760405162461bcd60e51b8152600401610394906147b8565b600282557f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316846001600160a01b031614610ebd5760405162461bcd60e51b8152602060048201526011602482015270155b9cdd5c1c1bdc9d195908185cdcd95d607a1b6044820152606401610394565b826101076000828254610ed09190614907565b90915550610ee090508484612ebc565b50600190555050565b60a3546001600160a01b03163314610f435760405162461bcd60e51b815260206004820152601b60248201527f43616c6c6572206973206e6f74207468652048617276657374657200000000006044820152606401610394565b600080516020614a2e83398151915280546002811415610f755760405162461bcd60e51b8152600401610394906147b8565b60028255610f81612f4e565b5060019055565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b0316146110235760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b6064820152608401610394565b61102c3361319c565b565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b0316146110a55760405162461bcd60e51b8152602060048201526011602482015270155b9cdd5c1c1bdc9d195908185cdcd95d607a1b6044820152606401610394565b6040516370a0823160e01b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b15801561110457600080fd5b505afa158015611118573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061113c919061426f565b603454611152906801bc16d674ec80000061491f565b61115c9190614907565b92915050565b61116a612724565b6111865760405162461bcd60e51b815260040161039490614720565b6040516001600160a01b03821681527f83f29c79feb71f8fba9d0fbc4ba5f0982a28b6b1e868b3fc50e6400d100bca0f9060200160405180910390a1603380546001600160a01b0390921661010002610100600160a81b0319909216919091179055565b60335461010090046001600160a01b031633146112195760405162461bcd60e51b815260040161039490614781565b60335460ff161561123c5760405162461bcd60e51b815260040161039490614757565b6000611251826801bc16d674ec80000061491f565b6040516370a0823160e01b81523060048201529091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b1580156112b357600080fd5b505afa1580156112c7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112eb919061426f565b81111561132e5760405162461bcd60e51b81526020600482015260116024820152700d2dce6eaccccd2c6d2cadce840ae8aa89607b1b6044820152606401610394565b604051632e1a7d4d60e01b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561139057600080fd5b505af11580156113a4573d6000803e3d6000fd5b505050506113b18161325d565b8160005b818110156116675760008585838181106113d1576113d16149de565b90506020028101906113e3919061485d565b6113ed9080614817565b6040516113fb9291906143a8565b6040805191829003909120600081815260356020529182205490925060ff169081600381111561142d5761142d6149b2565b1461147a5760405162461bcd60e51b815260206004820152601860248201527f56616c696461746f72206e6f74207265676973746572656400000000000000006044820152606401610394565b60408051600160f81b60208201526000602182018190526bffffffffffffffffffffffff193060601b16602c830152910160405160208183030381529060405290507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663228951186801bc16d674ec8000008a8a88818110611507576115076149de565b9050602002810190611519919061485d565b6115239080614817565b858d8d8b818110611536576115366149de565b9050602002810190611548919061485d565b611556906020810190614817565b8f8f8d818110611568576115686149de565b905060200281019061157a919061485d565b604001356040518863ffffffff1660e01b815260040161159f96959493929190614633565b6000604051808303818588803b1580156115b857600080fd5b505af11580156115cc573d6000803e3d6000fd5b50505050507ffeb31a79d38edb1b090d516e4df3e273651179c6f2c2ec53a9a22ae015b70ba9888886818110611604576116046149de565b9050602002810190611616919061485d565b6116209080614817565b6801bc16d674ec8000008460405161163b9493929190614682565b60405180910390a150506000908152603560205260409020805460ff19166001908117909155016113b5565b50806034600082825461167a9190614907565b909155505050505050565b60335461010090046001600160a01b031633146116b45760405162461bcd60e51b815260040161039490614781565b60335460ff16156116d75760405162461bcd60e51b815260040161039490614757565b60006035600087876040516116ed9291906143a8565b604080519182900390912082526020820192909252016000205460ff1690506002816003811115611720576117206149b2565b146117655760405162461bcd60e51b815260206004820152601560248201527456616c696461746f72206e6f742065786974696e6760581b6044820152606401610394565b6040516312b3fc1960e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906312b3fc19906117b990899089908990899089906004016145f2565b600060405180830381600087803b1580156117d357600080fd5b505af11580156117e7573d6000803e3d6000fd5b505050507ff72821b8777f002ccdf6326f1242d9e0f762eb077668b67bebe640535378066d868686866040516118209493929190614569565b60405180910390a1600360356000888860405161183e9291906143a8565b60408051918290039091208252602082019290925201600020805460ff19166001836003811115611871576118716149b2565b0217905550505050505050565b60a4818154811061188e57600080fd5b6000918252602090912001546001600160a01b0316905081565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b15801561190157600080fd5b505afa158015611915573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119399190613e29565b6001600160a01b0316336001600160a01b0316146119695760405162461bcd60e51b8152600401610394906147e0565b61102c61328a565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614806119c057506119ab610a8f565b6001600160a01b0316336001600160a01b0316145b611a185760405162461bcd60e51b815260206004820152602360248201527f43616c6c6572206973206e6f7420746865205661756c74206f7220476f7665726044820152623737b960e91b6064820152608401610394565b600080516020614a2e83398151915280546002811415611a4a5760405162461bcd60e51b8152600401610394906147b8565b600282556040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b158015611ab057600080fd5b505afa158015611ac4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ae8919061426f565b90508015611b3b57611b3b7f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000836132ff565b505060019055565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b158015611b9c57600080fd5b505afa158015611bb0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bd49190613e29565b6001600160a01b0316336001600160a01b031614611c045760405162461bcd60e51b8152600401610394906147e0565b60335460ff16611c4d5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610394565b43611c20606b54611c5e9190614907565b10611cb95760405162461bcd60e51b815260206004820152602560248201527f6d616e75616c6c794669784163636f756e74696e672063616c6c656420746f6f6044820152641039b7b7b760d91b6064820152608401610394565b6002198312158015611ccc575060038313155b8015611ce65750600083603454611ce391906148c6565b12155b611d325760405162461bcd60e51b815260206004820152601760248201527f696e76616c69642076616c696461746f727344656c74610000000000000000006044820152606401610394565b6811ff6cf0fd15afffff198212158015611d5557506811ff6cf0fd15b000008213155b8015611d6f5750600082606854611d6c91906148c6565b12155b611dbb5760405162461bcd60e51b815260206004820152601d60248201527f696e76616c696420636f6e73656e7375735265776172647344656c74610000006044820152606401610394565b68053444835ec5800000811115611e145760405162461bcd60e51b815260206004820152601960248201527f696e76616c69642077657468546f5661756c74416d6f756e74000000000000006044820152606401610394565b60408051848152602081018490529081018290527f80d022717ea022455c5886b8dd8a29c037570aae58aeb4d7b136d7a10ec2e4319060600160405180910390a182603454611e6391906148c6565b603455606854611e749083906148c6565b60685543606b558015611fc2577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b158015611edc57600080fd5b505af1158015611ef0573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb92506044019050602060405180830381600087803b158015611f8057600080fd5b505af1158015611f94573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fb8919061406d565b50611fc2816133f7565b611fcc600061345f565b61200b5760405162461bcd60e51b815260206004820152601060248201526f333ab9b29039ba34b63610313637bbb760811b6044820152606401610394565b6120136138de565b505050565b612020612724565b61203c5760405162461bcd60e51b815260040161039490614720565b60a054811061207d5760405162461bcd60e51b815260206004820152600d60248201526c092dcecc2d8d2c840d2dcc8caf609b1b6044820152606401610394565b600060a08281548110612092576120926149de565b60009182526020808320909101546001600160a01b03908116808452609f90925260409092205460a054919350909116906120cf9060019061493e565b8310156121515760a080546120e69060019061493e565b815481106120f6576120f66149de565b60009182526020909120015460a080546001600160a01b039092169185908110612122576121226149de565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505b60a0805480612162576121626149c8565b60008281526020808220600019908401810180546001600160a01b031990811690915593019093556001600160a01b03858116808352609f855260409283902080549094169093559051908416815290917f16b7600acff27e39a8a96056b3d533045298de927507f5c1d97e4accde60488c910160405180910390a2505050565b6121eb612724565b6122075760405162461bcd60e51b815260040161039490614720565b8060005b818110156122ba576000848483818110612227576122276149de565b905060200201602081019061223c9190613e0c565b6001600160a01b031614156122aa5760405162461bcd60e51b815260206004820152602e60248201527f43616e206e6f742073657420616e20656d70747920616464726573732061732060448201526d30903932bbb0b932103a37b5b2b760911b6064820152608401610394565b6122b381614981565b905061220b565b507f04c0b9649497d316554306e53678d5f5f5dbc3a06f97dec13ff4cfe98b986bbc60a484846040516122ef939291906144d1565b60405180910390a1610dc460a48484613b65565b60335460009061010090046001600160a01b031633146123355760405162461bcd60e51b815260040161039490614781565b60335460ff16156123585760405162461bcd60e51b815260040161039490614757565b610aa7600161345f565b61236a612724565b6123865760405162461bcd60e51b815260040161039490614720565b808210801561239d57506801bc16d674ec80000082105b80156123b157506801bc16d674ec80000081105b80156123ce5750673782dace9d9000006123cb838361493e565b10155b61241a5760405162461bcd60e51b815260206004820152601760248201527f696e636f7272656374206675736520696e74657276616c0000000000000000006044820152606401610394565b60408051838152602081018390527fcb8d24e46eb3c402bf344ee60a6576cba9ef2f59ea1af3b311520704924e901a910160405180910390a1606991909155606a55565b60405163095ea7b360e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015260001960248301527f0000000000000000000000000000000000000000000000000000000000000000169063095ea7b390604401602060405180830381600087803b1580156124e957600080fd5b505af11580156124fd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612521919061406d565b50565b60335461010090046001600160a01b031633146125535760405162461bcd60e51b815260040161039490614781565b60335460ff16156125765760405162461bcd60e51b815260040161039490614757565b6040516301ba3ee760e21b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906306e8fb9c906125d0908b908b908b908b908b908b908b908b90600401614590565b600060405180830381600087803b1580156125ea57600080fd5b505af11580156125fe573d6000803e3d6000fd5b505050506000603560008a8a6040516126189291906143a8565b60408051918290039091208252602082019290925201600020805460ff1916600183600381111561264b5761264b6149b2565b02179055507f75c4a66b2c6c28cf46db7131182a812e4fbbb2f0591377aa83a737909a9b68c3888888886040516126859493929190614569565b60405180910390a15050505050505050565b61269f612724565b6126bb5760405162461bcd60e51b815260040161039490614720565b60a354604080516001600160a01b03928316815291831660208301527fe48386b84419f4d36e0f96c10cc3510b6fb1a33795620c5098b22472bbe90796910160405180910390a160a380546001600160a01b0319166001600160a01b0392909216919091179055565b600061273c600080516020614a4e8339815191525490565b6001600160a01b0316336001600160a01b031614905090565b61275d612724565b6127795760405162461bcd60e51b815260040161039490614720565b6127a1817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b03166127c1600080516020614a4e8339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146128415760405162461bcd60e51b8152600401610394906146e9565b600080516020614a2e833981519152805460028114156128735760405162461bcd60e51b8152600401610394906147b8565b600282556128828585856132ff565b5060019055505050565b60335461010090046001600160a01b031633146128bb5760405162461bcd60e51b815260040161039490614781565b60335460ff16156128de5760405162461bcd60e51b815260040161039490614757565b60006035600086866040516128f49291906143a8565b604080519182900390912082526020820192909252016000205460ff1690506001816003811115612927576129276149b2565b1461296b5760405162461bcd60e51b815260206004820152601460248201527315985b1a59185d1bdc881b9bdd081cdd185ad95960621b6044820152606401610394565b604051633877322b60e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690633877322b906129bd908890889088908890600401614569565b600060405180830381600087803b1580156129d757600080fd5b505af11580156129eb573d6000803e3d6000fd5b505050507ff8821da16f5ed966b41e0343c3eff9903af782d74f99f1689dd9d4562b6545b385858585604051612a249493929190614569565b60405180910390a16002603560008787604051612a429291906143a8565b60408051918290039091208252602082019290925201600020805460ff19166001836003811115612a7557612a756149b2565b02179055505050505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614612ac95760405162461bcd60e51b8152600401610394906146e9565b600080516020614a2e83398151915280546002811415612afb5760405162461bcd60e51b8152600401610394906147b8565b600282556040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b158015612b6157600080fd5b505afa158015612b75573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b99919061426f565b905060006101075482612bac919061493e565b90508015612be457610107829055612be47f000000000000000000000000000000000000000000000000000000000000000082612ebc565b5050600182555050565b606060a4805480602002602001604051908101604052809291908181526020018280548015612c4657602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612c28575b5050505050905090565b6001600160a01b038281166000908152609f60205260409020541615612cad5760405162461bcd60e51b81526020600482015260126024820152711c151bdad95b88185b1c9958591e481cd95d60721b6044820152606401610394565b6001600160a01b03821615801590612ccd57506001600160a01b03811615155b612d0d5760405162461bcd60e51b8152602060048201526011602482015270496e76616c69642061646472657373657360781b6044820152606401610394565b6001600160a01b038281166000818152609f6020908152604080832080549587166001600160a01b0319968716811790915560a0805460018101825594527f78fdc8d422c49ced035a9edf18d00d3c6a8d81df210f3e5e448e045e77b41e8890930180549095168417909455925190815290917fef6485b84315f9b1483beffa32aae9a0596890395e3d7521f1c5fbb51790e765910160405180910390a25050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052612013908490613958565b8251612e149060a4906020860190613bc8565b50815181518114612e5e5760405162461bcd60e51b8152602060048201526014602482015273496e76616c696420696e7075742061727261797360601b6044820152606401610394565b60005b81811015612eb557612ea5848281518110612e7e57612e7e6149de565b6020026020010151848381518110612e9857612e986149de565b6020026020010151612c50565b612eae81614981565b9050612e61565b5050505050565b60008111612f055760405162461bcd60e51b81526020600482015260166024820152754d757374206465706f73697420736f6d657468696e6760501b6044820152606401610394565b6040805160008152602081018390526001600160a01b038416917f5548c837ab068cf56a2c2479df0882a4922fd203edb7517321831d95078c5f62910160405180910390a25050565b60335460ff1615612f715760405162461bcd60e51b815260040161039490614757565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663e52253816040518163ffffffff1660e01b8152600401602060405180830381600087803b158015612fce57600080fd5b505af1158015612fe2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613006919061426f565b90506000606854826130189190614907565b90508047101561306a5760405162461bcd60e51b815260206004820152601860248201527f696e73756666696369656e74206574682062616c616e636500000000000000006044820152606401610394565b8015610ada5760006068819055507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b1580156130d357600080fd5b505af11580156130e7573d6000803e3d6000fd5b505060a354604080516001600160a01b0392831681527f0000000000000000000000000000000000000000000000000000000000000000909216602083015281018590527ff6c07a063ed4e63808eb8da7112d46dbcd38de2b40a73dbcc9353c5a94c723539350606001915061315a9050565b60405180910390a160a354610ada906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116911683612daf565b6001600160a01b0381166131f25760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f7220697320616464726573732830290000000000006044820152606401610394565b806001600160a01b0316613212600080516020614a4e8339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a361252181600080516020614a4e83398151915255565b600061326c8261010754613a2a565b9050806101076000828254613281919061493e565b90915550505050565b60335460ff16156132ad5760405162461bcd60e51b815260040161039490614757565b6033805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586132e23390565b6040516001600160a01b03909116815260200160405180910390a1565b6000811161334f5760405162461bcd60e51b815260206004820152601760248201527f4d75737420776974686472617720736f6d657468696e670000000000000000006044820152606401610394565b6001600160a01b03831661339e5760405162461bcd60e51b8152602060048201526016602482015275135d5cdd081cdc1958da599e481c9958da5c1a595b9d60521b6044820152606401610394565b6040805160008152602081018390526001600160a01b038416917f2717ead6b9200dd235aad468c9809ea400fe33ac69b5bfaa6d3e90fc922b6398910160405180910390a26120136001600160a01b0383168483612daf565b6040805160008152602081018390526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016917f2717ead6b9200dd235aad468c9809ea400fe33ac69b5bfaa6d3e90fc922b6398910160405180910390a250565b60006068544710156134745761115c82613a42565b600060685447613484919061493e565b9050600191506801bc16d674ec80000081106136615760006801bc16d674ec8000008204905080603460008282546134bc919061493e565b90915550600090506134d7826801bc16d674ec80000061491f565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b15801561353457600080fd5b505af1158015613548573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb92506044019050602060405180830381600087803b1580156135d857600080fd5b505af11580156135ec573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613610919061406d565b5061361a816133f7565b60345460408051848152602081019290925281018290527fbe7040030ff7b347853214bf49820c6d455fedf58f3815f85c7bc5216993682b9060600160405180910390a150505b600060685447613671919061493e565b90506801bc16d674ec80000081106136c35760405162461bcd60e51b8152602060048201526015602482015274756e6578706563746564206163636f756e74696e6760581b6044820152606401610394565b806136cf575050919050565b6069548110156137295780606860008282546136eb9190614907565b90915550506040518181527f7a745a2c63a535068f52ceca27debd5297bbad5f7f37ec53d044a59d0362445d906020015b60405180910390a16138d7565b606a548111156138c6577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b15801561378e57600080fd5b505af11580156137a2573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb92506044019050602060405180830381600087803b15801561383257600080fd5b505af1158015613846573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061386a919061406d565b5060016034600082825461387e919061493e565b9091555061388d9050816133f7565b60345460408051918252602082018390527f6aa7e30787b26429ced603a7aba8b19c4b5d5bcf29a3257da953c8d53bcaa3a6910161371c565b6138cf84613a42565b949350505050565b5050919050565b60335460ff166139275760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610394565b6033805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa336132e2565b60006139ad826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316613a5a9092919063ffffffff16565b80519091501561201357808060200190518101906139cb919061406d565b6120135760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610394565b6000818310613a395781613a3b565b825b9392505050565b60008115613a5257613a5261328a565b506000919050565b60606138cf848460008585843b613ab35760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610394565b600080866001600160a01b03168587604051613acf91906143b8565b60006040518083038185875af1925050503d8060008114613b0c576040519150601f19603f3d011682016040523d82523d6000602084013e613b11565b606091505b5091509150613b21828286613b2c565b979650505050505050565b60608315613b3b575081613a3b565b825115613b4b5782518084602001fd5b8160405162461bcd60e51b815260040161039491906146d6565b828054828255906000526020600020908101928215613bb8579160200282015b82811115613bb85781546001600160a01b0319166001600160a01b03843516178255602090920191600190910190613b85565b50613bc4929150613c1d565b5090565b828054828255906000526020600020908101928215613bb8579160200282015b82811115613bb857825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190613be8565b5b80821115613bc45760008155600101613c1e565b60008083601f840112613c4457600080fd5b5081356001600160401b03811115613c5b57600080fd5b6020830191508360208260051b8501011115613c7657600080fd5b9250929050565b600082601f830112613c8e57600080fd5b81356020613ca3613c9e836148a3565b614873565b80838252828201915082860187848660051b8901011115613cc357600080fd5b60005b85811015613ceb578135613cd981614a0a565b84529284019290840190600101613cc6565b5090979650505050505050565b60008083601f840112613d0a57600080fd5b5081356001600160401b03811115613d2157600080fd5b602083019150836020828501011115613c7657600080fd5b600060a08284031215613d4b57600080fd5b50919050565b600060a08284031215613d6357600080fd5b60405160a081018181106001600160401b0382111715613d8557613d856149f4565b604052905080613d9483613ddc565b8152613da260208401613df5565b6020820152613db360408401613df5565b60408201526060830135613dc681614a1f565b6060820152608092830135920191909152919050565b803563ffffffff81168114613df057600080fd5b919050565b80356001600160401b0381168114613df057600080fd5b600060208284031215613e1e57600080fd5b8135613a3b81614a0a565b600060208284031215613e3b57600080fd5b8151613a3b81614a0a565b60008060408385031215613e5957600080fd5b8235613e6481614a0a565b91506020830135613e7481614a0a565b809150509250929050565b600080600060608486031215613e9457600080fd5b8335613e9f81614a0a565b92506020840135613eaf81614a0a565b929592945050506040919091013590565b60008060408385031215613ed357600080fd5b8235613ede81614a0a565b946020939093013593505050565b60008060208385031215613eff57600080fd5b82356001600160401b03811115613f1557600080fd5b613f2185828601613c32565b90969095509350505050565b600080600060608486031215613f4257600080fd5b83356001600160401b0380821115613f5957600080fd5b613f6587838801613c7d565b94506020860135915080821115613f7b57600080fd5b613f8787838801613c7d565b93506040860135915080821115613f9d57600080fd5b50613faa86828701613c7d565b9150509250925092565b600080600060e08486031215613fc957600080fd5b83356001600160401b03811115613fdf57600080fd5b8401601f81018613613ff057600080fd5b80356020614000613c9e836148a3565b8083825282820191508285018a848660051b880101111561402057600080fd5b600095505b8486101561404a5761403681613df5565b835260019590950194918301918301614025565b509650508601359350614064915086905060408601613d51565b90509250925092565b60006020828403121561407f57600080fd5b8151613a3b81614a1f565b60006020828403121561409c57600080fd5b5035919050565b600080600080604085870312156140b957600080fd5b84356001600160401b03808211156140d057600080fd5b6140dc88838901613cf8565b909650945060208701359150808211156140f557600080fd5b5061410287828801613c32565b95989497509550505050565b600080600080600080600080610120898b03121561412b57600080fd5b88356001600160401b038082111561414257600080fd5b61414e8c838d01613cf8565b909a50985060208b013591508082111561416757600080fd5b6141738c838d01613c32565b909850965060408b013591508082111561418c57600080fd5b506141998b828c01613cf8565b909550935050606089013591506141b38a60808b01613d39565b90509295985092959890939650565b600080600080600060e086880312156141da57600080fd5b85356001600160401b03808211156141f157600080fd5b6141fd89838a01613cf8565b9097509550602088013591508082111561421657600080fd5b5061422388828901613c32565b909450925061423790508760408801613d39565b90509295509295909350565b60008060006060848603121561425857600080fd5b505081359360208301359350604090920135919050565b60006020828403121561428157600080fd5b5051919050565b6000806040838503121561429b57600080fd5b50508035926020909101359150565b8183526000602080850194508260005b858110156142e6576001600160401b036142d383613df5565b16875295820195908201906001016142ba565b509495945050505050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b60008151808452614332816020860160208601614955565b601f01601f19169290920160200192915050565b63ffffffff61435482613ddc565b16825261436360208201613df5565b6001600160401b0380821660208501528061438060408501613df5565b1660408501525050606081013561439681614a1f565b15156060830152608090810135910152565b8183823760009101908152919050565b600082516143ca818460208701614955565b9190910192915050565b6001600160a01b03851681526101006020808301829052855191830182905260009161012084019187810191845b818110156144275783516001600160401b031685529382019392820192600101614402565b505082935086604086015263ffffffff865116606086015280860151925050506001600160401b0380821660808501528060408601511660a085015250506060830151151560c0830152608083015160e083015295945050505050565b6020808252825182820181905260009190848201906040850190845b818110156144c55783516001600160a01b0316835292840192918401916001016144a0565b50909695505050505050565b6000604082016040835280865480835260608501915087600052602092508260002060005b8281101561451b5781546001600160a01b0316845292840192600191820191016144f6565b505050838103828501528481528590820160005b8681101561455d57823561454281614a0a565b6001600160a01b03168252918301919083019060010161452f565b50979650505050505050565b60408152600061457d6040830186886142f1565b8281036020840152613b218185876142aa565b60006101208083526145a58184018b8d6142f1565b905082810360208401526145ba81898b6142aa565b905082810360408401526145cf8187896142f1565b9150508360608301526145e56080830184614346565b9998505050505050505050565b60e08152600061460660e0830187896142f1565b82810360208401526146198186886142aa565b9150506146296040830184614346565b9695505050505050565b60808152600061464760808301888a6142f1565b8281036020840152614659818861431a565b9050828103604084015261466e8186886142f1565b915050826060830152979650505050505050565b6060815260006146966060830186886142f1565b8460208401528281036040840152613b21818561431a565b60208101600483106146d057634e487b7160e01b600052602160045260246000fd5b91905290565b602081526000613a3b602083018461431a565b60208082526017908201527f43616c6c6572206973206e6f7420746865205661756c74000000000000000000604082015260600190565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b60208082526010908201526f14185d5cd8589b194e881c185d5cd95960821b604082015260600190565b6020808252601d908201527f43616c6c6572206973206e6f7420746865205265676973747261746f72000000604082015260600190565b6020808252600e908201526d1499595b9d1c985b9d0818d85b1b60921b604082015260600190565b6020808252601c908201527f43616c6c6572206973206e6f7420746865205374726174656769737400000000604082015260600190565b6000808335601e1984360301811261482e57600080fd5b8301803591506001600160401b0382111561484857600080fd5b602001915036819003821315613c7657600080fd5b60008235605e198336030181126143ca57600080fd5b604051601f8201601f191681016001600160401b038111828210171561489b5761489b6149f4565b604052919050565b60006001600160401b038211156148bc576148bc6149f4565b5060051b60200190565b600080821280156001600160ff1b03849003851316156148e8576148e861499c565b600160ff1b83900384128116156149015761490161499c565b50500190565b6000821982111561491a5761491a61499c565b500190565b60008160001904831182151516156149395761493961499c565b500290565b6000828210156149505761495061499c565b500390565b60005b83811015614970578181015183820152602001614958565b83811115610dc45750506000910152565b60006000198214156149955761499561499c565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b038116811461252157600080fd5b801515811461252157600080fdfe53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac45357bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa2646970667358221220e7e50cde0c8998aadaf7928bf094efc09a4ab9f91b5a4d0db51e66b9307dc59264736f6c634300080700337bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a", + "deployedBytecode": "0x6080604052600436106102e85760003560e01c8063853828b611610190578063c7af3352116100dc578063d9f00ec711610095578063de5f62681161006f578063de5f626814610a0e578063e752923914610a23578063f1188e4014610a39578063f6ca71b014610a6d57600080fd5b8063d9f00ec714610986578063dbe55e56146109a6578063dd505df6146109da57600080fd5b8063c7af3352146108c9578063c98517c5146108de578063cceab750146108fb578063d059f6ef1461092f578063d38bfff414610946578063d9caed121461096657600080fd5b80639da0e46211610149578063ab12edf511610123578063ab12edf514610854578063ad1728cb14610874578063bb1b918d14610889578063c2e1e3f4146108a957600080fd5b80639da0e462146107b5578063a4f98af4146107f2578063aa388af61461080757600080fd5b8063853828b6146106e757806387bae867146106fc5780638d7c0e46146107215780639092c31c146107415780639136616a1461077557806396d538bb1461079557600080fd5b80635c975abb1161024f57806367c7066c1161020857806371a735f3116101e257806371a735f31461067c5780637b2d9b2c1461069c578063842f5c46146106bc5780638456cb59146106d257600080fd5b806367c7066c1461061c5780636e811d381461063c5780636ef387951461065c57600080fd5b80635c975abb146105635780635d36b190146105875780635f5152261461059c5780636093d380146105bc57806363092383146105f057806366e3667e1461060657600080fd5b8063430bf08a116102a1578063430bf08a14610490578063435356d1146104c457806347e7ef24146104e4578063484be81214610504578063579a7e1a1461051a5780635a063f631461054e57600080fd5b80630c340a24146103a45780630ed57b3a146103d65780630fc3b4c4146103f65780631072cbea1461042c57806322495dc81461044c5780633c8649591461046c57600080fd5b3661039f57336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016148061034c5750336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016145b61039d5760405162461bcd60e51b815260206004820152601e60248201527f657468206e6f742066726f6d20616c6c6f77656420636f6e747261637473000060448201526064015b60405180910390fd5b005b600080fd5b3480156103b057600080fd5b506103b9610a8f565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156103e257600080fd5b5061039d6103f1366004613e46565b610aac565b34801561040257600080fd5b506103b9610411366004613e0c565b609f602052600090815260409020546001600160a01b031681565b34801561043857600080fd5b5061039d610447366004613ec0565b610ade565b34801561045857600080fd5b5061039d610467366004613fb4565b610b9b565b34801561047857600080fd5b5061048260695481565b6040519081526020016103cd565b34801561049c57600080fd5b506103b97f000000000000000000000000000000000000000000000000000000000000000081565b3480156104d057600080fd5b5061039d6104df366004613f2d565b610ce5565b3480156104f057600080fd5b5061039d6104ff366004613ec0565b610dca565b34801561051057600080fd5b50610482606a5481565b34801561052657600080fd5b506103b97f000000000000000000000000000000000000000000000000000000000000000081565b34801561055a57600080fd5b5061039d610ee9565b34801561056f57600080fd5b5060335460ff165b60405190151581526020016103cd565b34801561059357600080fd5b5061039d610f88565b3480156105a857600080fd5b506104826105b7366004613e0c565b61102e565b3480156105c857600080fd5b506103b97f000000000000000000000000000000000000000000000000000000000000000081565b3480156105fc57600080fd5b50610482611c2081565b34801561061257600080fd5b5061048260345481565b34801561062857600080fd5b5060a3546103b9906001600160a01b031681565b34801561064857600080fd5b5061039d610657366004613e0c565b611162565b34801561066857600080fd5b5061039d610677366004613eec565b6111ea565b34801561068857600080fd5b5061039d6106973660046141c2565b611685565b3480156106a857600080fd5b506103b96106b736600461408a565b61187e565b3480156106c857600080fd5b5061048260685481565b3480156106de57600080fd5b5061039d6118a8565b3480156106f357600080fd5b5061039d611971565b34801561070857600080fd5b506033546103b99061010090046001600160a01b031681565b34801561072d57600080fd5b5061039d61073c366004614243565b611b43565b34801561074d57600080fd5b506103b97f000000000000000000000000000000000000000000000000000000000000000081565b34801561078157600080fd5b5061039d61079036600461408a565b612018565b3480156107a157600080fd5b5061039d6107b0366004613eec565b6121e3565b3480156107c157600080fd5b506107e56107d036600461408a565b60356020526000908152604090205460ff1681565b6040516103cd91906146ae565b3480156107fe57600080fd5b50610577612303565b34801561081357600080fd5b50610577610822366004613e0c565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0390811691161490565b34801561086057600080fd5b5061039d61086f366004614288565b612362565b34801561088057600080fd5b5061039d61245e565b34801561089557600080fd5b5061039d6108a436600461410e565b612524565b3480156108b557600080fd5b5061039d6108c4366004613e0c565b612697565b3480156108d557600080fd5b50610577612724565b3480156108ea57600080fd5b506104826801bc16d674ec80000081565b34801561090757600080fd5b506103b97f000000000000000000000000000000000000000000000000000000000000000081565b34801561093b57600080fd5b506104826101075481565b34801561095257600080fd5b5061039d610961366004613e0c565b612755565b34801561097257600080fd5b5061039d610981366004613e7f565b6127f9565b34801561099257600080fd5b5061039d6109a13660046140a3565b61288c565b3480156109b257600080fd5b506103b97f000000000000000000000000000000000000000000000000000000000000000081565b3480156109e657600080fd5b506103b97f000000000000000000000000000000000000000000000000000000000000000081565b348015610a1a57600080fd5b5061039d612a81565b348015610a2f57600080fd5b50610482606b5481565b348015610a4557600080fd5b506103b97f000000000000000000000000000000000000000000000000000000000000000081565b348015610a7957600080fd5b50610a82612bee565b6040516103cd9190614484565b6000610aa7600080516020614a4e8339815191525490565b905090565b610ab4612724565b610ad05760405162461bcd60e51b815260040161039490614720565b610ada8282612c50565b5050565b610ae6612724565b610b025760405162461bcd60e51b815260040161039490614720565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b039081169083161415610b7f5760405162461bcd60e51b815260206004820152601f60248201527f43616e6e6f74207472616e7366657220737570706f72746564206173736574006044820152606401610394565b610ada610b8a610a8f565b6001600160a01b0384169083612daf565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b158015610bf457600080fd5b505afa158015610c08573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c2c9190613e29565b6001600160a01b0316336001600160a01b031614610c5c5760405162461bcd60e51b8152600401610394906147e0565b60405163bc26e7e560e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063bc26e7e590610cae9030908790879087906004016143d4565b600060405180830381600087803b158015610cc857600080fd5b505af1158015610cdc573d6000803e3d6000fd5b50505050505050565b610ced612724565b610d095760405162461bcd60e51b815260040161039490614720565b600054610100900460ff1680610d22575060005460ff16155b610d855760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610394565b600054610100900460ff16158015610da7576000805461ffff19166101011790555b610db2848484612e01565b8015610dc4576000805461ff00191690555b50505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610e125760405162461bcd60e51b8152600401610394906146e9565b600080516020614a2e83398151915280546002811415610e445760405162461bcd60e51b8152600401610394906147b8565b600282557f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316846001600160a01b031614610ebd5760405162461bcd60e51b8152602060048201526011602482015270155b9cdd5c1c1bdc9d195908185cdcd95d607a1b6044820152606401610394565b826101076000828254610ed09190614907565b90915550610ee090508484612ebc565b50600190555050565b60a3546001600160a01b03163314610f435760405162461bcd60e51b815260206004820152601b60248201527f43616c6c6572206973206e6f74207468652048617276657374657200000000006044820152606401610394565b600080516020614a2e83398151915280546002811415610f755760405162461bcd60e51b8152600401610394906147b8565b60028255610f81612f4e565b5060019055565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b0316146110235760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b6064820152608401610394565b61102c3361319c565b565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b0316146110a55760405162461bcd60e51b8152602060048201526011602482015270155b9cdd5c1c1bdc9d195908185cdcd95d607a1b6044820152606401610394565b6040516370a0823160e01b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b15801561110457600080fd5b505afa158015611118573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061113c919061426f565b603454611152906801bc16d674ec80000061491f565b61115c9190614907565b92915050565b61116a612724565b6111865760405162461bcd60e51b815260040161039490614720565b6040516001600160a01b03821681527f83f29c79feb71f8fba9d0fbc4ba5f0982a28b6b1e868b3fc50e6400d100bca0f9060200160405180910390a1603380546001600160a01b0390921661010002610100600160a81b0319909216919091179055565b60335461010090046001600160a01b031633146112195760405162461bcd60e51b815260040161039490614781565b60335460ff161561123c5760405162461bcd60e51b815260040161039490614757565b6000611251826801bc16d674ec80000061491f565b6040516370a0823160e01b81523060048201529091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b1580156112b357600080fd5b505afa1580156112c7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112eb919061426f565b81111561132e5760405162461bcd60e51b81526020600482015260116024820152700d2dce6eaccccd2c6d2cadce840ae8aa89607b1b6044820152606401610394565b604051632e1a7d4d60e01b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561139057600080fd5b505af11580156113a4573d6000803e3d6000fd5b505050506113b18161325d565b8160005b818110156116675760008585838181106113d1576113d16149de565b90506020028101906113e3919061485d565b6113ed9080614817565b6040516113fb9291906143a8565b6040805191829003909120600081815260356020529182205490925060ff169081600381111561142d5761142d6149b2565b1461147a5760405162461bcd60e51b815260206004820152601860248201527f56616c696461746f72206e6f74207265676973746572656400000000000000006044820152606401610394565b60408051600160f81b60208201526000602182018190526bffffffffffffffffffffffff193060601b16602c830152910160405160208183030381529060405290507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663228951186801bc16d674ec8000008a8a88818110611507576115076149de565b9050602002810190611519919061485d565b6115239080614817565b858d8d8b818110611536576115366149de565b9050602002810190611548919061485d565b611556906020810190614817565b8f8f8d818110611568576115686149de565b905060200281019061157a919061485d565b604001356040518863ffffffff1660e01b815260040161159f96959493929190614633565b6000604051808303818588803b1580156115b857600080fd5b505af11580156115cc573d6000803e3d6000fd5b50505050507ffeb31a79d38edb1b090d516e4df3e273651179c6f2c2ec53a9a22ae015b70ba9888886818110611604576116046149de565b9050602002810190611616919061485d565b6116209080614817565b6801bc16d674ec8000008460405161163b9493929190614682565b60405180910390a150506000908152603560205260409020805460ff19166001908117909155016113b5565b50806034600082825461167a9190614907565b909155505050505050565b60335461010090046001600160a01b031633146116b45760405162461bcd60e51b815260040161039490614781565b60335460ff16156116d75760405162461bcd60e51b815260040161039490614757565b60006035600087876040516116ed9291906143a8565b604080519182900390912082526020820192909252016000205460ff1690506002816003811115611720576117206149b2565b146117655760405162461bcd60e51b815260206004820152601560248201527456616c696461746f72206e6f742065786974696e6760581b6044820152606401610394565b6040516312b3fc1960e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906312b3fc19906117b990899089908990899089906004016145f2565b600060405180830381600087803b1580156117d357600080fd5b505af11580156117e7573d6000803e3d6000fd5b505050507ff72821b8777f002ccdf6326f1242d9e0f762eb077668b67bebe640535378066d868686866040516118209493929190614569565b60405180910390a1600360356000888860405161183e9291906143a8565b60408051918290039091208252602082019290925201600020805460ff19166001836003811115611871576118716149b2565b0217905550505050505050565b60a4818154811061188e57600080fd5b6000918252602090912001546001600160a01b0316905081565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b15801561190157600080fd5b505afa158015611915573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119399190613e29565b6001600160a01b0316336001600160a01b0316146119695760405162461bcd60e51b8152600401610394906147e0565b61102c61328a565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614806119c057506119ab610a8f565b6001600160a01b0316336001600160a01b0316145b611a185760405162461bcd60e51b815260206004820152602360248201527f43616c6c6572206973206e6f7420746865205661756c74206f7220476f7665726044820152623737b960e91b6064820152608401610394565b600080516020614a2e83398151915280546002811415611a4a5760405162461bcd60e51b8152600401610394906147b8565b600282556040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b158015611ab057600080fd5b505afa158015611ac4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ae8919061426f565b90508015611b3b57611b3b7f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000836132ff565b505060019055565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b158015611b9c57600080fd5b505afa158015611bb0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bd49190613e29565b6001600160a01b0316336001600160a01b031614611c045760405162461bcd60e51b8152600401610394906147e0565b60335460ff16611c4d5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610394565b43611c20606b54611c5e9190614907565b10611cb95760405162461bcd60e51b815260206004820152602560248201527f6d616e75616c6c794669784163636f756e74696e672063616c6c656420746f6f6044820152641039b7b7b760d91b6064820152608401610394565b6002198312158015611ccc575060038313155b8015611ce65750600083603454611ce391906148c6565b12155b611d325760405162461bcd60e51b815260206004820152601760248201527f696e76616c69642076616c696461746f727344656c74610000000000000000006044820152606401610394565b6811ff6cf0fd15afffff198212158015611d5557506811ff6cf0fd15b000008213155b8015611d6f5750600082606854611d6c91906148c6565b12155b611dbb5760405162461bcd60e51b815260206004820152601d60248201527f696e76616c696420636f6e73656e7375735265776172647344656c74610000006044820152606401610394565b68053444835ec5800000811115611e145760405162461bcd60e51b815260206004820152601960248201527f696e76616c69642077657468546f5661756c74416d6f756e74000000000000006044820152606401610394565b60408051848152602081018490529081018290527f80d022717ea022455c5886b8dd8a29c037570aae58aeb4d7b136d7a10ec2e4319060600160405180910390a182603454611e6391906148c6565b603455606854611e749083906148c6565b60685543606b558015611fc2577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b158015611edc57600080fd5b505af1158015611ef0573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb92506044019050602060405180830381600087803b158015611f8057600080fd5b505af1158015611f94573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fb8919061406d565b50611fc2816133f7565b611fcc600061345f565b61200b5760405162461bcd60e51b815260206004820152601060248201526f333ab9b29039ba34b63610313637bbb760811b6044820152606401610394565b6120136138de565b505050565b612020612724565b61203c5760405162461bcd60e51b815260040161039490614720565b60a054811061207d5760405162461bcd60e51b815260206004820152600d60248201526c092dcecc2d8d2c840d2dcc8caf609b1b6044820152606401610394565b600060a08281548110612092576120926149de565b60009182526020808320909101546001600160a01b03908116808452609f90925260409092205460a054919350909116906120cf9060019061493e565b8310156121515760a080546120e69060019061493e565b815481106120f6576120f66149de565b60009182526020909120015460a080546001600160a01b039092169185908110612122576121226149de565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505b60a0805480612162576121626149c8565b60008281526020808220600019908401810180546001600160a01b031990811690915593019093556001600160a01b03858116808352609f855260409283902080549094169093559051908416815290917f16b7600acff27e39a8a96056b3d533045298de927507f5c1d97e4accde60488c910160405180910390a2505050565b6121eb612724565b6122075760405162461bcd60e51b815260040161039490614720565b8060005b818110156122ba576000848483818110612227576122276149de565b905060200201602081019061223c9190613e0c565b6001600160a01b031614156122aa5760405162461bcd60e51b815260206004820152602e60248201527f43616e206e6f742073657420616e20656d70747920616464726573732061732060448201526d30903932bbb0b932103a37b5b2b760911b6064820152608401610394565b6122b381614981565b905061220b565b507f04c0b9649497d316554306e53678d5f5f5dbc3a06f97dec13ff4cfe98b986bbc60a484846040516122ef939291906144d1565b60405180910390a1610dc460a48484613b65565b60335460009061010090046001600160a01b031633146123355760405162461bcd60e51b815260040161039490614781565b60335460ff16156123585760405162461bcd60e51b815260040161039490614757565b610aa7600161345f565b61236a612724565b6123865760405162461bcd60e51b815260040161039490614720565b808210801561239d57506801bc16d674ec80000082105b80156123b157506801bc16d674ec80000081105b80156123ce5750673782dace9d9000006123cb838361493e565b10155b61241a5760405162461bcd60e51b815260206004820152601760248201527f696e636f7272656374206675736520696e74657276616c0000000000000000006044820152606401610394565b60408051838152602081018390527fcb8d24e46eb3c402bf344ee60a6576cba9ef2f59ea1af3b311520704924e901a910160405180910390a1606991909155606a55565b60405163095ea7b360e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015260001960248301527f0000000000000000000000000000000000000000000000000000000000000000169063095ea7b390604401602060405180830381600087803b1580156124e957600080fd5b505af11580156124fd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612521919061406d565b50565b60335461010090046001600160a01b031633146125535760405162461bcd60e51b815260040161039490614781565b60335460ff16156125765760405162461bcd60e51b815260040161039490614757565b6040516301ba3ee760e21b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906306e8fb9c906125d0908b908b908b908b908b908b908b908b90600401614590565b600060405180830381600087803b1580156125ea57600080fd5b505af11580156125fe573d6000803e3d6000fd5b505050506000603560008a8a6040516126189291906143a8565b60408051918290039091208252602082019290925201600020805460ff1916600183600381111561264b5761264b6149b2565b02179055507f75c4a66b2c6c28cf46db7131182a812e4fbbb2f0591377aa83a737909a9b68c3888888886040516126859493929190614569565b60405180910390a15050505050505050565b61269f612724565b6126bb5760405162461bcd60e51b815260040161039490614720565b60a354604080516001600160a01b03928316815291831660208301527fe48386b84419f4d36e0f96c10cc3510b6fb1a33795620c5098b22472bbe90796910160405180910390a160a380546001600160a01b0319166001600160a01b0392909216919091179055565b600061273c600080516020614a4e8339815191525490565b6001600160a01b0316336001600160a01b031614905090565b61275d612724565b6127795760405162461bcd60e51b815260040161039490614720565b6127a1817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b03166127c1600080516020614a4e8339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146128415760405162461bcd60e51b8152600401610394906146e9565b600080516020614a2e833981519152805460028114156128735760405162461bcd60e51b8152600401610394906147b8565b600282556128828585856132ff565b5060019055505050565b60335461010090046001600160a01b031633146128bb5760405162461bcd60e51b815260040161039490614781565b60335460ff16156128de5760405162461bcd60e51b815260040161039490614757565b60006035600086866040516128f49291906143a8565b604080519182900390912082526020820192909252016000205460ff1690506001816003811115612927576129276149b2565b1461296b5760405162461bcd60e51b815260206004820152601460248201527315985b1a59185d1bdc881b9bdd081cdd185ad95960621b6044820152606401610394565b604051633877322b60e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690633877322b906129bd908890889088908890600401614569565b600060405180830381600087803b1580156129d757600080fd5b505af11580156129eb573d6000803e3d6000fd5b505050507ff8821da16f5ed966b41e0343c3eff9903af782d74f99f1689dd9d4562b6545b385858585604051612a249493929190614569565b60405180910390a16002603560008787604051612a429291906143a8565b60408051918290039091208252602082019290925201600020805460ff19166001836003811115612a7557612a756149b2565b02179055505050505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614612ac95760405162461bcd60e51b8152600401610394906146e9565b600080516020614a2e83398151915280546002811415612afb5760405162461bcd60e51b8152600401610394906147b8565b600282556040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b158015612b6157600080fd5b505afa158015612b75573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b99919061426f565b905060006101075482612bac919061493e565b90508015612be457610107829055612be47f000000000000000000000000000000000000000000000000000000000000000082612ebc565b5050600182555050565b606060a4805480602002602001604051908101604052809291908181526020018280548015612c4657602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612c28575b5050505050905090565b6001600160a01b038281166000908152609f60205260409020541615612cad5760405162461bcd60e51b81526020600482015260126024820152711c151bdad95b88185b1c9958591e481cd95d60721b6044820152606401610394565b6001600160a01b03821615801590612ccd57506001600160a01b03811615155b612d0d5760405162461bcd60e51b8152602060048201526011602482015270496e76616c69642061646472657373657360781b6044820152606401610394565b6001600160a01b038281166000818152609f6020908152604080832080549587166001600160a01b0319968716811790915560a0805460018101825594527f78fdc8d422c49ced035a9edf18d00d3c6a8d81df210f3e5e448e045e77b41e8890930180549095168417909455925190815290917fef6485b84315f9b1483beffa32aae9a0596890395e3d7521f1c5fbb51790e765910160405180910390a25050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052612013908490613958565b8251612e149060a4906020860190613bc8565b50815181518114612e5e5760405162461bcd60e51b8152602060048201526014602482015273496e76616c696420696e7075742061727261797360601b6044820152606401610394565b60005b81811015612eb557612ea5848281518110612e7e57612e7e6149de565b6020026020010151848381518110612e9857612e986149de565b6020026020010151612c50565b612eae81614981565b9050612e61565b5050505050565b60008111612f055760405162461bcd60e51b81526020600482015260166024820152754d757374206465706f73697420736f6d657468696e6760501b6044820152606401610394565b6040805160008152602081018390526001600160a01b038416917f5548c837ab068cf56a2c2479df0882a4922fd203edb7517321831d95078c5f62910160405180910390a25050565b60335460ff1615612f715760405162461bcd60e51b815260040161039490614757565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663e52253816040518163ffffffff1660e01b8152600401602060405180830381600087803b158015612fce57600080fd5b505af1158015612fe2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613006919061426f565b90506000606854826130189190614907565b90508047101561306a5760405162461bcd60e51b815260206004820152601860248201527f696e73756666696369656e74206574682062616c616e636500000000000000006044820152606401610394565b8015610ada5760006068819055507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b1580156130d357600080fd5b505af11580156130e7573d6000803e3d6000fd5b505060a354604080516001600160a01b0392831681527f0000000000000000000000000000000000000000000000000000000000000000909216602083015281018590527ff6c07a063ed4e63808eb8da7112d46dbcd38de2b40a73dbcc9353c5a94c723539350606001915061315a9050565b60405180910390a160a354610ada906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116911683612daf565b6001600160a01b0381166131f25760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f7220697320616464726573732830290000000000006044820152606401610394565b806001600160a01b0316613212600080516020614a4e8339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a361252181600080516020614a4e83398151915255565b600061326c8261010754613a2a565b9050806101076000828254613281919061493e565b90915550505050565b60335460ff16156132ad5760405162461bcd60e51b815260040161039490614757565b6033805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586132e23390565b6040516001600160a01b03909116815260200160405180910390a1565b6000811161334f5760405162461bcd60e51b815260206004820152601760248201527f4d75737420776974686472617720736f6d657468696e670000000000000000006044820152606401610394565b6001600160a01b03831661339e5760405162461bcd60e51b8152602060048201526016602482015275135d5cdd081cdc1958da599e481c9958da5c1a595b9d60521b6044820152606401610394565b6040805160008152602081018390526001600160a01b038416917f2717ead6b9200dd235aad468c9809ea400fe33ac69b5bfaa6d3e90fc922b6398910160405180910390a26120136001600160a01b0383168483612daf565b6040805160008152602081018390526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016917f2717ead6b9200dd235aad468c9809ea400fe33ac69b5bfaa6d3e90fc922b6398910160405180910390a250565b60006068544710156134745761115c82613a42565b600060685447613484919061493e565b9050600191506801bc16d674ec80000081106136615760006801bc16d674ec8000008204905080603460008282546134bc919061493e565b90915550600090506134d7826801bc16d674ec80000061491f565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b15801561353457600080fd5b505af1158015613548573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb92506044019050602060405180830381600087803b1580156135d857600080fd5b505af11580156135ec573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613610919061406d565b5061361a816133f7565b60345460408051848152602081019290925281018290527fbe7040030ff7b347853214bf49820c6d455fedf58f3815f85c7bc5216993682b9060600160405180910390a150505b600060685447613671919061493e565b90506801bc16d674ec80000081106136c35760405162461bcd60e51b8152602060048201526015602482015274756e6578706563746564206163636f756e74696e6760581b6044820152606401610394565b806136cf575050919050565b6069548110156137295780606860008282546136eb9190614907565b90915550506040518181527f7a745a2c63a535068f52ceca27debd5297bbad5f7f37ec53d044a59d0362445d906020015b60405180910390a16138d7565b606a548111156138c6577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b15801561378e57600080fd5b505af11580156137a2573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb92506044019050602060405180830381600087803b15801561383257600080fd5b505af1158015613846573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061386a919061406d565b5060016034600082825461387e919061493e565b9091555061388d9050816133f7565b60345460408051918252602082018390527f6aa7e30787b26429ced603a7aba8b19c4b5d5bcf29a3257da953c8d53bcaa3a6910161371c565b6138cf84613a42565b949350505050565b5050919050565b60335460ff166139275760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610394565b6033805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa336132e2565b60006139ad826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316613a5a9092919063ffffffff16565b80519091501561201357808060200190518101906139cb919061406d565b6120135760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610394565b6000818310613a395781613a3b565b825b9392505050565b60008115613a5257613a5261328a565b506000919050565b60606138cf848460008585843b613ab35760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610394565b600080866001600160a01b03168587604051613acf91906143b8565b60006040518083038185875af1925050503d8060008114613b0c576040519150601f19603f3d011682016040523d82523d6000602084013e613b11565b606091505b5091509150613b21828286613b2c565b979650505050505050565b60608315613b3b575081613a3b565b825115613b4b5782518084602001fd5b8160405162461bcd60e51b815260040161039491906146d6565b828054828255906000526020600020908101928215613bb8579160200282015b82811115613bb85781546001600160a01b0319166001600160a01b03843516178255602090920191600190910190613b85565b50613bc4929150613c1d565b5090565b828054828255906000526020600020908101928215613bb8579160200282015b82811115613bb857825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190613be8565b5b80821115613bc45760008155600101613c1e565b60008083601f840112613c4457600080fd5b5081356001600160401b03811115613c5b57600080fd5b6020830191508360208260051b8501011115613c7657600080fd5b9250929050565b600082601f830112613c8e57600080fd5b81356020613ca3613c9e836148a3565b614873565b80838252828201915082860187848660051b8901011115613cc357600080fd5b60005b85811015613ceb578135613cd981614a0a565b84529284019290840190600101613cc6565b5090979650505050505050565b60008083601f840112613d0a57600080fd5b5081356001600160401b03811115613d2157600080fd5b602083019150836020828501011115613c7657600080fd5b600060a08284031215613d4b57600080fd5b50919050565b600060a08284031215613d6357600080fd5b60405160a081018181106001600160401b0382111715613d8557613d856149f4565b604052905080613d9483613ddc565b8152613da260208401613df5565b6020820152613db360408401613df5565b60408201526060830135613dc681614a1f565b6060820152608092830135920191909152919050565b803563ffffffff81168114613df057600080fd5b919050565b80356001600160401b0381168114613df057600080fd5b600060208284031215613e1e57600080fd5b8135613a3b81614a0a565b600060208284031215613e3b57600080fd5b8151613a3b81614a0a565b60008060408385031215613e5957600080fd5b8235613e6481614a0a565b91506020830135613e7481614a0a565b809150509250929050565b600080600060608486031215613e9457600080fd5b8335613e9f81614a0a565b92506020840135613eaf81614a0a565b929592945050506040919091013590565b60008060408385031215613ed357600080fd5b8235613ede81614a0a565b946020939093013593505050565b60008060208385031215613eff57600080fd5b82356001600160401b03811115613f1557600080fd5b613f2185828601613c32565b90969095509350505050565b600080600060608486031215613f4257600080fd5b83356001600160401b0380821115613f5957600080fd5b613f6587838801613c7d565b94506020860135915080821115613f7b57600080fd5b613f8787838801613c7d565b93506040860135915080821115613f9d57600080fd5b50613faa86828701613c7d565b9150509250925092565b600080600060e08486031215613fc957600080fd5b83356001600160401b03811115613fdf57600080fd5b8401601f81018613613ff057600080fd5b80356020614000613c9e836148a3565b8083825282820191508285018a848660051b880101111561402057600080fd5b600095505b8486101561404a5761403681613df5565b835260019590950194918301918301614025565b509650508601359350614064915086905060408601613d51565b90509250925092565b60006020828403121561407f57600080fd5b8151613a3b81614a1f565b60006020828403121561409c57600080fd5b5035919050565b600080600080604085870312156140b957600080fd5b84356001600160401b03808211156140d057600080fd5b6140dc88838901613cf8565b909650945060208701359150808211156140f557600080fd5b5061410287828801613c32565b95989497509550505050565b600080600080600080600080610120898b03121561412b57600080fd5b88356001600160401b038082111561414257600080fd5b61414e8c838d01613cf8565b909a50985060208b013591508082111561416757600080fd5b6141738c838d01613c32565b909850965060408b013591508082111561418c57600080fd5b506141998b828c01613cf8565b909550935050606089013591506141b38a60808b01613d39565b90509295985092959890939650565b600080600080600060e086880312156141da57600080fd5b85356001600160401b03808211156141f157600080fd5b6141fd89838a01613cf8565b9097509550602088013591508082111561421657600080fd5b5061422388828901613c32565b909450925061423790508760408801613d39565b90509295509295909350565b60008060006060848603121561425857600080fd5b505081359360208301359350604090920135919050565b60006020828403121561428157600080fd5b5051919050565b6000806040838503121561429b57600080fd5b50508035926020909101359150565b8183526000602080850194508260005b858110156142e6576001600160401b036142d383613df5565b16875295820195908201906001016142ba565b509495945050505050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b60008151808452614332816020860160208601614955565b601f01601f19169290920160200192915050565b63ffffffff61435482613ddc565b16825261436360208201613df5565b6001600160401b0380821660208501528061438060408501613df5565b1660408501525050606081013561439681614a1f565b15156060830152608090810135910152565b8183823760009101908152919050565b600082516143ca818460208701614955565b9190910192915050565b6001600160a01b03851681526101006020808301829052855191830182905260009161012084019187810191845b818110156144275783516001600160401b031685529382019392820192600101614402565b505082935086604086015263ffffffff865116606086015280860151925050506001600160401b0380821660808501528060408601511660a085015250506060830151151560c0830152608083015160e083015295945050505050565b6020808252825182820181905260009190848201906040850190845b818110156144c55783516001600160a01b0316835292840192918401916001016144a0565b50909695505050505050565b6000604082016040835280865480835260608501915087600052602092508260002060005b8281101561451b5781546001600160a01b0316845292840192600191820191016144f6565b505050838103828501528481528590820160005b8681101561455d57823561454281614a0a565b6001600160a01b03168252918301919083019060010161452f565b50979650505050505050565b60408152600061457d6040830186886142f1565b8281036020840152613b218185876142aa565b60006101208083526145a58184018b8d6142f1565b905082810360208401526145ba81898b6142aa565b905082810360408401526145cf8187896142f1565b9150508360608301526145e56080830184614346565b9998505050505050505050565b60e08152600061460660e0830187896142f1565b82810360208401526146198186886142aa565b9150506146296040830184614346565b9695505050505050565b60808152600061464760808301888a6142f1565b8281036020840152614659818861431a565b9050828103604084015261466e8186886142f1565b915050826060830152979650505050505050565b6060815260006146966060830186886142f1565b8460208401528281036040840152613b21818561431a565b60208101600483106146d057634e487b7160e01b600052602160045260246000fd5b91905290565b602081526000613a3b602083018461431a565b60208082526017908201527f43616c6c6572206973206e6f7420746865205661756c74000000000000000000604082015260600190565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b60208082526010908201526f14185d5cd8589b194e881c185d5cd95960821b604082015260600190565b6020808252601d908201527f43616c6c6572206973206e6f7420746865205265676973747261746f72000000604082015260600190565b6020808252600e908201526d1499595b9d1c985b9d0818d85b1b60921b604082015260600190565b6020808252601c908201527f43616c6c6572206973206e6f7420746865205374726174656769737400000000604082015260600190565b6000808335601e1984360301811261482e57600080fd5b8301803591506001600160401b0382111561484857600080fd5b602001915036819003821315613c7657600080fd5b60008235605e198336030181126143ca57600080fd5b604051601f8201601f191681016001600160401b038111828210171561489b5761489b6149f4565b604052919050565b60006001600160401b038211156148bc576148bc6149f4565b5060051b60200190565b600080821280156001600160ff1b03849003851316156148e8576148e861499c565b600160ff1b83900384128116156149015761490161499c565b50500190565b6000821982111561491a5761491a61499c565b500190565b60008160001904831182151516156149395761493961499c565b500290565b6000828210156149505761495061499c565b500390565b60005b83811015614970578181015183820152602001614958565b83811115610dc45750506000910152565b60006000198214156149955761499561499c565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b038116811461252157600080fd5b801515811461252157600080fdfe53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac45357bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa2646970667358221220e7e50cde0c8998aadaf7928bf094efc09a4ab9f91b5a4d0db51e66b9307dc59264736f6c63430008070033", "libraries": {}, "devdoc": { "author": "Origin Protocol Inc", + "details": "This contract handles WETH and ETH and in some operations interchanges between the two. Any WETH that is on the contract across multiple blocks (and not just transitory within a transaction) is considered an asset. Meaning deposits increase the balance of the asset and withdrawal decrease it. As opposed to all our other strategies the WETH doesn't immediately get deposited into an underlying strategy and can be present across multiple blocks waiting to be unwrapped to ETH and staked to validators. This separation of WETH and ETH is required since the rewards (reward token) is also in ETH. To simplify the accounting of WETH there is another difference in behavior compared to the other strategies. To withdraw WETH asset - exit message is posted to validators and the ETH hits this contract with multiple days delay. In order to simplify the WETH accounting upon detection of such an event the ValidatorAccountant immediately wraps ETH to WETH and sends it to the Vault. On the other hand any ETH on the contract (across multiple blocks) is there either: - as a result of already accounted for consensus rewards - as a result of not yet accounted for consensus rewards - as a results of not yet accounted for full validator withdrawals (or validator slashes) Even though the strategy assets and rewards are a very similar asset the consensus layer rewards and the execution layer rewards are considered rewards and those are dripped to the Vault over a configurable time interval and not immediately.", "kind": "dev", "methods": { "checkBalance(address)": { @@ -1377,10 +1417,11 @@ } }, "manuallyFixAccounting(int256,int256,uint256)": { + "details": "There is a case when a validator(s) gets slashed so much that the eth swept from the beacon chain enters the fuse area and there are no consensus rewards on the contract to \"dip into\"/use. To increase the amount of unaccounted ETH over the fuse end interval we need to reduce the amount of active deposited validators and immediately send WETH to the vault, so it doesn't interfere with further accounting.", "params": { "_consensusRewardsDelta": "adjust the accounted for consensus rewards up or down", - "_validatorsDelta": "adjust the active validators by plus one, minus one or unchanged with zero", - "_wethToVaultAmount": "the amount of WETH to be sent to the Vault" + "_ethToVaultAmount": "the amount of ETH that gets wrapped into WETH and sent to the Vault", + "_validatorsDelta": "adjust the active validators by up to plus three or minus three" } }, "paused()": { @@ -1439,6 +1480,9 @@ "stateVariables": { "FEE_ACCUMULATOR_ADDRESS": { "details": "this address will receive Execution layer rewards - These are rewards earned for executing transactions on the Ethereum network as part of block proposals. They include priority fees (fees paid by users for their transactions to be included) and MEV rewards (rewards for arranging transactions in a way that benefits the validator)." + }, + "depositedWethAccountedFor": { + "details": "This contract receives WETH as the deposit asset, but unlike other strategies doesn't immediately deposit it to an underlying platform. Rather a special privilege account stakes it to the validators. For that reason calling WETH.balanceOf(this) in a deposit function can contain WETH that has just been deposited and also WETH that has previously been deposited. To keep a correct count we need to keep track of WETH that has already been accounted for. This value represents the amount of WETH balance of this contract that has already been accounted for by the deposit events. It is important to note that this variable is not concerned with WETH that is a result of full/partial withdrawal of the validators. It is strictly concerned with WETH that has been deposited and is waiting to be staked." } }, "title": "Native Staking SSV Strategy", @@ -1456,6 +1500,9 @@ "MAX_STAKE()": { "notice": "The maximum amount of ETH that can be staked by a validator" }, + "MIN_FIX_ACCOUNTING_CADENCE()": { + "notice": "The minimum amount of blocks that need to pass between two calls to manuallyFixAccounting" + }, "SSV_NETWORK_ADDRESS()": { "notice": "The address of the SSV Network contract used to interface with" }, @@ -1522,6 +1569,9 @@ "isGovernor()": { "notice": "Returns true if the caller is the current Governor." }, + "lastFixAccountingBlockNumber()": { + "notice": "last block number manuallyFixAccounting has been called" + }, "manuallyFixAccounting(int256,int256,uint256)": { "notice": "Allow the Strategist to fix the accounting of this strategy and unpause." }, @@ -1592,7 +1642,7 @@ "storageLayout": { "storage": [ { - "astId": 5254, + "astId": 41769, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "initialized", "offset": 0, @@ -1600,7 +1650,7 @@ "type": "t_bool" }, { - "astId": 5257, + "astId": 41772, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "initializing", "offset": 1, @@ -1608,7 +1658,7 @@ "type": "t_bool" }, { - "astId": 5297, + "astId": 41812, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "______gap", "offset": 0, @@ -1616,7 +1666,7 @@ "type": "t_array(t_uint256)50_storage" }, { - "astId": 17, + "astId": 656, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "_paused", "offset": 0, @@ -1624,7 +1674,7 @@ "type": "t_bool" }, { - "astId": 3513, + "astId": 34884, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "validatorRegistrator", "offset": 1, @@ -1632,7 +1682,7 @@ "type": "t_address" }, { - "astId": 3516, + "astId": 34887, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "activeDepositedValidators", "offset": 0, @@ -1640,15 +1690,15 @@ "type": "t_uint256" }, { - "astId": 3522, + "astId": 34893, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "validatorsStates", "offset": 0, "slot": "53", - "type": "t_mapping(t_bytes32,t_enum(VALIDATOR_STATE)3531)" + "type": "t_mapping(t_bytes32,t_enum(VALIDATOR_STATE)34902)" }, { - "astId": 3526, + "astId": 34897, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "__gap", "offset": 0, @@ -1656,7 +1706,7 @@ "type": "t_array(t_uint256)50_storage" }, { - "astId": 3054, + "astId": 34379, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "consensusRewards", "offset": 0, @@ -1664,7 +1714,7 @@ "type": "t_uint256" }, { - "astId": 3057, + "astId": 34382, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "fuseIntervalStart", "offset": 0, @@ -1672,7 +1722,7 @@ "type": "t_uint256" }, { - "astId": 3060, + "astId": 34385, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "fuseIntervalEnd", "offset": 0, @@ -1680,15 +1730,23 @@ "type": "t_uint256" }, { - "astId": 3064, + "astId": 34388, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", - "label": "__gap", + "label": "lastFixAccountingBlockNumber", "offset": 0, "slot": "107", - "type": "t_array(t_uint256)50_storage" + "type": "t_uint256" }, { - "astId": 5377, + "astId": 34392, + "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", + "label": "__gap", + "offset": 0, + "slot": "108", + "type": "t_array(t_uint256)49_storage" + }, + { + "astId": 41892, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "_deprecated_platformAddress", "offset": 0, @@ -1696,7 +1754,7 @@ "type": "t_address" }, { - "astId": 5380, + "astId": 41895, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "_deprecated_vaultAddress", "offset": 0, @@ -1704,7 +1762,7 @@ "type": "t_address" }, { - "astId": 5385, + "astId": 41900, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "assetToPToken", "offset": 0, @@ -1712,7 +1770,7 @@ "type": "t_mapping(t_address,t_address)" }, { - "astId": 5389, + "astId": 41904, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "assetsMapped", "offset": 0, @@ -1720,7 +1778,7 @@ "type": "t_array(t_address)dyn_storage" }, { - "astId": 5391, + "astId": 41906, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "_deprecated_rewardTokenAddress", "offset": 0, @@ -1728,7 +1786,7 @@ "type": "t_address" }, { - "astId": 5393, + "astId": 41908, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "_deprecated_rewardLiquidationThreshold", "offset": 0, @@ -1736,7 +1794,7 @@ "type": "t_uint256" }, { - "astId": 5396, + "astId": 41911, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "harvesterAddress", "offset": 0, @@ -1744,7 +1802,7 @@ "type": "t_address" }, { - "astId": 5400, + "astId": 41915, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "rewardTokenAddresses", "offset": 0, @@ -1752,7 +1810,7 @@ "type": "t_array(t_address)dyn_storage" }, { - "astId": 5404, + "astId": 41919, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "_reserved", "offset": 0, @@ -1760,12 +1818,20 @@ "type": "t_array(t_int256)98_storage" }, { - "astId": 2625, + "astId": 33893, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", - "label": "__gap", + "label": "depositedWethAccountedFor", "offset": 0, "slot": "263", - "type": "t_array(t_uint256)50_storage" + "type": "t_uint256" + }, + { + "astId": 33897, + "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", + "label": "__gap", + "offset": 0, + "slot": "264", + "type": "t_array(t_uint256)49_storage" } ], "types": { @@ -1786,6 +1852,12 @@ "label": "int256[98]", "numberOfBytes": "3136" }, + "t_array(t_uint256)49_storage": { + "base": "t_uint256", + "encoding": "inplace", + "label": "uint256[49]", + "numberOfBytes": "1568" + }, "t_array(t_uint256)50_storage": { "base": "t_uint256", "encoding": "inplace", @@ -1802,7 +1874,7 @@ "label": "bytes32", "numberOfBytes": "32" }, - "t_enum(VALIDATOR_STATE)3531": { + "t_enum(VALIDATOR_STATE)34902": { "encoding": "inplace", "label": "enum ValidatorRegistrator.VALIDATOR_STATE", "numberOfBytes": "1" @@ -1819,12 +1891,12 @@ "numberOfBytes": "32", "value": "t_address" }, - "t_mapping(t_bytes32,t_enum(VALIDATOR_STATE)3531)": { + "t_mapping(t_bytes32,t_enum(VALIDATOR_STATE)34902)": { "encoding": "mapping", "key": "t_bytes32", "label": "mapping(bytes32 => enum ValidatorRegistrator.VALIDATOR_STATE)", "numberOfBytes": "32", - "value": "t_enum(VALIDATOR_STATE)3531" + "value": "t_enum(VALIDATOR_STATE)34902" }, "t_uint256": { "encoding": "inplace", diff --git a/contracts/deployments/holesky/solcInputs/279a9fe8a2da81dca55abd3c6ec521f8.json b/contracts/deployments/holesky/solcInputs/279a9fe8a2da81dca55abd3c6ec521f8.json new file mode 100644 index 0000000000..501a023dc0 --- /dev/null +++ b/contracts/deployments/holesky/solcInputs/279a9fe8a2da81dca55abd3c6ec521f8.json @@ -0,0 +1,689 @@ +{ + "language": "Solidity", + "sources": { + "@chainlink/contracts-ccip/src/v0.8/ccip/interfaces/IRouterClient.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {Client} from \"../libraries/Client.sol\";\n\ninterface IRouterClient {\n error UnsupportedDestinationChain(uint64 destChainSelector);\n error InsufficientFeeTokenAmount();\n error InvalidMsgValue();\n\n /// @notice Checks if the given chain ID is supported for sending/receiving.\n /// @param chainSelector The chain to check.\n /// @return supported is true if it is supported, false if not.\n function isChainSupported(uint64 chainSelector) external view returns (bool supported);\n\n /// @notice Gets a list of all supported tokens which can be sent or received\n /// to/from a given chain id.\n /// @param chainSelector The chainSelector.\n /// @return tokens The addresses of all tokens that are supported.\n function getSupportedTokens(uint64 chainSelector) external view returns (address[] memory tokens);\n\n /// @param destinationChainSelector The destination chainSelector\n /// @param message The cross-chain CCIP message including data and/or tokens\n /// @return fee returns execution fee for the message\n /// delivery to destination chain, denominated in the feeToken specified in the message.\n /// @dev Reverts with appropriate reason upon invalid message.\n function getFee(\n uint64 destinationChainSelector,\n Client.EVM2AnyMessage memory message\n ) external view returns (uint256 fee);\n\n /// @notice Request a message to be sent to the destination chain\n /// @param destinationChainSelector The destination chain ID\n /// @param message The cross-chain CCIP message including data and/or tokens\n /// @return messageId The message ID\n /// @dev Note if msg.value is larger than the required fee (from getFee) we accept\n /// the overpayment with no refund.\n /// @dev Reverts with appropriate reason upon invalid message.\n function ccipSend(\n uint64 destinationChainSelector,\n Client.EVM2AnyMessage calldata message\n ) external payable returns (bytes32);\n}\n" + }, + "@chainlink/contracts-ccip/src/v0.8/ccip/libraries/Client.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n// End consumer library.\nlibrary Client {\n /// @dev RMN depends on this struct, if changing, please notify the RMN maintainers.\n struct EVMTokenAmount {\n address token; // token address on the local chain.\n uint256 amount; // Amount of tokens.\n }\n\n struct Any2EVMMessage {\n bytes32 messageId; // MessageId corresponding to ccipSend on source.\n uint64 sourceChainSelector; // Source chain selector.\n bytes sender; // abi.decode(sender) if coming from an EVM chain.\n bytes data; // payload sent in original message.\n EVMTokenAmount[] destTokenAmounts; // Tokens and their amounts in their destination chain representation.\n }\n\n // If extraArgs is empty bytes, the default is 200k gas limit.\n struct EVM2AnyMessage {\n bytes receiver; // abi.encode(receiver address) for dest EVM chains\n bytes data; // Data payload\n EVMTokenAmount[] tokenAmounts; // Token transfers\n address feeToken; // Address of feeToken. address(0) means you will send msg.value.\n bytes extraArgs; // Populate this with _argsToBytes(EVMExtraArgsV1)\n }\n\n // bytes4(keccak256(\"CCIP EVMExtraArgsV1\"));\n bytes4 public constant EVM_EXTRA_ARGS_V1_TAG = 0x97a657c9;\n struct EVMExtraArgsV1 {\n uint256 gasLimit;\n }\n\n function _argsToBytes(EVMExtraArgsV1 memory extraArgs) internal pure returns (bytes memory bts) {\n return abi.encodeWithSelector(EVM_EXTRA_ARGS_V1_TAG, extraArgs);\n }\n}\n" + }, + "@openzeppelin/contracts/access/AccessControl.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/AccessControl.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IAccessControl.sol\";\nimport \"../utils/Context.sol\";\nimport \"../utils/Strings.sol\";\nimport \"../utils/introspection/ERC165.sol\";\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address => bool) members;\n bytes32 adminRole;\n }\n\n mapping(bytes32 => RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with a standardized message including the required role.\n *\n * The format of the revert reason is given by the following regular expression:\n *\n * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/\n *\n * _Available since v4.1._\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role, _msgSender());\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view override returns (bool) {\n return _roles[role].members[account];\n }\n\n /**\n * @dev Revert with a standard message if `account` is missing `role`.\n *\n * The format of the revert reason is given by the following regular expression:\n *\n * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/\n */\n function _checkRole(bytes32 role, address account) internal view {\n if (!hasRole(role, account)) {\n revert(\n string(\n abi.encodePacked(\n \"AccessControl: account \",\n Strings.toHexString(uint160(account), 20),\n \" is missing role \",\n Strings.toHexString(uint256(role), 32)\n )\n )\n );\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view override returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `account`.\n */\n function renounceRole(bytes32 role, address account) public virtual override {\n require(account == _msgSender(), \"AccessControl: can only renounce roles for self\");\n\n _revokeRole(role, account);\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event. Note that unlike {grantRole}, this function doesn't perform any\n * checks on the calling account.\n *\n * [WARNING]\n * ====\n * This function should only be called from the constructor when setting\n * up the initial roles for the system.\n *\n * Using this function in any other way is effectively circumventing the admin\n * system imposed by {AccessControl}.\n * ====\n *\n * NOTE: This function is deprecated in favor of {_grantRole}.\n */\n function _setupRole(bytes32 role, address account) internal virtual {\n _grantRole(role, account);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * Internal function without access restriction.\n */\n function _grantRole(bytes32 role, address account) internal virtual {\n if (!hasRole(role, account)) {\n _roles[role].members[account] = true;\n emit RoleGranted(role, account, _msgSender());\n }\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * Internal function without access restriction.\n */\n function _revokeRole(bytes32 role, address account) internal virtual {\n if (hasRole(role, account)) {\n _roles[role].members[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n }\n }\n}\n" + }, + "@openzeppelin/contracts/access/AccessControlEnumerable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/AccessControlEnumerable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IAccessControlEnumerable.sol\";\nimport \"./AccessControl.sol\";\nimport \"../utils/structs/EnumerableSet.sol\";\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 => EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view override returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view override returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override {\n super._grantRole(role, account);\n _roleMembers[role].add(account);\n }\n\n /**\n * @dev Overload {_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override {\n super._revokeRole(role, account);\n _roleMembers[role].remove(account);\n }\n}\n" + }, + "@openzeppelin/contracts/access/IAccessControl.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n *\n * _Available since v3.1._\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `account`.\n */\n function renounceRole(bytes32 role, address account) external;\n}\n" + }, + "@openzeppelin/contracts/access/IAccessControlEnumerable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/IAccessControlEnumerable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IAccessControl.sol\";\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n" + }, + "@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/introspection/ERC165.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC165.sol\";\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n *\n * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n" + }, + "@openzeppelin/contracts/utils/introspection/IERC165.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\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" + }, + "@openzeppelin/contracts/utils/structs/EnumerableSet.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/structs/EnumerableSet.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position of the value in the `values` array, plus 1 because index 0\n // means a value is not in the set.\n mapping(bytes32 => uint256) _indexes;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._indexes[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We read and store the value's index to prevent multiple reads from the same storage slot\n uint256 valueIndex = set._indexes[value];\n\n if (valueIndex != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 toDeleteIndex = valueIndex - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (lastIndex != toDeleteIndex) {\n bytes32 lastvalue = set._values[lastIndex];\n\n // Move the last value to the index where the value to delete is\n set._values[toDeleteIndex] = lastvalue;\n // Update the index for the moved value\n set._indexes[lastvalue] = valueIndex; // Replace lastvalue's index to valueIndex\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the index for the deleted slot\n delete set._indexes[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._indexes[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n return _values(set._inner);\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n assembly {\n result := store\n }\n\n return result;\n }\n}\n" + }, + "contracts/buyback/AbstractBuyback.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { Strategizable } from \"../governance/Strategizable.sol\";\nimport \"../interfaces/chainlink/AggregatorV3Interface.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { ICVXLocker } from \"../interfaces/ICVXLocker.sol\";\nimport { ISwapper } from \"../interfaces/ISwapper.sol\";\n\nimport { Initializable } from \"../utils/Initializable.sol\";\n\nabstract contract AbstractBuyback is Initializable, Strategizable {\n using SafeERC20 for IERC20;\n\n event SwapRouterUpdated(address indexed _address);\n\n event RewardsSourceUpdated(address indexed _address);\n event TreasuryManagerUpdated(address indexed _address);\n event CVXShareBpsUpdated(uint256 bps);\n\n // Emitted whenever OUSD/OETH is swapped for OGN/CVX or any other token\n event OTokenBuyback(\n address indexed oToken,\n address indexed swappedFor,\n uint256 swapAmountIn,\n uint256 amountOut\n );\n\n // Address of 1-inch Swap Router\n address public swapRouter;\n\n // slither-disable-next-line constable-states\n address private __deprecated_ousd;\n // slither-disable-next-line constable-states\n address private __deprecated_ogv;\n // slither-disable-next-line constable-states\n address private __deprecated_usdt;\n // slither-disable-next-line constable-states\n address private __deprecated_weth9;\n\n // Address that receives OGN after swaps\n address public rewardsSource;\n\n // Address that receives all other tokens after swaps\n address public treasuryManager;\n\n // slither-disable-next-line constable-states\n uint256 private __deprecated_treasuryBps;\n\n address public immutable oToken;\n address public immutable ogn;\n address public immutable cvx;\n address public immutable cvxLocker;\n\n // Amount of `oToken` balance to use for OGN buyback\n uint256 public balanceForOGN;\n\n // Amount of `oToken` balance to use for CVX buyback\n uint256 public balanceForCVX;\n\n // Percentage of `oToken` balance to be used for CVX\n uint256 public cvxShareBps; // 10000 = 100%\n\n constructor(\n address _oToken,\n address _ogn,\n address _cvx,\n address _cvxLocker\n ) {\n // Make sure nobody owns the implementation contract\n _setGovernor(address(0));\n\n oToken = _oToken;\n ogn = _ogn;\n cvx = _cvx;\n cvxLocker = _cvxLocker;\n }\n\n /**\n * @param _swapRouter Address of Uniswap V3 Router\n * @param _strategistAddr Address of Strategist multi-sig wallet\n * @param _treasuryManagerAddr Address that receives the treasury's share of OUSD\n * @param _rewardsSource Address of RewardsSource contract\n * @param _cvxShareBps Percentage of balance to use for CVX\n */\n function initialize(\n address _swapRouter,\n address _strategistAddr,\n address _treasuryManagerAddr,\n address _rewardsSource,\n uint256 _cvxShareBps\n ) external onlyGovernor initializer {\n _setStrategistAddr(_strategistAddr);\n\n _setSwapRouter(_swapRouter);\n _setRewardsSource(_rewardsSource);\n\n _setTreasuryManager(_treasuryManagerAddr);\n\n _setCVXShareBps(_cvxShareBps);\n }\n\n /**\n * @dev Set address of Uniswap Universal Router for performing liquidation\n * of platform fee tokens. Setting to 0x0 will pause swaps.\n *\n * @param _router Address of the Uniswap Universal router\n */\n function setSwapRouter(address _router) external onlyGovernor {\n _setSwapRouter(_router);\n }\n\n function _setSwapRouter(address _router) internal {\n address oldRouter = swapRouter;\n swapRouter = _router;\n\n if (oldRouter != address(0)) {\n // Remove allowance of old router, if any\n\n if (IERC20(ogn).allowance(address(this), oldRouter) != 0) {\n // slither-disable-next-line unused-return\n IERC20(ogn).safeApprove(oldRouter, 0);\n }\n\n if (IERC20(cvx).allowance(address(this), oldRouter) != 0) {\n // slither-disable-next-line unused-return\n IERC20(cvx).safeApprove(oldRouter, 0);\n }\n }\n\n emit SwapRouterUpdated(_router);\n }\n\n /**\n * @dev Sets the address that receives the OGN buyback rewards\n * @param _address Address\n */\n function setRewardsSource(address _address) external onlyGovernor {\n _setRewardsSource(_address);\n }\n\n function _setRewardsSource(address _address) internal {\n require(_address != address(0), \"Address not set\");\n rewardsSource = _address;\n emit RewardsSourceUpdated(_address);\n }\n\n /**\n * @dev Sets the address that can receive and manage the funds for Treasury\n * @param _address Address\n */\n function setTreasuryManager(address _address) external onlyGovernor {\n _setTreasuryManager(_address);\n }\n\n function _setTreasuryManager(address _address) internal {\n require(_address != address(0), \"Address not set\");\n treasuryManager = _address;\n emit TreasuryManagerUpdated(_address);\n }\n\n /**\n * @dev Sets the percentage of oToken to use for Flywheel tokens\n * @param _bps BPS, 10000 to 100%\n */\n function setCVXShareBps(uint256 _bps) external onlyGovernor {\n _setCVXShareBps(_bps);\n }\n\n function _setCVXShareBps(uint256 _bps) internal {\n require(_bps <= 10000, \"Invalid bps value\");\n cvxShareBps = _bps;\n emit CVXShareBpsUpdated(_bps);\n }\n\n /**\n * @dev Computes the split of oToken balance that can be\n * used for OGN and CVX buybacks.\n */\n function _updateBuybackSplits()\n internal\n returns (uint256 _balanceForOGN, uint256 _balanceForCVX)\n {\n _balanceForOGN = balanceForOGN;\n _balanceForCVX = balanceForCVX;\n\n uint256 totalBalance = IERC20(oToken).balanceOf(address(this));\n uint256 unsplitBalance = totalBalance - _balanceForOGN - _balanceForCVX;\n\n // Check if all balance is accounted for\n if (unsplitBalance != 0) {\n // If not, split unaccounted balance based on `cvxShareBps`\n uint256 addToCVX = (unsplitBalance * cvxShareBps) / 10000;\n _balanceForCVX = _balanceForCVX + addToCVX;\n _balanceForOGN = _balanceForOGN + unsplitBalance - addToCVX;\n\n // Update storage\n balanceForOGN = _balanceForOGN;\n balanceForCVX = _balanceForCVX;\n }\n }\n\n function updateBuybackSplits() external onlyGovernor {\n // slither-disable-next-line unused-return\n _updateBuybackSplits();\n }\n\n function _swapToken(\n address tokenOut,\n uint256 oTokenAmount,\n uint256 minAmountOut,\n bytes calldata swapData\n ) internal returns (uint256 amountOut) {\n require(oTokenAmount > 0, \"Invalid Swap Amount\");\n require(swapRouter != address(0), \"Swap Router not set\");\n require(minAmountOut > 0, \"Invalid minAmount\");\n\n // Transfer OToken to Swapper for swapping\n // slither-disable-next-line unchecked-transfer unused-return\n IERC20(oToken).transfer(swapRouter, oTokenAmount);\n\n // Swap\n amountOut = ISwapper(swapRouter).swap(\n oToken,\n tokenOut,\n oTokenAmount,\n minAmountOut,\n swapData\n );\n\n require(amountOut >= minAmountOut, \"Higher Slippage\");\n\n emit OTokenBuyback(oToken, tokenOut, oTokenAmount, amountOut);\n }\n\n /**\n * @dev Swaps `oTokenAmount` to OGN\n * @param oTokenAmount Amount of OUSD/OETH to swap\n * @param minOGN Minimum OGN to receive for oTokenAmount\n * @param swapData 1inch Swap Data\n */\n function swapForOGN(\n uint256 oTokenAmount,\n uint256 minOGN,\n bytes calldata swapData\n ) external onlyGovernorOrStrategist nonReentrant {\n (uint256 _amountForOGN, ) = _updateBuybackSplits();\n require(_amountForOGN >= oTokenAmount, \"Balance underflow\");\n require(rewardsSource != address(0), \"RewardsSource contract not set\");\n\n unchecked {\n // Subtract the amount to swap from net balance\n balanceForOGN = _amountForOGN - oTokenAmount;\n }\n\n uint256 ognReceived = _swapToken(ogn, oTokenAmount, minOGN, swapData);\n\n // Transfer OGN received to RewardsSource contract\n // slither-disable-next-line unchecked-transfer unused-return\n IERC20(ogn).transfer(rewardsSource, ognReceived);\n }\n\n /**\n * @dev Swaps `oTokenAmount` to CVX\n * @param oTokenAmount Amount of OUSD/OETH to swap\n * @param minCVX Minimum CVX to receive for oTokenAmount\n * @param swapData 1inch Swap Data\n */\n function swapForCVX(\n uint256 oTokenAmount,\n uint256 minCVX,\n bytes calldata swapData\n ) external onlyGovernorOrStrategist nonReentrant {\n (, uint256 _amountForCVX) = _updateBuybackSplits();\n require(_amountForCVX >= oTokenAmount, \"Balance underflow\");\n\n unchecked {\n // Subtract the amount to swap from net balance\n balanceForCVX = _amountForCVX - oTokenAmount;\n }\n\n uint256 cvxReceived = _swapToken(cvx, oTokenAmount, minCVX, swapData);\n\n // Lock all CVX\n _lockAllCVX(cvxReceived);\n }\n\n /**\n * @dev Locks all CVX held by the contract on behalf of the Treasury Manager\n */\n function lockAllCVX() external onlyGovernorOrStrategist {\n _lockAllCVX(IERC20(cvx).balanceOf(address(this)));\n }\n\n function _lockAllCVX(uint256 cvxAmount) internal {\n require(\n treasuryManager != address(0),\n \"Treasury manager address not set\"\n );\n\n // Lock all available CVX on behalf of `treasuryManager`\n ICVXLocker(cvxLocker).lock(treasuryManager, cvxAmount, 0);\n }\n\n /**\n * @dev Approve CVX Locker to move CVX held by this contract\n */\n function safeApproveAllTokens() external onlyGovernorOrStrategist {\n IERC20(cvx).safeApprove(cvxLocker, type(uint256).max);\n }\n\n /**\n * @notice Owner function to withdraw a specific amount of a token\n * @param token token to be transferered\n * @param amount amount of the token to be transferred\n */\n function transferToken(address token, uint256 amount)\n external\n onlyGovernor\n nonReentrant\n {\n IERC20(token).safeTransfer(_governor(), amount);\n }\n}\n" + }, + "contracts/buyback/OETHBuyback.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { AbstractBuyback } from \"./AbstractBuyback.sol\";\n\ncontract OETHBuyback is AbstractBuyback {\n constructor(\n address _oToken,\n address _ogn,\n address _cvx,\n address _cvxLocker\n ) AbstractBuyback(_oToken, _ogn, _cvx, _cvxLocker) {}\n}\n" + }, + "contracts/buyback/OUSDBuyback.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { AbstractBuyback } from \"./AbstractBuyback.sol\";\n\ncontract OUSDBuyback is AbstractBuyback {\n constructor(\n address _oToken,\n address _ogn,\n address _cvx,\n address _cvxLocker\n ) AbstractBuyback(_oToken, _ogn, _cvx, _cvxLocker) {}\n}\n" + }, + "contracts/compensation/CompensationClaims.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\";\n\nimport { Initializable } from \"../utils/Initializable.sol\";\nimport { Governable } from \"../governance/Governable.sol\";\n\n/**\n * @title Compensation Claims\n * @author Origin Protocol Inc\n * @dev Airdrop for ERC20 tokens.\n *\n * Provides a coin airdrop with a verification period in which everyone\n * can check that all claims are correct before any actual funds are moved\n * to the contract.\n *\n * - Users can claim funds during the claim period.\n *\n * - The adjuster can set the amount of each user's claim,\n * but only when unlocked, and not during the claim period.\n *\n * - The governor can unlock and lock the adjuster, outside the claim period.\n * - The governor can start the claim period, if it's not started.\n * - The governor can collect any remaining funds after the claim period is over.\n *\n * Intended use sequence:\n *\n * 1. Governor unlocks the adjuster\n * 2. Adjuster uploads claims\n * 3. Governor locks the adjuster\n * 4. Everyone verifies that the claim amounts and totals are correct\n * 5. Payout funds are moved to the contract\n * 6. The claim period starts\n * 7. Users claim funds\n * 8. The claim period ends\n * 9. Governor can collect any remaing funds\n *\n */\ncontract CompensationClaims is Governable {\n address public adjuster;\n address public token;\n uint256 public end;\n uint256 public totalClaims;\n mapping(address => uint256) claims;\n bool public isAdjusterLocked;\n\n using SafeMath for uint256;\n\n event Claim(address indexed recipient, uint256 amount);\n event ClaimSet(address indexed recipient, uint256 amount);\n event Start(uint256 end);\n event Lock();\n event Unlock();\n event Collect(address indexed coin, uint256 amount);\n\n constructor(address _token, address _adjuster) onlyGovernor {\n token = _token;\n adjuster = _adjuster;\n isAdjusterLocked = true;\n }\n\n function balanceOf(address _account) external view returns (uint256) {\n return claims[_account];\n }\n\n function decimals() external view returns (uint8) {\n return IERC20Decimals(token).decimals();\n }\n\n /* -- User -- */\n\n function claim(address _recipient) external onlyInClaimPeriod nonReentrant {\n uint256 amount = claims[_recipient];\n require(amount > 0, \"Amount must be greater than 0\");\n claims[_recipient] = 0;\n totalClaims = totalClaims.sub(amount);\n SafeERC20.safeTransfer(IERC20(token), _recipient, amount);\n emit Claim(_recipient, amount);\n }\n\n /* -- Adjustor -- */\n\n function setClaims(\n address[] calldata _addresses,\n uint256[] calldata _amounts\n ) external notInClaimPeriod onlyUnlockedAdjuster {\n require(\n _addresses.length == _amounts.length,\n \"Addresses and amounts must match\"\n );\n uint256 len = _addresses.length;\n for (uint256 i = 0; i < len; i++) {\n address recipient = _addresses[i];\n uint256 newAmount = _amounts[i];\n uint256 oldAmount = claims[recipient];\n claims[recipient] = newAmount;\n totalClaims = totalClaims.add(newAmount).sub(oldAmount);\n emit ClaimSet(recipient, newAmount);\n }\n }\n\n /* -- Governor -- */\n\n function lockAdjuster() external onlyGovernor notInClaimPeriod {\n _lockAdjuster();\n }\n\n function _lockAdjuster() internal {\n isAdjusterLocked = true;\n emit Lock();\n }\n\n function unlockAdjuster() external onlyGovernor notInClaimPeriod {\n isAdjusterLocked = false;\n emit Unlock();\n }\n\n function start(uint256 _seconds)\n external\n onlyGovernor\n notInClaimPeriod\n nonReentrant\n {\n require(totalClaims > 0, \"No claims\");\n uint256 funding = IERC20(token).balanceOf(address(this));\n require(funding >= totalClaims, \"Insufficient funds for all claims\");\n _lockAdjuster();\n end = block.timestamp.add(_seconds);\n require(end.sub(block.timestamp) < 31622400, \"Duration too long\"); // 31622400 = 366*24*60*60\n emit Start(end);\n }\n\n function collect(address _coin)\n external\n onlyGovernor\n notInClaimPeriod\n nonReentrant\n {\n uint256 amount = IERC20(_coin).balanceOf(address(this));\n SafeERC20.safeTransfer(IERC20(_coin), address(governor()), amount);\n emit Collect(_coin, amount);\n }\n\n /* -- modifiers -- */\n\n modifier onlyInClaimPeriod() {\n require(block.timestamp <= end, \"Should be in claim period\");\n _;\n }\n\n modifier notInClaimPeriod() {\n require(block.timestamp > end, \"Should not be in claim period\");\n _;\n }\n\n modifier onlyUnlockedAdjuster() {\n require(isAdjusterLocked == false, \"Adjuster must be unlocked\");\n require(msg.sender == adjuster, \"Must be adjuster\");\n _;\n }\n}\n\ninterface IERC20Decimals {\n function decimals() external view returns (uint8);\n}\n" + }, + "contracts/echidna/Debugger.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nlibrary Debugger {\n event Debug(string debugString);\n event Debug(string description, string data);\n event Debug(string prefix, string description, string data);\n event Debug(string description, bytes32 data);\n event Debug(string prefix, string description, bytes32 data);\n event Debug(string description, uint256 data);\n event Debug(string prefix, string description, uint256 data);\n event Debug(string description, int256 data);\n event Debug(string prefix, string description, int256 data);\n event Debug(string description, address data);\n event Debug(string prefix, string description, address data);\n event Debug(string description, bool data);\n event Debug(string prefix, string description, bool data);\n\n function log(string memory debugString) internal {\n emit Debug(debugString);\n }\n\n function log(string memory description, string memory data) internal {\n emit Debug(description, data);\n }\n\n function log(\n string memory prefix,\n string memory description,\n string memory data\n ) internal {\n emit Debug(prefix, description, data);\n }\n\n function log(string memory description, bytes32 data) internal {\n emit Debug(description, data);\n }\n\n function log(\n string memory prefix,\n string memory description,\n bytes32 data\n ) internal {\n emit Debug(prefix, description, data);\n }\n\n function log(string memory description, uint256 data) internal {\n emit Debug(description, data);\n }\n\n function log(\n string memory prefix,\n string memory description,\n uint256 data\n ) internal {\n emit Debug(prefix, description, data);\n }\n\n function log(string memory description, int256 data) internal {\n emit Debug(description, data);\n }\n\n function log(\n string memory prefix,\n string memory description,\n int256 data\n ) internal {\n emit Debug(prefix, description, data);\n }\n\n function log(string memory description, address data) internal {\n emit Debug(description, data);\n }\n\n function log(\n string memory prefix,\n string memory description,\n address data\n ) internal {\n emit Debug(prefix, description, data);\n }\n\n function log(string memory description, bool data) internal {\n emit Debug(description, data);\n }\n\n function log(\n string memory prefix,\n string memory description,\n bool data\n ) internal {\n emit Debug(prefix, description, data);\n }\n}\n" + }, + "contracts/echidna/Echidna.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./EchidnaTestApproval.sol\";\n\n/**\n * @title Echidna test contract for OUSD\n * @notice Target contract to be tested, containing all mixins\n * @author Rappie\n */\ncontract Echidna is EchidnaTestApproval {\n\n}\n" + }, + "contracts/echidna/EchidnaConfig.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @title Top-level mixin for configuring the desired fuzzing setup\n * @author Rappie\n */\ncontract EchidnaConfig {\n address internal constant ADDRESS_VAULT = address(0x10000);\n address internal constant ADDRESS_OUTSIDER_USER = address(0x20000);\n\n address internal constant ADDRESS_USER0 = address(0x30000);\n address internal constant ADDRESS_USER1 = address(0x40000);\n\n // Will be set in EchidnaSetup constructor\n address internal ADDRESS_OUTSIDER_CONTRACT;\n address internal ADDRESS_CONTRACT0;\n address internal ADDRESS_CONTRACT1;\n\n // Toggle known issues\n //\n // This can be used to skip tests that are known to fail. This is useful\n // when debugging a specific issue, but should be disabled when running\n // the full test suite.\n //\n // True => skip tests that are known to fail\n // False => run all tests\n //\n bool internal constant TOGGLE_KNOWN_ISSUES = false;\n\n // Toggle known issues within limits\n //\n // Same as TOGGLE_KNOWN_ISSUES, but also skip tests that are known to fail\n // within limits set by the variables below.\n //\n bool internal constant TOGGLE_KNOWN_ISSUES_WITHIN_LIMITS = true;\n\n // Starting balance\n //\n // Gives OUSD a non-zero starting supply, which can be useful to ignore\n // certain edge cases.\n //\n // The starting balance is given to outsider accounts that are not used as\n // accounts while fuzzing.\n //\n bool internal constant TOGGLE_STARTING_BALANCE = true;\n uint256 internal constant STARTING_BALANCE = 1_000_000e18;\n\n // Change supply\n //\n // Set a limit to the amount of change per rebase, which can be useful to\n // ignore certain edge cases.\n //\n // True => limit the amount of change to a percentage of total supply\n // False => no limit\n //\n bool internal constant TOGGLE_CHANGESUPPLY_LIMIT = true;\n uint256 internal constant CHANGESUPPLY_DIVISOR = 10; // 10% of total supply\n\n // Mint limit\n //\n // Set a limit the the amount minted per mint, which can be useful to\n // ignore certain edge cases.\n //\n // True => limit the amount of minted tokens\n // False => no limit\n //\n bool internal constant TOGGLE_MINT_LIMIT = true;\n uint256 internal constant MINT_MODULO = 1_000_000_000_000e18;\n\n // Known rounding errors\n uint256 internal constant TRANSFER_ROUNDING_ERROR = 1e18 - 1;\n uint256 internal constant OPT_IN_ROUNDING_ERROR = 1e18 - 1;\n uint256 internal constant MINT_ROUNDING_ERROR = 1e18 - 1;\n\n /**\n * @notice Modifier to skip tests that are known to fail\n * @dev see TOGGLE_KNOWN_ISSUES for more information\n */\n modifier hasKnownIssue() {\n if (TOGGLE_KNOWN_ISSUES) return;\n _;\n }\n\n /**\n * @notice Modifier to skip tests that are known to fail within limits\n * @dev see TOGGLE_KNOWN_ISSUES_WITHIN_LIMITS for more information\n */\n modifier hasKnownIssueWithinLimits() {\n if (TOGGLE_KNOWN_ISSUES_WITHIN_LIMITS) return;\n _;\n }\n\n /**\n * @notice Translate an account ID to an address\n * @param accountId The ID of the account\n * @return account The address of the account\n */\n function getAccount(uint8 accountId)\n internal\n view\n returns (address account)\n {\n accountId = accountId / 64;\n if (accountId == 0) return account = ADDRESS_USER0;\n if (accountId == 1) return account = ADDRESS_USER1;\n if (accountId == 2) return account = ADDRESS_CONTRACT0;\n if (accountId == 3) return account = ADDRESS_CONTRACT1;\n require(false, \"Unknown account ID\");\n }\n}\n" + }, + "contracts/echidna/EchidnaDebug.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { Address } from \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport \"./EchidnaHelper.sol\";\nimport \"./Debugger.sol\";\n\nimport \"../token/OUSD.sol\";\n\n/**\n * @title Room for random debugging functions\n * @author Rappie\n */\ncontract EchidnaDebug is EchidnaHelper {\n function debugOUSD() public pure {\n // assert(ousd.balanceOf(ADDRESS_USER0) == 1000);\n // assert(ousd.rebaseState(ADDRESS_USER0) != OUSD.RebaseOptions.OptIn);\n // assert(Address.isContract(ADDRESS_CONTRACT0));\n // Debugger.log(\"nonRebasingSupply\", ousd.nonRebasingSupply());\n // assert(false);\n }\n}\n" + }, + "contracts/echidna/EchidnaHelper.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./EchidnaSetup.sol\";\nimport \"./Debugger.sol\";\n\n/**\n * @title Mixin containing helper functions\n * @author Rappie\n */\ncontract EchidnaHelper is EchidnaSetup {\n /**\n * @notice Mint tokens to an account\n * @param toAcc Account to mint to\n * @param amount Amount to mint\n * @return Amount minted (in case of capped mint with modulo)\n */\n function mint(uint8 toAcc, uint256 amount) public returns (uint256) {\n address to = getAccount(toAcc);\n\n if (TOGGLE_MINT_LIMIT) {\n amount = amount % MINT_MODULO;\n }\n\n hevm.prank(ADDRESS_VAULT);\n ousd.mint(to, amount);\n\n return amount;\n }\n\n /**\n * @notice Burn tokens from an account\n * @param fromAcc Account to burn from\n * @param amount Amount to burn\n */\n function burn(uint8 fromAcc, uint256 amount) public {\n address from = getAccount(fromAcc);\n hevm.prank(ADDRESS_VAULT);\n ousd.burn(from, amount);\n }\n\n /**\n * @notice Change the total supply of OUSD (rebase)\n * @param amount New total supply\n */\n function changeSupply(uint256 amount) public {\n if (TOGGLE_CHANGESUPPLY_LIMIT) {\n amount =\n ousd.totalSupply() +\n (amount % (ousd.totalSupply() / CHANGESUPPLY_DIVISOR));\n }\n\n hevm.prank(ADDRESS_VAULT);\n ousd.changeSupply(amount);\n }\n\n /**\n * @notice Transfer tokens between accounts\n * @param fromAcc Account to transfer from\n * @param toAcc Account to transfer to\n * @param amount Amount to transfer\n */\n function transfer(\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public {\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n hevm.prank(from);\n // slither-disable-next-line unchecked-transfer\n ousd.transfer(to, amount);\n }\n\n /**\n * @notice Transfer approved tokens between accounts\n * @param authorizedAcc Account that is authorized to transfer\n * @param fromAcc Account to transfer from\n * @param toAcc Account to transfer to\n * @param amount Amount to transfer\n */\n function transferFrom(\n uint8 authorizedAcc,\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public {\n address authorized = getAccount(authorizedAcc);\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n hevm.prank(authorized);\n // slither-disable-next-line unchecked-transfer\n ousd.transferFrom(from, to, amount);\n }\n\n /**\n * @notice Opt in to rebasing\n * @param targetAcc Account to opt in\n */\n function optIn(uint8 targetAcc) public {\n address target = getAccount(targetAcc);\n hevm.prank(target);\n ousd.rebaseOptIn();\n }\n\n /**\n * @notice Opt out of rebasing\n * @param targetAcc Account to opt out\n */\n function optOut(uint8 targetAcc) public {\n address target = getAccount(targetAcc);\n hevm.prank(target);\n ousd.rebaseOptOut();\n }\n\n /**\n * @notice Approve an account to spend OUSD\n * @param ownerAcc Account that owns the OUSD\n * @param spenderAcc Account that is approved to spend the OUSD\n * @param amount Amount to approve\n */\n function approve(\n uint8 ownerAcc,\n uint8 spenderAcc,\n uint256 amount\n ) public {\n address owner = getAccount(ownerAcc);\n address spender = getAccount(spenderAcc);\n hevm.prank(owner);\n // slither-disable-next-line unused-return\n ousd.approve(spender, amount);\n }\n\n /**\n * @notice Increase the allowance of an account to spend OUSD\n * @param ownerAcc Account that owns the OUSD\n * @param spenderAcc Account that is approved to spend the OUSD\n * @param amount Amount to increase the allowance by\n */\n function increaseAllowance(\n uint8 ownerAcc,\n uint8 spenderAcc,\n uint256 amount\n ) public {\n address owner = getAccount(ownerAcc);\n address spender = getAccount(spenderAcc);\n hevm.prank(owner);\n // slither-disable-next-line unused-return\n ousd.increaseAllowance(spender, amount);\n }\n\n /**\n * @notice Decrease the allowance of an account to spend OUSD\n * @param ownerAcc Account that owns the OUSD\n * @param spenderAcc Account that is approved to spend the OUSD\n * @param amount Amount to decrease the allowance by\n */\n function decreaseAllowance(\n uint8 ownerAcc,\n uint8 spenderAcc,\n uint256 amount\n ) public {\n address owner = getAccount(ownerAcc);\n address spender = getAccount(spenderAcc);\n hevm.prank(owner);\n // slither-disable-next-line unused-return\n ousd.decreaseAllowance(spender, amount);\n }\n\n /**\n * @notice Get the sum of all OUSD balances\n * @return total Total balance\n */\n function getTotalBalance() public view returns (uint256 total) {\n total += ousd.balanceOf(ADDRESS_VAULT);\n total += ousd.balanceOf(ADDRESS_OUTSIDER_USER);\n total += ousd.balanceOf(ADDRESS_OUTSIDER_CONTRACT);\n total += ousd.balanceOf(ADDRESS_USER0);\n total += ousd.balanceOf(ADDRESS_USER1);\n total += ousd.balanceOf(ADDRESS_CONTRACT0);\n total += ousd.balanceOf(ADDRESS_CONTRACT1);\n }\n\n /**\n * @notice Get the sum of all non-rebasing OUSD balances\n * @return total Total balance\n */\n function getTotalNonRebasingBalance() public returns (uint256 total) {\n total += ousd._isNonRebasingAccountEchidna(ADDRESS_VAULT)\n ? ousd.balanceOf(ADDRESS_VAULT)\n : 0;\n total += ousd._isNonRebasingAccountEchidna(ADDRESS_OUTSIDER_USER)\n ? ousd.balanceOf(ADDRESS_OUTSIDER_USER)\n : 0;\n total += ousd._isNonRebasingAccountEchidna(ADDRESS_OUTSIDER_CONTRACT)\n ? ousd.balanceOf(ADDRESS_OUTSIDER_CONTRACT)\n : 0;\n total += ousd._isNonRebasingAccountEchidna(ADDRESS_USER0)\n ? ousd.balanceOf(ADDRESS_USER0)\n : 0;\n total += ousd._isNonRebasingAccountEchidna(ADDRESS_USER1)\n ? ousd.balanceOf(ADDRESS_USER1)\n : 0;\n total += ousd._isNonRebasingAccountEchidna(ADDRESS_CONTRACT0)\n ? ousd.balanceOf(ADDRESS_CONTRACT0)\n : 0;\n total += ousd._isNonRebasingAccountEchidna(ADDRESS_CONTRACT1)\n ? ousd.balanceOf(ADDRESS_CONTRACT1)\n : 0;\n }\n}\n" + }, + "contracts/echidna/EchidnaSetup.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./IHevm.sol\";\nimport \"./EchidnaConfig.sol\";\nimport \"./OUSDEchidna.sol\";\n\ncontract Dummy {}\n\n/**\n * @title Mixin for setup and deployment\n * @author Rappie\n */\ncontract EchidnaSetup is EchidnaConfig {\n IHevm hevm = IHevm(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D);\n OUSDEchidna ousd = new OUSDEchidna();\n\n /**\n * @notice Deploy the OUSD contract and set up initial state\n */\n constructor() {\n ousd.initialize(\"Origin Dollar\", \"OUSD\", ADDRESS_VAULT, 1e18);\n\n // Deploy dummny contracts as users\n Dummy outsider = new Dummy();\n ADDRESS_OUTSIDER_CONTRACT = address(outsider);\n Dummy dummy0 = new Dummy();\n ADDRESS_CONTRACT0 = address(dummy0);\n Dummy dummy1 = new Dummy();\n ADDRESS_CONTRACT1 = address(dummy1);\n\n // Start out with a reasonable amount of OUSD\n if (TOGGLE_STARTING_BALANCE) {\n // Rebasing tokens\n hevm.prank(ADDRESS_VAULT);\n ousd.mint(ADDRESS_OUTSIDER_USER, STARTING_BALANCE / 2);\n\n // Non-rebasing tokens\n hevm.prank(ADDRESS_VAULT);\n ousd.mint(ADDRESS_OUTSIDER_CONTRACT, STARTING_BALANCE / 2);\n }\n }\n}\n" + }, + "contracts/echidna/EchidnaTestAccounting.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./EchidnaDebug.sol\";\nimport \"./EchidnaTestSupply.sol\";\n\n/**\n * @title Mixin for testing accounting functions\n * @author Rappie\n */\ncontract EchidnaTestAccounting is EchidnaTestSupply {\n /**\n * @notice After opting in, balance should not increase. (Ok to lose rounding funds doing this)\n * @param targetAcc Account to opt in\n */\n function testOptInBalance(uint8 targetAcc) public {\n address target = getAccount(targetAcc);\n\n uint256 balanceBefore = ousd.balanceOf(target);\n optIn(targetAcc);\n uint256 balanceAfter = ousd.balanceOf(target);\n\n assert(balanceAfter <= balanceBefore);\n }\n\n /**\n * @notice After opting out, balance should remain the same\n * @param targetAcc Account to opt out\n */\n function testOptOutBalance(uint8 targetAcc) public {\n address target = getAccount(targetAcc);\n\n uint256 balanceBefore = ousd.balanceOf(target);\n optOut(targetAcc);\n uint256 balanceAfter = ousd.balanceOf(target);\n\n assert(balanceAfter == balanceBefore);\n }\n\n /**\n * @notice Account balance should remain the same after opting in minus rounding error\n * @param targetAcc Account to opt in\n */\n function testOptInBalanceRounding(uint8 targetAcc) public {\n address target = getAccount(targetAcc);\n\n uint256 balanceBefore = ousd.balanceOf(target);\n optIn(targetAcc);\n uint256 balanceAfter = ousd.balanceOf(target);\n\n int256 delta = int256(balanceAfter) - int256(balanceBefore);\n Debugger.log(\"delta\", delta);\n\n // slither-disable-next-line tautology\n assert(-1 * delta >= 0);\n assert(-1 * delta <= int256(OPT_IN_ROUNDING_ERROR));\n }\n\n /**\n * @notice After opting in, total supply should remain the same\n * @param targetAcc Account to opt in\n */\n function testOptInTotalSupply(uint8 targetAcc) public {\n uint256 totalSupplyBefore = ousd.totalSupply();\n optIn(targetAcc);\n uint256 totalSupplyAfter = ousd.totalSupply();\n\n assert(totalSupplyAfter == totalSupplyBefore);\n }\n\n /**\n * @notice After opting out, total supply should remain the same\n * @param targetAcc Account to opt out\n */\n function testOptOutTotalSupply(uint8 targetAcc) public {\n uint256 totalSupplyBefore = ousd.totalSupply();\n optOut(targetAcc);\n uint256 totalSupplyAfter = ousd.totalSupply();\n\n assert(totalSupplyAfter == totalSupplyBefore);\n }\n\n /**\n * @notice Account balance should remain the same when a smart contract auto converts\n * @param targetAcc Account to auto convert\n */\n function testAutoConvertBalance(uint8 targetAcc) public {\n address target = getAccount(targetAcc);\n\n uint256 balanceBefore = ousd.balanceOf(target);\n // slither-disable-next-line unused-return\n ousd._isNonRebasingAccountEchidna(target);\n uint256 balanceAfter = ousd.balanceOf(target);\n\n assert(balanceAfter == balanceBefore);\n }\n\n /**\n * @notice The `balanceOf` function should never revert\n * @param targetAcc Account to check balance of\n */\n function testBalanceOfShouldNotRevert(uint8 targetAcc) public {\n address target = getAccount(targetAcc);\n\n // slither-disable-next-line unused-return\n try ousd.balanceOf(target) {\n assert(true);\n } catch {\n assert(false);\n }\n }\n}\n" + }, + "contracts/echidna/EchidnaTestApproval.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./EchidnaTestMintBurn.sol\";\nimport \"./Debugger.sol\";\n\n/**\n * @title Mixin for testing approval related functions\n * @author Rappie\n */\ncontract EchidnaTestApproval is EchidnaTestMintBurn {\n /**\n * @notice Performing `transferFrom` with an amount inside the allowance should not revert\n * @param authorizedAcc The account that is authorized to transfer\n * @param fromAcc The account that is transferring\n * @param toAcc The account that is receiving\n * @param amount The amount to transfer\n */\n function testTransferFromShouldNotRevert(\n uint8 authorizedAcc,\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public {\n address authorized = getAccount(authorizedAcc);\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n\n require(amount <= ousd.balanceOf(from));\n require(amount <= ousd.allowance(from, authorized));\n\n hevm.prank(authorized);\n // slither-disable-next-line unchecked-transfer\n try ousd.transferFrom(from, to, amount) {\n // pass\n } catch {\n assert(false);\n }\n }\n\n /**\n * @notice Performing `transferFrom` with an amount outside the allowance should revert\n * @param authorizedAcc The account that is authorized to transfer\n * @param fromAcc The account that is transferring\n * @param toAcc The account that is receiving\n * @param amount The amount to transfer\n */\n function testTransferFromShouldRevert(\n uint8 authorizedAcc,\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public {\n address authorized = getAccount(authorizedAcc);\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n\n require(amount > 0);\n require(\n !(amount <= ousd.balanceOf(from) &&\n amount <= ousd.allowance(from, authorized))\n );\n\n hevm.prank(authorized);\n // slither-disable-next-line unchecked-transfer\n try ousd.transferFrom(from, to, amount) {\n assert(false);\n } catch {\n // pass\n }\n }\n\n /**\n * @notice Approving an amount should update the allowance and overwrite any previous allowance\n * @param ownerAcc The account that is approving\n * @param spenderAcc The account that is being approved\n * @param amount The amount to approve\n */\n function testApprove(\n uint8 ownerAcc,\n uint8 spenderAcc,\n uint256 amount\n ) public {\n address owner = getAccount(ownerAcc);\n address spender = getAccount(spenderAcc);\n\n approve(ownerAcc, spenderAcc, amount);\n uint256 allowanceAfter1 = ousd.allowance(owner, spender);\n\n assert(allowanceAfter1 == amount);\n\n approve(ownerAcc, spenderAcc, amount / 2);\n uint256 allowanceAfter2 = ousd.allowance(owner, spender);\n\n assert(allowanceAfter2 == amount / 2);\n }\n\n /**\n * @notice Increasing the allowance should raise it by the amount provided\n * @param ownerAcc The account that is approving\n * @param spenderAcc The account that is being approved\n * @param amount The amount to approve\n */\n function testIncreaseAllowance(\n uint8 ownerAcc,\n uint8 spenderAcc,\n uint256 amount\n ) public {\n address owner = getAccount(ownerAcc);\n address spender = getAccount(spenderAcc);\n\n uint256 allowanceBefore = ousd.allowance(owner, spender);\n increaseAllowance(ownerAcc, spenderAcc, amount);\n uint256 allowanceAfter = ousd.allowance(owner, spender);\n\n assert(allowanceAfter == allowanceBefore + amount);\n }\n\n /**\n * @notice Decreasing the allowance should lower it by the amount provided\n * @param ownerAcc The account that is approving\n * @param spenderAcc The account that is being approved\n * @param amount The amount to approve\n */\n function testDecreaseAllowance(\n uint8 ownerAcc,\n uint8 spenderAcc,\n uint256 amount\n ) public {\n address owner = getAccount(ownerAcc);\n address spender = getAccount(spenderAcc);\n\n uint256 allowanceBefore = ousd.allowance(owner, spender);\n decreaseAllowance(ownerAcc, spenderAcc, amount);\n uint256 allowanceAfter = ousd.allowance(owner, spender);\n\n assert(allowanceAfter == allowanceBefore - amount);\n }\n}\n" + }, + "contracts/echidna/EchidnaTestMintBurn.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./EchidnaDebug.sol\";\nimport \"./EchidnaTestAccounting.sol\";\n\n/**\n * @title Mixin for testing Mint and Burn functions\n * @author Rappie\n */\ncontract EchidnaTestMintBurn is EchidnaTestAccounting {\n /**\n * @notice Minting 0 tokens should not affect account balance\n * @param targetAcc Account to mint to\n */\n function testMintZeroBalance(uint8 targetAcc) public {\n address target = getAccount(targetAcc);\n\n uint256 balanceBefore = ousd.balanceOf(target);\n mint(targetAcc, 0);\n uint256 balanceAfter = ousd.balanceOf(target);\n\n assert(balanceAfter == balanceBefore);\n }\n\n /**\n * @notice Burning 0 tokens should not affect account balance\n * @param targetAcc Account to burn from\n */\n function testBurnZeroBalance(uint8 targetAcc) public {\n address target = getAccount(targetAcc);\n\n uint256 balanceBefore = ousd.balanceOf(target);\n burn(targetAcc, 0);\n uint256 balanceAfter = ousd.balanceOf(target);\n\n assert(balanceAfter == balanceBefore);\n }\n\n /**\n * @notice Minting tokens must increase the account balance by at least amount\n * @param targetAcc Account to mint to\n * @param amount Amount to mint\n * @custom:error testMintBalance(uint8,uint256): failed!💥\n * Call sequence:\n * changeSupply(1)\n * testMintBalance(0,1)\n * Event sequence:\n * Debug(«balanceBefore», 0)\n * Debug(«balanceAfter», 0)\n */\n function testMintBalance(uint8 targetAcc, uint256 amount)\n public\n hasKnownIssue\n hasKnownIssueWithinLimits\n {\n address target = getAccount(targetAcc);\n\n uint256 balanceBefore = ousd.balanceOf(target);\n uint256 amountMinted = mint(targetAcc, amount);\n uint256 balanceAfter = ousd.balanceOf(target);\n\n Debugger.log(\"amountMinted\", amountMinted);\n Debugger.log(\"balanceBefore\", balanceBefore);\n Debugger.log(\"balanceAfter\", balanceAfter);\n\n assert(balanceAfter >= balanceBefore + amountMinted);\n }\n\n /**\n * @notice Burning tokens must decrease the account balance by at least amount\n * @param targetAcc Account to burn from\n * @param amount Amount to burn\n * @custom:error testBurnBalance(uint8,uint256): failed!💥\n * Call sequence:\n * changeSupply(1)\n * mint(0,3)\n * testBurnBalance(0,1)\n * Event sequence:\n * Debug(«balanceBefore», 2)\n * Debug(«balanceAfter», 2)\n */\n function testBurnBalance(uint8 targetAcc, uint256 amount)\n public\n hasKnownIssue\n hasKnownIssueWithinLimits\n {\n address target = getAccount(targetAcc);\n\n uint256 balanceBefore = ousd.balanceOf(target);\n burn(targetAcc, amount);\n uint256 balanceAfter = ousd.balanceOf(target);\n\n Debugger.log(\"balanceBefore\", balanceBefore);\n Debugger.log(\"balanceAfter\", balanceAfter);\n\n assert(balanceAfter <= balanceBefore - amount);\n }\n\n /**\n * @notice Minting tokens should not increase the account balance by less than rounding error above amount\n * @param targetAcc Account to mint to\n * @param amount Amount to mint\n */\n function testMintBalanceRounding(uint8 targetAcc, uint256 amount) public {\n address target = getAccount(targetAcc);\n\n uint256 balanceBefore = ousd.balanceOf(target);\n uint256 amountMinted = mint(targetAcc, amount);\n uint256 balanceAfter = ousd.balanceOf(target);\n\n int256 delta = int256(balanceAfter) - int256(balanceBefore);\n\n // delta == amount, if no error\n // delta < amount, if too little is minted\n // delta > amount, if too much is minted\n int256 error = int256(amountMinted) - delta;\n\n assert(error >= 0);\n assert(error <= int256(MINT_ROUNDING_ERROR));\n }\n\n /**\n * @notice A burn of an account balance must result in a zero balance\n * @param targetAcc Account to burn from\n */\n function testBurnAllBalanceToZero(uint8 targetAcc) public hasKnownIssue {\n address target = getAccount(targetAcc);\n\n burn(targetAcc, ousd.balanceOf(target));\n assert(ousd.balanceOf(target) == 0);\n }\n\n /**\n * @notice You should always be able to burn an account's balance\n * @param targetAcc Account to burn from\n */\n function testBurnAllBalanceShouldNotRevert(uint8 targetAcc)\n public\n hasKnownIssue\n {\n address target = getAccount(targetAcc);\n uint256 balance = ousd.balanceOf(target);\n\n hevm.prank(ADDRESS_VAULT);\n try ousd.burn(target, balance) {\n assert(true);\n } catch {\n assert(false);\n }\n }\n}\n" + }, + "contracts/echidna/EchidnaTestSupply.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./EchidnaDebug.sol\";\nimport \"./EchidnaTestTransfer.sol\";\n\nimport { StableMath } from \"../utils/StableMath.sol\";\n\n/**\n * @title Mixin for testing supply related functions\n * @author Rappie\n */\ncontract EchidnaTestSupply is EchidnaTestTransfer {\n using StableMath for uint256;\n\n uint256 prevRebasingCreditsPerToken = type(uint256).max;\n\n /**\n * @notice After a `changeSupply`, the total supply should exactly\n * match the target total supply. (This is needed to ensure successive\n * rebases are correct).\n * @param supply New total supply\n * @custom:error testChangeSupply(uint256): failed!💥\n * Call sequence:\n * testChangeSupply(1044505275072865171609)\n * Event sequence:\n * TotalSupplyUpdatedHighres(1044505275072865171610, 1000000000000000000000000, 957391048054055578595)\n */\n function testChangeSupply(uint256 supply)\n public\n hasKnownIssue\n hasKnownIssueWithinLimits\n {\n hevm.prank(ADDRESS_VAULT);\n ousd.changeSupply(supply);\n\n assert(ousd.totalSupply() == supply);\n }\n\n /**\n * @notice The total supply must not be less than the sum of account balances.\n * (The difference will go into future rebases)\n * @custom:error testTotalSupplyLessThanTotalBalance(): failed!💥\n * Call sequence:\n * mint(0,1)\n * changeSupply(1)\n * optOut(64)\n * transfer(0,64,1)\n * testTotalSupplyLessThanTotalBalance()\n * Event sequence:\n * Debug(«totalSupply», 1000000000000000001000001)\n * Debug(«totalBalance», 1000000000000000001000002)\n */\n function testTotalSupplyLessThanTotalBalance()\n public\n hasKnownIssue\n hasKnownIssueWithinLimits\n {\n uint256 totalSupply = ousd.totalSupply();\n uint256 totalBalance = getTotalBalance();\n\n Debugger.log(\"totalSupply\", totalSupply);\n Debugger.log(\"totalBalance\", totalBalance);\n\n assert(totalSupply >= totalBalance);\n }\n\n /**\n * @notice Non-rebasing supply should not be larger than total supply\n * @custom:error testNonRebasingSupplyVsTotalSupply(): failed!💥\n * Call sequence:\n * mint(0,2)\n * changeSupply(3)\n * burn(0,1)\n * optOut(0)\n * testNonRebasingSupplyVsTotalSupply()\n */\n function testNonRebasingSupplyVsTotalSupply() public hasKnownIssue {\n uint256 nonRebasingSupply = ousd.nonRebasingSupply();\n uint256 totalSupply = ousd.totalSupply();\n\n assert(nonRebasingSupply <= totalSupply);\n }\n\n /**\n * @notice Global `rebasingCreditsPerToken` should never increase\n * @custom:error testRebasingCreditsPerTokenNotIncreased(): failed!💥\n * Call sequence:\n * testRebasingCreditsPerTokenNotIncreased()\n * changeSupply(1)\n * testRebasingCreditsPerTokenNotIncreased()\n */\n function testRebasingCreditsPerTokenNotIncreased() public hasKnownIssue {\n uint256 curRebasingCreditsPerToken = ousd\n .rebasingCreditsPerTokenHighres();\n\n Debugger.log(\n \"prevRebasingCreditsPerToken\",\n prevRebasingCreditsPerToken\n );\n Debugger.log(\"curRebasingCreditsPerToken\", curRebasingCreditsPerToken);\n\n assert(curRebasingCreditsPerToken <= prevRebasingCreditsPerToken);\n\n prevRebasingCreditsPerToken = curRebasingCreditsPerToken;\n }\n\n /**\n * @notice The rebasing credits per token ratio must greater than zero\n */\n function testRebasingCreditsPerTokenAboveZero() public {\n assert(ousd.rebasingCreditsPerTokenHighres() > 0);\n }\n\n /**\n * @notice The sum of all non-rebasing balances should not be larger than\n * non-rebasing supply\n * @custom:error testTotalNonRebasingSupplyLessThanTotalBalance(): failed!💥\n * Call sequence\n * mint(0,2)\n * changeSupply(1)\n * optOut(0)\n * burn(0,1)\n * testTotalNonRebasingSupplyLessThanTotalBalance()\n * Event sequence:\n * Debug(«totalNonRebasingSupply», 500000000000000000000001)\n * Debug(«totalNonRebasingBalance», 500000000000000000000002)\n */\n function testTotalNonRebasingSupplyLessThanTotalBalance()\n public\n hasKnownIssue\n hasKnownIssueWithinLimits\n {\n uint256 totalNonRebasingSupply = ousd.nonRebasingSupply();\n uint256 totalNonRebasingBalance = getTotalNonRebasingBalance();\n\n Debugger.log(\"totalNonRebasingSupply\", totalNonRebasingSupply);\n Debugger.log(\"totalNonRebasingBalance\", totalNonRebasingBalance);\n\n assert(totalNonRebasingSupply >= totalNonRebasingBalance);\n }\n\n /**\n * @notice An accounts credits / credits per token should not be larger it's balance\n * @param targetAcc The account to check\n */\n function testCreditsPerTokenVsBalance(uint8 targetAcc) public {\n address target = getAccount(targetAcc);\n\n (uint256 credits, uint256 creditsPerToken, ) = ousd\n .creditsBalanceOfHighres(target);\n uint256 expectedBalance = credits.divPrecisely(creditsPerToken);\n\n uint256 balance = ousd.balanceOf(target);\n\n Debugger.log(\"credits\", credits);\n Debugger.log(\"creditsPerToken\", creditsPerToken);\n Debugger.log(\"expectedBalance\", expectedBalance);\n Debugger.log(\"balance\", balance);\n\n assert(expectedBalance == balance);\n }\n}\n" + }, + "contracts/echidna/EchidnaTestTransfer.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./EchidnaDebug.sol\";\nimport \"./Debugger.sol\";\n\n/**\n * @title Mixin for testing transfer related functions\n * @author Rappie\n */\ncontract EchidnaTestTransfer is EchidnaDebug {\n /**\n * @notice The receiving account's balance after a transfer must not increase by\n * less than the amount transferred\n * @param fromAcc Account to transfer from\n * @param toAcc Account to transfer to\n * @param amount Amount to transfer\n * @custom:error testTransferBalanceReceivedLess(uint8,uint8,uint256): failed!💥\n * Call sequence:\n * changeSupply(1)\n * mint(64,2)\n * testTransferBalanceReceivedLess(64,0,1)\n * Event sequence:\n * Debug(«totalSupply», 1000000000000000000500002)\n * Debug(«toBalBefore», 0)\n * Debug(«toBalAfter», 0)\n */\n function testTransferBalanceReceivedLess(\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public hasKnownIssue hasKnownIssueWithinLimits {\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n\n require(from != to);\n\n uint256 toBalBefore = ousd.balanceOf(to);\n transfer(fromAcc, toAcc, amount);\n uint256 toBalAfter = ousd.balanceOf(to);\n\n Debugger.log(\"totalSupply\", ousd.totalSupply());\n Debugger.log(\"toBalBefore\", toBalBefore);\n Debugger.log(\"toBalAfter\", toBalAfter);\n\n assert(toBalAfter >= toBalBefore + amount);\n }\n\n /**\n * @notice The receiving account's balance after a transfer must not\n * increase by more than the amount transferred\n * @param fromAcc Account to transfer from\n * @param toAcc Account to transfer to\n * @param amount Amount to transfer\n */\n function testTransferBalanceReceivedMore(\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public {\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n\n require(from != to);\n\n uint256 toBalBefore = ousd.balanceOf(to);\n transfer(fromAcc, toAcc, amount);\n uint256 toBalAfter = ousd.balanceOf(to);\n\n Debugger.log(\"totalSupply\", ousd.totalSupply());\n Debugger.log(\"toBalBefore\", toBalBefore);\n Debugger.log(\"toBalAfter\", toBalAfter);\n\n assert(toBalAfter <= toBalBefore + amount);\n }\n\n /**\n * @notice The sending account's balance after a transfer must not\n * decrease by less than the amount transferred\n * @param fromAcc Account to transfer from\n * @param toAcc Account to transfer to\n * @param amount Amount to transfer\n * @custom:error testTransferBalanceSentLess(uint8,uint8,uint256): failed!💥\n * Call sequence:\n * mint(0,1)\n * changeSupply(1)\n * testTransferBalanceSentLess(0,64,1)\n * Event sequence:\n * Debug(«totalSupply», 1000000000000000000500001)\n * Debug(«fromBalBefore», 1)\n * Debug(«fromBalAfter», 1)\n */\n function testTransferBalanceSentLess(\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public hasKnownIssue hasKnownIssueWithinLimits {\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n\n require(from != to);\n\n uint256 fromBalBefore = ousd.balanceOf(from);\n transfer(fromAcc, toAcc, amount);\n uint256 fromBalAfter = ousd.balanceOf(from);\n\n Debugger.log(\"totalSupply\", ousd.totalSupply());\n Debugger.log(\"fromBalBefore\", fromBalBefore);\n Debugger.log(\"fromBalAfter\", fromBalAfter);\n\n assert(fromBalAfter <= fromBalBefore - amount);\n }\n\n /**\n * @notice The sending account's balance after a transfer must not\n * decrease by more than the amount transferred\n * @param fromAcc Account to transfer from\n * @param toAcc Account to transfer to\n * @param amount Amount to transfer\n */\n function testTransferBalanceSentMore(\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public {\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n\n require(from != to);\n\n uint256 fromBalBefore = ousd.balanceOf(from);\n transfer(fromAcc, toAcc, amount);\n uint256 fromBalAfter = ousd.balanceOf(from);\n\n Debugger.log(\"totalSupply\", ousd.totalSupply());\n Debugger.log(\"fromBalBefore\", fromBalBefore);\n Debugger.log(\"fromBalAfter\", fromBalAfter);\n\n assert(fromBalAfter >= fromBalBefore - amount);\n }\n\n /**\n * @notice The receiving account's balance after a transfer must not\n * increase by less than the amount transferred (minus rounding error)\n * @param fromAcc Account to transfer from\n * @param toAcc Account to transfer to\n * @param amount Amount to transfer\n */\n function testTransferBalanceReceivedLessRounding(\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public {\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n\n require(from != to);\n\n uint256 toBalBefore = ousd.balanceOf(to);\n transfer(fromAcc, toAcc, amount);\n uint256 toBalAfter = ousd.balanceOf(to);\n\n int256 toDelta = int256(toBalAfter) - int256(toBalBefore);\n\n // delta == amount, if no error\n // delta < amount, if too little is sent\n // delta > amount, if too much is sent\n int256 error = int256(amount) - toDelta;\n\n Debugger.log(\"totalSupply\", ousd.totalSupply());\n Debugger.log(\"toBalBefore\", toBalBefore);\n Debugger.log(\"toBalAfter\", toBalAfter);\n Debugger.log(\"toDelta\", toDelta);\n Debugger.log(\"error\", error);\n\n assert(error >= 0);\n assert(error <= int256(TRANSFER_ROUNDING_ERROR));\n }\n\n /**\n * @notice The sending account's balance after a transfer must\n * not decrease by less than the amount transferred (minus rounding error)\n * @param fromAcc Account to transfer from\n * @param toAcc Account to transfer to\n * @param amount Amount to transfer\n */\n function testTransferBalanceSentLessRounding(\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public {\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n\n require(from != to);\n\n uint256 fromBalBefore = ousd.balanceOf(from);\n transfer(fromAcc, toAcc, amount);\n uint256 fromBalAfter = ousd.balanceOf(from);\n\n int256 fromDelta = int256(fromBalAfter) - int256(fromBalBefore);\n\n // delta == -amount, if no error\n // delta < -amount, if too much is sent\n // delta > -amount, if too little is sent\n int256 error = int256(amount) + fromDelta;\n\n Debugger.log(\"totalSupply\", ousd.totalSupply());\n Debugger.log(\"fromBalBefore\", fromBalBefore);\n Debugger.log(\"fromBalAfter\", fromBalAfter);\n Debugger.log(\"fromDelta\", fromDelta);\n Debugger.log(\"error\", error);\n\n assert(error >= 0);\n assert(error <= int256(TRANSFER_ROUNDING_ERROR));\n }\n\n /**\n * @notice An account should always be able to successfully transfer\n * an amount within its balance.\n * @param fromAcc Account to transfer from\n * @param toAcc Account to transfer to\n * @param amount Amount to transfer\n * @custom:error testTransferWithinBalanceDoesNotRevert(uint8,uint8,uint8): failed!💥\n * Call sequence:\n * mint(0,1)\n * changeSupply(3)\n * optOut(0)\n * testTransferWithinBalanceDoesNotRevert(0,128,2)\n * optIn(0)\n * testTransferWithinBalanceDoesNotRevert(128,0,1)\n * Event sequence:\n * error Revert Panic(17): SafeMath over-/under-flows\n */\n function testTransferWithinBalanceDoesNotRevert(\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public hasKnownIssue {\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n\n require(amount > 0);\n amount = amount % ousd.balanceOf(from);\n\n Debugger.log(\"Total supply\", ousd.totalSupply());\n\n hevm.prank(from);\n // slither-disable-next-line unchecked-transfer\n try ousd.transfer(to, amount) {\n assert(true);\n } catch {\n assert(false);\n }\n }\n\n /**\n * @notice An account should never be able to successfully transfer\n * an amount greater than their balance.\n * @param fromAcc Account to transfer from\n * @param toAcc Account to transfer to\n * @param amount Amount to transfer\n */\n function testTransferExceedingBalanceReverts(\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public {\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n\n amount = ousd.balanceOf(from) + 1 + amount;\n\n hevm.prank(from);\n // slither-disable-next-line unchecked-transfer\n try ousd.transfer(to, amount) {\n assert(false);\n } catch {\n assert(true);\n }\n }\n\n /**\n * @notice A transfer to the same account should not change that account's balance\n * @param targetAcc Account to transfer to\n * @param amount Amount to transfer\n */\n function testTransferSelf(uint8 targetAcc, uint256 amount) public {\n address target = getAccount(targetAcc);\n\n uint256 balanceBefore = ousd.balanceOf(target);\n transfer(targetAcc, targetAcc, amount);\n uint256 balanceAfter = ousd.balanceOf(target);\n\n assert(balanceBefore == balanceAfter);\n }\n\n /**\n * @notice Transfers to the zero account revert\n * @param fromAcc Account to transfer from\n * @param amount Amount to transfer\n */\n function testTransferToZeroAddress(uint8 fromAcc, uint256 amount) public {\n address from = getAccount(fromAcc);\n\n hevm.prank(from);\n // slither-disable-next-line unchecked-transfer\n try ousd.transfer(address(0), amount) {\n assert(false);\n } catch {\n assert(true);\n }\n }\n}\n" + }, + "contracts/echidna/IHevm.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n// https://github.com/ethereum/hevm/blob/main/doc/src/controlling-the-unit-testing-environment.md#cheat-codes\n\ninterface IHevm {\n function warp(uint256 x) external;\n\n function roll(uint256 x) external;\n\n function store(\n address c,\n bytes32 loc,\n bytes32 val\n ) external;\n\n function load(address c, bytes32 loc) external returns (bytes32 val);\n\n function sign(uint256 sk, bytes32 digest)\n external\n returns (\n uint8 v,\n bytes32 r,\n bytes32 s\n );\n\n function addr(uint256 sk) external returns (address addr);\n\n function ffi(string[] calldata) external returns (bytes memory);\n\n function prank(address sender) external;\n}\n" + }, + "contracts/echidna/OUSDEchidna.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../token/OUSD.sol\";\n\ncontract OUSDEchidna is OUSD {\n constructor() OUSD() {}\n\n function _isNonRebasingAccountEchidna(address _account)\n public\n returns (bool)\n {\n return _isNonRebasingAccount(_account);\n }\n}\n" + }, + "contracts/flipper/Flipper.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../governance/Governable.sol\";\nimport \"../token/OUSD.sol\";\nimport \"../interfaces/Tether.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Contract to exchange usdt, usdc, dai from and to ousd.\n// - 1 to 1. No slippage\n// - Optimized for low gas usage\n// - No guarantee of availability\n\ncontract Flipper is Governable {\n using SafeERC20 for IERC20;\n\n uint256 constant MAXIMUM_PER_TRADE = (25000 * 1e18);\n\n // Settable coin addresses allow easy testing and use of mock currencies.\n IERC20 immutable dai;\n OUSD immutable ousd;\n IERC20 immutable usdc;\n Tether immutable usdt;\n\n // ---------------------\n // Dev constructor\n // ---------------------\n constructor(\n address _dai,\n address _ousd,\n address _usdc,\n address _usdt\n ) {\n require(address(_dai) != address(0));\n require(address(_ousd) != address(0));\n require(address(_usdc) != address(0));\n require(address(_usdt) != address(0));\n dai = IERC20(_dai);\n ousd = OUSD(_ousd);\n usdc = IERC20(_usdc);\n usdt = Tether(_usdt);\n }\n\n // -----------------\n // Trading functions\n // -----------------\n\n /// @notice Purchase OUSD with Dai\n /// @param amount Amount of OUSD to purchase, in 18 fixed decimals.\n function buyOusdWithDai(uint256 amount) external {\n require(amount <= MAXIMUM_PER_TRADE, \"Amount too large\");\n require(\n dai.transferFrom(msg.sender, address(this), amount),\n \"DAI transfer failed\"\n );\n require(ousd.transfer(msg.sender, amount), \"OUSD transfer failed\");\n }\n\n /// @notice Sell OUSD for Dai\n /// @param amount Amount of OUSD to sell, in 18 fixed decimals.\n function sellOusdForDai(uint256 amount) external {\n require(amount <= MAXIMUM_PER_TRADE, \"Amount too large\");\n require(dai.transfer(msg.sender, amount), \"DAI transfer failed\");\n require(\n ousd.transferFrom(msg.sender, address(this), amount),\n \"OUSD transfer failed\"\n );\n }\n\n /// @notice Purchase OUSD with USDC\n /// @param amount Amount of OUSD to purchase, in 18 fixed decimals.\n function buyOusdWithUsdc(uint256 amount) external {\n require(amount <= MAXIMUM_PER_TRADE, \"Amount too large\");\n // Potential rounding error is an intentional trade off\n require(\n usdc.transferFrom(msg.sender, address(this), amount / 1e12),\n \"USDC transfer failed\"\n );\n require(ousd.transfer(msg.sender, amount), \"OUSD transfer failed\");\n }\n\n /// @notice Sell OUSD for USDC\n /// @param amount Amount of OUSD to sell, in 18 fixed decimals.\n function sellOusdForUsdc(uint256 amount) external {\n require(amount <= MAXIMUM_PER_TRADE, \"Amount too large\");\n require(\n usdc.transfer(msg.sender, amount / 1e12),\n \"USDC transfer failed\"\n );\n require(\n ousd.transferFrom(msg.sender, address(this), amount),\n \"OUSD transfer failed\"\n );\n }\n\n /// @notice Purchase OUSD with USDT\n /// @param amount Amount of OUSD to purchase, in 18 fixed decimals.\n function buyOusdWithUsdt(uint256 amount) external {\n require(amount <= MAXIMUM_PER_TRADE, \"Amount too large\");\n // Potential rounding error is an intentional trade off\n // USDT does not return a boolean and reverts,\n // so no need for a require.\n usdt.transferFrom(msg.sender, address(this), amount / 1e12);\n require(ousd.transfer(msg.sender, amount), \"OUSD transfer failed\");\n }\n\n /// @notice Sell OUSD for USDT\n /// @param amount Amount of OUSD to sell, in 18 fixed decimals.\n function sellOusdForUsdt(uint256 amount) external {\n require(amount <= MAXIMUM_PER_TRADE, \"Amount too large\");\n // USDT does not return a boolean and reverts,\n // so no need for a require.\n usdt.transfer(msg.sender, amount / 1e12);\n require(\n ousd.transferFrom(msg.sender, address(this), amount),\n \"OUSD transfer failed\"\n );\n }\n\n // --------------------\n // Governance functions\n // --------------------\n\n /// @dev Opting into yield reduces the gas cost per transfer by about 4K, since\n /// ousd needs to do less accounting and one less storage write.\n function rebaseOptIn() external onlyGovernor nonReentrant {\n ousd.rebaseOptIn();\n }\n\n /// @notice Owner function to withdraw a specific amount of a token\n function withdraw(address token, uint256 amount)\n external\n onlyGovernor\n nonReentrant\n {\n IERC20(token).safeTransfer(_governor(), amount);\n }\n\n /// @notice Owner function to withdraw all tradable tokens\n /// @dev Contract will not perform any swaps until liquidity is provided\n /// again by transferring assets to the contract.\n function withdrawAll() external onlyGovernor nonReentrant {\n IERC20(dai).safeTransfer(_governor(), dai.balanceOf(address(this)));\n IERC20(ousd).safeTransfer(_governor(), ousd.balanceOf(address(this)));\n IERC20(address(usdt)).safeTransfer(\n _governor(),\n usdt.balanceOf(address(this))\n );\n IERC20(usdc).safeTransfer(_governor(), usdc.balanceOf(address(this)));\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/governance/Governor.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./../timelock/Timelock.sol\";\n\n// Modeled off of Compound's Governor Alpha\n// https://github.com/compound-finance/compound-protocol/blob/master/contracts/Governance/GovernorAlpha.sol\ncontract Governor is Timelock {\n // @notice The total number of proposals\n uint256 public proposalCount;\n\n struct Proposal {\n // @notice Unique id for looking up a proposal\n uint256 id;\n // @notice Creator of the proposal\n address proposer;\n // @notice The timestamp that the proposal will be available for\n // execution, set once the vote succeeds\n uint256 eta;\n // @notice the ordered list of target addresses for calls to be made\n address[] targets;\n // @notice The ordered list of function signatures to be called\n string[] signatures;\n // @notice The ordered list of calldata to be passed to each call\n bytes[] calldatas;\n // @notice Flag marking whether the proposal has been executed\n bool executed;\n }\n\n // @notice The official record of all proposals ever proposed\n mapping(uint256 => Proposal) public proposals;\n\n // @notice An event emitted when a new proposal is created\n event ProposalCreated(\n uint256 id,\n address proposer,\n address[] targets,\n string[] signatures,\n bytes[] calldatas,\n string description\n );\n\n // @notice An event emitted when a proposal has been queued in the Timelock\n event ProposalQueued(uint256 id, uint256 eta);\n\n // @notice An event emitted when a proposal has been executed in the Timelock\n event ProposalExecuted(uint256 id);\n\n // @notice An event emitted when a proposal has been cancelled\n event ProposalCancelled(uint256 id);\n\n uint256 public constant MAX_OPERATIONS = 32;\n\n // @notice Possible states that a proposal may be in\n enum ProposalState {\n Pending,\n Queued,\n Expired,\n Executed\n }\n\n constructor(address admin_, uint256 delay_) Timelock(admin_, delay_) {}\n\n /**\n * @notice Propose Governance call(s)\n * @param targets Ordered list of targeted addresses\n * @param signatures Orderd list of function signatures to be called\n * @param calldatas Orderded list of calldata to be passed with each call\n * @param description Description of the governance\n * @return uint256 id of the proposal\n */\n function propose(\n address[] memory targets,\n string[] memory signatures,\n bytes[] memory calldatas,\n string memory description\n ) public returns (uint256) {\n // Allow anyone to propose for now, since only admin can queue the\n // transaction it should be harmless, you just need to pay the gas\n require(\n targets.length == signatures.length &&\n targets.length == calldatas.length,\n \"Governor::propose: proposal function information arity mismatch\"\n );\n require(targets.length != 0, \"Governor::propose: must provide actions\");\n require(\n targets.length <= MAX_OPERATIONS,\n \"Governor::propose: too many actions\"\n );\n\n proposalCount++;\n Proposal memory newProposal = Proposal({\n id: proposalCount,\n proposer: msg.sender,\n eta: 0,\n targets: targets,\n signatures: signatures,\n calldatas: calldatas,\n executed: false\n });\n\n proposals[newProposal.id] = newProposal;\n\n emit ProposalCreated(\n newProposal.id,\n msg.sender,\n targets,\n signatures,\n calldatas,\n description\n );\n return newProposal.id;\n }\n\n /**\n * @notice Queue a proposal for execution\n * @param proposalId id of the proposal to queue\n */\n function queue(uint256 proposalId) public onlyAdmin {\n require(\n state(proposalId) == ProposalState.Pending,\n \"Governor::queue: proposal can only be queued if it is pending\"\n );\n Proposal storage proposal = proposals[proposalId];\n proposal.eta = block.timestamp + delay;\n\n for (uint256 i = 0; i < proposal.targets.length; i++) {\n _queueOrRevert(\n proposal.targets[i],\n proposal.signatures[i],\n proposal.calldatas[i],\n proposal.eta\n );\n }\n\n emit ProposalQueued(proposal.id, proposal.eta);\n }\n\n /**\n * @notice Get the state of a proposal\n * @param proposalId id of the proposal\n * @return ProposalState\n */\n function state(uint256 proposalId) public view returns (ProposalState) {\n require(\n proposalCount >= proposalId && proposalId > 0,\n \"Governor::state: invalid proposal id\"\n );\n Proposal storage proposal = proposals[proposalId];\n if (proposal.executed) {\n return ProposalState.Executed;\n } else if (proposal.eta == 0) {\n return ProposalState.Pending;\n } else if (block.timestamp >= proposal.eta + GRACE_PERIOD) {\n return ProposalState.Expired;\n } else {\n return ProposalState.Queued;\n }\n }\n\n function _queueOrRevert(\n address target,\n string memory signature,\n bytes memory data,\n uint256 eta\n ) internal {\n require(\n !queuedTransactions[\n keccak256(abi.encode(target, signature, keccak256(data), eta))\n ],\n \"Governor::_queueOrRevert: proposal action already queued at eta\"\n );\n require(\n queuedTransactions[queueTransaction(target, signature, data, eta)],\n \"Governor::_queueOrRevert: failed to queue transaction\"\n );\n }\n\n /**\n * @notice Execute a proposal.\n * @param proposalId id of the proposal\n */\n function execute(uint256 proposalId) public {\n require(\n state(proposalId) == ProposalState.Queued,\n \"Governor::execute: proposal can only be executed if it is queued\"\n );\n Proposal storage proposal = proposals[proposalId];\n proposal.executed = true;\n for (uint256 i = 0; i < proposal.targets.length; i++) {\n executeTransaction(\n proposal.targets[i],\n proposal.signatures[i],\n proposal.calldatas[i],\n proposal.eta\n );\n }\n emit ProposalExecuted(proposalId);\n }\n\n /**\n * @notice Cancel a proposal.\n * @param proposalId id of the proposal\n */\n function cancel(uint256 proposalId) public onlyAdmin {\n ProposalState proposalState = state(proposalId);\n\n require(\n proposalState == ProposalState.Queued ||\n proposalState == ProposalState.Pending,\n \"Governor::execute: proposal can only be cancelled if it is queued or pending\"\n );\n Proposal storage proposal = proposals[proposalId];\n proposal.eta = 1; // To mark the proposal as `Expired`\n for (uint256 i = 0; i < proposal.targets.length; i++) {\n cancelTransaction(\n proposal.targets[i],\n proposal.signatures[i],\n proposal.calldatas[i],\n proposal.eta\n );\n }\n emit ProposalCancelled(proposalId);\n }\n\n /**\n * @notice Get the actions that a proposal will take.\n * @param proposalId id of the proposal\n */\n function getActions(uint256 proposalId)\n public\n view\n returns (\n address[] memory targets,\n string[] memory signatures,\n bytes[] memory calldatas\n )\n {\n Proposal storage p = proposals[proposalId];\n return (p.targets, p.signatures, p.calldatas);\n }\n}\n" + }, + "contracts/governance/InitializableGovernable.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @title OUSD InitializableGovernable Contract\n * @author Origin Protocol Inc\n */\nimport { Initializable } from \"../utils/Initializable.sol\";\n\nimport { Governable } from \"./Governable.sol\";\n\ncontract InitializableGovernable is Governable, Initializable {\n function _initialize(address _newGovernor) internal {\n _changeGovernor(_newGovernor);\n }\n}\n" + }, + "contracts/governance/Strategizable.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { Governable } from \"./Governable.sol\";\n\ncontract Strategizable is Governable {\n event StrategistUpdated(address _address);\n\n // Address of strategist\n address public strategistAddr;\n\n // For future use\n uint256[50] private __gap;\n\n /**\n * @dev Verifies that the caller is either 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 * @dev Set address of Strategist\n * @param _address Address of Strategist\n */\n function setStrategistAddr(address _address) external onlyGovernor {\n _setStrategistAddr(_address);\n }\n\n /**\n * @dev Set address of Strategist\n * @param _address Address of Strategist\n */\n function _setStrategistAddr(address _address) internal {\n strategistAddr = _address;\n emit StrategistUpdated(_address);\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/IOracleWeightedPool.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n// The three values that can be queried:\n//\n// - PAIR_PRICE: the price of the tokens in the Pool, expressed as the price of the second token in units of the\n// first token. For example, if token A is worth $2, and token B is worth $4, the pair price will be 2.0.\n// Note that the price is computed *including* the tokens decimals. This means that the pair price of a Pool with\n// DAI and USDC will be close to 1.0, despite DAI having 18 decimals and USDC 6.\n//\n// - BPT_PRICE: the price of the Pool share token (BPT), in units of the first token.\n// Note that the price is computed *including* the tokens decimals. This means that the BPT price of a Pool with\n// USDC in which BPT is worth $5 will be 5.0, despite the BPT having 18 decimals and USDC 6.\n//\n// - INVARIANT: the value of the Pool's invariant, which serves as a measure of its liquidity.\nenum Variable {\n PAIR_PRICE,\n BPT_PRICE,\n INVARIANT\n}\n\n/**\n * @dev Information for a Time Weighted Average query.\n *\n * Each query computes the average over a window of duration `secs` seconds that ended `ago` seconds ago. For\n * example, the average over the past 30 minutes is computed by settings secs to 1800 and ago to 0. If secs is 1800\n * and ago is 1800 as well, the average between 60 and 30 minutes ago is computed instead.\n */\nstruct OracleAverageQuery {\n Variable variable;\n uint256 secs;\n uint256 ago;\n}\n\ninterface IOracleWeightedPool {\n /**\n * @dev Returns the time average weighted price corresponding to each of `queries`. Prices are represented as 18\n * decimal fixed point values.\n */\n function getTimeWeightedAverage(OracleAverageQuery[] memory queries)\n external\n view\n returns (uint256[] memory results);\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/chainlink/AggregatorV3Interface.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface AggregatorV3Interface {\n function decimals() external view returns (uint8);\n\n function description() external view returns (string memory);\n\n function version() external view returns (uint256);\n\n // getRoundData and latestRoundData should both raise \"No data present\"\n // if they do not have data to report, instead of returning unset values\n // which could be misinterpreted as actual reported values.\n function getRoundData(uint80 _roundId)\n external\n view\n returns (\n uint80 roundId,\n int256 answer,\n uint256 startedAt,\n uint256 updatedAt,\n uint80 answeredInRound\n );\n\n function latestRoundData()\n external\n view\n returns (\n uint80 roundId,\n int256 answer,\n uint256 startedAt,\n uint256 updatedAt,\n uint80 answeredInRound\n );\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/IBuyback.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IBuyback {\n function swap() external;\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/ICVXLocker.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface ICVXLocker {\n function lock(\n address _account,\n uint256 _amount,\n uint256 _spendRatio\n ) external;\n\n function lockedBalanceOf(address _account) external view returns (uint256);\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/IEthUsdOracle.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IEthUsdOracle {\n /**\n * @notice Returns ETH price in USD.\n * @return Price in USD with 6 decimal digits.\n */\n function ethUsdPrice() external view returns (uint256);\n\n /**\n * @notice Returns token price in USD.\n * @param symbol. Asset symbol. For ex. \"DAI\".\n * @return Price in USD with 6 decimal digits.\n */\n function tokUsdPrice(string calldata symbol)\n external\n view\n returns (uint256);\n\n /**\n * @notice Returns the asset price in ETH.\n * @param symbol. Asset symbol. For ex. \"DAI\".\n * @return Price in ETH with 8 decimal digits.\n */\n function tokEthPrice(string calldata symbol)\n external\n view\n returns (uint256);\n}\n\ninterface IViewEthUsdOracle {\n /**\n * @notice Returns ETH price in USD.\n * @return Price in USD with 6 decimal digits.\n */\n function ethUsdPrice() external view returns (uint256);\n\n /**\n * @notice Returns token price in USD.\n * @param symbol. Asset symbol. For ex. \"DAI\".\n * @return Price in USD with 6 decimal digits.\n */\n function tokUsdPrice(string calldata symbol)\n external\n view\n returns (uint256);\n\n /**\n * @notice Returns the asset price in ETH.\n * @param symbol. Asset symbol. For ex. \"DAI\".\n * @return Price in ETH with 8 decimal digits.\n */\n function tokEthPrice(string calldata symbol)\n external\n view\n returns (uint256);\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/IMinMaxOracle.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IMinMaxOracle {\n //Assuming 8 decimals\n function priceMin(string calldata symbol) external view returns (uint256);\n\n function priceMax(string calldata symbol) external view returns (uint256);\n}\n" + }, + "contracts/interfaces/IOETHZapper.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IOETHZapper {\n function deposit() external payable returns (uint256);\n}\n" + }, + "contracts/interfaces/IOneInch.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/// 1Inch swap data\nstruct SwapDescription {\n IERC20 srcToken; // contract address of a token to sell\n IERC20 dstToken; // contract address of a token to buy\n address payable srcReceiver;\n address payable dstReceiver; // Receiver of destination currency. default: fromAddress\n uint256 amount;\n uint256 minReturnAmount;\n uint256 flags;\n}\n\n/// @title Interface for making arbitrary calls during swap\ninterface IAggregationExecutor {\n /// @notice propagates information about original msg.sender and executes arbitrary data\n function execute(address msgSender) external payable; // 0x4b64e492\n}\n\ninterface IOneInchRouter {\n /// @notice Performs a swap, delegating all calls encoded in `data` to `executor`.\n function swap(\n IAggregationExecutor executor,\n SwapDescription calldata desc,\n bytes calldata permit,\n bytes calldata data\n ) external returns (uint256 returnAmount, uint256 spentAmount);\n\n /// @notice Performs swap using Uniswap exchange. Wraps and unwraps ETH if required.\n function unoswapTo(\n address payable recipient,\n IERC20 srcToken,\n uint256 amount,\n uint256 minReturn,\n uint256[] calldata pools\n ) external payable returns (uint256 returnAmount);\n\n /// @notice Performs swap using Uniswap V3 exchange. Wraps and unwraps ETH if required.\n function uniswapV3SwapTo(\n address payable recipient,\n uint256 amount,\n uint256 minReturn,\n uint256[] calldata pools\n ) external payable returns (uint256 returnAmount);\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/IPriceOracle.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IPriceOracle {\n /**\n * @dev returns the asset price in USD, 6 decimal digits.\n * Compatible with the Open Price Feed.\n */\n function price(string calldata symbol) external view returns (uint256);\n}\n" + }, + "contracts/interfaces/IRETH.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IRETH {\n function getEthValue(uint256 _rethAmount) external view returns (uint256);\n\n function getRethValue(uint256 _ethAmount) external view returns (uint256);\n\n function getExchangeRate() external view returns (uint256);\n\n function totalSupply() external view returns (uint256);\n\n function balanceOf(address account) external view returns (uint256);\n\n function transfer(address recipient, uint256 amount)\n external\n returns (bool);\n\n function allowance(address owner, address spender)\n external\n view\n returns (uint256);\n\n function approve(address spender, uint256 amount) external returns (bool);\n\n function transferFrom(\n address sender,\n address recipient,\n uint256 amount\n ) external returns (bool);\n\n function name() external view returns (string memory);\n\n function symbol() external view returns (string memory);\n\n function decimals() external view returns (uint8);\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 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 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 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/ITimelock.sol": { + "content": "pragma solidity ^0.8.0;\n\ninterface ITimelock {\n function delay() external view returns (uint256);\n\n function GRACE_PERIOD() external view returns (uint256);\n\n function acceptAdmin() external;\n\n function queuedTransactions(bytes32 hash) external view returns (bool);\n\n function queueTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) external returns (bytes32);\n\n function cancelTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) external;\n\n function executeTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) external payable returns (bytes memory);\n}\n" + }, + "contracts/interfaces/ITimelockController.sol": { + "content": "pragma solidity ^0.8.0;\n\ninterface ITimelockController {\n function grantRole(bytes32 role, address account) external;\n\n function revokeRole(bytes32 role, address account) external;\n\n function renounceRole(bytes32 role, address account) external;\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\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 function removeAsset(address _asset) external;\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/Tether.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface Tether {\n function transfer(address to, uint256 value) external;\n\n function transferFrom(\n address from,\n address to,\n uint256 value\n ) external;\n\n function balanceOf(address) external returns (uint256);\n}\n" + }, + "contracts/interfaces/uniswap/IUniswapUniversalRouter.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IUniswapUniversalRouter {\n /// @notice Executes encoded commands along with provided inputs. Reverts if deadline has expired.\n /// @param commands A set of concatenated commands, each 1 byte in length\n /// @param inputs An array of byte strings containing abi encoded inputs for each command\n /// @param deadline The deadline by which the transaction must be executed\n function execute(\n bytes calldata commands,\n bytes[] calldata inputs,\n uint256 deadline\n ) external payable;\n\n function execute(bytes calldata commands, bytes[] calldata inputs)\n external\n payable;\n}\n" + }, + "contracts/interfaces/uniswap/IUniswapV2Pair.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IUniswapV2Pair {\n function token0() external view returns (address);\n\n function token1() external view returns (address);\n\n function getReserves()\n external\n view\n returns (\n uint112 reserve0,\n uint112 reserve1,\n uint32 blockTimestampLast\n );\n\n function price0CumulativeLast() external view returns (uint256);\n\n function price1CumulativeLast() external view returns (uint256);\n\n function sync() external;\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/liquidity/LiquidityReward.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { SafeMath } from \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\n\nimport { Initializable } from \"../utils/Initializable.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\nimport { Governable } from \"../governance/Governable.sol\";\n\n//\n// LiquidityReward contract doles out reward for liquidity\n// base off of Sushiswap's MasterChef: https://github.com/sushiswap/sushiswap/blob/master/contracts/MasterChef.sol\n//\ncontract LiquidityReward is Initializable, Governable {\n using SafeMath for uint256;\n using StableMath for uint256;\n using SafeERC20 for IERC20;\n\n // Info of each user.\n struct UserInfo {\n uint256 amount; // How many LP tokens the user has provided.\n int256 rewardDebt; // Reward debt. See explanation below.\n //\n // We do some fancy math here. Basically, any point in time, the amount of Reward Tokens\n // entitled to a user but is pending to be distributed is:\n //\n // pending reward = (user.amount * pool.accRewardPerShare) - user.rewardDebt\n //\n // Whenever a user deposits or withdraws LP tokens to a pool. Here's what happens:\n // 1. The pool's `accRewardPerShare` (and `lastRewardBlock`) gets updated.\n // 2. User receives the pending reward sent to his/her address.\n // 3. User's `amount` gets updated.\n // 4. User's `rewardDebt` gets updated.\n //\n // NOTE: rewardDebt can go negative because we allow withdraws without claiming the reward\n // in that case we owe the account holder some reward.\n }\n\n // Info of each pool.\n struct PoolInfo {\n IERC20 lpToken; // Address of LP token contract.\n uint256 lastRewardBlock; // Last block number that Reward calculation occurs.\n uint256 accRewardPerShare; // Accumulated Reward per share in reward precision. See below.\n }\n\n // The Reward token\n IERC20 public reward;\n\n // Reward tokens created per block in 1e18 precision.\n uint256 public rewardPerBlock;\n\n // Info on the LP.\n PoolInfo public pool;\n // total Reward debt, useful to calculate if we have enough to pay out all rewards\n int256 public totalRewardDebt;\n // total Supply that is accounted for via deposit/withdraw so that our rewards calc are stable\n uint256 public totalSupply;\n // Info of each user that stakes LP tokens.\n mapping(address => UserInfo) public userInfo;\n // The block number when Liquidity rewards ends.\n uint256 public endBlock;\n\n event CampaignStarted(\n uint256 rewardRate,\n uint256 startBlock,\n uint256 endBlock\n );\n event CampaignStopped(uint256 endBlock);\n event Deposit(address indexed user, uint256 amount);\n event Withdraw(address indexed user, uint256 amount);\n event Claim(address indexed user, uint256 amount);\n event DrainExtraReward(address indexed user, uint256 amount);\n event DrainExtraLP(address indexed user, uint256 amount);\n\n /**\n * Initializer for setting up Liquidity Reward internal state.\n * @param _reward Address of the reward token(OGN)\n * @param _lpToken Address of the LP token(Uniswap Pair)\n */\n function initialize(IERC20 _reward, IERC20 _lpToken)\n external\n onlyGovernor\n initializer\n {\n reward = _reward;\n pool.lpToken = _lpToken;\n pool.lastRewardBlock = block.number;\n }\n\n /**\n * @dev start a new reward campaign.\n * This will calculate all rewards up to the current block at the old rate.\n * This ensures that we pay everyone at the promised rate before update to the new rate.\n * @param _rewardPerBlock Amount rewarded per block\n * @param _startBlock Block number that we want to start the rewards at (0 for current block)\n * @param _numBlocks number of blocks that the campaign should last\n */\n function startCampaign(\n uint256 _rewardPerBlock,\n uint256 _startBlock,\n uint256 _numBlocks\n ) external onlyGovernor {\n // Calculate up to the current block at the current rate for everyone.\n updatePool();\n\n // total Pending calculated at the current pool rate\n uint256 totalPending = subDebt(\n pool.accRewardPerShare.mulTruncate(totalSupply),\n totalRewardDebt\n );\n\n require(_numBlocks > 0, \"startCampaign: zero blocks\");\n\n require(\n reward.balanceOf(address(this)) >=\n _rewardPerBlock.mul(_numBlocks).add(totalPending),\n \"startCampaign: insufficient rewards\"\n );\n\n uint256 startBlock = _startBlock;\n if (startBlock == 0) {\n // start block number isn't given so we start at the current\n startBlock = block.number;\n }\n require(\n startBlock >= block.number,\n \"startCampaign: _startBlock can't be in the past\"\n );\n endBlock = startBlock.add(_numBlocks);\n // we don't start accrue until the startBlock\n pool.lastRewardBlock = startBlock;\n // new blocks start at the new reward rate\n rewardPerBlock = _rewardPerBlock;\n emit CampaignStarted(rewardPerBlock, startBlock, endBlock);\n }\n\n function stopCampaign() external onlyGovernor {\n //calculate until current pool\n updatePool();\n //end the block here (the CampaignMultiplier will be zero)\n endBlock = block.number;\n emit CampaignStopped(endBlock);\n }\n\n function drainExtraRewards() external onlyGovernor {\n require(endBlock < block.number, \"drainExtraRewards:Campaign active\");\n updatePool();\n uint256 extraRewards = reward.balanceOf(address(this)).sub(\n subDebt(\n pool.accRewardPerShare.mulTruncate(totalSupply),\n totalRewardDebt\n )\n );\n if (extraRewards > 0) {\n emit DrainExtraReward(msg.sender, extraRewards);\n reward.safeTransfer(msg.sender, extraRewards);\n }\n }\n\n function drainExtraLP() external onlyGovernor {\n uint256 extraLP = pool.lpToken.balanceOf(address(this)).sub(\n totalSupply\n );\n require(extraLP > 0, \"drainExtraLP:no extra\");\n emit DrainExtraLP(msg.sender, extraLP);\n pool.lpToken.safeTransfer(msg.sender, extraLP);\n }\n\n function campaignActive() external view returns (bool) {\n return endBlock > block.number && block.number >= pool.lastRewardBlock;\n }\n\n function balanceOf(address _account) external view returns (uint256) {\n return userInfo[_account].amount;\n }\n\n /**\n * @dev calculate the number of blocks since we last updated\n * within start and end as constraints\n * @param _to Block number of the ending point.\n * @return multiplier Multiplier over the given _from to _to block.\n */\n function getCampaignMultiplier(uint256 _to)\n internal\n view\n returns (uint256)\n {\n uint256 from = pool.lastRewardBlock;\n if (from > endBlock) {\n return 0;\n } else {\n return (_to < endBlock ? _to : endBlock).sub(from);\n }\n }\n\n /**\n * @dev View function to see pending rewards for each account on frontend.\n * @param _user Address of the account we're looking up.\n * @return reward Total rewards owed to this account.\n */\n function pendingRewards(address _user) external view returns (uint256) {\n UserInfo storage user = userInfo[_user];\n return _pendingRewards(user);\n }\n\n function _pendingRewards(UserInfo storage user)\n internal\n view\n returns (uint256)\n {\n uint256 accRewardPerShare = pool.accRewardPerShare;\n if (block.number > pool.lastRewardBlock) {\n if (totalSupply != 0) {\n uint256 multiplier = getCampaignMultiplier(block.number);\n uint256 incReward = multiplier.mul(rewardPerBlock);\n accRewardPerShare = accRewardPerShare.add(\n incReward.divPrecisely(totalSupply)\n );\n }\n }\n return\n subDebt(\n user.amount.mulTruncate(accRewardPerShare),\n user.rewardDebt\n );\n }\n\n /**\n * @dev View function to see total outstanding rewards for the entire contract.\n * This is how much is owed when everyone pulls out.\n * @return reward Total rewards owed to everyone.\n */\n function totalOutstandingRewards() external view returns (uint256) {\n if (block.number > pool.lastRewardBlock && totalSupply != 0) {\n uint256 multiplier = getCampaignMultiplier(block.number);\n uint256 incReward = multiplier.mul(rewardPerBlock);\n uint256 accRewardPerShare = pool.accRewardPerShare;\n accRewardPerShare = accRewardPerShare.add(\n incReward.divPrecisely(totalSupply)\n );\n return\n subDebt(\n accRewardPerShare.mulTruncate(totalSupply),\n totalRewardDebt\n );\n }\n // no supply or not even started\n return 0;\n }\n\n /**\n * @dev External call for updating the pool.\n */\n function doUpdatePool() external {\n // There should be no harm allowing anyone to call this function.\n // It just updates the latest accRewardPerShare for the pool.\n updatePool();\n }\n\n /**\n * @dev Update the Liquidity Pool reward multiplier.\n * This locks in the accRewardPerShare from the last update block number to now.\n * Will fail if we do not have enough to pay everyone.\n * Always call updatePool whenever the balance changes!\n */\n function updatePool() internal {\n if (\n block.number <= pool.lastRewardBlock ||\n endBlock <= pool.lastRewardBlock\n ) {\n return;\n }\n\n if (totalSupply == 0) {\n pool.lastRewardBlock = block.number;\n return;\n }\n\n uint256 incReward = getCampaignMultiplier(block.number).mul(\n rewardPerBlock\n );\n // we are of course assuming lpTokens are in 1e18 precision\n uint256 accRewardPerShare = pool.accRewardPerShare.add(\n incReward.divPrecisely(totalSupply)\n );\n\n pool.accRewardPerShare = accRewardPerShare;\n pool.lastRewardBlock = block.number;\n }\n\n /**\n * @dev Deposit LP tokens into contract, must be preapproved.\n * @param _amount Amount of LPToken to deposit.\n */\n function deposit(uint256 _amount) external {\n UserInfo storage user = userInfo[msg.sender];\n updatePool();\n if (_amount > 0) {\n user.amount = user.amount.add(_amount);\n // newDebt is equal to the change in amount * accRewardPerShare (note accRewardPerShare is historic)\n int256 newDebt = int256(\n _amount.mulTruncate(pool.accRewardPerShare)\n );\n user.rewardDebt += newDebt;\n totalRewardDebt += newDebt;\n totalSupply = totalSupply.add(_amount);\n emit Deposit(msg.sender, _amount);\n pool.lpToken.safeTransferFrom(\n address(msg.sender),\n address(this),\n _amount\n );\n }\n }\n\n /**\n * @dev Exit out of the contract completely, withdraw LP tokens and claim rewards\n */\n function exit() external {\n UserInfo storage user = userInfo[msg.sender];\n // withdraw everything\n _withdraw(user, user.amount, true);\n }\n\n /**\n * @dev Withdraw LP tokens from contract.\n * @param _amount Amount of LPToken to withdraw.\n * @param _claim Boolean do we want to claim our rewards or not\n */\n function withdraw(uint256 _amount, bool _claim) external {\n UserInfo storage user = userInfo[msg.sender];\n _withdraw(user, _amount, _claim);\n }\n\n function _withdraw(\n UserInfo storage user,\n uint256 _amount,\n bool _claim\n ) internal {\n require(user.amount >= _amount, \"withdraw: overflow\");\n updatePool();\n\n // newDebt is equal to the change in amount * accRewardPerShare (note accRewardPerShare is historic)\n int256 newDebt = -int256(_amount.mulTruncate(pool.accRewardPerShare));\n uint256 pending = 0;\n if (_claim) {\n //This is an optimization so we don't modify the storage variable twice\n pending = subDebt(\n user.amount.mulTruncate(pool.accRewardPerShare),\n user.rewardDebt\n );\n\n newDebt += int256(pending);\n }\n\n user.rewardDebt += newDebt;\n totalRewardDebt += newDebt;\n emit Withdraw(msg.sender, _amount);\n // actually make the changes to the amount and debt\n if (_amount > 0) {\n user.amount = user.amount.sub(_amount);\n totalSupply = totalSupply.sub(_amount, \"withdraw: total overflow\");\n }\n //putting this all at the end to avoid reentrancy error\n if (pending > 0) {\n emit Claim(msg.sender, pending);\n reward.safeTransfer(msg.sender, pending);\n }\n if (_amount > 0) {\n pool.lpToken.safeTransfer(address(msg.sender), _amount);\n }\n }\n\n /**\n * @dev Claim all pending rewards up to current block\n */\n function claim() external {\n UserInfo storage user = userInfo[msg.sender];\n uint256 pending = _pendingRewards(user);\n if (pending > 0) {\n emit Claim(msg.sender, pending);\n int256 debtDelta = int256(pending);\n user.rewardDebt += debtDelta;\n totalRewardDebt += debtDelta;\n reward.safeTransfer(msg.sender, pending);\n }\n }\n\n function subDebt(uint256 amount, int256 debt)\n internal\n pure\n returns (uint256 result)\n {\n if (debt < 0) {\n result = amount.add(uint256(-debt));\n } else {\n result = amount.sub(uint256(debt));\n }\n }\n}\n" + }, + "contracts/mocks/BeaconChainDepositContractMock.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ncontract BeaconChainDepositContractMock {\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 // Extended ABI length checks since dynamic types are used.\n require(pubkey.length == 48, \"DepositContract: invalid pubkey length\");\n require(\n withdrawal_credentials.length == 32,\n \"DepositContract: invalid withdrawal_credentials length\"\n );\n require(\n signature.length == 96,\n \"DepositContract: invalid signature length\"\n );\n\n // Check deposit amount\n require(msg.value >= 1 ether, \"DepositContract: deposit value too low\");\n require(\n msg.value % 1 gwei == 0,\n \"DepositContract: deposit value not multiple of gwei\"\n );\n uint256 deposit_amount = msg.value / 1 gwei;\n require(\n deposit_amount <= type(uint64).max,\n \"DepositContract: deposit value too high\"\n );\n require(\n deposit_data_root != 0,\n \"DepositContract: invalid deposit_data_root\"\n );\n }\n}\n" + }, + "contracts/mocks/BurnableERC20.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { ERC20 } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ninterface IBurnableERC20 {\n function burn(uint256 value) external returns (bool);\n\n function burnFrom(address account, uint256 value) external returns (bool);\n}\n\n/**\n * @title BurnableERC20\n * @dev Exposes the burn function of ERC20 for tests\n */\nabstract contract BurnableERC20 is IBurnableERC20, ERC20 {\n /**\n * @dev Function to burn tokens\n * @param value The amount of tokens to burn.\n * @return A boolean that indicates if the operation was successful.\n */\n function burn(uint256 value) public virtual override returns (bool) {\n _burn(msg.sender, value);\n return true;\n }\n\n /**\n * @dev Function to burn tokens from a specific account\n * @param account The address with the tokens to burn.\n * @param value The amount of tokens to burn.\n * @return A boolean that indicates if the operation was successful.\n */\n function burnFrom(address account, uint256 value)\n public\n override\n returns (bool)\n {\n _burn(account, value);\n return true;\n }\n}\n" + }, + "contracts/mocks/curve/Mock3CRV.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { ERC20, MintableERC20 } from \"../MintableERC20.sol\";\nimport { BurnableERC20 } from \"../BurnableERC20.sol\";\n\ncontract Mock3CRV is MintableERC20, BurnableERC20 {\n constructor() ERC20(\"Curve.fi DAI/USDC/USDT\", \"3Crv\") {}\n\n function decimals() public pure override returns (uint8) {\n return 18;\n }\n}\n" + }, + "contracts/mocks/curve/MockBooster.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 { MockRewardPool } from \"./MockRewardPool.sol\";\n\nimport { IRewardStaking } from \"../../strategies/IRewardStaking.sol\";\nimport { IMintableERC20, MintableERC20, ERC20 } from \"../MintableERC20.sol\";\nimport { IBurnableERC20, BurnableERC20 } from \"../BurnableERC20.sol\";\n\ncontract MockDepositToken is MintableERC20, BurnableERC20 {\n constructor() ERC20(\"DCVX\", \"CVX Deposit Token\") {}\n}\n\ncontract MockBooster {\n using SafeERC20 for IERC20;\n\n struct PoolInfo {\n address lptoken;\n address token;\n address crvRewards;\n }\n\n address public minter; // this is CVx for the booster on live\n address public crv; // Curve rewards token\n address public cvx; // Convex rewards token\n mapping(uint256 => PoolInfo) public poolInfo;\n\n constructor(\n address _rewardsMinter,\n address _crv,\n address _cvx\n ) public {\n minter = _rewardsMinter;\n crv = _crv;\n cvx = _cvx;\n }\n\n function setPool(uint256 pid, address _lpToken)\n external\n returns (address rewards)\n {\n address token = address(new MockDepositToken());\n // Deploy a new Convex Rewards Pool\n rewards = address(\n new MockRewardPool(pid, token, crv, cvx, address(this))\n );\n\n poolInfo[pid] = PoolInfo({\n lptoken: _lpToken,\n token: token,\n crvRewards: rewards\n });\n }\n\n function deposit(\n uint256 _pid,\n uint256 _amount,\n bool _stake\n ) public returns (bool) {\n PoolInfo storage pool = poolInfo[_pid];\n\n address lptoken = pool.lptoken;\n\n // hold on to the Curve LP tokens\n IERC20(lptoken).safeTransferFrom(msg.sender, address(this), _amount);\n\n address token = pool.token;\n if (_stake) {\n // mint Convex pool LP tokens and stake in rewards contract on user behalf\n IMintableERC20(token).mint(_amount);\n address rewardContract = pool.crvRewards;\n IERC20(token).safeApprove(rewardContract, 0);\n IERC20(token).safeApprove(rewardContract, _amount);\n IRewardStaking(rewardContract).stakeFor(msg.sender, _amount);\n } else {\n // mint Convex pool LP tokens and send to user\n IMintableERC20(token).mint(_amount);\n IERC20(token).transfer(msg.sender, _amount);\n }\n return true;\n }\n\n // Deposit all Curve LP tokens and stake\n function depositAll(uint256 _pid, bool _stake) external returns (bool) {\n address lptoken = poolInfo[_pid].lptoken;\n uint256 balance = IERC20(lptoken).balanceOf(msg.sender);\n deposit(_pid, balance, _stake);\n return true;\n }\n\n // withdraw Curve LP tokens\n function _withdraw(\n uint256 _pid,\n uint256 _amount,\n address _from,\n address _to\n ) internal {\n PoolInfo storage pool = poolInfo[_pid];\n\n // burn the Convex pool LP tokens\n IBurnableERC20(pool.token).burnFrom(_from, _amount);\n\n // return the Curve LP tokens\n IERC20(pool.lptoken).safeTransfer(_to, _amount);\n }\n\n // withdraw Curve LP tokens\n function withdraw(uint256 _pid, uint256 _amount) public returns (bool) {\n _withdraw(_pid, _amount, msg.sender, msg.sender);\n return true;\n }\n\n // withdraw all Curve LP tokens\n function withdrawAll(uint256 _pid) public returns (bool) {\n address token = poolInfo[_pid].token;\n uint256 userBal = IERC20(token).balanceOf(msg.sender);\n withdraw(_pid, userBal);\n return true;\n }\n\n // allow reward contracts to send here and withdraw to user\n function withdrawTo(\n uint256 _pid,\n uint256 _amount,\n address _to\n ) external returns (bool) {\n address rewardContract = poolInfo[_pid].crvRewards;\n require(msg.sender == rewardContract, \"!auth\");\n\n _withdraw(_pid, _amount, msg.sender, _to);\n return true;\n }\n\n // callback from reward contract when crv is received.\n function rewardClaimed(\n uint256 _pid,\n // solhint-disable-next-line no-unused-vars\n address _address,\n uint256 _amount\n ) external returns (bool) {\n address rewardContract = poolInfo[_pid].crvRewards;\n require(msg.sender == rewardContract, \"!auth\");\n\n //mint reward tokens\n // and transfer it\n IMintableERC20(minter).mint(_amount);\n IERC20(minter).transfer(msg.sender, _amount);\n return true;\n }\n}\n" + }, + "contracts/mocks/curve/MockCRV.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../MintableERC20.sol\";\n\ncontract MockCRV is MintableERC20 {\n constructor() ERC20(\"Curve DAO Token\", \"CRV\") {}\n\n function decimals() public pure override returns (uint8) {\n return 18;\n }\n}\n" + }, + "contracts/mocks/curve/MockCRVMinter.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\nimport { IMintableERC20 } from \"../MintableERC20.sol\";\n\ncontract MockCRVMinter {\n address crv;\n\n constructor(address _crv) {\n crv = _crv;\n }\n\n function mint(address _address) external {\n uint256 amount = 2e18;\n IMintableERC20(crv).mint(amount);\n IERC20(crv).transfer(_address, amount);\n }\n}\n" + }, + "contracts/mocks/curve/MockCurveAbstractMetapool.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\nimport { MintableERC20, IMintableERC20 } from \"../MintableERC20.sol\";\nimport { StableMath } from \"../../utils/StableMath.sol\";\nimport \"../../utils/Helpers.sol\";\n\nabstract contract MockCurveAbstractMetapool is MintableERC20 {\n using StableMath for uint256;\n\n address[] public coins;\n uint256[2] public balances;\n\n // Returns the same amount of LP tokens in 1e18 decimals\n function add_liquidity(uint256[2] calldata _amounts, uint256 _minAmount)\n external\n returns (uint256 lpAmount)\n {\n for (uint256 i = 0; i < _amounts.length; i++) {\n if (_amounts[i] > 0) {\n IERC20(coins[i]).transferFrom(\n msg.sender,\n address(this),\n _amounts[i]\n );\n uint256 assetDecimals = Helpers.getDecimals(coins[i]);\n // Convert to 1e18 and add to sum\n lpAmount += _amounts[i].scaleBy(18, assetDecimals);\n balances[i] = balances[i] + _amounts[i];\n }\n }\n // Hacky way of simulating slippage to check _minAmount\n if (lpAmount == 29000e18) lpAmount = 14500e18;\n require(lpAmount >= _minAmount, \"Slippage ruined your day\");\n // Send LP token to sender, e.g. 3CRV\n _mint(msg.sender, lpAmount);\n }\n\n // Dumb implementation that returns the same amount\n function calc_withdraw_one_coin(uint256 _amount, int128 _index)\n public\n view\n returns (uint256 lpAmount)\n {\n uint256 assetDecimals = Helpers.getDecimals(coins[uint128(_index)]);\n lpAmount = _amount.scaleBy(assetDecimals, 18);\n }\n\n function remove_liquidity_one_coin(\n uint256 _lpAmount,\n int128 _index,\n // solhint-disable-next-line no-unused-vars\n uint256 _minAmount\n ) external returns (uint256 amount) {\n _burn(msg.sender, _lpAmount);\n uint256[] memory amounts = new uint256[](coins.length);\n amounts[uint128(_index)] = _lpAmount;\n amount = calc_withdraw_one_coin(_lpAmount, _index);\n balances[uint128(_index)] -= amount;\n IERC20(coins[uint128(_index)]).transfer(msg.sender, amount);\n }\n\n function get_virtual_price() external pure returns (uint256) {\n return 1e18;\n }\n\n // solhint-disable-next-line no-unused-vars\n function remove_liquidity(uint256 _amount, uint256[2] memory _min_amounts)\n public\n returns (uint256[2] memory amounts)\n {\n _burn(msg.sender, _amount);\n uint256 totalSupply = totalSupply();\n for (uint256 i = 0; i < 2; i++) {\n amounts[i] = totalSupply > 0\n ? (_amount * IERC20(coins[i]).balanceOf(address(this))) /\n totalSupply\n : IERC20(coins[i]).balanceOf(address(this));\n balances[i] -= amounts[i];\n IERC20(coins[i]).transfer(msg.sender, amounts[i]);\n }\n }\n\n function remove_liquidity_imbalance(\n uint256[2] memory _amounts,\n uint256 _max_burned_tokens\n ) public returns (uint256) {\n return\n _remove_liquidity_imbalance(\n _amounts,\n _max_burned_tokens,\n msg.sender\n );\n }\n\n function remove_liquidity_imbalance(\n uint256[2] memory _amounts,\n uint256 _max_burned_tokens,\n address _reveiver\n ) public returns (uint256) {\n return\n _remove_liquidity_imbalance(\n _amounts,\n _max_burned_tokens,\n _reveiver\n );\n }\n\n function _remove_liquidity_imbalance(\n uint256[2] memory _amounts,\n uint256 _max_burned_tokens,\n address _reveiver\n ) internal returns (uint256 lpTokens) {\n lpTokens = _max_burned_tokens;\n _burn(msg.sender, lpTokens);\n for (uint256 i = 0; i < _amounts.length; i++) {\n balances[i] -= _amounts[i];\n if (_amounts[i] > 0) {\n IERC20(coins[i]).transfer(_reveiver, _amounts[i]);\n }\n }\n }\n\n // Dumb implementation that sums the scaled amounts\n function calc_token_amount(uint256[2] memory _amounts, bool)\n public\n view\n returns (uint256 lpTokens)\n {\n for (uint256 i = 0; i < _amounts.length; i++) {\n uint256 assetDecimals = Helpers.getDecimals(coins[i]);\n // Convert to 1e18 and add to lpTokens\n lpTokens += _amounts[i].scaleBy(18, assetDecimals);\n }\n }\n\n /// @notice 0.02% fee\n function fee() external pure returns (uint256) {\n return 2000000;\n }\n\n function decimals() public pure override returns (uint8) {\n return 18;\n }\n\n function burnFrom(address from, uint256 value) public {\n _burn(from, value);\n }\n}\n" + }, + "contracts/mocks/curve/MockCurveGauge.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\nimport { ICurveGauge } from \"../../strategies/ICurveGauge.sol\";\n\ncontract MockCurveGauge is ICurveGauge {\n mapping(address => uint256) private _balances;\n address lpToken;\n\n constructor(address _lpToken) {\n lpToken = _lpToken;\n }\n\n function balanceOf(address account) public view override returns (uint256) {\n return _balances[account];\n }\n\n function deposit(uint256 _value, address _account) external override {\n IERC20(lpToken).transferFrom(msg.sender, address(this), _value);\n _balances[_account] += _value;\n }\n\n function withdraw(uint256 _value) external override {\n IERC20(lpToken).transfer(msg.sender, _value);\n // solhint-disable-next-line reentrancy\n _balances[msg.sender] -= _value;\n }\n}\n" + }, + "contracts/mocks/curve/MockCurveLUSDMetapool.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { MockCurveAbstractMetapool } from \"./MockCurveAbstractMetapool.sol\";\nimport \"../MintableERC20.sol\";\n\ncontract MockCurveLUSDMetapool is MockCurveAbstractMetapool {\n constructor(address[2] memory _coins)\n ERC20(\"Curve.fi Factory USD Metapool: LUSD\", \"LUSD3CRV-f\")\n {\n coins = _coins;\n }\n}\n" + }, + "contracts/mocks/curve/MockCurveMetapool.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { MockCurveAbstractMetapool } from \"./MockCurveAbstractMetapool.sol\";\nimport \"../MintableERC20.sol\";\n\ncontract MockCurveMetapool is MockCurveAbstractMetapool {\n constructor(address[2] memory _coins)\n ERC20(\"Curve.fi 3pool/OUSD metapool\", \"3crv_OUSD\")\n {\n coins = _coins;\n }\n}\n" + }, + "contracts/mocks/curve/MockCurvePool.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { IBurnableERC20 } from \"../BurnableERC20.sol\";\n\nimport { IMintableERC20 } from \"../MintableERC20.sol\";\nimport { ICurvePool } from \"../../strategies/ICurvePool.sol\";\nimport { StableMath } from \"../../utils/StableMath.sol\";\nimport \"../../utils/Helpers.sol\";\n\ncontract MockCurvePool {\n using StableMath for uint256;\n\n address[] public coins;\n uint256[3] public balances;\n address lpToken;\n uint256 public slippage = 1 ether;\n\n constructor(address[3] memory _coins, address _lpToken) {\n coins = _coins;\n lpToken = _lpToken;\n }\n\n function setCoins(address[] memory _coins) external {\n coins = _coins;\n }\n\n // Returns the same amount of LP tokens in 1e18 decimals\n function add_liquidity(uint256[3] calldata _amounts, uint256 _minAmount)\n external\n {\n uint256 sum = 0;\n for (uint256 i = 0; i < _amounts.length; i++) {\n if (_amounts[i] > 0) {\n IERC20(coins[i]).transferFrom(\n msg.sender,\n address(this),\n _amounts[i]\n );\n uint256 assetDecimals = Helpers.getDecimals(coins[i]);\n // Convert to 1e18 and add to sum\n sum += _amounts[i].scaleBy(18, assetDecimals);\n balances[i] = balances[i] + _amounts[i];\n }\n }\n // Hacky way of simulating slippage to check _minAmount\n if (sum == 29000e18) sum = 14500e18;\n require(sum >= _minAmount, \"Slippage ruined your day\");\n // Send LP token to sender, e.g. 3CRV\n IMintableERC20(lpToken).mint(sum);\n IERC20(lpToken).transfer(msg.sender, sum);\n }\n\n // Dumb implementation that returns the same amount\n function calc_withdraw_one_coin(uint256 _amount, int128 _index)\n public\n view\n returns (uint256)\n {\n uint256 assetDecimals = Helpers.getDecimals(coins[uint128(_index)]);\n return _amount.scaleBy(assetDecimals, 18);\n }\n\n function remove_liquidity_one_coin(\n uint256 _amount,\n int128 _index,\n // solhint-disable-next-line no-unused-vars\n uint256 _minAmount\n ) external {\n // Burn the Curve LP tokens\n IBurnableERC20(lpToken).burnFrom(msg.sender, _amount);\n uint256[] memory amounts = new uint256[](coins.length);\n amounts[uint128(_index)] = _amount;\n uint256 coinAmount = calc_withdraw_one_coin(_amount, _index);\n balances[uint128(_index)] -= coinAmount;\n IERC20(coins[uint128(_index)]).transfer(msg.sender, coinAmount);\n }\n\n function get_virtual_price() external pure returns (uint256) {\n return 1e18;\n }\n\n // solhint-disable-next-line no-unused-vars\n function remove_liquidity(uint256 _lpAmount, uint256[3] memory _min_amounts)\n public\n {\n // Burn the Curve LP tokens\n IBurnableERC20(lpToken).burnFrom(msg.sender, _lpAmount);\n uint256 totalSupply = IERC20(lpToken).totalSupply();\n for (uint256 i = 0; i < 3; i++) {\n uint256 coinAmount = totalSupply > 0\n ? (_lpAmount * IERC20(coins[i]).balanceOf(address(this))) /\n totalSupply\n : IERC20(coins[i]).balanceOf(address(this));\n balances[i] -= coinAmount;\n IERC20(coins[i]).transfer(msg.sender, coinAmount);\n }\n }\n\n function remove_liquidity_imbalance(\n uint256[3] memory _amounts,\n uint256 _max_burned_tokens\n ) public {\n // Burn the Curve LP tokens\n IBurnableERC20(lpToken).burnFrom(msg.sender, _max_burned_tokens);\n // For each coin, transfer to the caller\n for (uint256 i = 0; i < _amounts.length; i++) {\n balances[i] -= _amounts[i];\n if (_amounts[i] > 0) {\n IERC20(coins[i]).transfer(msg.sender, _amounts[i]);\n }\n }\n }\n\n // Dumb implementation that sums the scaled amounts\n function calc_token_amount(uint256[3] memory _amounts, bool)\n public\n view\n returns (uint256 lpTokens)\n {\n for (uint256 i = 0; i < _amounts.length; i++) {\n uint256 assetDecimals = Helpers.getDecimals(coins[i]);\n // Convert to 1e18 and add to lpTokens\n lpTokens += _amounts[i].scaleBy(18, assetDecimals);\n }\n }\n\n function fee() external pure returns (uint256) {\n return 1000000;\n }\n\n function exchange(\n uint256 coin0,\n uint256 coin1,\n uint256 amountIn,\n uint256 minAmountOut\n ) external returns (uint256 amountOut) {\n IERC20(coins[coin0]).transferFrom(msg.sender, address(this), amountIn);\n amountOut = (minAmountOut * slippage) / 1 ether;\n require(amountOut >= minAmountOut, \"Slippage error\");\n IMintableERC20(coins[coin1]).mintTo(msg.sender, amountOut);\n }\n\n function setSlippage(uint256 _slippage) external {\n slippage = _slippage;\n }\n}\n" + }, + "contracts/mocks/curve/MockCVX.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../MintableERC20.sol\";\n\ncontract MockCVX is MintableERC20 {\n constructor() ERC20(\"CVX\", \"CVX DAO Token\") {}\n}\n" + }, + "contracts/mocks/curve/MockLUSD.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../MintableERC20.sol\";\n\ncontract MockLUSD is MintableERC20 {\n constructor() ERC20(\"LUSD\", \"Liquity Token\") {}\n}\n" + }, + "contracts/mocks/curve/MockRewardPool.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 { IMintableERC20 } from \"../MintableERC20.sol\";\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\n\ninterface IDeposit {\n function poolInfo(uint256)\n external\n view\n returns (\n address,\n address,\n address,\n address,\n address,\n bool\n );\n\n function rewardClaimed(\n uint256,\n address,\n uint256\n ) external;\n\n function withdrawTo(\n uint256,\n uint256,\n address\n ) external;\n}\n\ncontract MockRewardPool {\n using SafeMath for uint256;\n using SafeERC20 for IERC20;\n\n uint256 public pid;\n address public stakingToken;\n address public rewardTokenA;\n address public rewardTokenB;\n address public operator;\n\n uint256 private _totalSupply;\n\n mapping(address => uint256) private _balances;\n mapping(address => uint256) public rewards;\n\n constructor(\n uint256 _pid,\n address _stakingToken,\n address _rewardTokenA,\n address _rewardTokenB,\n address _operator\n ) public {\n pid = _pid;\n stakingToken = _stakingToken;\n rewardTokenA = _rewardTokenA;\n rewardTokenB = _rewardTokenB;\n operator = _operator;\n }\n\n function totalSupply() public view returns (uint256) {\n return _totalSupply;\n }\n\n function balanceOf(address account) public view returns (uint256) {\n return _balances[account];\n }\n\n function stakeFor(address _for, uint256 _amount) public returns (bool) {\n require(_amount > 0, \"RewardPool : Cannot stake 0\");\n\n //give to _for\n _totalSupply = _totalSupply.add(_amount);\n _balances[_for] = _balances[_for].add(_amount);\n\n //take away from sender\n IERC20(stakingToken).safeTransferFrom(\n msg.sender,\n address(this),\n _amount\n );\n\n return true;\n }\n\n function withdrawAndUnwrap(uint256 amount, bool claim)\n public\n returns (bool)\n {\n _totalSupply = _totalSupply.sub(amount);\n _balances[msg.sender] = _balances[msg.sender].sub(amount);\n\n //tell operator to withdraw from here directly to user\n IDeposit(operator).withdrawTo(pid, amount, msg.sender);\n\n //get rewards too\n if (claim) {\n getReward(msg.sender, true);\n }\n return true;\n }\n\n function withdrawAllAndUnwrap(bool claim) external {\n withdrawAndUnwrap(_balances[msg.sender], claim);\n }\n\n // solhint-disable-next-line no-unused-vars\n function getReward(address _account, bool _claimExtras)\n public\n returns (bool)\n {\n IMintableERC20(rewardTokenA).mint(2 * 1e18);\n IERC20(rewardTokenA).transfer(_account, 2 * 1e18);\n\n IMintableERC20(rewardTokenB).mint(3 * 1e18);\n IERC20(rewardTokenB).transfer(_account, 3 * 1e18);\n\n return true;\n }\n\n function getReward() public returns (bool) {\n getReward(msg.sender, true);\n }\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/Mock1InchSwapRouter.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\";\n\nimport { SwapDescription } from \"../interfaces/IOneInch.sol\";\n\ncontract Mock1InchSwapRouter {\n using SafeERC20 for IERC20;\n\n event MockSwap(address executor, bytes permitData, bytes executorData);\n\n event MockSwapDesc(\n address srcToken,\n address dstToken,\n address srcReceiver,\n address dstReceiver,\n uint256 amount,\n uint256 minReturnAmount,\n uint256 flags\n );\n\n event MockUnoswapTo(\n address recipient,\n address srcToken,\n uint256 amount,\n uint256 minReturn,\n uint256[] pools\n );\n\n event MockUniswapV3SwapTo(\n address recipient,\n uint256 amount,\n uint256 minReturn,\n uint256[] pools\n );\n\n /**\n * @dev transfers the shource asset and returns the minReturnAmount of the destination asset.\n */\n function swap(\n address executor,\n SwapDescription calldata desc,\n bytes calldata permitData,\n bytes calldata executorData\n ) public returns (uint256 returnAmount, uint256 spentAmount) {\n // Transfer the source tokens to the receiver contract\n IERC20(desc.srcToken).safeTransferFrom(\n msg.sender,\n desc.srcReceiver,\n desc.amount\n );\n\n // Transfer the destination tokens to the recipient\n IERC20(desc.dstToken).safeTransfer(\n desc.dstReceiver,\n desc.minReturnAmount\n );\n\n emit MockSwap(executor, permitData, executorData);\n _swapDesc(desc);\n returnAmount = 0;\n spentAmount = 0;\n }\n\n function _swapDesc(SwapDescription calldata desc) public {\n emit MockSwapDesc(\n address(desc.srcToken),\n address(desc.dstToken),\n desc.srcReceiver,\n desc.dstReceiver,\n desc.amount,\n desc.minReturnAmount,\n desc.flags\n );\n }\n\n /**\n * @dev only transfers the source asset to this contract.\n * Ideally it would return the destination asset but that's encoded in the pools array.\n */\n function unoswapTo(\n address payable recipient,\n address srcToken,\n uint256 amount,\n uint256 minReturn,\n uint256[] calldata pools\n ) public returns (uint256 returnAmount) {\n // transfer the from asset from the caller\n IERC20(srcToken).safeTransferFrom(msg.sender, address(this), amount);\n\n emit MockUnoswapTo(recipient, srcToken, amount, minReturn, pools);\n returnAmount = 0;\n }\n\n /**\n * @dev does not do any transfers. Just emits MockUniswapV3SwapTo.\n */\n function uniswapV3SwapTo(\n address payable recipient,\n uint256 amount,\n uint256 minReturn,\n uint256[] calldata pools\n ) public returns (uint256 returnAmount) {\n emit MockUniswapV3SwapTo(recipient, amount, minReturn, pools);\n returnAmount = 0;\n }\n}\n" + }, + "contracts/mocks/MockAave.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { IERC20, ERC20 } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\nimport { MintableERC20 } from \"./MintableERC20.sol\";\nimport { IAaveLendingPool, ILendingPoolAddressesProvider } from \"../strategies/IAave.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\n\n// 1. User calls 'getLendingPool'\n// 2. User calls 'deposit' (Aave)\n// - Deposit their underlying\n// - Mint aToken to them\n// 3. User calls redeem (aToken)\n// - Retrieve their aToken\n// - Return equal amount of underlying\n\ncontract MockAToken is MintableERC20 {\n address public lendingPool;\n IERC20 public underlyingToken;\n using SafeERC20 for IERC20;\n\n constructor(\n address _lendingPool,\n string memory _name,\n string memory _symbol,\n IERC20 _underlyingToken\n ) ERC20(_name, _symbol) {\n lendingPool = _lendingPool;\n underlyingToken = _underlyingToken;\n // addMinter(_lendingPool);\n }\n\n function decimals() public view override returns (uint8) {\n return ERC20(address(underlyingToken)).decimals();\n }\n\n function poolRedeem(uint256 _amount, address _to) external {\n require(msg.sender == lendingPool, \"pool only\");\n // Redeem these a Tokens\n _burn(_to, _amount);\n // For the underlying\n underlyingToken.safeTransferFrom(lendingPool, _to, _amount);\n }\n}\n\ncontract MockAave is IAaveLendingPool, ILendingPoolAddressesProvider {\n using SafeERC20 for IERC20;\n using StableMath for uint256;\n\n mapping(address => address) reserveToAToken;\n address pool = address(this);\n address payable core = payable(address(this));\n uint256 factor;\n\n function addAToken(address _aToken, address _underlying) public {\n IERC20(_underlying).safeApprove(_aToken, 0);\n IERC20(_underlying).safeApprove(_aToken, type(uint256).max);\n reserveToAToken[_underlying] = _aToken;\n }\n\n // set the reserve factor / basically the interest on deposit\n // in 18 precision\n // so 0.5% would be 5 * 10 ^ 15\n function setFactor(uint256 factor_) public {\n factor = factor_;\n }\n\n function deposit(\n address _reserve,\n uint256 _amount,\n address _to,\n uint16 /*_referralCode*/\n ) external override {\n uint256 previousBal = IERC20(reserveToAToken[_reserve]).balanceOf(\n msg.sender\n );\n uint256 interest = previousBal.mulTruncate(factor);\n MintableERC20(reserveToAToken[_reserve]).mintTo(msg.sender, interest);\n // Take their reserve\n IERC20(_reserve).safeTransferFrom(msg.sender, address(this), _amount);\n // Credit them with aToken\n MintableERC20(reserveToAToken[_reserve]).mintTo(_to, _amount);\n }\n\n function withdraw(\n address asset,\n uint256 amount,\n address to\n ) external override returns (uint256) {\n MockAToken atoken = MockAToken(reserveToAToken[asset]);\n atoken.poolRedeem(amount, to);\n return amount;\n }\n\n function getLendingPool() external view override returns (address) {\n return pool;\n }\n}\n" + }, + "contracts/mocks/MockAaveIncentivesController.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { MockStkAave } from \"./MockStkAave.sol\";\n\ncontract MockAaveIncentivesController {\n mapping(address => uint256) private rewards;\n MockStkAave public REWARD_TOKEN;\n\n constructor(address _reward_token) {\n REWARD_TOKEN = MockStkAave(_reward_token);\n }\n\n function setRewardsBalance(address user, uint256 amount) external {\n rewards[user] = amount;\n }\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 // solhint-disable-next-line no-unused-vars\n function getRewardsBalance(address[] calldata assets, address user)\n external\n view\n returns (uint256)\n {\n return rewards[user];\n }\n\n /**\n * @dev Claims reward for an user, on all the assets of the lending pool, 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 // solhint-disable-next-line no-unused-vars\n address[] calldata assets,\n uint256 amount,\n address to\n ) external returns (uint256) {\n require(amount > 0);\n require(rewards[to] == amount);\n REWARD_TOKEN.mint(amount);\n require(REWARD_TOKEN.transfer(to, amount));\n // solhint-disable-next-line reentrancy\n rewards[to] = 0;\n return amount;\n }\n}\n" + }, + "contracts/mocks/MockAAVEToken.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./MintableERC20.sol\";\n\ncontract MockAAVEToken is MintableERC20 {\n constructor() ERC20(\"AAVE\", \"AAVE\") {}\n}\n" + }, + "contracts/mocks/MockAura.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./MintableERC20.sol\";\n\ncontract MockAura is MintableERC20 {\n constructor() ERC20(\"Aura\", \"AURA\") {}\n}\n" + }, + "contracts/mocks/MockBAL.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./MintableERC20.sol\";\n\ncontract MockBAL is MintableERC20 {\n constructor() ERC20(\"Balancer\", \"BAL\") {}\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/MockChainlinkOracleFeed.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../interfaces/chainlink/AggregatorV3Interface.sol\";\n\ncontract MockChainlinkOracleFeed is AggregatorV3Interface {\n int256 price;\n uint8 numDecimals;\n\n constructor(int256 _price, uint8 _decimals) {\n price = _price;\n numDecimals = _decimals;\n }\n\n function decimals() external view override returns (uint8) {\n return numDecimals;\n }\n\n function description() external pure override returns (string memory) {\n return \"MockOracleEthFeed\";\n }\n\n function version() external pure override returns (uint256) {\n return 1;\n }\n\n function setPrice(int256 _price) public {\n price = _price;\n }\n\n function setDecimals(uint8 _decimals) public {\n numDecimals = _decimals;\n }\n\n // getRoundData and latestRoundData should both raise \"No data present\"\n // if they do not have data to report, instead of returning unset values\n // which could be misinterpreted as actual reported values.\n function getRoundData(uint80 _roundId)\n external\n view\n override\n returns (\n uint80 roundId,\n int256 answer,\n uint256 startedAt,\n uint256 updatedAt,\n uint80 answeredInRound\n )\n {\n roundId = _roundId;\n answer = price;\n startedAt = 0;\n updatedAt = 0;\n answeredInRound = 0;\n }\n\n function latestRoundData()\n external\n view\n override\n returns (\n uint80 roundId,\n int256 answer,\n uint256 startedAt,\n uint256 updatedAt,\n uint80 answeredInRound\n )\n {\n roundId = 0;\n answer = price;\n startedAt = 0;\n updatedAt = block.timestamp;\n answeredInRound = 0;\n }\n}\n" + }, + "contracts/mocks/MockCOMP.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./MintableERC20.sol\";\n\ncontract MockCOMP is MintableERC20 {\n constructor() ERC20(\"COMP\", \"COMP\") {}\n}\n" + }, + "contracts/mocks/MockComptroller.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ncontract MockComptroller {\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" + }, + "contracts/mocks/MockCToken.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { IERC20, ERC20 } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\nimport { ICERC20 } from \"../strategies/ICompound.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\n\ncontract MockCToken is ICERC20, ERC20 {\n using StableMath for uint256;\n\n IERC20 public underlyingToken;\n // underlying = cToken * exchangeRate\n // cToken = underlying / exchangeRate\n uint256 exchangeRate;\n address public override comptroller;\n\n constructor(ERC20 _underlyingToken, address _comptroller)\n ERC20(\"cMock\", \"cMK\")\n {\n uint8 underlyingDecimals = _underlyingToken.decimals();\n // if has 18 dp, exchange rate should be 1e26\n // if has 8 dp, exchange rate should be 1e18\n if (underlyingDecimals > 8) {\n exchangeRate = 10**uint256(18 + underlyingDecimals - 10);\n } else if (underlyingDecimals < 8) {\n // e.g. 18-8+6 = 16\n exchangeRate = 10**uint256(18 - 8 + underlyingDecimals);\n } else {\n exchangeRate = 1e18;\n }\n underlyingToken = _underlyingToken;\n comptroller = _comptroller;\n }\n\n function decimals() public pure override returns (uint8) {\n return 8;\n }\n\n function mint(uint256 mintAmount) public override returns (uint256) {\n // Credit them with cToken\n _mint(msg.sender, mintAmount.divPrecisely(exchangeRate));\n // Take their reserve\n underlyingToken.transferFrom(msg.sender, address(this), mintAmount);\n return 0;\n }\n\n function redeem(uint256 redeemAmount) external override returns (uint256) {\n uint256 tokenAmount = redeemAmount.mulTruncate(exchangeRate);\n // Burn the cToken\n _burn(msg.sender, redeemAmount);\n // Transfer underlying to caller\n underlyingToken.transfer(msg.sender, tokenAmount);\n return 0;\n }\n\n function redeemUnderlying(uint256 redeemAmount)\n external\n override\n returns (uint256)\n {\n uint256 cTokens = redeemAmount.divPrecisely(exchangeRate);\n // Burn the cToken\n _burn(msg.sender, cTokens);\n // Transfer underlying to caller\n underlyingToken.transfer(msg.sender, redeemAmount);\n return 0;\n }\n\n function balanceOfUnderlying(address owner)\n external\n view\n override\n returns (uint256)\n {\n uint256 cTokenBal = this.balanceOf(owner);\n return cTokenBal.mulTruncate(exchangeRate);\n }\n\n function balanceOf(address owner)\n public\n view\n override(ICERC20, ERC20)\n returns (uint256)\n {\n return ERC20.balanceOf(owner);\n }\n\n function updateExchangeRate()\n internal\n view\n returns (uint256 newExchangeRate)\n {\n uint256 factor = 100002 * (10**13); // 0.002%\n newExchangeRate = exchangeRate.mulTruncate(factor);\n }\n\n function exchangeRateStored() external view override returns (uint256) {\n return exchangeRate;\n }\n\n function supplyRatePerBlock() external pure override returns (uint256) {\n return 141 * (10**8);\n }\n}\n" + }, + "contracts/mocks/MockCVXLocker.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { ERC20 } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ncontract MockCVXLocker {\n address public immutable cvx;\n mapping(address => uint256) public lockedBalanceOf;\n\n constructor(address _cvx) {\n cvx = _cvx;\n }\n\n function lock(\n address _account,\n uint256 _amount,\n uint256\n ) external {\n lockedBalanceOf[_account] += _amount;\n ERC20(cvx).transferFrom(msg.sender, address(this), _amount);\n }\n\n function unlockAllTokens(address _account) external {\n lockedBalanceOf[_account] = 0;\n ERC20(cvx).transfer(_account, lockedBalanceOf[_account]);\n }\n}\n" + }, + "contracts/mocks/MockDAI.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./MintableERC20.sol\";\n\ncontract MockDAI is MintableERC20 {\n constructor() ERC20(\"DAI\", \"DAI\") {}\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/MockfrxETH.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./MintableERC20.sol\";\n\ncontract MockfrxETH is MintableERC20 {\n constructor() ERC20(\"frxETH\", \"frxETH\") {}\n}\n" + }, + "contracts/mocks/MockFrxETHMinter.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./MintableERC20.sol\";\n\ncontract MockFrxETHMinter {\n address public immutable frxETH;\n address public immutable sfrxETH;\n\n constructor(address _frxETH, address _sfrxETH) {\n frxETH = _frxETH;\n sfrxETH = _sfrxETH;\n }\n\n function submitAndDeposit(address recipient)\n external\n payable\n returns (uint256 shares)\n {\n IMintableERC20(frxETH).mintTo(sfrxETH, msg.value);\n IMintableERC20(sfrxETH).mintTo(recipient, msg.value);\n shares = msg.value;\n }\n}\n" + }, + "contracts/mocks/MockLimitedWrappedOusd.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { WrappedOusd } from \"../token/WrappedOusd.sol\";\nimport { ERC20 } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ncontract MockLimitedWrappedOusd is WrappedOusd {\n constructor(\n ERC20 underlying_,\n string memory name_,\n string memory symbol_\n ) WrappedOusd(underlying_, name_, symbol_) {}\n\n function maxDeposit(address)\n public\n view\n virtual\n override\n returns (uint256)\n {\n return 1e18;\n }\n}\n" + }, + "contracts/mocks/MockMetadataToken.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n// IERC20Metadata is used in the resolveAsset function in contracts/utils/assets.js\n// We just need to import it here to make its ABI available to Hardhat\nimport { IERC20Metadata } from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\n" + }, + "contracts/mocks/MockMintableUniswapPair.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./MintableERC20.sol\";\nimport \"./MockUniswapPair.sol\";\n\ncontract MockMintableUniswapPair is MockUniswapPair, MintableERC20 {\n constructor(\n address _token0,\n address _token1,\n uint112 _reserve0,\n uint112 _reserve1\n )\n MockUniswapPair(_token0, _token1, _reserve0, _reserve1)\n ERC20(\"Uniswap V2\", \"UNI-v2\")\n {}\n\n function decimals() public pure override returns (uint8) {\n return 18;\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/MockNonStandardToken.sol": { + "content": "pragma solidity ^0.8.0;\n\nimport { SafeMath } from \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\n\nimport \"./MintableERC20.sol\";\n\n/**\n * Mock token contract to simulate tokens that don't\n * throw/revert when a transfer/transferFrom call fails\n */\ncontract MockNonStandardToken is MintableERC20 {\n using SafeMath for uint256;\n\n constructor() ERC20(\"NonStandardToken\", \"NonStandardToken\") {}\n\n function decimals() public pure override returns (uint8) {\n return 6;\n }\n\n function transfer(address recipient, uint256 amount)\n public\n override\n returns (bool)\n {\n if (balanceOf(msg.sender) < amount) {\n // Fail silently\n return false;\n }\n\n _transfer(_msgSender(), recipient, amount);\n return true;\n }\n\n function transferFrom(\n address sender,\n address recipient,\n uint256 amount\n ) public override returns (bool) {\n if (balanceOf(sender) < amount) {\n // Fail silently\n return false;\n }\n\n _transfer(sender, recipient, amount);\n _approve(\n sender,\n _msgSender(),\n allowance(sender, _msgSender()).sub(\n amount,\n \"ERC20: transfer amount exceeds allowance\"\n )\n );\n return true;\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/MockOGN.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./BurnableERC20.sol\";\nimport \"./MintableERC20.sol\";\n\n/**\n * @title Origin token (OGN).\n *\n * @dev Token that allows minting and burning.\n * @dev Important note:\n * @dev There is a known race condition in the ERC20 standard on the approve() method.\n * @dev See details: https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n * @dev The Origin token contract implements the increaseApproval() and decreaseApproval() methods.\n * @dev It is strongly recommended to use those methods rather than approve()\n * @dev when updating the token allowance.\n */\ncontract MockOGN is MintableERC20, BurnableERC20 {\n event SetWhitelistExpiration(uint256 expiration);\n event AllowedTransactorAdded(address sender);\n event AllowedTransactorRemoved(address sender);\n event AddCallSpenderWhitelist(address enabler, address spender);\n event RemoveCallSpenderWhitelist(address disabler, address spender);\n\n mapping(address => bool) public callSpenderWhitelist;\n address public owner = msg.sender;\n // UNIX timestamp (in seconds) after which this whitelist no longer applies\n uint256 public whitelistExpiration;\n // While the whitelist is active, either the sender or recipient must be\n // in allowedTransactors.\n mapping(address => bool) public allowedTransactors;\n\n // @dev Constructor that gives msg.sender all initial tokens.\n constructor(uint256 _initialSupply) ERC20(\"OriginToken\", \"OGN\") {\n owner = msg.sender;\n _mint(owner, _initialSupply);\n }\n\n //\n // approveAndCall methods\n //\n\n // @dev Add spender to whitelist of spenders for approveAndCall\n // @param _spender Address to add\n function addCallSpenderWhitelist(address _spender) public onlyOwner {\n callSpenderWhitelist[_spender] = true;\n emit AddCallSpenderWhitelist(msg.sender, _spender);\n }\n\n // @dev Remove spender from whitelist of spenders for approveAndCall\n // @param _spender Address to remove\n function removeCallSpenderWhitelist(address _spender) public onlyOwner {\n delete callSpenderWhitelist[_spender];\n emit RemoveCallSpenderWhitelist(msg.sender, _spender);\n }\n\n // @dev Approve transfer of tokens and make a contract call in a single\n // @dev transaction. This allows a DApp to avoid requiring two MetaMask\n // @dev approvals for a single logical action, such as creating a listing,\n // @dev which requires the seller to approve a token transfer and the\n // @dev marketplace contract to transfer tokens from the seller.\n //\n // @dev This is based on the ERC827 function approveAndCall and avoids\n // @dev security issues by only working with a whitelisted set of _spender\n // @dev addresses. The other difference is that the combination of this\n // @dev function ensures that the proxied function call receives the\n // @dev msg.sender for this function as its first parameter.\n //\n // @param _spender The address that will spend the funds.\n // @param _value The amount of tokens to be spent.\n // @param _selector Function selector for function to be called.\n // @param _callParams Packed, encoded parameters, omitting the first parameter which is always msg.sender\n function approveAndCallWithSender(\n address _spender,\n uint256 _value,\n bytes4 _selector,\n bytes memory _callParams\n ) public payable returns (bool) {\n require(_spender != address(this), \"token contract can't be approved\");\n require(callSpenderWhitelist[_spender], \"spender not in whitelist\");\n\n require(super.approve(_spender, _value), \"approve failed\");\n\n bytes memory callData = abi.encodePacked(\n _selector,\n uint256(uint160(msg.sender)),\n _callParams\n );\n // solium-disable-next-line security/no-call-value\n (bool success, ) = _spender.call{ value: msg.value }(callData);\n require(success, \"proxied call failed\");\n return true;\n }\n\n //\n // Functions for maintaining whitelist\n //\n\n modifier onlyOwner() {\n require(msg.sender == owner);\n _;\n }\n modifier allowedTransfer(address _from, address _to) {\n require(\n // solium-disable-next-line operator-whitespace\n !whitelistActive() ||\n allowedTransactors[_from] ||\n allowedTransactors[_to],\n \"neither sender nor recipient are allowed\"\n );\n _;\n }\n\n function whitelistActive() public view returns (bool) {\n return block.timestamp < whitelistExpiration;\n }\n\n function addAllowedTransactor(address _transactor) public onlyOwner {\n emit AllowedTransactorAdded(_transactor);\n allowedTransactors[_transactor] = true;\n }\n\n function removeAllowedTransactor(address _transactor) public onlyOwner {\n emit AllowedTransactorRemoved(_transactor);\n delete allowedTransactors[_transactor];\n }\n\n /**\n * @dev Set the whitelist expiration, after which the whitelist no longer\n * applies.\n */\n function setWhitelistExpiration(uint256 _expiration) public onlyOwner {\n // allow only if whitelist expiration hasn't yet been set, or if the\n // whitelist expiration hasn't passed yet\n require(\n whitelistExpiration == 0 || whitelistActive(),\n \"an expired whitelist cannot be extended\"\n );\n // prevent possible mistakes in calling this function\n require(\n _expiration >= block.timestamp + 1 days,\n \"whitelist expiration not far enough into the future\"\n );\n emit SetWhitelistExpiration(_expiration);\n whitelistExpiration = _expiration;\n }\n\n //\n // ERC20 transfer functions that have been overridden to enforce the\n // whitelist.\n //\n\n function transfer(address _to, uint256 _value)\n public\n override\n allowedTransfer(msg.sender, _to)\n returns (bool)\n {\n return super.transfer(_to, _value);\n }\n\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n ) public override allowedTransfer(_from, _to) returns (bool) {\n return super.transferFrom(_from, _to, _value);\n }\n}\n" + }, + "contracts/mocks/MockOGV.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./MintableERC20.sol\";\n\ncontract MockOGV is MintableERC20 {\n constructor() ERC20(\"OGV\", \"OGV\") {}\n}\n" + }, + "contracts/mocks/MockOracle.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../interfaces/IPriceOracle.sol\";\nimport \"../interfaces/IMinMaxOracle.sol\";\n\n/**\n * Mock of both price Oracle and min max oracles\n */\ncontract MockOracle is IPriceOracle, IMinMaxOracle {\n mapping(bytes32 => uint256) prices;\n mapping(bytes32 => uint256[]) pricesMinMax;\n uint256 ethMin;\n uint256 ethMax;\n\n /**\n * @dev returns the asset price in USD, 6 decimal digits.\n * Compatible with the Open Price Feed.\n */\n function price(string calldata symbol)\n external\n view\n override\n returns (uint256)\n {\n return prices[keccak256(abi.encodePacked(symbol))];\n }\n\n /**\n * @dev sets the price of the asset in USD, 6 decimal digits\n *\n */\n function setPrice(string calldata symbol, uint256 _price) external {\n prices[keccak256(abi.encodePacked(symbol))] = _price;\n }\n\n /**\n * @dev sets the min and max price of ETH in USD, 6 decimal digits\n *\n */\n function setEthPriceMinMax(uint256 _min, uint256 _max) external {\n ethMin = _min;\n ethMax = _max;\n }\n\n /**\n * @dev sets the prices Min Max for a specific symbol in ETH, 8 decimal digits\n *\n */\n function setTokPriceMinMax(\n string calldata symbol,\n uint256 _min,\n uint256 _max\n ) external {\n pricesMinMax[keccak256(abi.encodePacked(symbol))] = [_min, _max];\n }\n\n /**\n * @dev get the price of asset in ETH, 8 decimal digits.\n */\n function priceMin(string calldata symbol)\n external\n view\n override\n returns (uint256)\n {\n uint256[] storage pMinMax = pricesMinMax[\n keccak256(abi.encodePacked(symbol))\n ];\n return (pMinMax[0] * ethMin) / 1e6;\n }\n\n /**\n * @dev get the price of asset in USD, 8 decimal digits.\n * Not needed for now\n */\n function priceMax(string calldata symbol)\n external\n view\n override\n returns (uint256)\n {\n uint256[] storage pMinMax = pricesMinMax[\n keccak256(abi.encodePacked(symbol))\n ];\n return (pMinMax[1] * ethMax) / 1e6;\n }\n}\n" + }, + "contracts/mocks/MockOracleRouter.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../interfaces/chainlink/AggregatorV3Interface.sol\";\nimport { IOracle } from \"../interfaces/IOracle.sol\";\nimport { Helpers } from \"../utils/Helpers.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\nimport { SafeCast } from \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\nimport { OracleRouterBase } from \"../oracle/OracleRouterBase.sol\";\n\n// @notice Oracle Router required for testing environment\ncontract MockOracleRouter is OracleRouterBase {\n struct FeedMetadata {\n address feedAddress;\n uint256 maxStaleness;\n }\n\n mapping(address => FeedMetadata) public assetToFeedMetadata;\n\n /* @dev Override feed and maxStaleness information for a particular asset\n * @param _asset the asset to override feed for\n * @param _feed new feed\n * @param _maxStaleness new maximum time allowed for feed data to be stale\n */\n function setFeed(\n address _asset,\n address _feed,\n uint256 _maxStaleness\n ) external {\n assetToFeedMetadata[_asset] = FeedMetadata(_feed, _maxStaleness);\n }\n\n /*\n * The dev version of the Oracle doesn't need to gas optimize and cache the decimals\n */\n function getDecimals(address _feed) internal view override returns (uint8) {\n require(_feed != address(0), \"Asset not available\");\n require(_feed != FIXED_PRICE, \"Fixed price feeds not supported\");\n\n return AggregatorV3Interface(_feed).decimals();\n }\n\n /**\n * @dev The price feed contract to use for a particular asset along with\n * maximum data staleness\n * @param asset address of the asset\n * @return feedAddress address of the price feed for the asset\n * @return maxStaleness maximum acceptable data staleness duration\n */\n function feedMetadata(address asset)\n internal\n view\n override\n returns (address feedAddress, uint256 maxStaleness)\n {\n FeedMetadata storage fm = assetToFeedMetadata[asset];\n feedAddress = fm.feedAddress;\n maxStaleness = fm.maxStaleness;\n }\n}\n" + }, + "contracts/mocks/MockOracleRouterNoStale.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../interfaces/chainlink/AggregatorV3Interface.sol\";\nimport { IOracle } from \"../interfaces/IOracle.sol\";\nimport { Helpers } from \"../utils/Helpers.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\nimport { SafeCast } from \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\nimport { OracleRouter } from \"../oracle/OracleRouter.sol\";\nimport { OETHOracleRouter } from \"../oracle/OETHOracleRouter.sol\";\n\n// @notice Oracle Router used to bypass staleness\ncontract MockOracleRouterNoStale is OracleRouter {\n function feedMetadata(address asset)\n internal\n pure\n virtual\n override\n returns (address feedAddress, uint256 maxStaleness)\n {\n (feedAddress, ) = super.feedMetadata(asset);\n maxStaleness = 365 days;\n }\n}\n\n// @notice Oracle Router used to bypass staleness\ncontract MockOETHOracleRouterNoStale is OETHOracleRouter {\n constructor(address auraPriceFeed) OETHOracleRouter(auraPriceFeed) {}\n\n function feedMetadata(address asset)\n internal\n view\n virtual\n override\n returns (address feedAddress, uint256 maxStaleness)\n {\n (feedAddress, ) = super.feedMetadata(asset);\n maxStaleness = 365 days;\n }\n}\n" + }, + "contracts/mocks/MockOracleWeightedPool.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { Variable, OracleAverageQuery, IOracleWeightedPool } from \"../interfaces/balancer/IOracleWeightedPool.sol\";\n\ncontract MockOracleWeightedPool is IOracleWeightedPool {\n uint256[] public nextResults;\n\n constructor() {\n nextResults = [1 ether, 1 ether];\n }\n\n function getTimeWeightedAverage(OracleAverageQuery[] memory)\n external\n view\n override\n returns (uint256[] memory results)\n {\n return nextResults;\n }\n\n function setNextResults(uint256[] calldata results) external {\n nextResults = results;\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/MockRETH.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./MintableERC20.sol\";\nimport \"../interfaces/IGetExchangeRateToken.sol\";\n\ncontract MockRETH is MintableERC20, IGetExchangeRateToken {\n uint256 private exchangeRate = 12e17;\n\n constructor() ERC20(\"Rocket Pool ETH\", \"rETH\") {}\n\n function getExchangeRate() external view override returns (uint256) {\n return exchangeRate;\n }\n\n function setExchangeRate(uint256 _rate) external {\n exchangeRate = _rate;\n }\n}\n" + }, + "contracts/mocks/MocksfrxETH.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./MintableERC20.sol\";\n\ncontract MocksfrxETH is MintableERC20 {\n address public frxETH;\n\n constructor(address _frxETH) ERC20(\"sfrxETH\", \"sfrxETH\") {\n frxETH = _frxETH;\n }\n\n function setMockfrxETHAddress(address _frxETH) external {\n frxETH = _frxETH;\n }\n\n function deposit(uint256 assets, address receiver)\n external\n returns (uint256 shares)\n {\n ERC20(frxETH).transferFrom(msg.sender, address(this), assets);\n\n _mint(receiver, assets);\n\n return assets;\n }\n\n function maxWithdraw(address owner) external view returns (uint256) {\n return balanceOf(owner);\n }\n\n function setMaxWithdrawableBalance(address owner, uint256 balance)\n external\n {\n uint256 currentBalance = balanceOf(owner);\n if (currentBalance > balance) {\n _burn(owner, currentBalance - balance);\n } else if (balance > currentBalance) {\n _mint(owner, balance - currentBalance);\n }\n }\n\n function redeem(\n uint256 shares,\n address receiver,\n address owner\n ) external returns (uint256 assets) {\n _burn(owner, shares);\n\n ERC20(frxETH).transfer(receiver, shares);\n\n assets = shares;\n }\n\n function withdraw(\n uint256 assets,\n address receiver,\n address owner\n ) external returns (uint256 shares) {\n _burn(owner, assets);\n\n ERC20(frxETH).transfer(receiver, assets);\n\n shares = assets;\n }\n\n function submitAndDeposit(address recipient)\n external\n payable\n returns (uint256 shares)\n {\n _mint(recipient, msg.value);\n shares = msg.value;\n }\n}\n" + }, + "contracts/mocks/MockSSV.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./MintableERC20.sol\";\n\ncontract MockSSV is MintableERC20 {\n constructor() ERC20(\"SSV Token\", \"SSV\") {}\n}\n" + }, + "contracts/mocks/MockSSVNetwork.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ncontract MockSSVNetwork {\n constructor() {}\n}\n" + }, + "contracts/mocks/MockstETH.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./MintableERC20.sol\";\n\ncontract MockstETH is MintableERC20 {\n constructor() ERC20(\"stETH\", \"stETH\") {}\n}\n" + }, + "contracts/mocks/MockStkAave.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 \"./MintableERC20.sol\";\n\ncontract MockStkAave is MintableERC20 {\n uint256 public COOLDOWN_SECONDS = 864000;\n uint256 public UNSTAKE_WINDOW = 172800;\n address public STAKED_TOKEN;\n\n mapping(address => uint256) public stakerRewardsToClaim;\n mapping(address => uint256) public stakersCooldowns;\n\n using SafeERC20 for IERC20;\n\n constructor(address _stakedToken) ERC20(\"Staked Aave\", \"stkAAVE\") {\n STAKED_TOKEN = _stakedToken;\n }\n\n function decimals() public pure override returns (uint8) {\n return 18;\n }\n\n function setStakedToken(address _stakedToken) external {\n STAKED_TOKEN = _stakedToken;\n }\n\n /**\n * @dev Redeems staked tokens, and stop earning rewards\n * @param to Address to redeem to\n * @param amount Amount to redeem\n **/\n function redeem(address to, uint256 amount) external {\n uint256 cooldownStartTimestamp = stakersCooldowns[msg.sender];\n uint256 windowStart = cooldownStartTimestamp + COOLDOWN_SECONDS;\n require(amount != 0, \"INVALID_ZERO_AMOUNT\");\n require(block.timestamp > windowStart, \"INSUFFICIENT_COOLDOWN\");\n require(\n block.timestamp - windowStart <= UNSTAKE_WINDOW,\n \"UNSTAKE_WINDOW_FINISHED\"\n );\n uint256 balanceOfMessageSender = balanceOf(msg.sender);\n uint256 amountToRedeem = (amount > balanceOfMessageSender)\n ? balanceOfMessageSender\n : amount;\n\n stakersCooldowns[msg.sender] = 0;\n _burn(msg.sender, amountToRedeem);\n IERC20(STAKED_TOKEN).safeTransfer(to, amountToRedeem);\n }\n\n /**\n * @dev Activates the cooldown period to unstake\n * - It can't be called if the user is not staking\n **/\n function cooldown() external {\n require(balanceOf(msg.sender) != 0, \"INVALID_BALANCE_ON_COOLDOWN\");\n stakersCooldowns[msg.sender] = block.timestamp;\n }\n\n /**\n * @dev Test helper function to allow changing the cooldown\n **/\n function setCooldown(address account, uint256 _cooldown) external {\n stakersCooldowns[account] = _cooldown;\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 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 require(false, \"Not implemented\");\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" + }, + "contracts/mocks/MockSwapper.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { IMintableERC20 } from \"./MintableERC20.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\ncontract MockSwapper {\n uint256 public nextOutAmount;\n\n function swap(\n // solhint-disable-next-line no-unused-vars\n address _fromAsset,\n address _toAsset,\n // solhint-disable-next-line no-unused-vars\n uint256 _fromAssetAmount,\n uint256 _minToAssetAmount,\n // solhint-disable-next-line no-unused-vars\n bytes calldata _data\n ) external returns (uint256 toAssetAmount) {\n toAssetAmount = (nextOutAmount > 0) ? nextOutAmount : _minToAssetAmount;\n nextOutAmount = 0;\n IMintableERC20(_toAsset).mint(toAssetAmount);\n IERC20(_toAsset).transfer(msg.sender, toAssetAmount);\n }\n\n function setNextOutAmount(uint256 _nextOutAmount) public {\n nextOutAmount = _nextOutAmount;\n }\n}\n" + }, + "contracts/mocks/MockTUSD.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./MintableERC20.sol\";\n\ncontract MockTUSD is MintableERC20 {\n constructor() ERC20(\"TrueUSD\", \"TUSD\") {}\n\n function decimals() public pure override returns (uint8) {\n return 18;\n }\n}\n" + }, + "contracts/mocks/MockUniswapPair.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { IUniswapV2Pair } from \"../interfaces/uniswap/IUniswapV2Pair.sol\";\n\ncontract MockUniswapPair is IUniswapV2Pair {\n address tok0;\n address tok1;\n uint112 reserve0;\n uint112 reserve1;\n uint256 blockTimestampLast;\n\n bool public hasSynced = false;\n\n constructor(\n address _token0,\n address _token1,\n uint112 _reserve0,\n uint112 _reserve1\n ) {\n tok0 = _token0;\n tok1 = _token1;\n reserve0 = _reserve0;\n reserve1 = _reserve1;\n blockTimestampLast = block.timestamp;\n }\n\n function token0() external view override returns (address) {\n return tok0;\n }\n\n function token1() external view override returns (address) {\n return tok1;\n }\n\n function getReserves()\n external\n view\n override\n returns (\n uint112,\n uint112,\n uint32\n )\n {\n return (reserve0, reserve1, uint32(blockTimestampLast));\n }\n\n function setReserves(uint112 _reserve0, uint112 _reserve1) public {\n reserve0 = _reserve0;\n reserve1 = _reserve1;\n blockTimestampLast = block.timestamp;\n }\n\n // CAUTION This will not work if you setReserves multiple times over\n // multiple different blocks because then it wouldn't be a continuous\n // reserve factor over that blockTimestamp, this assumes an even reserve\n // ratio all the way through\n function price0CumulativeLast() external view override returns (uint256) {\n return\n uint256(FixedPoint.fraction(reserve1, reserve0)._x) *\n blockTimestampLast;\n }\n\n function price1CumulativeLast() external view override returns (uint256) {\n return\n uint256(FixedPoint.fraction(reserve0, reserve1)._x) *\n blockTimestampLast;\n }\n\n function sync() external override {\n hasSynced = true;\n }\n\n function checkHasSynced() external view {\n require(hasSynced, \"Not synced\");\n }\n}\n\n// a library for handling binary fixed point numbers (https://en.wikipedia.org/wiki/Q_(number_format))\nlibrary FixedPoint {\n // range: [0, 2**112 - 1]\n // resolution: 1 / 2**112\n struct uq112x112 {\n uint224 _x;\n }\n\n // returns a uq112x112 which represents the ratio of the numerator to the denominator\n // equivalent to encode(numerator).div(denominator)\n function fraction(uint112 numerator, uint112 denominator)\n internal\n pure\n returns (uq112x112 memory)\n {\n require(denominator > 0, \"FixedPoint: DIV_BY_ZERO\");\n return uq112x112((uint224(numerator) << 112) / denominator);\n }\n}\n" + }, + "contracts/mocks/MockUniswapRouter.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { MintableERC20 } from \"./MintableERC20.sol\";\nimport { IUniswapV2Router } from \"../interfaces/uniswap/IUniswapV2Router02.sol\";\nimport { Helpers } from \"../utils/Helpers.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\n\ncontract MockUniswapRouter is IUniswapV2Router {\n using StableMath for uint256;\n\n mapping(address => address) public pairMaps;\n uint256 public slippage = 1 ether;\n\n function initialize(\n address[] calldata _0tokens,\n address[] calldata _1tokens\n ) public {\n require(\n _0tokens.length == _1tokens.length,\n \"Mock token pairs should be of the same length\"\n );\n for (uint256 i = 0; i < _0tokens.length; i++) {\n pairMaps[_0tokens[i]] = _1tokens[i];\n }\n }\n\n function setSlippage(uint256 _slippage) external {\n slippage = _slippage;\n }\n\n function swapExactTokensForTokens(\n uint256 amountIn,\n uint256 amountOutMin,\n address[] calldata path,\n address to,\n // solhint-disable-next-line no-unused-vars\n uint256\n ) external override returns (uint256[] memory amountsOut) {\n address tok0 = path[0];\n address tok1 = path[path.length - 1];\n\n uint256 amountOut = (amountOutMin * slippage) / 1 ether;\n require(amountOut >= amountOutMin, \"Slippage error\");\n\n IERC20(tok0).transferFrom(msg.sender, address(this), amountIn);\n MintableERC20(tok1).mintTo(to, amountOut);\n\n amountsOut = new uint256[](path.length);\n amountsOut[path.length - 1] = amountOut;\n }\n\n struct ExactInputParams {\n bytes path;\n address recipient;\n uint256 deadline;\n uint256 amountIn;\n uint256 amountOutMinimum;\n }\n\n function exactInput(ExactInputParams calldata params)\n external\n payable\n returns (uint256 amountOut)\n {\n (address tok0, address tok1) = _getFirstAndLastToken(params.path);\n\n amountOut = (params.amountOutMinimum * slippage) / 1 ether;\n\n IERC20(tok0).transferFrom(msg.sender, address(this), params.amountIn);\n MintableERC20(tok1).mintTo(params.recipient, amountOut);\n\n require(\n amountOut >= params.amountOutMinimum,\n \"UniswapMock: amountOut less than amountOutMinimum\"\n );\n return amountOut;\n }\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 override\n returns (\n uint256 amountA,\n uint256 amountB,\n uint256 liquidity\n )\n {\n // this is needed to make this contract whole else it'd be just virtual\n }\n\n function WETH() external pure override returns (address) {\n return address(0);\n }\n\n // Universal router mock\n function execute(\n bytes calldata,\n bytes[] calldata inputs,\n uint256\n ) external payable {\n uint256 inLen = inputs.length;\n for (uint256 i = 0; i < inLen; ++i) {\n (\n address recipient,\n ,\n uint256 amountOutMinimum,\n bytes memory path,\n\n ) = abi.decode(inputs[i], (address, uint256, uint256, bytes, bool));\n\n (address token0, address token1) = _getFirstAndLastToken(path);\n\n amountOutMinimum = amountOutMinimum.scaleBy(\n Helpers.getDecimals(token0),\n Helpers.getDecimals(token1)\n );\n\n MintableERC20(token1).mintTo(recipient, amountOutMinimum);\n }\n }\n\n function _getFirstAndLastToken(bytes memory path)\n internal\n view\n returns (address token0, address token1)\n {\n bytes memory tok0Bytes = new bytes(20);\n for (uint256 j = 0; j < 20; ++j) {\n tok0Bytes[j] = path[j];\n }\n token0 = address(bytes20(tok0Bytes));\n\n if (pairMaps[token0] != address(0)) {\n token0 = pairMaps[token0];\n }\n\n bytes memory tok1Bytes = new bytes(20);\n uint256 tok1Offset = path.length - 20;\n for (uint256 j = 0; j < 20; ++j) {\n tok1Bytes[j] = path[j + tok1Offset];\n }\n token1 = address(bytes20(tok1Bytes));\n\n if (pairMaps[token1] != address(0)) {\n token1 = pairMaps[token1];\n }\n }\n}\n" + }, + "contracts/mocks/MockUSDC.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./MintableERC20.sol\";\n\ncontract MockUSDC is MintableERC20 {\n constructor() ERC20(\"USDC Coin\", \"USDC\") {}\n\n function decimals() public pure override returns (uint8) {\n return 6;\n }\n}\n" + }, + "contracts/mocks/MockUSDT.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./MintableERC20.sol\";\n\ncontract MockUSDT is MintableERC20 {\n constructor() ERC20(\"USDT Coin\", \"USDT\") {}\n\n function decimals() public pure override returns (uint8) {\n return 6;\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/mocks/MockWETH.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./MintableERC20.sol\";\n\ncontract MockWETH is MintableERC20 {\n constructor() ERC20(\"WETH\", \"WETH\") {}\n\n function deposit() external payable {\n _mint(msg.sender, msg.value);\n }\n\n function withdraw(uint256 wad) external {\n _burn(msg.sender, wad);\n payable(msg.sender).transfer(wad);\n }\n}\n" + }, + "contracts/oracle/AuraWETHPriceFeed.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { Variable, OracleAverageQuery, IOracleWeightedPool } from \"../interfaces/balancer/IOracleWeightedPool.sol\";\nimport { Strategizable } from \"../governance/Strategizable.sol\";\nimport { AggregatorV3Interface } from \"../interfaces/chainlink/AggregatorV3Interface.sol\";\nimport { SafeCast } from \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\n\ncontract AuraWETHPriceFeed is AggregatorV3Interface, Strategizable {\n using SafeCast for uint256;\n using SafeCast for int256;\n\n event PriceFeedPaused();\n event PriceFeedUnpaused();\n event ToleranceChanged(uint256 oldTolerance, uint256 newTolerance);\n\n error PriceFeedPausedError();\n error PriceFeedUnpausedError();\n error InvalidToleranceBps();\n error HighPriceVolatility(uint256 deviation);\n\n bool public paused;\n uint256 public tolerance = 0.02 ether; // 2% by default\n\n // Fields to make it compatible with `AggregatorV3Interface`\n uint8 public constant override decimals = 18;\n string public constant override description = \"\";\n uint256 public constant override version = 1;\n\n IOracleWeightedPool public immutable auraOracleWeightedPool;\n\n constructor(address _auraOracleWeightedPool, address _governor) {\n _setGovernor(_governor);\n auraOracleWeightedPool = IOracleWeightedPool(_auraOracleWeightedPool);\n }\n\n /**\n * @dev Queries the OracleWeightedPool for TWAP of two intervals\n * (1h data from 5m ago and the recent 5m data) and ensures that\n * the price hasn't deviated too much and returns the most recent\n * TWAP price.\n *\n * @return price The price scaled to 18 decimals\n **/\n function price() external view returns (int256) {\n return _price();\n }\n\n function _price() internal view returns (int256) {\n if (paused) {\n revert PriceFeedPausedError();\n }\n OracleAverageQuery[] memory queries = new OracleAverageQuery[](2);\n\n queries[0] = OracleAverageQuery({\n variable: Variable.PAIR_PRICE,\n secs: 3600, // Get 1h data\n ago: 300 // From 5min ago\n });\n queries[1] = OracleAverageQuery({\n variable: Variable.PAIR_PRICE,\n secs: 300, // Get 5min data\n ago: 0 // From now\n });\n\n uint256[] memory prices = auraOracleWeightedPool.getTimeWeightedAverage(\n queries\n );\n int256 price_1h = prices[0].toInt256();\n int256 price_5m = prices[1].toInt256();\n\n int256 diff = (1e18 * (price_1h - price_5m)) /\n ((price_1h + price_5m) / 2);\n uint256 absDiff = diff >= 0 ? diff.toUint256() : (-diff).toUint256();\n\n // Ensure the price hasn't moved too much (2% tolerance)\n // between now and the past hour\n if (absDiff > tolerance) {\n revert HighPriceVolatility(absDiff);\n }\n\n // Return the recent price\n return price_5m;\n }\n\n /**\n * Pauses the price feed. Callable by Strategist as well.\n **/\n function pause() external onlyGovernorOrStrategist {\n if (paused) {\n revert PriceFeedPausedError();\n }\n paused = true;\n emit PriceFeedPaused();\n }\n\n /**\n * Unpauses the price feed. Only Governor can call it\n **/\n function unpause() external onlyGovernor {\n if (!paused) {\n revert PriceFeedUnpausedError();\n }\n paused = false;\n emit PriceFeedUnpaused();\n }\n\n /**\n * Set the max amount of tolerance acceptable between\n * two different price points.\n *\n * @param _tolerance New tolerance value\n **/\n function setTolerance(uint256 _tolerance) external onlyGovernor {\n if (_tolerance > 0.1 ether) {\n revert InvalidToleranceBps();\n }\n emit ToleranceChanged(tolerance, _tolerance);\n tolerance = _tolerance;\n }\n\n /**\n * @dev This function exists to make the contract compatible\n * with AggregatorV3Interface (which OETHOracleRouter uses to\n * get the price).\n *\n * The `answer` returned by this is same as what `price()` would return.\n *\n * It doesn't return any data about rounds (since those doesn't exist).\n **/\n function latestRoundData()\n external\n view\n override\n returns (\n uint80,\n int256 answer,\n uint256,\n uint256 updatedAt,\n uint80\n )\n {\n answer = _price();\n updatedAt = block.timestamp;\n }\n\n /**\n * @dev This function exists to make the contract compatible\n * with AggregatorV3Interface.\n *\n * Always reverts since there're no round data in this contract.\n **/\n function getRoundData(uint80)\n external\n pure\n override\n returns (\n uint80,\n int256,\n uint256,\n uint256,\n uint80\n )\n {\n revert(\"No data present\");\n }\n}\n" + }, + "contracts/oracle/OETHFixedOracle.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { OETHOracleRouter } from \"./OETHOracleRouter.sol\";\n\n// @notice Oracle Router that returns 1e18 for all prices\n// used solely for deployment to testnets\ncontract OETHFixedOracle is OETHOracleRouter {\n constructor(address _auraPriceFeed) OETHOracleRouter(_auraPriceFeed) {}\n\n /**\n * @dev The price feed contract to use for a particular asset along with\n * maximum data staleness\n * @param asset address of the asset\n * @return feedAddress address of the price feed for the asset\n * @return maxStaleness maximum acceptable data staleness duration\n */\n // solhint-disable-next-line no-unused-vars\n function feedMetadata(address asset)\n internal\n view\n virtual\n override\n returns (address feedAddress, uint256 maxStaleness)\n {\n // fixes price for all of the assets\n feedAddress = FIXED_PRICE;\n maxStaleness = 0;\n }\n}\n" + }, + "contracts/oracle/OETHOracleRouter.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../interfaces/chainlink/AggregatorV3Interface.sol\";\nimport { OracleRouterBase } from \"./OracleRouterBase.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\n\n// @notice Oracle Router that denominates all prices in ETH\ncontract OETHOracleRouter is OracleRouterBase {\n using StableMath for uint256;\n\n address public immutable auraPriceFeed;\n\n constructor(address _auraPriceFeed) {\n auraPriceFeed = _auraPriceFeed;\n }\n\n /**\n * @notice Returns the total price in 18 digit units for a given asset.\n * This implementation does not (!) do range checks as the\n * parent OracleRouter does.\n * @param asset address of the asset\n * @return uint256 unit price for 1 asset unit, in 18 decimal fixed\n */\n function price(address asset)\n external\n view\n virtual\n override\n returns (uint256)\n {\n (address _feed, uint256 maxStaleness) = feedMetadata(asset);\n if (_feed == FIXED_PRICE) {\n return 1e18;\n }\n require(_feed != address(0), \"Asset not available\");\n\n // slither-disable-next-line unused-return\n (, int256 _iprice, , uint256 updatedAt, ) = AggregatorV3Interface(_feed)\n .latestRoundData();\n\n require(\n updatedAt + maxStaleness >= block.timestamp,\n \"Oracle price too old\"\n );\n\n uint8 decimals = getDecimals(_feed);\n uint256 _price = uint256(_iprice).scaleBy(18, decimals);\n return _price;\n }\n\n /**\n * @dev The price feed contract to use for a particular asset along with\n * maximum data staleness\n * @param asset address of the asset\n * @return feedAddress address of the price feed for the asset\n * @return maxStaleness maximum acceptable data staleness duration\n */\n function feedMetadata(address asset)\n internal\n view\n virtual\n override\n returns (address feedAddress, uint256 maxStaleness)\n {\n if (asset == 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2) {\n // FIXED_PRICE: WETH/ETH\n feedAddress = FIXED_PRICE;\n maxStaleness = 0;\n } else if (asset == 0x5E8422345238F34275888049021821E8E08CAa1f) {\n // frxETH/ETH\n feedAddress = 0xC58F3385FBc1C8AD2c0C9a061D7c13b141D7A5Df;\n maxStaleness = 18 hours + STALENESS_BUFFER;\n } else if (asset == 0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84) {\n // https://data.chain.link/ethereum/mainnet/crypto-eth/steth-eth\n // Chainlink: stETH/ETH\n feedAddress = 0x86392dC19c0b719886221c78AB11eb8Cf5c52812;\n maxStaleness = 1 days + STALENESS_BUFFER;\n } else if (asset == 0xae78736Cd615f374D3085123A210448E74Fc6393) {\n // https://data.chain.link/ethereum/mainnet/crypto-eth/reth-eth\n // Chainlink: rETH/ETH\n feedAddress = 0x536218f9E9Eb48863970252233c8F271f554C2d0;\n maxStaleness = 1 days + STALENESS_BUFFER;\n } else if (asset == 0xD533a949740bb3306d119CC777fa900bA034cd52) {\n // https://data.chain.link/ethereum/mainnet/crypto-eth/crv-eth\n // Chainlink: CRV/ETH\n feedAddress = 0x8a12Be339B0cD1829b91Adc01977caa5E9ac121e;\n maxStaleness = 1 days + STALENESS_BUFFER;\n } else if (asset == 0x4e3FBD56CD56c3e72c1403e103b45Db9da5B9D2B) {\n // https://data.chain.link/ethereum/mainnet/crypto-eth/cvx-eth\n // Chainlink: CVX/ETH\n feedAddress = 0xC9CbF687f43176B302F03f5e58470b77D07c61c6;\n maxStaleness = 1 days + STALENESS_BUFFER;\n } else if (asset == 0xBe9895146f7AF43049ca1c1AE358B0541Ea49704) {\n // https://data.chain.link/ethereum/mainnet/crypto-eth/cbeth-eth\n // Chainlink: cbETH/ETH\n feedAddress = 0xF017fcB346A1885194689bA23Eff2fE6fA5C483b;\n maxStaleness = 1 days + STALENESS_BUFFER;\n } else if (asset == 0xba100000625a3754423978a60c9317c58a424e3D) {\n // https://data.chain.link/ethereum/mainnet/crypto-eth/bal-eth\n // Chainlink: BAL/ETH\n feedAddress = 0xC1438AA3823A6Ba0C159CfA8D98dF5A994bA120b;\n maxStaleness = 1 days + STALENESS_BUFFER;\n } else if (asset == 0xC0c293ce456fF0ED870ADd98a0828Dd4d2903DBF) {\n // AURA/ETH\n feedAddress = auraPriceFeed;\n maxStaleness = 0;\n } else {\n revert(\"Asset not available\");\n }\n }\n}\n" + }, + "contracts/oracle/OracleRouter.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../interfaces/chainlink/AggregatorV3Interface.sol\";\nimport { OracleRouterBase } from \"./OracleRouterBase.sol\";\n\n// @notice Oracle Router that denominates all prices in USD\ncontract OracleRouter is OracleRouterBase {\n /**\n * @dev The price feed contract to use for a particular asset along with\n * maximum data staleness\n * @param asset address of the asset\n * @return feedAddress address of the price feed for the asset\n * @return maxStaleness maximum acceptable data staleness duration\n */\n function feedMetadata(address asset)\n internal\n pure\n virtual\n override\n returns (address feedAddress, uint256 maxStaleness)\n {\n /* + STALENESS_BUFFER is added in case Oracle for some reason doesn't\n * update on heartbeat and we add a generous buffer amount.\n */\n if (asset == 0x6B175474E89094C44Da98b954EedeAC495271d0F) {\n // https://data.chain.link/ethereum/mainnet/stablecoins/dai-usd\n // Chainlink: DAI/USD\n feedAddress = 0xAed0c38402a5d19df6E4c03F4E2DceD6e29c1ee9;\n maxStaleness = 1 hours + STALENESS_BUFFER;\n } else if (asset == 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48) {\n // https://data.chain.link/ethereum/mainnet/stablecoins/usdc-usd\n // Chainlink: USDC/USD\n feedAddress = 0x8fFfFfd4AfB6115b954Bd326cbe7B4BA576818f6;\n maxStaleness = 1 days + STALENESS_BUFFER;\n } else if (asset == 0xdAC17F958D2ee523a2206206994597C13D831ec7) {\n // https://data.chain.link/ethereum/mainnet/stablecoins/usdt-usd\n // Chainlink: USDT/USD\n feedAddress = 0x3E7d1eAB13ad0104d2750B8863b489D65364e32D;\n maxStaleness = 1 days + STALENESS_BUFFER;\n } else if (asset == 0xc00e94Cb662C3520282E6f5717214004A7f26888) {\n // https://data.chain.link/ethereum/mainnet/crypto-usd/comp-usd\n // Chainlink: COMP/USD\n feedAddress = 0xdbd020CAeF83eFd542f4De03e3cF0C28A4428bd5;\n maxStaleness = 1 hours + STALENESS_BUFFER;\n } else if (asset == 0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9) {\n // https://data.chain.link/ethereum/mainnet/crypto-usd/aave-usd\n // Chainlink: AAVE/USD\n feedAddress = 0x547a514d5e3769680Ce22B2361c10Ea13619e8a9;\n maxStaleness = 1 hours + STALENESS_BUFFER;\n } else if (asset == 0xD533a949740bb3306d119CC777fa900bA034cd52) {\n // https://data.chain.link/ethereum/mainnet/crypto-usd/crv-usd\n // Chainlink: CRV/USD\n feedAddress = 0xCd627aA160A6fA45Eb793D19Ef54f5062F20f33f;\n maxStaleness = 1 days + STALENESS_BUFFER;\n } else if (asset == 0x4e3FBD56CD56c3e72c1403e103b45Db9da5B9D2B) {\n // Chainlink: CVX/USD\n feedAddress = 0xd962fC30A72A84cE50161031391756Bf2876Af5D;\n maxStaleness = 1 days + STALENESS_BUFFER;\n } else {\n revert(\"Asset not available\");\n }\n }\n}\n" + }, + "contracts/oracle/OracleRouterBase.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../interfaces/chainlink/AggregatorV3Interface.sol\";\nimport { IOracle } from \"../interfaces/IOracle.sol\";\nimport { Helpers } from \"../utils/Helpers.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\nimport { SafeCast } from \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\n\n// @notice Abstract functionality that is shared between various Oracle Routers\nabstract contract OracleRouterBase is IOracle {\n using StableMath for uint256;\n using SafeCast for int256;\n\n uint256 internal constant MIN_DRIFT = 0.7e18;\n uint256 internal constant MAX_DRIFT = 1.3e18;\n address internal constant FIXED_PRICE =\n 0x0000000000000000000000000000000000000001;\n // Maximum allowed staleness buffer above normal Oracle maximum staleness\n uint256 internal constant STALENESS_BUFFER = 1 days;\n mapping(address => uint8) internal decimalsCache;\n\n /**\n * @dev The price feed contract to use for a particular asset along with\n * maximum data staleness\n * @param asset address of the asset\n * @return feedAddress address of the price feed for the asset\n * @return maxStaleness maximum acceptable data staleness duration\n */\n function feedMetadata(address asset)\n internal\n view\n virtual\n returns (address feedAddress, uint256 maxStaleness);\n\n /**\n * @notice Returns the total price in 18 digit unit for a given asset.\n * @param asset address of the asset\n * @return uint256 unit price for 1 asset unit, in 18 decimal fixed\n */\n function price(address asset)\n external\n view\n virtual\n override\n returns (uint256)\n {\n (address _feed, uint256 maxStaleness) = feedMetadata(asset);\n require(_feed != address(0), \"Asset not available\");\n require(_feed != FIXED_PRICE, \"Fixed price feeds not supported\");\n\n // slither-disable-next-line unused-return\n (, int256 _iprice, , uint256 updatedAt, ) = AggregatorV3Interface(_feed)\n .latestRoundData();\n\n require(\n updatedAt + maxStaleness >= block.timestamp,\n \"Oracle price too old\"\n );\n\n uint8 decimals = getDecimals(_feed);\n\n uint256 _price = _iprice.toUint256().scaleBy(18, decimals);\n if (shouldBePegged(asset)) {\n require(_price <= MAX_DRIFT, \"Oracle: Price exceeds max\");\n require(_price >= MIN_DRIFT, \"Oracle: Price under min\");\n }\n return _price;\n }\n\n function getDecimals(address _feed) internal view virtual returns (uint8) {\n uint8 decimals = decimalsCache[_feed];\n require(decimals > 0, \"Oracle: Decimals not cached\");\n return decimals;\n }\n\n /**\n * @notice Before an asset/feed price is fetches for the first time the\n * decimals need to be cached. This is a gas optimization\n * @param asset address of the asset\n * @return uint8 corresponding asset decimals\n */\n function cacheDecimals(address asset) external returns (uint8) {\n (address _feed, ) = feedMetadata(asset);\n require(_feed != address(0), \"Asset not available\");\n require(_feed != FIXED_PRICE, \"Fixed price feeds not supported\");\n\n uint8 decimals = AggregatorV3Interface(_feed).decimals();\n decimalsCache[_feed] = decimals;\n return decimals;\n }\n\n function shouldBePegged(address _asset) internal view returns (bool) {\n string memory symbol = Helpers.getSymbol(_asset);\n bytes32 symbolHash = keccak256(abi.encodePacked(symbol));\n return\n symbolHash == keccak256(abi.encodePacked(\"DAI\")) ||\n symbolHash == keccak256(abi.encodePacked(\"USDC\")) ||\n symbolHash == keccak256(abi.encodePacked(\"USDT\"));\n }\n}\n" + }, + "contracts/proxies/InitializeGovernedUpgradeabilityProxy.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { Address } from \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport { Governable } from \"../governance/Governable.sol\";\n\n/**\n * @title BaseGovernedUpgradeabilityProxy\n * @dev This contract combines an upgradeability proxy with our governor system.\n * It is based on an older version of OpenZeppelins BaseUpgradeabilityProxy\n * with Solidity ^0.8.0.\n * @author Origin Protocol Inc\n */\ncontract InitializeGovernedUpgradeabilityProxy is Governable {\n /**\n * @dev Emitted when the implementation is upgraded.\n * @param implementation Address of the new implementation.\n */\n event Upgraded(address indexed implementation);\n\n /**\n * @dev Contract initializer with Governor enforcement\n * @param _logic Address of the initial implementation.\n * @param _initGovernor Address of the initial Governor.\n * @param _data Data to send as msg.data to the implementation to initialize\n * the proxied contract.\n * It should include the signature and the parameters of the function to be\n * called, as described in\n * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.\n * This parameter is optional, if no data is given the initialization call\n * to proxied contract will be skipped.\n */\n function initialize(\n address _logic,\n address _initGovernor,\n bytes calldata _data\n ) public payable onlyGovernor {\n require(_implementation() == address(0));\n assert(\n IMPLEMENTATION_SLOT ==\n bytes32(uint256(keccak256(\"eip1967.proxy.implementation\")) - 1)\n );\n _setImplementation(_logic);\n if (_data.length > 0) {\n (bool success, ) = _logic.delegatecall(_data);\n require(success);\n }\n _changeGovernor(_initGovernor);\n }\n\n /**\n * @return The address of the proxy admin/it's also the governor.\n */\n function admin() external view returns (address) {\n return _governor();\n }\n\n /**\n * @return The address of the implementation.\n */\n function implementation() external view returns (address) {\n return _implementation();\n }\n\n /**\n * @dev Upgrade the backing implementation of the proxy.\n * Only the admin can call this function.\n * @param newImplementation Address of the new implementation.\n */\n function upgradeTo(address newImplementation) external onlyGovernor {\n _upgradeTo(newImplementation);\n }\n\n /**\n * @dev Upgrade the backing implementation of the proxy and call a function\n * on the new implementation.\n * This is useful to initialize the proxied contract.\n * @param newImplementation Address of the new implementation.\n * @param data Data to send as msg.data in the low level call.\n * It should include the signature and the parameters of the function to be called, as described in\n * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.\n */\n function upgradeToAndCall(address newImplementation, bytes calldata data)\n external\n payable\n onlyGovernor\n {\n _upgradeTo(newImplementation);\n (bool success, ) = newImplementation.delegatecall(data);\n require(success);\n }\n\n /**\n * @dev Fallback function.\n * Implemented entirely in `_fallback`.\n */\n fallback() external payable {\n _fallback();\n }\n\n /**\n * @dev Delegates execution to an implementation contract.\n * This is a low level function that doesn't return to its internal call site.\n * It will return to the external caller whatever the implementation returns.\n * @param _impl Address to delegate.\n */\n function _delegate(address _impl) internal {\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(gas(), _impl, 0, calldatasize(), 0, 0)\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 /**\n * @dev Function that is run as the first thing in the fallback function.\n * Can be redefined in derived contracts to add functionality.\n * Redefinitions must call super._willFallback().\n */\n function _willFallback() internal {}\n\n /**\n * @dev fallback implementation.\n * Extracted to enable manual triggering.\n */\n function _fallback() internal {\n _willFallback();\n _delegate(_implementation());\n }\n\n /**\n * @dev Storage slot with the address of the current implementation.\n * This is the keccak-256 hash of \"eip1967.proxy.implementation\" subtracted by 1, and is\n * validated in the constructor.\n */\n bytes32 internal constant IMPLEMENTATION_SLOT =\n 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\n\n /**\n * @dev Returns the current implementation.\n * @return impl Address of the current implementation\n */\n function _implementation() internal view returns (address impl) {\n bytes32 slot = IMPLEMENTATION_SLOT;\n // solhint-disable-next-line no-inline-assembly\n assembly {\n impl := sload(slot)\n }\n }\n\n /**\n * @dev Upgrades the proxy to a new implementation.\n * @param newImplementation Address of the new implementation.\n */\n function _upgradeTo(address newImplementation) internal {\n _setImplementation(newImplementation);\n emit Upgraded(newImplementation);\n }\n\n /**\n * @dev Sets the implementation address of the proxy.\n * @param newImplementation Address of the new implementation.\n */\n function _setImplementation(address newImplementation) internal {\n require(\n Address.isContract(newImplementation),\n \"Cannot set a proxy implementation to a non-contract address\"\n );\n\n bytes32 slot = IMPLEMENTATION_SLOT;\n\n // solhint-disable-next-line no-inline-assembly\n assembly {\n sstore(slot, newImplementation)\n }\n }\n}\n" + }, + "contracts/proxies/Proxies.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { InitializeGovernedUpgradeabilityProxy } from \"./InitializeGovernedUpgradeabilityProxy.sol\";\n\n/**\n * @notice OUSDProxy delegates calls to an OUSD implementation\n */\ncontract OUSDProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice WrappedOUSDProxy delegates calls to a WrappedOUSD implementation\n */\ncontract WrappedOUSDProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice VaultProxy delegates calls to a Vault implementation\n */\ncontract VaultProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice CompoundStrategyProxy delegates calls to a CompoundStrategy implementation\n */\ncontract CompoundStrategyProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice AaveStrategyProxy delegates calls to a AaveStrategy implementation\n */\ncontract AaveStrategyProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice ThreePoolStrategyProxy delegates calls to a ThreePoolStrategy implementation\n */\ncontract ThreePoolStrategyProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice ConvexStrategyProxy delegates calls to a ConvexStrategy implementation\n */\ncontract ConvexStrategyProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice HarvesterProxy delegates calls to a Harvester implementation\n */\ncontract HarvesterProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice DripperProxy delegates calls to a Dripper implementation\n */\ncontract DripperProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice MorphoCompoundStrategyProxy delegates calls to a MorphoCompoundStrategy implementation\n */\ncontract MorphoCompoundStrategyProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice ConvexOUSDMetaStrategyProxy delegates calls to a ConvexOUSDMetaStrategy implementation\n */\ncontract ConvexOUSDMetaStrategyProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice ConvexLUSDMetaStrategyProxy delegates calls to a ConvexalGeneralizedMetaStrategy implementation\n */\ncontract ConvexLUSDMetaStrategyProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice MorphoAaveStrategyProxy delegates calls to a MorphoCompoundStrategy implementation\n */\ncontract MorphoAaveStrategyProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice OETHProxy delegates calls to nowhere for now\n */\ncontract OETHProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice WOETHProxy delegates calls to nowhere for now\n */\ncontract WOETHProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice OETHVaultProxy delegates calls to a Vault implementation\n */\ncontract OETHVaultProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice OETHDripperProxy delegates calls to a OETHDripper implementation\n */\ncontract OETHDripperProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice OETHHarvesterProxy delegates calls to a Harvester implementation\n */\ncontract OETHHarvesterProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice FraxETHStrategyProxy delegates calls to a FraxETHStrategy implementation\n */\ncontract FraxETHStrategyProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice CurveEthStrategyProxy delegates calls to a CurveEthStrategy implementation\n */\ncontract ConvexEthMetaStrategyProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice BuybackProxy delegates calls to Buyback implementation\n */\ncontract BuybackProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice OETHMorphoAaveStrategyProxy delegates calls to a MorphoAaveStrategy implementation\n */\ncontract OETHMorphoAaveStrategyProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice OETHBalancerMetaPoolrEthStrategyProxy delegates calls to a BalancerMetaPoolStrategy implementation\n */\ncontract OETHBalancerMetaPoolrEthStrategyProxy is\n InitializeGovernedUpgradeabilityProxy\n{\n\n}\n\n/**\n * @notice OETHBalancerMetaPoolwstEthStrategyProxy delegates calls to a BalancerMetaPoolStrategy implementation\n */\ncontract OETHBalancerMetaPoolwstEthStrategyProxy is\n InitializeGovernedUpgradeabilityProxy\n{\n\n}\n\n/**\n * @notice FluxStrategyProxy delegates calls to a CompoundStrategy implementation\n */\ncontract FluxStrategyProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice MakerDsrStrategyProxy delegates calls to a Generalized4626Strategy implementation\n */\ncontract MakerDsrStrategyProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice FrxEthRedeemStrategyProxy delegates calls to a FrxEthRedeemStrategy implementation\n */\ncontract FrxEthRedeemStrategyProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice OETHBuybackProxy delegates calls to Buyback implementation\n */\ncontract OETHBuybackProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice BridgedWOETHProxy delegates calls to BridgedWOETH implementation\n */\ncontract BridgedWOETHProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice NativeStakingSSVStrategyProxy delegates calls to NativeStakingSSVStrategy implementation\n */\ncontract NativeStakingSSVStrategyProxy is\n InitializeGovernedUpgradeabilityProxy\n{\n\n}\n\n/**\n * @notice NativeStakingFeeAccumulatorProxy delegates calls to NativeStakingFeeCollector implementation\n */\ncontract NativeStakingFeeAccumulatorProxy is\n InitializeGovernedUpgradeabilityProxy\n{\n\n}\n" + }, + "contracts/staking/SingleAssetStaking.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeMath } from \"@openzeppelin/contracts/utils/math/SafeMath.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 { StableMath } from \"../utils/StableMath.sol\";\n\ncontract SingleAssetStaking is Initializable, Governable {\n using SafeMath for uint256;\n using StableMath for uint256;\n using SafeERC20 for IERC20;\n\n /* ========== STATE VARIABLES ========== */\n\n IERC20 public stakingToken; // this is both the staking and rewards\n\n struct Stake {\n uint256 amount; // amount to stake\n uint256 end; // when does the staking period end\n uint256 duration; // the duration of the stake\n uint240 rate; // rate to charge use 248 to reserve 8 bits for the bool\n bool paid;\n uint8 stakeType;\n }\n\n struct DropRoot {\n bytes32 hash;\n uint256 depth;\n }\n\n uint256[] public durations; // allowed durations\n uint256[] public rates; // rates that correspond with the allowed durations\n\n uint256 public totalOutstanding;\n bool public paused;\n\n mapping(address => Stake[]) public userStakes;\n\n mapping(uint8 => DropRoot) public dropRoots;\n\n // type 0 is reserved for stakes done by the user, all other types will be drop/preApproved stakes\n uint8 constant USER_STAKE_TYPE = 0;\n uint256 constant MAX_STAKES = 256;\n\n address public transferAgent;\n\n /* ========== Initialize ========== */\n\n /**\n * @dev Initialize the contracts, sets up durations, rates, and preApprover\n * for preApproved contracts can only be called once\n * @param _stakingToken Address of the token that we are staking\n * @param _durations Array of allowed durations in seconds\n * @param _rates Array of rates(0.3 is 30%) that correspond to the allowed\n * durations in 1e18 precision\n */\n function initialize(\n address _stakingToken,\n uint256[] calldata _durations,\n uint256[] calldata _rates\n ) external onlyGovernor initializer {\n stakingToken = IERC20(_stakingToken);\n _setDurationRates(_durations, _rates);\n }\n\n /* ========= Internal helper functions ======== */\n\n /**\n * @dev Validate and set the duration and corresponding rates, will emit\n * events NewRate and NewDurations\n */\n function _setDurationRates(\n uint256[] memory _durations,\n uint256[] memory _rates\n ) internal {\n require(\n _rates.length == _durations.length,\n \"Mismatch durations and rates\"\n );\n\n for (uint256 i = 0; i < _rates.length; i++) {\n require(_rates[i] < type(uint240).max, \"Max rate exceeded\");\n }\n\n rates = _rates;\n durations = _durations;\n\n emit NewRates(msg.sender, rates);\n emit NewDurations(msg.sender, durations);\n }\n\n function _totalExpectedRewards(Stake[] storage stakes)\n internal\n view\n returns (uint256 total)\n {\n for (uint256 i = 0; i < stakes.length; i++) {\n Stake storage stake = stakes[i];\n if (!stake.paid) {\n total = total.add(stake.amount.mulTruncate(stake.rate));\n }\n }\n }\n\n function _totalExpected(Stake storage _stake)\n internal\n view\n returns (uint256)\n {\n return _stake.amount.add(_stake.amount.mulTruncate(_stake.rate));\n }\n\n function _airDroppedStakeClaimed(address account, uint8 stakeType)\n internal\n view\n returns (bool)\n {\n Stake[] storage stakes = userStakes[account];\n for (uint256 i = 0; i < stakes.length; i++) {\n if (stakes[i].stakeType == stakeType) {\n return true;\n }\n }\n return false;\n }\n\n function _findDurationRate(uint256 duration)\n internal\n view\n returns (uint240)\n {\n for (uint256 i = 0; i < durations.length; i++) {\n if (duration == durations[i]) {\n return uint240(rates[i]);\n }\n }\n return 0;\n }\n\n /**\n * @dev Internal staking function\n * will insert the stake into the stakes array and verify we have\n * enough to pay off stake + reward\n * @param staker Address of the staker\n * @param stakeType Number that represent the type of the stake, 0 is user\n * initiated all else is currently preApproved\n * @param duration Number of seconds this stake will be held for\n * @param rate Rate(0.3 is 30%) of reward for this stake in 1e18, uint240 =\n * to fit the bool and type in struct Stake\n * @param amount Number of tokens to stake in 1e18\n */\n function _stake(\n address staker,\n uint8 stakeType,\n uint256 duration,\n uint240 rate,\n uint256 amount\n ) internal {\n require(!paused, \"Staking paused\");\n\n Stake[] storage stakes = userStakes[staker];\n\n uint256 end = block.timestamp.add(duration);\n\n uint256 i = stakes.length; // start at the end of the current array\n\n require(i < MAX_STAKES, \"Max stakes\");\n\n stakes.push(); // grow the array\n // find the spot where we can insert the current stake\n // this should make an increasing list sorted by end\n while (i != 0 && stakes[i - 1].end > end) {\n // shift it back one\n stakes[i] = stakes[i - 1];\n i -= 1;\n }\n\n // insert the stake\n Stake storage newStake = stakes[i];\n newStake.rate = rate;\n newStake.stakeType = stakeType;\n newStake.end = end;\n newStake.duration = duration;\n newStake.amount = amount;\n\n totalOutstanding = totalOutstanding.add(_totalExpected(newStake));\n\n emit Staked(staker, amount, duration, rate);\n }\n\n function _stakeWithChecks(\n address staker,\n uint256 amount,\n uint256 duration\n ) internal {\n require(amount > 0, \"Cannot stake 0\");\n\n uint240 rewardRate = _findDurationRate(duration);\n require(rewardRate > 0, \"Invalid duration\"); // we couldn't find the rate that correspond to the passed duration\n\n _stake(staker, USER_STAKE_TYPE, duration, rewardRate, amount);\n // transfer in the token so that we can stake the correct amount\n stakingToken.safeTransferFrom(staker, address(this), amount);\n }\n\n modifier requireLiquidity() {\n // we need to have enough balance to cover the rewards after the operation is complete\n _;\n require(\n stakingToken.balanceOf(address(this)) >= totalOutstanding,\n \"Insufficient rewards\"\n );\n }\n\n /* ========== VIEWS ========== */\n\n function getAllDurations() external view returns (uint256[] memory) {\n return durations;\n }\n\n function getAllRates() external view returns (uint256[] memory) {\n return rates;\n }\n\n /**\n * @dev Return all the stakes paid and unpaid for a given user\n * @param account Address of the account that we want to look up\n */\n function getAllStakes(address account)\n external\n view\n returns (Stake[] memory)\n {\n return userStakes[account];\n }\n\n /**\n * @dev Find the rate that corresponds to a given duration\n * @param _duration Number of seconds\n */\n function durationRewardRate(uint256 _duration)\n external\n view\n returns (uint256)\n {\n return _findDurationRate(_duration);\n }\n\n /**\n * @dev Has the airdropped stake already been claimed\n */\n function airDroppedStakeClaimed(address account, uint8 stakeType)\n external\n view\n returns (bool)\n {\n return _airDroppedStakeClaimed(account, stakeType);\n }\n\n /**\n * @dev Calculate all the staked value a user has put into the contract,\n * rewards not included\n * @param account Address of the account that we want to look up\n */\n function totalStaked(address account)\n external\n view\n returns (uint256 total)\n {\n Stake[] storage stakes = userStakes[account];\n\n for (uint256 i = 0; i < stakes.length; i++) {\n if (!stakes[i].paid) {\n total = total.add(stakes[i].amount);\n }\n }\n }\n\n /**\n * @dev Calculate all the rewards a user can expect to receive.\n * @param account Address of the account that we want to look up\n */\n function totalExpectedRewards(address account)\n external\n view\n returns (uint256)\n {\n return _totalExpectedRewards(userStakes[account]);\n }\n\n /**\n * @dev Calculate all current holdings of a user: staked value + prorated rewards\n * @param account Address of the account that we want to look up\n */\n function totalCurrentHoldings(address account)\n external\n view\n returns (uint256 total)\n {\n Stake[] storage stakes = userStakes[account];\n\n for (uint256 i = 0; i < stakes.length; i++) {\n Stake storage stake = stakes[i];\n if (stake.paid) {\n continue;\n } else if (stake.end < block.timestamp) {\n total = total.add(_totalExpected(stake));\n } else {\n //calcualte the precentage accrued in term of rewards\n total = total.add(\n stake.amount.add(\n stake.amount.mulTruncate(stake.rate).mulTruncate(\n stake\n .duration\n .sub(stake.end.sub(block.timestamp))\n .divPrecisely(stake.duration)\n )\n )\n );\n }\n }\n }\n\n /* ========== MUTATIVE FUNCTIONS ========== */\n\n /**\n * @dev Make a preapproved stake for the user, this is a presigned voucher that the user can redeem either from\n * an airdrop or a compensation program.\n * Only 1 of each type is allowed per user. The proof must match the root hash\n * @param index Number that is zero base index of the stake in the payout entry\n * @param stakeType Number that represent the type of the stake, must not be 0 which is user stake\n * @param duration Number of seconds this stake will be held for\n * @param rate Rate(0.3 is 30%) of reward for this stake in 1e18, uint240 to fit the bool and type in struct Stake\n * @param amount Number of tokens to stake in 1e18\n * @param merkleProof Array of proofs for that amount\n */\n function airDroppedStake(\n uint256 index,\n uint8 stakeType,\n uint256 duration,\n uint256 rate,\n uint256 amount,\n bytes32[] calldata merkleProof\n ) external requireLiquidity {\n require(stakeType != USER_STAKE_TYPE, \"Cannot be normal staking\");\n require(rate < type(uint240).max, \"Max rate exceeded\");\n require(index < 2**merkleProof.length, \"Invalid index\");\n DropRoot storage dropRoot = dropRoots[stakeType];\n require(merkleProof.length == dropRoot.depth, \"Invalid proof\");\n\n // Compute the merkle root\n bytes32 node = keccak256(\n abi.encodePacked(\n index,\n stakeType,\n address(this),\n msg.sender,\n duration,\n rate,\n amount\n )\n );\n uint256 path = index;\n for (uint16 i = 0; i < merkleProof.length; i++) {\n if ((path & 0x01) == 1) {\n node = keccak256(abi.encodePacked(merkleProof[i], node));\n } else {\n node = keccak256(abi.encodePacked(node, merkleProof[i]));\n }\n path /= 2;\n }\n\n // Check the merkle proof\n require(node == dropRoot.hash, \"Stake not approved\");\n\n // verify that we haven't already staked\n require(\n !_airDroppedStakeClaimed(msg.sender, stakeType),\n \"Already staked\"\n );\n\n _stake(msg.sender, stakeType, duration, uint240(rate), amount);\n }\n\n /**\n * @dev Stake an approved amount of staking token into the contract.\n * User must have already approved the contract for specified amount.\n * @param amount Number of tokens to stake in 1e18\n * @param duration Number of seconds this stake will be held for\n */\n function stake(uint256 amount, uint256 duration) external requireLiquidity {\n // no checks are performed in this function since those are already present in _stakeWithChecks\n _stakeWithChecks(msg.sender, amount, duration);\n }\n\n /**\n * @dev Stake an approved amount of staking token into the contract. This function\n * can only be called by OGN token contract.\n * @param staker Address of the account that is creating the stake\n * @param amount Number of tokens to stake in 1e18\n * @param duration Number of seconds this stake will be held for\n */\n function stakeWithSender(\n address staker,\n uint256 amount,\n uint256 duration\n ) external requireLiquidity returns (bool) {\n require(\n msg.sender == address(stakingToken),\n \"Only token contract can make this call\"\n );\n\n _stakeWithChecks(staker, amount, duration);\n return true;\n }\n\n /**\n * @dev Exit out of all possible stakes\n */\n function exit() external requireLiquidity {\n Stake[] storage stakes = userStakes[msg.sender];\n require(stakes.length > 0, \"Nothing staked\");\n\n uint256 totalWithdraw = 0;\n uint256 stakedAmount = 0;\n uint256 l = stakes.length;\n do {\n Stake storage exitStake = stakes[l - 1];\n // stop on the first ended stake that's already been paid\n if (exitStake.end < block.timestamp && exitStake.paid) {\n break;\n }\n //might not be ended\n if (exitStake.end < block.timestamp) {\n //we are paying out the stake\n exitStake.paid = true;\n totalWithdraw = totalWithdraw.add(_totalExpected(exitStake));\n stakedAmount = stakedAmount.add(exitStake.amount);\n }\n l--;\n } while (l > 0);\n require(totalWithdraw > 0, \"All stakes in lock-up\");\n\n totalOutstanding = totalOutstanding.sub(totalWithdraw);\n emit Withdrawn(msg.sender, totalWithdraw, stakedAmount);\n stakingToken.safeTransfer(msg.sender, totalWithdraw);\n }\n\n /**\n * @dev Use to transfer all the stakes of an account in the case that the account is compromised\n * Requires access to both the account itself and the transfer agent\n * @param _frmAccount the address to transfer from\n * @param _dstAccount the address to transfer to(must be a clean address with no stakes)\n * @param r r portion of the signature by the transfer agent\n * @param s s portion of the signature\n * @param v v portion of the signature\n */\n function transferStakes(\n address _frmAccount,\n address _dstAccount,\n bytes32 r,\n bytes32 s,\n uint8 v\n ) external {\n require(transferAgent == msg.sender, \"must be transfer agent\");\n Stake[] storage dstStakes = userStakes[_dstAccount];\n require(dstStakes.length == 0, \"Dest stakes must be empty\");\n require(_frmAccount != address(0), \"from account not set\");\n Stake[] storage stakes = userStakes[_frmAccount];\n require(stakes.length > 0, \"Nothing to transfer\");\n\n // matches ethers.signMsg(ethers.utils.solidityPack([string(4), address, adddress, address]))\n bytes32 hash = keccak256(\n abi.encodePacked(\n \"\\x19Ethereum Signed Message:\\n64\",\n abi.encodePacked(\n \"tran\",\n address(this),\n _frmAccount,\n _dstAccount\n )\n )\n );\n require(ecrecover(hash, v, r, s) == _frmAccount, \"Transfer not authed\");\n\n // copy the stakes into the dstAccount array and delete the old one\n userStakes[_dstAccount] = stakes;\n delete userStakes[_frmAccount];\n emit StakesTransfered(_frmAccount, _dstAccount, stakes.length);\n }\n\n /* ========== MODIFIERS ========== */\n\n function setPaused(bool _paused) external onlyGovernor {\n paused = _paused;\n emit Paused(msg.sender, paused);\n }\n\n /**\n * @dev Set new durations and rates will not effect existing stakes\n * @param _durations Array of durations in seconds\n * @param _rates Array of rates that corresponds to the durations (0.01 is 1%) in 1e18\n */\n function setDurationRates(\n uint256[] calldata _durations,\n uint256[] calldata _rates\n ) external onlyGovernor {\n _setDurationRates(_durations, _rates);\n }\n\n /**\n * @dev Set the agent that will authorize transfers\n * @param _agent Address of agent\n */\n function setTransferAgent(address _agent) external onlyGovernor {\n transferAgent = _agent;\n }\n\n /**\n * @dev Set air drop root for a specific stake type\n * @param _stakeType Type of staking must be greater than 0\n * @param _rootHash Root hash of the Merkle Tree\n * @param _proofDepth Depth of the Merklke Tree\n */\n function setAirDropRoot(\n uint8 _stakeType,\n bytes32 _rootHash,\n uint256 _proofDepth\n ) external onlyGovernor {\n require(_stakeType != USER_STAKE_TYPE, \"Cannot be normal staking\");\n dropRoots[_stakeType].hash = _rootHash;\n dropRoots[_stakeType].depth = _proofDepth;\n emit NewAirDropRootHash(_stakeType, _rootHash, _proofDepth);\n }\n\n /* ========== EVENTS ========== */\n\n event Staked(\n address indexed user,\n uint256 amount,\n uint256 duration,\n uint256 rate\n );\n event Withdrawn(address indexed user, uint256 amount, uint256 stakedAmount);\n event Paused(address indexed user, bool yes);\n event NewDurations(address indexed user, uint256[] durations);\n event NewRates(address indexed user, uint256[] rates);\n event NewAirDropRootHash(\n uint8 stakeType,\n bytes32 rootHash,\n uint256 proofDepth\n );\n event StakesTransfered(\n address indexed fromUser,\n address toUser,\n uint256 numStakes\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/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\nimport { Governable } from \"../../governance/Governable.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 is Governable {\n /// @notice The address of the Native Staking Strategy\n address public immutable STRATEGY;\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 }\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_ADDRESS;\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 _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 address _feeAccumulator,\n address _beaconChainDepositContract\n )\n InitializableAbstractStrategy(_baseConfig)\n ValidatorAccountant(\n _wethAddress,\n _baseConfig.vaultAddress,\n _beaconChainDepositContract,\n _ssvNetwork\n )\n {\n SSV_TOKEN_ADDRESS = _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 /// @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_TOKEN_ADDRESS).deposit{ value: ethRewards }();\n\n emit RewardTokenCollected(\n harvesterAddress,\n WETH_TOKEN_ADDRESS,\n ethRewards\n );\n IERC20(WETH_TOKEN_ADDRESS).safeTransfer(\n harvesterAddress,\n ethRewards\n );\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_TOKEN_ADDRESS, \"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_TOKEN_ADDRESS).balanceOf(\n address(this)\n );\n uint256 newWeth = wethBalance - depositedWethAccountedFor;\n\n if (newWeth > 0) {\n depositedWethAccountedFor = wethBalance;\n\n _deposit(WETH_TOKEN_ADDRESS, newWeth);\n }\n }\n\n /// @notice Withdraw WETH from this contract. Used only if some WETH for is lingering on the contract. That\n /// can happen when:\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 _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 emit Withdrawal(_asset, address(0), _amount);\n IERC20(_asset).safeTransfer(_recipient, _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_TOKEN_ADDRESS).balanceOf(\n address(this)\n );\n if (wethBalance > 0) {\n _withdraw(vaultAddress, WETH_TOKEN_ADDRESS, wethBalance);\n }\n }\n\n function _abstractSetPToken(address _asset, address) internal override {}\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_TOKEN_ADDRESS, \"Unsupported asset\");\n\n balance =\n // add the ETH that has been staked in validators\n activeDepositedValidators *\n 32 ether +\n // add the WETH in the strategy from deposits that are still to be staked\n IERC20(WETH_TOKEN_ADDRESS).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_TOKEN_ADDRESS;\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_ADDRESS).approve(\n SSV_NETWORK_ADDRESS,\n type(uint256).max\n );\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 ||\n msg.sender == WETH_TOKEN_ADDRESS,\n \"eth not from allowed contracts\"\n );\n }\n\n function _wethWithdrawnToVault(uint256 _amount) internal override {\n emit Withdrawal(WETH_TOKEN_ADDRESS, address(0), _amount);\n }\n\n function _wethWithdrawnAndStaked(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 direclty\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 /// @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 MAX_STAKE = 32 ether;\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 constructor(\n address _wethAddress,\n address _vaultAddress,\n address _beaconChainDepositContract,\n address _ssvNetwork\n )\n ValidatorRegistrator(\n _wethAddress,\n _vaultAddress,\n _beaconChainDepositContract,\n _ssvNetwork\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 _fuseIntervalStart < 32 ether &&\n _fuseIntervalEnd < 32 ether &&\n _fuseIntervalEnd - _fuseIntervalStart >= 4 ether,\n \"incorrect fuse interval\"\n );\n\n emit FuseIntervalUpdated(_fuseIntervalStart, _fuseIntervalEnd);\n\n fuseIntervalStart = _fuseIntervalStart;\n fuseIntervalEnd = _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 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 >= MAX_STAKE) {\n uint256 fullyWithdrawnValidators;\n // safe since MAX_STAKE is hardcoded to 32ETH\n unchecked {\n // explicitly cast to uint256 as we want to round to a whole number of validators\n fullyWithdrawnValidators = uint256(newSweptETH / MAX_STAKE);\n }\n activeDepositedValidators -= fullyWithdrawnValidators;\n\n uint256 wethToVault = MAX_STAKE * fullyWithdrawnValidators;\n IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: wethToVault }();\n // slither-disable-next-line unchecked-transfer\n IWETH9(WETH_TOKEN_ADDRESS).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 < 32 ether, \"unexpected accounting\");\n\n // If no Beacon chain consensus rewards swept\n if (ethRemaining == 0) {\n // do nothing\n return accountingValid;\n }\n // Beacon chain consensus rewards swept (partial validator withdrawals)\n else if (ethRemaining < fuseIntervalStart) {\n // solhint-disable-next-line reentrancy\n consensusRewards += ethRemaining;\n emit AccountingConsensusRewards(ethRemaining);\n }\n // Beacon chain consensus rewards swept but also a slashed validator fully exited\n else if (ethRemaining > fuseIntervalEnd) {\n IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: ethRemaining }();\n // slither-disable-next-line unchecked-transfer\n IWETH9(WETH_TOKEN_ADDRESS).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 {\n require(\n lastFixAccountingBlockNumber + MIN_FIX_ACCOUNTING_CADENCE <\n block.number,\n \"manuallyFixAccounting 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 emit AccountingManuallyFixed(\n _validatorsDelta,\n _consensusRewardsDelta,\n _ethToVaultAmount\n );\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_TOKEN_ADDRESS).deposit{ value: _ethToVaultAmount }();\n // slither-disable-next-line unchecked-transfer\n IWETH9(WETH_TOKEN_ADDRESS).transfer(\n VAULT_ADDRESS,\n _ethToVaultAmount\n );\n _wethWithdrawnToVault(_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 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 address of the Wrapped ETH (WETH) token contract\n address public immutable WETH_TOKEN_ADDRESS;\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_ADDRESS;\n /// @notice Address of the OETH Vault proxy contract\n address public immutable VAULT_ADDRESS;\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\n // For future use\n uint256[50] private __gap;\n\n enum VALIDATOR_STATE {\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 newAddress);\n event ETHStaked(bytes pubkey, uint256 amount, bytes withdrawal_credentials);\n event SSVValidatorRegistered(bytes pubkey, uint64[] operatorIds);\n event SSVValidatorExitInitiated(bytes pubkey, uint64[] operatorIds);\n event SSVValidatorExitCompleted(bytes pubkey, uint64[] operatorIds);\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 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 constructor(\n address _wethAddress,\n address _vaultAddress,\n address _beaconChainDepositContract,\n address _ssvNetwork\n ) {\n WETH_TOKEN_ADDRESS = _wethAddress;\n BEACON_CHAIN_DEPOSIT_CONTRACT = _beaconChainDepositContract;\n SSV_NETWORK_ADDRESS = _ssvNetwork;\n VAULT_ADDRESS = _vaultAddress;\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 emit RegistratorChanged(_address);\n validatorRegistrator = _address;\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 {\n uint256 requiredETH = validators.length * 32 ether;\n\n // Check there is enough WETH from the deposits sitting in this strategy contract\n require(\n requiredETH <= IWETH9(WETH_TOKEN_ADDRESS).balanceOf(address(this)),\n \"insufficient WETH\"\n );\n\n // Convert required ETH from WETH\n IWETH9(WETH_TOKEN_ADDRESS).withdraw(requiredETH);\n _wethWithdrawnAndStaked(requiredETH);\n\n uint256 validatorsLength = validators.length;\n // For each validator\n for (uint256 i = 0; i < validatorsLength; ) {\n bytes32 pubkeyHash = keccak256(validators[i].pubkey);\n VALIDATOR_STATE currentState = validatorsStates[pubkeyHash];\n\n require(\n currentState == VALIDATOR_STATE.REGISTERED,\n \"Validator not registered\"\n );\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 withdrawal_credentials = abi.encodePacked(\n bytes1(0x01),\n bytes11(0),\n address(this)\n );\n IDepositContract(BEACON_CHAIN_DEPOSIT_CONTRACT).deposit{\n value: 32 ether\n }(\n validators[i].pubkey,\n withdrawal_credentials,\n validators[i].signature,\n validators[i].depositDataRoot\n );\n\n emit ETHStaked(\n validators[i].pubkey,\n 32 ether,\n withdrawal_credentials\n );\n\n validatorsStates[pubkeyHash] = VALIDATOR_STATE.STAKED;\n\n unchecked {\n ++i;\n }\n }\n // save gas by changing this storage variable only once rather each time in the loop.\n activeDepositedValidators += validatorsLength;\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 function registerSsvValidator(\n bytes calldata publicKey,\n uint64[] calldata operatorIds,\n bytes calldata sharesData,\n uint256 amount,\n Cluster calldata cluster\n ) external onlyRegistrator whenNotPaused {\n ISSVNetwork(SSV_NETWORK_ADDRESS).registerValidator(\n publicKey,\n operatorIds,\n sharesData,\n amount,\n cluster\n );\n validatorsStates[keccak256(publicKey)] = VALIDATOR_STATE.REGISTERED;\n emit SSVValidatorRegistered(publicKey, operatorIds);\n }\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 // slither-disable-start reentrancy-no-eth\n function exitSsvValidator(\n bytes calldata publicKey,\n uint64[] calldata operatorIds\n ) external onlyRegistrator whenNotPaused {\n VALIDATOR_STATE currentState = validatorsStates[keccak256(publicKey)];\n require(currentState == VALIDATOR_STATE.STAKED, \"Validator not staked\");\n\n ISSVNetwork(SSV_NETWORK_ADDRESS).exitValidator(publicKey, operatorIds);\n emit SSVValidatorExitInitiated(publicKey, operatorIds);\n\n validatorsStates[keccak256(publicKey)] = VALIDATOR_STATE.EXITING;\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 // 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 VALIDATOR_STATE currentState = validatorsStates[keccak256(publicKey)];\n require(\n currentState == VALIDATOR_STATE.EXITING,\n \"Validator not exiting\"\n );\n\n ISSVNetwork(SSV_NETWORK_ADDRESS).removeValidator(\n publicKey,\n operatorIds,\n cluster\n );\n emit SSVValidatorExitCompleted(publicKey, operatorIds);\n\n validatorsStates[keccak256(publicKey)] = VALIDATOR_STATE.EXIT_COMPLETE;\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 cluster The SSV cluster details that must be derived from emitted events from the SSVNetwork contract.\n function depositSSV(\n uint64[] memory operatorIds,\n uint256 amount,\n Cluster memory cluster\n ) external onlyStrategist {\n ISSVNetwork(SSV_NETWORK_ADDRESS).deposit(\n address(this),\n operatorIds,\n amount,\n cluster\n );\n }\n\n /***************************************\n Abstract\n ****************************************/\n\n /// @dev allows for NativeStakingSSVStrategy contract know how much WETH had been staked\n function _wethWithdrawnAndStaked(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/swapper/Swapper1InchV5.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @notice 1Inch Pathfinder V5 implementation of the general ISwapper interface.\n * @author Origin Protocol Inc\n * @dev It is possible that dust token amounts are left in this contract after a swap.\n * This can happen with some tokens that don't send the full transfer amount.\n * These dust amounts can build up over time and be used by anyone who calls the `swap` function.\n */\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nimport { IAggregationExecutor, IOneInchRouter, SwapDescription } from \"../interfaces/IOneInch.sol\";\nimport { ISwapper } from \"../interfaces/ISwapper.sol\";\n\ncontract Swapper1InchV5 is ISwapper {\n using SafeERC20 for IERC20;\n\n /// @notice 1Inch router contract to give allowance to perform swaps\n address public constant SWAP_ROUTER =\n 0x1111111254EEB25477B68fb85Ed929f73A960582;\n\n // swap(address,(address,address,address,address,uint256,uint256,uint256),bytes,bytes)\n bytes4 internal constant SWAP_SELECTOR = 0x12aa3caf;\n // unoswapTo(address,address,uint256,uint256,uint256[])\n bytes4 internal constant UNISWAP_SELECTOR = 0xf78dc253;\n // uniswapV3SwapTo(address,uint256,uint256,uint256[])\n bytes4 internal constant UNISWAPV3_SELECTOR = 0xbc80f1a8;\n\n /**\n * @notice Strategist swaps assets sitting in the contract of the `assetHolder`.\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 RLP encoded executer address and bytes data. This is re-encoded tx.data from 1Inch swap API\n */\n function swap(\n address _fromAsset,\n address _toAsset,\n uint256 _fromAssetAmount,\n uint256 _minToAssetAmount,\n bytes calldata _data\n ) external override returns (uint256 toAssetAmount) {\n // Decode the function selector from the RLP encoded _data param\n bytes4 swapSelector = bytes4(_data[:4]);\n\n if (swapSelector == SWAP_SELECTOR) {\n // Decode the executer address and data from the RLP encoded _data param\n (, address executer, bytes memory executerData) = abi.decode(\n _data,\n (bytes4, address, bytes)\n );\n SwapDescription memory swapDesc = SwapDescription({\n srcToken: IERC20(_fromAsset),\n dstToken: IERC20(_toAsset),\n srcReceiver: payable(executer),\n dstReceiver: payable(msg.sender),\n amount: _fromAssetAmount,\n minReturnAmount: _minToAssetAmount,\n flags: 4 // 1st bit _PARTIAL_FILL, 2nd bit _REQUIRES_EXTRA_ETH, 3rd bit _SHOULD_CLAIM\n });\n (toAssetAmount, ) = IOneInchRouter(SWAP_ROUTER).swap(\n IAggregationExecutor(executer),\n swapDesc,\n hex\"\",\n executerData\n );\n } else if (swapSelector == UNISWAP_SELECTOR) {\n // Need to get the Uniswap pools data from the _data param\n (, uint256[] memory pools) = abi.decode(_data, (bytes4, uint256[]));\n toAssetAmount = IOneInchRouter(SWAP_ROUTER).unoswapTo(\n payable(msg.sender),\n IERC20(_fromAsset),\n _fromAssetAmount,\n _minToAssetAmount,\n pools\n );\n } else if (swapSelector == UNISWAPV3_SELECTOR) {\n // Need to get the Uniswap pools data from the _data param\n // slither-disable-next-line uninitialized-storage\n (, uint256[] memory pools) = abi.decode(_data, (bytes4, uint256[]));\n toAssetAmount = IOneInchRouter(SWAP_ROUTER).uniswapV3SwapTo(\n payable(msg.sender),\n _fromAssetAmount,\n _minToAssetAmount,\n pools\n );\n } else {\n revert(\"Unsupported swap function\");\n }\n }\n\n /**\n * @notice Approve assets for swapping.\n * @param _assets Array of token addresses to approve.\n * @dev unlimited approval is used as no tokens sit in this contract outside a transaction.\n */\n function approveAssets(address[] memory _assets) external {\n for (uint256 i = 0; i < _assets.length; ++i) {\n // Give the 1Inch router approval to transfer unlimited assets\n IERC20(_assets[i]).safeApprove(SWAP_ROUTER, type(uint256).max);\n }\n }\n}\n" + }, + "contracts/timelock/Timelock.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @title OUSD Timelock Contract\n * @author Origin Protocol Inc\n */\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\n\ninterface CapitalPausable {\n function pauseCapital() external;\n\n function unpauseCapital() external;\n}\n\ncontract Timelock {\n using SafeMath for uint256;\n\n event NewAdmin(address indexed newAdmin);\n event NewPendingAdmin(address indexed newPendingAdmin);\n event NewDelay(uint256 indexed newDelay);\n event CancelTransaction(\n bytes32 indexed txHash,\n address indexed target,\n string signature,\n bytes data,\n uint256 eta\n );\n event ExecuteTransaction(\n bytes32 indexed txHash,\n address indexed target,\n string signature,\n bytes data,\n uint256 eta\n );\n event QueueTransaction(\n bytes32 indexed txHash,\n address indexed target,\n string signature,\n bytes data,\n uint256 eta\n );\n\n uint256 public constant GRACE_PERIOD = 3 days;\n uint256 public constant MINIMUM_DELAY = 1 minutes;\n uint256 public constant MAXIMUM_DELAY = 2 days;\n\n address public admin;\n address public pendingAdmin;\n uint256 public delay;\n\n mapping(bytes32 => bool) public queuedTransactions;\n\n /**\n * @dev Throws if called by any account other than the Admin.\n */\n modifier onlyAdmin() {\n require(msg.sender == admin, \"Caller is not the admin\");\n _;\n }\n\n constructor(address admin_, uint256 delay_) {\n require(\n delay_ >= MINIMUM_DELAY,\n \"Timelock::constructor: Delay must exceed minimum delay.\"\n );\n require(\n delay_ <= MAXIMUM_DELAY,\n \"Timelock::setDelay: Delay must not exceed maximum delay.\"\n );\n\n admin = admin_;\n delay = delay_;\n }\n\n function setDelay(uint256 delay_) public {\n require(\n msg.sender == address(this),\n \"Timelock::setDelay: Call must come from Timelock.\"\n );\n require(\n delay_ >= MINIMUM_DELAY,\n \"Timelock::setDelay: Delay must exceed minimum delay.\"\n );\n require(\n delay_ <= MAXIMUM_DELAY,\n \"Timelock::setDelay: Delay must not exceed maximum delay.\"\n );\n delay = delay_;\n\n emit NewDelay(delay);\n }\n\n function acceptAdmin() public {\n require(\n msg.sender == pendingAdmin,\n \"Timelock::acceptAdmin: Call must come from pendingAdmin.\"\n );\n admin = msg.sender;\n pendingAdmin = address(0);\n\n emit NewAdmin(admin);\n }\n\n function setPendingAdmin(address pendingAdmin_) public onlyAdmin {\n pendingAdmin = pendingAdmin_;\n\n emit NewPendingAdmin(pendingAdmin);\n }\n\n function queueTransaction(\n address target,\n string memory signature,\n bytes memory data,\n uint256 eta\n ) internal returns (bytes32) {\n require(\n msg.sender == admin,\n \"Timelock::queueTransaction: Call must come from admin.\"\n );\n require(\n eta >= getBlockTimestamp().add(delay),\n \"Timelock::queueTransaction: Estimated execution block must satisfy delay.\"\n );\n\n bytes32 txHash = keccak256(\n abi.encode(target, signature, keccak256(data), eta)\n );\n queuedTransactions[txHash] = true;\n\n emit QueueTransaction(txHash, target, signature, data, eta);\n return txHash;\n }\n\n function cancelTransaction(\n address target,\n string memory signature,\n bytes memory data,\n uint256 eta\n ) internal {\n require(\n msg.sender == admin,\n \"Timelock::cancelTransaction: Call must come from admin.\"\n );\n\n bytes32 txHash = keccak256(\n abi.encode(target, signature, keccak256(data), eta)\n );\n queuedTransactions[txHash] = false;\n\n emit CancelTransaction(txHash, target, signature, data, eta);\n }\n\n function _getRevertMsg(bytes memory _returnData)\n internal\n pure\n returns (string memory)\n {\n // If the _res length is less than 68, then the transaction failed\n // silently (without a revert message)\n if (_returnData.length < 68) return \"Transaction reverted silently\";\n\n // solhint-disable-next-line no-inline-assembly\n assembly {\n // Slice the sighash.\n _returnData := add(_returnData, 0x04)\n }\n return abi.decode(_returnData, (string));\n }\n\n function executeTransaction(\n address target,\n string memory signature,\n bytes memory data,\n uint256 eta\n ) internal returns (bytes memory) {\n require(\n msg.sender == admin,\n \"Timelock::executeTransaction: Call must come from admin.\"\n );\n\n bytes32 txHash = keccak256(\n abi.encode(target, signature, keccak256(data), eta)\n );\n require(\n queuedTransactions[txHash],\n \"Timelock::executeTransaction: Transaction hasn't been queued.\"\n );\n require(\n getBlockTimestamp() >= eta,\n \"Timelock::executeTransaction: Transaction hasn't surpassed time lock.\"\n );\n require(\n getBlockTimestamp() <= eta.add(GRACE_PERIOD),\n \"Timelock::executeTransaction: Transaction is stale.\"\n );\n\n queuedTransactions[txHash] = false;\n\n bytes memory callData;\n\n if (bytes(signature).length == 0) {\n callData = data;\n } else {\n callData = abi.encodePacked(\n bytes4(keccak256(bytes(signature))),\n data\n );\n }\n\n (bool success, bytes memory returnData) = target.call(callData);\n\n if (!success) {\n revert(_getRevertMsg(returnData));\n }\n\n emit ExecuteTransaction(txHash, target, signature, data, eta);\n\n return returnData;\n }\n\n function getBlockTimestamp() internal view returns (uint256) {\n // solium-disable-next-line security/no-block-members\n return block.timestamp;\n }\n\n function pauseCapital(address target) external {\n require(\n msg.sender == admin,\n \"Timelock::pauseCapital: Call must come from admin.\"\n );\n CapitalPausable(target).pauseCapital();\n }\n\n function unpauseCapital(address target) external {\n require(\n msg.sender == admin,\n \"Timelock::unpauseCapital: Call must come from admin.\"\n );\n CapitalPausable(target).unpauseCapital();\n }\n}\n" + }, + "contracts/token/BridgedWOETH.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { ERC20 } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport { AccessControlEnumerable } from \"@openzeppelin/contracts/access/AccessControlEnumerable.sol\";\nimport { Governable } from \"../governance/Governable.sol\";\nimport { Initializable } from \"../utils/Initializable.sol\";\n\ncontract BridgedWOETH is\n Governable,\n AccessControlEnumerable,\n Initializable,\n ERC20\n{\n bytes32 public constant MINTER_ROLE = keccak256(\"MINTER_ROLE\");\n bytes32 public constant BURNER_ROLE = keccak256(\"BURNER_ROLE\");\n\n constructor() ERC20(\"Wrapped OETH\", \"WOETH\") {\n // Nobody owns the implementation\n _setGovernor(address(0));\n }\n\n /**\n * @dev Initialize the proxy and set the Governor\n */\n function initialize() external initializer {\n // Governor can grant Minter/Burner roles\n _setupRole(DEFAULT_ADMIN_ROLE, _governor());\n }\n\n /**\n * @dev Mint tokens for `account`\n * @param account Address to mint tokens for\n * @param amount Amount of tokens to mint\n */\n function mint(address account, uint256 amount)\n external\n onlyRole(MINTER_ROLE)\n nonReentrant\n {\n _mint(account, amount);\n }\n\n /**\n * @dev Burns tokens from `account`\n * @param account Address to burn tokens from\n * @param amount Amount of tokens to burn\n */\n function burn(address account, uint256 amount)\n external\n onlyRole(BURNER_ROLE)\n nonReentrant\n {\n _burn(account, amount);\n }\n\n /**\n * @dev Burns tokens from `msg.sender`\n * @param amount Amount of tokens to burn\n */\n function burn(uint256 amount) external onlyRole(BURNER_ROLE) nonReentrant {\n _burn(msg.sender, amount);\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual override returns (string memory) {\n return \"Wrapped OETH\";\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 \"WOETH\";\n }\n\n /**\n * @dev Returns the decimals of the token\n */\n function decimals() public view virtual override returns (uint8) {\n return 18;\n }\n}\n" + }, + "contracts/token/OETH.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { OUSD } from \"./OUSD.sol\";\n\n/**\n * @title OETH Token Contract\n * @author Origin Protocol Inc\n */\ncontract OETH is 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/token/OUSDResolutionUpgrade.sol": { + "content": "pragma solidity ^0.8.0;\n\ncontract OUSDResolutionUpgrade {\n enum RebaseOptions {\n NotSet,\n OptOut,\n OptIn\n }\n\n // From Initializable\n bool private initialized;\n bool private initializing;\n uint256[50] private ______igap;\n\n // From InitializableERC20Detailed\n uint256[100] private _____ugap;\n string private _name;\n string private _symbol;\n uint8 private _decimals;\n\n // From OUSD\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 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 /**\n * @return High resolution rebasingCreditsPerToken\n */\n function rebasingCreditsPerToken() public view returns (uint256) {\n return _rebasingCreditsPerToken / RESOLUTION_INCREASE;\n }\n\n /**\n * @return High 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 function upgradeGlobals() external {\n require(isUpgraded[address(0)] == 0, \"Globals already upgraded\");\n require(_rebasingCredits > 0, \"Sanity _rebasingCredits\");\n require(\n _rebasingCreditsPerToken > 0,\n \"Sanity _rebasingCreditsPerToken\"\n );\n isUpgraded[address(0)] = 1;\n _rebasingCredits = _rebasingCredits * RESOLUTION_INCREASE;\n _rebasingCreditsPerToken =\n _rebasingCreditsPerToken *\n RESOLUTION_INCREASE;\n }\n\n function upgradeAccounts(address[] calldata accounts) external {\n for (uint256 i = 0; i < accounts.length; i++) {\n address account = accounts[i];\n require(account != address(0), \"Reserved\");\n require(isUpgraded[account] == 0, \"Account already upgraded\");\n isUpgraded[account] = 1;\n\n // Handle special for non-rebasing accounts\n uint256 nrc = nonRebasingCreditsPerToken[account];\n if (nrc > 0) {\n require(nrc < 1e18, \"Account already highres\");\n nonRebasingCreditsPerToken[account] = nrc * RESOLUTION_INCREASE;\n }\n // Upgrade balance\n uint256 balance = _creditBalances[account];\n require(balance > 0, \"Will not upgrade zero balance\");\n _creditBalances[account] = balance * RESOLUTION_INCREASE;\n }\n }\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 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" + }, + "contracts/token/WOETH.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { ERC4626 } from \"../../lib/openzeppelin/contracts/token/ERC20/extensions/ERC4626.sol\";\nimport { ERC20 } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nimport { Governable } from \"../governance/Governable.sol\";\nimport { Initializable } from \"../utils/Initializable.sol\";\nimport { OETH } from \"./OETH.sol\";\n\n/**\n * @title OETH Token Contract\n * @author Origin Protocol Inc\n */\n\ncontract WOETH is ERC4626, Governable, Initializable {\n using SafeERC20 for IERC20;\n\n constructor(\n ERC20 underlying_,\n string memory name_,\n string memory symbol_\n ) ERC20(name_, symbol_) ERC4626(underlying_) Governable() {}\n\n /**\n * @notice Enable OETH rebasing for this contract\n */\n function initialize() external onlyGovernor initializer {\n OETH(address(asset())).rebaseOptIn();\n }\n\n function name() public view override returns (string memory) {\n return \"Wrapped OETH\";\n }\n\n function symbol() public view override returns (string memory) {\n return \"WOETH\";\n }\n\n /**\n * @notice Transfer token to governor. Intended for recovering tokens stuck in\n * contract, i.e. mistaken sends. Cannot transfer OETH\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(asset_ != address(asset()), \"Cannot collect OETH\");\n IERC20(asset_).safeTransfer(governor(), amount_);\n }\n}\n" + }, + "contracts/token/WrappedOusd.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { ERC4626 } from \"../../lib/openzeppelin/contracts/token/ERC20/extensions/ERC4626.sol\";\nimport { ERC20 } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nimport { Governable } from \"../governance/Governable.sol\";\nimport { Initializable } from \"../utils/Initializable.sol\";\nimport { OUSD } from \"./OUSD.sol\";\n\ncontract WrappedOusd is ERC4626, Governable, Initializable {\n using SafeERC20 for IERC20;\n\n constructor(\n ERC20 underlying_,\n string memory name_,\n string memory symbol_\n ) ERC20(name_, symbol_) ERC4626(underlying_) Governable() {}\n\n /**\n * @notice Enable OUSD rebasing for this contract\n */\n function initialize() external onlyGovernor initializer {\n OUSD(address(asset())).rebaseOptIn();\n }\n\n function name() public view override returns (string memory) {\n return \"Wrapped OUSD\";\n }\n\n function symbol() public view override returns (string memory) {\n return \"WOUSD\";\n }\n\n /**\n * @notice Transfer token to governor. Intended for recovering tokens stuck in\n * contract, i.e. mistaken sends. Cannot transfer OUSD\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(asset_ != address(asset()), \"Cannot collect OUSD\");\n IERC20(asset_).safeTransfer(governor(), amount_);\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/DepositContractUtils.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ncontract DepositContractUtils {\n \n function calculateDepositDataRoot(\n bytes calldata pubkey,\n bytes calldata withdrawal_credentials,\n bytes calldata signature\n ) public pure returns(bytes32 node){\n uint deposit_amount = 32 ether / 1 gwei;\n bytes memory amount = to_little_endian_64(uint64(deposit_amount));\n\n // Compute deposit data root (`DepositData` hash tree root)\n bytes32 pubkey_root = sha256(abi.encodePacked(pubkey, bytes16(0)));\n bytes32 signature_root = sha256(abi.encodePacked(\n sha256(abi.encodePacked(signature[:64])),\n sha256(abi.encodePacked(signature[64:], bytes32(0)))\n ));\n node = sha256(abi.encodePacked(\n sha256(abi.encodePacked(pubkey_root, withdrawal_credentials)),\n sha256(abi.encodePacked(amount, bytes24(0), signature_root))\n ));\n }\n\n function to_little_endian_64(uint64 value) internal pure returns (bytes memory ret) {\n ret = new bytes(8);\n bytes8 bytesValue = bytes8(value);\n // Byteswapping during copying to bytes.\n ret[0] = bytesValue[7];\n ret[1] = bytesValue[6];\n ret[2] = bytesValue[5];\n ret[3] = bytesValue[4];\n ret[4] = bytesValue[3];\n ret[5] = bytesValue[2];\n ret[6] = bytesValue[1];\n ret[7] = bytesValue[0];\n }\n \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 { VaultAdmin } from \"./VaultAdmin.sol\";\n\n/**\n * @title OETH VaultAdmin Contract\n * @author Origin Protocol Inc\n */\ncontract OETHVaultAdmin is VaultAdmin {\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\";\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" + }, + "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 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 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 {\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" + }, + "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" + }, + "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\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" + }, + "contracts/zapper/WOETHCCIPZapper.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { IRouterClient } from \"@chainlink/contracts-ccip/src/v0.8/ccip/interfaces/IRouterClient.sol\";\nimport { Client } from \"@chainlink/contracts-ccip/src/v0.8/ccip/libraries/Client.sol\";\n// solhint-disable-next-line max-line-length\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { IERC4626 } from \"./../../lib/openzeppelin/interfaces/IERC4626.sol\";\nimport { IOETHZapper } from \"./../interfaces/IOETHZapper.sol\";\n\n/**\n * @title WOETH CCIP Zapper Contract\n * @notice Helps to directly convert ETH on mainnet into WOETH on L2s.\n * @author Origin Protocol Inc\n */\n\ncontract WOETHCCIPZapper {\n /**\n * @dev Event emitted when a zap occurs\n * @param messageId Unique message identifier for each zap\n * @param sender Address initiating the zap\n * @param recipient Recipient address at destination chain\n * @param amount Amount of ETH zapped\n */\n event Zap(\n bytes32 indexed messageId,\n address sender,\n address recipient,\n uint256 amount\n );\n\n // @dev Thrown when Zap amount is less than fee.\n error AmountLessThanFee();\n\n /**\n * @dev The destination chain selector\n */\n uint64 public immutable destinationChainSelector;\n\n /**\n * @dev The WOETH source chain (Mainnet)\n */\n IERC4626 public immutable woethOnSourceChain;\n\n /**\n * @dev The WOETH destination chain (Arbitrum)\n */\n IERC20 public immutable woethOnDestinationChain;\n\n /**\n * @dev The OETH zapper contract address\n */\n IOETHZapper public immutable oethZapper;\n\n /**\n * @dev The CCIP router contract address\n */\n IRouterClient public immutable ccipRouter;\n\n /**\n * @dev The OETH token contract address\n */\n IERC20 public immutable oeth;\n\n constructor(\n address _ccipRouter,\n uint64 _destinationChainSelector,\n IERC4626 _woethOnSourceChain,\n IERC20 _woethOnDestinationChain,\n IOETHZapper _oethZapper,\n IERC20 _oeth\n ) {\n ccipRouter = IRouterClient(_ccipRouter);\n destinationChainSelector = _destinationChainSelector;\n woethOnSourceChain = _woethOnSourceChain;\n woethOnDestinationChain = _woethOnDestinationChain;\n oethZapper = _oethZapper;\n oeth = _oeth;\n\n // Max allowance for Router and WOETH contracts\n _oeth.approve(address(_woethOnSourceChain), type(uint256).max); // for wrapping\n _woethOnSourceChain.approve(address(_ccipRouter), type(uint256).max); // for zapping\n }\n\n /**\n * @notice Accepts ETH, zaps for OETH, wraps it for WOETH and sends it to the destination chain (arbitrum)\n * @param receiver The address of the EOA on the destination chain\n * @return messageId The ID of the message that was sent\n */\n function zap(address receiver)\n external\n payable\n returns (bytes32 messageId)\n {\n return _zap(receiver, msg.value);\n }\n\n /**\n * @notice Used to estimate fee for CCIP transaction\n * @param amount The amount of ETH to be zapped\n * @param receiver The address of the EOA on the destination chain\n * @return feeAmount The CCIP tx fee in ETH.\n */\n\n function getFee(uint256 amount, address receiver)\n public\n view\n returns (uint256 feeAmount)\n {\n Client.EVMTokenAmount[]\n memory tokenAmounts = new Client.EVMTokenAmount[](1);\n Client.EVMTokenAmount memory tokenAmount = Client.EVMTokenAmount({\n token: address(woethOnSourceChain),\n amount: amount\n });\n tokenAmounts[0] = tokenAmount;\n\n Client.EVM2AnyMessage memory message = Client.EVM2AnyMessage({\n receiver: abi.encode(receiver), // ABI-encoded receiver address\n data: abi.encode(\"\"),\n tokenAmounts: tokenAmounts,\n extraArgs: Client._argsToBytes(\n Client.EVMExtraArgsV1({ gasLimit: 0 })\n ),\n feeToken: address(0)\n });\n\n feeAmount = ccipRouter.getFee(destinationChainSelector, message);\n }\n\n /**\n * @dev Deposit ETH and receive WOETH in L2.\n * @dev Note that the WOETH will be sent to the msg.sender at destination chain as well.\n */\n receive() external payable {\n _zap(msg.sender, msg.value);\n }\n\n function _zap(address receiver, uint256 amount)\n internal\n returns (bytes32 messageId)\n {\n // Estimate fee for zapping.\n uint256 feeAmount = getFee(amount, receiver);\n if (amount < feeAmount) {\n revert AmountLessThanFee();\n }\n\n // Convert only the msg.value - fees amount to WOETH.\n amount -= feeAmount;\n\n // 1.) Zap for OETH\n uint256 oethReceived = oethZapper.deposit{ value: amount }();\n\n // 2.) Wrap the received woeth\n uint256 woethReceived = woethOnSourceChain.deposit(\n oethReceived,\n address(this)\n );\n\n // 3.) Setup params for CCIP transfer\n\n Client.EVMTokenAmount[]\n memory tokenAmounts = new Client.EVMTokenAmount[](1);\n Client.EVMTokenAmount memory tokenAmount = Client.EVMTokenAmount({\n token: address(woethOnSourceChain),\n amount: woethReceived\n });\n tokenAmounts[0] = tokenAmount;\n\n Client.EVM2AnyMessage memory message = Client.EVM2AnyMessage({\n receiver: abi.encode(receiver), // ABI-encoded receiver address\n data: abi.encode(\"\"),\n tokenAmounts: tokenAmounts,\n extraArgs: Client._argsToBytes(\n // See: https://docs.chain.link/ccip/best-practices#setting-gaslimit\n Client.EVMExtraArgsV1({ gasLimit: 0 })\n ),\n feeToken: address(0)\n });\n\n // ZAP ϟ\n //slither-disable-next-line arbitrary-send-eth\n messageId = ccipRouter.ccipSend{ value: feeAmount }(\n destinationChainSelector,\n message\n );\n\n // Emit Zap event with message details\n emit Zap(messageId, msg.sender, receiver, amount);\n\n // Return the message ID\n return messageId;\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/contracts/token/ERC20/extensions/ERC4626.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\nimport { IERC4626 } from \"../../../../interfaces/IERC4626.sol\";\nimport { ERC20 } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { IERC20Metadata } from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\n\n// From Open Zeppelin draft PR commit:\n// fac43034dca85ff539db3fc8aa2a7084b843d454\n// https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3171\n\nabstract contract ERC4626 is ERC20, IERC4626 {\n IERC20Metadata private immutable _asset;\n\n constructor(IERC20Metadata __asset) {\n _asset = __asset;\n }\n\n /** @dev See {IERC4262-asset} */\n function asset() public view virtual override returns (address) {\n return address(_asset);\n }\n\n /** @dev See {IERC4262-totalAssets} */\n function totalAssets() public view virtual override returns (uint256) {\n return _asset.balanceOf(address(this));\n }\n\n /**\n * @dev See {IERC4262-convertToShares}\n *\n * Will revert if asserts > 0, totalSupply > 0 and totalAssets = 0. That corresponds to a case where any asset\n * would represent an infinite amout of shares.\n */\n function convertToShares(uint256 assets) public view virtual override returns (uint256 shares) {\n uint256 supply = totalSupply();\n\n return\n (assets == 0 || supply == 0)\n ? (assets * 10**decimals()) / 10**_asset.decimals()\n : (assets * supply) / totalAssets();\n }\n\n /** @dev See {IERC4262-convertToAssets} */\n function convertToAssets(uint256 shares) public view virtual override returns (uint256 assets) {\n uint256 supply = totalSupply();\n\n return (supply == 0) ? (shares * 10**_asset.decimals()) / 10**decimals() : (shares * totalAssets()) / supply;\n }\n\n /** @dev See {IERC4262-maxDeposit} */\n function maxDeposit(address) public view virtual override returns (uint256) {\n return type(uint256).max;\n }\n\n /** @dev See {IERC4262-maxMint} */\n function maxMint(address) public view virtual override returns (uint256) {\n return type(uint256).max;\n }\n\n /** @dev See {IERC4262-maxWithdraw} */\n function maxWithdraw(address owner) public view virtual override returns (uint256) {\n return convertToAssets(balanceOf(owner));\n }\n\n /** @dev See {IERC4262-maxRedeem} */\n function maxRedeem(address owner) public view virtual override returns (uint256) {\n return balanceOf(owner);\n }\n\n /** @dev See {IERC4262-previewDeposit} */\n function previewDeposit(uint256 assets) public view virtual override returns (uint256) {\n return convertToShares(assets);\n }\n\n /** @dev See {IERC4262-previewMint} */\n function previewMint(uint256 shares) public view virtual override returns (uint256) {\n uint256 assets = convertToAssets(shares);\n return assets + (convertToShares(assets) < shares ? 1 : 0);\n }\n\n /** @dev See {IERC4262-previewWithdraw} */\n function previewWithdraw(uint256 assets) public view virtual override returns (uint256) {\n uint256 shares = convertToShares(assets);\n return shares + (convertToAssets(shares) < assets ? 1 : 0);\n }\n\n /** @dev See {IERC4262-previewRedeem} */\n function previewRedeem(uint256 shares) public view virtual override returns (uint256) {\n return convertToAssets(shares);\n }\n\n /** @dev See {IERC4262-deposit} */\n function deposit(uint256 assets, address receiver) public virtual override returns (uint256) {\n require(assets <= maxDeposit(receiver), \"ERC4626: deposit more then max\");\n\n address caller = _msgSender();\n uint256 shares = previewDeposit(assets);\n\n // if _asset is ERC777, transferFrom can call reenter BEFORE the transfer happens through\n // the tokensToSend hook, so we need to transfer before we mint to keep the invariants.\n SafeERC20.safeTransferFrom(_asset, caller, address(this), assets);\n _mint(receiver, shares);\n\n emit Deposit(caller, receiver, assets, shares);\n\n return shares;\n }\n\n /** @dev See {IERC4262-mint} */\n function mint(uint256 shares, address receiver) public virtual override returns (uint256) {\n require(shares <= maxMint(receiver), \"ERC4626: mint more then max\");\n\n address caller = _msgSender();\n uint256 assets = previewMint(shares);\n\n // if _asset is ERC777, transferFrom can call reenter BEFORE the transfer happens through\n // the tokensToSend hook, so we need to transfer before we mint to keep the invariants.\n SafeERC20.safeTransferFrom(_asset, caller, address(this), assets);\n _mint(receiver, shares);\n\n emit Deposit(caller, receiver, assets, shares);\n\n return assets;\n }\n\n /** @dev See {IERC4262-withdraw} */\n function withdraw(\n uint256 assets,\n address receiver,\n address owner\n ) public virtual override returns (uint256) {\n require(assets <= maxWithdraw(owner), \"ERC4626: withdraw more then max\");\n\n address caller = _msgSender();\n uint256 shares = previewWithdraw(assets);\n\n if (caller != owner) {\n _spendAllowance(owner, caller, shares);\n }\n\n // if _asset is ERC777, transfer can call reenter AFTER the transfer happens through\n // the tokensReceived hook, so we need to transfer after we burn to keep the invariants.\n _burn(owner, shares);\n SafeERC20.safeTransfer(_asset, receiver, assets);\n\n emit Withdraw(caller, receiver, owner, assets, shares);\n\n return shares;\n }\n\n /** @dev See {IERC4262-redeem} */\n function redeem(\n uint256 shares,\n address receiver,\n address owner\n ) public virtual override returns (uint256) {\n require(shares <= maxRedeem(owner), \"ERC4626: redeem more then max\");\n\n address caller = _msgSender();\n uint256 assets = previewRedeem(shares);\n\n if (caller != owner) {\n _spendAllowance(owner, caller, shares);\n }\n\n // if _asset is ERC777, transfer can call reenter AFTER the transfer happens through\n // the tokensReceived hook, so we need to transfer after we burn to keep the invariants.\n _burn(owner, shares);\n SafeERC20.safeTransfer(_asset, receiver, assets);\n\n emit Withdraw(caller, receiver, owner, assets, shares);\n\n return assets;\n }\n\n // Included here, since this method was not yet present in\n // the version of Open Zeppelin ERC20 code we use.\n function _spendAllowance(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n uint256 currentAllowance = allowance(owner, spender);\n if (currentAllowance != type(uint256).max) {\n require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n unchecked {\n _approve(owner, spender, currentAllowance - amount);\n }\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/docs/NativeStakingSSVStrategySquashed.svg b/contracts/docs/NativeStakingSSVStrategySquashed.svg index ebfd5bec6c..86d64e08ec 100644 --- a/contracts/docs/NativeStakingSSVStrategySquashed.svg +++ b/contracts/docs/NativeStakingSSVStrategySquashed.svg @@ -4,73 +4,75 @@ - - + + UmlClassDiagram - + 284 - -NativeStakingSSVStrategy -../contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol - -Private: -   governorPosition: bytes32 <<Governable>> -   pendingGovernorPosition: bytes32 <<Governable>> -   reentryStatusPosition: bytes32 <<Governable>> -   _paused: bool <<Pausable>> -   __gap: uint256[50] <<ValidatorRegistrator>> -   __gap: uint256[49] <<ValidatorAccountant>> -   initialized: bool <<Initializable>> -   initializing: bool <<Initializable>> -   ______gap: uint256[50] <<Initializable>> -   _deprecated_platformAddress: address <<InitializableAbstractStrategy>> -   _deprecated_vaultAddress: address <<InitializableAbstractStrategy>> -   _deprecated_rewardTokenAddress: address <<InitializableAbstractStrategy>> -   _deprecated_rewardLiquidationThreshold: uint256 <<InitializableAbstractStrategy>> -   _reserved: int256[98] <<InitializableAbstractStrategy>> -   __gap: uint256[50] <<NativeStakingSSVStrategy>> -Internal: -   assetsMapped: address[] <<InitializableAbstractStrategy>> -Public: -   _NOT_ENTERED: uint256 <<Governable>> -   _ENTERED: uint256 <<Governable>> -   WETH_TOKEN_ADDRESS: address <<ValidatorRegistrator>> -   BEACON_CHAIN_DEPOSIT_CONTRACT: address <<ValidatorRegistrator>> -   SSV_NETWORK_ADDRESS: address <<ValidatorRegistrator>> -   VAULT_ADDRESS: address <<ValidatorRegistrator>> -   validatorRegistrator: address <<ValidatorRegistrator>> -   activeDepositedValidators: uint256 <<ValidatorRegistrator>> -   validatorsStates: mapping(bytes32=>VALIDATOR_STATE) <<ValidatorRegistrator>> -   MIN_FIX_ACCOUNTING_CADENCE: uint256 <<ValidatorAccountant>> -   MAX_STAKE: uint256 <<ValidatorAccountant>> -   consensusRewards: uint256 <<ValidatorAccountant>> -   fuseIntervalStart: uint256 <<ValidatorAccountant>> -   fuseIntervalEnd: uint256 <<ValidatorAccountant>> -   lastFixAccountingBlockNumber: uint256 <<ValidatorAccountant>> -   platformAddress: address <<InitializableAbstractStrategy>> -   vaultAddress: address <<InitializableAbstractStrategy>> -   assetToPToken: mapping(address=>address) <<InitializableAbstractStrategy>> -   harvesterAddress: address <<InitializableAbstractStrategy>> -   rewardTokenAddresses: address[] <<InitializableAbstractStrategy>> -   SSV_TOKEN_ADDRESS: address <<NativeStakingSSVStrategy>> -   FEE_ACCUMULATOR_ADDRESS: address <<NativeStakingSSVStrategy>> - -Internal: -    _governor(): (governorOut: address) <<Governable>> -    _pendingGovernor(): (pendingGovernor: address) <<Governable>> -    _setGovernor(newGovernor: address) <<Governable>> -    _setPendingGovernor(newGovernor: address) <<Governable>> -    _changeGovernor(_newGovernor: address) <<Governable>> -    _msgSender(): address <<Context>> -    _msgData(): bytes <<Context>> -    _pause() <<whenNotPaused>> <<Pausable>> -    _unpause() <<whenPaused>> <<Pausable>> + +NativeStakingSSVStrategy +../contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol + +Private: +   governorPosition: bytes32 <<Governable>> +   pendingGovernorPosition: bytes32 <<Governable>> +   reentryStatusPosition: bytes32 <<Governable>> +   _paused: bool <<Pausable>> +   __gap: uint256[50] <<ValidatorRegistrator>> +   __gap: uint256[49] <<ValidatorAccountant>> +   initialized: bool <<Initializable>> +   initializing: bool <<Initializable>> +   ______gap: uint256[50] <<Initializable>> +   _deprecated_platformAddress: address <<InitializableAbstractStrategy>> +   _deprecated_vaultAddress: address <<InitializableAbstractStrategy>> +   _deprecated_rewardTokenAddress: address <<InitializableAbstractStrategy>> +   _deprecated_rewardLiquidationThreshold: uint256 <<InitializableAbstractStrategy>> +   _reserved: int256[98] <<InitializableAbstractStrategy>> +   __gap: uint256[49] <<NativeStakingSSVStrategy>> +Internal: +   assetsMapped: address[] <<InitializableAbstractStrategy>> +Public: +   _NOT_ENTERED: uint256 <<Governable>> +   _ENTERED: uint256 <<Governable>> +   WETH_TOKEN_ADDRESS: address <<ValidatorRegistrator>> +   BEACON_CHAIN_DEPOSIT_CONTRACT: address <<ValidatorRegistrator>> +   SSV_NETWORK_ADDRESS: address <<ValidatorRegistrator>> +   VAULT_ADDRESS: address <<ValidatorRegistrator>> +   validatorRegistrator: address <<ValidatorRegistrator>> +   activeDepositedValidators: uint256 <<ValidatorRegistrator>> +   validatorsStates: mapping(bytes32=>VALIDATOR_STATE) <<ValidatorRegistrator>> +   MIN_FIX_ACCOUNTING_CADENCE: uint256 <<ValidatorAccountant>> +   MAX_STAKE: uint256 <<ValidatorAccountant>> +   consensusRewards: uint256 <<ValidatorAccountant>> +   fuseIntervalStart: uint256 <<ValidatorAccountant>> +   fuseIntervalEnd: uint256 <<ValidatorAccountant>> +   lastFixAccountingBlockNumber: uint256 <<ValidatorAccountant>> +   platformAddress: address <<InitializableAbstractStrategy>> +   vaultAddress: address <<InitializableAbstractStrategy>> +   assetToPToken: mapping(address=>address) <<InitializableAbstractStrategy>> +   harvesterAddress: address <<InitializableAbstractStrategy>> +   rewardTokenAddresses: address[] <<InitializableAbstractStrategy>> +   SSV_TOKEN_ADDRESS: address <<NativeStakingSSVStrategy>> +   FEE_ACCUMULATOR_ADDRESS: address <<NativeStakingSSVStrategy>> +   depositedWethAccountedFor: uint256 <<NativeStakingSSVStrategy>> + +Internal: +    _governor(): (governorOut: address) <<Governable>> +    _pendingGovernor(): (pendingGovernor: address) <<Governable>> +    _setGovernor(newGovernor: address) <<Governable>> +    _setPendingGovernor(newGovernor: address) <<Governable>> +    _changeGovernor(_newGovernor: address) <<Governable>> +    _msgSender(): address <<Context>> +    _msgData(): bytes <<Context>> +    _pause() <<whenNotPaused>> <<Pausable>> +    _unpause() <<whenPaused>> <<Pausable>> +    _wethWithdrawnAndStaked(_amount: uint256) <<NativeStakingSSVStrategy>>    _doAccounting(pauseOnFail: bool): (accountingValid: bool) <<ValidatorAccountant>>    _failAccounting(pauseOnFail: bool): (accountingValid: bool) <<ValidatorAccountant>> -    wethWithdrawnToVault(_amount: uint256) <<NativeStakingSSVStrategy>> +    _wethWithdrawnToVault(_amount: uint256) <<NativeStakingSSVStrategy>>    _initialize(_rewardTokenAddresses: address[], _assets: address[], _pTokens: address[]) <<InitializableAbstractStrategy>>    _collectRewardTokens() <<whenNotPaused>> <<NativeStakingSSVStrategy>>    _setPTokenAddress(_asset: address, _pToken: address) <<InitializableAbstractStrategy>> @@ -89,7 +91,7 @@    depositSSV(operatorIds: uint64[], amount: uint256, cluster: Cluster) <<onlyStrategist>> <<ValidatorRegistrator>>    setFuseInterval(_fuseIntervalStart: uint256, _fuseIntervalEnd: uint256) <<onlyGovernor>> <<ValidatorAccountant>>    doAccounting(): (accountingValid: bool) <<onlyRegistrator, whenNotPaused>> <<ValidatorAccountant>> -    manuallyFixAccounting(_validatorsDelta: int256, _consensusRewardsDelta: int256) <<onlyStrategist, whenPaused>> <<ValidatorAccountant>> +    manuallyFixAccounting(_validatorsDelta: int256, _consensusRewardsDelta: int256, _ethToVaultAmount: uint256) <<onlyStrategist, whenPaused>> <<ValidatorAccountant>>    collectRewardTokens() <<onlyHarvester, nonReentrant>> <<InitializableAbstractStrategy>>    setRewardTokenAddresses(_rewardTokenAddresses: address[]) <<onlyGovernor>> <<InitializableAbstractStrategy>>    getRewardTokenAddresses(): address[] <<InitializableAbstractStrategy>> @@ -118,7 +120,7 @@    <<event>> AccountingFullyWithdrawnValidator(noOfValidators: uint256, remainingValidators: uint256, wethSentToVault: uint256) <<ValidatorAccountant>>    <<event>> AccountingValidatorSlashed(remainingValidators: uint256, wethSentToVault: uint256) <<ValidatorAccountant>>    <<event>> AccountingConsensusRewards(amount: uint256) <<ValidatorAccountant>> -    <<event>> AccountingManuallyFixed(validatorsDelta: int256, consensusRewardsDelta: int256) <<ValidatorAccountant>> +    <<event>> AccountingManuallyFixed(validatorsDelta: int256, consensusRewardsDelta: int256, wethToVault: uint256) <<ValidatorAccountant>>    <<event>> PTokenAdded(_asset: address, _pToken: address) <<InitializableAbstractStrategy>>    <<event>> PTokenRemoved(_asset: address, _pToken: address) <<InitializableAbstractStrategy>>    <<event>> Deposit(_asset: address, _pToken: address, _amount: uint256) <<InitializableAbstractStrategy>> diff --git a/contracts/docs/NativeStakingSSVStrategyStorage.svg b/contracts/docs/NativeStakingSSVStrategyStorage.svg index 3d9f146ce8..27ada6cae1 100644 --- a/contracts/docs/NativeStakingSSVStrategyStorage.svg +++ b/contracts/docs/NativeStakingSSVStrategyStorage.svg @@ -4,166 +4,170 @@ - - + + StorageDiagram - + 3 - -NativeStakingSSVStrategy <<Contract>> - -slot + +NativeStakingSSVStrategy <<Contract>> + +slot + +0 -0 +1 -1 +2 -2 +3-52 -3-52 +53 -53 +54 -54 +55 -55 +56 -56 +57-105 -57-105 +106 -106 +107-156 -107-156 +157 -157 +158 -158 +159 -159 +160 -160 +161 -161 +162 -162 +163 -163 +164 -164 +165-262 -165-262 +263 -263-312 - -type: <inherited contract>.variable (bytes) +264-312 + +type: <inherited contract>.variable (bytes) + +unallocated (11) + +address: ValidatorRegistrator.validatorRegistrator (20) + +bool: Pausable._paused (1) -unallocated (11) - -address: ValidatorRegistrator.validatorRegistrator (20) - -bool: Pausable._paused (1) +uint256: ValidatorRegistrator.activeDepositedValidators (32) -uint256: ValidatorRegistrator.activeDepositedValidators (32) +mapping(bytes32=>VALIDATOR_STATE): ValidatorRegistrator.validatorsStates (32) -mapping(bytes32=>VALIDATOR_STATE): ValidatorRegistrator.validatorsStates (32) +uint256[50]: ValidatorRegistrator.__gap (1600) -uint256[50]: ValidatorRegistrator.__gap (1600) +uint256: ValidatorAccountant.consensusRewards (32) -uint256: ValidatorAccountant.consensusRewards (32) +uint256: ValidatorAccountant.fuseIntervalStart (32) -uint256: ValidatorAccountant.fuseIntervalStart (32) +uint256: ValidatorAccountant.fuseIntervalEnd (32) -uint256: ValidatorAccountant.fuseIntervalEnd (32) +uint256: ValidatorAccountant.lastFixAccountingBlockNumber (32) -uint256: ValidatorAccountant.lastFixAccountingBlockNumber (32) +uint256[49]: ValidatorAccountant.__gap (1568) -uint256[49]: ValidatorAccountant.__gap (1568) +unallocated (30) + +bool: Initializable.initializing (1) + +bool: Initializable.initialized (1) -unallocated (30) - -bool: Initializable.initializing (1) - -bool: Initializable.initialized (1) +uint256[50]: Initializable.______gap (1600) -uint256[50]: Initializable.______gap (1600) +unallocated (12) + +address: InitializableAbstractStrategy._deprecated_platformAddress (20) -unallocated (12) - -address: InitializableAbstractStrategy._deprecated_platformAddress (20) +unallocated (12) + +address: InitializableAbstractStrategy._deprecated_vaultAddress (20) -unallocated (12) - -address: InitializableAbstractStrategy._deprecated_vaultAddress (20) +mapping(address=>address): InitializableAbstractStrategy.assetToPToken (32) -mapping(address=>address): InitializableAbstractStrategy.assetToPToken (32) +address[]: InitializableAbstractStrategy.assetsMapped (32) -address[]: InitializableAbstractStrategy.assetsMapped (32) +unallocated (12) + +address: InitializableAbstractStrategy._deprecated_rewardTokenAddress (20) -unallocated (12) - -address: InitializableAbstractStrategy._deprecated_rewardTokenAddress (20) +uint256: InitializableAbstractStrategy._deprecated_rewardLiquidationThreshold (32) -uint256: InitializableAbstractStrategy._deprecated_rewardLiquidationThreshold (32) +unallocated (12) + +address: InitializableAbstractStrategy.harvesterAddress (20) -unallocated (12) - -address: InitializableAbstractStrategy.harvesterAddress (20) +address[]: InitializableAbstractStrategy.rewardTokenAddresses (32) -address[]: InitializableAbstractStrategy.rewardTokenAddresses (32) +int256[98]: InitializableAbstractStrategy._reserved (3136) -int256[98]: InitializableAbstractStrategy._reserved (3136) +uint256: depositedWethAccountedFor (32) -uint256[50]: __gap (1600) +uint256[49]: __gap (1568) 1 - -address[]: assetsMapped <<Array>> -0x78fdc8d422c49ced035a9edf18d00d3c6a8d81df210f3e5e448e045e77b41e88 - -offset - -0 - -type: variable (bytes) - -unallocated (12) - -address (20) + +address[]: assetsMapped <<Array>> +0x78fdc8d422c49ced035a9edf18d00d3c6a8d81df210f3e5e448e045e77b41e88 + +offset + +0 + +type: variable (bytes) + +unallocated (12) + +address (20) 3:18->1 - - + + 2 - -address[]: rewardTokenAddresses <<Array>> -0xe434dc35da084cf8d7e8186688ea2dacb53db7003d427af3abf351bd9d0a4e8d - -offset - -0 - -type: variable (bytes) - -unallocated (12) - -address (20) + +address[]: rewardTokenAddresses <<Array>> +0xe434dc35da084cf8d7e8186688ea2dacb53db7003d427af3abf351bd9d0a4e8d + +offset + +0 + +type: variable (bytes) + +unallocated (12) + +address (20) 3:23->2 - - + + diff --git a/contracts/test/behaviour/ssvStrategy.js b/contracts/test/behaviour/ssvStrategy.js index 44b4c7949b..d39e0abf59 100644 --- a/contracts/test/behaviour/ssvStrategy.js +++ b/contracts/test/behaviour/ssvStrategy.js @@ -131,7 +131,7 @@ const shouldBehaveLikeAnSsvStrategy = (context) => { const { weth, domen, nativeStakingSSVStrategy, oethVault, strategist } = await context(); - // Add 32 WETH to the strategy via a Vualt deposit + // Add WETH to the strategy via a Vualt deposit await weth.connect(domen).transfer(oethVault.address, amount); return await oethVault From 77d7b0729fb652e5843f1e0b6175ce25d2efda84 Mon Sep 17 00:00:00 2001 From: Domen Grabec Date: Wed, 22 May 2024 13:39:47 +0200 Subject: [PATCH 084/273] Deploy native staking Proxy via Relayer (#2066) * deploy native staking proxy and add auxiliary functions to transfer its governance * Shortened error message in InitializeGovernedUpgradeabilityProxy.initialize --------- Co-authored-by: Nicholas Addison --- .../InitializeGovernedUpgradeabilityProxy.sol | 1 + .../contracts/utils/DepositContractUtils.sol | 32 ++- .../deploy/mainnet/097_native_ssv_staking.js | 38 ++- .../NativeStakingSSVStrategyProxy.json | 259 ++++++++++++++++++ contracts/tasks/tasks.js | 71 +++++ contracts/utils/addresses.js | 1 + contracts/utils/hardhat-helpers.js | 6 +- 7 files changed, 385 insertions(+), 23 deletions(-) create mode 100644 contracts/deployments/mainnet/NativeStakingSSVStrategyProxy.json diff --git a/contracts/contracts/proxies/InitializeGovernedUpgradeabilityProxy.sol b/contracts/contracts/proxies/InitializeGovernedUpgradeabilityProxy.sol index ae83f28c10..82fc8953fe 100644 --- a/contracts/contracts/proxies/InitializeGovernedUpgradeabilityProxy.sol +++ b/contracts/contracts/proxies/InitializeGovernedUpgradeabilityProxy.sol @@ -37,6 +37,7 @@ contract InitializeGovernedUpgradeabilityProxy is Governable { bytes calldata _data ) public payable onlyGovernor { require(_implementation() == address(0)); + require(_logic != address(0), "Implementation not set"); assert( IMPLEMENTATION_SLOT == bytes32(uint256(keccak256("eip1967.proxy.implementation")) - 1) diff --git a/contracts/contracts/utils/DepositContractUtils.sol b/contracts/contracts/utils/DepositContractUtils.sol index 05154132e0..da1f2e8e57 100644 --- a/contracts/contracts/utils/DepositContractUtils.sol +++ b/contracts/contracts/utils/DepositContractUtils.sol @@ -2,28 +2,35 @@ pragma solidity ^0.8.0; contract DepositContractUtils { - function calculateDepositDataRoot( bytes calldata pubkey, bytes calldata withdrawal_credentials, bytes calldata signature - ) public pure returns(bytes32 node){ - uint deposit_amount = 32 ether / 1 gwei; + ) public pure returns (bytes32 node) { + uint256 deposit_amount = 32 ether / 1 gwei; bytes memory amount = to_little_endian_64(uint64(deposit_amount)); // Compute deposit data root (`DepositData` hash tree root) bytes32 pubkey_root = sha256(abi.encodePacked(pubkey, bytes16(0))); - bytes32 signature_root = sha256(abi.encodePacked( - sha256(abi.encodePacked(signature[:64])), - sha256(abi.encodePacked(signature[64:], bytes32(0))) - )); - node = sha256(abi.encodePacked( - sha256(abi.encodePacked(pubkey_root, withdrawal_credentials)), - sha256(abi.encodePacked(amount, bytes24(0), signature_root)) - )); + bytes32 signature_root = sha256( + abi.encodePacked( + sha256(abi.encodePacked(signature[:64])), + sha256(abi.encodePacked(signature[64:], bytes32(0))) + ) + ); + node = sha256( + abi.encodePacked( + sha256(abi.encodePacked(pubkey_root, withdrawal_credentials)), + sha256(abi.encodePacked(amount, bytes24(0), signature_root)) + ) + ); } - function to_little_endian_64(uint64 value) internal pure returns (bytes memory ret) { + function to_little_endian_64(uint64 value) + internal + pure + returns (bytes memory ret) + { ret = new bytes(8); bytes8 bytesValue = bytes8(value); // Byteswapping during copying to bytes. @@ -36,5 +43,4 @@ contract DepositContractUtils { ret[6] = bytesValue[1]; ret[7] = bytesValue[0]; } - } diff --git a/contracts/deploy/mainnet/097_native_ssv_staking.js b/contracts/deploy/mainnet/097_native_ssv_staking.js index bbdcb794b2..c1258b4dd6 100644 --- a/contracts/deploy/mainnet/097_native_ssv_staking.js +++ b/contracts/deploy/mainnet/097_native_ssv_staking.js @@ -1,5 +1,7 @@ const { deploymentWithGovernanceProposal } = require("../../utils/deploy"); const addresses = require("../../utils/addresses"); +const { isFork } = require("../../test/helpers.js"); +const { impersonateAndFund } = require("../../utils/signers"); module.exports = deploymentWithGovernanceProposal( { @@ -30,14 +32,10 @@ module.exports = deploymentWithGovernanceProposal( // Deployer Actions // ---------------- - // 1. Deploy the new strategy proxy - const dStrategyProxy = await deployWithConfirmation( + // 1. Fetch the strategy proxy deployed by relayer + const cStrategyProxy = await ethers.getContract( "NativeStakingSSVStrategyProxy" ); - const cStrategyProxy = await ethers.getContractAt( - "NativeStakingSSVStrategyProxy", - dStrategyProxy.address - ); // 2. Deploy the new fee accumulator proxy const dFeeAccumulatorProxy = await deployWithConfirmation( @@ -64,9 +62,10 @@ module.exports = deploymentWithGovernanceProposal( "NativeStakingSSVStrategy", dStrategyImpl.address ); + const cStrategy = await ethers.getContractAt( "NativeStakingSSVStrategy", - dStrategyProxy.address + cStrategyProxy.address ); // 3. Initialize Proxy with new implementation and strategy initialization @@ -82,6 +81,31 @@ module.exports = deploymentWithGovernanceProposal( ] ); + if (isFork) { + const relayerSigner = await impersonateAndFund( + addresses.mainnet.validatorRegistrator, + "100" + ); + await withConfirmation( + cStrategyProxy + .connect(relayerSigner) + .transferGovernance(deployerAddr, await getTxOpts()) + ); + } else { + /* Before kicking off the deploy script make sure the Defender relayer transfers the governance + * of the proxy to the deployer account that shall be deploying this script so it will be able + * to initialize the proxy contract + * + * Run the following to make it happen, and comment this error block out: + * yarn run hardhat transferGovernanceNativeStakingProxy --address 0xdeployerAddress --network mainnet + */ + new Error("Transfer governance not yet ran"); + } + + await withConfirmation( + cStrategyProxy.connect(sDeployer).claimGovernance(await getTxOpts()) + ); + // 4. Init the proxy to point at the implementation, set the governor, and call initialize const proxyInitFunction = "initialize(address,address,bytes)"; await withConfirmation( diff --git a/contracts/deployments/mainnet/NativeStakingSSVStrategyProxy.json b/contracts/deployments/mainnet/NativeStakingSSVStrategyProxy.json new file mode 100644 index 0000000000..26255d1aa5 --- /dev/null +++ b/contracts/deployments/mainnet/NativeStakingSSVStrategyProxy.json @@ -0,0 +1,259 @@ +{ + "address": "0x34edb2ee25751ee67f68a45813b22811687c0238", + "abi": [ + { + "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": true, + "internalType": "address", + "name": "previousGovernor", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newGovernor", + "type": "address" + } + ], + "name": "PendingGovernorshipTransfer", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "implementation", + "type": "address" + } + ], + "name": "Upgraded", + "type": "event" + }, + { + "stateMutability": "payable", + "type": "fallback" + }, + { + "inputs": [], + "name": "admin", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "claimGovernance", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "governor", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "implementation", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_logic", + "type": "address" + }, + { + "internalType": "address", + "name": "_initGovernor", + "type": "address" + }, + { + "internalType": "bytes", + "name": "_data", + "type": "bytes" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [], + "name": "isGovernor", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_newGovernor", + "type": "address" + } + ], + "name": "transferGovernance", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newImplementation", + "type": "address" + } + ], + "name": "upgradeTo", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newImplementation", + "type": "address" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "upgradeToAndCall", + "outputs": [], + "stateMutability": "payable", + "type": "function" + } + ], + "transactionHash": "0xeb2ba5b203fb2de462a9171f906556269e09e0ea6c6fae49c3dd000edc316b2b", + "args": [], + "numDeployments": 1, + "solcInputHash": "5e7101910c63b5cb160cf1f36fa86058", + "metadata": "{\"compiler\":{\"version\":\"0.8.7+commit.e28d00a7\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"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\":true,\"internalType\":\"address\",\"name\":\"previousGovernor\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newGovernor\",\"type\":\"address\"}],\"name\":\"PendingGovernorshipTransfer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"implementation\",\"type\":\"address\"}],\"name\":\"Upgraded\",\"type\":\"event\"},{\"stateMutability\":\"payable\",\"type\":\"fallback\"},{\"inputs\":[],\"name\":\"admin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"claimGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"governor\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"implementation\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_logic\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_initGovernor\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isGovernor\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_newGovernor\",\"type\":\"address\"}],\"name\":\"transferGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newImplementation\",\"type\":\"address\"}],\"name\":\"upgradeTo\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newImplementation\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"upgradeToAndCall\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"admin()\":{\"returns\":{\"_0\":\"The address of the proxy admin/it's also the governor.\"}},\"implementation()\":{\"returns\":{\"_0\":\"The address of the implementation.\"}},\"initialize(address,address,bytes)\":{\"details\":\"Contract initializer with Governor enforcement\",\"params\":{\"_data\":\"Data to send as msg.data to the implementation to initialize the proxied contract. It should include the signature and the parameters of the function to be called, as described in https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding. This parameter is optional, if no data is given the initialization call to proxied contract will be skipped.\",\"_initGovernor\":\"Address of the initial Governor.\",\"_logic\":\"Address of the initial implementation.\"}},\"transferGovernance(address)\":{\"params\":{\"_newGovernor\":\"Address of the new Governor\"}},\"upgradeTo(address)\":{\"details\":\"Upgrade the backing implementation of the proxy. Only the admin can call this function.\",\"params\":{\"newImplementation\":\"Address of the new implementation.\"}},\"upgradeToAndCall(address,bytes)\":{\"details\":\"Upgrade the backing implementation of the proxy and call a function on the new implementation. This is useful to initialize the proxied contract.\",\"params\":{\"data\":\"Data to send as msg.data in the low level call. It should include the signature and the parameters of the function to be called, as described in https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.\",\"newImplementation\":\"Address of the new implementation.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"claimGovernance()\":{\"notice\":\"Claim Governance of the contract to a new account (`newGovernor`). Can only be called by the new Governor.\"},\"governor()\":{\"notice\":\"Returns the address of the current Governor.\"},\"isGovernor()\":{\"notice\":\"Returns true if the caller is the current Governor.\"},\"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\"}},\"notice\":\"NativeStakingSSVStrategyProxy delegates calls to NativeStakingSSVStrategy implementation\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/proxies/Proxies.sol\":\"NativeStakingSSVStrategyProxy\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@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\"},\"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/proxies/InitializeGovernedUpgradeabilityProxy.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport { Address } from \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\n\\nimport { Governable } from \\\"../governance/Governable.sol\\\";\\n\\n/**\\n * @title BaseGovernedUpgradeabilityProxy\\n * @dev This contract combines an upgradeability proxy with our governor system.\\n * It is based on an older version of OpenZeppelins BaseUpgradeabilityProxy\\n * with Solidity ^0.8.0.\\n * @author Origin Protocol Inc\\n */\\ncontract InitializeGovernedUpgradeabilityProxy is Governable {\\n /**\\n * @dev Emitted when the implementation is upgraded.\\n * @param implementation Address of the new implementation.\\n */\\n event Upgraded(address indexed implementation);\\n\\n /**\\n * @dev Contract initializer with Governor enforcement\\n * @param _logic Address of the initial implementation.\\n * @param _initGovernor Address of the initial Governor.\\n * @param _data Data to send as msg.data to the implementation to initialize\\n * the proxied contract.\\n * It should include the signature and the parameters of the function to be\\n * called, as described in\\n * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.\\n * This parameter is optional, if no data is given the initialization call\\n * to proxied contract will be skipped.\\n */\\n function initialize(\\n address _logic,\\n address _initGovernor,\\n bytes calldata _data\\n ) public payable onlyGovernor {\\n require(_implementation() == address(0));\\n assert(\\n IMPLEMENTATION_SLOT ==\\n bytes32(uint256(keccak256(\\\"eip1967.proxy.implementation\\\")) - 1)\\n );\\n _setImplementation(_logic);\\n if (_data.length > 0) {\\n (bool success, ) = _logic.delegatecall(_data);\\n require(success);\\n }\\n _changeGovernor(_initGovernor);\\n }\\n\\n /**\\n * @return The address of the proxy admin/it's also the governor.\\n */\\n function admin() external view returns (address) {\\n return _governor();\\n }\\n\\n /**\\n * @return The address of the implementation.\\n */\\n function implementation() external view returns (address) {\\n return _implementation();\\n }\\n\\n /**\\n * @dev Upgrade the backing implementation of the proxy.\\n * Only the admin can call this function.\\n * @param newImplementation Address of the new implementation.\\n */\\n function upgradeTo(address newImplementation) external onlyGovernor {\\n _upgradeTo(newImplementation);\\n }\\n\\n /**\\n * @dev Upgrade the backing implementation of the proxy and call a function\\n * on the new implementation.\\n * This is useful to initialize the proxied contract.\\n * @param newImplementation Address of the new implementation.\\n * @param data Data to send as msg.data in the low level call.\\n * It should include the signature and the parameters of the function to be called, as described in\\n * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.\\n */\\n function upgradeToAndCall(address newImplementation, bytes calldata data)\\n external\\n payable\\n onlyGovernor\\n {\\n _upgradeTo(newImplementation);\\n (bool success, ) = newImplementation.delegatecall(data);\\n require(success);\\n }\\n\\n /**\\n * @dev Fallback function.\\n * Implemented entirely in `_fallback`.\\n */\\n fallback() external payable {\\n _fallback();\\n }\\n\\n /**\\n * @dev Delegates execution to an implementation contract.\\n * This is a low level function that doesn't return to its internal call site.\\n * It will return to the external caller whatever the implementation returns.\\n * @param _impl Address to delegate.\\n */\\n function _delegate(address _impl) internal {\\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(gas(), _impl, 0, calldatasize(), 0, 0)\\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 /**\\n * @dev Function that is run as the first thing in the fallback function.\\n * Can be redefined in derived contracts to add functionality.\\n * Redefinitions must call super._willFallback().\\n */\\n function _willFallback() internal {}\\n\\n /**\\n * @dev fallback implementation.\\n * Extracted to enable manual triggering.\\n */\\n function _fallback() internal {\\n _willFallback();\\n _delegate(_implementation());\\n }\\n\\n /**\\n * @dev Storage slot with the address of the current implementation.\\n * This is the keccak-256 hash of \\\"eip1967.proxy.implementation\\\" subtracted by 1, and is\\n * validated in the constructor.\\n */\\n bytes32 internal constant IMPLEMENTATION_SLOT =\\n 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\\n\\n /**\\n * @dev Returns the current implementation.\\n * @return impl Address of the current implementation\\n */\\n function _implementation() internal view returns (address impl) {\\n bytes32 slot = IMPLEMENTATION_SLOT;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n impl := sload(slot)\\n }\\n }\\n\\n /**\\n * @dev Upgrades the proxy to a new implementation.\\n * @param newImplementation Address of the new implementation.\\n */\\n function _upgradeTo(address newImplementation) internal {\\n _setImplementation(newImplementation);\\n emit Upgraded(newImplementation);\\n }\\n\\n /**\\n * @dev Sets the implementation address of the proxy.\\n * @param newImplementation Address of the new implementation.\\n */\\n function _setImplementation(address newImplementation) internal {\\n require(\\n Address.isContract(newImplementation),\\n \\\"Cannot set a proxy implementation to a non-contract address\\\"\\n );\\n\\n bytes32 slot = IMPLEMENTATION_SLOT;\\n\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n sstore(slot, newImplementation)\\n }\\n }\\n}\\n\",\"keccak256\":\"0xcf9bc33957fa41a745726edb6461a4bddca875a038c848286a059f0f22b7f184\",\"license\":\"MIT\"},\"contracts/proxies/Proxies.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport { InitializeGovernedUpgradeabilityProxy } from \\\"./InitializeGovernedUpgradeabilityProxy.sol\\\";\\n\\n/**\\n * @notice OUSDProxy delegates calls to an OUSD implementation\\n */\\ncontract OUSDProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice WrappedOUSDProxy delegates calls to a WrappedOUSD implementation\\n */\\ncontract WrappedOUSDProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice VaultProxy delegates calls to a Vault implementation\\n */\\ncontract VaultProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice CompoundStrategyProxy delegates calls to a CompoundStrategy implementation\\n */\\ncontract CompoundStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice AaveStrategyProxy delegates calls to a AaveStrategy implementation\\n */\\ncontract AaveStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice ThreePoolStrategyProxy delegates calls to a ThreePoolStrategy implementation\\n */\\ncontract ThreePoolStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice ConvexStrategyProxy delegates calls to a ConvexStrategy implementation\\n */\\ncontract ConvexStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice HarvesterProxy delegates calls to a Harvester implementation\\n */\\ncontract HarvesterProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice DripperProxy delegates calls to a Dripper implementation\\n */\\ncontract DripperProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice MorphoCompoundStrategyProxy delegates calls to a MorphoCompoundStrategy implementation\\n */\\ncontract MorphoCompoundStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice ConvexOUSDMetaStrategyProxy delegates calls to a ConvexOUSDMetaStrategy implementation\\n */\\ncontract ConvexOUSDMetaStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice ConvexLUSDMetaStrategyProxy delegates calls to a ConvexalGeneralizedMetaStrategy implementation\\n */\\ncontract ConvexLUSDMetaStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice MorphoAaveStrategyProxy delegates calls to a MorphoCompoundStrategy implementation\\n */\\ncontract MorphoAaveStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice OETHProxy delegates calls to nowhere for now\\n */\\ncontract OETHProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice WOETHProxy delegates calls to nowhere for now\\n */\\ncontract WOETHProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice OETHVaultProxy delegates calls to a Vault implementation\\n */\\ncontract OETHVaultProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice OETHDripperProxy delegates calls to a OETHDripper implementation\\n */\\ncontract OETHDripperProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice OETHHarvesterProxy delegates calls to a Harvester implementation\\n */\\ncontract OETHHarvesterProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice FraxETHStrategyProxy delegates calls to a FraxETHStrategy implementation\\n */\\ncontract FraxETHStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice CurveEthStrategyProxy delegates calls to a CurveEthStrategy implementation\\n */\\ncontract ConvexEthMetaStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice BuybackProxy delegates calls to Buyback implementation\\n */\\ncontract BuybackProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice OETHMorphoAaveStrategyProxy delegates calls to a MorphoAaveStrategy implementation\\n */\\ncontract OETHMorphoAaveStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice OETHBalancerMetaPoolrEthStrategyProxy delegates calls to a BalancerMetaPoolStrategy implementation\\n */\\ncontract OETHBalancerMetaPoolrEthStrategyProxy is\\n InitializeGovernedUpgradeabilityProxy\\n{\\n\\n}\\n\\n/**\\n * @notice OETHBalancerMetaPoolwstEthStrategyProxy delegates calls to a BalancerMetaPoolStrategy implementation\\n */\\ncontract OETHBalancerMetaPoolwstEthStrategyProxy is\\n InitializeGovernedUpgradeabilityProxy\\n{\\n\\n}\\n\\n/**\\n * @notice FluxStrategyProxy delegates calls to a CompoundStrategy implementation\\n */\\ncontract FluxStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice MakerDsrStrategyProxy delegates calls to a Generalized4626Strategy implementation\\n */\\ncontract MakerDsrStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice FrxEthRedeemStrategyProxy delegates calls to a FrxEthRedeemStrategy implementation\\n */\\ncontract FrxEthRedeemStrategyProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice OETHBuybackProxy delegates calls to Buyback implementation\\n */\\ncontract OETHBuybackProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice BridgedWOETHProxy delegates calls to BridgedWOETH implementation\\n */\\ncontract BridgedWOETHProxy is InitializeGovernedUpgradeabilityProxy {\\n\\n}\\n\\n/**\\n * @notice NativeStakingSSVStrategyProxy delegates calls to NativeStakingSSVStrategy implementation\\n */\\ncontract NativeStakingSSVStrategyProxy is\\n InitializeGovernedUpgradeabilityProxy\\n{\\n\\n}\\n\\n/**\\n * @notice NativeStakingFeeAccumulatorProxy delegates calls to NativeStakingFeeCollector implementation\\n */\\ncontract NativeStakingFeeAccumulatorProxy is\\n InitializeGovernedUpgradeabilityProxy\\n{\\n\\n}\\n\",\"keccak256\":\"0x2e294507edd91494e1020a2a1c43502d2f5cba01266c228406562ecde7a2d872\",\"license\":\"MIT\"}},\"version\":1}", + "bytecode": "0x608060405234801561001057600080fd5b506100273360008051602061099083398151915255565b600080516020610990833981519152546040516001600160a01b03909116906000907fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a908290a36109138061007d6000396000f3fe6080604052600436106100865760003560e01c80635d36b190116100595780635d36b1901461010a578063c7af33521461011f578063cf7a1d7714610144578063d38bfff414610157578063f851a4401461009057610086565b80630c340a24146100905780633659cfe6146100c25780634f1ef286146100e25780635c60da1b146100f5575b61008e610177565b005b34801561009c57600080fd5b506100a5610197565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156100ce57600080fd5b5061008e6100dd366004610745565b6101b4565b61008e6100f03660046107c8565b6101ed565b34801561010157600080fd5b506100a561028a565b34801561011657600080fd5b5061008e6102a2565b34801561012b57600080fd5b50610134610346565b60405190151581526020016100b9565b61008e610152366004610767565b610377565b34801561016357600080fd5b5061008e610172366004610745565b610491565b61019561019060008051602061089e8339815191525490565b610535565b565b60006101af6000805160206108be8339815191525490565b905090565b6101bc610346565b6101e15760405162461bcd60e51b81526004016101d89061082b565b60405180910390fd5b6101ea81610559565b50565b6101f5610346565b6102115760405162461bcd60e51b81526004016101d89061082b565b61021a83610559565b6000836001600160a01b0316838360405161023692919061081b565b600060405180830381855af49150503d8060008114610271576040519150601f19603f3d011682016040523d82523d6000602084013e610276565b606091505b505090508061028457600080fd5b50505050565b60006101af60008051602061089e8339815191525490565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b03161461033d5760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b60648201526084016101d8565b61019533610599565b600061035e6000805160206108be8339815191525490565b6001600160a01b0316336001600160a01b031614905090565b61037f610346565b61039b5760405162461bcd60e51b81526004016101d89061082b565b60006103b360008051602061089e8339815191525490565b6001600160a01b0316146103c657600080fd5b6103f160017f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbd610862565b60008051602061089e8339815191521461040d5761040d610887565b6104168461065a565b8015610488576000846001600160a01b0316838360405161043892919061081b565b600060405180830381855af49150503d8060008114610473576040519150601f19603f3d011682016040523d82523d6000602084013e610478565b606091505b505090508061048657600080fd5b505b61028483610599565b610499610346565b6104b55760405162461bcd60e51b81526004016101d89061082b565b6104dd817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b03166104fd6000805160206108be8339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b3660008037600080366000845af43d6000803e808015610554573d6000f35b3d6000fd5b6105628161065a565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b6001600160a01b0381166105ef5760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f72206973206164647265737328302900000000000060448201526064016101d8565b806001600160a01b031661060f6000805160206108be8339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a36101ea816000805160206108be83398151915255565b803b6106ce5760405162461bcd60e51b815260206004820152603b60248201527f43616e6e6f742073657420612070726f787920696d706c656d656e746174696f60448201527f6e20746f2061206e6f6e2d636f6e74726163742061646472657373000000000060648201526084016101d8565b60008051602061089e83398151915255565b80356001600160a01b03811681146106f757600080fd5b919050565b60008083601f84011261070e57600080fd5b50813567ffffffffffffffff81111561072657600080fd5b60208301915083602082850101111561073e57600080fd5b9250929050565b60006020828403121561075757600080fd5b610760826106e0565b9392505050565b6000806000806060858703121561077d57600080fd5b610786856106e0565b9350610794602086016106e0565b9250604085013567ffffffffffffffff8111156107b057600080fd5b6107bc878288016106fc565b95989497509550505050565b6000806000604084860312156107dd57600080fd5b6107e6846106e0565b9250602084013567ffffffffffffffff81111561080257600080fd5b61080e868287016106fc565b9497909650939450505050565b8183823760009101908152919050565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b60008282101561088257634e487b7160e01b600052601160045260246000fd5b500390565b634e487b7160e01b600052600160045260246000fdfe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa26469706673582212203019a79a43f7d4ec89620197adcc99852be5f4965adfb8a6bbb0ad3954812e2c64736f6c634300080700337bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a", + "deployedBytecode": "0x6080604052600436106100865760003560e01c80635d36b190116100595780635d36b1901461010a578063c7af33521461011f578063cf7a1d7714610144578063d38bfff414610157578063f851a4401461009057610086565b80630c340a24146100905780633659cfe6146100c25780634f1ef286146100e25780635c60da1b146100f5575b61008e610177565b005b34801561009c57600080fd5b506100a5610197565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156100ce57600080fd5b5061008e6100dd366004610745565b6101b4565b61008e6100f03660046107c8565b6101ed565b34801561010157600080fd5b506100a561028a565b34801561011657600080fd5b5061008e6102a2565b34801561012b57600080fd5b50610134610346565b60405190151581526020016100b9565b61008e610152366004610767565b610377565b34801561016357600080fd5b5061008e610172366004610745565b610491565b61019561019060008051602061089e8339815191525490565b610535565b565b60006101af6000805160206108be8339815191525490565b905090565b6101bc610346565b6101e15760405162461bcd60e51b81526004016101d89061082b565b60405180910390fd5b6101ea81610559565b50565b6101f5610346565b6102115760405162461bcd60e51b81526004016101d89061082b565b61021a83610559565b6000836001600160a01b0316838360405161023692919061081b565b600060405180830381855af49150503d8060008114610271576040519150601f19603f3d011682016040523d82523d6000602084013e610276565b606091505b505090508061028457600080fd5b50505050565b60006101af60008051602061089e8339815191525490565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b03161461033d5760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b60648201526084016101d8565b61019533610599565b600061035e6000805160206108be8339815191525490565b6001600160a01b0316336001600160a01b031614905090565b61037f610346565b61039b5760405162461bcd60e51b81526004016101d89061082b565b60006103b360008051602061089e8339815191525490565b6001600160a01b0316146103c657600080fd5b6103f160017f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbd610862565b60008051602061089e8339815191521461040d5761040d610887565b6104168461065a565b8015610488576000846001600160a01b0316838360405161043892919061081b565b600060405180830381855af49150503d8060008114610473576040519150601f19603f3d011682016040523d82523d6000602084013e610478565b606091505b505090508061048657600080fd5b505b61028483610599565b610499610346565b6104b55760405162461bcd60e51b81526004016101d89061082b565b6104dd817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b03166104fd6000805160206108be8339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b3660008037600080366000845af43d6000803e808015610554573d6000f35b3d6000fd5b6105628161065a565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b6001600160a01b0381166105ef5760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f72206973206164647265737328302900000000000060448201526064016101d8565b806001600160a01b031661060f6000805160206108be8339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a36101ea816000805160206108be83398151915255565b803b6106ce5760405162461bcd60e51b815260206004820152603b60248201527f43616e6e6f742073657420612070726f787920696d706c656d656e746174696f60448201527f6e20746f2061206e6f6e2d636f6e74726163742061646472657373000000000060648201526084016101d8565b60008051602061089e83398151915255565b80356001600160a01b03811681146106f757600080fd5b919050565b60008083601f84011261070e57600080fd5b50813567ffffffffffffffff81111561072657600080fd5b60208301915083602082850101111561073e57600080fd5b9250929050565b60006020828403121561075757600080fd5b610760826106e0565b9392505050565b6000806000806060858703121561077d57600080fd5b610786856106e0565b9350610794602086016106e0565b9250604085013567ffffffffffffffff8111156107b057600080fd5b6107bc878288016106fc565b95989497509550505050565b6000806000604084860312156107dd57600080fd5b6107e6846106e0565b9250602084013567ffffffffffffffff81111561080257600080fd5b61080e868287016106fc565b9497909650939450505050565b8183823760009101908152919050565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b60008282101561088257634e487b7160e01b600052601160045260246000fd5b500390565b634e487b7160e01b600052600160045260246000fdfe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa26469706673582212203019a79a43f7d4ec89620197adcc99852be5f4965adfb8a6bbb0ad3954812e2c64736f6c63430008070033", + "libraries": {}, + "devdoc": { + "kind": "dev", + "methods": { + "admin()": { + "returns": { + "_0": "The address of the proxy admin/it's also the governor." + } + }, + "implementation()": { + "returns": { + "_0": "The address of the implementation." + } + }, + "initialize(address,address,bytes)": { + "details": "Contract initializer with Governor enforcement", + "params": { + "_data": "Data to send as msg.data to the implementation to initialize the proxied contract. It should include the signature and the parameters of the function to be called, as described in https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding. This parameter is optional, if no data is given the initialization call to proxied contract will be skipped.", + "_initGovernor": "Address of the initial Governor.", + "_logic": "Address of the initial implementation." + } + }, + "transferGovernance(address)": { + "params": { + "_newGovernor": "Address of the new Governor" + } + }, + "upgradeTo(address)": { + "details": "Upgrade the backing implementation of the proxy. Only the admin can call this function.", + "params": { + "newImplementation": "Address of the new implementation." + } + }, + "upgradeToAndCall(address,bytes)": { + "details": "Upgrade the backing implementation of the proxy and call a function on the new implementation. This is useful to initialize the proxied contract.", + "params": { + "data": "Data to send as msg.data in the low level call. It should include the signature and the parameters of the function to be called, as described in https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.", + "newImplementation": "Address of the new implementation." + } + } + }, + "version": 1 + }, + "userdoc": { + "kind": "user", + "methods": { + "claimGovernance()": { + "notice": "Claim Governance of the contract to a new account (`newGovernor`). Can only be called by the new Governor." + }, + "governor()": { + "notice": "Returns the address of the current Governor." + }, + "isGovernor()": { + "notice": "Returns true if the caller is the current Governor." + }, + "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" + } + }, + "notice": "NativeStakingSSVStrategyProxy delegates calls to NativeStakingSSVStrategy implementation", + "version": 1 + }, + "storageLayout": { + "storage": [], + "types": null + } +} \ No newline at end of file diff --git a/contracts/tasks/tasks.js b/contracts/tasks/tasks.js index 55fd7c0b28..a492c52c4a 100644 --- a/contracts/tasks/tasks.js +++ b/contracts/tasks/tasks.js @@ -72,6 +72,20 @@ const { checkBalance, } = require("./strategy"); +// can not import from utils/deploy since that imports hardhat globally +const withConfirmation = async (deployOrTransactionPromise) => { + const hre = require("hardhat"); + + const result = await deployOrTransactionPromise; + const receipt = await hre.ethers.provider.waitForTransaction( + result.receipt ? result.receipt.transactionHash : result.hash, + 3 + ); + + result.receipt = receipt; + return result; +}; + const log = require("../utils/logger")("tasks"); // Environment tasks. @@ -885,6 +899,63 @@ task("depositSSV").setAction(async (_, __, runSuper) => { return runSuper(); }); +/** + * The native staking proxy needs to be deployed via the defender relayer because the SSV networkd + * grants the SSV rewards to the deployer of the contract. And we want the Defender Relayer to be + * the recipient + */ +subtask( + "deployNativeStakingProxy", + "Deploy the native staking proxy via the Defender Relayer" +).setAction(async () => { + const defenderSigner = await getDefenderSigner(); + + log("Deploy NativeStakingSSVStrategyProxy"); + const nativeStakingProxyFactory = await ethers.getContractFactory( + "NativeStakingSSVStrategyProxy" + ); + const contract = await nativeStakingProxyFactory + .connect(defenderSigner) + .deploy(); + await contract.deployed(); + log(`Address of deployed contract is: ${contract.address}`); +}); +task("deployNativeStakingProxy").setAction(async (_, __, runSuper) => { + return runSuper(); +}); + +/** + * Governance of the SSV strategy proxy needs to be transferred to the deployer address so that + * the deployer is able to initialize the proxy + */ +subtask( + "transferGovernanceNativeStakingProxy", + "Transfer governance of the proxy from the the Defender Relayer" +) + .addParam("address", "Address of the new governor", undefined, types.string) + .setAction(async (taskArgs) => { + const defenderSigner = await getDefenderSigner(); + + log("Tranfer governance of NativeStakingSSVStrategyProxy"); + + const nativeStakingProxyFactory = await ethers.getContract( + "NativeStakingSSVStrategyProxy" + ); + await withConfirmation( + nativeStakingProxyFactory + .connect(defenderSigner) + .transferGovernance(taskArgs.address) + ); + log( + `Governance of NativeStakingSSVStrategyProxy transferred to ${taskArgs.address}` + ); + }); +task("transferGovernanceNativeStakingProxy").setAction( + async (_, __, runSuper) => { + return runSuper(); + } +); + // Defender subtask( "operateValidators", diff --git a/contracts/utils/addresses.js b/contracts/utils/addresses.js index 4d2ac56496..7206b94b15 100644 --- a/contracts/utils/addresses.js +++ b/contracts/utils/addresses.js @@ -254,6 +254,7 @@ addresses.mainnet.beaconChainDepositContract = "0x00000000219ab540356cBB839Cbe05303d7705Fa"; // Native Staking Strategy +// Defender relayer addresses.mainnet.validatorRegistrator = "0x4b91827516f79d6F6a1F292eD99671663b09169a"; diff --git a/contracts/utils/hardhat-helpers.js b/contracts/utils/hardhat-helpers.js index 9474f402ad..405cac9ca8 100644 --- a/contracts/utils/hardhat-helpers.js +++ b/contracts/utils/hardhat-helpers.js @@ -27,15 +27,15 @@ const adjustTheForkBlockNumber = () => { if (isForkTest) { if (isArbForkTest) { forkBlockNumber = process.env.ARBITRUM_BLOCK_NUMBER - ? process.env.ARBITRUM_BLOCK_NUMBER + ? Number(process.env.ARBITRUM_BLOCK_NUMBER) : undefined; } else if (isHoleskyForkTest) { forkBlockNumber = process.env.HOLESKY_BLOCK_NUMBER - ? process.env.HOLESKY_BLOCK_NUMBER + ? Number(process.env.HOLESKY_BLOCK_NUMBER) : undefined; } else { forkBlockNumber = process.env.BLOCK_NUMBER - ? process.env.BLOCK_NUMBER + ? Number(process.env.BLOCK_NUMBER) : undefined; } } From 4c25093880719355c58cf97b7a3ab8974ef0cc74 Mon Sep 17 00:00:00 2001 From: Domen Grabec Date: Wed, 22 May 2024 14:06:58 +0200 Subject: [PATCH 085/273] Setup basic defender action (#2072) * deploy native staking proxy and add auxiliary functions to transfer its governance * Setup basic defender action * update defender-sdk version * add defender client as an external export * configuration update --------- Co-authored-by: Nicholas Addison --- .gitignore | 3 +- contracts/README.md | 61 + contracts/abi/IWETH9.json | 282 ++++ .../abi/native_staking_SSV_strategy.json | 1276 +++++++++++++++++ contracts/package.json | 9 +- .../defender-actions/operateValidators.js | 94 ++ .../defender-actions/rollup.config.cjs | 34 + contracts/tasks/defender.js | 22 + contracts/tasks/tasks.js | 18 +- contracts/tasks/validator.js | 80 +- contracts/utils/addresses.js | 7 + contracts/utils/logger.js | 5 + contracts/yarn.lock | 426 ++++-- 13 files changed, 2151 insertions(+), 166 deletions(-) create mode 100644 contracts/abi/IWETH9.json create mode 100644 contracts/abi/native_staking_SSV_strategy.json create mode 100644 contracts/scripts/defender-actions/operateValidators.js create mode 100644 contracts/scripts/defender-actions/rollup.config.cjs create mode 100644 contracts/tasks/defender.js diff --git a/.gitignore b/.gitignore index 7770a7cb26..e2ac4a3fba 100644 --- a/.gitignore +++ b/.gitignore @@ -62,6 +62,7 @@ contracts/dist/ contracts/.localKeyValueStorage contracts/.localKeyValueStorageMainnet contracts/.localKeyValueStorageHolesky +contracts/scripts/defender-actions/dist/ todo.txt brownie/env-brownie/ @@ -79,4 +80,4 @@ coverage.json fork-coverage unit-coverage -.VSCodeCounter \ No newline at end of file +.VSCodeCounter diff --git a/contracts/README.md b/contracts/README.md index ac1e209a2f..84c6df5154 100644 --- a/contracts/README.md +++ b/contracts/README.md @@ -295,6 +295,67 @@ unset DEFENDER_API_KEY unset DEFENDER_API_SECRET ``` +### Deploying Defender Actions + +Actions are used to run operational jobs are specific times or intervals. + +[rollup](https://rollupjs.org/) is used to bundle Actions source code in +[/script/defender-actions](./script/defender-actions) into a single file that can be uploaded to Defender. The +implementation was based off +[Defender Actions example using Rollup](https://github.com/OpenZeppelin/defender-autotask-examples/tree/master/rollup). +The rollup config is in [/scripts/defender-actions/rollup.config.cjs](./script/defender-actions/rollup.config.cjs). The +outputs are written to task specific folders under [/scripts/defender-actions/dist](./script/defender-actions/dist/). + +The [defender-autotask CLI](https://www.npmjs.com/package/@openzeppelin/defender-autotask-client) is used to upload the +Action code to Defender. For this to work, a Defender Team API key with `Manage Actions` capabilities is needed. This +can be generated by a Defender team admin under the `Manage` tab on the top right of the UI and then `API Keys` on the +left menu. Best to unselect all capabilities except `Manage Actions`. + +Save the Defender Team API key and secret to your `.env` file. + +``` +# Open Zeppelin Defender Team API key +DEFENDER_TEAM_KEY= +DEFENDER_TEAM_SECRET= +``` + +The following will bundle the Actions code ready for upload. + +``` +cd ./script/defender-actions + +npx rollup -c +``` + +The following will upload the different Action bundles to Defender. + +```sh +# change to the defender-actions folder +cd ./script/defender-actions +npx rollup -c + +# Export the DEFENDER_TEAM_KEY and DEFENDER_TEAM_SECRET environment variables +export DEFENDER_TEAM_KEY= +export DEFENDER_TEAM_SECRET= +# Alternatively, the following can be used but it will export all env var including DEPLOYER_PRIVATE_KEY +# set -o allexport && source ../../.env && set +o allexport + +# Set the DEBUG environment variable to oeth* for the Defender Action +npx hardhat setActionVars --id 38e44420-f38b-4d4a-86b0-6012a8897ad9 +npx hardhat setActionVars --id f4b5b8d4-82ff-483f-bfae-9fef015790ca + +# Upload Deposit to EigenLayer code +# The Defender autotask client uses generic env var names so we'll set them first from the values in the .env file +export API_KEY=${DEFENDER_TEAM_KEY} +export API_SECRET=${DEFENDER_TEAM_SECRET} +# Holesky +npx defender-autotask update-code 38e44420-f38b-4d4a-86b0-6012a8897ad9 ./dist/operateValidators +# Mainnet +npx defender-autotask update-code f4b5b8d4-82ff-483f-bfae-9fef015790ca ./dist/operateValidators +``` + +`rollup` and `defender-autotask-client` can be installed globally to avoid the `npx` prefix. + ## Contract Verification The Hardhat plug-in [@nomiclabs/hardhat-etherscan](https://www.npmjs.com/package/@nomiclabs/hardhat-etherscan) is used to verify contracts on Etherscan. diff --git a/contracts/abi/IWETH9.json b/contracts/abi/IWETH9.json new file mode 100644 index 0000000000..7a9c673653 --- /dev/null +++ b/contracts/abi/IWETH9.json @@ -0,0 +1,282 @@ +[ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "src", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "guy", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "wad", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "dst", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "wad", + "type": "uint256" + } + ], + "name": "Deposit", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "src", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "dst", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "wad", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "src", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "wad", + "type": "uint256" + } + ], + "name": "Withdrawal", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "guy", + "type": "address" + }, + { + "internalType": "uint256", + "name": "wad", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "decimals", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "deposit", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [], + "name": "name", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "symbol", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "dst", + "type": "address" + }, + { + "internalType": "uint256", + "name": "wad", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "src", + "type": "address" + }, + { + "internalType": "address", + "name": "dst", + "type": "address" + }, + { + "internalType": "uint256", + "name": "wad", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "wad", + "type": "uint256" + } + ], + "name": "withdraw", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ] \ No newline at end of file diff --git a/contracts/abi/native_staking_SSV_strategy.json b/contracts/abi/native_staking_SSV_strategy.json new file mode 100644 index 0000000000..01c581d567 --- /dev/null +++ b/contracts/abi/native_staking_SSV_strategy.json @@ -0,0 +1,1276 @@ +[ + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "platformAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "vaultAddress", + "type": "address" + } + ], + "internalType": "struct InitializableAbstractStrategy.BaseStrategyConfig", + "name": "_baseConfig", + "type": "tuple" + }, + { + "internalType": "address", + "name": "_wethAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_ssvToken", + "type": "address" + }, + { + "internalType": "address", + "name": "_ssvNetwork", + "type": "address" + }, + { + "internalType": "address", + "name": "_feeAccumulator", + "type": "address" + }, + { + "internalType": "address", + "name": "_beaconChainDepositContract", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "AccountingConsensusRewards", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "noOfValidators", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "remainingValidators", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "wethSentToVault", + "type": "uint256" + } + ], + "name": "AccountingFullyWithdrawnValidator", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "int256", + "name": "validatorsDelta", + "type": "int256" + }, + { + "indexed": false, + "internalType": "int256", + "name": "consensusRewardsDelta", + "type": "int256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "wethToVault", + "type": "uint256" + } + ], + "name": "AccountingManuallyFixed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "remainingValidators", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "wethSentToVault", + "type": "uint256" + } + ], + "name": "AccountingValidatorSlashed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_asset", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "_pToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + } + ], + "name": "Deposit", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "pubkey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "withdrawal_credentials", + "type": "bytes" + } + ], + "name": "ETHStaked", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "start", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "end", + "type": "uint256" + } + ], + "name": "FuseIntervalUpdated", + "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": "address", + "name": "_oldHarvesterAddress", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "_newHarvesterAddress", + "type": "address" + } + ], + "name": "HarvesterAddressesUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_asset", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "_pToken", + "type": "address" + } + ], + "name": "PTokenAdded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_asset", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "_pToken", + "type": "address" + } + ], + "name": "PTokenRemoved", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Paused", + "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": "newAddress", + "type": "address" + } + ], + "name": "RegistratorChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address[]", + "name": "_oldAddresses", + "type": "address[]" + }, + { + "indexed": false, + "internalType": "address[]", + "name": "_newAddresses", + "type": "address[]" + } + ], + "name": "RewardTokenAddressesUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "rewardToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "RewardTokenCollected", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "pubkey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint64[]", + "name": "operatorIds", + "type": "uint64[]" + } + ], + "name": "SSVValidatorExitCompleted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "pubkey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint64[]", + "name": "operatorIds", + "type": "uint64[]" + } + ], + "name": "SSVValidatorExitInitiated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "pubkey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint64[]", + "name": "operatorIds", + "type": "uint64[]" + } + ], + "name": "SSVValidatorRegistered", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Unpaused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_asset", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "_pToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + } + ], + "name": "Withdrawal", + "type": "event" + }, + { + "inputs": [], + "name": "BEACON_CHAIN_DEPOSIT_CONTRACT", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "FEE_ACCUMULATOR_ADDRESS", + "outputs": [ + { + "internalType": "address payable", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "MAX_STAKE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "SSV_NETWORK_ADDRESS", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "SSV_TOKEN_ADDRESS", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "VAULT_ADDRESS", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "WETH_TOKEN_ADDRESS", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "activeDepositedValidators", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "assetToPToken", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_asset", + "type": "address" + } + ], + "name": "checkBalance", + "outputs": [ + { + "internalType": "uint256", + "name": "balance", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "claimGovernance", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "collectRewardTokens", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "consensusRewards", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_asset", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + } + ], + "name": "deposit", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "depositAll", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint64[]", + "name": "operatorIds", + "type": "uint64[]" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "uint32", + "name": "validatorCount", + "type": "uint32" + }, + { + "internalType": "uint64", + "name": "networkFeeIndex", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "index", + "type": "uint64" + }, + { + "internalType": "bool", + "name": "active", + "type": "bool" + }, + { + "internalType": "uint256", + "name": "balance", + "type": "uint256" + } + ], + "internalType": "struct Cluster", + "name": "cluster", + "type": "tuple" + } + ], + "name": "depositSSV", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "doAccounting", + "outputs": [ + { + "internalType": "bool", + "name": "accountingValid", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + }, + { + "internalType": "uint64[]", + "name": "operatorIds", + "type": "uint64[]" + } + ], + "name": "exitSsvValidator", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "fuseIntervalEnd", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "fuseIntervalStart", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getRewardTokenAddresses", + "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": "harvesterAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "_rewardTokenAddresses", + "type": "address[]" + }, + { + "internalType": "address[]", + "name": "_assets", + "type": "address[]" + }, + { + "internalType": "address[]", + "name": "_pTokens", + "type": "address[]" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "isGovernor", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "int256", + "name": "_validatorsDelta", + "type": "int256" + }, + { + "internalType": "int256", + "name": "_consensusRewardsDelta", + "type": "int256" + }, + { + "internalType": "uint256", + "name": "_wethToVaultAmount", + "type": "uint256" + } + ], + "name": "manuallyFixAccounting", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "pause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "paused", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "platformAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + }, + { + "internalType": "uint64[]", + "name": "operatorIds", + "type": "uint64[]" + }, + { + "internalType": "bytes", + "name": "sharesData", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "uint32", + "name": "validatorCount", + "type": "uint32" + }, + { + "internalType": "uint64", + "name": "networkFeeIndex", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "index", + "type": "uint64" + }, + { + "internalType": "bool", + "name": "active", + "type": "bool" + }, + { + "internalType": "uint256", + "name": "balance", + "type": "uint256" + } + ], + "internalType": "struct Cluster", + "name": "cluster", + "type": "tuple" + } + ], + "name": "registerSsvValidator", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_assetIndex", + "type": "uint256" + } + ], + "name": "removePToken", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + }, + { + "internalType": "uint64[]", + "name": "operatorIds", + "type": "uint64[]" + }, + { + "components": [ + { + "internalType": "uint32", + "name": "validatorCount", + "type": "uint32" + }, + { + "internalType": "uint64", + "name": "networkFeeIndex", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "index", + "type": "uint64" + }, + { + "internalType": "bool", + "name": "active", + "type": "bool" + }, + { + "internalType": "uint256", + "name": "balance", + "type": "uint256" + } + ], + "internalType": "struct Cluster", + "name": "cluster", + "type": "tuple" + } + ], + "name": "removeSsvValidator", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "rewardTokenAddresses", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "safeApproveAllTokens", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_fuseIntervalStart", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_fuseIntervalEnd", + "type": "uint256" + } + ], + "name": "setFuseInterval", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_harvesterAddress", + "type": "address" + } + ], + "name": "setHarvesterAddress", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_asset", + "type": "address" + }, + { + "internalType": "address", + "name": "_pToken", + "type": "address" + } + ], + "name": "setPTokenAddress", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_address", + "type": "address" + } + ], + "name": "setRegistrator", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "_rewardTokenAddresses", + "type": "address[]" + } + ], + "name": "setRewardTokenAddresses", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "bytes", + "name": "pubkey", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + }, + { + "internalType": "bytes32", + "name": "depositDataRoot", + "type": "bytes32" + } + ], + "internalType": "struct ValidatorStakeData[]", + "name": "validators", + "type": "tuple[]" + } + ], + "name": "stakeEth", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_asset", + "type": "address" + } + ], + "name": "supportsAsset", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "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": "validatorRegistrator", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "name": "validatorsStates", + "outputs": [ + { + "internalType": "enum ValidatorRegistrator.VALIDATOR_STATE", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "vaultAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_recipient", + "type": "address" + }, + { + "internalType": "address", + "name": "_asset", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + } + ], + "name": "withdraw", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "withdrawAll", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" + } + ] \ No newline at end of file diff --git a/contracts/package.json b/contracts/package.json index 47f6a3a223..b732aa0ae9 100644 --- a/contracts/package.json +++ b/contracts/package.json @@ -48,14 +48,19 @@ "@nomiclabs/hardhat-solhint": "^2.0.0", "@nomiclabs/hardhat-waffle": "^2.0.6", "@openzeppelin/contracts": "4.4.2", - "@openzeppelin/defender-sdk": "^1.3.0", + "@openzeppelin/defender-autotask-client": "^1.54.1", + "@openzeppelin/defender-kvstore-client": "^1.54.5", + "@openzeppelin/defender-relay-client": "^1.54.4", + "@openzeppelin/defender-sdk": "^1.13.1", "@openzeppelin/hardhat-upgrades": "^1.10.0", + "@rollup/plugin-commonjs": "^25.0.7", + "@rollup/plugin-json": "^6.1.0", + "@rollup/plugin-node-resolve": "^15.2.3", "@uniswap/v3-core": "^1.0.0", "@uniswap/v3-periphery": "^1.1.1", "axios": "^1.4.0", "chai": "^4.3.4", "debug": "^4.3.4", - "defender-kvstore-client": "^1.38.1-rc.0", "dotenv": "^10.0.0", "eslint": "^7.32.0", "eslint-plugin-no-only-tests": "^3.1.0", diff --git a/contracts/scripts/defender-actions/operateValidators.js b/contracts/scripts/defender-actions/operateValidators.js new file mode 100644 index 0000000000..d6c1c5fe07 --- /dev/null +++ b/contracts/scripts/defender-actions/operateValidators.js @@ -0,0 +1,94 @@ +const { ethers } = require("ethers"); +const { + DefenderRelaySigner, + DefenderRelayProvider, +} = require("@openzeppelin/defender-relay-client/lib/ethers"); +const { + KeyValueStoreClient, +} = require("@openzeppelin/defender-kvstore-client"); +const { operateValidators } = require("../../tasks/validator"); +const addresses = require("../../utils/addresses"); + +const nativeStakingStrategyAbi = require("../../abi/native_staking_SSV_strategy.json"); +const IWETH9Abi = require("../../abi/IWETH9.json"); + +const log = require("../../utils/logger")("action:operateValidators"); + +// Entrypoint for the Defender Action +const handler = async (event) => { + const store = new KeyValueStoreClient(event); + // Initialize defender relayer provider and signer + console.log( + `DEBUG env var in handler before being set: "${process.env.DEBUG}"` + ); + + const provider = new DefenderRelayProvider(event); + const signer = new DefenderRelaySigner(event, provider, { speed: "fastest" }); + + const network = await provider.getNetwork(); + const networkName = network.chainId === 1 ? "mainnet" : "holesky"; + log(`Network: ${networkName} with chain id (${network.chainId})`); + console.log(`Network: ${networkName} with chain id (${network.chainId})`); + + const nativeStakingProxyAddress = + addresses[networkName].NativeStakingSSVStrategyProxy; + log( + `Resolved Native Staking Strategy address to ${nativeStakingProxyAddress}` + ); + console.log( + `Resolved Native Staking Strategy address to ${nativeStakingProxyAddress}` + ); + const nativeStakingStrategy = new ethers.Contract( + nativeStakingProxyAddress, + nativeStakingStrategyAbi, + signer + ); + + const wethAddress = addresses[networkName].WETH; + log(`Resolved WETH address to ${wethAddress}`); + console.log(`Resolved WETH address to ${wethAddress}`); + const WETH = new ethers.Contract(wethAddress, IWETH9Abi, signer); + + const feeAccumulatorAddress = + await nativeStakingStrategy.FEE_ACCUMULATOR_ADDRESS(); + + const contracts = { + nativeStakingStrategy, + WETH, + }; + + const p2p_api_key = + network.chainId === 1 + ? event.secrets.P2P_MAINNET_API_KEY + : event.secrets.P2P_HOLESKY_API_KEY; + if (!p2p_api_key) { + throw new Error( + "Secret with P2P API key not set. Add the P2P_MAINNET_API_KEY or P2P_HOLESKY_API_KEY secret" + ); + } + const p2p_base_url = + network.chainId === 1 ? "api.p2p.org" : "api-test-holesky.p2p.org"; + + const config = { + feeAccumulatorAddress, + p2p_api_key, + p2p_base_url, + // how much SSV (expressed in days of runway) gets deposited into the + // SSV Network contract on validator registration. This is calculated + // at a Cluster level rather than a single validator. + validatorSpawnOperationalPeriodInDays: 1, + // Stake the 32 ETH into the validator + stake: true, + // Clear the local state of the Defender Action + clear: true, + }; + + await operateValidators({ + signer, + contracts, + store, + config, + }); +}; + +module.exports = { handler }; diff --git a/contracts/scripts/defender-actions/rollup.config.cjs b/contracts/scripts/defender-actions/rollup.config.cjs new file mode 100644 index 0000000000..939c02e2e1 --- /dev/null +++ b/contracts/scripts/defender-actions/rollup.config.cjs @@ -0,0 +1,34 @@ +const resolve = require("@rollup/plugin-node-resolve"); +const commonjs = require("@rollup/plugin-commonjs"); +const json = require("@rollup/plugin-json"); +const builtins = require("builtin-modules"); + +const commonConfig = { + plugins: [resolve({ preferBuiltins: true, exportConditions: ["node"] }), commonjs(), json({ compact: true })], + // Do not bundle these packages. + // ethers is required to be bundled even though its an Autotask package. + external: [ + ...builtins, + "axios", + "chai", + "@openzeppelin/defender-relay-client/lib/ethers", + "@openzeppelin/defender-sdk", + "@openzeppelin/defender-autotask-client", + "@openzeppelin/defender-kvstore-client", + "@openzeppelin/defender-relay-client/lib/ethers", + "@nomicfoundation/solidity-analyzer-darwin-arm64", + "@nomicfoundation/solidity-analyzer-darwin-x64", + "fsevents", + ], +}; + +module.exports = [ + { + ...commonConfig, + input: "operateValidators.js", + output: { + file: "dist/operateValidators/index.js", + format: "cjs", + }, + } +]; diff --git a/contracts/tasks/defender.js b/contracts/tasks/defender.js new file mode 100644 index 0000000000..97742c15f8 --- /dev/null +++ b/contracts/tasks/defender.js @@ -0,0 +1,22 @@ +const { AutotaskClient } = require("@openzeppelin/defender-autotask-client"); + +const log = require("../utils/logger")("task:defender"); + +const setActionVars = async (options) => { + log(`Used DEFENDER_TEAM_KEY ${process.env.DEFENDER_TEAM_KEY}`); + const creds = { + apiKey: process.env.DEFENDER_TEAM_KEY, + apiSecret: process.env.DEFENDER_TEAM_SECRET, + }; + const client = new AutotaskClient(creds); + + // Update Variables + const variables = await client.updateEnvironmentVariables(options.id, { + DEBUG: "origin*", + }); + console.log("updated Autotask environment variables", variables); +}; + +module.exports = { + setActionVars, +}; diff --git a/contracts/tasks/tasks.js b/contracts/tasks/tasks.js index a492c52c4a..ce1feca2dc 100644 --- a/contracts/tasks/tasks.js +++ b/contracts/tasks/tasks.js @@ -2,13 +2,16 @@ const { subtask, task, types } = require("hardhat/config"); const { fund } = require("./account"); const { debug } = require("./debug"); const { env } = require("./env"); +const { setActionVars } = require("./defender"); const { execute, executeOnFork, proposal, governors } = require("./governance"); const { smokeTest, smokeTestCheck } = require("./smokeTest"); const addresses = require("../utils/addresses"); const { getDefenderSigner } = require("../utils/signers"); const { networkMap } = require("../utils/hardhat-helpers"); const { resolveContract } = require("../utils/resolvers"); -const { KeyValueStoreClient } = require("defender-kvstore-client"); +const { + KeyValueStoreClient, +} = require("@openzeppelin/defender-kvstore-client"); const { operateValidators } = require("./validator"); const { formatUnits } = require("ethers/lib/utils"); @@ -983,7 +986,7 @@ subtask( if (!isMainnet && !isHolesky) { throw new Error( - "operate validatos is supported on Mainnet and Holesky only" + "operate validators is supported on Mainnet and Holesky only" ); } @@ -1049,3 +1052,14 @@ subtask( task("operateValidators").setAction(async (_, __, runSuper) => { return runSuper(); }); + +// Defender +subtask( + "setActionVars", + "Set environment variables on a Defender Actions. eg DEBUG=origin*" +) + .addParam("id", "Identifier of the Defender Actions", undefined, types.string) + .setAction(setActionVars); +task("setActionVars").setAction(async (_, __, runSuper) => { + return runSuper(); +}); diff --git a/contracts/tasks/validator.js b/contracts/tasks/validator.js index 9b9f484238..992ac02b67 100644 --- a/contracts/tasks/validator.js +++ b/contracts/tasks/validator.js @@ -3,11 +3,9 @@ const { defaultAbiCoder, formatUnits, hexDataSlice, parseEther } = require("ethers").utils; const { v4: uuidv4 } = require("uuid"); -const { resolveContract } = require("../utils/resolvers"); -const { getSigner } = require("../utils/signers"); +//const { resolveContract } = require("../utils/resolvers"); const { sleep } = require("../utils/time"); -const { getClusterInfo } = require("./ssv"); -const { logTxDetails } = require("../utils/txLogger"); +//const { getClusterInfo } = require("./ssv"); const log = require("../utils/logger")("task:p2p"); @@ -518,46 +516,42 @@ const confirmValidatorCreatedRequest = async ( } }; -async function exitValidator({ publicKey, operatorIds }) { - const signer = await getSigner(); - - const strategy = await resolveContract( - "NativeStakingSSVStrategyProxy", - "NativeStakingSSVStrategy" - ); - - log(`About to exit validator`); - const tx = await strategy - .connect(signer) - .exitSsvValidator(publicKey, operatorIds); - await logTxDetails(tx, "exitSsvValidator"); -} - -async function removeValidator({ publicKey, operatorIds }) { - const signer = await getSigner(); - - const strategy = await resolveContract( - "NativeStakingSSVStrategyProxy", - "NativeStakingSSVStrategy" - ); - - // Cluster details - const { cluster } = await getClusterInfo({ - chainId: hre.network.config.chainId, - ssvNetwork: hre.network.name.toUpperCase(), - operatorIds, - ownerAddress: strategy.address, - }); - - log(`About to exit validator`); - const tx = await strategy - .connect(signer) - .removeSsvValidator(publicKey, operatorIds, cluster); - await logTxDetails(tx, "removeSsvValidator"); -} +// async function exitValidator({ publicKey, signer, operatorIds }) { +// const strategy = await resolveContract( +// "NativeStakingSSVStrategyProxy", +// "NativeStakingSSVStrategy" +// ); + +// log(`About to exit validator`); +// const tx = await strategy +// .connect(signer) +// .exitSsvValidator(publicKey, operatorIds); +// await logTxDetails(tx, "exitSsvValidator"); +// } + +// async function removeValidator({ publicKey, signer, operatorIds }) { +// const strategy = await resolveContract( +// "NativeStakingSSVStrategyProxy", +// "NativeStakingSSVStrategy" +// ); + +// // Cluster details +// const { cluster } = await getClusterInfo({ +// chainId: hre.network.config.chainId, +// ssvNetwork: hre.network.name.toUpperCase(), +// operatorIds, +// ownerAddress: strategy.address, +// }); + +// log(`About to exit validator`); +// const tx = await strategy +// .connect(signer) +// .removeSsvValidator(publicKey, operatorIds, cluster); +// await logTxDetails(tx, "removeSsvValidator"); +// } module.exports = { operateValidators, - removeValidator, - exitValidator, + //removeValidator, + //exitValidator, }; diff --git a/contracts/utils/addresses.js b/contracts/utils/addresses.js index 7206b94b15..9e99c8e283 100644 --- a/contracts/utils/addresses.js +++ b/contracts/utils/addresses.js @@ -254,6 +254,9 @@ addresses.mainnet.beaconChainDepositContract = "0x00000000219ab540356cBB839Cbe05303d7705Fa"; // Native Staking Strategy +addresses.mainnet.NativeStakingSSVStrategyProxy = + "0x34edb2ee25751ee67f68a45813b22811687c0238"; + // Defender relayer addresses.mainnet.validatorRegistrator = "0x4b91827516f79d6F6a1F292eD99671663b09169a"; @@ -271,6 +274,10 @@ addresses.holesky.SSVNetwork = "0x38A4794cCEd47d3baf7370CcC43B560D3a1beEFA"; addresses.holesky.beaconChainDepositContract = "0x4242424242424242424242424242424242424242"; +// Native Staking Strategy +addresses.holesky.NativeStakingSSVStrategyProxy = + "0xcf4a9e80Ddb173cc17128A361B98B9A140e3932E"; + addresses.holesky.OETHVaultProxy = "0x19d2bAaBA949eFfa163bFB9efB53ed8701aA5dD9"; // Address of the Holesky defender relayer addresses.holesky.validatorRegistrator = diff --git a/contracts/utils/logger.js b/contracts/utils/logger.js index ad73c62444..b4362787ae 100644 --- a/contracts/utils/logger.js +++ b/contracts/utils/logger.js @@ -1,5 +1,10 @@ const debug = require("debug"); +// https://www.npmjs.com/package/debug#output-streams +// set all output to go via console.log instead of stderr +// This is needed for Defender Actions to capture the logs +debug.log = console.log.bind(console); + /** * Creates a logger for a module. * @example diff --git a/contracts/yarn.lock b/contracts/yarn.lock index 72b9e29ee4..cea1711fd5 100644 --- a/contracts/yarn.lock +++ b/contracts/yarn.lock @@ -2,6 +2,11 @@ # yarn lockfile v1 +"@adraffy/ens-normalize@1.10.1": + version "1.10.1" + resolved "https://registry.yarnpkg.com/@adraffy/ens-normalize/-/ens-normalize-1.10.1.tgz#63430d04bd8c5e74f8d7d049338f1cd9d4f02069" + integrity sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw== + "@aws-crypto/sha256-js@1.2.2": version "1.2.2" resolved "https://registry.yarnpkg.com/@aws-crypto/sha256-js/-/sha256-js-1.2.2.tgz#02acd1a1fda92896fc5a28ec7c6e164644ea32fc" @@ -484,7 +489,7 @@ resolved "https://registry.yarnpkg.com/@ethersproject/logger/-/logger-5.7.0.tgz#6ce9ae168e74fecf287be17062b590852c311892" integrity sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig== -"@ethersproject/networks@5.7.1", "@ethersproject/networks@^5.7.0", "@ethersproject/networks@^5.7.1": +"@ethersproject/networks@5.7.1", "@ethersproject/networks@^5.7.0": version "5.7.1" resolved "https://registry.yarnpkg.com/@ethersproject/networks/-/networks-5.7.1.tgz#118e1a981d757d45ccea6bb58d9fd3d9db14ead6" integrity sha512-n/MufjFYv3yFcUyfhnXotyDlNdFb7onmkSy8aQERi2PjNcnWQ66xXxa3XlS8nCcA8aJKJjIIMNJTC7tu80GwpQ== @@ -733,6 +738,11 @@ resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== +"@jridgewell/sourcemap-codec@^1.4.15": + version "1.4.15" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" + integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== + "@metamask/eth-sig-util@^4.0.0": version "4.0.1" resolved "https://registry.yarnpkg.com/@metamask/eth-sig-util/-/eth-sig-util-4.0.1.tgz#3ad61f6ea9ad73ba5b19db780d40d9aae5157088" @@ -744,6 +754,13 @@ tweetnacl "^1.0.3" tweetnacl-util "^0.15.1" +"@noble/curves@1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.2.0.tgz#92d7e12e4e49b23105a2555c6984d41733d65c35" + integrity sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw== + dependencies: + "@noble/hashes" "1.3.2" + "@noble/curves@1.3.0", "@noble/curves@~1.3.0": version "1.3.0" resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.3.0.tgz#01be46da4fd195822dab821e72f71bf4aeec635e" @@ -756,6 +773,11 @@ resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.2.0.tgz#a3150eeb09cc7ab207ebf6d7b9ad311a9bdbed12" integrity sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ== +"@noble/hashes@1.3.2": + version "1.3.2" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.2.tgz#6f26dbc8fbc7205873ce3cee2f690eba0d421b39" + integrity sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ== + "@noble/hashes@1.3.3", "@noble/hashes@~1.3.2": version "1.3.3" resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.3.tgz#39908da56a4adc270147bb07968bf3b16cfe1699" @@ -1052,116 +1074,163 @@ resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-4.3.3.tgz#ff6ee919fc2a1abaf72b22814bfb72ed129ec137" integrity sha512-tDBopO1c98Yk7Cv/PZlHqrvtVjlgK5R4J6jxLwoO7qxK4xqOiZG+zSkIvGFpPZ0ikc3QOED3plgdqjgNTnBc7g== -"@openzeppelin/defender-sdk-action-client@^1.3.0": - version "1.3.0" - resolved "https://registry.yarnpkg.com/@openzeppelin/defender-sdk-action-client/-/defender-sdk-action-client-1.3.0.tgz#6964523bc29da5c0104d364bb72123322c01954a" - integrity sha512-j1AzY4A+4ywHgI0SYJfh1LC5bNR430TCJmNfyn7D5ZM32sXPvTPu0SAQKGz6bYRFp+YAB6bOJZDyT1J3YbnxMw== +"@openzeppelin/defender-autotask-client@^1.54.1": + version "1.54.4" + resolved "https://registry.yarnpkg.com/@openzeppelin/defender-autotask-client/-/defender-autotask-client-1.54.4.tgz#2b4063e3ad6542cd0b1fe000e601afad3f1fa3af" + integrity sha512-I5Ges1tVLkaFhc7+q9tl3qVCIbpPqd1jJExKqzCilR83Xe3gDLZhgKuW5LC4iQ4kLzi6rEaONFML7XKG+Mz1NQ== dependencies: - "@openzeppelin/defender-sdk-base-client" "^1.3.0" + "@openzeppelin/defender-base-client" "1.54.4" axios "^1.4.0" + dotenv "^10.0.0" glob "^7.1.6" - jszip "^3.8.0" - lodash "^4.17.21" + jszip "^3.5.0" + lodash "^4.17.19" + node-fetch "^2.6.0" -"@openzeppelin/defender-sdk-base-client@^1.3.0": - version "1.3.0" - resolved "https://registry.yarnpkg.com/@openzeppelin/defender-sdk-base-client/-/defender-sdk-base-client-1.3.0.tgz#9e4bc35e9c5d86578c5e509edcbda4aefffb2413" - integrity sha512-OMMt7NaAL8C95ralF9nMeKZpg96COLZT9FPpGpPsI7aB8fVZfCM8+6k99gTF44hMS6IsRdN2WthS3m7VzQeeoA== +"@openzeppelin/defender-base-client@1.54.4": + version "1.54.4" + resolved "https://registry.yarnpkg.com/@openzeppelin/defender-base-client/-/defender-base-client-1.54.4.tgz#27a5a73455a433aabde25f893f1f1021cbfa5289" + integrity sha512-LEDiHFI8BavbjVjR/H8IJSyw0Dlr2NTiutTwMIJk6QKtQ1ZlTuUktl+tBzl3Fe3SpLiaBZvqYx4/3tN0byeE4Q== dependencies: amazon-cognito-identity-js "^6.0.1" async-retry "^1.3.3" + axios "^1.4.0" + lodash "^4.17.19" + node-fetch "^2.6.0" -"@openzeppelin/defender-sdk-deploy-client@^1.3.0": - version "1.3.0" - resolved "https://registry.yarnpkg.com/@openzeppelin/defender-sdk-deploy-client/-/defender-sdk-deploy-client-1.3.0.tgz#d70f06e849080d6a0ad5b86f631567642204f1ba" - integrity sha512-RTYM3HnVvD2d5NoYfTug8UwT41e0Jjwb13lk9v0Jl8z7mcclUVvAnKD4DHJ4b8RhKpg4B15oLQK/Igzjg1HHRA== +"@openzeppelin/defender-kvstore-client@^1.54.5": + version "1.54.5" + resolved "https://registry.yarnpkg.com/@openzeppelin/defender-kvstore-client/-/defender-kvstore-client-1.54.5.tgz#d65fba0d956f5b3b90136bc774479d94af058559" + integrity sha512-vhkFgXJanwD/RvLtKogCCWBzWdBDyZTO9h0DKnS9ZFHV7E27zMTqjt9FISNT1pD2b1QBHVVlKaKXVk6SDYCrtQ== dependencies: - "@ethersproject/abi" "^5.6.3" - "@openzeppelin/defender-sdk-base-client" "^1.3.0" + "@openzeppelin/defender-base-client" "1.54.4" axios "^1.4.0" - lodash "^4.17.21" + fs-extra "^10.0.0" + lodash "^4.17.19" + node-fetch "^2.6.0" -"@openzeppelin/defender-sdk-monitor-client@^1.3.0": - version "1.3.0" - resolved "https://registry.yarnpkg.com/@openzeppelin/defender-sdk-monitor-client/-/defender-sdk-monitor-client-1.3.0.tgz#c72f6fb517f3ae15d087de8d1837d49350b5dfd0" - integrity sha512-0drfifN4lk4Jpn5goU0imuuvQfxH8EDHUCEQSqxHbubsmNMrI+RqnHSuLZ26VceXbmcVbpfrYhVPnIVyyL4bVw== +"@openzeppelin/defender-relay-client@^1.54.4": + version "1.54.4" + resolved "https://registry.yarnpkg.com/@openzeppelin/defender-relay-client/-/defender-relay-client-1.54.4.tgz#613c75436fcd15e53c3ae20df7a4288081559f0a" + integrity sha512-AgPw4FY7RK9ZaWpPEIqeayBPIlOg/ltvviiBc+bV5fXWXdJQ77iw8Lbv7KrS9pZ21TcgblbRtE3T1epq21tbrg== dependencies: - "@ethersproject/abi" "^5.6.3" - "@openzeppelin/defender-sdk-base-client" "^1.3.0" + "@openzeppelin/defender-base-client" "1.54.4" + amazon-cognito-identity-js "^6.0.1" axios "^1.4.0" + lodash "^4.17.19" + node-fetch "^2.6.0" + +"@openzeppelin/defender-sdk-account-client@^1.13.1": + version "1.13.1" + resolved "https://registry.yarnpkg.com/@openzeppelin/defender-sdk-account-client/-/defender-sdk-account-client-1.13.1.tgz#8670fff98b35f70a10f6ed741e6d7c12ae539b69" + integrity sha512-xjPjXMDMwTB1Y6qYECKn1TwCXEyxjEKuOcj2FlRg+xvn1bpEJfye9NBCFXYZW4MDKABwMFBukU0gVspGaXe1ZQ== + dependencies: + "@openzeppelin/defender-sdk-base-client" "^1.13.1" + axios "^1.6.7" lodash "^4.17.21" -"@openzeppelin/defender-sdk-network-client@^1.3.0": - version "1.3.0" - resolved "https://registry.yarnpkg.com/@openzeppelin/defender-sdk-network-client/-/defender-sdk-network-client-1.3.0.tgz#6ec7b8180a43ce5d2f02f814dc178ab033769e44" - integrity sha512-GNDCH6b0KV0rNOVqxWDeKumEsvPGQAFih6XrOV2kU/AJWhtzLfRngvhaphB/Dv6wbCopo3e+8I8UN4PSC9+vEQ== +"@openzeppelin/defender-sdk-action-client@^1.13.1": + version "1.13.1" + resolved "https://registry.yarnpkg.com/@openzeppelin/defender-sdk-action-client/-/defender-sdk-action-client-1.13.1.tgz#13b300f033c05244d5f24c347ec6b58f8f07337e" + integrity sha512-iJC/wmE+GgbUdB74248Rw6YSgSld+/gKDf4rrKGzmKpxxxrB6Ro65QE9IxeJS3bWdy5snEEEaZnJGOsZSXqBlQ== dependencies: - "@ethersproject/abi" "^5.6.3" - "@openzeppelin/defender-sdk-base-client" "^1.3.0" - axios "^1.4.0" + "@openzeppelin/defender-sdk-base-client" "^1.13.1" + axios "^1.6.7" + dotenv "^16.3.1" + glob "^7.1.6" + jszip "^3.10.1" lodash "^4.17.21" -"@openzeppelin/defender-sdk-notification-channel-client@^1.3.0": - version "1.3.0" - resolved "https://registry.yarnpkg.com/@openzeppelin/defender-sdk-notification-channel-client/-/defender-sdk-notification-channel-client-1.3.0.tgz#cbff26029c92d20275a079e2b1e81f8a694f86df" - integrity sha512-W5YrxB9nLXavtdVUpvgepXhBKLvJcJMcbWDs78/gpvLicKbpTXD0V1Vg9UjSstGUbOeU9yOqYSIzDqj6+cgq3Q== +"@openzeppelin/defender-sdk-base-client@^1.13.1": + version "1.13.1" + resolved "https://registry.yarnpkg.com/@openzeppelin/defender-sdk-base-client/-/defender-sdk-base-client-1.13.1.tgz#da1631f5bc943859c70740865954ffdadc308d44" + integrity sha512-FI7YdfgDf0px+cXbXyDkS0mpqzyySHeLkKj90ymzAy1/sGYKHNC03vyzMnMfIRuxa4bF15wdL4MCpA60PSWGpQ== dependencies: - "@ethersproject/abi" "^5.6.3" - "@openzeppelin/defender-sdk-base-client" "^1.3.0" - axios "^1.4.0" + amazon-cognito-identity-js "^6.3.6" + async-retry "^1.3.3" + +"@openzeppelin/defender-sdk-deploy-client@^1.13.1": + version "1.13.1" + resolved "https://registry.yarnpkg.com/@openzeppelin/defender-sdk-deploy-client/-/defender-sdk-deploy-client-1.13.1.tgz#2840a37eceb9adae327f2f427533d1b9f7a886a8" + integrity sha512-zQEoURBRMknrOXLDNzK3gXiHfQbDImLKtEVPBOybya/MYqququBdNkRmPpSkJ45LHVbuxWyqRkkGFQp8+l/UQg== + dependencies: + "@openzeppelin/defender-sdk-base-client" "^1.13.1" + axios "^1.6.7" lodash "^4.17.21" -"@openzeppelin/defender-sdk-proposal-client@^1.3.0": - version "1.3.0" - resolved "https://registry.yarnpkg.com/@openzeppelin/defender-sdk-proposal-client/-/defender-sdk-proposal-client-1.3.0.tgz#cbcad0200b262d28234c6c45ef344050365f5704" - integrity sha512-IO2ZLgYshboBB0GCURM4APaePQIjOgTEgFchik612sk41VfGfIV7Ei/r0EllNVHS4385mMH2qWe/fK6isseBzQ== +"@openzeppelin/defender-sdk-monitor-client@^1.13.1": + version "1.13.1" + resolved "https://registry.yarnpkg.com/@openzeppelin/defender-sdk-monitor-client/-/defender-sdk-monitor-client-1.13.1.tgz#06323434efe79ac6b09075e51ff7295653d31fa2" + integrity sha512-3j6aj/fBc7/g5KDlRJ5epMO9f5W4R2PJGtNxsXWDYnX+7mXVR9uH+eKuCeGHBi9jWeYN3Je3UaapD0fZnrj8kA== dependencies: - "@openzeppelin/defender-sdk-base-client" "^1.3.0" - axios "^1.4.0" - ethers "^5.7.2" + "@openzeppelin/defender-sdk-base-client" "^1.13.1" + axios "^1.6.7" + ethers "^6.9.0" lodash "^4.17.21" -"@openzeppelin/defender-sdk-relay-client@^1.3.0": - version "1.3.0" - resolved "https://registry.yarnpkg.com/@openzeppelin/defender-sdk-relay-client/-/defender-sdk-relay-client-1.3.0.tgz#1eadb1f2ff2f8cb56a28c3ce82d9e86b0d73739d" - integrity sha512-PhvIcy1kRM+KHSILRPLAs3CKs44VsVkx966L//52jS8b38DW3XJTdmpCNGWUCg2BRIV4qFv13BXO4qXd3u6/1g== +"@openzeppelin/defender-sdk-network-client@^1.13.1": + version "1.13.1" + resolved "https://registry.yarnpkg.com/@openzeppelin/defender-sdk-network-client/-/defender-sdk-network-client-1.13.1.tgz#6ce269bedcd3074bc14e6a9d15280c2a892e9beb" + integrity sha512-QR9dTZ6MuJ5o+GwAKH4Hxy+xuElI0iCwpVqN/ntHG0Ar7neHoq/f7jPtk04/DgEmrwTUMLzTKpZWmUO1fxiEMA== dependencies: - "@openzeppelin/defender-sdk-base-client" "^1.3.0" - axios "^1.4.0" + "@openzeppelin/defender-sdk-base-client" "^1.13.1" + axios "^1.6.7" lodash "^4.17.21" -"@openzeppelin/defender-sdk-relay-signer-client@^1.3.0": - version "1.3.0" - resolved "https://registry.yarnpkg.com/@openzeppelin/defender-sdk-relay-signer-client/-/defender-sdk-relay-signer-client-1.3.0.tgz#2fc0448bebc60a08af4ca7a7e14b4ee6b4d681a4" - integrity sha512-aVBvZUy3TS1WcRykcFKd1sjO+LcDQP5kxKLovwb+JFuAqigsEoiJRZktnI5zFRzHs4wfuzOUPfbPcNW89mvNVw== +"@openzeppelin/defender-sdk-notification-channel-client@^1.13.1": + version "1.13.1" + resolved "https://registry.yarnpkg.com/@openzeppelin/defender-sdk-notification-channel-client/-/defender-sdk-notification-channel-client-1.13.1.tgz#370d6737c4bdf6b038e0411bc5bd90e4a529b244" + integrity sha512-jCMIm7b89QzBA3ZN4iCYrPk+Km95F2D1l+t1ymA3lVdD1Ds97dMeYk2gMkNRQphS+7NLBmItOFv9tyrk7WmY/w== dependencies: - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/contracts" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/networks" "^5.7.1" - "@ethersproject/properties" "^5.7.0" - "@ethersproject/random" "^5.7.0" - "@ethersproject/strings" "^5.7.0" - "@openzeppelin/defender-sdk-base-client" "^1.3.0" - amazon-cognito-identity-js "^6.0.1" - axios "^1.4.0" + "@openzeppelin/defender-sdk-base-client" "^1.13.1" + axios "^1.6.7" lodash "^4.17.21" -"@openzeppelin/defender-sdk@^1.3.0": - version "1.3.0" - resolved "https://registry.yarnpkg.com/@openzeppelin/defender-sdk/-/defender-sdk-1.3.0.tgz#6b9f9d918081122504bf7c00a592226c96cc1772" - integrity sha512-bP3pInKR/JvAemGFaGB8z1cBJT88uQYID9X82jtphGLfnl8hjWjtLMej+F0X6JcJoY1F/8c0/7Q51vdPXaUE7Q== - dependencies: - "@openzeppelin/defender-sdk-action-client" "^1.3.0" - "@openzeppelin/defender-sdk-base-client" "^1.3.0" - "@openzeppelin/defender-sdk-deploy-client" "^1.3.0" - "@openzeppelin/defender-sdk-monitor-client" "^1.3.0" - "@openzeppelin/defender-sdk-network-client" "^1.3.0" - "@openzeppelin/defender-sdk-notification-channel-client" "^1.3.0" - "@openzeppelin/defender-sdk-proposal-client" "^1.3.0" - "@openzeppelin/defender-sdk-relay-client" "^1.3.0" - "@openzeppelin/defender-sdk-relay-signer-client" "^1.3.0" +"@openzeppelin/defender-sdk-proposal-client@^1.13.1": + version "1.13.1" + resolved "https://registry.yarnpkg.com/@openzeppelin/defender-sdk-proposal-client/-/defender-sdk-proposal-client-1.13.1.tgz#8249fd9143831a8270146558d772bb7f0b8148fd" + integrity sha512-2VHYqY1vOET90EWJhmaCHb53Lw6r9vren6Q9VM5xbtM7qXGwe3EedfR5MrWjWaqgt/QjbHkO6JtWR0rVkn7vaQ== + dependencies: + "@openzeppelin/defender-sdk-base-client" "^1.13.1" + axios "^1.6.7" + ethers "^6.9.0" + lodash "^4.17.21" + +"@openzeppelin/defender-sdk-relay-client@^1.13.1": + version "1.13.1" + resolved "https://registry.yarnpkg.com/@openzeppelin/defender-sdk-relay-client/-/defender-sdk-relay-client-1.13.1.tgz#83b0fa1a24a8c2e6127b5ef5bcfe262e745524f6" + integrity sha512-oSHATNIXPvSSwkPMrCzj4FJmDx+NbderRoz8rmUd8rHNrVOcqyB8AEK6jYa1nkLRiLgsET/xXtvIL4C8bPrpkg== + dependencies: + "@openzeppelin/defender-sdk-base-client" "^1.13.1" + axios "^1.6.7" + lodash "^4.17.21" + +"@openzeppelin/defender-sdk-relay-signer-client@^1.13.1": + version "1.13.1" + resolved "https://registry.yarnpkg.com/@openzeppelin/defender-sdk-relay-signer-client/-/defender-sdk-relay-signer-client-1.13.1.tgz#0ecca4858fce84ba904ba589f825329a04780671" + integrity sha512-+E9j621OtQn6AlXCdPckpltOw6cz8NDPHovyhVpDDAO1fp8JIjoDHl9L41PXoMHeeYj82Ex/HLNzLcL+igPaNQ== + dependencies: + "@openzeppelin/defender-sdk-base-client" "^1.13.1" + amazon-cognito-identity-js "^6.3.6" + axios "^1.6.7" + ethers "^6.9.0" + lodash "^4.17.21" + +"@openzeppelin/defender-sdk@^1.13.1": + version "1.13.1" + resolved "https://registry.yarnpkg.com/@openzeppelin/defender-sdk/-/defender-sdk-1.13.1.tgz#178ecaae358929a050720687975f852a0c2e5d71" + integrity sha512-GC3pCqtuG82z4cfGo8ze3sAFM2gwWv/1Do/HPtH4f+a8jTbNXpHqWIQXQ+9Utsq36reVsC60pBeQHUuHvumpyg== + dependencies: + "@openzeppelin/defender-sdk-account-client" "^1.13.1" + "@openzeppelin/defender-sdk-action-client" "^1.13.1" + "@openzeppelin/defender-sdk-base-client" "^1.13.1" + "@openzeppelin/defender-sdk-deploy-client" "^1.13.1" + "@openzeppelin/defender-sdk-monitor-client" "^1.13.1" + "@openzeppelin/defender-sdk-network-client" "^1.13.1" + "@openzeppelin/defender-sdk-notification-channel-client" "^1.13.1" + "@openzeppelin/defender-sdk-proposal-client" "^1.13.1" + "@openzeppelin/defender-sdk-relay-client" "^1.13.1" + "@openzeppelin/defender-sdk-relay-signer-client" "^1.13.1" "@openzeppelin/hardhat-upgrades@^1.10.0": version "1.27.0" @@ -1225,6 +1294,46 @@ path-browserify "^1.0.0" url "^0.11.0" +"@rollup/plugin-commonjs@^25.0.7": + version "25.0.7" + resolved "https://registry.yarnpkg.com/@rollup/plugin-commonjs/-/plugin-commonjs-25.0.7.tgz#145cec7589ad952171aeb6a585bbeabd0fd3b4cf" + integrity sha512-nEvcR+LRjEjsaSsc4x3XZfCCvZIaSMenZu/OiwOKGN2UhQpAYI7ru7czFvyWbErlpoGjnSX3D5Ch5FcMA3kRWQ== + dependencies: + "@rollup/pluginutils" "^5.0.1" + commondir "^1.0.1" + estree-walker "^2.0.2" + glob "^8.0.3" + is-reference "1.2.1" + magic-string "^0.30.3" + +"@rollup/plugin-json@^6.1.0": + version "6.1.0" + resolved "https://registry.yarnpkg.com/@rollup/plugin-json/-/plugin-json-6.1.0.tgz#fbe784e29682e9bb6dee28ea75a1a83702e7b805" + integrity sha512-EGI2te5ENk1coGeADSIwZ7G2Q8CJS2sF120T7jLw4xFw9n7wIOXHo+kIYRAoVpJAN+kmqZSoO3Fp4JtoNF4ReA== + dependencies: + "@rollup/pluginutils" "^5.1.0" + +"@rollup/plugin-node-resolve@^15.2.3": + version "15.2.3" + resolved "https://registry.yarnpkg.com/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.2.3.tgz#e5e0b059bd85ca57489492f295ce88c2d4b0daf9" + integrity sha512-j/lym8nf5E21LwBT4Df1VD6hRO2L2iwUeUmP7litikRsVp1H6NWx20NEp0Y7su+7XGc476GnXXc4kFeZNGmaSQ== + dependencies: + "@rollup/pluginutils" "^5.0.1" + "@types/resolve" "1.20.2" + deepmerge "^4.2.2" + is-builtin-module "^3.2.1" + is-module "^1.0.0" + resolve "^1.22.1" + +"@rollup/pluginutils@^5.0.1", "@rollup/pluginutils@^5.1.0": + version "5.1.0" + resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-5.1.0.tgz#7e53eddc8c7f483a4ad0b94afb1f7f5fd3c771e0" + integrity sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g== + dependencies: + "@types/estree" "^1.0.0" + estree-walker "^2.0.2" + picomatch "^2.3.1" + "@scure/base@~1.1.0": version "1.1.1" resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.1.1.tgz#ebb651ee52ff84f420097055f4bf46cfba403938" @@ -1459,6 +1568,11 @@ dependencies: "@types/node" "*" +"@types/estree@*", "@types/estree@^1.0.0": + version "1.0.5" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.5.tgz#a6ce3e556e00fd9895dd872dd172ad0d4bd687f4" + integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw== + "@types/figlet@^1.5.4": version "1.5.8" resolved "https://registry.yarnpkg.com/@types/figlet/-/figlet-1.5.8.tgz#96b8186c7e2a388b4f8d09ee3276cba2af88bb0b" @@ -1540,6 +1654,11 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-11.11.6.tgz#df929d1bb2eee5afdda598a41930fe50b43eaa6a" integrity sha512-Exw4yUWMBXM3X+8oqzJNRqZSwUAaS4+7NdvHqQuFi/d+synz++xmX3QIf+BFqneW8N31R8Ky+sikfZUXq07ggQ== +"@types/node@18.15.13": + version "18.15.13" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.15.13.tgz#f64277c341150c979e42b00e4ac289290c9df469" + integrity sha512-N+0kuo9KgrUQ1Sn/ifDXsvg0TTleP7rIy4zOBGECxAljqvqfqpTfzx0Q1NUedOixRMBfe2Whhb056a42cWs26Q== + "@types/node@^10.0.3": version "10.17.60" resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.60.tgz#35f3d6213daed95da7f0f73e75bcc6980e90597b" @@ -1585,6 +1704,11 @@ "@types/node" "*" safe-buffer "~5.1.1" +"@types/resolve@1.20.2": + version "1.20.2" + resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-1.20.2.tgz#97d26e00cd4a0423b4af620abecf3e6f442b7975" + integrity sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q== + "@types/responselike@^1.0.0": version "1.0.3" resolved "https://registry.yarnpkg.com/@types/responselike/-/responselike-1.0.3.tgz#cc29706f0a397cfe6df89debfe4bf5cea159db50" @@ -1759,6 +1883,11 @@ aes-js@3.0.0: resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-3.0.0.tgz#e21df10ad6c2053295bcbb8dab40b09dbea87e4d" integrity sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw== +aes-js@4.0.0-beta.5: + version "4.0.0-beta.5" + resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-4.0.0-beta.5.tgz#8d2452c52adedebc3a3e28465d858c11ca315873" + integrity sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q== + aes-js@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-3.1.2.tgz#db9aabde85d5caabbfc0d4f2a4446960f627146a" @@ -1799,21 +1928,21 @@ ajv@^8.0.1: require-from-string "^2.0.2" uri-js "^4.2.2" -amazon-cognito-identity-js@^4.3.3: - version "4.6.3" - resolved "https://registry.yarnpkg.com/amazon-cognito-identity-js/-/amazon-cognito-identity-js-4.6.3.tgz#889410379a5fc5e883edc95f4ce233cc628e354c" - integrity sha512-MPVJfirbdmSGo7l4h7Kbn3ms1eJXT5Xq8ly+mCPPi8yAxaxdg7ouMUUNTqtDykoZxIdDLF/P6F3Zbg3dlGKOWg== +amazon-cognito-identity-js@^6.0.1: + version "6.2.0" + resolved "https://registry.yarnpkg.com/amazon-cognito-identity-js/-/amazon-cognito-identity-js-6.2.0.tgz#99e96666944429cb8f67b62e4cf7ad77fbe71ad0" + integrity sha512-9Fxrp9+MtLdsJvqOwSaE3ll+pneICeuE3pwj2yDkiyGNWuHx97b8bVLR2bOgfDmDJnY0Hq8QoeXtwdM4aaXJjg== dependencies: + "@aws-crypto/sha256-js" "1.2.2" buffer "4.9.2" - crypto-js "^4.0.0" fast-base64-decode "^1.0.0" isomorphic-unfetch "^3.0.0" js-cookie "^2.2.1" -amazon-cognito-identity-js@^6.0.1: - version "6.2.0" - resolved "https://registry.yarnpkg.com/amazon-cognito-identity-js/-/amazon-cognito-identity-js-6.2.0.tgz#99e96666944429cb8f67b62e4cf7ad77fbe71ad0" - integrity sha512-9Fxrp9+MtLdsJvqOwSaE3ll+pneICeuE3pwj2yDkiyGNWuHx97b8bVLR2bOgfDmDJnY0Hq8QoeXtwdM4aaXJjg== +amazon-cognito-identity-js@^6.3.6: + version "6.3.12" + resolved "https://registry.yarnpkg.com/amazon-cognito-identity-js/-/amazon-cognito-identity-js-6.3.12.tgz#af73df033094ad4c679c19cf6122b90058021619" + integrity sha512-s7NKDZgx336cp+oDeUtB2ZzT8jWJp/v2LWuYl+LQtMEODe22RF1IJ4nRiDATp+rp1pTffCZcm44Quw4jx2bqNg== dependencies: "@aws-crypto/sha256-js" "1.2.2" buffer "4.9.2" @@ -2097,6 +2226,15 @@ axios@^1.4.0: form-data "^4.0.0" proxy-from-env "^1.1.0" +axios@^1.6.7: + version "1.7.1" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.1.tgz#522145622a09dfaf49359837db9649ff245a35b9" + integrity sha512-+LV37nQcd1EpFalkXksWNBiA17NZ5m5/WspmHGmZmdx1qBOg/VNq/c4eRJiA9VQQHBOs+N0ZhhdU10h2TyNK7Q== + dependencies: + follow-redirects "^1.15.6" + form-data "^4.0.0" + proxy-from-env "^1.1.0" + balanced-match@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" @@ -2398,6 +2536,11 @@ builtin-modules@^1.1.1: resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" integrity sha512-wxXCdllwGhI2kCC0MnvTGYTMvnVZTvqgypkiTI8Pa5tcz2i6VqsqwYGgqwXji+4RgCzms6EajE4IxiUH6HH8nQ== +builtin-modules@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.3.0.tgz#cae62812b89801e9656336e46223e030386be7b6" + integrity sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw== + busboy@^1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/busboy/-/busboy-1.6.0.tgz#966ea36a9502e43cdb9146962523b92f531f6893" @@ -2812,6 +2955,11 @@ commander@^8.1.0: resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66" integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww== +commondir@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" + integrity sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg== + compare-versions@^5.0.0: version "5.0.3" resolved "https://registry.yarnpkg.com/compare-versions/-/compare-versions-5.0.3.tgz#a9b34fea217472650ef4a2651d905f42c28ebfd7" @@ -3001,11 +3149,6 @@ crypto-browserify@3.12.0: randombytes "^2.0.0" randomfill "^1.0.3" -crypto-js@^4.0.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/crypto-js/-/crypto-js-4.2.0.tgz#4d931639ecdfd12ff80e8186dba6af2c2e856631" - integrity sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q== - crypto@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/crypto/-/crypto-1.0.1.tgz#2af1b7cad8175d24c8a1b0778255794a21803037" @@ -3105,16 +3248,10 @@ deep-is@^0.1.3, deep-is@~0.1.3: resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== -defender-base-client@1.38.1-rc.0: - version "1.38.1-rc.0" - resolved "https://registry.yarnpkg.com/defender-base-client/-/defender-base-client-1.38.1-rc.0.tgz#0d167845648a38bd2f5f80f5c50e081ec5f58b54" - integrity sha512-LNsuop5CE7fYyfWV3C4tlqkZawnxsMKW1SeF8TnobhZ6V5pO9LKyGSOo/V3KvPhO2/cTw5/S66+p1f6nkGCREA== - dependencies: - amazon-cognito-identity-js "^4.3.3" - async-retry "^1.3.3" - axios "^0.21.2" - lodash "^4.17.19" - node-fetch "^2.6.0" +deepmerge@^4.2.2: + version "4.3.1" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a" + integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A== defender-base-client@^1.44.0: version "1.44.0" @@ -3127,17 +3264,6 @@ defender-base-client@^1.44.0: lodash "^4.17.19" node-fetch "^2.6.0" -defender-kvstore-client@^1.38.1-rc.0: - version "1.38.1-rc.0" - resolved "https://registry.yarnpkg.com/defender-kvstore-client/-/defender-kvstore-client-1.38.1-rc.0.tgz#6e33633a90e1355893141bad72298c6727abf30d" - integrity sha512-MeN8CtQSY72QFIys56Phxcn3tQ1nnmDXVtP/RlY9HCMynUO4zOQZaanDkgUmXTb+MYMj5VO3y+qfOfdEE+5EWA== - dependencies: - axios "^0.21.2" - defender-base-client "1.38.1-rc.0" - fs-extra "^10.0.0" - lodash "^4.17.19" - node-fetch "^2.6.0" - defer-to-connect@^1.0.1: version "1.1.3" resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-1.1.3.tgz#331ae050c08dcf789f8c83a7b81f0ed94f4ac591" @@ -3268,6 +3394,11 @@ dotenv@^10.0.0: resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-10.0.0.tgz#3d4227b8fb95f81096cdd2b66653fb2c7085ba81" integrity sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q== +dotenv@^16.3.1: + version "16.4.5" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.4.5.tgz#cdd3b3b604cb327e286b4762e13502f717cb099f" + integrity sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg== + duplexer3@^0.1.4: version "0.1.5" resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.5.tgz#0b5e4d7bad5de8901ea4440624c8e1d20099217e" @@ -3729,6 +3860,11 @@ estraverse@^5.1.0, estraverse@^5.2.0: resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== +estree-walker@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac" + integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w== + esutils@^2.0.2: version "2.0.3" resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" @@ -3972,6 +4108,19 @@ ethers@^5.4.6, ethers@^5.5.3, ethers@^5.6.1, ethers@^5.7.1, ethers@^5.7.2: "@ethersproject/web" "5.7.1" "@ethersproject/wordlists" "5.7.0" +ethers@^6.9.0: + version "6.12.1" + resolved "https://registry.yarnpkg.com/ethers/-/ethers-6.12.1.tgz#517ff6d66d4fd5433e38e903051da3e57c87ff37" + integrity sha512-j6wcVoZf06nqEcBbDWkKg8Fp895SS96dSnTCjiXT+8vt2o02raTn4Lo9ERUuIVU5bAjoPYeA+7ytQFexFmLuVw== + dependencies: + "@adraffy/ens-normalize" "1.10.1" + "@noble/curves" "1.2.0" + "@noble/hashes" "1.3.2" + "@types/node" "18.15.13" + aes-js "4.0.0-beta.5" + tslib "2.4.0" + ws "8.5.0" + ethjs-unit@0.1.6: version "0.1.6" resolved "https://registry.yarnpkg.com/ethjs-unit/-/ethjs-unit-0.1.6.tgz#c665921e476e87bce2a9d588a6fe0405b2c41699" @@ -4256,6 +4405,11 @@ follow-redirects@^1.12.1, follow-redirects@^1.14.0, follow-redirects@^1.15.0: resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13" integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA== +follow-redirects@^1.15.6: + version "1.15.6" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.6.tgz#7f815c0cda4249c74ff09e95ef97c23b5fd0399b" + integrity sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA== + for-each@^0.3.3: version "0.3.3" resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" @@ -5283,6 +5437,13 @@ is-buffer@^2.0.5, is-buffer@~2.0.3: resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.5.tgz#ebc252e400d22ff8d77fa09888821a24a658c191" integrity sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ== +is-builtin-module@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-3.2.1.tgz#f03271717d8654cfcaf07ab0463faa3571581169" + integrity sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A== + dependencies: + builtin-modules "^3.3.0" + is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.7: version "1.2.7" resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" @@ -5353,6 +5514,11 @@ is-hex-prefixed@1.0.0: resolved "https://registry.yarnpkg.com/is-hex-prefixed/-/is-hex-prefixed-1.0.0.tgz#7d8d37e6ad77e5d127148913c573e082d777f554" integrity sha512-WvtOiug1VFrE9v1Cydwm+FnXd3+w9GaeVUss5W4v/SLy3UW00vP+6iNF2SdnfiBoLy4bTqVdkftNGTUeOFVsbA== +is-module@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-module/-/is-module-1.0.0.tgz#3258fb69f78c14d5b815d664336b4cffb6441591" + integrity sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g== + is-nan@^1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/is-nan/-/is-nan-1.3.2.tgz#043a54adea31748b55b6cd4e09aadafa69bd9e1d" @@ -5383,6 +5549,13 @@ is-plain-obj@^2.1.0: resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== +is-reference@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/is-reference/-/is-reference-1.2.1.tgz#8b2dac0b371f4bc994fdeaba9eb542d03002d0b7" + integrity sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ== + dependencies: + "@types/estree" "*" + is-regex@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" @@ -5633,7 +5806,7 @@ jsprim@^1.2.2: json-schema "0.4.0" verror "1.10.0" -jszip@^3.8.0: +jszip@^3.10.1, jszip@^3.5.0: version "3.10.1" resolved "https://registry.yarnpkg.com/jszip/-/jszip-3.10.1.tgz#34aee70eb18ea1faec2f589208a157d1feb091c2" integrity sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g== @@ -5950,6 +6123,13 @@ ltgt@~2.2.0: resolved "https://registry.yarnpkg.com/ltgt/-/ltgt-2.2.1.tgz#f35ca91c493f7b73da0e07495304f17b31f87ee5" integrity sha512-AI2r85+4MquTw9ZYqabu4nMwy9Oftlfa/e/52t9IjtfG+mGBbTNdAoZ3RQKLHR6r0wQnwZnPIEh/Ya6XTWAKNA== +magic-string@^0.30.3: + version "0.30.10" + resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.10.tgz#123d9c41a0cb5640c892b041d4cfb3bd0aa4b39e" + integrity sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ== + dependencies: + "@jridgewell/sourcemap-codec" "^1.4.15" + markdown-table@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/markdown-table/-/markdown-table-1.1.3.tgz#9fcb69bcfdb8717bfd0398c6ec2d93036ef8de60" @@ -7241,7 +7421,7 @@ resolve@^1.1.6: path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" -resolve@^1.3.2: +resolve@^1.22.1, resolve@^1.3.2: version "1.22.8" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== @@ -8226,6 +8406,11 @@ ts-essentials@^7.0.1: resolved "https://registry.yarnpkg.com/ts-essentials/-/ts-essentials-7.0.3.tgz#686fd155a02133eedcc5362dc8b5056cde3e5a38" integrity sha512-8+gr5+lqO3G84KdiTSMRLtuyJ+nTBVRKuCrK4lidMPdVeEp0uqC875uE5NMcaA7YYMN7XsNiFQuMvasF8HT/xQ== +tslib@2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3" + integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== + tslib@^1.11.1, tslib@^1.13.0, tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3: version "1.14.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" @@ -9180,6 +9365,11 @@ ws@7.4.6: resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.6.tgz#5654ca8ecdeee47c33a9a4bf6d28e2be2980377c" integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A== +ws@8.5.0: + version "8.5.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.5.0.tgz#bfb4be96600757fe5382de12c670dab984a1ed4f" + integrity sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg== + ws@^3.0.0: version "3.3.3" resolved "https://registry.yarnpkg.com/ws/-/ws-3.3.3.tgz#f1cf84fe2d5e901ebce94efaece785f187a228f2" From c4456b92013797d8dc1441bb336f03e420b13e43 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Thu, 23 May 2024 12:16:05 +1000 Subject: [PATCH 086/273] Output more contract details in 097 deploy script --- .../deploy/mainnet/097_native_ssv_staking.js | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/contracts/deploy/mainnet/097_native_ssv_staking.js b/contracts/deploy/mainnet/097_native_ssv_staking.js index c1258b4dd6..dd3de4663e 100644 --- a/contracts/deploy/mainnet/097_native_ssv_staking.js +++ b/contracts/deploy/mainnet/097_native_ssv_staking.js @@ -148,12 +148,23 @@ module.exports = deploymentWithGovernanceProposal( const dOETHHarvesterImpl = await ethers.getContract("OETHHarvester"); console.log( - "Native Staking SSV Strategy address: ", + "Native Staking SSV Strategy proxy: ", cStrategyProxy.address ); - console.log("Fee accumulator address: ", cFeeAccumulator.address); console.log( - "New OETHHarvester implementation address: ", + "Native Staking SSV Strategy implementation: ", + dStrategyImpl.address + ); + console.log( + "Fee accumulator proxy: ", + cFeeAccumulatorProxy.address + ); + console.log( + "Fee accumulator implementation: ", + cFeeAccumulator.address + ); + console.log( + "New OETHHarvester implementation: ", dOETHHarvesterImpl.address ); From c1922b65c199f801e81f748cb6ad643d246d8cfd Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Thu, 23 May 2024 13:15:58 +1000 Subject: [PATCH 087/273] Added claimWithdrawals to OETHVaultCore --- contracts/contracts/interfaces/IVault.sol | 47 +++++++++++++-------- contracts/contracts/vault/OETHVaultCore.sol | 33 +++++++++++++-- 2 files changed, 59 insertions(+), 21 deletions(-) diff --git a/contracts/contracts/interfaces/IVault.sol b/contracts/contracts/interfaces/IVault.sol index aa30fb3d60..a764b66c87 100644 --- a/contracts/contracts/interfaces/IVault.sol +++ b/contracts/contracts/interfaces/IVault.sol @@ -86,10 +86,8 @@ interface IVault { function setSwapAllowedUndervalue(uint16 _percentageBps) external; - function setOracleSlippage( - address _asset, - uint16 _allowedOracleSlippageBps - ) external; + function setOracleSlippage(address _asset, uint16 _allowedOracleSlippageBps) + external; function supportAsset(address _asset, uint8 _supportsAsset) external; @@ -97,14 +95,13 @@ interface IVault { function removeStrategy(address _addr) external; - function setAssetDefaultStrategy( - address _asset, - address _strategy - ) external; + function setAssetDefaultStrategy(address _asset, address _strategy) + external; - function assetDefaultStrategies( - address _asset - ) external view returns (address); + function assetDefaultStrategies(address _asset) + external + view + returns (address); function pauseRebase() external; @@ -171,15 +168,17 @@ interface IVault { function checkBalance(address _asset) external view returns (uint256); - function calculateRedeemOutputs( - uint256 _amount - ) external view returns (uint256[] memory); + function calculateRedeemOutputs(uint256 _amount) + external + view + returns (uint256[] memory); function getAssetCount() external view returns (uint256); - function getAssetConfig( - address _asset - ) external view returns (VaultStorage.Asset memory config); + function getAssetConfig(address _asset) + external + view + returns (VaultStorage.Asset memory config); function getAllAssets() external view returns (address[] memory); @@ -215,6 +214,18 @@ interface IVault { function removeAsset(address _asset) external; - // This is an OETH specific function + // 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); } diff --git a/contracts/contracts/vault/OETHVaultCore.sol b/contracts/contracts/vault/OETHVaultCore.sol index 54f74d1367..bd17a1cb30 100644 --- a/contracts/contracts/vault/OETHVaultCore.sol +++ b/contracts/contracts/vault/OETHVaultCore.sol @@ -200,6 +200,36 @@ contract OETHVaultCore is VaultCore { whenNotCapitalPaused nonReentrant returns (uint256 amount) + { + amount = _claimWithdrawal(requestId); + + // transfer WETH from the vault to the withdrawer + IERC20(weth).safeTransfer(msg.sender, amount); + } + + /** + * @notice Claim a previously requested withdrawals once they are claimable. + * @param requestIds Unique ID of each withdrawal request + * @return amounts Amount of WETH received for each request + */ + function claimWithdrawals(uint256[] memory requestIds) + external + whenNotCapitalPaused + nonReentrant + returns (uint256[] memory amounts, uint256 totalAmount) + { + 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); + } + + function _claimWithdrawal(uint256 requestId) + internal + returns (uint256 amount) { // Check if there's enough liquidity to cover the withdrawal request WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata; @@ -216,9 +246,6 @@ contract OETHVaultCore is VaultCore { emit WithdrawalClaimed(msg.sender, requestId, request.amount); - // transfer WETH from the vault to the withdrawer - IERC20(weth).safeTransfer(msg.sender, request.amount); - return request.amount; } From 06430349eea2ea350e58f9601c442868b35363a9 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Thu, 23 May 2024 13:30:00 +1000 Subject: [PATCH 088/273] prettier --- .../deploy/mainnet/097_native_ssv_staking.js | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/contracts/deploy/mainnet/097_native_ssv_staking.js b/contracts/deploy/mainnet/097_native_ssv_staking.js index dd3de4663e..70503d6891 100644 --- a/contracts/deploy/mainnet/097_native_ssv_staking.js +++ b/contracts/deploy/mainnet/097_native_ssv_staking.js @@ -147,22 +147,13 @@ module.exports = deploymentWithGovernanceProposal( ]); const dOETHHarvesterImpl = await ethers.getContract("OETHHarvester"); - console.log( - "Native Staking SSV Strategy proxy: ", - cStrategyProxy.address - ); + console.log("Native Staking SSV Strategy proxy: ", cStrategyProxy.address); console.log( "Native Staking SSV Strategy implementation: ", dStrategyImpl.address ); - console.log( - "Fee accumulator proxy: ", - cFeeAccumulatorProxy.address - ); - console.log( - "Fee accumulator implementation: ", - cFeeAccumulator.address - ); + console.log("Fee accumulator proxy: ", cFeeAccumulatorProxy.address); + console.log("Fee accumulator implementation: ", cFeeAccumulator.address); console.log( "New OETHHarvester implementation: ", dOETHHarvesterImpl.address From a50f2d29bbcebd8fc1048bcd7dabac3dc178f1a5 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Thu, 23 May 2024 14:02:31 +1000 Subject: [PATCH 089/273] Add getting WETH from Dripper on mints over rebaseThreshold claimWithdrawal collects from Dripper and adds any unallocated WETH to the withdrawal queue if not enough liquidity available --- contracts/contracts/vault/OETHVaultCore.sol | 22 +++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/contracts/contracts/vault/OETHVaultCore.sol b/contracts/contracts/vault/OETHVaultCore.sol index bd17a1cb30..175fb6fed4 100644 --- a/contracts/contracts/vault/OETHVaultCore.sol +++ b/contracts/contracts/vault/OETHVaultCore.sol @@ -7,6 +7,7 @@ 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 { IStrategy } from "../interfaces/IStrategy.sol"; +import { IDripper } from "../interfaces/IDripper.sol"; /** * @title OETH VaultCore Contract @@ -57,6 +58,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(); } @@ -235,10 +239,20 @@ contract OETHVaultCore is VaultCore { WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata; WithdrawalRequest memory request = withdrawalRequests[requestId]; - require(request.queued <= queue.claimable, "pending liquidity"); require(request.claimed == false, "already claimed"); require(request.withdrawer == msg.sender, "not requester"); + // Try and get more liquidity in the withdrawal queue if there is not enough + if (request.queued > queue.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(); + } + // If there still isn't enough liquidity in the queue to claim, revert + require(request.queued <= queue.claimable, "pending liquidity"); + // Store the updated claimed amount withdrawalQueueMetadata.claimed = queue.claimed + request.amount; // Store the request as claimed @@ -249,9 +263,13 @@ contract OETHVaultCore is VaultCore { return request.amount; } - /// @notice Adds any unallocated WETH to the withdrawal queue if there is a funding shortfall. + /// @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. function addWithdrawalQueueLiquidity() external { + // Stream any harvested rewards (WETH) that are available to the Vault + IDripper(dripper).collect(); + _addWithdrawalQueueLiquidity(); } From 82b4fd193e975bf21574b83adfdff48c2ed84124 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Thu, 23 May 2024 18:43:06 +1000 Subject: [PATCH 090/273] Restricted OETH's depositToStrategy to only deposit WETH depositToStrategy only deposits WETH not allocated to the withdrawal queue swapCollateral restricted to only swap to WETH swapCollateral adds to withdrawal queue after swap --- contracts/contracts/vault/OETHVaultAdmin.sol | 75 ++++++++++++++++++- contracts/contracts/vault/OETHVaultCore.sol | 6 +- contracts/contracts/vault/VaultAdmin.sol | 18 ++++- contracts/contracts/vault/VaultStorage.sol | 1 + .../deploy/mainnet/097_withdraw_queue.js | 2 +- contracts/test/_hot-deploy.js | 1 + .../balancerMetaStablePool.fork-test.js | 34 +-------- 7 files changed, 101 insertions(+), 36 deletions(-) diff --git a/contracts/contracts/vault/OETHVaultAdmin.sol b/contracts/contracts/vault/OETHVaultAdmin.sol index 0b028bd6a6..f78cc38bca 100644 --- a/contracts/contracts/vault/OETHVaultAdmin.sol +++ b/contracts/contracts/vault/OETHVaultAdmin.sol @@ -1,14 +1,51 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import { VaultAdmin } from "./VaultAdmin.sol"; +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"; /** * @title OETH VaultAdmin Contract * @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, @@ -36,4 +73,40 @@ contract OETHVaultAdmin is VaultAdmin { IVault(address(this)).addWithdrawalQueueLiquidity(); } + + // TODO move to a library? + function _wethAvailable() internal view returns (uint256 wethAvailable) { + WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata; + + // Check if the claimable WETH is less than the queued amount + uint256 queueShortfall = queue.queued - queue.claimable; + uint256 wethBalance = IERC20(weth).balanceOf(address(this)); + // Of the claimable withdrawal requests, how much is unclaimed? + uint256 unclaimed = queue.claimable - queue.claimed; + + if (wethBalance > queueShortfall + unclaimed) { + wethAvailable = wethBalance - queueShortfall - unclaimed; + } + } + + function _swapCollateral( + address _fromAsset, + address _toAsset, + uint256 _fromAssetAmount, + uint256 _minToAssetAmount, + bytes calldata _data + ) internal override returns (uint256 toAssetAmount) { + require(_fromAsset != weth, "swap from WETH not supported"); + require(_toAsset == weth, "only swap to WETH"); + toAssetAmount = super._swapCollateral( + _fromAsset, + _toAsset, + _fromAssetAmount, + _minToAssetAmount, + _data + ); + + // Add any new WETH to the withdrawal queue first + IVault(address(this)).addWithdrawalQueueLiquidity(); + } } diff --git a/contracts/contracts/vault/OETHVaultCore.sol b/contracts/contracts/vault/OETHVaultCore.sol index 175fb6fed4..22b3b49cba 100644 --- a/contracts/contracts/vault/OETHVaultCore.sol +++ b/contracts/contracts/vault/OETHVaultCore.sol @@ -231,6 +231,8 @@ contract OETHVaultCore is VaultCore { IERC20(weth).safeTransfer(msg.sender, totalAmount); } + // slither-disable-start reentrancy-no-eth + function _claimWithdrawal(uint256 requestId) internal returns (uint256 amount) @@ -263,7 +265,9 @@ contract OETHVaultCore is VaultCore { return request.amount; } - /// @notice Collects harvested rewards from the Dripper as WETH then + // slither-disable-end reentrancy-no-eth + + /// @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. function addWithdrawalQueueLiquidity() external { diff --git a/contracts/contracts/vault/VaultAdmin.sol b/contracts/contracts/vault/VaultAdmin.sol index 6ffaf5f370..0bc783a766 100644 --- a/contracts/contracts/vault/VaultAdmin.sol +++ b/contracts/contracts/vault/VaultAdmin.sol @@ -188,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]; @@ -479,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" diff --git a/contracts/contracts/vault/VaultStorage.sol b/contracts/contracts/vault/VaultStorage.sol index 95ef0c26f3..2582041cc1 100644 --- a/contracts/contracts/vault/VaultStorage.sol +++ b/contracts/contracts/vault/VaultStorage.sol @@ -197,6 +197,7 @@ contract VaultStorage is Initializable, Governable { uint128 nextWithdrawalIndex; } + // slither-disable-next-line uninitialized-state WithdrawalQueueMetadata public withdrawalQueueMetadata; struct WithdrawalRequest { diff --git a/contracts/deploy/mainnet/097_withdraw_queue.js b/contracts/deploy/mainnet/097_withdraw_queue.js index b82f01f7f3..dfd9e241af 100644 --- a/contracts/deploy/mainnet/097_withdraw_queue.js +++ b/contracts/deploy/mainnet/097_withdraw_queue.js @@ -25,7 +25,7 @@ module.exports = deploymentWithGovernanceProposal( ); const dVaultAdmin = await deployWithConfirmation( "OETHVaultAdmin", - [], + [addresses.mainnet.WETH], null, true ); diff --git a/contracts/test/_hot-deploy.js b/contracts/test/_hot-deploy.js index 1e395d04a6..c5ee8773bc 100644 --- a/contracts/test/_hot-deploy.js +++ b/contracts/test/_hot-deploy.js @@ -213,6 +213,7 @@ async function hotDeployVaultAdmin( await deploy(vaultAdminName, { from: addresses.mainnet.Timelock, // doesn't matter which address deploys it contract: vaultAdminName, + args: isOeth ? [fixture.weth.address] : [], }); const implementation = await ethers.getContract(vaultAdminName); diff --git a/contracts/test/strategies/balancerMetaStablePool.fork-test.js b/contracts/test/strategies/balancerMetaStablePool.fork-test.js index 6ca919b81c..518c1c6271 100644 --- a/contracts/test/strategies/balancerMetaStablePool.fork-test.js +++ b/contracts/test/strategies/balancerMetaStablePool.fork-test.js @@ -1,7 +1,6 @@ const { expect } = require("chai"); const { formatUnits } = require("ethers").utils; const { BigNumber } = require("ethers"); -const { mine } = require("@nomicfoundation/hardhat-network-helpers"); const addresses = require("../../utils/addresses"); const { balancer_rETH_WETH_PID } = require("../../utils/constants"); @@ -167,7 +166,7 @@ describe("ForkTest: Balancer MetaStablePool rETH/WETH Strategy", function () { }); }); - describe("Deposit", function () { + describe.skip("Deposit", function () { beforeEach(async () => { fixture = await loadBalancerREthFixtureNotDefault(); const { oethVault, josh, reth } = fixture; @@ -270,18 +269,6 @@ describe("ForkTest: Balancer MetaStablePool rETH/WETH Strategy", function () { describe("Withdraw", function () { beforeEach(async () => { fixture = await loadBalancerREthFixtureNotDefault(); - const { balancerREthStrategy, oethVault, josh, strategist, reth, weth } = - fixture; - - await reth.connect(josh).transfer(oethVault.address, oethUnits("32")); - - await oethVault - .connect(strategist) - .depositToStrategy( - balancerREthStrategy.address, - [weth.address, reth.address], - [oethUnits("32"), oethUnits("32")] - ); }); // a list of WETH/RETH pairs @@ -554,23 +541,12 @@ describe("ForkTest: Balancer MetaStablePool rETH/WETH Strategy", function () { await reth.connect(josh).transfer(oethVault.address, oethUnits("32")); }); it("Should be able to collect reward tokens", async function () { - const { - weth, - reth, - rEthBPT, - balancerREthStrategy, - oethHarvester, - bal, - aura, - } = fixture; + const { balancerREthStrategy, oethHarvester, bal, aura } = fixture; const sHarvester = await impersonateAndFund(oethHarvester.address); const balBefore = await bal.balanceOf(oethHarvester.address); const auraBefore = await aura.balanceOf(oethHarvester.address); - await depositTest(fixture, [5, 5], [weth, reth], rEthBPT); - await mine(1000); - await balancerREthStrategy.connect(sHarvester).collectRewardTokens(); expect(await bal.balanceOf(oethHarvester.address)).to.be.gt( @@ -586,18 +562,12 @@ describe("ForkTest: Balancer MetaStablePool rETH/WETH Strategy", function () { josh, balancerREthStrategy, weth, - reth, oethHarvester, - rEthBPT, oethDripper, bal, aura, } = fixture; - // Deposite some LP to the pool so that we can harvest some tokens - await depositTest(fixture, [5, 5], [weth, reth], rEthBPT); - await mine(1000); - // Let the strategy have some tokens it can send to Harvester await setERC20TokenBalance( balancerREthStrategy.address, From 10b95df64530db1c54cb5b134ec07f989da9b1af Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Thu, 23 May 2024 20:27:15 +1000 Subject: [PATCH 091/273] Fixed unit tests --- contracts/deploy/deployActions.js | 4 ++- contracts/test/_fixture.js | 41 +++---------------------- contracts/test/vault/oneinch-swapper.js | 26 ++++++++-------- 3 files changed, 20 insertions(+), 51 deletions(-) diff --git a/contracts/deploy/deployActions.js b/contracts/deploy/deployActions.js index 3f9bddd72b..0d1ef1d7bd 100644 --- a/contracts/deploy/deployActions.js +++ b/contracts/deploy/deployActions.js @@ -1091,7 +1091,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/test/_fixture.js b/contracts/test/_fixture.js index 9c87c52f43..2ea51d5a8e 100644 --- a/contracts/test/_fixture.js +++ b/contracts/test/_fixture.js @@ -833,8 +833,7 @@ async function oethDefaultFixture() { async function oethCollateralSwapFixture() { const fixture = await oethDefaultFixture(); - const { weth, matt, strategist, domen, frxETH, timelock, oethVault } = - fixture; + const { reth, stETH, matt, strategist, timelock, oethVault } = fixture; const bufferBps = await oethVault.vaultBuffer(); const shouldChangeBuffer = bufferBps.lt(oethUnits("1")); @@ -846,10 +845,7 @@ async function oethCollateralSwapFixture() { ); } - // Set frxETH/ETH price above 0.998 so we can mint OETH using frxETH - await setFraxOraclePrice(parseUnits("0.999", 18)); - - for (const token of [weth]) { + for (const token of [reth, stETH]) { await token .connect(matt) .approve( @@ -857,8 +853,8 @@ async function oethCollateralSwapFixture() { parseEther("100000000000000000000000000000000000") ); - // Mint some tokens, so it ends up in Vault - await oethVault.connect(matt).mint(token.address, parseEther("200"), "0"); + // Transfer some tokens to the Vault so they can be swapped out + await token.connect(matt).transfer(oethVault.address, parseEther("200")); } if (shouldChangeBuffer) { @@ -866,35 +862,6 @@ async function oethCollateralSwapFixture() { await oethVault.connect(strategist).setVaultBuffer(bufferBps); } - const allStrats = await oethVault.getAllStrategies(); - if ( - allStrats - .map((x) => x.toLowerCase()) - .includes(addresses.mainnet.FraxETHStrategy.toLowerCase()) - ) { - // Remove fraxETH strategy if it exists - // Because it no longer holds assets and causes this test to fail - - // Send some dust to that first - await frxETH.connect(domen).transfer(oethVault.address, oethUnits("1")); - - // Now make sure it's deposited - await oethVault - .connect(strategist) - .depositToStrategy( - addresses.mainnet.FraxETHStrategy, - [frxETH.address], - [oethUnits("1")] - ); - - await oethVault - .connect(timelock) - .setAssetDefaultStrategy(frxETH.address, addresses.zero); - await oethVault - .connect(timelock) - .removeStrategy(addresses.mainnet.FraxETHStrategy); - } - // Withdraw all from strategies so we have assets to swap await oethVault.connect(timelock).withdrawAllFromStrategies(); diff --git a/contracts/test/vault/oneinch-swapper.js b/contracts/test/vault/oneinch-swapper.js index 8855aa8966..cdc09fafac 100644 --- a/contracts/test/vault/oneinch-swapper.js +++ b/contracts/test/vault/oneinch-swapper.js @@ -130,12 +130,12 @@ describe("1Inch Swapper", () => { }); it("Should allow to swap tokens", async () => { - const { weth, reth, stETH, frxETH, oethVault, strategist } = fixture; + const { weth, reth, stETH, oethVault, strategist } = fixture; const fromAmount = utils.parseEther("20"); - for (const fromAsset of [weth]) { - for (const toAsset of [reth, stETH, frxETH]) { + for (const fromAsset of [reth, stETH]) { + for (const toAsset of [weth]) { const toAmount = utils.parseEther("24"); log( `swapping 20 ${await fromAsset.symbol()} to ${await toAsset.symbol()}` @@ -173,7 +173,7 @@ describe("1Inch Swapper", () => { // Call swap method const tx = oethVault .connect(strategist) - .swapCollateral(weth.address, stETH.address, fromAmount, toAmount, []); + .swapCollateral(stETH.address, weth.address, fromAmount, toAmount, []); await expect(tx).to.be.revertedWith("Strategist slippage limit"); }); @@ -187,12 +187,12 @@ describe("1Inch Swapper", () => { // Call swap method const tx = oethVault .connect(strategist) - .swapCollateral(weth.address, stETH.address, fromAmount, toAmount, []); + .swapCollateral(stETH.address, weth.address, fromAmount, toAmount, []); await expect(tx).to.be.revertedWith("Oracle slippage limit exceeded"); }); - it("Should revert swap if value is under supply", async () => { + it.skip("Should revert swap if value is under supply", async () => { const { weth, stETH, @@ -220,7 +220,7 @@ describe("1Inch Swapper", () => { // Call swap method const tx = oethVault .connect(strategist) - .swapCollateral(weth.address, stETH.address, fromAmount, toAmount, []); + .swapCollateral(stETH.address, weth.address, fromAmount, toAmount, []); await expect(tx).to.be.revertedWith("Allowed value < supply"); @@ -255,7 +255,7 @@ describe("1Inch Swapper", () => { // Call swap method const tx = await oethVault .connect(strategist) - .swapCollateral(weth.address, stETH.address, fromAmount, toAmount, []); + .swapCollateral(stETH.address, weth.address, fromAmount, toAmount, []); await expect(tx).to.emit(oethVault, "Swapped"); @@ -277,16 +277,16 @@ describe("1Inch Swapper", () => { }); it("Should revert if toAsset is not supported", async () => { - const { weth, dai, oethVault, strategist } = fixture; + const { stETH, dai, oethVault, strategist } = fixture; const fromAmount = utils.parseEther("100"); const toAmount = utils.parseEther("100"); // Call swap method const tx = oethVault .connect(strategist) - .swapCollateral(weth.address, dai.address, fromAmount, toAmount, []); + .swapCollateral(stETH.address, dai.address, fromAmount, toAmount, []); - await expect(tx).to.be.revertedWith("To asset is not supported"); + await expect(tx).to.be.revertedWith("only swap to WETH"); }); it("Should swap if capital is paused", async () => { @@ -303,7 +303,7 @@ describe("1Inch Swapper", () => { // Call swap method const tx = await oethVault .connect(strategist) - .swapCollateral(weth.address, stETH.address, fromAmount, toAmount, []); + .swapCollateral(stETH.address, weth.address, fromAmount, toAmount, []); expect(tx).to.emit(oethVault, "Swapped"); }); @@ -316,7 +316,7 @@ describe("1Inch Swapper", () => { // Call swap method const tx = oethVault .connect(josh) - .swapCollateral(weth.address, stETH.address, fromAmount, toAmount, []); + .swapCollateral(stETH.address, weth.address, fromAmount, toAmount, []); await expect(tx).to.be.revertedWith( "Caller is not the Strategist or Governor" From f27966b243faa035e005a7c9c500395f77a4b6e7 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Thu, 23 May 2024 20:41:38 +1000 Subject: [PATCH 092/273] Suppress Slither --- contracts/contracts/vault/VaultStorage.sol | 2 ++ 1 file changed, 2 insertions(+) diff --git a/contracts/contracts/vault/VaultStorage.sol b/contracts/contracts/vault/VaultStorage.sol index 2582041cc1..705cb097d0 100644 --- a/contracts/contracts/vault/VaultStorage.sol +++ b/contracts/contracts/vault/VaultStorage.sol @@ -181,8 +181,10 @@ contract VaultStorage is Initializable, Governable { /// @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 ///// From 112dd371d9814efa48f92cee383b8047bcd69e06 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Thu, 23 May 2024 23:46:35 +1000 Subject: [PATCH 093/273] Changed ssv util getClusterInfo to use the SSV API instead of the ssv-scanner Moved duplicate getClusterInfo in tasks to utils --- contracts/tasks/ssv.js | 79 ++-------------------- contracts/tasks/tasks.js | 4 +- contracts/test/behaviour/ssvStrategy.js | 4 +- contracts/utils/ssv.js | 90 ++++++++++++++----------- 4 files changed, 61 insertions(+), 116 deletions(-) diff --git a/contracts/tasks/ssv.js b/contracts/tasks/ssv.js index c156f76ad1..1669d6798a 100644 --- a/contracts/tasks/ssv.js +++ b/contracts/tasks/ssv.js @@ -1,93 +1,25 @@ const { parseUnits, formatUnits } = require("ethers/lib/utils"); -const { ClusterScanner, NonceScanner } = require("ssv-scanner"); const addresses = require("../utils/addresses"); const { resolveContract } = require("../utils/resolvers"); const { getSigner } = require("../utils/signers"); +const { getClusterInfo } = require("../utils/ssv"); const { logTxDetails } = require("../utils/txLogger"); const log = require("../utils/logger")("task:ssv"); const printClusterInfo = async (options) => { const cluster = await getClusterInfo(options); - const nextNonce = await getClusterNonce(options); + // const nextNonce = await getClusterNonce(options); console.log(`block ${cluster.block}`); console.log(`Cluster: ${JSON.stringify(cluster.snapshot, null, " ")}`); - console.log("Next Nonce:", nextNonce); -}; - -const getClusterInfo = async ({ - ownerAddress, - operatorids, - chainId, - ssvNetwork, -}) => { - const operatorIds = operatorids.split(".").map((id) => parseInt(id)); - - const ssvNetworkName = chainId === 1 ? "MAINNET" : "PRATER"; - const providerUrl = - chainId === 1 ? process.env.PROVIDER_URL : process.env.HOLESKY_PROVIDER_URL; - - const params = { - nodeUrl: providerUrl, // this can be an Infura, or Alchemy node, necessary to query the blockchain - contractAddress: ssvNetwork, // this is the address of SSV smart contract - ownerAddress, // this is the wallet address of the cluster owner - /* Based on the network they fetch contract ABIs. See code: https://github.com/bloxapp/ssv-scanner/blob/v1.0.3/src/lib/contract.provider.ts#L16-L22 - * and the ABIs are fetched from here: https://github.com/bloxapp/ssv-scanner/tree/v1.0.3/src/shared/abi - * - * Prater seems to work for Goerli at the moment - */ - network: ssvNetworkName, - operatorIds: operatorIds, // this is a list of operator IDs chosen by the owner for their cluster - }; - - // ClusterScanner is initialized with the given parameters - const clusterScanner = new ClusterScanner(params); - // and when run, it returns the Cluster Snapshot - const result = await clusterScanner.run(params.operatorIds); - const cluster = { - block: result.payload.Block, - snapshot: result.cluster, - cluster: Object.values(result.cluster), - }; - log(`Cluster info ${JSON.stringify(cluster)}`); - return cluster; -}; - -const getClusterNonce = async ({ - ownerAddress, - operatorids, - chainId, - ssvNetwork, -}) => { - const operatorIds = operatorids.split(".").map((id) => parseInt(id)); - - const ssvNetworkName = chainId === 1 ? "MAINNET" : "PRATER"; - const providerUrl = - chainId === 1 ? process.env.PROVIDER_URL : process.env.HOLESKY_PROVIDER_URL; - - const params = { - nodeUrl: providerUrl, // this can be an Infura, or Alchemy node, necessary to query the blockchain - contractAddress: ssvNetwork, // this is the address of SSV smart contract - ownerAddress, // this is the wallet address of the cluster owner - /* Based on the network they fetch contract ABIs. See code: https://github.com/bloxapp/ssv-scanner/blob/v1.0.3/src/lib/contract.provider.ts#L16-L22 - * and the ABIs are fetched from here: https://github.com/bloxapp/ssv-scanner/tree/v1.0.3/src/shared/abi - * - * Prater seems to work for Goerli at the moment - */ - network: ssvNetworkName, - operatorIds: operatorIds, // this is a list of operator IDs chosen by the owner for their cluster - }; - - const nonceScanner = new NonceScanner(params); - const nextNonce = await nonceScanner.run(); - return nextNonce; + // console.log("Next Nonce:", nextNonce); }; const depositSSV = async ({ amount, operatorids }, hre) => { const amountBN = parseUnits(amount.toString(), 18); log(`Splitting operator IDs ${operatorids}`); - const operatorIds = operatorids.split(".").map((id) => parseInt(id)); + const operatorIds = operatorids.split(",").map((id) => parseInt(id)); const signer = await getSigner(); @@ -102,7 +34,7 @@ const depositSSV = async ({ amount, operatorids }, hre) => { const clusterInfo = await getClusterInfo({ chainId: hre.network.config.chainId, ssvNetwork: ssvNetwork.address, - operatorIds, + operatorIds: operatorids, ownerAddress: strategy.address, }); @@ -122,6 +54,5 @@ const depositSSV = async ({ amount, operatorids }, hre) => { module.exports = { printClusterInfo, - getClusterInfo, depositSSV, }; diff --git a/contracts/tasks/tasks.js b/contracts/tasks/tasks.js index ce1feca2dc..60f6e36621 100644 --- a/contracts/tasks/tasks.js +++ b/contracts/tasks/tasks.js @@ -858,7 +858,7 @@ task("setRewardTokenAddresses", "Sets the reward token of a strategy") subtask("getClusterInfo", "Print out information regarding SSV cluster") .addParam( "operatorids", - "4 operator ids separated with a dot: same as IP format. E.g. 60.79.220.349", + "Comma separated operator ids. E.g. 60,79,220,349", "", types.string ) @@ -893,7 +893,7 @@ subtask( .addParam("amount", "Amount of SSV tokens to deposit", undefined, types.float) .addParam( "operatorids", - "4 operator ids separated with a dot: same as IP format. E.g. 60.79.220.349", + "Comma separated operator ids. E.g. 60,79,220,349", undefined, types.string ) diff --git a/contracts/test/behaviour/ssvStrategy.js b/contracts/test/behaviour/ssvStrategy.js index d39e0abf59..9b97868cf8 100644 --- a/contracts/test/behaviour/ssvStrategy.js +++ b/contracts/test/behaviour/ssvStrategy.js @@ -159,7 +159,7 @@ const shouldBehaveLikeAnSsvStrategy = (context) => { const { cluster } = await getClusterInfo({ ownerAddress: nativeStakingSSVStrategy.address, - operatorIds: testValidator.operatorIds, + operatorids: testValidator.operatorIds, chainId: hre.network.config.chainId, ssvNetwork: addresses.SSVNetwork, }); @@ -263,7 +263,7 @@ const shouldBehaveLikeAnSsvStrategy = (context) => { const { cluster } = await getClusterInfo({ ownerAddress: nativeStakingSSVStrategy.address, - operatorIds: testValidator.operatorIds, + operatorids: testValidator.operatorIds, chainId: hre.network.config.chainId, ssvNetwork: addresses.SSVNetwork, }); diff --git a/contracts/utils/ssv.js b/contracts/utils/ssv.js index c756c82d13..86f5e848b9 100644 --- a/contracts/utils/ssv.js +++ b/contracts/utils/ssv.js @@ -1,12 +1,20 @@ -const { ClusterScanner, NonceScanner } = require("ssv-scanner"); +const { NonceScanner } = require("ssv-scanner"); const { SSVKeys, KeyShares, KeySharesItem } = require("ssv-keys"); const path = require("path"); const fsp = require("fs").promises; - -const { isForkWithLocalNode } = require("../test/helpers"); +const axios = require("axios"); const log = require("../utils/logger")("utils:ssv"); +const SSV_API_ENDPOINT = "https://api.ssv.network/api/v4"; +const emptyCluster = { + validatorCount: 0, + networkFeeIndex: 0, + index: 0, + active: true, + balance: 0, +}; + const splitValidatorKey = async ({ keystorelocation, keystorepass, @@ -91,43 +99,48 @@ const splitValidatorKey = async ({ }); }; -const getClusterInfo = async ({ - ownerAddress, - operatorIds, - chainId, - ssvNetwork, -}) => { - const ssvNetworkName = chainId === 1 ? "MAINNET" : "HOLESKY"; - log(`SSV network: ${ssvNetworkName}`); - const providerUrl = isForkWithLocalNode - ? "http://localhost:8545/" - : process.env.PROVIDER_URL; - log(`Provider URL: ${providerUrl}`); +const getClusterInfo = async ({ ownerAddress, operatorids, chainId }) => { + // HTTP encode the operator IDs + // the .toString() will convert the array to a comma-separated string if not already a string + const encodedOperatorIds = encodeURIComponent(operatorids.toString()); + const network = chainId === 1 ? "mainnet" : "holesky"; + const url = `${SSV_API_ENDPOINT}/${network}/clusters/owner/${ownerAddress}/operators/${encodedOperatorIds}`; + log(`SSV url: ${url}`); + + try { + // Call the SSV API to get the Cluster data + const response = await axios.get(url); + + if (!response.data) { + console.error(response.data); + throw Error("response is missing data"); + } - const params = { - nodeUrl: providerUrl, // this can be an Infura, or Alchemy node, necessary to query the blockchain - contractAddress: ssvNetwork, // this is the address of SSV smart contract - ownerAddress, // this is the wallet address of the cluster owner - /* Based on the network they fetch contract ABIs. See code: https://github.com/bloxapp/ssv-scanner/blob/v1.0.3/src/lib/contract.provider.ts#L16-L22 - * and the ABIs are fetched from here: https://github.com/bloxapp/ssv-scanner/tree/v1.0.3/src/shared/abi - * - * Prater seems to work for Goerli at the moment - */ - network: ssvNetworkName, - operatorIds, // this is a list of operator IDs chosen by the owner for their cluster - }; + if (response.data.cluster === null) { + log( + `Cluster not found for network ${network}, owner ${ownerAddress} and operators ${operatorids}` + ); + return { + block: 0, + snapshot: emptyCluster, + cluster: emptyCluster, + }; + } - // ClusterScanner is initialized with the given parameters - const clusterScanner = new ClusterScanner(params); - // and when run, it returns the Cluster Snapshot - const result = await clusterScanner.run(params.operatorIds); - const cluster = { - block: result.payload.Block, - snapshot: result.cluster, - cluster: Object.values(result.cluster), - }; - log(`Cluster info ${JSON.stringify(cluster)}`); - return cluster; + log("Cluster data from SSV API: ", JSON.stringify(response.data.cluster)); + + return { + block: response.data.cluster.blockNumber, + cluster: response.data.cluster, + snapshot: response.data.cluster, + }; + } catch (err) { + if (err.response) { + console.error("Response data : ", err.response.data); + console.error("Response status: ", err.response.status); + } + throw Error(`Call to SSV API failed: ${err.message}`); + } }; const getClusterNonce = async ({ @@ -168,5 +181,6 @@ const printClusterInfo = async (options) => { module.exports = { printClusterInfo, getClusterInfo, + getClusterNonce, splitValidatorKey, }; From f3e9d35103092269e7f64895a13a1081c53085d9 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Fri, 24 May 2024 10:23:32 +1000 Subject: [PATCH 094/273] Fix Native Staking fork tests --- contracts/test/strategies/nativeSSVStaking.js | 31 +++++++++++++++---- .../strategies/nativeSsvStaking.fork-test.js | 2 +- 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/contracts/test/strategies/nativeSSVStaking.js b/contracts/test/strategies/nativeSSVStaking.js index f3cff0d0aa..27fb8c92b3 100644 --- a/contracts/test/strategies/nativeSSVStaking.js +++ b/contracts/test/strategies/nativeSSVStaking.js @@ -6,6 +6,7 @@ const { setStorageAt, mine, } = require("@nomicfoundation/hardhat-network-helpers"); +const { solidityPack } = require("ethers/lib/utils"); const { isCI } = require("../helpers"); const { shouldBehaveLikeGovernable } = require("../behaviour/governable"); @@ -1014,16 +1015,34 @@ describe("Unit test: Native SSV Staking Strategy", function () { } }); - it.skip("Deposit alternate deposit_data_root ", async () => { + it("Deposit alternate deposit_data_root ", async () => { const { depositContractUtils } = fixture; - const newDepositDataRoot = + const withdrawalCredentials = solidityPack( + ["bytes1", "bytes11", "address"], + [ + "0x01", + "0x0000000000000000000000", + // mainnet Native Staking Strategy proxy + "0x34edb2ee25751ee67f68a45813b22811687c0238", + ] + ); + expect(withdrawalCredentials).to.equal( + "0x01000000000000000000000034edb2ee25751ee67f68a45813b22811687c0238" + ); + + const expectedDepositDataRoot = await depositContractUtils.calculateDepositDataRoot( - "0x9254b0fba5173550bcf0950031533e816150167577c15636922406977bafa09ed1a1cc72a148030db977d7091d31c1fa", - "0x010000000000000000000000cf4a9e80ddb173cc17128a361b98b9a140e3932e", - "0x9144bddd6d969571dd058d9656c9da32cf4b8556e18a16362383d02a93bd0901f100874f7f795165a2162badceb5466811f5cfbce8be21d02a87af1898cbe53f5d160d46cbc0863d8e6e28d5f0becf4804cf728b39d0bae69540df896ce97b8b" + // Mainnet fork test public key + "0xaba6acd335d524a89fb89b9977584afdb23f34a6742547fa9ec1c656fbd2bfc0e7a234460328c2731828c9a43be06e25", + withdrawalCredentials, + // Mainnet fork test signature + "0x90157a1c1b26384f0b4d41bec867d1a000f75e7b634ac7c4c6d8dfc0b0eaeb73bcc99586333d42df98c6b0a8c5ef0d8d071c68991afcd8fbbaa8b423e3632ee4fe0782bc03178a30a8bc6261f64f84a6c833fb96a0f29de1c34ede42c4a859b0" ); - console.log(`the new newDepositDataRoot is: ${newDepositDataRoot}`); + + expect( + "0xf7d704e25a2b5bea06fafa2dfe5c6fa906816e5c1622400339b2088a11d5f446" + ).to.equal(expectedDepositDataRoot, "Incorrect deposit data root"); }); }); diff --git a/contracts/test/strategies/nativeSsvStaking.fork-test.js b/contracts/test/strategies/nativeSsvStaking.fork-test.js index 4249ffeb66..dbaf6f7c81 100644 --- a/contracts/test/strategies/nativeSsvStaking.fork-test.js +++ b/contracts/test/strategies/nativeSsvStaking.fork-test.js @@ -28,7 +28,7 @@ describe("ForkTest: Native SSV Staking Strategy", function () { signature: "0x90157a1c1b26384f0b4d41bec867d1a000f75e7b634ac7c4c6d8dfc0b0eaeb73bcc99586333d42df98c6b0a8c5ef0d8d071c68991afcd8fbbaa8b423e3632ee4fe0782bc03178a30a8bc6261f64f84a6c833fb96a0f29de1c34ede42c4a859b0", depositDataRoot: - "0xdbe778a625c68446f3cc8b2009753a5e7dd7c37b8721ee98a796bb9179dfe8ac", + "0xf7d704e25a2b5bea06fafa2dfe5c6fa906816e5c1622400339b2088a11d5f446", }, }; }); From 4e9e24f98a8554dc8e5391162fcd89cb125bc672 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Fri, 24 May 2024 10:25:02 +1000 Subject: [PATCH 095/273] Fix Native Staking fork tests --- contracts/test/strategies/nativeSSVStaking.js | 31 +++++++++++++++---- .../strategies/nativeSsvStaking.fork-test.js | 2 +- 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/contracts/test/strategies/nativeSSVStaking.js b/contracts/test/strategies/nativeSSVStaking.js index f3cff0d0aa..27fb8c92b3 100644 --- a/contracts/test/strategies/nativeSSVStaking.js +++ b/contracts/test/strategies/nativeSSVStaking.js @@ -6,6 +6,7 @@ const { setStorageAt, mine, } = require("@nomicfoundation/hardhat-network-helpers"); +const { solidityPack } = require("ethers/lib/utils"); const { isCI } = require("../helpers"); const { shouldBehaveLikeGovernable } = require("../behaviour/governable"); @@ -1014,16 +1015,34 @@ describe("Unit test: Native SSV Staking Strategy", function () { } }); - it.skip("Deposit alternate deposit_data_root ", async () => { + it("Deposit alternate deposit_data_root ", async () => { const { depositContractUtils } = fixture; - const newDepositDataRoot = + const withdrawalCredentials = solidityPack( + ["bytes1", "bytes11", "address"], + [ + "0x01", + "0x0000000000000000000000", + // mainnet Native Staking Strategy proxy + "0x34edb2ee25751ee67f68a45813b22811687c0238", + ] + ); + expect(withdrawalCredentials).to.equal( + "0x01000000000000000000000034edb2ee25751ee67f68a45813b22811687c0238" + ); + + const expectedDepositDataRoot = await depositContractUtils.calculateDepositDataRoot( - "0x9254b0fba5173550bcf0950031533e816150167577c15636922406977bafa09ed1a1cc72a148030db977d7091d31c1fa", - "0x010000000000000000000000cf4a9e80ddb173cc17128a361b98b9a140e3932e", - "0x9144bddd6d969571dd058d9656c9da32cf4b8556e18a16362383d02a93bd0901f100874f7f795165a2162badceb5466811f5cfbce8be21d02a87af1898cbe53f5d160d46cbc0863d8e6e28d5f0becf4804cf728b39d0bae69540df896ce97b8b" + // Mainnet fork test public key + "0xaba6acd335d524a89fb89b9977584afdb23f34a6742547fa9ec1c656fbd2bfc0e7a234460328c2731828c9a43be06e25", + withdrawalCredentials, + // Mainnet fork test signature + "0x90157a1c1b26384f0b4d41bec867d1a000f75e7b634ac7c4c6d8dfc0b0eaeb73bcc99586333d42df98c6b0a8c5ef0d8d071c68991afcd8fbbaa8b423e3632ee4fe0782bc03178a30a8bc6261f64f84a6c833fb96a0f29de1c34ede42c4a859b0" ); - console.log(`the new newDepositDataRoot is: ${newDepositDataRoot}`); + + expect( + "0xf7d704e25a2b5bea06fafa2dfe5c6fa906816e5c1622400339b2088a11d5f446" + ).to.equal(expectedDepositDataRoot, "Incorrect deposit data root"); }); }); diff --git a/contracts/test/strategies/nativeSsvStaking.fork-test.js b/contracts/test/strategies/nativeSsvStaking.fork-test.js index 4249ffeb66..dbaf6f7c81 100644 --- a/contracts/test/strategies/nativeSsvStaking.fork-test.js +++ b/contracts/test/strategies/nativeSsvStaking.fork-test.js @@ -28,7 +28,7 @@ describe("ForkTest: Native SSV Staking Strategy", function () { signature: "0x90157a1c1b26384f0b4d41bec867d1a000f75e7b634ac7c4c6d8dfc0b0eaeb73bcc99586333d42df98c6b0a8c5ef0d8d071c68991afcd8fbbaa8b423e3632ee4fe0782bc03178a30a8bc6261f64f84a6c833fb96a0f29de1c34ede42c4a859b0", depositDataRoot: - "0xdbe778a625c68446f3cc8b2009753a5e7dd7c37b8721ee98a796bb9179dfe8ac", + "0xf7d704e25a2b5bea06fafa2dfe5c6fa906816e5c1622400339b2088a11d5f446", }, }; }); From 8cf9a25979abe4e25c29cc50816ca7335b0e7fbf Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Fri, 24 May 2024 10:31:44 +1000 Subject: [PATCH 096/273] Changed ssv util getClusterInfo to use the SSV API instead of the ssv-scanner Moved duplicate getClusterInfo in tasks to utils --- contracts/tasks/ssv.js | 79 ++-------------------- contracts/tasks/tasks.js | 4 +- contracts/test/behaviour/ssvStrategy.js | 4 +- contracts/utils/ssv.js | 90 ++++++++++++++----------- 4 files changed, 61 insertions(+), 116 deletions(-) diff --git a/contracts/tasks/ssv.js b/contracts/tasks/ssv.js index c156f76ad1..1669d6798a 100644 --- a/contracts/tasks/ssv.js +++ b/contracts/tasks/ssv.js @@ -1,93 +1,25 @@ const { parseUnits, formatUnits } = require("ethers/lib/utils"); -const { ClusterScanner, NonceScanner } = require("ssv-scanner"); const addresses = require("../utils/addresses"); const { resolveContract } = require("../utils/resolvers"); const { getSigner } = require("../utils/signers"); +const { getClusterInfo } = require("../utils/ssv"); const { logTxDetails } = require("../utils/txLogger"); const log = require("../utils/logger")("task:ssv"); const printClusterInfo = async (options) => { const cluster = await getClusterInfo(options); - const nextNonce = await getClusterNonce(options); + // const nextNonce = await getClusterNonce(options); console.log(`block ${cluster.block}`); console.log(`Cluster: ${JSON.stringify(cluster.snapshot, null, " ")}`); - console.log("Next Nonce:", nextNonce); -}; - -const getClusterInfo = async ({ - ownerAddress, - operatorids, - chainId, - ssvNetwork, -}) => { - const operatorIds = operatorids.split(".").map((id) => parseInt(id)); - - const ssvNetworkName = chainId === 1 ? "MAINNET" : "PRATER"; - const providerUrl = - chainId === 1 ? process.env.PROVIDER_URL : process.env.HOLESKY_PROVIDER_URL; - - const params = { - nodeUrl: providerUrl, // this can be an Infura, or Alchemy node, necessary to query the blockchain - contractAddress: ssvNetwork, // this is the address of SSV smart contract - ownerAddress, // this is the wallet address of the cluster owner - /* Based on the network they fetch contract ABIs. See code: https://github.com/bloxapp/ssv-scanner/blob/v1.0.3/src/lib/contract.provider.ts#L16-L22 - * and the ABIs are fetched from here: https://github.com/bloxapp/ssv-scanner/tree/v1.0.3/src/shared/abi - * - * Prater seems to work for Goerli at the moment - */ - network: ssvNetworkName, - operatorIds: operatorIds, // this is a list of operator IDs chosen by the owner for their cluster - }; - - // ClusterScanner is initialized with the given parameters - const clusterScanner = new ClusterScanner(params); - // and when run, it returns the Cluster Snapshot - const result = await clusterScanner.run(params.operatorIds); - const cluster = { - block: result.payload.Block, - snapshot: result.cluster, - cluster: Object.values(result.cluster), - }; - log(`Cluster info ${JSON.stringify(cluster)}`); - return cluster; -}; - -const getClusterNonce = async ({ - ownerAddress, - operatorids, - chainId, - ssvNetwork, -}) => { - const operatorIds = operatorids.split(".").map((id) => parseInt(id)); - - const ssvNetworkName = chainId === 1 ? "MAINNET" : "PRATER"; - const providerUrl = - chainId === 1 ? process.env.PROVIDER_URL : process.env.HOLESKY_PROVIDER_URL; - - const params = { - nodeUrl: providerUrl, // this can be an Infura, or Alchemy node, necessary to query the blockchain - contractAddress: ssvNetwork, // this is the address of SSV smart contract - ownerAddress, // this is the wallet address of the cluster owner - /* Based on the network they fetch contract ABIs. See code: https://github.com/bloxapp/ssv-scanner/blob/v1.0.3/src/lib/contract.provider.ts#L16-L22 - * and the ABIs are fetched from here: https://github.com/bloxapp/ssv-scanner/tree/v1.0.3/src/shared/abi - * - * Prater seems to work for Goerli at the moment - */ - network: ssvNetworkName, - operatorIds: operatorIds, // this is a list of operator IDs chosen by the owner for their cluster - }; - - const nonceScanner = new NonceScanner(params); - const nextNonce = await nonceScanner.run(); - return nextNonce; + // console.log("Next Nonce:", nextNonce); }; const depositSSV = async ({ amount, operatorids }, hre) => { const amountBN = parseUnits(amount.toString(), 18); log(`Splitting operator IDs ${operatorids}`); - const operatorIds = operatorids.split(".").map((id) => parseInt(id)); + const operatorIds = operatorids.split(",").map((id) => parseInt(id)); const signer = await getSigner(); @@ -102,7 +34,7 @@ const depositSSV = async ({ amount, operatorids }, hre) => { const clusterInfo = await getClusterInfo({ chainId: hre.network.config.chainId, ssvNetwork: ssvNetwork.address, - operatorIds, + operatorIds: operatorids, ownerAddress: strategy.address, }); @@ -122,6 +54,5 @@ const depositSSV = async ({ amount, operatorids }, hre) => { module.exports = { printClusterInfo, - getClusterInfo, depositSSV, }; diff --git a/contracts/tasks/tasks.js b/contracts/tasks/tasks.js index ce1feca2dc..60f6e36621 100644 --- a/contracts/tasks/tasks.js +++ b/contracts/tasks/tasks.js @@ -858,7 +858,7 @@ task("setRewardTokenAddresses", "Sets the reward token of a strategy") subtask("getClusterInfo", "Print out information regarding SSV cluster") .addParam( "operatorids", - "4 operator ids separated with a dot: same as IP format. E.g. 60.79.220.349", + "Comma separated operator ids. E.g. 60,79,220,349", "", types.string ) @@ -893,7 +893,7 @@ subtask( .addParam("amount", "Amount of SSV tokens to deposit", undefined, types.float) .addParam( "operatorids", - "4 operator ids separated with a dot: same as IP format. E.g. 60.79.220.349", + "Comma separated operator ids. E.g. 60,79,220,349", undefined, types.string ) diff --git a/contracts/test/behaviour/ssvStrategy.js b/contracts/test/behaviour/ssvStrategy.js index d39e0abf59..9b97868cf8 100644 --- a/contracts/test/behaviour/ssvStrategy.js +++ b/contracts/test/behaviour/ssvStrategy.js @@ -159,7 +159,7 @@ const shouldBehaveLikeAnSsvStrategy = (context) => { const { cluster } = await getClusterInfo({ ownerAddress: nativeStakingSSVStrategy.address, - operatorIds: testValidator.operatorIds, + operatorids: testValidator.operatorIds, chainId: hre.network.config.chainId, ssvNetwork: addresses.SSVNetwork, }); @@ -263,7 +263,7 @@ const shouldBehaveLikeAnSsvStrategy = (context) => { const { cluster } = await getClusterInfo({ ownerAddress: nativeStakingSSVStrategy.address, - operatorIds: testValidator.operatorIds, + operatorids: testValidator.operatorIds, chainId: hre.network.config.chainId, ssvNetwork: addresses.SSVNetwork, }); diff --git a/contracts/utils/ssv.js b/contracts/utils/ssv.js index c756c82d13..86f5e848b9 100644 --- a/contracts/utils/ssv.js +++ b/contracts/utils/ssv.js @@ -1,12 +1,20 @@ -const { ClusterScanner, NonceScanner } = require("ssv-scanner"); +const { NonceScanner } = require("ssv-scanner"); const { SSVKeys, KeyShares, KeySharesItem } = require("ssv-keys"); const path = require("path"); const fsp = require("fs").promises; - -const { isForkWithLocalNode } = require("../test/helpers"); +const axios = require("axios"); const log = require("../utils/logger")("utils:ssv"); +const SSV_API_ENDPOINT = "https://api.ssv.network/api/v4"; +const emptyCluster = { + validatorCount: 0, + networkFeeIndex: 0, + index: 0, + active: true, + balance: 0, +}; + const splitValidatorKey = async ({ keystorelocation, keystorepass, @@ -91,43 +99,48 @@ const splitValidatorKey = async ({ }); }; -const getClusterInfo = async ({ - ownerAddress, - operatorIds, - chainId, - ssvNetwork, -}) => { - const ssvNetworkName = chainId === 1 ? "MAINNET" : "HOLESKY"; - log(`SSV network: ${ssvNetworkName}`); - const providerUrl = isForkWithLocalNode - ? "http://localhost:8545/" - : process.env.PROVIDER_URL; - log(`Provider URL: ${providerUrl}`); +const getClusterInfo = async ({ ownerAddress, operatorids, chainId }) => { + // HTTP encode the operator IDs + // the .toString() will convert the array to a comma-separated string if not already a string + const encodedOperatorIds = encodeURIComponent(operatorids.toString()); + const network = chainId === 1 ? "mainnet" : "holesky"; + const url = `${SSV_API_ENDPOINT}/${network}/clusters/owner/${ownerAddress}/operators/${encodedOperatorIds}`; + log(`SSV url: ${url}`); + + try { + // Call the SSV API to get the Cluster data + const response = await axios.get(url); + + if (!response.data) { + console.error(response.data); + throw Error("response is missing data"); + } - const params = { - nodeUrl: providerUrl, // this can be an Infura, or Alchemy node, necessary to query the blockchain - contractAddress: ssvNetwork, // this is the address of SSV smart contract - ownerAddress, // this is the wallet address of the cluster owner - /* Based on the network they fetch contract ABIs. See code: https://github.com/bloxapp/ssv-scanner/blob/v1.0.3/src/lib/contract.provider.ts#L16-L22 - * and the ABIs are fetched from here: https://github.com/bloxapp/ssv-scanner/tree/v1.0.3/src/shared/abi - * - * Prater seems to work for Goerli at the moment - */ - network: ssvNetworkName, - operatorIds, // this is a list of operator IDs chosen by the owner for their cluster - }; + if (response.data.cluster === null) { + log( + `Cluster not found for network ${network}, owner ${ownerAddress} and operators ${operatorids}` + ); + return { + block: 0, + snapshot: emptyCluster, + cluster: emptyCluster, + }; + } - // ClusterScanner is initialized with the given parameters - const clusterScanner = new ClusterScanner(params); - // and when run, it returns the Cluster Snapshot - const result = await clusterScanner.run(params.operatorIds); - const cluster = { - block: result.payload.Block, - snapshot: result.cluster, - cluster: Object.values(result.cluster), - }; - log(`Cluster info ${JSON.stringify(cluster)}`); - return cluster; + log("Cluster data from SSV API: ", JSON.stringify(response.data.cluster)); + + return { + block: response.data.cluster.blockNumber, + cluster: response.data.cluster, + snapshot: response.data.cluster, + }; + } catch (err) { + if (err.response) { + console.error("Response data : ", err.response.data); + console.error("Response status: ", err.response.status); + } + throw Error(`Call to SSV API failed: ${err.message}`); + } }; const getClusterNonce = async ({ @@ -168,5 +181,6 @@ const printClusterInfo = async (options) => { module.exports = { printClusterInfo, getClusterInfo, + getClusterNonce, splitValidatorKey, }; From fc09bed874bcc21e00c8c1f594c41f31e464a24b Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Fri, 24 May 2024 10:37:23 +1000 Subject: [PATCH 097/273] Prettier --- .../deploy/mainnet/097_native_ssv_staking.js | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/contracts/deploy/mainnet/097_native_ssv_staking.js b/contracts/deploy/mainnet/097_native_ssv_staking.js index dd3de4663e..70503d6891 100644 --- a/contracts/deploy/mainnet/097_native_ssv_staking.js +++ b/contracts/deploy/mainnet/097_native_ssv_staking.js @@ -147,22 +147,13 @@ module.exports = deploymentWithGovernanceProposal( ]); const dOETHHarvesterImpl = await ethers.getContract("OETHHarvester"); - console.log( - "Native Staking SSV Strategy proxy: ", - cStrategyProxy.address - ); + console.log("Native Staking SSV Strategy proxy: ", cStrategyProxy.address); console.log( "Native Staking SSV Strategy implementation: ", dStrategyImpl.address ); - console.log( - "Fee accumulator proxy: ", - cFeeAccumulatorProxy.address - ); - console.log( - "Fee accumulator implementation: ", - cFeeAccumulator.address - ); + console.log("Fee accumulator proxy: ", cFeeAccumulatorProxy.address); + console.log("Fee accumulator implementation: ", cFeeAccumulator.address); console.log( "New OETHHarvester implementation: ", dOETHHarvesterImpl.address From bb3b7e67f33c2288213ff816eb319e908cb25875 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Fri, 24 May 2024 10:42:30 +1000 Subject: [PATCH 098/273] ValidatorRegistrator.stakeEth gas improvement when multiple validators --- .../NativeStaking/ValidatorRegistrator.sol | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/contracts/contracts/strategies/NativeStaking/ValidatorRegistrator.sol b/contracts/contracts/strategies/NativeStaking/ValidatorRegistrator.sol index 23d07e2e4e..a34079abd5 100644 --- a/contracts/contracts/strategies/NativeStaking/ValidatorRegistrator.sol +++ b/contracts/contracts/strategies/NativeStaking/ValidatorRegistrator.sol @@ -116,6 +116,17 @@ abstract contract ValidatorRegistrator is Governable, Pausable { IWETH9(WETH_TOKEN_ADDRESS).withdraw(requiredETH); _wethWithdrawnAndStaked(requiredETH); + /* 0x01 to indicate that withdrawal credentials will contain an EOA address that the sweeping function + * can sweep funds to. + * bytes11(0) to fill up the required zeros + * remaining bytes20 are for the address + */ + bytes memory withdrawal_credentials = abi.encodePacked( + bytes1(0x01), + bytes11(0), + address(this) + ); + uint256 validatorsLength = validators.length; // For each validator for (uint256 i = 0; i < validatorsLength; ) { @@ -127,16 +138,6 @@ abstract contract ValidatorRegistrator is Governable, Pausable { "Validator not registered" ); - /* 0x01 to indicate that withdrawal credentials will contain an EOA address that the sweeping function - * can sweep funds to. - * bytes11(0) to fill up the required zeros - * remaining bytes20 are for the address - */ - bytes memory withdrawal_credentials = abi.encodePacked( - bytes1(0x01), - bytes11(0), - address(this) - ); IDepositContract(BEACON_CHAIN_DEPOSIT_CONTRACT).deposit{ value: 32 ether }( From e163cffe4bc893b3d32d516512ce948a735ac69f Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Fri, 24 May 2024 10:47:04 +1000 Subject: [PATCH 099/273] Corrected stakeEth call in OETH processes diagram --- contracts/docs/plantuml/oethProcesses.png | Bin 433112 -> 436788 bytes contracts/docs/plantuml/oethProcesses.puml | 7 +++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/contracts/docs/plantuml/oethProcesses.png b/contracts/docs/plantuml/oethProcesses.png index 7aad421c47ad8aefdc51ba03892fb3c521593ec3..fcc51c0e34967ac65db31f1d102c0b6f370f4564 100644 GIT binary patch delta 316682 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

}=ozrZ`V{2UjTPw0%_bbU86 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

Y0s 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 H_xOJSu|Ojb diff --git a/contracts/docs/plantuml/oethProcesses.puml b/contracts/docs/plantuml/oethProcesses.puml index 43a39e8f8f..b313262224 100644 --- a/contracts/docs/plantuml/oethProcesses.puml +++ b/contracts/docs/plantuml/oethProcesses.puml @@ -87,7 +87,7 @@ return return return -reg -> nativeStrat : stake([\npubkey,\nwithdrawal_credentials,\nsignature,\ndepositDataRoot]) +reg -> nativeStrat : stakeEth([\npubkey,\nsignature,\ndepositDataRoot]) activate nativeStrat nativeStrat -> weth : withdraw(32 ETH * number of validators) activate weth @@ -98,7 +98,10 @@ loop for each validator nativeStrat -> dep : stake(\npubkey,\nwithdrawal_credentials,\nsignature,\ndepositDataRoot) activate dep -note left : 32 ETH from Native Staking Strategy\nis sent to Beacon Deposit +note left +32 ETH from Native Staking Strategy is sent to Beacon Deposit. +Withdrawal credential is the Native Staking Strategy +end note return end return From 9d302ecf6a7b5c27e646de3a6207f5f03b94f295 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Fri, 24 May 2024 15:24:38 +1000 Subject: [PATCH 100/273] Fixes to withdrawal queue WIP withdrawal queue unit tests --- contracts/contracts/interfaces/IVault.sol | 22 ++ contracts/contracts/vault/OETHVaultCore.sol | 23 +- contracts/test/vault/oeth-vault.js | 229 ++++++++++++++++++++ 3 files changed, 265 insertions(+), 9 deletions(-) diff --git a/contracts/contracts/interfaces/IVault.sol b/contracts/contracts/interfaces/IVault.sol index a764b66c87..da7aca411b 100644 --- a/contracts/contracts/interfaces/IVault.sol +++ b/contracts/contracts/interfaces/IVault.sol @@ -35,6 +35,18 @@ interface IVault { uint256 _toAssetAmount ); event DripperChanged(address indexed _dripper); + event WithdrawalRequested( + address indexed _withdrawer, + uint256 indexed _requestId, + uint256 _amount, + uint256 _queued + ); + event WithdrawalClaimed( + address indexed _withdrawer, + uint256 indexed _requestId, + uint256 _amount + ); + event WithdrawalClaimable(uint256 _claimable, uint256 _newClaimable); // Governable.sol function transferGovernance(address _newGovernor) external; @@ -228,4 +240,14 @@ interface IVault { 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/vault/OETHVaultCore.sol b/contracts/contracts/vault/OETHVaultCore.sol index 22b3b49cba..d12fb03a6e 100644 --- a/contracts/contracts/vault/OETHVaultCore.sol +++ b/contracts/contracts/vault/OETHVaultCore.sol @@ -171,10 +171,8 @@ contract OETHVaultCore is VaultCore { nonReentrant returns (uint256 requestId, uint256 queued) { - // Check the user has enough OETH to burn - require(oUSD.balanceOf(msg.sender) >= _amount, "Insufficient OETH"); - - // burn the user's oTokens + // Burn the user's OETH + // This also checks the requester has enough OETH to burn oUSD.burn(msg.sender, _amount); requestId = withdrawalQueueMetadata.nextWithdrawalIndex; @@ -250,10 +248,14 @@ contract OETHVaultCore is VaultCore { IDripper(dripper).collect(); // Add any WETH from the Dripper to the withdrawal queue - _addWithdrawalQueueLiquidity(); + uint256 addedClaimable = _addWithdrawalQueueLiquidity(); + + // If there still isn't enough liquidity in the queue to claim, revert + require( + request.queued <= queue.claimable + addedClaimable, + "pending liquidity" + ); } - // If there still isn't enough liquidity in the queue to claim, revert - require(request.queued <= queue.claimable, "pending liquidity"); // Store the updated claimed amount withdrawalQueueMetadata.claimed = queue.claimed + request.amount; @@ -278,7 +280,10 @@ contract OETHVaultCore is VaultCore { } /// @dev Adds WETH to the withdrawal queue if there is a funding shortfall. - function _addWithdrawalQueueLiquidity() internal { + function _addWithdrawalQueueLiquidity() + internal + returns (uint256 addedClaimable) + { WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata; // Check if the claimable WETH is less than the queued amount @@ -296,7 +301,7 @@ contract OETHVaultCore is VaultCore { uint256 unallocatedWeth = wethBalance - unclaimed; // the new claimable amount is the smaller of the queue shortfall or unallocated weth - uint256 addedClaimable = queueShortfall < unallocatedWeth + addedClaimable = queueShortfall < unallocatedWeth ? queueShortfall : unallocatedWeth; uint256 newClaimable = queue.claimable + addedClaimable; diff --git a/contracts/test/vault/oeth-vault.js b/contracts/test/vault/oeth-vault.js index ddc6259356..8e7bd0fc7b 100644 --- a/contracts/test/vault/oeth-vault.js +++ b/contracts/test/vault/oeth-vault.js @@ -15,10 +15,66 @@ describe("OETH Vault", function () { fixture = await oethFixture(); }); + const snapData = async (fixture) => { + const { oeth, oethVault, weth, user } = fixture; + + const oethTotal = await oeth.totalSupply(); + const userOeth = await oeth.balanceOf(user.address); + const userWeth = await weth.balanceOf(user.address); + const vaultWeth = await weth.balanceOf(oethVault.address); + const queue = await oethVault.withdrawalQueueMetadata(); + + return { + oethTotal, + userOeth, + userWeth, + vaultWeth, + queue, + }; + }; + + const assertChangedData = async (dataBefore, delta, fixture) => { + const { oeth, oethVault, weth, user } = fixture; + + expect(await oeth.totalSupply()).to.equal( + dataBefore.oethTotal.add(delta.oethTotal), + "OETH Total Supply" + ); + expect(await oeth.balanceOf(user.address)).to.equal( + dataBefore.userOeth.add(delta.userOeth), + "user's OETH balance" + ); + expect(await weth.balanceOf(user.address)).to.equal( + dataBefore.userWeth.add(delta.userWeth), + "user's WETH balance" + ); + expect(await weth.balanceOf(oethVault.address)).to.equal( + dataBefore.vaultWeth.add(delta.vaultWeth), + "Vault WETH balance" + ); + + const queueAfter = await oethVault.withdrawalQueueMetadata(); + expect(queueAfter.queued).to.equal( + dataBefore.queue.queued.add(delta.queued) + ); + expect(queueAfter.claimable).to.equal( + dataBefore.queue.claimable.add(delta.claimable) + ); + expect(queueAfter.claimed).to.equal( + dataBefore.queue.claimed.add(delta.claimed) + ); + expect(queueAfter.nextWithdrawalIndex).to.equal( + dataBefore.queue.nextWithdrawalIndex.add(delta.nextWithdrawalIndex) + ); + }; + describe("Mint", () => { it("should mint with WETH", async () => { const { oethVault, weth, josh } = fixture; + const fixtureWithUser = { ...fixture, user: josh }; + const dataBefore = await snapData(fixtureWithUser); + const amount = parseUnits("1", 18); const minOeth = parseUnits("0.8", 18); @@ -31,6 +87,20 @@ describe("OETH Vault", function () { await expect(tx) .to.emit(oethVault, "Mint") .withArgs(josh.address, amount); + + assertChangedData( + dataBefore, + { + oethTotal: amount, + userWeth: amount.mul(-1), + vaultWeth: amount, + queued: 0, + claimable: 0, + claimed: 0, + nextWithdrawalIndex: 0, + }, + fixtureWithUser + ); }); it("should not mint with any other asset", async () => { @@ -289,4 +359,163 @@ describe("OETH Vault", function () { await expect(tx).to.not.be.revertedWith("Vault still holds asset"); }); }); + + describe("with withdrawal queue", () => { + beforeEach(async () => { + const { oethVault, weth, daniel, josh, matt } = fixture; + // Mint some OETH to three users + await oethVault.connect(daniel).mint(weth.address, oethUnits("10"), "0"); + await oethVault.connect(josh).mint(weth.address, oethUnits("20"), "0"); + await oethVault.connect(matt).mint(weth.address, oethUnits("30"), "0"); + }); + const firstRequestAmount = oethUnits("5"); + const secondRequestAmount = oethUnits("5"); + it("should request first withdrawal by josh", async () => { + const { oethVault, josh } = fixture; + const fixtureWithUser = { ...fixture, user: josh }; + const dataBefore = await snapData(fixtureWithUser); + + const tx = await oethVault + .connect(josh) + .requestWithdrawal(firstRequestAmount); + + await expect(tx) + .to.emit(oethVault, "WithdrawalRequested") + .withArgs(josh.address, 0, firstRequestAmount, firstRequestAmount); + + assertChangedData( + dataBefore, + { + oethTotal: firstRequestAmount.mul(-1), + userOeth: firstRequestAmount.mul(-1), + userWeth: 0, + vaultWeth: 0, + queued: firstRequestAmount, + claimable: 0, + claimed: 0, + nextWithdrawalIndex: 1, + }, + fixtureWithUser + ); + }); + it("should request second withdrawal by matt", async () => { + const { oethVault, josh, matt } = fixture; + const fixtureWithUser = { ...fixture, user: matt }; + await oethVault.connect(josh).requestWithdrawal(firstRequestAmount); + const dataBefore = await snapData(fixtureWithUser); + + const tx = await oethVault + .connect(matt) + .requestWithdrawal(secondRequestAmount); + + await expect(tx) + .to.emit(oethVault, "WithdrawalRequested") + .withArgs( + matt.address, + 1, + secondRequestAmount, + firstRequestAmount.add(secondRequestAmount) + ); + + assertChangedData( + dataBefore, + { + oethTotal: secondRequestAmount.mul(-1), + userOeth: secondRequestAmount.mul(-1), + userWeth: 0, + vaultWeth: 0, + queued: firstRequestAmount.add(secondRequestAmount), + claimable: 0, + claimed: 0, + nextWithdrawalIndex: 1, + }, + fixtureWithUser + ); + }); + it("Should add liquidity to the withdrawal queue", async () => { + const { oethVault, josh, matt } = fixture; + const fixtureWithUser = { ...fixture, user: matt }; + await oethVault.connect(josh).requestWithdrawal(firstRequestAmount); + await oethVault.connect(matt).requestWithdrawal(secondRequestAmount); + const dataBefore = await snapData(fixtureWithUser); + + const tx = await oethVault.connect(matt).addWithdrawalQueueLiquidity(); + + await expect(tx) + .to.emit(oethVault, "WithdrawalClaimable") + .withArgs( + firstRequestAmount.add(secondRequestAmount), + firstRequestAmount.add(secondRequestAmount) + ); + + assertChangedData( + dataBefore, + { + oethTotal: 0, + userOeth: 0, + userWeth: 0, + vaultWeth: 0, + queued: 0, + claimable: firstRequestAmount.add(secondRequestAmount), + claimed: 0, + nextWithdrawalIndex: 0, + }, + fixtureWithUser + ); + }); + it("Should claim matt's request with enough liquidity", async () => { + const { oethVault, josh, matt } = fixture; + const fixtureWithUser = { ...fixture, user: matt }; + await oethVault.connect(josh).requestWithdrawal(firstRequestAmount); + await oethVault.connect(matt).requestWithdrawal(secondRequestAmount); + const requestId = 1; // ids start at 0 so the second request is at index 1 + const dataBefore = await snapData(fixtureWithUser); + + const tx = await oethVault.connect(matt).claimWithdrawal(requestId); + + await expect(tx) + .to.emit(oethVault, "WithdrawalClaimable") + .withArgs( + firstRequestAmount.add(secondRequestAmount), + firstRequestAmount.add(secondRequestAmount) + ); + + assertChangedData( + dataBefore, + { + oethTotal: secondRequestAmount.mul(-1), + userOeth: secondRequestAmount.mul(-1), + userWeth: secondRequestAmount, + vaultWeth: secondRequestAmount.mul(-1), + queued: firstRequestAmount.add(secondRequestAmount), + claimable: firstRequestAmount.add(secondRequestAmount), + claimed: secondRequestAmount, + nextWithdrawalIndex: 0, + }, + fixtureWithUser + ); + }); + + // deposit some WETH to a strategy + // Should claim the first request with enough WETH liquidity + // Should not claim the second request as not enough WETH liquidity + // Should claim after withdraw from strategy + // Should claim after withdrawAll from strategies + // Should not claim after a new mint didn't add enough liquidity + // Should claim after a new mint did add enough liquidity + + describe("Should fail when", () => { + it("request doesn't have enough OETH", async () => { + const { oethVault, josh } = fixture; + const fixtureWithUser = { ...fixture, user: josh }; + const dataBefore = await snapData(fixtureWithUser); + + const tx = oethVault + .connect(josh) + .requestWithdrawal(dataBefore.userOeth.add(1)); + + await expect(tx).to.revertedWith("Remove exceeds balance"); + }); + }); + }); }); From ef1c325d90aaf5406ef175090064c9e87f6958ea Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Fri, 24 May 2024 17:35:43 +1000 Subject: [PATCH 101/273] Add more withdrawal queue unit tests --- contracts/test/vault/oeth-vault.js | 140 ++++++++++++++++++++++++++++- 1 file changed, 138 insertions(+), 2 deletions(-) diff --git a/contracts/test/vault/oeth-vault.js b/contracts/test/vault/oeth-vault.js index 8e7bd0fc7b..80bce07e78 100644 --- a/contracts/test/vault/oeth-vault.js +++ b/contracts/test/vault/oeth-vault.js @@ -369,7 +369,7 @@ describe("OETH Vault", function () { await oethVault.connect(matt).mint(weth.address, oethUnits("30"), "0"); }); const firstRequestAmount = oethUnits("5"); - const secondRequestAmount = oethUnits("5"); + const secondRequestAmount = oethUnits("8"); it("should request first withdrawal by josh", async () => { const { oethVault, josh } = fixture; const fixtureWithUser = { ...fixture, user: josh }; @@ -398,6 +398,80 @@ describe("OETH Vault", function () { fixtureWithUser ); }); + it("should request withdrawal of zero amount", async () => { + const { oethVault, josh } = fixture; + const fixtureWithUser = { ...fixture, user: josh }; + await oethVault.connect(josh).requestWithdrawal(firstRequestAmount); + const dataBefore = await snapData(fixtureWithUser); + + const tx = await oethVault.connect(josh).requestWithdrawal(0); + + await expect(tx) + .to.emit(oethVault, "WithdrawalRequested") + .withArgs(josh.address, 1, 0, firstRequestAmount); + + assertChangedData( + dataBefore, + { + oethTotal: 0, + userOeth: 0, + userWeth: 0, + vaultWeth: 0, + queued: firstRequestAmount, + claimable: 0, + claimed: 0, + nextWithdrawalIndex: 2, + }, + fixtureWithUser + ); + }); + it("should request withdrawal with no WETH in the Vault", async () => { + const { oethVault, governor, josh, matt, weth } = fixture; + const fixtureWithUser = { ...fixture, user: josh }; + + const mockStrategy = await deployWithConfirmation("MockStrategy"); + await oethVault.connect(governor).approveStrategy(mockStrategy.address); + + // Deposit all 10 + 20 + 30 = 60 WETH to strategy + await oethVault + .connect(governor) + .depositToStrategy( + mockStrategy.address, + [weth.address], + [oethUnits("60")] + ); + + const dataBefore = await snapData(fixtureWithUser); + + await oethVault.connect(josh).requestWithdrawal(firstRequestAmount); + const tx = await oethVault + .connect(matt) + .requestWithdrawal(secondRequestAmount); + + await expect(tx) + .to.emit(oethVault, "WithdrawalRequested") + .withArgs( + matt.address, + 1, + secondRequestAmount, + firstRequestAmount.add(secondRequestAmount) + ); + + assertChangedData( + dataBefore, + { + oethTotal: secondRequestAmount.mul(-1), + userOeth: secondRequestAmount.mul(-1), + userWeth: 0, + vaultWeth: 0, + queued: firstRequestAmount.add(secondRequestAmount), + claimable: 0, + claimed: 0, + nextWithdrawalIndex: 1, + }, + fixtureWithUser + ); + }); it("should request second withdrawal by matt", async () => { const { oethVault, josh, matt } = fixture; const fixtureWithUser = { ...fixture, user: matt }; @@ -495,8 +569,59 @@ describe("OETH Vault", function () { fixtureWithUser ); }); + // Should deposit all WETH to a strategy if no WETH in the withdrawal queue + + describe("deposit some WETH to a strategy", () => { + let mockStrategy; + beforeEach(async () => { + const { oethVault, weth, governor, matt, josh } = fixture; + + mockStrategy = await deployWithConfirmation("MockStrategy"); + await oethVault.connect(governor).approveStrategy(mockStrategy.address); + + // Deposit 15 WETH of 10 + 20 + 30 = 60 WETH to strategy + await oethVault + .connect(governor) + .depositToStrategy( + mockStrategy.address, + [weth.address], + [oethUnits("15")] + ); + // Request withdrawal of 5 + 8 = 13 OETH + await oethVault.connect(josh).requestWithdrawal(firstRequestAmount); + await oethVault.connect(matt).requestWithdrawal(secondRequestAmount); + }); + it("Should not deposit allocated WETH to a strategy", async () => { + const { oethVault, weth, governor } = fixture; - // deposit some WETH to a strategy + // WETH in the vault = 60 - 15 = 45 WETH + // unallocated WETH in the Vault = 45 - 13 = 32 WETH + // 33 WETH to deposit > the 32 WETH available so it should revert + const depositAmount = oethUnits("33"); + const tx = oethVault + .connect(governor) + .depositToStrategy( + mockStrategy.address, + [weth.address], + [depositAmount] + ); + await expect(tx).to.be.revertedWith("Not enough WETH available"); + }); + it("Should deposit unallocated WETH to a strategy", async () => { + const { oethVault, weth, governor } = fixture; + + // WETH in the vault = 60 - 15 = 45 WETH + // unallocated WETH in the Vault = 45 - 13 = 32 WETH + const depositAmount = oethUnits("32"); + await oethVault + .connect(governor) + .depositToStrategy( + mockStrategy.address, + [weth.address], + [depositAmount] + ); + }); + }); // Should claim the first request with enough WETH liquidity // Should not claim the second request as not enough WETH liquidity // Should claim after withdraw from strategy @@ -516,6 +641,17 @@ describe("OETH Vault", function () { await expect(tx).to.revertedWith("Remove exceeds balance"); }); + it("capital is paused", async () => { + const { oethVault, governor, josh } = fixture; + + await oethVault.connect(governor).pauseCapital(); + + const tx = oethVault + .connect(josh) + .requestWithdrawal(firstRequestAmount); + + await expect(tx).to.be.revertedWith("Capital paused"); + }); }); }); }); From 267d0450029b92f50b6b793ab2aa0e031b5303fd Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Fri, 24 May 2024 20:04:40 +1000 Subject: [PATCH 102/273] More withdrawal queue unit tests --- contracts/contracts/vault/OETHVaultCore.sol | 2 +- contracts/test/vault/oeth-vault.js | 177 ++++++++++++++------ 2 files changed, 126 insertions(+), 53 deletions(-) diff --git a/contracts/contracts/vault/OETHVaultCore.sol b/contracts/contracts/vault/OETHVaultCore.sol index d12fb03a6e..4d1fd1843f 100644 --- a/contracts/contracts/vault/OETHVaultCore.sol +++ b/contracts/contracts/vault/OETHVaultCore.sol @@ -253,7 +253,7 @@ contract OETHVaultCore is VaultCore { // If there still isn't enough liquidity in the queue to claim, revert require( request.queued <= queue.claimable + addedClaimable, - "pending liquidity" + "queue pending liquidity" ); } diff --git a/contracts/test/vault/oeth-vault.js b/contracts/test/vault/oeth-vault.js index 80bce07e78..ca30e588b3 100644 --- a/contracts/test/vault/oeth-vault.js +++ b/contracts/test/vault/oeth-vault.js @@ -88,10 +88,11 @@ describe("OETH Vault", function () { .to.emit(oethVault, "Mint") .withArgs(josh.address, amount); - assertChangedData( + await assertChangedData( dataBefore, { oethTotal: amount, + userOeth: amount, userWeth: amount.mul(-1), vaultWeth: amount, queued: 0, @@ -369,21 +370,21 @@ describe("OETH Vault", function () { await oethVault.connect(matt).mint(weth.address, oethUnits("30"), "0"); }); const firstRequestAmount = oethUnits("5"); - const secondRequestAmount = oethUnits("8"); - it("should request first withdrawal by josh", async () => { - const { oethVault, josh } = fixture; - const fixtureWithUser = { ...fixture, user: josh }; + const secondRequestAmount = oethUnits("18"); + it("should request first withdrawal by Daniel", async () => { + const { oethVault, daniel } = fixture; + const fixtureWithUser = { ...fixture, user: daniel }; const dataBefore = await snapData(fixtureWithUser); const tx = await oethVault - .connect(josh) + .connect(daniel) .requestWithdrawal(firstRequestAmount); await expect(tx) .to.emit(oethVault, "WithdrawalRequested") - .withArgs(josh.address, 0, firstRequestAmount, firstRequestAmount); + .withArgs(daniel.address, 0, firstRequestAmount, firstRequestAmount); - assertChangedData( + await assertChangedData( dataBefore, { oethTotal: firstRequestAmount.mul(-1), @@ -410,22 +411,22 @@ describe("OETH Vault", function () { .to.emit(oethVault, "WithdrawalRequested") .withArgs(josh.address, 1, 0, firstRequestAmount); - assertChangedData( + await assertChangedData( dataBefore, { oethTotal: 0, userOeth: 0, userWeth: 0, vaultWeth: 0, - queued: firstRequestAmount, + queued: 0, claimable: 0, claimed: 0, - nextWithdrawalIndex: 2, + nextWithdrawalIndex: 1, }, fixtureWithUser ); }); - it("should request withdrawal with no WETH in the Vault", async () => { + it("should request first and second withdrawals with no WETH in the Vault", async () => { const { oethVault, governor, josh, matt, weth } = fixture; const fixtureWithUser = { ...fixture, user: josh }; @@ -457,25 +458,25 @@ describe("OETH Vault", function () { firstRequestAmount.add(secondRequestAmount) ); - assertChangedData( + await assertChangedData( dataBefore, { - oethTotal: secondRequestAmount.mul(-1), - userOeth: secondRequestAmount.mul(-1), + oethTotal: firstRequestAmount.add(secondRequestAmount).mul(-1), + userOeth: firstRequestAmount.mul(-1), userWeth: 0, vaultWeth: 0, queued: firstRequestAmount.add(secondRequestAmount), claimable: 0, claimed: 0, - nextWithdrawalIndex: 1, + nextWithdrawalIndex: 2, }, fixtureWithUser ); }); it("should request second withdrawal by matt", async () => { - const { oethVault, josh, matt } = fixture; + const { oethVault, daniel, matt } = fixture; const fixtureWithUser = { ...fixture, user: matt }; - await oethVault.connect(josh).requestWithdrawal(firstRequestAmount); + await oethVault.connect(daniel).requestWithdrawal(firstRequestAmount); const dataBefore = await snapData(fixtureWithUser); const tx = await oethVault @@ -491,14 +492,14 @@ describe("OETH Vault", function () { firstRequestAmount.add(secondRequestAmount) ); - assertChangedData( + await assertChangedData( dataBefore, { oethTotal: secondRequestAmount.mul(-1), userOeth: secondRequestAmount.mul(-1), userWeth: 0, vaultWeth: 0, - queued: firstRequestAmount.add(secondRequestAmount), + queued: secondRequestAmount, claimable: 0, claimed: 0, nextWithdrawalIndex: 1, @@ -506,14 +507,14 @@ describe("OETH Vault", function () { fixtureWithUser ); }); - it("Should add liquidity to the withdrawal queue", async () => { - const { oethVault, josh, matt } = fixture; - const fixtureWithUser = { ...fixture, user: matt }; - await oethVault.connect(josh).requestWithdrawal(firstRequestAmount); - await oethVault.connect(matt).requestWithdrawal(secondRequestAmount); + it("Should add claimable liquidity to the withdrawal queue", async () => { + const { oethVault, daniel, josh } = fixture; + const fixtureWithUser = { ...fixture, user: josh }; + await oethVault.connect(daniel).requestWithdrawal(firstRequestAmount); + await oethVault.connect(josh).requestWithdrawal(secondRequestAmount); const dataBefore = await snapData(fixtureWithUser); - const tx = await oethVault.connect(matt).addWithdrawalQueueLiquidity(); + const tx = await oethVault.connect(josh).addWithdrawalQueueLiquidity(); await expect(tx) .to.emit(oethVault, "WithdrawalClaimable") @@ -522,7 +523,7 @@ describe("OETH Vault", function () { firstRequestAmount.add(secondRequestAmount) ); - assertChangedData( + await assertChangedData( dataBefore, { oethTotal: 0, @@ -538,14 +539,14 @@ describe("OETH Vault", function () { ); }); it("Should claim matt's request with enough liquidity", async () => { - const { oethVault, josh, matt } = fixture; - const fixtureWithUser = { ...fixture, user: matt }; - await oethVault.connect(josh).requestWithdrawal(firstRequestAmount); - await oethVault.connect(matt).requestWithdrawal(secondRequestAmount); + const { oethVault, daniel, josh } = fixture; + const fixtureWithUser = { ...fixture, user: josh }; + await oethVault.connect(daniel).requestWithdrawal(firstRequestAmount); + await oethVault.connect(josh).requestWithdrawal(secondRequestAmount); const requestId = 1; // ids start at 0 so the second request is at index 1 const dataBefore = await snapData(fixtureWithUser); - const tx = await oethVault.connect(matt).claimWithdrawal(requestId); + const tx = await oethVault.connect(josh).claimWithdrawal(requestId); await expect(tx) .to.emit(oethVault, "WithdrawalClaimable") @@ -554,14 +555,14 @@ describe("OETH Vault", function () { firstRequestAmount.add(secondRequestAmount) ); - assertChangedData( + await assertChangedData( dataBefore, { - oethTotal: secondRequestAmount.mul(-1), - userOeth: secondRequestAmount.mul(-1), + oethTotal: 0, + userOeth: 0, userWeth: secondRequestAmount, vaultWeth: secondRequestAmount.mul(-1), - queued: firstRequestAmount.add(secondRequestAmount), + queued: 0, claimable: firstRequestAmount.add(secondRequestAmount), claimed: secondRequestAmount, nextWithdrawalIndex: 0, @@ -571,15 +572,16 @@ describe("OETH Vault", function () { }); // Should deposit all WETH to a strategy if no WETH in the withdrawal queue - describe("deposit some WETH to a strategy", () => { + describe("when deposit some WETH to a strategy", () => { let mockStrategy; beforeEach(async () => { - const { oethVault, weth, governor, matt, josh } = fixture; + const { oethVault, weth, governor, daniel, josh } = fixture; mockStrategy = await deployWithConfirmation("MockStrategy"); await oethVault.connect(governor).approveStrategy(mockStrategy.address); // Deposit 15 WETH of 10 + 20 + 30 = 60 WETH to strategy + // This leave 60 - 15 = 45 WETH in the vault await oethVault .connect(governor) .depositToStrategy( @@ -587,17 +589,18 @@ describe("OETH Vault", function () { [weth.address], [oethUnits("15")] ); - // Request withdrawal of 5 + 8 = 13 OETH - await oethVault.connect(josh).requestWithdrawal(firstRequestAmount); - await oethVault.connect(matt).requestWithdrawal(secondRequestAmount); + // Request withdrawal of 5 + 18 = 23 OETH + // This leave 45 - 23 = 22 WETH unallocated to the withdrawal queue + await oethVault.connect(daniel).requestWithdrawal(firstRequestAmount); + await oethVault.connect(josh).requestWithdrawal(secondRequestAmount); }); it("Should not deposit allocated WETH to a strategy", async () => { const { oethVault, weth, governor } = fixture; // WETH in the vault = 60 - 15 = 45 WETH - // unallocated WETH in the Vault = 45 - 13 = 32 WETH - // 33 WETH to deposit > the 32 WETH available so it should revert - const depositAmount = oethUnits("33"); + // unallocated WETH in the Vault = 45 - 23 = 22 WETH + // 23 WETH to deposit > the 22 WETH available so it should revert + const depositAmount = oethUnits("23"); const tx = oethVault .connect(governor) .depositToStrategy( @@ -611,8 +614,8 @@ describe("OETH Vault", function () { const { oethVault, weth, governor } = fixture; // WETH in the vault = 60 - 15 = 45 WETH - // unallocated WETH in the Vault = 45 - 13 = 32 WETH - const depositAmount = oethUnits("32"); + // unallocated WETH in the Vault = 45 - 23 = 22 WETH + const depositAmount = oethUnits("22"); await oethVault .connect(governor) .depositToStrategy( @@ -621,13 +624,83 @@ describe("OETH Vault", function () { [depositAmount] ); }); + it("Should claim first request with enough liquidity", async () => { + const { oethVault, daniel } = fixture; + const fixtureWithUser = { ...fixture, user: daniel }; + const dataBefore = await snapData(fixtureWithUser); + + const tx = await oethVault.connect(daniel).claimWithdrawal(0); + + await expect(tx) + .to.emit(oethVault, "WithdrawalClaimed") + .withArgs(daniel.address, 0, firstRequestAmount); + + await assertChangedData( + dataBefore, + { + oethTotal: 0, + userOeth: 0, + userWeth: firstRequestAmount, + vaultWeth: firstRequestAmount.mul(-1), + queued: 0, + claimable: firstRequestAmount.add(secondRequestAmount), + claimed: firstRequestAmount, + nextWithdrawalIndex: 0, + }, + fixtureWithUser + ); + }); + it("Should claim a second request with enough WETH liquidity", async () => { + const { oethVault, matt } = fixture; + const fixtureWithUser = { ...fixture, user: matt }; + + // Set the claimable amount to the queued amount + await oethVault.addWithdrawalQueueLiquidity(); + + // WETH in the vault = 60 - 15 = 45 WETH + // unallocated WETH in the Vault = 45 - 23 = 22 WETH + // Matt request all unallocated WETH to be withdrawn + const requestAmount = oethUnits("22"); + await oethVault.connect(matt).requestWithdrawal(requestAmount); + + const dataBefore = await snapData(fixtureWithUser); + + const tx = await oethVault.connect(matt).claimWithdrawal(2); + + await expect(tx) + .to.emit(oethVault, "WithdrawalClaimed") + .withArgs(matt.address, 2, requestAmount); + + await assertChangedData( + dataBefore, + { + oethTotal: 0, + userOeth: 0, + userWeth: requestAmount, + vaultWeth: requestAmount.mul(-1), + queued: 0, + claimable: requestAmount, + claimed: requestAmount, + nextWithdrawalIndex: 0, + }, + fixtureWithUser + ); + }); + it("Should not claim a new request when pending queue liquidity", async () => { + const { oethVault, matt } = fixture; + + // Matt request 23 OETH to be withdrawn when only 22 WETH is unallocated to existing requests + const requestAmount = oethUnits("23"); + await oethVault.connect(matt).requestWithdrawal(requestAmount); + + const tx = oethVault.connect(matt).claimWithdrawal(2); + await expect(tx).to.be.revertedWith("queue pending liquidity"); + }); + // Should claim after withdraw from strategy + // Should claim after withdrawAll from strategies + // Should not claim after a new mint didn't add enough liquidity + // Should claim after a new mint did add enough liquidity }); - // Should claim the first request with enough WETH liquidity - // Should not claim the second request as not enough WETH liquidity - // Should claim after withdraw from strategy - // Should claim after withdrawAll from strategies - // Should not claim after a new mint didn't add enough liquidity - // Should claim after a new mint did add enough liquidity describe("Should fail when", () => { it("request doesn't have enough OETH", async () => { From beb91707a2ef09a9529cb9e177c08cdfbd186a1e Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Fri, 24 May 2024 21:04:12 +1000 Subject: [PATCH 103/273] Fixed adjusting the vault value for the withdrawal queue --- contracts/contracts/vault/OETHVaultCore.sol | 13 ++--- contracts/test/vault/oeth-vault.js | 60 +++++++++++++++++++-- 2 files changed, 59 insertions(+), 14 deletions(-) diff --git a/contracts/contracts/vault/OETHVaultCore.sol b/contracts/contracts/vault/OETHVaultCore.sol index 4d1fd1843f..1064b583a9 100644 --- a/contracts/contracts/vault/OETHVaultCore.sol +++ b/contracts/contracts/vault/OETHVaultCore.sol @@ -355,17 +355,12 @@ contract OETHVaultCore is VaultCore { super._allocate(); } - function _totalValueInVault() - internal - view - override - returns (uint256 value) - { - value = super._totalValueInVault(); + function _totalValue() internal view override returns (uint256 value) { + value = super._totalValue(); + // Need to remove WETH that is reserved for the withdrawal queue. + // reserved for the withdrawal queue = cumulative queued total - total claimed WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata; - // Need to remove WETH that is reserved for the withdrawal queue - // reserver for the withdrawal queue = cumulative queued total - total claimed value = value + queue.claimed - queue.queued; } } diff --git a/contracts/test/vault/oeth-vault.js b/contracts/test/vault/oeth-vault.js index ca30e588b3..7bf828a275 100644 --- a/contracts/test/vault/oeth-vault.js +++ b/contracts/test/vault/oeth-vault.js @@ -650,7 +650,7 @@ describe("OETH Vault", function () { fixtureWithUser ); }); - it("Should claim a second request with enough WETH liquidity", async () => { + it("Should claim a new request with enough WETH liquidity", async () => { const { oethVault, matt } = fixture; const fixtureWithUser = { ...fixture, user: matt }; @@ -686,7 +686,7 @@ describe("OETH Vault", function () { fixtureWithUser ); }); - it("Should not claim a new request when pending queue liquidity", async () => { + it("Should fail to claim a new request with NOT enough WETH liquidity", async () => { const { oethVault, matt } = fixture; // Matt request 23 OETH to be withdrawn when only 22 WETH is unallocated to existing requests @@ -696,10 +696,60 @@ describe("OETH Vault", function () { const tx = oethVault.connect(matt).claimWithdrawal(2); await expect(tx).to.be.revertedWith("queue pending liquidity"); }); - // Should claim after withdraw from strategy + // Should claim after liquidity added to the queue from withdraw from strategy // Should claim after withdrawAll from strategies - // Should not claim after a new mint didn't add enough liquidity - // Should claim after a new mint did add enough liquidity + + it("Should fail to claim a new request after mint with NOT enough liquidity", async () => { + const { oethVault, daniel, matt, weth } = fixture; + + // Matt requests all 30 OETH to be withdrawn which is not enough liquidity + const requestAmount = oethUnits("30"); + await oethVault.connect(matt).requestWithdrawal(requestAmount); + + // WETH in the vault = 60 - 15 = 45 WETH + // unallocated WETH in the Vault = 45 - 23 = 22 WETH + // Add another 6 WETH so the unallocated WETH is 22 + 6 = 28 WETH + await oethVault.connect(daniel).mint(weth.address, oethUnits("6"), 0); + + const tx = oethVault.connect(matt).claimWithdrawal(2); + await expect(tx).to.be.revertedWith("queue pending liquidity"); + }); + it("Should claim a new request after mint adds enough liquidity", async () => { + const { oethVault, daniel, matt, weth } = fixture; + + // Set the claimable amount to the queued amount + await oethVault.addWithdrawalQueueLiquidity(); + + // Matt requests all 30 OETH to be withdrawn which is currently 8 WETH short + const requestAmount = oethUnits("30"); + await oethVault.connect(matt).requestWithdrawal(requestAmount); + + const fixtureWithUser = { ...fixture, user: daniel }; + const dataBeforeMint = await snapData(fixtureWithUser); + + // WETH in the vault = 60 - 15 = 45 WETH + // unallocated WETH in the Vault = 45 - 23 = 22 WETH + // Add another 8 WETH so the unallocated WETH is 22 + 8 = 30 WETH + const mintAmount = oethUnits("8"); + await oethVault.connect(daniel).mint(weth.address, mintAmount, 0); + + await assertChangedData( + dataBeforeMint, + { + oethTotal: mintAmount, + userOeth: mintAmount, + userWeth: mintAmount.mul(-1), + vaultWeth: mintAmount, + queued: 0, + claimable: requestAmount, + claimed: 0, + nextWithdrawalIndex: 0, + }, + fixtureWithUser + ); + + await oethVault.connect(matt).claimWithdrawal(2); + }); }); describe("Should fail when", () => { From 10259cefa5a0241d0277e5816431d2dfd040f498 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Fri, 24 May 2024 22:15:53 +1000 Subject: [PATCH 104/273] Add more withdrawal queue tests --- contracts/test/vault/oeth-vault.js | 88 +++++++++++++++++++++++++++++- 1 file changed, 85 insertions(+), 3 deletions(-) diff --git a/contracts/test/vault/oeth-vault.js b/contracts/test/vault/oeth-vault.js index 7bf828a275..1152e58e63 100644 --- a/contracts/test/vault/oeth-vault.js +++ b/contracts/test/vault/oeth-vault.js @@ -577,7 +577,12 @@ describe("OETH Vault", function () { beforeEach(async () => { const { oethVault, weth, governor, daniel, josh } = fixture; - mockStrategy = await deployWithConfirmation("MockStrategy"); + const dMockStrategy = await deployWithConfirmation("MockStrategy"); + mockStrategy = await ethers.getContractAt( + "MockStrategy", + dMockStrategy.address + ); + await mockStrategy.setWithdrawAll(weth.address, oethVault.address); await oethVault.connect(governor).approveStrategy(mockStrategy.address); // Deposit 15 WETH of 10 + 20 + 30 = 60 WETH to strategy @@ -696,9 +701,86 @@ describe("OETH Vault", function () { const tx = oethVault.connect(matt).claimWithdrawal(2); await expect(tx).to.be.revertedWith("queue pending liquidity"); }); - // Should claim after liquidity added to the queue from withdraw from strategy - // Should claim after withdrawAll from strategies + it("Should claim a new request after withdraw from strategy adds enough liquidity", async () => { + const { oethVault, daniel, matt, strategist, weth } = fixture; + // Set the claimable amount to the queued amount + await oethVault.addWithdrawalQueueLiquidity(); + + // Matt requests all 30 OETH to be withdrawn which is currently 8 WETH short + const requestAmount = oethUnits("30"); + await oethVault.connect(matt).requestWithdrawal(requestAmount); + + const fixtureWithUser = { ...fixture, user: daniel }; + const dataBeforeMint = await snapData(fixtureWithUser); + + // WETH in the vault = 60 - 15 = 45 WETH + // unallocated WETH in the Vault = 45 - 23 = 22 WETH + // Add another 8 WETH so the unallocated WETH is 22 + 8 = 30 WETH + const withdrawAmount = oethUnits("8"); + await oethVault + .connect(strategist) + .withdrawFromStrategy( + mockStrategy.address, + [weth.address], + [withdrawAmount] + ); + + await assertChangedData( + dataBeforeMint, + { + oethTotal: 0, + userOeth: 0, + userWeth: 0, + vaultWeth: withdrawAmount, + queued: 0, + claimable: requestAmount, + claimed: 0, + nextWithdrawalIndex: 0, + }, + fixtureWithUser + ); + + await oethVault.connect(matt).claimWithdrawal(2); + }); + it("Should claim a new request after withdrawAll from strategies adds enough liquidity", async () => { + const { oethVault, daniel, matt, strategist, weth } = fixture; + + // Set the claimable amount to the queued amount + await oethVault.addWithdrawalQueueLiquidity(); + + // Matt requests all 30 OETH to be withdrawn which is currently 8 WETH short + const requestAmount = oethUnits("30"); + await oethVault.connect(matt).requestWithdrawal(requestAmount); + + const fixtureWithUser = { ...fixture, user: daniel }; + const dataBeforeMint = await snapData(fixtureWithUser); + const strategyBalanceBefore = await weth.balanceOf( + mockStrategy.address + ); + + // WETH in the vault = 60 - 15 = 45 WETH + // unallocated WETH in the Vault = 45 - 23 = 22 WETH + // Add another 8 WETH so the unallocated WETH is 22 + 8 = 30 WETH + await oethVault.connect(strategist).withdrawAllFromStrategies(); + + await assertChangedData( + dataBeforeMint, + { + oethTotal: 0, + userOeth: 0, + userWeth: 0, + vaultWeth: strategyBalanceBefore, + queued: 0, + claimable: requestAmount, + claimed: 0, + nextWithdrawalIndex: 0, + }, + fixtureWithUser + ); + + await oethVault.connect(matt).claimWithdrawal(2); + }); it("Should fail to claim a new request after mint with NOT enough liquidity", async () => { const { oethVault, daniel, matt, weth } = fixture; From dd7632d1e28269abdc283c48fd9f6e95e27fe34f Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Fri, 24 May 2024 22:16:17 +1000 Subject: [PATCH 105/273] Implemented withdrawAll in MockStrategy --- contracts/contracts/mocks/MockStrategy.sol | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) 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; + } } From 84d9a7f6e69fd22e164077c7e9d4fbf82be6c810 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Fri, 24 May 2024 22:39:15 +1000 Subject: [PATCH 106/273] Fixed bug in claimWithdrawals Added more withdrawal queue coverage --- contracts/contracts/vault/OETHVaultCore.sol | 1 + contracts/test/vault/oeth-vault.js | 83 ++++++++++++++++++++- 2 files changed, 82 insertions(+), 2 deletions(-) diff --git a/contracts/contracts/vault/OETHVaultCore.sol b/contracts/contracts/vault/OETHVaultCore.sol index 1064b583a9..6b67cb2594 100644 --- a/contracts/contracts/vault/OETHVaultCore.sol +++ b/contracts/contracts/vault/OETHVaultCore.sol @@ -220,6 +220,7 @@ contract OETHVaultCore is VaultCore { nonReentrant returns (uint256[] memory amounts, uint256 totalAmount) { + amounts = new uint256[](requestIds.length); for (uint256 i = 0; i < requestIds.length; ++i) { amounts[i] = _claimWithdrawal(requestIds[i]); totalAmount += amounts[i]; diff --git a/contracts/test/vault/oeth-vault.js b/contracts/test/vault/oeth-vault.js index 1152e58e63..dfd2b12f36 100644 --- a/contracts/test/vault/oeth-vault.js +++ b/contracts/test/vault/oeth-vault.js @@ -538,7 +538,7 @@ describe("OETH Vault", function () { fixtureWithUser ); }); - it("Should claim matt's request with enough liquidity", async () => { + it("Should claim second request with enough liquidity", async () => { const { oethVault, daniel, josh } = fixture; const fixtureWithUser = { ...fixture, user: josh }; await oethVault.connect(daniel).requestWithdrawal(firstRequestAmount); @@ -548,6 +548,9 @@ describe("OETH Vault", function () { const tx = await oethVault.connect(josh).claimWithdrawal(requestId); + await expect(tx) + .to.emit(oethVault, "WithdrawalClaimed") + .withArgs(josh.address, requestId, secondRequestAmount); await expect(tx) .to.emit(oethVault, "WithdrawalClaimable") .withArgs( @@ -570,7 +573,43 @@ describe("OETH Vault", function () { fixtureWithUser ); }); - // Should deposit all WETH to a strategy if no WETH in the withdrawal queue + it("Should claim multiple requests with enough liquidity", async () => { + const { oethVault, matt } = fixture; + const fixtureWithUser = { ...fixture, user: matt }; + await oethVault.connect(matt).requestWithdrawal(firstRequestAmount); + await oethVault.connect(matt).requestWithdrawal(secondRequestAmount); + const dataBefore = await snapData(fixtureWithUser); + + const tx = await oethVault.connect(matt).claimWithdrawals([0, 1]); + + await expect(tx) + .to.emit(oethVault, "WithdrawalClaimed") + .withArgs(matt.address, 0, firstRequestAmount); + await expect(tx) + .to.emit(oethVault, "WithdrawalClaimed") + .withArgs(matt.address, 1, secondRequestAmount); + await expect(tx) + .to.emit(oethVault, "WithdrawalClaimable") + .withArgs( + firstRequestAmount.add(secondRequestAmount), + firstRequestAmount.add(secondRequestAmount) + ); + + await assertChangedData( + dataBefore, + { + oethTotal: 0, + userOeth: 0, + userWeth: firstRequestAmount.add(secondRequestAmount), + vaultWeth: firstRequestAmount.add(secondRequestAmount).mul(-1), + queued: 0, + claimable: firstRequestAmount.add(secondRequestAmount), + claimed: firstRequestAmount.add(secondRequestAmount), + nextWithdrawalIndex: 0, + }, + fixtureWithUser + ); + }); describe("when deposit some WETH to a strategy", () => { let mockStrategy; @@ -743,6 +782,46 @@ describe("OETH Vault", function () { await oethVault.connect(matt).claimWithdrawal(2); }); + it("Should claim a new request after withdrawAllFromStrategy adds enough liquidity", async () => { + const { oethVault, daniel, matt, strategist, weth } = fixture; + + // Set the claimable amount to the queued amount + await oethVault.addWithdrawalQueueLiquidity(); + + // Matt requests all 30 OETH to be withdrawn which is currently 8 WETH short + const requestAmount = oethUnits("30"); + await oethVault.connect(matt).requestWithdrawal(requestAmount); + + const fixtureWithUser = { ...fixture, user: daniel }; + const dataBeforeMint = await snapData(fixtureWithUser); + const strategyBalanceBefore = await weth.balanceOf( + mockStrategy.address + ); + + // WETH in the vault = 60 - 15 = 45 WETH + // unallocated WETH in the Vault = 45 - 23 = 22 WETH + // Add another 8 WETH so the unallocated WETH is 22 + 8 = 30 WETH + await oethVault + .connect(strategist) + .withdrawAllFromStrategy(mockStrategy.address); + + await assertChangedData( + dataBeforeMint, + { + oethTotal: 0, + userOeth: 0, + userWeth: 0, + vaultWeth: strategyBalanceBefore, + queued: 0, + claimable: requestAmount, + claimed: 0, + nextWithdrawalIndex: 0, + }, + fixtureWithUser + ); + + await oethVault.connect(matt).claimWithdrawal(2); + }); it("Should claim a new request after withdrawAll from strategies adds enough liquidity", async () => { const { oethVault, daniel, matt, strategist, weth } = fixture; From bb8577fd816ee3ae7dbfca09dcf208836c7a3620 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Fri, 24 May 2024 22:50:52 +1000 Subject: [PATCH 107/273] Complete code coverage of OETH Vault unit tests --- contracts/test/vault/oeth-vault.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/contracts/test/vault/oeth-vault.js b/contracts/test/vault/oeth-vault.js index dfd2b12f36..59299c8602 100644 --- a/contracts/test/vault/oeth-vault.js +++ b/contracts/test/vault/oeth-vault.js @@ -243,6 +243,12 @@ describe("OETH Vault", function () { expect(vaultBalanceBefore).to.eq(vaultBalanceAfter); }); + it("should redeem zero amount without revert", async () => { + const { oethVault, daniel } = fixture; + + await oethVault.connect(daniel).redeem(0, 0); + }); + it("should revert on liquidity error", async () => { const { oethVault, daniel } = fixture; const tx = oethVault From e853081e49d564fa8d0e284ff7868fd389f2280f Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Mon, 27 May 2024 16:11:57 +1000 Subject: [PATCH 108/273] Added fork test for registering a validator twice --- contracts/test/behaviour/ssvStrategy.js | 63 +++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/contracts/test/behaviour/ssvStrategy.js b/contracts/test/behaviour/ssvStrategy.js index 9b97868cf8..39c292fda6 100644 --- a/contracts/test/behaviour/ssvStrategy.js +++ b/contracts/test/behaviour/ssvStrategy.js @@ -218,6 +218,69 @@ const shouldBehaveLikeAnSsvStrategy = (context) => { await registerAndStakeEth(); }); + it("Should fail to register a validator twice", async () => { + const { + addresses, + ssv, + nativeStakingSSVStrategy, + validatorRegistrator, + testValidator, + } = await context(); + + const stakeAmount = oethUnits("32"); + + await depositToStrategy(stakeAmount); + + await setERC20TokenBalance( + nativeStakingSSVStrategy.address, + ssv, + "1000", + hre + ); + + const { cluster } = await getClusterInfo({ + ownerAddress: nativeStakingSSVStrategy.address, + operatorids: testValidator.operatorIds, + chainId: hre.network.config.chainId, + ssvNetwork: addresses.SSVNetwork, + }); + + // Register a new validator the first time + await nativeStakingSSVStrategy + .connect(validatorRegistrator) + .registerSsvValidator( + testValidator.publicKey, + testValidator.operatorIds, + testValidator.sharesData, + stakeAmount, + cluster + ); + + const emptyCluster = { + validatorCount: 0, + networkFeeIndex: 0, + index: 0, + active: true, + balance: 0, + }; + + // Try to register the same validator again in a different cluster + const tx2 = nativeStakingSSVStrategy + .connect(validatorRegistrator) + .registerSsvValidator( + testValidator.publicKey, + [1, 20, 300, 4000], + testValidator.sharesData, + stakeAmount, + emptyCluster + ); + + // Waffle's custom error matcher is not working here. + // Checking the trace, the error thrown is ValidatorAlreadyExistsWithData + // which is what we expect. + await expect(tx2).to.be.reverted; + }); + it("Should emit correct values in deposit event", async () => { const { weth, nativeStakingSSVStrategy } = await context(); From 12bba64a87155ae1de0942b638ce5fe3f8b02820 Mon Sep 17 00:00:00 2001 From: Domen Grabec Date: Tue, 28 May 2024 13:33:58 +0200 Subject: [PATCH 109/273] Stake funds with confirmations for front-running protection of Beacon Deposits (#2074) * contract changes and tests for gated protection against front running * Update off-chain validator registration process to also consider stake threshold * front run protection changes (#2076) * Added Holesky deploy script * Fixed OUSD metapool fork test * Generated latest NativeStakingSSVStrategy contract diagrams * Deployed new NativeStakingSSVStrategy to Holesky --------- Co-authored-by: Nicholas Addison --- .../mocks/BeaconChainDepositContractMock.sol | 53 ---- .../contracts/mocks/MockDepositContract.sol | 80 ++++++ contracts/contracts/mocks/MockSSVNetwork.sol | 28 +- .../NativeStaking/ValidatorRegistrator.sol | 44 ++- .../deploy/holesky/010_upgrade_strategy.js | 48 ++++ contracts/deploy/mainnet/000_mock.js | 9 +- .../deploy/mainnet/097_native_ssv_staking.js | 16 +- .../deployments/holesky/.migrations.json | 3 +- .../holesky/NativeStakingSSVStrategy.json | 254 +++++++++++++---- .../a7af3565925bcd06d3e7b2ed59f01c90.json | 107 +++++++ .../docs/NativeStakingSSVStrategySquashed.svg | 260 +++++++++--------- .../docs/NativeStakingSSVStrategyStorage.svg | 122 ++++---- contracts/tasks/validator.js | 25 +- contracts/test/_fixture.js | 3 + contracts/test/behaviour/ssvStrategy.js | 8 + contracts/test/helpers.js | 5 +- contracts/test/strategies/nativeSSVStaking.js | 132 +++++++++ .../ousd-metapool-balanced-pool.fork-test.js | 2 +- contracts/utils/addresses.js | 6 +- 19 files changed, 906 insertions(+), 299 deletions(-) delete mode 100644 contracts/contracts/mocks/BeaconChainDepositContractMock.sol create mode 100644 contracts/contracts/mocks/MockDepositContract.sol create mode 100644 contracts/deploy/holesky/010_upgrade_strategy.js create mode 100644 contracts/deployments/holesky/solcInputs/a7af3565925bcd06d3e7b2ed59f01c90.json diff --git a/contracts/contracts/mocks/BeaconChainDepositContractMock.sol b/contracts/contracts/mocks/BeaconChainDepositContractMock.sol deleted file mode 100644 index 3d8b995efe..0000000000 --- a/contracts/contracts/mocks/BeaconChainDepositContractMock.sol +++ /dev/null @@ -1,53 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -contract BeaconChainDepositContractMock { - /// @notice A processed deposit event. - event DepositEvent( - bytes pubkey, - bytes withdrawal_credentials, - bytes amount, - bytes signature, - bytes index - ); - - /// @notice Submit a Phase 0 DepositData object. - /// @param pubkey A BLS12-381 public key. - /// @param withdrawal_credentials Commitment to a public key for withdrawals. - /// @param signature A BLS12-381 signature. - /// @param deposit_data_root The SHA-256 hash of the SSZ-encoded DepositData object. - /// Used as a protection against malformed input. - function deposit( - bytes calldata pubkey, - bytes calldata withdrawal_credentials, - bytes calldata signature, - bytes32 deposit_data_root - ) external payable { - // Extended ABI length checks since dynamic types are used. - require(pubkey.length == 48, "DepositContract: invalid pubkey length"); - require( - withdrawal_credentials.length == 32, - "DepositContract: invalid withdrawal_credentials length" - ); - require( - signature.length == 96, - "DepositContract: invalid signature length" - ); - - // Check deposit amount - require(msg.value >= 1 ether, "DepositContract: deposit value too low"); - require( - msg.value % 1 gwei == 0, - "DepositContract: deposit value not multiple of gwei" - ); - uint256 deposit_amount = msg.value / 1 gwei; - require( - deposit_amount <= type(uint64).max, - "DepositContract: deposit value too high" - ); - require( - deposit_data_root != 0, - "DepositContract: invalid deposit_data_root" - ); - } -} diff --git a/contracts/contracts/mocks/MockDepositContract.sol b/contracts/contracts/mocks/MockDepositContract.sol new file mode 100644 index 0000000000..dbe41ec780 --- /dev/null +++ b/contracts/contracts/mocks/MockDepositContract.sol @@ -0,0 +1,80 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import { IDepositContract } from "./../interfaces/IDepositContract.sol"; + +contract MockDepositContract is IDepositContract { + uint256 deposit_count; + + function deposit( + bytes calldata pubkey, + bytes calldata withdrawal_credentials, + bytes calldata signature, + bytes32 deposit_data_root + ) external payable override { + require(pubkey.length == 48, "DepositContract: invalid pubkey length"); + require( + withdrawal_credentials.length == 32, + "DepositContract: invalid withdrawal_credentials length" + ); + require( + signature.length == 96, + "DepositContract: invalid signature length" + ); + + // Check deposit amount + require(msg.value >= 1 ether, "DepositContract: deposit value too low"); + require( + msg.value % 1 gwei == 0, + "DepositContract: deposit value not multiple of gwei" + ); + uint256 deposit_amount = msg.value / 1 gwei; + require( + deposit_amount <= type(uint64).max, + "DepositContract: deposit value too high" + ); + + // Emit `DepositEvent` log + bytes memory amount = to_little_endian_64(uint64(deposit_amount)); + emit DepositEvent( + pubkey, + withdrawal_credentials, + amount, + signature, + to_little_endian_64(uint64(deposit_count)) + ); + require( + deposit_data_root != 0, + "DepositContract: invalid deposit_data_root" + ); + } + + function get_deposit_root() external view override returns (bytes32) { + // just return some bytes32 + return sha256(abi.encodePacked(deposit_count, bytes16(0))); + } + + /// @notice Query the current deposit count. + /// @return The deposit count encoded as a little endian 64-bit number. + function get_deposit_count() external view override returns (bytes memory) { + return to_little_endian_64(uint64(deposit_count)); + } + + function to_little_endian_64(uint64 value) + internal + pure + returns (bytes memory ret) + { + ret = new bytes(8); + bytes8 bytesValue = bytes8(value); + // Byteswapping during copying to bytes. + ret[0] = bytesValue[7]; + ret[1] = bytesValue[6]; + ret[2] = bytesValue[5]; + ret[3] = bytesValue[4]; + ret[4] = bytesValue[3]; + ret[5] = bytesValue[2]; + ret[6] = bytesValue[1]; + ret[7] = bytesValue[0]; + } +} diff --git a/contracts/contracts/mocks/MockSSVNetwork.sol b/contracts/contracts/mocks/MockSSVNetwork.sol index b2ef1e8509..38b36e3e5f 100644 --- a/contracts/contracts/mocks/MockSSVNetwork.sol +++ b/contracts/contracts/mocks/MockSSVNetwork.sol @@ -1,6 +1,32 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; +import { Cluster } from "./../interfaces/ISSVNetwork.sol"; + contract MockSSVNetwork { - constructor() {} + function registerValidator( + bytes calldata publicKey, + uint64[] calldata operatorIds, + bytes calldata sharesData, + uint256 amount, + Cluster memory cluster + ) external {} + + function exitValidator( + bytes calldata publicKey, + uint64[] calldata operatorIds + ) external {} + + function removeValidator( + bytes calldata publicKey, + uint64[] calldata operatorIds, + Cluster memory cluster + ) external {} + + function deposit( + address clusterOwner, + uint64[] calldata operatorIds, + uint256 amount, + Cluster memory cluster + ) external {} } diff --git a/contracts/contracts/strategies/NativeStaking/ValidatorRegistrator.sol b/contracts/contracts/strategies/NativeStaking/ValidatorRegistrator.sol index a34079abd5..219ebfb45e 100644 --- a/contracts/contracts/strategies/NativeStaking/ValidatorRegistrator.sol +++ b/contracts/contracts/strategies/NativeStaking/ValidatorRegistrator.sol @@ -37,9 +37,15 @@ abstract contract ValidatorRegistrator is Governable, Pausable { uint256 public activeDepositedValidators; /// @notice State of the validators keccak256(pubKey) => state mapping(bytes32 => VALIDATOR_STATE) public validatorsStates; - + /// @notice The account that is allowed to modify stakeETHThreshold and reset stakeETHTally + address public stakingMonitor; + /// @notice Amount of ETH that can be staked before staking on the contract is suspended + /// and the governor needs to approve further staking + uint256 public stakeETHThreshold; + /// @notice Amount of ETH that can has been staked since the last governor approval. + uint256 public stakeETHTally; // For future use - uint256[50] private __gap; + uint256[47] private __gap; enum VALIDATOR_STATE { REGISTERED, // validator is registered on the SSV network @@ -49,10 +55,13 @@ abstract contract ValidatorRegistrator is Governable, Pausable { } event RegistratorChanged(address newAddress); + event StakingMonitorChanged(address newAddress); event ETHStaked(bytes pubkey, uint256 amount, bytes withdrawal_credentials); event SSVValidatorRegistered(bytes pubkey, uint64[] operatorIds); event SSVValidatorExitInitiated(bytes pubkey, uint64[] operatorIds); event SSVValidatorExitCompleted(bytes pubkey, uint64[] operatorIds); + event StakeETHThresholdChanged(uint256 amount); + event StakeETHTallyReset(); /// @dev Throws if called by any account other than the Registrator modifier onlyRegistrator() { @@ -63,6 +72,12 @@ abstract contract ValidatorRegistrator is Governable, Pausable { _; } + /// @dev Throws if called by any account other than the Staking monitor + modifier onlyStakingMonitor() { + require(msg.sender == stakingMonitor, "Caller is not the Monitor"); + _; + } + /// @dev Throws if called by any account other than the Strategist modifier onlyStrategist() { require( @@ -94,6 +109,25 @@ abstract contract ValidatorRegistrator is Governable, Pausable { validatorRegistrator = _address; } + /// @notice Set the address of the staking monitor that is allowed to reset stakeETHTally + function setStakingMonitor(address _address) external onlyGovernor { + emit StakingMonitorChanged(_address); + stakingMonitor = _address; + } + + /// @notice Set the amount of ETH that can be staked before staking monitor + // needs to a approve further staking by resetting the stake ETH tally + function setStakeETHThreshold(uint256 _amount) external onlyGovernor { + emit StakeETHThresholdChanged(_amount); + stakeETHThreshold = _amount; + } + + /// @notice Reset the stakeETHTally + function resetStakeETHTally() external onlyStakingMonitor { + emit StakeETHTallyReset(); + stakeETHTally = 0; + } + /// @notice Stakes WETH to the node validators /// @param validators A list of validator data needed to stake. /// The `ValidatorStakeData` struct contains the pubkey, signature and depositDataRoot. @@ -112,6 +146,12 @@ abstract contract ValidatorRegistrator is Governable, Pausable { "insufficient WETH" ); + require( + stakeETHTally + requiredETH <= stakeETHThreshold, + "Staking ETH over threshold" + ); + stakeETHTally += requiredETH; + // Convert required ETH from WETH IWETH9(WETH_TOKEN_ADDRESS).withdraw(requiredETH); _wethWithdrawnAndStaked(requiredETH); diff --git a/contracts/deploy/holesky/010_upgrade_strategy.js b/contracts/deploy/holesky/010_upgrade_strategy.js new file mode 100644 index 0000000000..a073a9d2b1 --- /dev/null +++ b/contracts/deploy/holesky/010_upgrade_strategy.js @@ -0,0 +1,48 @@ +const { upgradeNativeStakingSSVStrategy } = require("../deployActions"); +const { withConfirmation } = require("../../utils/deploy"); +const { resolveContract } = require("../../utils/resolvers"); +const addresses = require("../../utils/addresses"); +const { parseEther } = require("ethers/lib/utils"); +// const { impersonateAndFund } = require("../../utils/signers.js"); + +const mainExport = async () => { + console.log("Running 010 deployment on Holesky..."); + + console.log("Upgrading native staking strategy"); + await upgradeNativeStakingSSVStrategy(); + + const cNativeStakingStrategy = await resolveContract( + "NativeStakingSSVStrategyProxy", + "NativeStakingSSVStrategy" + ); + + const { governorAddr } = await getNamedAccounts(); + const sGovernor = await ethers.provider.getSigner(governorAddr); + + await withConfirmation( + cNativeStakingStrategy + .connect(sGovernor) + // Holesky defender relayer + .setStakingMonitor(addresses.holesky.Guardian) + ); + + await withConfirmation( + cNativeStakingStrategy + .connect(sGovernor) + .setStakeETHThreshold(parseEther("64")) + ); + + console.log( + `Set the staking monitor to ${addresses.holesky.Guardian} and stake ETH threshold to 32 ETH` + ); + + console.log("Running 010 deployment done"); + return true; +}; + +mainExport.id = "010_upgrade_strategy"; +mainExport.tags = []; +mainExport.dependencies = []; +mainExport.skip = () => false; + +module.exports = mainExport; diff --git a/contracts/deploy/mainnet/000_mock.js b/contracts/deploy/mainnet/000_mock.js index 1de8037eb4..0c3fac6db7 100644 --- a/contracts/deploy/mainnet/000_mock.js +++ b/contracts/deploy/mainnet/000_mock.js @@ -136,6 +136,11 @@ const deployMocks = async ({ getNamedAccounts, deployments }) => { from: deployerAddr, }); + // Mock SSV Network + await deploy("MockDepositContract", { + from: deployerAddr, + }); + const dai = await ethers.getContract("MockDAI"); const usdc = await ethers.getContract("MockUSDC"); const usdt = await ethers.getContract("MockUSDT"); @@ -425,10 +430,6 @@ const deployMocks = async ({ getNamedAccounts, deployments }) => { from: deployerAddr, }); - await deploy("BeaconChainDepositContractMock", { - from: deployerAddr, - }); - console.log("000_mock deploy done."); return true; diff --git a/contracts/deploy/mainnet/097_native_ssv_staking.js b/contracts/deploy/mainnet/097_native_ssv_staking.js index 70503d6891..64fa655a42 100644 --- a/contracts/deploy/mainnet/097_native_ssv_staking.js +++ b/contracts/deploy/mainnet/097_native_ssv_staking.js @@ -197,7 +197,21 @@ module.exports = deploymentWithGovernanceProposal( signature: "setRegistrator(address)", args: [addresses.mainnet.validatorRegistrator], }, - // 6. Upgrade the OETH Harvester + // 6. set staking threshold + { + contract: cStrategy, + signature: "setStakeETHThreshold(uint256)", + // TODO: confirm this number makes sense + args: [ethers.utils.parseEther("1024")], // 32ETH * 32 + }, + // 7. set staking monitor + { + contract: cStrategy, + signature: "setStakingMonitor(address)", + // The 5/8 multisig + args: [addresses.mainnet.Guardian], + }, + // 8. Upgrade the OETH Harvester { contract: cOETHHarvesterProxy, signature: "upgradeTo(address)", diff --git a/contracts/deployments/holesky/.migrations.json b/contracts/deployments/holesky/.migrations.json index 4335e20f75..f9a0e00a78 100644 --- a/contracts/deployments/holesky/.migrations.json +++ b/contracts/deployments/holesky/.migrations.json @@ -7,5 +7,6 @@ "006_update_registrator": 1715184342, "007_upgrade_strategy": 1715251466, "008_upgrade_strategy": 1715341541, - "009_upgrade_strategy": 1716360052 + "009_upgrade_strategy": 1716360052, + "010_upgrade_strategy": 1716890877 } \ No newline at end of file diff --git a/contracts/deployments/holesky/NativeStakingSSVStrategy.json b/contracts/deployments/holesky/NativeStakingSSVStrategy.json index f466e3a4fb..4600085e5f 100644 --- a/contracts/deployments/holesky/NativeStakingSSVStrategy.json +++ b/contracts/deployments/holesky/NativeStakingSSVStrategy.json @@ -1,5 +1,5 @@ { - "address": "0xa48dE0659EA8d9CFC293F47FD0d74d644690EB4B", + "address": "0x0D875FD10401F57e117bd53f82411c706247AD4f", "abi": [ { "inputs": [ @@ -422,6 +422,38 @@ "name": "SSVValidatorRegistered", "type": "event" }, + { + "anonymous": false, + "inputs": [], + "name": "StakeETHTallyReset", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "StakeETHThresholdChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "newAddress", + "type": "address" + } + ], + "name": "StakingMonitorChanged", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -1054,6 +1086,13 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [], + "name": "resetStakeETHTally", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -1155,6 +1194,58 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + } + ], + "name": "setStakeETHThreshold", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_address", + "type": "address" + } + ], + "name": "setStakingMonitor", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "stakeETHTally", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "stakeETHThreshold", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -1185,6 +1276,19 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [], + "name": "stakingMonitor", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -1315,34 +1419,34 @@ "type": "receive" } ], - "transactionHash": "0x8ca768edbc9a7d1fc3fcd31ced7c70f27cba30f49f1916f6a7f68934956feb76", + "transactionHash": "0x065cc099e02ada3882563847d84334b70335d2c03ef455ffb1710506b00a329c", "receipt": { "to": null, "from": "0x1b94CA50D3Ad9f8368851F8526132272d1a5028C", - "contractAddress": "0xa48dE0659EA8d9CFC293F47FD0d74d644690EB4B", - "transactionIndex": 8, - "gasUsed": "4205791", - "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000002004000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000010000000000000000000000000000000000000000020000000000000000008000000000000000000000000000000000000000000000000", - "blockHash": "0x1a290a506c0cf9148a26e778adacf7bd59da033eede5b446f4f2a8b0ce51f393", - "transactionHash": "0x8ca768edbc9a7d1fc3fcd31ced7c70f27cba30f49f1916f6a7f68934956feb76", + "contractAddress": "0x0D875FD10401F57e117bd53f82411c706247AD4f", + "transactionIndex": 130, + "gasUsed": "4375470", + "logsBloom": "0x00000000000000000002000000000000000000000000000000000000000000000000000000000000000000040000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000000004000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000018000000000010000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0xb813c87a79b54dfd4eeb9cebc658d24eb347d0b2e94ec4f40934550ef9e6681b", + "transactionHash": "0x065cc099e02ada3882563847d84334b70335d2c03ef455ffb1710506b00a329c", "logs": [ { - "transactionIndex": 8, - "blockNumber": 1589658, - "transactionHash": "0x8ca768edbc9a7d1fc3fcd31ced7c70f27cba30f49f1916f6a7f68934956feb76", - "address": "0xa48dE0659EA8d9CFC293F47FD0d74d644690EB4B", + "transactionIndex": 130, + "blockNumber": 1626892, + "transactionHash": "0x065cc099e02ada3882563847d84334b70335d2c03ef455ffb1710506b00a329c", + "address": "0x0D875FD10401F57e117bd53f82411c706247AD4f", "topics": [ "0xc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000001b94ca50d3ad9f8368851f8526132272d1a5028c" ], "data": "0x", - "logIndex": 12, - "blockHash": "0x1a290a506c0cf9148a26e778adacf7bd59da033eede5b446f4f2a8b0ce51f393" + "logIndex": 209, + "blockHash": "0xb813c87a79b54dfd4eeb9cebc658d24eb347d0b2e94ec4f40934550ef9e6681b" } ], - "blockNumber": 1589658, - "cumulativeGasUsed": "4985268", + "blockNumber": 1626892, + "cumulativeGasUsed": "13590958", "status": 1, "byzantium": true }, @@ -1357,11 +1461,11 @@ "0x65a289f4BF934c964C942eFF6E6F83b6481BE550", "0x4242424242424242424242424242424242424242" ], - "numDeployments": 4, - "solcInputHash": "279a9fe8a2da81dca55abd3c6ec521f8", - "metadata": "{\"compiler\":{\"version\":\"0.8.7+commit.e28d00a7\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"platformAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"vaultAddress\",\"type\":\"address\"}],\"internalType\":\"struct InitializableAbstractStrategy.BaseStrategyConfig\",\"name\":\"_baseConfig\",\"type\":\"tuple\"},{\"internalType\":\"address\",\"name\":\"_wethAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_ssvToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_ssvNetwork\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_feeAccumulator\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_beaconChainDepositContract\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"AccountingConsensusRewards\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"noOfValidators\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"remainingValidators\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"wethSentToVault\",\"type\":\"uint256\"}],\"name\":\"AccountingFullyWithdrawnValidator\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"validatorsDelta\",\"type\":\"int256\"},{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"consensusRewardsDelta\",\"type\":\"int256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"wethToVault\",\"type\":\"uint256\"}],\"name\":\"AccountingManuallyFixed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"remainingValidators\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"wethSentToVault\",\"type\":\"uint256\"}],\"name\":\"AccountingValidatorSlashed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"Deposit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"pubkey\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"withdrawal_credentials\",\"type\":\"bytes\"}],\"name\":\"ETHStaked\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"start\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"end\",\"type\":\"uint256\"}],\"name\":\"FuseIntervalUpdated\",\"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\":\"address\",\"name\":\"_oldHarvesterAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_newHarvesterAddress\",\"type\":\"address\"}],\"name\":\"HarvesterAddressesUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"}],\"name\":\"PTokenAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"}],\"name\":\"PTokenRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Paused\",\"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\":\"newAddress\",\"type\":\"address\"}],\"name\":\"RegistratorChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"_oldAddresses\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"_newAddresses\",\"type\":\"address[]\"}],\"name\":\"RewardTokenAddressesUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"rewardToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"RewardTokenCollected\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"pubkey\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"}],\"name\":\"SSVValidatorExitCompleted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"pubkey\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"}],\"name\":\"SSVValidatorExitInitiated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"pubkey\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"}],\"name\":\"SSVValidatorRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Unpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"Withdrawal\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"BEACON_CHAIN_DEPOSIT_CONTRACT\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_ACCUMULATOR_ADDRESS\",\"outputs\":[{\"internalType\":\"address payable\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MAX_STAKE\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MIN_FIX_ACCOUNTING_CADENCE\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"SSV_NETWORK_ADDRESS\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"SSV_TOKEN_ADDRESS\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"VAULT_ADDRESS\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"WETH_TOKEN_ADDRESS\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"activeDepositedValidators\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"assetToPToken\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"}],\"name\":\"checkBalance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"claimGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"collectRewardTokens\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"consensusRewards\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"depositAll\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"validatorCount\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"networkFeeIndex\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"index\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"active\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"internalType\":\"struct Cluster\",\"name\":\"cluster\",\"type\":\"tuple\"}],\"name\":\"depositSSV\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"depositedWethAccountedFor\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"doAccounting\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"accountingValid\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"publicKey\",\"type\":\"bytes\"},{\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"}],\"name\":\"exitSsvValidator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fuseIntervalEnd\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fuseIntervalStart\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRewardTokenAddresses\",\"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\":\"harvesterAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"_rewardTokenAddresses\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"_assets\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"_pTokens\",\"type\":\"address[]\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isGovernor\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastFixAccountingBlockNumber\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"int256\",\"name\":\"_validatorsDelta\",\"type\":\"int256\"},{\"internalType\":\"int256\",\"name\":\"_consensusRewardsDelta\",\"type\":\"int256\"},{\"internalType\":\"uint256\",\"name\":\"_ethToVaultAmount\",\"type\":\"uint256\"}],\"name\":\"manuallyFixAccounting\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"paused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"platformAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"publicKey\",\"type\":\"bytes\"},{\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"},{\"internalType\":\"bytes\",\"name\":\"sharesData\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"validatorCount\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"networkFeeIndex\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"index\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"active\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"internalType\":\"struct Cluster\",\"name\":\"cluster\",\"type\":\"tuple\"}],\"name\":\"registerSsvValidator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_assetIndex\",\"type\":\"uint256\"}],\"name\":\"removePToken\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"publicKey\",\"type\":\"bytes\"},{\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"validatorCount\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"networkFeeIndex\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"index\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"active\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"internalType\":\"struct Cluster\",\"name\":\"cluster\",\"type\":\"tuple\"}],\"name\":\"removeSsvValidator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"rewardTokenAddresses\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"safeApproveAllTokens\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_fuseIntervalStart\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_fuseIntervalEnd\",\"type\":\"uint256\"}],\"name\":\"setFuseInterval\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_harvesterAddress\",\"type\":\"address\"}],\"name\":\"setHarvesterAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"}],\"name\":\"setPTokenAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"setRegistrator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"_rewardTokenAddresses\",\"type\":\"address[]\"}],\"name\":\"setRewardTokenAddresses\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"pubkey\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"depositDataRoot\",\"type\":\"bytes32\"}],\"internalType\":\"struct ValidatorStakeData[]\",\"name\":\"validators\",\"type\":\"tuple[]\"}],\"name\":\"stakeEth\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"}],\"name\":\"supportsAsset\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"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\":\"validatorRegistrator\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"validatorsStates\",\"outputs\":[{\"internalType\":\"enum ValidatorRegistrator.VALIDATOR_STATE\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"vaultAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"withdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdrawAll\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"author\":\"Origin Protocol Inc\",\"details\":\"This contract handles WETH and ETH and in some operations interchanges between the two. Any WETH that is on the contract across multiple blocks (and not just transitory within a transaction) is considered an asset. Meaning deposits increase the balance of the asset and withdrawal decrease it. As opposed to all our other strategies the WETH doesn't immediately get deposited into an underlying strategy and can be present across multiple blocks waiting to be unwrapped to ETH and staked to validators. This separation of WETH and ETH is required since the rewards (reward token) is also in ETH. To simplify the accounting of WETH there is another difference in behavior compared to the other strategies. To withdraw WETH asset - exit message is posted to validators and the ETH hits this contract with multiple days delay. In order to simplify the WETH accounting upon detection of such an event the ValidatorAccountant immediately wraps ETH to WETH and sends it to the Vault. On the other hand any ETH on the contract (across multiple blocks) is there either: - as a result of already accounted for consensus rewards - as a result of not yet accounted for consensus rewards - as a results of not yet accounted for full validator withdrawals (or validator slashes) Even though the strategy assets and rewards are a very similar asset the consensus layer rewards and the execution layer rewards are considered rewards and those are dripped to the Vault over a configurable time interval and not immediately.\",\"kind\":\"dev\",\"methods\":{\"checkBalance(address)\":{\"params\":{\"_asset\":\"Address of weth asset\"},\"returns\":{\"balance\":\" Total value of (W)ETH\"}},\"constructor\":{\"params\":{\"_baseConfig\":\"Base strategy config with platformAddress (ERC-4626 Vault contract), eg sfrxETH or sDAI, and vaultAddress (OToken Vault contract), eg VaultProxy or OETHVaultProxy\",\"_beaconChainDepositContract\":\"Address of the beacon chain deposit contract\",\"_feeAccumulator\":\"Address of the fee accumulator receiving execution layer validator rewards\",\"_ssvNetwork\":\"Address of the SSV Network contract\",\"_ssvToken\":\"Address of the Erc20 SSV Token contract\",\"_wethAddress\":\"Address of the Erc20 WETH Token contract\"}},\"deposit(address,uint256)\":{\"params\":{\"_amount\":\"Amount of assets that were transferred to the strategy by the vault.\",\"_asset\":\"Address of asset to deposit. Has to be WETH.\"}},\"depositSSV(uint64[],uint256,(uint32,uint64,uint64,bool,uint256))\":{\"details\":\"A SSV cluster is defined by the SSVOwnerAddress and the set of operatorIds. uses \\\"onlyStrategist\\\" modifier so continuous front-running can't DOS our maintenance service that tries to top up SSV tokens.\",\"params\":{\"cluster\":\"The SSV cluster details that must be derived from emitted events from the SSVNetwork contract.\"}},\"doAccounting()\":{\"details\":\"This function could in theory be permission-less but lets allow only the Registrator (Defender Action) to call it for now.\",\"returns\":{\"accountingValid\":\"true if accounting was successful, false if fuse is blown\"}},\"getRewardTokenAddresses()\":{\"returns\":{\"_0\":\"address[] the reward token addresses.\"}},\"initialize(address[],address[],address[])\":{\"params\":{\"_assets\":\"Addresses of initial supported assets\",\"_pTokens\":\"Platform Token corresponding addresses\",\"_rewardTokenAddresses\":\"Address of reward token for platform\"}},\"manuallyFixAccounting(int256,int256,uint256)\":{\"details\":\"There is a case when a validator(s) gets slashed so much that the eth swept from the beacon chain enters the fuse area and there are no consensus rewards on the contract to \\\"dip into\\\"/use. To increase the amount of unaccounted ETH over the fuse end interval we need to reduce the amount of active deposited validators and immediately send WETH to the vault, so it doesn't interfere with further accounting.\",\"params\":{\"_consensusRewardsDelta\":\"adjust the accounted for consensus rewards up or down\",\"_ethToVaultAmount\":\"the amount of ETH that gets wrapped into WETH and sent to the Vault\",\"_validatorsDelta\":\"adjust the active validators by up to plus three or minus three\"}},\"paused()\":{\"details\":\"Returns true if the contract is paused, and false otherwise.\"},\"removePToken(uint256)\":{\"params\":{\"_assetIndex\":\"Index of the asset to be removed\"}},\"setHarvesterAddress(address)\":{\"params\":{\"_harvesterAddress\":\"Address of the harvester contract.\"}},\"setPTokenAddress(address,address)\":{\"params\":{\"_asset\":\"Address for the asset\",\"_pToken\":\"Address for the corresponding platform token\"}},\"setRewardTokenAddresses(address[])\":{\"params\":{\"_rewardTokenAddresses\":\"Array of reward token addresses\"}},\"stakeEth((bytes,bytes,bytes32)[])\":{\"params\":{\"validators\":\"A list of validator data needed to stake. The `ValidatorStakeData` struct contains the pubkey, signature and depositDataRoot. Only the registrator can call this function.\"}},\"supportsAsset(address)\":{\"params\":{\"_asset\":\"The address of the asset token.\"}},\"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\"}},\"withdraw(address,address,uint256)\":{\"params\":{\"_amount\":\"Amount of WETH to withdraw\",\"_asset\":\"WETH to withdraw\",\"_recipient\":\"Address to receive withdrawn assets\"}}},\"stateVariables\":{\"FEE_ACCUMULATOR_ADDRESS\":{\"details\":\"this address will receive Execution layer rewards - These are rewards earned for executing transactions on the Ethereum network as part of block proposals. They include priority fees (fees paid by users for their transactions to be included) and MEV rewards (rewards for arranging transactions in a way that benefits the validator).\"},\"depositedWethAccountedFor\":{\"details\":\"This contract receives WETH as the deposit asset, but unlike other strategies doesn't immediately deposit it to an underlying platform. Rather a special privilege account stakes it to the validators. For that reason calling WETH.balanceOf(this) in a deposit function can contain WETH that has just been deposited and also WETH that has previously been deposited. To keep a correct count we need to keep track of WETH that has already been accounted for. This value represents the amount of WETH balance of this contract that has already been accounted for by the deposit events. It is important to note that this variable is not concerned with WETH that is a result of full/partial withdrawal of the validators. It is strictly concerned with WETH that has been deposited and is waiting to be staked.\"}},\"title\":\"Native Staking SSV Strategy\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"BEACON_CHAIN_DEPOSIT_CONTRACT()\":{\"notice\":\"The address of the beacon chain deposit contract\"},\"FEE_ACCUMULATOR_ADDRESS()\":{\"notice\":\"Fee collector address\"},\"MAX_STAKE()\":{\"notice\":\"The maximum amount of ETH that can be staked by a validator\"},\"MIN_FIX_ACCOUNTING_CADENCE()\":{\"notice\":\"The minimum amount of blocks that need to pass between two calls to manuallyFixAccounting\"},\"SSV_NETWORK_ADDRESS()\":{\"notice\":\"The address of the SSV Network contract used to interface with\"},\"SSV_TOKEN_ADDRESS()\":{\"notice\":\"SSV ERC20 token that serves as a payment for operating SSV validators\"},\"VAULT_ADDRESS()\":{\"notice\":\"Address of the OETH Vault proxy contract\"},\"WETH_TOKEN_ADDRESS()\":{\"notice\":\"The address of the Wrapped ETH (WETH) token contract\"},\"activeDepositedValidators()\":{\"notice\":\"The number of validators that have 32 (!) ETH actively deposited. When a new deposit to a validator happens this number increases, when a validator exit is detected this number decreases.\"},\"assetToPToken(address)\":{\"notice\":\"asset => pToken (Platform Specific Token Address)\"},\"checkBalance(address)\":{\"notice\":\"Returns the total value of (W)ETH that is staked to the validators and WETH deposits that are still to be staked. This does not include ETH from consensus rewards sitting in this strategy or ETH from MEV rewards in the FeeAccumulator. These rewards are harvested and sent to the Dripper so will eventually be sent to the Vault as WETH.\"},\"claimGovernance()\":{\"notice\":\"Claim Governance of the contract to a new account (`newGovernor`). Can only be called by the new Governor.\"},\"collectRewardTokens()\":{\"notice\":\"Collect accumulated reward token and send to Vault.\"},\"consensusRewards()\":{\"notice\":\"Keeps track of the total consensus rewards swept from the beacon chain\"},\"deposit(address,uint256)\":{\"notice\":\"Unlike other strategies, this does not deposit assets into the underlying platform. It just checks the asset is WETH and emits the Deposit event. To deposit WETH into validators `registerSsvValidator` and `stakeEth` must be used. Will NOT revert if the strategy is paused from an accounting failure.\"},\"depositAll()\":{\"notice\":\"Unlike other strategies, this does not deposit assets into the underlying platform. It just emits the Deposit event. To deposit WETH into validators `registerSsvValidator` and `stakeEth` must be used. Will NOT revert if the strategy is paused from an accounting failure.\"},\"depositSSV(uint64[],uint256,(uint32,uint64,uint64,bool,uint256))\":{\"notice\":\"Deposits more SSV Tokens to the SSV Network contract which is used to pay the SSV Operators.\"},\"doAccounting()\":{\"notice\":\"This notion page offers a good explanation of how the accounting functions https://www.notion.so/originprotocol/Limited-simplified-native-staking-accounting-67a217c8420d40678eb943b9da0ee77d In short, after dividing by 32, if the ETH remaining on the contract falls between 0 and fuseIntervalStart, the accounting function will treat that ETH as Beacon chain consensus rewards. On the contrary, if after dividing by 32, the ETH remaining on the contract falls between fuseIntervalEnd and 32, the accounting function will treat that as a validator slashing.Perform the accounting attributing beacon chain ETH to either full or partial withdrawals. Returns true when accounting is valid and fuse isn't \\\"blown\\\". Returns false when fuse is blown.\"},\"exitSsvValidator(bytes,uint64[])\":{\"notice\":\"Exit a validator from the Beacon chain. The staked ETH will eventually swept to this native staking strategy. Only the registrator can call this function.\"},\"fuseIntervalEnd()\":{\"notice\":\"end of fuse interval\"},\"fuseIntervalStart()\":{\"notice\":\"start of fuse interval\"},\"getRewardTokenAddresses()\":{\"notice\":\"Get the reward token addresses.\"},\"governor()\":{\"notice\":\"Returns the address of the current Governor.\"},\"harvesterAddress()\":{\"notice\":\"Address of the Harvester contract allowed to collect reward tokens\"},\"initialize(address[],address[],address[])\":{\"notice\":\"initialize function, to set up initial internal state\"},\"isGovernor()\":{\"notice\":\"Returns true if the caller is the current Governor.\"},\"lastFixAccountingBlockNumber()\":{\"notice\":\"last block number manuallyFixAccounting has been called\"},\"manuallyFixAccounting(int256,int256,uint256)\":{\"notice\":\"Allow the Strategist to fix the accounting of this strategy and unpause.\"},\"platformAddress()\":{\"notice\":\"Address of the underlying platform\"},\"registerSsvValidator(bytes,uint64[],bytes,uint256,(uint32,uint64,uint64,bool,uint256))\":{\"notice\":\"Registers a new validator in the SSV Cluster. Only the registrator can call this function.\"},\"removePToken(uint256)\":{\"notice\":\"Remove a supported asset by passing its index. This method can only be called by the system Governor\"},\"removeSsvValidator(bytes,uint64[],(uint32,uint64,uint64,bool,uint256))\":{\"notice\":\"Remove a validator from the SSV Cluster. Make sure `exitSsvValidator` is called before and the validate has exited the Beacon chain. If removed before the validator has exited the beacon chain will result in the validator being slashed. Only the registrator can call this function.\"},\"rewardTokenAddresses(uint256)\":{\"notice\":\"Address of the reward tokens. eg CRV, BAL, CVX, AURA\"},\"safeApproveAllTokens()\":{\"notice\":\"Approves the SSV Network contract to transfer SSV tokens for deposits\"},\"setFuseInterval(uint256,uint256)\":{\"notice\":\"set fuse interval values\"},\"setHarvesterAddress(address)\":{\"notice\":\"Set the Harvester contract that can collect rewards.\"},\"setPTokenAddress(address,address)\":{\"notice\":\"Provide support for asset by passing its pToken address. This method can only be called by the system Governor\"},\"setRegistrator(address)\":{\"notice\":\"Set the address of the registrator which can register, exit and remove validators\"},\"setRewardTokenAddresses(address[])\":{\"notice\":\"Set the reward token addresses. Any old addresses will be overwritten.\"},\"stakeEth((bytes,bytes,bytes32)[])\":{\"notice\":\"Stakes WETH to the node validators\"},\"supportsAsset(address)\":{\"notice\":\"Returns bool indicating whether asset is supported by strategy.\"},\"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 strategy contracts, i.e. mistaken sends.\"},\"validatorRegistrator()\":{\"notice\":\"Address of the registrator - allowed to register, exit and remove validators\"},\"validatorsStates(bytes32)\":{\"notice\":\"State of the validators keccak256(pubKey) => state\"},\"vaultAddress()\":{\"notice\":\"Address of the OToken vault\"},\"withdraw(address,address,uint256)\":{\"notice\":\"Withdraw WETH from this contract. Used only if some WETH for is lingering on the contract. That can happen when: - the deposit was not a multiple of 32 WETH - someone sent WETH directly to this contract Will NOT revert if the strategy is paused from an accounting failure.\"},\"withdrawAll()\":{\"notice\":\"transfer all WETH deposits back to the vault. This does not withdraw from the validators. That has to be done separately with the `exitSsvValidator` and `removeSsvValidator` operations. This does not withdraw any execution rewards from the FeeAccumulator or consensus rewards in this strategy. Any ETH in this strategy that was swept from a full validator withdrawal will not be withdrawn. ETH from full validator withdrawals is sent to the Vault using `doAccounting`. Will NOT revert if the strategy is paused from an accounting failure.\"}},\"notice\":\"Strategy to deploy funds into DVT validators powered by the SSV Network\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol\":\"NativeStakingSSVStrategy\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"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\",\"keccak256\":\"0xe68ed7fb8766ed1e888291f881e36b616037f852b37d96877045319ad298ba87\",\"license\":\"MIT\"},\"@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/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\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@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\",\"keccak256\":\"0xfaad496c1c944b6259b7dc70b4865eb1775d6402bc0c81b38a0b24d9f525ae37\",\"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/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\",\"keccak256\":\"0x598f90bdbc854250bbd5991426bfb43367207e64e33109c41aa8b54323fd8d8e\",\"license\":\"MIT\"},\"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 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 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 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\",\"keccak256\":\"0xbef02bd5257e61dec0a6be4b1531064a7fdfeb4043885443a1902fb5d1b23e1b\",\"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/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 function removeAsset(address _asset) external;\\n}\\n\",\"keccak256\":\"0xa03ba17b6224bec26290794760fc807e017260406037b4f812970701888e72c8\",\"license\":\"MIT\"},\"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\",\"keccak256\":\"0x05b7dce6c24d3cd4e48b5c6346d86e5e40ecc3291bcdf3f3ef091c98fc826519\",\"license\":\"MIT\"},\"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\\nimport { Governable } from \\\"../../governance/Governable.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 is Governable {\\n /// @notice The address of the Native Staking Strategy\\n address public immutable STRATEGY;\\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 }\\n\\n /**\\n * @dev Accept ETH\\n */\\n receive() external payable {}\\n}\\n\",\"keccak256\":\"0xb8fda3b87dc5d6f8aee4bf1d015a585211e5b5a319dfa4b0f4770e3f5a2d5939\",\"license\":\"MIT\"},\"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_ADDRESS;\\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 _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 address _feeAccumulator,\\n address _beaconChainDepositContract\\n )\\n InitializableAbstractStrategy(_baseConfig)\\n ValidatorAccountant(\\n _wethAddress,\\n _baseConfig.vaultAddress,\\n _beaconChainDepositContract,\\n _ssvNetwork\\n )\\n {\\n SSV_TOKEN_ADDRESS = _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 /// @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_TOKEN_ADDRESS).deposit{ value: ethRewards }();\\n\\n emit RewardTokenCollected(\\n harvesterAddress,\\n WETH_TOKEN_ADDRESS,\\n ethRewards\\n );\\n IERC20(WETH_TOKEN_ADDRESS).safeTransfer(\\n harvesterAddress,\\n ethRewards\\n );\\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_TOKEN_ADDRESS, \\\"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_TOKEN_ADDRESS).balanceOf(\\n address(this)\\n );\\n uint256 newWeth = wethBalance - depositedWethAccountedFor;\\n\\n if (newWeth > 0) {\\n depositedWethAccountedFor = wethBalance;\\n\\n _deposit(WETH_TOKEN_ADDRESS, newWeth);\\n }\\n }\\n\\n /// @notice Withdraw WETH from this contract. Used only if some WETH for is lingering on the contract. That\\n /// can happen when:\\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 _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 emit Withdrawal(_asset, address(0), _amount);\\n IERC20(_asset).safeTransfer(_recipient, _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_TOKEN_ADDRESS).balanceOf(\\n address(this)\\n );\\n if (wethBalance > 0) {\\n _withdraw(vaultAddress, WETH_TOKEN_ADDRESS, wethBalance);\\n }\\n }\\n\\n function _abstractSetPToken(address _asset, address) internal override {}\\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_TOKEN_ADDRESS, \\\"Unsupported asset\\\");\\n\\n balance =\\n // add the ETH that has been staked in validators\\n activeDepositedValidators *\\n 32 ether +\\n // add the WETH in the strategy from deposits that are still to be staked\\n IERC20(WETH_TOKEN_ADDRESS).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_TOKEN_ADDRESS;\\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_ADDRESS).approve(\\n SSV_NETWORK_ADDRESS,\\n type(uint256).max\\n );\\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 ||\\n msg.sender == WETH_TOKEN_ADDRESS,\\n \\\"eth not from allowed contracts\\\"\\n );\\n }\\n\\n function _wethWithdrawnToVault(uint256 _amount) internal override {\\n emit Withdrawal(WETH_TOKEN_ADDRESS, address(0), _amount);\\n }\\n\\n function _wethWithdrawnAndStaked(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 direclty\\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\",\"keccak256\":\"0x937ce31cd4b90ad532fdde874dc02eaf0a29a800c2c2292d2d6cb71afa75f32d\",\"license\":\"MIT\"},\"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 /// @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 MAX_STAKE = 32 ether;\\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 constructor(\\n address _wethAddress,\\n address _vaultAddress,\\n address _beaconChainDepositContract,\\n address _ssvNetwork\\n )\\n ValidatorRegistrator(\\n _wethAddress,\\n _vaultAddress,\\n _beaconChainDepositContract,\\n _ssvNetwork\\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 _fuseIntervalStart < 32 ether &&\\n _fuseIntervalEnd < 32 ether &&\\n _fuseIntervalEnd - _fuseIntervalStart >= 4 ether,\\n \\\"incorrect fuse interval\\\"\\n );\\n\\n emit FuseIntervalUpdated(_fuseIntervalStart, _fuseIntervalEnd);\\n\\n fuseIntervalStart = _fuseIntervalStart;\\n fuseIntervalEnd = _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 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 >= MAX_STAKE) {\\n uint256 fullyWithdrawnValidators;\\n // safe since MAX_STAKE is hardcoded to 32ETH\\n unchecked {\\n // explicitly cast to uint256 as we want to round to a whole number of validators\\n fullyWithdrawnValidators = uint256(newSweptETH / MAX_STAKE);\\n }\\n activeDepositedValidators -= fullyWithdrawnValidators;\\n\\n uint256 wethToVault = MAX_STAKE * fullyWithdrawnValidators;\\n IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: wethToVault }();\\n // slither-disable-next-line unchecked-transfer\\n IWETH9(WETH_TOKEN_ADDRESS).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 < 32 ether, \\\"unexpected accounting\\\");\\n\\n // If no Beacon chain consensus rewards swept\\n if (ethRemaining == 0) {\\n // do nothing\\n return accountingValid;\\n }\\n // Beacon chain consensus rewards swept (partial validator withdrawals)\\n else if (ethRemaining < fuseIntervalStart) {\\n // solhint-disable-next-line reentrancy\\n consensusRewards += ethRemaining;\\n emit AccountingConsensusRewards(ethRemaining);\\n }\\n // Beacon chain consensus rewards swept but also a slashed validator fully exited\\n else if (ethRemaining > fuseIntervalEnd) {\\n IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: ethRemaining }();\\n // slither-disable-next-line unchecked-transfer\\n IWETH9(WETH_TOKEN_ADDRESS).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 {\\n require(\\n lastFixAccountingBlockNumber + MIN_FIX_ACCOUNTING_CADENCE <\\n block.number,\\n \\\"manuallyFixAccounting 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 emit AccountingManuallyFixed(\\n _validatorsDelta,\\n _consensusRewardsDelta,\\n _ethToVaultAmount\\n );\\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_TOKEN_ADDRESS).deposit{ value: _ethToVaultAmount }();\\n // slither-disable-next-line unchecked-transfer\\n IWETH9(WETH_TOKEN_ADDRESS).transfer(\\n VAULT_ADDRESS,\\n _ethToVaultAmount\\n );\\n _wethWithdrawnToVault(_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 Withdrawal event\\n function _wethWithdrawnToVault(uint256 _amount) internal virtual;\\n}\\n\",\"keccak256\":\"0x0adba45b3fa66233c9e9bc0575ca388ebcd027cba2546278c5887065b95da708\",\"license\":\"MIT\"},\"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 address of the Wrapped ETH (WETH) token contract\\n address public immutable WETH_TOKEN_ADDRESS;\\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_ADDRESS;\\n /// @notice Address of the OETH Vault proxy contract\\n address public immutable VAULT_ADDRESS;\\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\\n // For future use\\n uint256[50] private __gap;\\n\\n enum VALIDATOR_STATE {\\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 newAddress);\\n event ETHStaked(bytes pubkey, uint256 amount, bytes withdrawal_credentials);\\n event SSVValidatorRegistered(bytes pubkey, uint64[] operatorIds);\\n event SSVValidatorExitInitiated(bytes pubkey, uint64[] operatorIds);\\n event SSVValidatorExitCompleted(bytes pubkey, uint64[] operatorIds);\\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 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 constructor(\\n address _wethAddress,\\n address _vaultAddress,\\n address _beaconChainDepositContract,\\n address _ssvNetwork\\n ) {\\n WETH_TOKEN_ADDRESS = _wethAddress;\\n BEACON_CHAIN_DEPOSIT_CONTRACT = _beaconChainDepositContract;\\n SSV_NETWORK_ADDRESS = _ssvNetwork;\\n VAULT_ADDRESS = _vaultAddress;\\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 emit RegistratorChanged(_address);\\n validatorRegistrator = _address;\\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 {\\n uint256 requiredETH = validators.length * 32 ether;\\n\\n // Check there is enough WETH from the deposits sitting in this strategy contract\\n require(\\n requiredETH <= IWETH9(WETH_TOKEN_ADDRESS).balanceOf(address(this)),\\n \\\"insufficient WETH\\\"\\n );\\n\\n // Convert required ETH from WETH\\n IWETH9(WETH_TOKEN_ADDRESS).withdraw(requiredETH);\\n _wethWithdrawnAndStaked(requiredETH);\\n\\n uint256 validatorsLength = validators.length;\\n // For each validator\\n for (uint256 i = 0; i < validatorsLength; ) {\\n bytes32 pubkeyHash = keccak256(validators[i].pubkey);\\n VALIDATOR_STATE currentState = validatorsStates[pubkeyHash];\\n\\n require(\\n currentState == VALIDATOR_STATE.REGISTERED,\\n \\\"Validator not registered\\\"\\n );\\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 withdrawal_credentials = abi.encodePacked(\\n bytes1(0x01),\\n bytes11(0),\\n address(this)\\n );\\n IDepositContract(BEACON_CHAIN_DEPOSIT_CONTRACT).deposit{\\n value: 32 ether\\n }(\\n validators[i].pubkey,\\n withdrawal_credentials,\\n validators[i].signature,\\n validators[i].depositDataRoot\\n );\\n\\n emit ETHStaked(\\n validators[i].pubkey,\\n 32 ether,\\n withdrawal_credentials\\n );\\n\\n validatorsStates[pubkeyHash] = VALIDATOR_STATE.STAKED;\\n\\n unchecked {\\n ++i;\\n }\\n }\\n // save gas by changing this storage variable only once rather each time in the loop.\\n activeDepositedValidators += validatorsLength;\\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 function registerSsvValidator(\\n bytes calldata publicKey,\\n uint64[] calldata operatorIds,\\n bytes calldata sharesData,\\n uint256 amount,\\n Cluster calldata cluster\\n ) external onlyRegistrator whenNotPaused {\\n ISSVNetwork(SSV_NETWORK_ADDRESS).registerValidator(\\n publicKey,\\n operatorIds,\\n sharesData,\\n amount,\\n cluster\\n );\\n validatorsStates[keccak256(publicKey)] = VALIDATOR_STATE.REGISTERED;\\n emit SSVValidatorRegistered(publicKey, operatorIds);\\n }\\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 // slither-disable-start reentrancy-no-eth\\n function exitSsvValidator(\\n bytes calldata publicKey,\\n uint64[] calldata operatorIds\\n ) external onlyRegistrator whenNotPaused {\\n VALIDATOR_STATE currentState = validatorsStates[keccak256(publicKey)];\\n require(currentState == VALIDATOR_STATE.STAKED, \\\"Validator not staked\\\");\\n\\n ISSVNetwork(SSV_NETWORK_ADDRESS).exitValidator(publicKey, operatorIds);\\n emit SSVValidatorExitInitiated(publicKey, operatorIds);\\n\\n validatorsStates[keccak256(publicKey)] = VALIDATOR_STATE.EXITING;\\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 // 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 VALIDATOR_STATE currentState = validatorsStates[keccak256(publicKey)];\\n require(\\n currentState == VALIDATOR_STATE.EXITING,\\n \\\"Validator not exiting\\\"\\n );\\n\\n ISSVNetwork(SSV_NETWORK_ADDRESS).removeValidator(\\n publicKey,\\n operatorIds,\\n cluster\\n );\\n emit SSVValidatorExitCompleted(publicKey, operatorIds);\\n\\n validatorsStates[keccak256(publicKey)] = VALIDATOR_STATE.EXIT_COMPLETE;\\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 cluster The SSV cluster details that must be derived from emitted events from the SSVNetwork contract.\\n function depositSSV(\\n uint64[] memory operatorIds,\\n uint256 amount,\\n Cluster memory cluster\\n ) external onlyStrategist {\\n ISSVNetwork(SSV_NETWORK_ADDRESS).deposit(\\n address(this),\\n operatorIds,\\n amount,\\n cluster\\n );\\n }\\n\\n /***************************************\\n Abstract\\n ****************************************/\\n\\n /// @dev allows for NativeStakingSSVStrategy contract know how much WETH had been staked\\n function _wethWithdrawnAndStaked(uint256 _amount) internal virtual;\\n}\\n\",\"keccak256\":\"0xb9a6e9b02ff8437f5389df287438f14cfea6dc27739942f278ef224d579474fb\",\"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/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\",\"keccak256\":\"0x5e17bb3db9f9e1014b7c5c836547f8fa81e02af7568c0bb8f2a2e0e7c2192db4\",\"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/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\\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\":\"0xcbdb87104749e20c8411bc2acbfa0b7d48e876e3f4e1c46c9a7b00fcdb9722d9\",\"license\":\"MIT\"}},\"version\":1}", - "bytecode": "0x6101806040523480156200001257600080fd5b5060405162004e7a38038062004e7a833981016040819052620000359162000138565b8585876020015183868383838362000053336200010860201b60201c565b60008051602062004e5a833981519152546040516001600160a01b03909116906000907fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a908290a36033805460ff191690556001600160601b0319606094851b811660805291841b821660a052831b811660c05290821b811660e0528651821b811661010052602090960151811b86166101205298891b851661014052505050509190931b1661016052506200021392505050565b60008051602062004e5a83398151915255565b80516001600160a01b03811681146200013357600080fd5b919050565b60008060008060008086880360e08112156200015357600080fd5b60408112156200016257600080fd5b50604080519081016001600160401b03811182821017156200019457634e487b7160e01b600052604160045260246000fd5b604052620001a2886200011b565b8152620001b2602089016200011b565b60208201529550620001c7604088016200011b565b9450620001d7606088016200011b565b9350620001e7608088016200011b565b9250620001f760a088016200011b565b91506200020760c088016200011b565b90509295509295509295565b60805160601c60a05160601c60c05160601c60e05160601c6101005160601c6101205160601c6101405160601c6101605160601c614aa3620003b7600039600081816102f8015281816109ec0152612f750152600081816105ce01526124a50152600081816104a201528181610dd50152818161197c01528181611af5015281816128040152612a8c015260006109b801526000818161075301528181610b9d015281816118aa01528181611b4501528181611f090152818161356101526137bb015260008181610a4b01528181610c730152818161177c015281816124750152818161258d015261298201526000818161090d01526114be01526000818161032a0152818161052c0152818161082401528181610b0401528181610e4a01528181611032015281816110ba015281816112690152818161134401528181611a6601528181611b1601528181611e8301528181611f3801528181612b1701528181612bbf0152818161307a015281816130ff0152818161317301528181613410015281816134db015281816135900152818161373501526137ea0152614aa36000f3fe6080604052600436106102e85760003560e01c8063853828b611610190578063c7af3352116100dc578063d9f00ec711610095578063de5f62681161006f578063de5f626814610a0e578063e752923914610a23578063f1188e4014610a39578063f6ca71b014610a6d57600080fd5b8063d9f00ec714610986578063dbe55e56146109a6578063dd505df6146109da57600080fd5b8063c7af3352146108c9578063c98517c5146108de578063cceab750146108fb578063d059f6ef1461092f578063d38bfff414610946578063d9caed121461096657600080fd5b80639da0e46211610149578063ab12edf511610123578063ab12edf514610854578063ad1728cb14610874578063bb1b918d14610889578063c2e1e3f4146108a957600080fd5b80639da0e462146107b5578063a4f98af4146107f2578063aa388af61461080757600080fd5b8063853828b6146106e757806387bae867146106fc5780638d7c0e46146107215780639092c31c146107415780639136616a1461077557806396d538bb1461079557600080fd5b80635c975abb1161024f57806367c7066c1161020857806371a735f3116101e257806371a735f31461067c5780637b2d9b2c1461069c578063842f5c46146106bc5780638456cb59146106d257600080fd5b806367c7066c1461061c5780636e811d381461063c5780636ef387951461065c57600080fd5b80635c975abb146105635780635d36b190146105875780635f5152261461059c5780636093d380146105bc57806363092383146105f057806366e3667e1461060657600080fd5b8063430bf08a116102a1578063430bf08a14610490578063435356d1146104c457806347e7ef24146104e4578063484be81214610504578063579a7e1a1461051a5780635a063f631461054e57600080fd5b80630c340a24146103a45780630ed57b3a146103d65780630fc3b4c4146103f65780631072cbea1461042c57806322495dc81461044c5780633c8649591461046c57600080fd5b3661039f57336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016148061034c5750336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016145b61039d5760405162461bcd60e51b815260206004820152601e60248201527f657468206e6f742066726f6d20616c6c6f77656420636f6e747261637473000060448201526064015b60405180910390fd5b005b600080fd5b3480156103b057600080fd5b506103b9610a8f565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156103e257600080fd5b5061039d6103f1366004613e46565b610aac565b34801561040257600080fd5b506103b9610411366004613e0c565b609f602052600090815260409020546001600160a01b031681565b34801561043857600080fd5b5061039d610447366004613ec0565b610ade565b34801561045857600080fd5b5061039d610467366004613fb4565b610b9b565b34801561047857600080fd5b5061048260695481565b6040519081526020016103cd565b34801561049c57600080fd5b506103b97f000000000000000000000000000000000000000000000000000000000000000081565b3480156104d057600080fd5b5061039d6104df366004613f2d565b610ce5565b3480156104f057600080fd5b5061039d6104ff366004613ec0565b610dca565b34801561051057600080fd5b50610482606a5481565b34801561052657600080fd5b506103b97f000000000000000000000000000000000000000000000000000000000000000081565b34801561055a57600080fd5b5061039d610ee9565b34801561056f57600080fd5b5060335460ff165b60405190151581526020016103cd565b34801561059357600080fd5b5061039d610f88565b3480156105a857600080fd5b506104826105b7366004613e0c565b61102e565b3480156105c857600080fd5b506103b97f000000000000000000000000000000000000000000000000000000000000000081565b3480156105fc57600080fd5b50610482611c2081565b34801561061257600080fd5b5061048260345481565b34801561062857600080fd5b5060a3546103b9906001600160a01b031681565b34801561064857600080fd5b5061039d610657366004613e0c565b611162565b34801561066857600080fd5b5061039d610677366004613eec565b6111ea565b34801561068857600080fd5b5061039d6106973660046141c2565b611685565b3480156106a857600080fd5b506103b96106b736600461408a565b61187e565b3480156106c857600080fd5b5061048260685481565b3480156106de57600080fd5b5061039d6118a8565b3480156106f357600080fd5b5061039d611971565b34801561070857600080fd5b506033546103b99061010090046001600160a01b031681565b34801561072d57600080fd5b5061039d61073c366004614243565b611b43565b34801561074d57600080fd5b506103b97f000000000000000000000000000000000000000000000000000000000000000081565b34801561078157600080fd5b5061039d61079036600461408a565b612018565b3480156107a157600080fd5b5061039d6107b0366004613eec565b6121e3565b3480156107c157600080fd5b506107e56107d036600461408a565b60356020526000908152604090205460ff1681565b6040516103cd91906146ae565b3480156107fe57600080fd5b50610577612303565b34801561081357600080fd5b50610577610822366004613e0c565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0390811691161490565b34801561086057600080fd5b5061039d61086f366004614288565b612362565b34801561088057600080fd5b5061039d61245e565b34801561089557600080fd5b5061039d6108a436600461410e565b612524565b3480156108b557600080fd5b5061039d6108c4366004613e0c565b612697565b3480156108d557600080fd5b50610577612724565b3480156108ea57600080fd5b506104826801bc16d674ec80000081565b34801561090757600080fd5b506103b97f000000000000000000000000000000000000000000000000000000000000000081565b34801561093b57600080fd5b506104826101075481565b34801561095257600080fd5b5061039d610961366004613e0c565b612755565b34801561097257600080fd5b5061039d610981366004613e7f565b6127f9565b34801561099257600080fd5b5061039d6109a13660046140a3565b61288c565b3480156109b257600080fd5b506103b97f000000000000000000000000000000000000000000000000000000000000000081565b3480156109e657600080fd5b506103b97f000000000000000000000000000000000000000000000000000000000000000081565b348015610a1a57600080fd5b5061039d612a81565b348015610a2f57600080fd5b50610482606b5481565b348015610a4557600080fd5b506103b97f000000000000000000000000000000000000000000000000000000000000000081565b348015610a7957600080fd5b50610a82612bee565b6040516103cd9190614484565b6000610aa7600080516020614a4e8339815191525490565b905090565b610ab4612724565b610ad05760405162461bcd60e51b815260040161039490614720565b610ada8282612c50565b5050565b610ae6612724565b610b025760405162461bcd60e51b815260040161039490614720565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b039081169083161415610b7f5760405162461bcd60e51b815260206004820152601f60248201527f43616e6e6f74207472616e7366657220737570706f72746564206173736574006044820152606401610394565b610ada610b8a610a8f565b6001600160a01b0384169083612daf565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b158015610bf457600080fd5b505afa158015610c08573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c2c9190613e29565b6001600160a01b0316336001600160a01b031614610c5c5760405162461bcd60e51b8152600401610394906147e0565b60405163bc26e7e560e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063bc26e7e590610cae9030908790879087906004016143d4565b600060405180830381600087803b158015610cc857600080fd5b505af1158015610cdc573d6000803e3d6000fd5b50505050505050565b610ced612724565b610d095760405162461bcd60e51b815260040161039490614720565b600054610100900460ff1680610d22575060005460ff16155b610d855760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610394565b600054610100900460ff16158015610da7576000805461ffff19166101011790555b610db2848484612e01565b8015610dc4576000805461ff00191690555b50505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610e125760405162461bcd60e51b8152600401610394906146e9565b600080516020614a2e83398151915280546002811415610e445760405162461bcd60e51b8152600401610394906147b8565b600282557f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316846001600160a01b031614610ebd5760405162461bcd60e51b8152602060048201526011602482015270155b9cdd5c1c1bdc9d195908185cdcd95d607a1b6044820152606401610394565b826101076000828254610ed09190614907565b90915550610ee090508484612ebc565b50600190555050565b60a3546001600160a01b03163314610f435760405162461bcd60e51b815260206004820152601b60248201527f43616c6c6572206973206e6f74207468652048617276657374657200000000006044820152606401610394565b600080516020614a2e83398151915280546002811415610f755760405162461bcd60e51b8152600401610394906147b8565b60028255610f81612f4e565b5060019055565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b0316146110235760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b6064820152608401610394565b61102c3361319c565b565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b0316146110a55760405162461bcd60e51b8152602060048201526011602482015270155b9cdd5c1c1bdc9d195908185cdcd95d607a1b6044820152606401610394565b6040516370a0823160e01b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b15801561110457600080fd5b505afa158015611118573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061113c919061426f565b603454611152906801bc16d674ec80000061491f565b61115c9190614907565b92915050565b61116a612724565b6111865760405162461bcd60e51b815260040161039490614720565b6040516001600160a01b03821681527f83f29c79feb71f8fba9d0fbc4ba5f0982a28b6b1e868b3fc50e6400d100bca0f9060200160405180910390a1603380546001600160a01b0390921661010002610100600160a81b0319909216919091179055565b60335461010090046001600160a01b031633146112195760405162461bcd60e51b815260040161039490614781565b60335460ff161561123c5760405162461bcd60e51b815260040161039490614757565b6000611251826801bc16d674ec80000061491f565b6040516370a0823160e01b81523060048201529091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b1580156112b357600080fd5b505afa1580156112c7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112eb919061426f565b81111561132e5760405162461bcd60e51b81526020600482015260116024820152700d2dce6eaccccd2c6d2cadce840ae8aa89607b1b6044820152606401610394565b604051632e1a7d4d60e01b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561139057600080fd5b505af11580156113a4573d6000803e3d6000fd5b505050506113b18161325d565b8160005b818110156116675760008585838181106113d1576113d16149de565b90506020028101906113e3919061485d565b6113ed9080614817565b6040516113fb9291906143a8565b6040805191829003909120600081815260356020529182205490925060ff169081600381111561142d5761142d6149b2565b1461147a5760405162461bcd60e51b815260206004820152601860248201527f56616c696461746f72206e6f74207265676973746572656400000000000000006044820152606401610394565b60408051600160f81b60208201526000602182018190526bffffffffffffffffffffffff193060601b16602c830152910160405160208183030381529060405290507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663228951186801bc16d674ec8000008a8a88818110611507576115076149de565b9050602002810190611519919061485d565b6115239080614817565b858d8d8b818110611536576115366149de565b9050602002810190611548919061485d565b611556906020810190614817565b8f8f8d818110611568576115686149de565b905060200281019061157a919061485d565b604001356040518863ffffffff1660e01b815260040161159f96959493929190614633565b6000604051808303818588803b1580156115b857600080fd5b505af11580156115cc573d6000803e3d6000fd5b50505050507ffeb31a79d38edb1b090d516e4df3e273651179c6f2c2ec53a9a22ae015b70ba9888886818110611604576116046149de565b9050602002810190611616919061485d565b6116209080614817565b6801bc16d674ec8000008460405161163b9493929190614682565b60405180910390a150506000908152603560205260409020805460ff19166001908117909155016113b5565b50806034600082825461167a9190614907565b909155505050505050565b60335461010090046001600160a01b031633146116b45760405162461bcd60e51b815260040161039490614781565b60335460ff16156116d75760405162461bcd60e51b815260040161039490614757565b60006035600087876040516116ed9291906143a8565b604080519182900390912082526020820192909252016000205460ff1690506002816003811115611720576117206149b2565b146117655760405162461bcd60e51b815260206004820152601560248201527456616c696461746f72206e6f742065786974696e6760581b6044820152606401610394565b6040516312b3fc1960e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906312b3fc19906117b990899089908990899089906004016145f2565b600060405180830381600087803b1580156117d357600080fd5b505af11580156117e7573d6000803e3d6000fd5b505050507ff72821b8777f002ccdf6326f1242d9e0f762eb077668b67bebe640535378066d868686866040516118209493929190614569565b60405180910390a1600360356000888860405161183e9291906143a8565b60408051918290039091208252602082019290925201600020805460ff19166001836003811115611871576118716149b2565b0217905550505050505050565b60a4818154811061188e57600080fd5b6000918252602090912001546001600160a01b0316905081565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b15801561190157600080fd5b505afa158015611915573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119399190613e29565b6001600160a01b0316336001600160a01b0316146119695760405162461bcd60e51b8152600401610394906147e0565b61102c61328a565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614806119c057506119ab610a8f565b6001600160a01b0316336001600160a01b0316145b611a185760405162461bcd60e51b815260206004820152602360248201527f43616c6c6572206973206e6f7420746865205661756c74206f7220476f7665726044820152623737b960e91b6064820152608401610394565b600080516020614a2e83398151915280546002811415611a4a5760405162461bcd60e51b8152600401610394906147b8565b600282556040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b158015611ab057600080fd5b505afa158015611ac4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ae8919061426f565b90508015611b3b57611b3b7f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000836132ff565b505060019055565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b158015611b9c57600080fd5b505afa158015611bb0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bd49190613e29565b6001600160a01b0316336001600160a01b031614611c045760405162461bcd60e51b8152600401610394906147e0565b60335460ff16611c4d5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610394565b43611c20606b54611c5e9190614907565b10611cb95760405162461bcd60e51b815260206004820152602560248201527f6d616e75616c6c794669784163636f756e74696e672063616c6c656420746f6f6044820152641039b7b7b760d91b6064820152608401610394565b6002198312158015611ccc575060038313155b8015611ce65750600083603454611ce391906148c6565b12155b611d325760405162461bcd60e51b815260206004820152601760248201527f696e76616c69642076616c696461746f727344656c74610000000000000000006044820152606401610394565b6811ff6cf0fd15afffff198212158015611d5557506811ff6cf0fd15b000008213155b8015611d6f5750600082606854611d6c91906148c6565b12155b611dbb5760405162461bcd60e51b815260206004820152601d60248201527f696e76616c696420636f6e73656e7375735265776172647344656c74610000006044820152606401610394565b68053444835ec5800000811115611e145760405162461bcd60e51b815260206004820152601960248201527f696e76616c69642077657468546f5661756c74416d6f756e74000000000000006044820152606401610394565b60408051848152602081018490529081018290527f80d022717ea022455c5886b8dd8a29c037570aae58aeb4d7b136d7a10ec2e4319060600160405180910390a182603454611e6391906148c6565b603455606854611e749083906148c6565b60685543606b558015611fc2577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b158015611edc57600080fd5b505af1158015611ef0573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb92506044019050602060405180830381600087803b158015611f8057600080fd5b505af1158015611f94573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fb8919061406d565b50611fc2816133f7565b611fcc600061345f565b61200b5760405162461bcd60e51b815260206004820152601060248201526f333ab9b29039ba34b63610313637bbb760811b6044820152606401610394565b6120136138de565b505050565b612020612724565b61203c5760405162461bcd60e51b815260040161039490614720565b60a054811061207d5760405162461bcd60e51b815260206004820152600d60248201526c092dcecc2d8d2c840d2dcc8caf609b1b6044820152606401610394565b600060a08281548110612092576120926149de565b60009182526020808320909101546001600160a01b03908116808452609f90925260409092205460a054919350909116906120cf9060019061493e565b8310156121515760a080546120e69060019061493e565b815481106120f6576120f66149de565b60009182526020909120015460a080546001600160a01b039092169185908110612122576121226149de565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505b60a0805480612162576121626149c8565b60008281526020808220600019908401810180546001600160a01b031990811690915593019093556001600160a01b03858116808352609f855260409283902080549094169093559051908416815290917f16b7600acff27e39a8a96056b3d533045298de927507f5c1d97e4accde60488c910160405180910390a2505050565b6121eb612724565b6122075760405162461bcd60e51b815260040161039490614720565b8060005b818110156122ba576000848483818110612227576122276149de565b905060200201602081019061223c9190613e0c565b6001600160a01b031614156122aa5760405162461bcd60e51b815260206004820152602e60248201527f43616e206e6f742073657420616e20656d70747920616464726573732061732060448201526d30903932bbb0b932103a37b5b2b760911b6064820152608401610394565b6122b381614981565b905061220b565b507f04c0b9649497d316554306e53678d5f5f5dbc3a06f97dec13ff4cfe98b986bbc60a484846040516122ef939291906144d1565b60405180910390a1610dc460a48484613b65565b60335460009061010090046001600160a01b031633146123355760405162461bcd60e51b815260040161039490614781565b60335460ff16156123585760405162461bcd60e51b815260040161039490614757565b610aa7600161345f565b61236a612724565b6123865760405162461bcd60e51b815260040161039490614720565b808210801561239d57506801bc16d674ec80000082105b80156123b157506801bc16d674ec80000081105b80156123ce5750673782dace9d9000006123cb838361493e565b10155b61241a5760405162461bcd60e51b815260206004820152601760248201527f696e636f7272656374206675736520696e74657276616c0000000000000000006044820152606401610394565b60408051838152602081018390527fcb8d24e46eb3c402bf344ee60a6576cba9ef2f59ea1af3b311520704924e901a910160405180910390a1606991909155606a55565b60405163095ea7b360e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015260001960248301527f0000000000000000000000000000000000000000000000000000000000000000169063095ea7b390604401602060405180830381600087803b1580156124e957600080fd5b505af11580156124fd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612521919061406d565b50565b60335461010090046001600160a01b031633146125535760405162461bcd60e51b815260040161039490614781565b60335460ff16156125765760405162461bcd60e51b815260040161039490614757565b6040516301ba3ee760e21b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906306e8fb9c906125d0908b908b908b908b908b908b908b908b90600401614590565b600060405180830381600087803b1580156125ea57600080fd5b505af11580156125fe573d6000803e3d6000fd5b505050506000603560008a8a6040516126189291906143a8565b60408051918290039091208252602082019290925201600020805460ff1916600183600381111561264b5761264b6149b2565b02179055507f75c4a66b2c6c28cf46db7131182a812e4fbbb2f0591377aa83a737909a9b68c3888888886040516126859493929190614569565b60405180910390a15050505050505050565b61269f612724565b6126bb5760405162461bcd60e51b815260040161039490614720565b60a354604080516001600160a01b03928316815291831660208301527fe48386b84419f4d36e0f96c10cc3510b6fb1a33795620c5098b22472bbe90796910160405180910390a160a380546001600160a01b0319166001600160a01b0392909216919091179055565b600061273c600080516020614a4e8339815191525490565b6001600160a01b0316336001600160a01b031614905090565b61275d612724565b6127795760405162461bcd60e51b815260040161039490614720565b6127a1817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b03166127c1600080516020614a4e8339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146128415760405162461bcd60e51b8152600401610394906146e9565b600080516020614a2e833981519152805460028114156128735760405162461bcd60e51b8152600401610394906147b8565b600282556128828585856132ff565b5060019055505050565b60335461010090046001600160a01b031633146128bb5760405162461bcd60e51b815260040161039490614781565b60335460ff16156128de5760405162461bcd60e51b815260040161039490614757565b60006035600086866040516128f49291906143a8565b604080519182900390912082526020820192909252016000205460ff1690506001816003811115612927576129276149b2565b1461296b5760405162461bcd60e51b815260206004820152601460248201527315985b1a59185d1bdc881b9bdd081cdd185ad95960621b6044820152606401610394565b604051633877322b60e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690633877322b906129bd908890889088908890600401614569565b600060405180830381600087803b1580156129d757600080fd5b505af11580156129eb573d6000803e3d6000fd5b505050507ff8821da16f5ed966b41e0343c3eff9903af782d74f99f1689dd9d4562b6545b385858585604051612a249493929190614569565b60405180910390a16002603560008787604051612a429291906143a8565b60408051918290039091208252602082019290925201600020805460ff19166001836003811115612a7557612a756149b2565b02179055505050505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614612ac95760405162461bcd60e51b8152600401610394906146e9565b600080516020614a2e83398151915280546002811415612afb5760405162461bcd60e51b8152600401610394906147b8565b600282556040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b158015612b6157600080fd5b505afa158015612b75573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b99919061426f565b905060006101075482612bac919061493e565b90508015612be457610107829055612be47f000000000000000000000000000000000000000000000000000000000000000082612ebc565b5050600182555050565b606060a4805480602002602001604051908101604052809291908181526020018280548015612c4657602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612c28575b5050505050905090565b6001600160a01b038281166000908152609f60205260409020541615612cad5760405162461bcd60e51b81526020600482015260126024820152711c151bdad95b88185b1c9958591e481cd95d60721b6044820152606401610394565b6001600160a01b03821615801590612ccd57506001600160a01b03811615155b612d0d5760405162461bcd60e51b8152602060048201526011602482015270496e76616c69642061646472657373657360781b6044820152606401610394565b6001600160a01b038281166000818152609f6020908152604080832080549587166001600160a01b0319968716811790915560a0805460018101825594527f78fdc8d422c49ced035a9edf18d00d3c6a8d81df210f3e5e448e045e77b41e8890930180549095168417909455925190815290917fef6485b84315f9b1483beffa32aae9a0596890395e3d7521f1c5fbb51790e765910160405180910390a25050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052612013908490613958565b8251612e149060a4906020860190613bc8565b50815181518114612e5e5760405162461bcd60e51b8152602060048201526014602482015273496e76616c696420696e7075742061727261797360601b6044820152606401610394565b60005b81811015612eb557612ea5848281518110612e7e57612e7e6149de565b6020026020010151848381518110612e9857612e986149de565b6020026020010151612c50565b612eae81614981565b9050612e61565b5050505050565b60008111612f055760405162461bcd60e51b81526020600482015260166024820152754d757374206465706f73697420736f6d657468696e6760501b6044820152606401610394565b6040805160008152602081018390526001600160a01b038416917f5548c837ab068cf56a2c2479df0882a4922fd203edb7517321831d95078c5f62910160405180910390a25050565b60335460ff1615612f715760405162461bcd60e51b815260040161039490614757565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663e52253816040518163ffffffff1660e01b8152600401602060405180830381600087803b158015612fce57600080fd5b505af1158015612fe2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613006919061426f565b90506000606854826130189190614907565b90508047101561306a5760405162461bcd60e51b815260206004820152601860248201527f696e73756666696369656e74206574682062616c616e636500000000000000006044820152606401610394565b8015610ada5760006068819055507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b1580156130d357600080fd5b505af11580156130e7573d6000803e3d6000fd5b505060a354604080516001600160a01b0392831681527f0000000000000000000000000000000000000000000000000000000000000000909216602083015281018590527ff6c07a063ed4e63808eb8da7112d46dbcd38de2b40a73dbcc9353c5a94c723539350606001915061315a9050565b60405180910390a160a354610ada906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116911683612daf565b6001600160a01b0381166131f25760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f7220697320616464726573732830290000000000006044820152606401610394565b806001600160a01b0316613212600080516020614a4e8339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a361252181600080516020614a4e83398151915255565b600061326c8261010754613a2a565b9050806101076000828254613281919061493e565b90915550505050565b60335460ff16156132ad5760405162461bcd60e51b815260040161039490614757565b6033805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586132e23390565b6040516001600160a01b03909116815260200160405180910390a1565b6000811161334f5760405162461bcd60e51b815260206004820152601760248201527f4d75737420776974686472617720736f6d657468696e670000000000000000006044820152606401610394565b6001600160a01b03831661339e5760405162461bcd60e51b8152602060048201526016602482015275135d5cdd081cdc1958da599e481c9958da5c1a595b9d60521b6044820152606401610394565b6040805160008152602081018390526001600160a01b038416917f2717ead6b9200dd235aad468c9809ea400fe33ac69b5bfaa6d3e90fc922b6398910160405180910390a26120136001600160a01b0383168483612daf565b6040805160008152602081018390526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016917f2717ead6b9200dd235aad468c9809ea400fe33ac69b5bfaa6d3e90fc922b6398910160405180910390a250565b60006068544710156134745761115c82613a42565b600060685447613484919061493e565b9050600191506801bc16d674ec80000081106136615760006801bc16d674ec8000008204905080603460008282546134bc919061493e565b90915550600090506134d7826801bc16d674ec80000061491f565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b15801561353457600080fd5b505af1158015613548573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb92506044019050602060405180830381600087803b1580156135d857600080fd5b505af11580156135ec573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613610919061406d565b5061361a816133f7565b60345460408051848152602081019290925281018290527fbe7040030ff7b347853214bf49820c6d455fedf58f3815f85c7bc5216993682b9060600160405180910390a150505b600060685447613671919061493e565b90506801bc16d674ec80000081106136c35760405162461bcd60e51b8152602060048201526015602482015274756e6578706563746564206163636f756e74696e6760581b6044820152606401610394565b806136cf575050919050565b6069548110156137295780606860008282546136eb9190614907565b90915550506040518181527f7a745a2c63a535068f52ceca27debd5297bbad5f7f37ec53d044a59d0362445d906020015b60405180910390a16138d7565b606a548111156138c6577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b15801561378e57600080fd5b505af11580156137a2573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb92506044019050602060405180830381600087803b15801561383257600080fd5b505af1158015613846573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061386a919061406d565b5060016034600082825461387e919061493e565b9091555061388d9050816133f7565b60345460408051918252602082018390527f6aa7e30787b26429ced603a7aba8b19c4b5d5bcf29a3257da953c8d53bcaa3a6910161371c565b6138cf84613a42565b949350505050565b5050919050565b60335460ff166139275760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610394565b6033805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa336132e2565b60006139ad826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316613a5a9092919063ffffffff16565b80519091501561201357808060200190518101906139cb919061406d565b6120135760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610394565b6000818310613a395781613a3b565b825b9392505050565b60008115613a5257613a5261328a565b506000919050565b60606138cf848460008585843b613ab35760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610394565b600080866001600160a01b03168587604051613acf91906143b8565b60006040518083038185875af1925050503d8060008114613b0c576040519150601f19603f3d011682016040523d82523d6000602084013e613b11565b606091505b5091509150613b21828286613b2c565b979650505050505050565b60608315613b3b575081613a3b565b825115613b4b5782518084602001fd5b8160405162461bcd60e51b815260040161039491906146d6565b828054828255906000526020600020908101928215613bb8579160200282015b82811115613bb85781546001600160a01b0319166001600160a01b03843516178255602090920191600190910190613b85565b50613bc4929150613c1d565b5090565b828054828255906000526020600020908101928215613bb8579160200282015b82811115613bb857825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190613be8565b5b80821115613bc45760008155600101613c1e565b60008083601f840112613c4457600080fd5b5081356001600160401b03811115613c5b57600080fd5b6020830191508360208260051b8501011115613c7657600080fd5b9250929050565b600082601f830112613c8e57600080fd5b81356020613ca3613c9e836148a3565b614873565b80838252828201915082860187848660051b8901011115613cc357600080fd5b60005b85811015613ceb578135613cd981614a0a565b84529284019290840190600101613cc6565b5090979650505050505050565b60008083601f840112613d0a57600080fd5b5081356001600160401b03811115613d2157600080fd5b602083019150836020828501011115613c7657600080fd5b600060a08284031215613d4b57600080fd5b50919050565b600060a08284031215613d6357600080fd5b60405160a081018181106001600160401b0382111715613d8557613d856149f4565b604052905080613d9483613ddc565b8152613da260208401613df5565b6020820152613db360408401613df5565b60408201526060830135613dc681614a1f565b6060820152608092830135920191909152919050565b803563ffffffff81168114613df057600080fd5b919050565b80356001600160401b0381168114613df057600080fd5b600060208284031215613e1e57600080fd5b8135613a3b81614a0a565b600060208284031215613e3b57600080fd5b8151613a3b81614a0a565b60008060408385031215613e5957600080fd5b8235613e6481614a0a565b91506020830135613e7481614a0a565b809150509250929050565b600080600060608486031215613e9457600080fd5b8335613e9f81614a0a565b92506020840135613eaf81614a0a565b929592945050506040919091013590565b60008060408385031215613ed357600080fd5b8235613ede81614a0a565b946020939093013593505050565b60008060208385031215613eff57600080fd5b82356001600160401b03811115613f1557600080fd5b613f2185828601613c32565b90969095509350505050565b600080600060608486031215613f4257600080fd5b83356001600160401b0380821115613f5957600080fd5b613f6587838801613c7d565b94506020860135915080821115613f7b57600080fd5b613f8787838801613c7d565b93506040860135915080821115613f9d57600080fd5b50613faa86828701613c7d565b9150509250925092565b600080600060e08486031215613fc957600080fd5b83356001600160401b03811115613fdf57600080fd5b8401601f81018613613ff057600080fd5b80356020614000613c9e836148a3565b8083825282820191508285018a848660051b880101111561402057600080fd5b600095505b8486101561404a5761403681613df5565b835260019590950194918301918301614025565b509650508601359350614064915086905060408601613d51565b90509250925092565b60006020828403121561407f57600080fd5b8151613a3b81614a1f565b60006020828403121561409c57600080fd5b5035919050565b600080600080604085870312156140b957600080fd5b84356001600160401b03808211156140d057600080fd5b6140dc88838901613cf8565b909650945060208701359150808211156140f557600080fd5b5061410287828801613c32565b95989497509550505050565b600080600080600080600080610120898b03121561412b57600080fd5b88356001600160401b038082111561414257600080fd5b61414e8c838d01613cf8565b909a50985060208b013591508082111561416757600080fd5b6141738c838d01613c32565b909850965060408b013591508082111561418c57600080fd5b506141998b828c01613cf8565b909550935050606089013591506141b38a60808b01613d39565b90509295985092959890939650565b600080600080600060e086880312156141da57600080fd5b85356001600160401b03808211156141f157600080fd5b6141fd89838a01613cf8565b9097509550602088013591508082111561421657600080fd5b5061422388828901613c32565b909450925061423790508760408801613d39565b90509295509295909350565b60008060006060848603121561425857600080fd5b505081359360208301359350604090920135919050565b60006020828403121561428157600080fd5b5051919050565b6000806040838503121561429b57600080fd5b50508035926020909101359150565b8183526000602080850194508260005b858110156142e6576001600160401b036142d383613df5565b16875295820195908201906001016142ba565b509495945050505050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b60008151808452614332816020860160208601614955565b601f01601f19169290920160200192915050565b63ffffffff61435482613ddc565b16825261436360208201613df5565b6001600160401b0380821660208501528061438060408501613df5565b1660408501525050606081013561439681614a1f565b15156060830152608090810135910152565b8183823760009101908152919050565b600082516143ca818460208701614955565b9190910192915050565b6001600160a01b03851681526101006020808301829052855191830182905260009161012084019187810191845b818110156144275783516001600160401b031685529382019392820192600101614402565b505082935086604086015263ffffffff865116606086015280860151925050506001600160401b0380821660808501528060408601511660a085015250506060830151151560c0830152608083015160e083015295945050505050565b6020808252825182820181905260009190848201906040850190845b818110156144c55783516001600160a01b0316835292840192918401916001016144a0565b50909695505050505050565b6000604082016040835280865480835260608501915087600052602092508260002060005b8281101561451b5781546001600160a01b0316845292840192600191820191016144f6565b505050838103828501528481528590820160005b8681101561455d57823561454281614a0a565b6001600160a01b03168252918301919083019060010161452f565b50979650505050505050565b60408152600061457d6040830186886142f1565b8281036020840152613b218185876142aa565b60006101208083526145a58184018b8d6142f1565b905082810360208401526145ba81898b6142aa565b905082810360408401526145cf8187896142f1565b9150508360608301526145e56080830184614346565b9998505050505050505050565b60e08152600061460660e0830187896142f1565b82810360208401526146198186886142aa565b9150506146296040830184614346565b9695505050505050565b60808152600061464760808301888a6142f1565b8281036020840152614659818861431a565b9050828103604084015261466e8186886142f1565b915050826060830152979650505050505050565b6060815260006146966060830186886142f1565b8460208401528281036040840152613b21818561431a565b60208101600483106146d057634e487b7160e01b600052602160045260246000fd5b91905290565b602081526000613a3b602083018461431a565b60208082526017908201527f43616c6c6572206973206e6f7420746865205661756c74000000000000000000604082015260600190565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b60208082526010908201526f14185d5cd8589b194e881c185d5cd95960821b604082015260600190565b6020808252601d908201527f43616c6c6572206973206e6f7420746865205265676973747261746f72000000604082015260600190565b6020808252600e908201526d1499595b9d1c985b9d0818d85b1b60921b604082015260600190565b6020808252601c908201527f43616c6c6572206973206e6f7420746865205374726174656769737400000000604082015260600190565b6000808335601e1984360301811261482e57600080fd5b8301803591506001600160401b0382111561484857600080fd5b602001915036819003821315613c7657600080fd5b60008235605e198336030181126143ca57600080fd5b604051601f8201601f191681016001600160401b038111828210171561489b5761489b6149f4565b604052919050565b60006001600160401b038211156148bc576148bc6149f4565b5060051b60200190565b600080821280156001600160ff1b03849003851316156148e8576148e861499c565b600160ff1b83900384128116156149015761490161499c565b50500190565b6000821982111561491a5761491a61499c565b500190565b60008160001904831182151516156149395761493961499c565b500290565b6000828210156149505761495061499c565b500390565b60005b83811015614970578181015183820152602001614958565b83811115610dc45750506000910152565b60006000198214156149955761499561499c565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b038116811461252157600080fd5b801515811461252157600080fdfe53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac45357bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa2646970667358221220e7e50cde0c8998aadaf7928bf094efc09a4ab9f91b5a4d0db51e66b9307dc59264736f6c634300080700337bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a", - "deployedBytecode": "0x6080604052600436106102e85760003560e01c8063853828b611610190578063c7af3352116100dc578063d9f00ec711610095578063de5f62681161006f578063de5f626814610a0e578063e752923914610a23578063f1188e4014610a39578063f6ca71b014610a6d57600080fd5b8063d9f00ec714610986578063dbe55e56146109a6578063dd505df6146109da57600080fd5b8063c7af3352146108c9578063c98517c5146108de578063cceab750146108fb578063d059f6ef1461092f578063d38bfff414610946578063d9caed121461096657600080fd5b80639da0e46211610149578063ab12edf511610123578063ab12edf514610854578063ad1728cb14610874578063bb1b918d14610889578063c2e1e3f4146108a957600080fd5b80639da0e462146107b5578063a4f98af4146107f2578063aa388af61461080757600080fd5b8063853828b6146106e757806387bae867146106fc5780638d7c0e46146107215780639092c31c146107415780639136616a1461077557806396d538bb1461079557600080fd5b80635c975abb1161024f57806367c7066c1161020857806371a735f3116101e257806371a735f31461067c5780637b2d9b2c1461069c578063842f5c46146106bc5780638456cb59146106d257600080fd5b806367c7066c1461061c5780636e811d381461063c5780636ef387951461065c57600080fd5b80635c975abb146105635780635d36b190146105875780635f5152261461059c5780636093d380146105bc57806363092383146105f057806366e3667e1461060657600080fd5b8063430bf08a116102a1578063430bf08a14610490578063435356d1146104c457806347e7ef24146104e4578063484be81214610504578063579a7e1a1461051a5780635a063f631461054e57600080fd5b80630c340a24146103a45780630ed57b3a146103d65780630fc3b4c4146103f65780631072cbea1461042c57806322495dc81461044c5780633c8649591461046c57600080fd5b3661039f57336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016148061034c5750336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016145b61039d5760405162461bcd60e51b815260206004820152601e60248201527f657468206e6f742066726f6d20616c6c6f77656420636f6e747261637473000060448201526064015b60405180910390fd5b005b600080fd5b3480156103b057600080fd5b506103b9610a8f565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156103e257600080fd5b5061039d6103f1366004613e46565b610aac565b34801561040257600080fd5b506103b9610411366004613e0c565b609f602052600090815260409020546001600160a01b031681565b34801561043857600080fd5b5061039d610447366004613ec0565b610ade565b34801561045857600080fd5b5061039d610467366004613fb4565b610b9b565b34801561047857600080fd5b5061048260695481565b6040519081526020016103cd565b34801561049c57600080fd5b506103b97f000000000000000000000000000000000000000000000000000000000000000081565b3480156104d057600080fd5b5061039d6104df366004613f2d565b610ce5565b3480156104f057600080fd5b5061039d6104ff366004613ec0565b610dca565b34801561051057600080fd5b50610482606a5481565b34801561052657600080fd5b506103b97f000000000000000000000000000000000000000000000000000000000000000081565b34801561055a57600080fd5b5061039d610ee9565b34801561056f57600080fd5b5060335460ff165b60405190151581526020016103cd565b34801561059357600080fd5b5061039d610f88565b3480156105a857600080fd5b506104826105b7366004613e0c565b61102e565b3480156105c857600080fd5b506103b97f000000000000000000000000000000000000000000000000000000000000000081565b3480156105fc57600080fd5b50610482611c2081565b34801561061257600080fd5b5061048260345481565b34801561062857600080fd5b5060a3546103b9906001600160a01b031681565b34801561064857600080fd5b5061039d610657366004613e0c565b611162565b34801561066857600080fd5b5061039d610677366004613eec565b6111ea565b34801561068857600080fd5b5061039d6106973660046141c2565b611685565b3480156106a857600080fd5b506103b96106b736600461408a565b61187e565b3480156106c857600080fd5b5061048260685481565b3480156106de57600080fd5b5061039d6118a8565b3480156106f357600080fd5b5061039d611971565b34801561070857600080fd5b506033546103b99061010090046001600160a01b031681565b34801561072d57600080fd5b5061039d61073c366004614243565b611b43565b34801561074d57600080fd5b506103b97f000000000000000000000000000000000000000000000000000000000000000081565b34801561078157600080fd5b5061039d61079036600461408a565b612018565b3480156107a157600080fd5b5061039d6107b0366004613eec565b6121e3565b3480156107c157600080fd5b506107e56107d036600461408a565b60356020526000908152604090205460ff1681565b6040516103cd91906146ae565b3480156107fe57600080fd5b50610577612303565b34801561081357600080fd5b50610577610822366004613e0c565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0390811691161490565b34801561086057600080fd5b5061039d61086f366004614288565b612362565b34801561088057600080fd5b5061039d61245e565b34801561089557600080fd5b5061039d6108a436600461410e565b612524565b3480156108b557600080fd5b5061039d6108c4366004613e0c565b612697565b3480156108d557600080fd5b50610577612724565b3480156108ea57600080fd5b506104826801bc16d674ec80000081565b34801561090757600080fd5b506103b97f000000000000000000000000000000000000000000000000000000000000000081565b34801561093b57600080fd5b506104826101075481565b34801561095257600080fd5b5061039d610961366004613e0c565b612755565b34801561097257600080fd5b5061039d610981366004613e7f565b6127f9565b34801561099257600080fd5b5061039d6109a13660046140a3565b61288c565b3480156109b257600080fd5b506103b97f000000000000000000000000000000000000000000000000000000000000000081565b3480156109e657600080fd5b506103b97f000000000000000000000000000000000000000000000000000000000000000081565b348015610a1a57600080fd5b5061039d612a81565b348015610a2f57600080fd5b50610482606b5481565b348015610a4557600080fd5b506103b97f000000000000000000000000000000000000000000000000000000000000000081565b348015610a7957600080fd5b50610a82612bee565b6040516103cd9190614484565b6000610aa7600080516020614a4e8339815191525490565b905090565b610ab4612724565b610ad05760405162461bcd60e51b815260040161039490614720565b610ada8282612c50565b5050565b610ae6612724565b610b025760405162461bcd60e51b815260040161039490614720565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b039081169083161415610b7f5760405162461bcd60e51b815260206004820152601f60248201527f43616e6e6f74207472616e7366657220737570706f72746564206173736574006044820152606401610394565b610ada610b8a610a8f565b6001600160a01b0384169083612daf565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b158015610bf457600080fd5b505afa158015610c08573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c2c9190613e29565b6001600160a01b0316336001600160a01b031614610c5c5760405162461bcd60e51b8152600401610394906147e0565b60405163bc26e7e560e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063bc26e7e590610cae9030908790879087906004016143d4565b600060405180830381600087803b158015610cc857600080fd5b505af1158015610cdc573d6000803e3d6000fd5b50505050505050565b610ced612724565b610d095760405162461bcd60e51b815260040161039490614720565b600054610100900460ff1680610d22575060005460ff16155b610d855760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610394565b600054610100900460ff16158015610da7576000805461ffff19166101011790555b610db2848484612e01565b8015610dc4576000805461ff00191690555b50505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610e125760405162461bcd60e51b8152600401610394906146e9565b600080516020614a2e83398151915280546002811415610e445760405162461bcd60e51b8152600401610394906147b8565b600282557f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316846001600160a01b031614610ebd5760405162461bcd60e51b8152602060048201526011602482015270155b9cdd5c1c1bdc9d195908185cdcd95d607a1b6044820152606401610394565b826101076000828254610ed09190614907565b90915550610ee090508484612ebc565b50600190555050565b60a3546001600160a01b03163314610f435760405162461bcd60e51b815260206004820152601b60248201527f43616c6c6572206973206e6f74207468652048617276657374657200000000006044820152606401610394565b600080516020614a2e83398151915280546002811415610f755760405162461bcd60e51b8152600401610394906147b8565b60028255610f81612f4e565b5060019055565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b0316146110235760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b6064820152608401610394565b61102c3361319c565b565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b0316146110a55760405162461bcd60e51b8152602060048201526011602482015270155b9cdd5c1c1bdc9d195908185cdcd95d607a1b6044820152606401610394565b6040516370a0823160e01b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b15801561110457600080fd5b505afa158015611118573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061113c919061426f565b603454611152906801bc16d674ec80000061491f565b61115c9190614907565b92915050565b61116a612724565b6111865760405162461bcd60e51b815260040161039490614720565b6040516001600160a01b03821681527f83f29c79feb71f8fba9d0fbc4ba5f0982a28b6b1e868b3fc50e6400d100bca0f9060200160405180910390a1603380546001600160a01b0390921661010002610100600160a81b0319909216919091179055565b60335461010090046001600160a01b031633146112195760405162461bcd60e51b815260040161039490614781565b60335460ff161561123c5760405162461bcd60e51b815260040161039490614757565b6000611251826801bc16d674ec80000061491f565b6040516370a0823160e01b81523060048201529091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b1580156112b357600080fd5b505afa1580156112c7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112eb919061426f565b81111561132e5760405162461bcd60e51b81526020600482015260116024820152700d2dce6eaccccd2c6d2cadce840ae8aa89607b1b6044820152606401610394565b604051632e1a7d4d60e01b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561139057600080fd5b505af11580156113a4573d6000803e3d6000fd5b505050506113b18161325d565b8160005b818110156116675760008585838181106113d1576113d16149de565b90506020028101906113e3919061485d565b6113ed9080614817565b6040516113fb9291906143a8565b6040805191829003909120600081815260356020529182205490925060ff169081600381111561142d5761142d6149b2565b1461147a5760405162461bcd60e51b815260206004820152601860248201527f56616c696461746f72206e6f74207265676973746572656400000000000000006044820152606401610394565b60408051600160f81b60208201526000602182018190526bffffffffffffffffffffffff193060601b16602c830152910160405160208183030381529060405290507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663228951186801bc16d674ec8000008a8a88818110611507576115076149de565b9050602002810190611519919061485d565b6115239080614817565b858d8d8b818110611536576115366149de565b9050602002810190611548919061485d565b611556906020810190614817565b8f8f8d818110611568576115686149de565b905060200281019061157a919061485d565b604001356040518863ffffffff1660e01b815260040161159f96959493929190614633565b6000604051808303818588803b1580156115b857600080fd5b505af11580156115cc573d6000803e3d6000fd5b50505050507ffeb31a79d38edb1b090d516e4df3e273651179c6f2c2ec53a9a22ae015b70ba9888886818110611604576116046149de565b9050602002810190611616919061485d565b6116209080614817565b6801bc16d674ec8000008460405161163b9493929190614682565b60405180910390a150506000908152603560205260409020805460ff19166001908117909155016113b5565b50806034600082825461167a9190614907565b909155505050505050565b60335461010090046001600160a01b031633146116b45760405162461bcd60e51b815260040161039490614781565b60335460ff16156116d75760405162461bcd60e51b815260040161039490614757565b60006035600087876040516116ed9291906143a8565b604080519182900390912082526020820192909252016000205460ff1690506002816003811115611720576117206149b2565b146117655760405162461bcd60e51b815260206004820152601560248201527456616c696461746f72206e6f742065786974696e6760581b6044820152606401610394565b6040516312b3fc1960e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906312b3fc19906117b990899089908990899089906004016145f2565b600060405180830381600087803b1580156117d357600080fd5b505af11580156117e7573d6000803e3d6000fd5b505050507ff72821b8777f002ccdf6326f1242d9e0f762eb077668b67bebe640535378066d868686866040516118209493929190614569565b60405180910390a1600360356000888860405161183e9291906143a8565b60408051918290039091208252602082019290925201600020805460ff19166001836003811115611871576118716149b2565b0217905550505050505050565b60a4818154811061188e57600080fd5b6000918252602090912001546001600160a01b0316905081565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b15801561190157600080fd5b505afa158015611915573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119399190613e29565b6001600160a01b0316336001600160a01b0316146119695760405162461bcd60e51b8152600401610394906147e0565b61102c61328a565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614806119c057506119ab610a8f565b6001600160a01b0316336001600160a01b0316145b611a185760405162461bcd60e51b815260206004820152602360248201527f43616c6c6572206973206e6f7420746865205661756c74206f7220476f7665726044820152623737b960e91b6064820152608401610394565b600080516020614a2e83398151915280546002811415611a4a5760405162461bcd60e51b8152600401610394906147b8565b600282556040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b158015611ab057600080fd5b505afa158015611ac4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ae8919061426f565b90508015611b3b57611b3b7f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000836132ff565b505060019055565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b158015611b9c57600080fd5b505afa158015611bb0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bd49190613e29565b6001600160a01b0316336001600160a01b031614611c045760405162461bcd60e51b8152600401610394906147e0565b60335460ff16611c4d5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610394565b43611c20606b54611c5e9190614907565b10611cb95760405162461bcd60e51b815260206004820152602560248201527f6d616e75616c6c794669784163636f756e74696e672063616c6c656420746f6f6044820152641039b7b7b760d91b6064820152608401610394565b6002198312158015611ccc575060038313155b8015611ce65750600083603454611ce391906148c6565b12155b611d325760405162461bcd60e51b815260206004820152601760248201527f696e76616c69642076616c696461746f727344656c74610000000000000000006044820152606401610394565b6811ff6cf0fd15afffff198212158015611d5557506811ff6cf0fd15b000008213155b8015611d6f5750600082606854611d6c91906148c6565b12155b611dbb5760405162461bcd60e51b815260206004820152601d60248201527f696e76616c696420636f6e73656e7375735265776172647344656c74610000006044820152606401610394565b68053444835ec5800000811115611e145760405162461bcd60e51b815260206004820152601960248201527f696e76616c69642077657468546f5661756c74416d6f756e74000000000000006044820152606401610394565b60408051848152602081018490529081018290527f80d022717ea022455c5886b8dd8a29c037570aae58aeb4d7b136d7a10ec2e4319060600160405180910390a182603454611e6391906148c6565b603455606854611e749083906148c6565b60685543606b558015611fc2577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b158015611edc57600080fd5b505af1158015611ef0573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb92506044019050602060405180830381600087803b158015611f8057600080fd5b505af1158015611f94573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fb8919061406d565b50611fc2816133f7565b611fcc600061345f565b61200b5760405162461bcd60e51b815260206004820152601060248201526f333ab9b29039ba34b63610313637bbb760811b6044820152606401610394565b6120136138de565b505050565b612020612724565b61203c5760405162461bcd60e51b815260040161039490614720565b60a054811061207d5760405162461bcd60e51b815260206004820152600d60248201526c092dcecc2d8d2c840d2dcc8caf609b1b6044820152606401610394565b600060a08281548110612092576120926149de565b60009182526020808320909101546001600160a01b03908116808452609f90925260409092205460a054919350909116906120cf9060019061493e565b8310156121515760a080546120e69060019061493e565b815481106120f6576120f66149de565b60009182526020909120015460a080546001600160a01b039092169185908110612122576121226149de565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505b60a0805480612162576121626149c8565b60008281526020808220600019908401810180546001600160a01b031990811690915593019093556001600160a01b03858116808352609f855260409283902080549094169093559051908416815290917f16b7600acff27e39a8a96056b3d533045298de927507f5c1d97e4accde60488c910160405180910390a2505050565b6121eb612724565b6122075760405162461bcd60e51b815260040161039490614720565b8060005b818110156122ba576000848483818110612227576122276149de565b905060200201602081019061223c9190613e0c565b6001600160a01b031614156122aa5760405162461bcd60e51b815260206004820152602e60248201527f43616e206e6f742073657420616e20656d70747920616464726573732061732060448201526d30903932bbb0b932103a37b5b2b760911b6064820152608401610394565b6122b381614981565b905061220b565b507f04c0b9649497d316554306e53678d5f5f5dbc3a06f97dec13ff4cfe98b986bbc60a484846040516122ef939291906144d1565b60405180910390a1610dc460a48484613b65565b60335460009061010090046001600160a01b031633146123355760405162461bcd60e51b815260040161039490614781565b60335460ff16156123585760405162461bcd60e51b815260040161039490614757565b610aa7600161345f565b61236a612724565b6123865760405162461bcd60e51b815260040161039490614720565b808210801561239d57506801bc16d674ec80000082105b80156123b157506801bc16d674ec80000081105b80156123ce5750673782dace9d9000006123cb838361493e565b10155b61241a5760405162461bcd60e51b815260206004820152601760248201527f696e636f7272656374206675736520696e74657276616c0000000000000000006044820152606401610394565b60408051838152602081018390527fcb8d24e46eb3c402bf344ee60a6576cba9ef2f59ea1af3b311520704924e901a910160405180910390a1606991909155606a55565b60405163095ea7b360e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015260001960248301527f0000000000000000000000000000000000000000000000000000000000000000169063095ea7b390604401602060405180830381600087803b1580156124e957600080fd5b505af11580156124fd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612521919061406d565b50565b60335461010090046001600160a01b031633146125535760405162461bcd60e51b815260040161039490614781565b60335460ff16156125765760405162461bcd60e51b815260040161039490614757565b6040516301ba3ee760e21b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906306e8fb9c906125d0908b908b908b908b908b908b908b908b90600401614590565b600060405180830381600087803b1580156125ea57600080fd5b505af11580156125fe573d6000803e3d6000fd5b505050506000603560008a8a6040516126189291906143a8565b60408051918290039091208252602082019290925201600020805460ff1916600183600381111561264b5761264b6149b2565b02179055507f75c4a66b2c6c28cf46db7131182a812e4fbbb2f0591377aa83a737909a9b68c3888888886040516126859493929190614569565b60405180910390a15050505050505050565b61269f612724565b6126bb5760405162461bcd60e51b815260040161039490614720565b60a354604080516001600160a01b03928316815291831660208301527fe48386b84419f4d36e0f96c10cc3510b6fb1a33795620c5098b22472bbe90796910160405180910390a160a380546001600160a01b0319166001600160a01b0392909216919091179055565b600061273c600080516020614a4e8339815191525490565b6001600160a01b0316336001600160a01b031614905090565b61275d612724565b6127795760405162461bcd60e51b815260040161039490614720565b6127a1817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b03166127c1600080516020614a4e8339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146128415760405162461bcd60e51b8152600401610394906146e9565b600080516020614a2e833981519152805460028114156128735760405162461bcd60e51b8152600401610394906147b8565b600282556128828585856132ff565b5060019055505050565b60335461010090046001600160a01b031633146128bb5760405162461bcd60e51b815260040161039490614781565b60335460ff16156128de5760405162461bcd60e51b815260040161039490614757565b60006035600086866040516128f49291906143a8565b604080519182900390912082526020820192909252016000205460ff1690506001816003811115612927576129276149b2565b1461296b5760405162461bcd60e51b815260206004820152601460248201527315985b1a59185d1bdc881b9bdd081cdd185ad95960621b6044820152606401610394565b604051633877322b60e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690633877322b906129bd908890889088908890600401614569565b600060405180830381600087803b1580156129d757600080fd5b505af11580156129eb573d6000803e3d6000fd5b505050507ff8821da16f5ed966b41e0343c3eff9903af782d74f99f1689dd9d4562b6545b385858585604051612a249493929190614569565b60405180910390a16002603560008787604051612a429291906143a8565b60408051918290039091208252602082019290925201600020805460ff19166001836003811115612a7557612a756149b2565b02179055505050505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614612ac95760405162461bcd60e51b8152600401610394906146e9565b600080516020614a2e83398151915280546002811415612afb5760405162461bcd60e51b8152600401610394906147b8565b600282556040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b158015612b6157600080fd5b505afa158015612b75573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b99919061426f565b905060006101075482612bac919061493e565b90508015612be457610107829055612be47f000000000000000000000000000000000000000000000000000000000000000082612ebc565b5050600182555050565b606060a4805480602002602001604051908101604052809291908181526020018280548015612c4657602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612c28575b5050505050905090565b6001600160a01b038281166000908152609f60205260409020541615612cad5760405162461bcd60e51b81526020600482015260126024820152711c151bdad95b88185b1c9958591e481cd95d60721b6044820152606401610394565b6001600160a01b03821615801590612ccd57506001600160a01b03811615155b612d0d5760405162461bcd60e51b8152602060048201526011602482015270496e76616c69642061646472657373657360781b6044820152606401610394565b6001600160a01b038281166000818152609f6020908152604080832080549587166001600160a01b0319968716811790915560a0805460018101825594527f78fdc8d422c49ced035a9edf18d00d3c6a8d81df210f3e5e448e045e77b41e8890930180549095168417909455925190815290917fef6485b84315f9b1483beffa32aae9a0596890395e3d7521f1c5fbb51790e765910160405180910390a25050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052612013908490613958565b8251612e149060a4906020860190613bc8565b50815181518114612e5e5760405162461bcd60e51b8152602060048201526014602482015273496e76616c696420696e7075742061727261797360601b6044820152606401610394565b60005b81811015612eb557612ea5848281518110612e7e57612e7e6149de565b6020026020010151848381518110612e9857612e986149de565b6020026020010151612c50565b612eae81614981565b9050612e61565b5050505050565b60008111612f055760405162461bcd60e51b81526020600482015260166024820152754d757374206465706f73697420736f6d657468696e6760501b6044820152606401610394565b6040805160008152602081018390526001600160a01b038416917f5548c837ab068cf56a2c2479df0882a4922fd203edb7517321831d95078c5f62910160405180910390a25050565b60335460ff1615612f715760405162461bcd60e51b815260040161039490614757565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663e52253816040518163ffffffff1660e01b8152600401602060405180830381600087803b158015612fce57600080fd5b505af1158015612fe2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613006919061426f565b90506000606854826130189190614907565b90508047101561306a5760405162461bcd60e51b815260206004820152601860248201527f696e73756666696369656e74206574682062616c616e636500000000000000006044820152606401610394565b8015610ada5760006068819055507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b1580156130d357600080fd5b505af11580156130e7573d6000803e3d6000fd5b505060a354604080516001600160a01b0392831681527f0000000000000000000000000000000000000000000000000000000000000000909216602083015281018590527ff6c07a063ed4e63808eb8da7112d46dbcd38de2b40a73dbcc9353c5a94c723539350606001915061315a9050565b60405180910390a160a354610ada906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116911683612daf565b6001600160a01b0381166131f25760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f7220697320616464726573732830290000000000006044820152606401610394565b806001600160a01b0316613212600080516020614a4e8339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a361252181600080516020614a4e83398151915255565b600061326c8261010754613a2a565b9050806101076000828254613281919061493e565b90915550505050565b60335460ff16156132ad5760405162461bcd60e51b815260040161039490614757565b6033805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586132e23390565b6040516001600160a01b03909116815260200160405180910390a1565b6000811161334f5760405162461bcd60e51b815260206004820152601760248201527f4d75737420776974686472617720736f6d657468696e670000000000000000006044820152606401610394565b6001600160a01b03831661339e5760405162461bcd60e51b8152602060048201526016602482015275135d5cdd081cdc1958da599e481c9958da5c1a595b9d60521b6044820152606401610394565b6040805160008152602081018390526001600160a01b038416917f2717ead6b9200dd235aad468c9809ea400fe33ac69b5bfaa6d3e90fc922b6398910160405180910390a26120136001600160a01b0383168483612daf565b6040805160008152602081018390526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016917f2717ead6b9200dd235aad468c9809ea400fe33ac69b5bfaa6d3e90fc922b6398910160405180910390a250565b60006068544710156134745761115c82613a42565b600060685447613484919061493e565b9050600191506801bc16d674ec80000081106136615760006801bc16d674ec8000008204905080603460008282546134bc919061493e565b90915550600090506134d7826801bc16d674ec80000061491f565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b15801561353457600080fd5b505af1158015613548573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb92506044019050602060405180830381600087803b1580156135d857600080fd5b505af11580156135ec573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613610919061406d565b5061361a816133f7565b60345460408051848152602081019290925281018290527fbe7040030ff7b347853214bf49820c6d455fedf58f3815f85c7bc5216993682b9060600160405180910390a150505b600060685447613671919061493e565b90506801bc16d674ec80000081106136c35760405162461bcd60e51b8152602060048201526015602482015274756e6578706563746564206163636f756e74696e6760581b6044820152606401610394565b806136cf575050919050565b6069548110156137295780606860008282546136eb9190614907565b90915550506040518181527f7a745a2c63a535068f52ceca27debd5297bbad5f7f37ec53d044a59d0362445d906020015b60405180910390a16138d7565b606a548111156138c6577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b15801561378e57600080fd5b505af11580156137a2573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb92506044019050602060405180830381600087803b15801561383257600080fd5b505af1158015613846573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061386a919061406d565b5060016034600082825461387e919061493e565b9091555061388d9050816133f7565b60345460408051918252602082018390527f6aa7e30787b26429ced603a7aba8b19c4b5d5bcf29a3257da953c8d53bcaa3a6910161371c565b6138cf84613a42565b949350505050565b5050919050565b60335460ff166139275760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610394565b6033805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa336132e2565b60006139ad826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316613a5a9092919063ffffffff16565b80519091501561201357808060200190518101906139cb919061406d565b6120135760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610394565b6000818310613a395781613a3b565b825b9392505050565b60008115613a5257613a5261328a565b506000919050565b60606138cf848460008585843b613ab35760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610394565b600080866001600160a01b03168587604051613acf91906143b8565b60006040518083038185875af1925050503d8060008114613b0c576040519150601f19603f3d011682016040523d82523d6000602084013e613b11565b606091505b5091509150613b21828286613b2c565b979650505050505050565b60608315613b3b575081613a3b565b825115613b4b5782518084602001fd5b8160405162461bcd60e51b815260040161039491906146d6565b828054828255906000526020600020908101928215613bb8579160200282015b82811115613bb85781546001600160a01b0319166001600160a01b03843516178255602090920191600190910190613b85565b50613bc4929150613c1d565b5090565b828054828255906000526020600020908101928215613bb8579160200282015b82811115613bb857825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190613be8565b5b80821115613bc45760008155600101613c1e565b60008083601f840112613c4457600080fd5b5081356001600160401b03811115613c5b57600080fd5b6020830191508360208260051b8501011115613c7657600080fd5b9250929050565b600082601f830112613c8e57600080fd5b81356020613ca3613c9e836148a3565b614873565b80838252828201915082860187848660051b8901011115613cc357600080fd5b60005b85811015613ceb578135613cd981614a0a565b84529284019290840190600101613cc6565b5090979650505050505050565b60008083601f840112613d0a57600080fd5b5081356001600160401b03811115613d2157600080fd5b602083019150836020828501011115613c7657600080fd5b600060a08284031215613d4b57600080fd5b50919050565b600060a08284031215613d6357600080fd5b60405160a081018181106001600160401b0382111715613d8557613d856149f4565b604052905080613d9483613ddc565b8152613da260208401613df5565b6020820152613db360408401613df5565b60408201526060830135613dc681614a1f565b6060820152608092830135920191909152919050565b803563ffffffff81168114613df057600080fd5b919050565b80356001600160401b0381168114613df057600080fd5b600060208284031215613e1e57600080fd5b8135613a3b81614a0a565b600060208284031215613e3b57600080fd5b8151613a3b81614a0a565b60008060408385031215613e5957600080fd5b8235613e6481614a0a565b91506020830135613e7481614a0a565b809150509250929050565b600080600060608486031215613e9457600080fd5b8335613e9f81614a0a565b92506020840135613eaf81614a0a565b929592945050506040919091013590565b60008060408385031215613ed357600080fd5b8235613ede81614a0a565b946020939093013593505050565b60008060208385031215613eff57600080fd5b82356001600160401b03811115613f1557600080fd5b613f2185828601613c32565b90969095509350505050565b600080600060608486031215613f4257600080fd5b83356001600160401b0380821115613f5957600080fd5b613f6587838801613c7d565b94506020860135915080821115613f7b57600080fd5b613f8787838801613c7d565b93506040860135915080821115613f9d57600080fd5b50613faa86828701613c7d565b9150509250925092565b600080600060e08486031215613fc957600080fd5b83356001600160401b03811115613fdf57600080fd5b8401601f81018613613ff057600080fd5b80356020614000613c9e836148a3565b8083825282820191508285018a848660051b880101111561402057600080fd5b600095505b8486101561404a5761403681613df5565b835260019590950194918301918301614025565b509650508601359350614064915086905060408601613d51565b90509250925092565b60006020828403121561407f57600080fd5b8151613a3b81614a1f565b60006020828403121561409c57600080fd5b5035919050565b600080600080604085870312156140b957600080fd5b84356001600160401b03808211156140d057600080fd5b6140dc88838901613cf8565b909650945060208701359150808211156140f557600080fd5b5061410287828801613c32565b95989497509550505050565b600080600080600080600080610120898b03121561412b57600080fd5b88356001600160401b038082111561414257600080fd5b61414e8c838d01613cf8565b909a50985060208b013591508082111561416757600080fd5b6141738c838d01613c32565b909850965060408b013591508082111561418c57600080fd5b506141998b828c01613cf8565b909550935050606089013591506141b38a60808b01613d39565b90509295985092959890939650565b600080600080600060e086880312156141da57600080fd5b85356001600160401b03808211156141f157600080fd5b6141fd89838a01613cf8565b9097509550602088013591508082111561421657600080fd5b5061422388828901613c32565b909450925061423790508760408801613d39565b90509295509295909350565b60008060006060848603121561425857600080fd5b505081359360208301359350604090920135919050565b60006020828403121561428157600080fd5b5051919050565b6000806040838503121561429b57600080fd5b50508035926020909101359150565b8183526000602080850194508260005b858110156142e6576001600160401b036142d383613df5565b16875295820195908201906001016142ba565b509495945050505050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b60008151808452614332816020860160208601614955565b601f01601f19169290920160200192915050565b63ffffffff61435482613ddc565b16825261436360208201613df5565b6001600160401b0380821660208501528061438060408501613df5565b1660408501525050606081013561439681614a1f565b15156060830152608090810135910152565b8183823760009101908152919050565b600082516143ca818460208701614955565b9190910192915050565b6001600160a01b03851681526101006020808301829052855191830182905260009161012084019187810191845b818110156144275783516001600160401b031685529382019392820192600101614402565b505082935086604086015263ffffffff865116606086015280860151925050506001600160401b0380821660808501528060408601511660a085015250506060830151151560c0830152608083015160e083015295945050505050565b6020808252825182820181905260009190848201906040850190845b818110156144c55783516001600160a01b0316835292840192918401916001016144a0565b50909695505050505050565b6000604082016040835280865480835260608501915087600052602092508260002060005b8281101561451b5781546001600160a01b0316845292840192600191820191016144f6565b505050838103828501528481528590820160005b8681101561455d57823561454281614a0a565b6001600160a01b03168252918301919083019060010161452f565b50979650505050505050565b60408152600061457d6040830186886142f1565b8281036020840152613b218185876142aa565b60006101208083526145a58184018b8d6142f1565b905082810360208401526145ba81898b6142aa565b905082810360408401526145cf8187896142f1565b9150508360608301526145e56080830184614346565b9998505050505050505050565b60e08152600061460660e0830187896142f1565b82810360208401526146198186886142aa565b9150506146296040830184614346565b9695505050505050565b60808152600061464760808301888a6142f1565b8281036020840152614659818861431a565b9050828103604084015261466e8186886142f1565b915050826060830152979650505050505050565b6060815260006146966060830186886142f1565b8460208401528281036040840152613b21818561431a565b60208101600483106146d057634e487b7160e01b600052602160045260246000fd5b91905290565b602081526000613a3b602083018461431a565b60208082526017908201527f43616c6c6572206973206e6f7420746865205661756c74000000000000000000604082015260600190565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b60208082526010908201526f14185d5cd8589b194e881c185d5cd95960821b604082015260600190565b6020808252601d908201527f43616c6c6572206973206e6f7420746865205265676973747261746f72000000604082015260600190565b6020808252600e908201526d1499595b9d1c985b9d0818d85b1b60921b604082015260600190565b6020808252601c908201527f43616c6c6572206973206e6f7420746865205374726174656769737400000000604082015260600190565b6000808335601e1984360301811261482e57600080fd5b8301803591506001600160401b0382111561484857600080fd5b602001915036819003821315613c7657600080fd5b60008235605e198336030181126143ca57600080fd5b604051601f8201601f191681016001600160401b038111828210171561489b5761489b6149f4565b604052919050565b60006001600160401b038211156148bc576148bc6149f4565b5060051b60200190565b600080821280156001600160ff1b03849003851316156148e8576148e861499c565b600160ff1b83900384128116156149015761490161499c565b50500190565b6000821982111561491a5761491a61499c565b500190565b60008160001904831182151516156149395761493961499c565b500290565b6000828210156149505761495061499c565b500390565b60005b83811015614970578181015183820152602001614958565b83811115610dc45750506000910152565b60006000198214156149955761499561499c565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b038116811461252157600080fd5b801515811461252157600080fdfe53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac45357bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa2646970667358221220e7e50cde0c8998aadaf7928bf094efc09a4ab9f91b5a4d0db51e66b9307dc59264736f6c63430008070033", + "numDeployments": 5, + "solcInputHash": "a7af3565925bcd06d3e7b2ed59f01c90", + "metadata": "{\"compiler\":{\"version\":\"0.8.7+commit.e28d00a7\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"platformAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"vaultAddress\",\"type\":\"address\"}],\"internalType\":\"struct InitializableAbstractStrategy.BaseStrategyConfig\",\"name\":\"_baseConfig\",\"type\":\"tuple\"},{\"internalType\":\"address\",\"name\":\"_wethAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_ssvToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_ssvNetwork\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_feeAccumulator\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_beaconChainDepositContract\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"AccountingConsensusRewards\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"noOfValidators\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"remainingValidators\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"wethSentToVault\",\"type\":\"uint256\"}],\"name\":\"AccountingFullyWithdrawnValidator\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"validatorsDelta\",\"type\":\"int256\"},{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"consensusRewardsDelta\",\"type\":\"int256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"wethToVault\",\"type\":\"uint256\"}],\"name\":\"AccountingManuallyFixed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"remainingValidators\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"wethSentToVault\",\"type\":\"uint256\"}],\"name\":\"AccountingValidatorSlashed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"Deposit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"pubkey\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"withdrawal_credentials\",\"type\":\"bytes\"}],\"name\":\"ETHStaked\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"start\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"end\",\"type\":\"uint256\"}],\"name\":\"FuseIntervalUpdated\",\"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\":\"address\",\"name\":\"_oldHarvesterAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_newHarvesterAddress\",\"type\":\"address\"}],\"name\":\"HarvesterAddressesUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"}],\"name\":\"PTokenAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"}],\"name\":\"PTokenRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Paused\",\"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\":\"newAddress\",\"type\":\"address\"}],\"name\":\"RegistratorChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"_oldAddresses\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"_newAddresses\",\"type\":\"address[]\"}],\"name\":\"RewardTokenAddressesUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"rewardToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"RewardTokenCollected\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"pubkey\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"}],\"name\":\"SSVValidatorExitCompleted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"pubkey\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"}],\"name\":\"SSVValidatorExitInitiated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"pubkey\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"}],\"name\":\"SSVValidatorRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"StakeETHTallyReset\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"StakeETHThresholdChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newAddress\",\"type\":\"address\"}],\"name\":\"StakingMonitorChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Unpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"Withdrawal\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"BEACON_CHAIN_DEPOSIT_CONTRACT\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_ACCUMULATOR_ADDRESS\",\"outputs\":[{\"internalType\":\"address payable\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MAX_STAKE\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MIN_FIX_ACCOUNTING_CADENCE\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"SSV_NETWORK_ADDRESS\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"SSV_TOKEN_ADDRESS\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"VAULT_ADDRESS\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"WETH_TOKEN_ADDRESS\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"activeDepositedValidators\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"assetToPToken\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"}],\"name\":\"checkBalance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"claimGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"collectRewardTokens\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"consensusRewards\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"depositAll\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"validatorCount\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"networkFeeIndex\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"index\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"active\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"internalType\":\"struct Cluster\",\"name\":\"cluster\",\"type\":\"tuple\"}],\"name\":\"depositSSV\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"depositedWethAccountedFor\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"doAccounting\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"accountingValid\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"publicKey\",\"type\":\"bytes\"},{\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"}],\"name\":\"exitSsvValidator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fuseIntervalEnd\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fuseIntervalStart\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRewardTokenAddresses\",\"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\":\"harvesterAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"_rewardTokenAddresses\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"_assets\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"_pTokens\",\"type\":\"address[]\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isGovernor\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastFixAccountingBlockNumber\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"int256\",\"name\":\"_validatorsDelta\",\"type\":\"int256\"},{\"internalType\":\"int256\",\"name\":\"_consensusRewardsDelta\",\"type\":\"int256\"},{\"internalType\":\"uint256\",\"name\":\"_ethToVaultAmount\",\"type\":\"uint256\"}],\"name\":\"manuallyFixAccounting\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"paused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"platformAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"publicKey\",\"type\":\"bytes\"},{\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"},{\"internalType\":\"bytes\",\"name\":\"sharesData\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"validatorCount\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"networkFeeIndex\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"index\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"active\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"internalType\":\"struct Cluster\",\"name\":\"cluster\",\"type\":\"tuple\"}],\"name\":\"registerSsvValidator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_assetIndex\",\"type\":\"uint256\"}],\"name\":\"removePToken\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"publicKey\",\"type\":\"bytes\"},{\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"validatorCount\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"networkFeeIndex\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"index\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"active\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"internalType\":\"struct Cluster\",\"name\":\"cluster\",\"type\":\"tuple\"}],\"name\":\"removeSsvValidator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"resetStakeETHTally\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"rewardTokenAddresses\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"safeApproveAllTokens\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_fuseIntervalStart\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_fuseIntervalEnd\",\"type\":\"uint256\"}],\"name\":\"setFuseInterval\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_harvesterAddress\",\"type\":\"address\"}],\"name\":\"setHarvesterAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"}],\"name\":\"setPTokenAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"setRegistrator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"_rewardTokenAddresses\",\"type\":\"address[]\"}],\"name\":\"setRewardTokenAddresses\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"setStakeETHThreshold\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"setStakingMonitor\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"stakeETHTally\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"stakeETHThreshold\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"pubkey\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"depositDataRoot\",\"type\":\"bytes32\"}],\"internalType\":\"struct ValidatorStakeData[]\",\"name\":\"validators\",\"type\":\"tuple[]\"}],\"name\":\"stakeEth\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"stakingMonitor\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"}],\"name\":\"supportsAsset\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"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\":\"validatorRegistrator\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"validatorsStates\",\"outputs\":[{\"internalType\":\"enum ValidatorRegistrator.VALIDATOR_STATE\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"vaultAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"withdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdrawAll\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"author\":\"Origin Protocol Inc\",\"details\":\"This contract handles WETH and ETH and in some operations interchanges between the two. Any WETH that is on the contract across multiple blocks (and not just transitory within a transaction) is considered an asset. Meaning deposits increase the balance of the asset and withdrawal decrease it. As opposed to all our other strategies the WETH doesn't immediately get deposited into an underlying strategy and can be present across multiple blocks waiting to be unwrapped to ETH and staked to validators. This separation of WETH and ETH is required since the rewards (reward token) is also in ETH. To simplify the accounting of WETH there is another difference in behavior compared to the other strategies. To withdraw WETH asset - exit message is posted to validators and the ETH hits this contract with multiple days delay. In order to simplify the WETH accounting upon detection of such an event the ValidatorAccountant immediately wraps ETH to WETH and sends it to the Vault. On the other hand any ETH on the contract (across multiple blocks) is there either: - as a result of already accounted for consensus rewards - as a result of not yet accounted for consensus rewards - as a results of not yet accounted for full validator withdrawals (or validator slashes) Even though the strategy assets and rewards are a very similar asset the consensus layer rewards and the execution layer rewards are considered rewards and those are dripped to the Vault over a configurable time interval and not immediately.\",\"kind\":\"dev\",\"methods\":{\"checkBalance(address)\":{\"params\":{\"_asset\":\"Address of weth asset\"},\"returns\":{\"balance\":\" Total value of (W)ETH\"}},\"constructor\":{\"params\":{\"_baseConfig\":\"Base strategy config with platformAddress (ERC-4626 Vault contract), eg sfrxETH or sDAI, and vaultAddress (OToken Vault contract), eg VaultProxy or OETHVaultProxy\",\"_beaconChainDepositContract\":\"Address of the beacon chain deposit contract\",\"_feeAccumulator\":\"Address of the fee accumulator receiving execution layer validator rewards\",\"_ssvNetwork\":\"Address of the SSV Network contract\",\"_ssvToken\":\"Address of the Erc20 SSV Token contract\",\"_wethAddress\":\"Address of the Erc20 WETH Token contract\"}},\"deposit(address,uint256)\":{\"params\":{\"_amount\":\"Amount of assets that were transferred to the strategy by the vault.\",\"_asset\":\"Address of asset to deposit. Has to be WETH.\"}},\"depositSSV(uint64[],uint256,(uint32,uint64,uint64,bool,uint256))\":{\"details\":\"A SSV cluster is defined by the SSVOwnerAddress and the set of operatorIds. uses \\\"onlyStrategist\\\" modifier so continuous front-running can't DOS our maintenance service that tries to top up SSV tokens.\",\"params\":{\"cluster\":\"The SSV cluster details that must be derived from emitted events from the SSVNetwork contract.\"}},\"doAccounting()\":{\"details\":\"This function could in theory be permission-less but lets allow only the Registrator (Defender Action) to call it for now.\",\"returns\":{\"accountingValid\":\"true if accounting was successful, false if fuse is blown\"}},\"getRewardTokenAddresses()\":{\"returns\":{\"_0\":\"address[] the reward token addresses.\"}},\"initialize(address[],address[],address[])\":{\"params\":{\"_assets\":\"Addresses of initial supported assets\",\"_pTokens\":\"Platform Token corresponding addresses\",\"_rewardTokenAddresses\":\"Address of reward token for platform\"}},\"manuallyFixAccounting(int256,int256,uint256)\":{\"details\":\"There is a case when a validator(s) gets slashed so much that the eth swept from the beacon chain enters the fuse area and there are no consensus rewards on the contract to \\\"dip into\\\"/use. To increase the amount of unaccounted ETH over the fuse end interval we need to reduce the amount of active deposited validators and immediately send WETH to the vault, so it doesn't interfere with further accounting.\",\"params\":{\"_consensusRewardsDelta\":\"adjust the accounted for consensus rewards up or down\",\"_ethToVaultAmount\":\"the amount of ETH that gets wrapped into WETH and sent to the Vault\",\"_validatorsDelta\":\"adjust the active validators by up to plus three or minus three\"}},\"paused()\":{\"details\":\"Returns true if the contract is paused, and false otherwise.\"},\"removePToken(uint256)\":{\"params\":{\"_assetIndex\":\"Index of the asset to be removed\"}},\"setHarvesterAddress(address)\":{\"params\":{\"_harvesterAddress\":\"Address of the harvester contract.\"}},\"setPTokenAddress(address,address)\":{\"params\":{\"_asset\":\"Address for the asset\",\"_pToken\":\"Address for the corresponding platform token\"}},\"setRewardTokenAddresses(address[])\":{\"params\":{\"_rewardTokenAddresses\":\"Array of reward token addresses\"}},\"stakeEth((bytes,bytes,bytes32)[])\":{\"params\":{\"validators\":\"A list of validator data needed to stake. The `ValidatorStakeData` struct contains the pubkey, signature and depositDataRoot. Only the registrator can call this function.\"}},\"supportsAsset(address)\":{\"params\":{\"_asset\":\"The address of the asset token.\"}},\"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\"}},\"withdraw(address,address,uint256)\":{\"params\":{\"_amount\":\"Amount of WETH to withdraw\",\"_asset\":\"WETH to withdraw\",\"_recipient\":\"Address to receive withdrawn assets\"}}},\"stateVariables\":{\"FEE_ACCUMULATOR_ADDRESS\":{\"details\":\"this address will receive Execution layer rewards - These are rewards earned for executing transactions on the Ethereum network as part of block proposals. They include priority fees (fees paid by users for their transactions to be included) and MEV rewards (rewards for arranging transactions in a way that benefits the validator).\"},\"depositedWethAccountedFor\":{\"details\":\"This contract receives WETH as the deposit asset, but unlike other strategies doesn't immediately deposit it to an underlying platform. Rather a special privilege account stakes it to the validators. For that reason calling WETH.balanceOf(this) in a deposit function can contain WETH that has just been deposited and also WETH that has previously been deposited. To keep a correct count we need to keep track of WETH that has already been accounted for. This value represents the amount of WETH balance of this contract that has already been accounted for by the deposit events. It is important to note that this variable is not concerned with WETH that is a result of full/partial withdrawal of the validators. It is strictly concerned with WETH that has been deposited and is waiting to be staked.\"}},\"title\":\"Native Staking SSV Strategy\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"BEACON_CHAIN_DEPOSIT_CONTRACT()\":{\"notice\":\"The address of the beacon chain deposit contract\"},\"FEE_ACCUMULATOR_ADDRESS()\":{\"notice\":\"Fee collector address\"},\"MAX_STAKE()\":{\"notice\":\"The maximum amount of ETH that can be staked by a validator\"},\"MIN_FIX_ACCOUNTING_CADENCE()\":{\"notice\":\"The minimum amount of blocks that need to pass between two calls to manuallyFixAccounting\"},\"SSV_NETWORK_ADDRESS()\":{\"notice\":\"The address of the SSV Network contract used to interface with\"},\"SSV_TOKEN_ADDRESS()\":{\"notice\":\"SSV ERC20 token that serves as a payment for operating SSV validators\"},\"VAULT_ADDRESS()\":{\"notice\":\"Address of the OETH Vault proxy contract\"},\"WETH_TOKEN_ADDRESS()\":{\"notice\":\"The address of the Wrapped ETH (WETH) token contract\"},\"activeDepositedValidators()\":{\"notice\":\"The number of validators that have 32 (!) ETH actively deposited. When a new deposit to a validator happens this number increases, when a validator exit is detected this number decreases.\"},\"assetToPToken(address)\":{\"notice\":\"asset => pToken (Platform Specific Token Address)\"},\"checkBalance(address)\":{\"notice\":\"Returns the total value of (W)ETH that is staked to the validators and WETH deposits that are still to be staked. This does not include ETH from consensus rewards sitting in this strategy or ETH from MEV rewards in the FeeAccumulator. These rewards are harvested and sent to the Dripper so will eventually be sent to the Vault as WETH.\"},\"claimGovernance()\":{\"notice\":\"Claim Governance of the contract to a new account (`newGovernor`). Can only be called by the new Governor.\"},\"collectRewardTokens()\":{\"notice\":\"Collect accumulated reward token and send to Vault.\"},\"consensusRewards()\":{\"notice\":\"Keeps track of the total consensus rewards swept from the beacon chain\"},\"deposit(address,uint256)\":{\"notice\":\"Unlike other strategies, this does not deposit assets into the underlying platform. It just checks the asset is WETH and emits the Deposit event. To deposit WETH into validators `registerSsvValidator` and `stakeEth` must be used. Will NOT revert if the strategy is paused from an accounting failure.\"},\"depositAll()\":{\"notice\":\"Unlike other strategies, this does not deposit assets into the underlying platform. It just emits the Deposit event. To deposit WETH into validators `registerSsvValidator` and `stakeEth` must be used. Will NOT revert if the strategy is paused from an accounting failure.\"},\"depositSSV(uint64[],uint256,(uint32,uint64,uint64,bool,uint256))\":{\"notice\":\"Deposits more SSV Tokens to the SSV Network contract which is used to pay the SSV Operators.\"},\"doAccounting()\":{\"notice\":\"This notion page offers a good explanation of how the accounting functions https://www.notion.so/originprotocol/Limited-simplified-native-staking-accounting-67a217c8420d40678eb943b9da0ee77d In short, after dividing by 32, if the ETH remaining on the contract falls between 0 and fuseIntervalStart, the accounting function will treat that ETH as Beacon chain consensus rewards. On the contrary, if after dividing by 32, the ETH remaining on the contract falls between fuseIntervalEnd and 32, the accounting function will treat that as a validator slashing.Perform the accounting attributing beacon chain ETH to either full or partial withdrawals. Returns true when accounting is valid and fuse isn't \\\"blown\\\". Returns false when fuse is blown.\"},\"exitSsvValidator(bytes,uint64[])\":{\"notice\":\"Exit a validator from the Beacon chain. The staked ETH will eventually swept to this native staking strategy. Only the registrator can call this function.\"},\"fuseIntervalEnd()\":{\"notice\":\"end of fuse interval\"},\"fuseIntervalStart()\":{\"notice\":\"start of fuse interval\"},\"getRewardTokenAddresses()\":{\"notice\":\"Get the reward token addresses.\"},\"governor()\":{\"notice\":\"Returns the address of the current Governor.\"},\"harvesterAddress()\":{\"notice\":\"Address of the Harvester contract allowed to collect reward tokens\"},\"initialize(address[],address[],address[])\":{\"notice\":\"initialize function, to set up initial internal state\"},\"isGovernor()\":{\"notice\":\"Returns true if the caller is the current Governor.\"},\"lastFixAccountingBlockNumber()\":{\"notice\":\"last block number manuallyFixAccounting has been called\"},\"manuallyFixAccounting(int256,int256,uint256)\":{\"notice\":\"Allow the Strategist to fix the accounting of this strategy and unpause.\"},\"platformAddress()\":{\"notice\":\"Address of the underlying platform\"},\"registerSsvValidator(bytes,uint64[],bytes,uint256,(uint32,uint64,uint64,bool,uint256))\":{\"notice\":\"Registers a new validator in the SSV Cluster. Only the registrator can call this function.\"},\"removePToken(uint256)\":{\"notice\":\"Remove a supported asset by passing its index. This method can only be called by the system Governor\"},\"removeSsvValidator(bytes,uint64[],(uint32,uint64,uint64,bool,uint256))\":{\"notice\":\"Remove a validator from the SSV Cluster. Make sure `exitSsvValidator` is called before and the validate has exited the Beacon chain. If removed before the validator has exited the beacon chain will result in the validator being slashed. Only the registrator can call this function.\"},\"resetStakeETHTally()\":{\"notice\":\"Reset the stakeETHTally\"},\"rewardTokenAddresses(uint256)\":{\"notice\":\"Address of the reward tokens. eg CRV, BAL, CVX, AURA\"},\"safeApproveAllTokens()\":{\"notice\":\"Approves the SSV Network contract to transfer SSV tokens for deposits\"},\"setFuseInterval(uint256,uint256)\":{\"notice\":\"set fuse interval values\"},\"setHarvesterAddress(address)\":{\"notice\":\"Set the Harvester contract that can collect rewards.\"},\"setPTokenAddress(address,address)\":{\"notice\":\"Provide support for asset by passing its pToken address. This method can only be called by the system Governor\"},\"setRegistrator(address)\":{\"notice\":\"Set the address of the registrator which can register, exit and remove validators\"},\"setRewardTokenAddresses(address[])\":{\"notice\":\"Set the reward token addresses. Any old addresses will be overwritten.\"},\"setStakeETHThreshold(uint256)\":{\"notice\":\"Set the amount of ETH that can be staked before staking monitor\"},\"setStakingMonitor(address)\":{\"notice\":\"Set the address of the staking monitor that is allowed to reset stakeETHTally\"},\"stakeETHTally()\":{\"notice\":\"Amount of ETH that can has been staked since the last governor approval.\"},\"stakeETHThreshold()\":{\"notice\":\"Amount of ETH that can be staked before staking on the contract is suspended and the governor needs to approve further staking\"},\"stakeEth((bytes,bytes,bytes32)[])\":{\"notice\":\"Stakes WETH to the node validators\"},\"stakingMonitor()\":{\"notice\":\"The account that is allowed to modify stakeETHThreshold and reset stakeETHTally\"},\"supportsAsset(address)\":{\"notice\":\"Returns bool indicating whether asset is supported by strategy.\"},\"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 strategy contracts, i.e. mistaken sends.\"},\"validatorRegistrator()\":{\"notice\":\"Address of the registrator - allowed to register, exit and remove validators\"},\"validatorsStates(bytes32)\":{\"notice\":\"State of the validators keccak256(pubKey) => state\"},\"vaultAddress()\":{\"notice\":\"Address of the OToken vault\"},\"withdraw(address,address,uint256)\":{\"notice\":\"Withdraw WETH from this contract. Used only if some WETH for is lingering on the contract. That can happen when: - the deposit was not a multiple of 32 WETH - someone sent WETH directly to this contract Will NOT revert if the strategy is paused from an accounting failure.\"},\"withdrawAll()\":{\"notice\":\"transfer all WETH deposits back to the vault. This does not withdraw from the validators. That has to be done separately with the `exitSsvValidator` and `removeSsvValidator` operations. This does not withdraw any execution rewards from the FeeAccumulator or consensus rewards in this strategy. Any ETH in this strategy that was swept from a full validator withdrawal will not be withdrawn. ETH from full validator withdrawals is sent to the Vault using `doAccounting`. Will NOT revert if the strategy is paused from an accounting failure.\"}},\"notice\":\"Strategy to deploy funds into DVT validators powered by the SSV Network\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol\":\"NativeStakingSSVStrategy\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"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\",\"keccak256\":\"0xe68ed7fb8766ed1e888291f881e36b616037f852b37d96877045319ad298ba87\",\"license\":\"MIT\"},\"@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/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\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@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\",\"keccak256\":\"0xfaad496c1c944b6259b7dc70b4865eb1775d6402bc0c81b38a0b24d9f525ae37\",\"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/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\",\"keccak256\":\"0x598f90bdbc854250bbd5991426bfb43367207e64e33109c41aa8b54323fd8d8e\",\"license\":\"MIT\"},\"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 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 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 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\",\"keccak256\":\"0xbef02bd5257e61dec0a6be4b1531064a7fdfeb4043885443a1902fb5d1b23e1b\",\"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/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 function removeAsset(address _asset) external;\\n}\\n\",\"keccak256\":\"0xa03ba17b6224bec26290794760fc807e017260406037b4f812970701888e72c8\",\"license\":\"MIT\"},\"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\",\"keccak256\":\"0x05b7dce6c24d3cd4e48b5c6346d86e5e40ecc3291bcdf3f3ef091c98fc826519\",\"license\":\"MIT\"},\"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\\nimport { Governable } from \\\"../../governance/Governable.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 is Governable {\\n /// @notice The address of the Native Staking Strategy\\n address public immutable STRATEGY;\\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 }\\n\\n /**\\n * @dev Accept ETH\\n */\\n receive() external payable {}\\n}\\n\",\"keccak256\":\"0xb8fda3b87dc5d6f8aee4bf1d015a585211e5b5a319dfa4b0f4770e3f5a2d5939\",\"license\":\"MIT\"},\"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_ADDRESS;\\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 _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 address _feeAccumulator,\\n address _beaconChainDepositContract\\n )\\n InitializableAbstractStrategy(_baseConfig)\\n ValidatorAccountant(\\n _wethAddress,\\n _baseConfig.vaultAddress,\\n _beaconChainDepositContract,\\n _ssvNetwork\\n )\\n {\\n SSV_TOKEN_ADDRESS = _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 /// @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_TOKEN_ADDRESS).deposit{ value: ethRewards }();\\n\\n emit RewardTokenCollected(\\n harvesterAddress,\\n WETH_TOKEN_ADDRESS,\\n ethRewards\\n );\\n IERC20(WETH_TOKEN_ADDRESS).safeTransfer(\\n harvesterAddress,\\n ethRewards\\n );\\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_TOKEN_ADDRESS, \\\"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_TOKEN_ADDRESS).balanceOf(\\n address(this)\\n );\\n uint256 newWeth = wethBalance - depositedWethAccountedFor;\\n\\n if (newWeth > 0) {\\n depositedWethAccountedFor = wethBalance;\\n\\n _deposit(WETH_TOKEN_ADDRESS, newWeth);\\n }\\n }\\n\\n /// @notice Withdraw WETH from this contract. Used only if some WETH for is lingering on the contract. That\\n /// can happen when:\\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 _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 emit Withdrawal(_asset, address(0), _amount);\\n IERC20(_asset).safeTransfer(_recipient, _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_TOKEN_ADDRESS).balanceOf(\\n address(this)\\n );\\n if (wethBalance > 0) {\\n _withdraw(vaultAddress, WETH_TOKEN_ADDRESS, wethBalance);\\n }\\n }\\n\\n function _abstractSetPToken(address _asset, address) internal override {}\\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_TOKEN_ADDRESS, \\\"Unsupported asset\\\");\\n\\n balance =\\n // add the ETH that has been staked in validators\\n activeDepositedValidators *\\n 32 ether +\\n // add the WETH in the strategy from deposits that are still to be staked\\n IERC20(WETH_TOKEN_ADDRESS).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_TOKEN_ADDRESS;\\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_ADDRESS).approve(\\n SSV_NETWORK_ADDRESS,\\n type(uint256).max\\n );\\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 ||\\n msg.sender == WETH_TOKEN_ADDRESS,\\n \\\"eth not from allowed contracts\\\"\\n );\\n }\\n\\n function _wethWithdrawnToVault(uint256 _amount) internal override {\\n emit Withdrawal(WETH_TOKEN_ADDRESS, address(0), _amount);\\n }\\n\\n function _wethWithdrawnAndStaked(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 direclty\\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\",\"keccak256\":\"0x937ce31cd4b90ad532fdde874dc02eaf0a29a800c2c2292d2d6cb71afa75f32d\",\"license\":\"MIT\"},\"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 /// @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 MAX_STAKE = 32 ether;\\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 constructor(\\n address _wethAddress,\\n address _vaultAddress,\\n address _beaconChainDepositContract,\\n address _ssvNetwork\\n )\\n ValidatorRegistrator(\\n _wethAddress,\\n _vaultAddress,\\n _beaconChainDepositContract,\\n _ssvNetwork\\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 _fuseIntervalStart < 32 ether &&\\n _fuseIntervalEnd < 32 ether &&\\n _fuseIntervalEnd - _fuseIntervalStart >= 4 ether,\\n \\\"incorrect fuse interval\\\"\\n );\\n\\n emit FuseIntervalUpdated(_fuseIntervalStart, _fuseIntervalEnd);\\n\\n fuseIntervalStart = _fuseIntervalStart;\\n fuseIntervalEnd = _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 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 >= MAX_STAKE) {\\n uint256 fullyWithdrawnValidators;\\n // safe since MAX_STAKE is hardcoded to 32ETH\\n unchecked {\\n // explicitly cast to uint256 as we want to round to a whole number of validators\\n fullyWithdrawnValidators = uint256(newSweptETH / MAX_STAKE);\\n }\\n activeDepositedValidators -= fullyWithdrawnValidators;\\n\\n uint256 wethToVault = MAX_STAKE * fullyWithdrawnValidators;\\n IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: wethToVault }();\\n // slither-disable-next-line unchecked-transfer\\n IWETH9(WETH_TOKEN_ADDRESS).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 < 32 ether, \\\"unexpected accounting\\\");\\n\\n // If no Beacon chain consensus rewards swept\\n if (ethRemaining == 0) {\\n // do nothing\\n return accountingValid;\\n }\\n // Beacon chain consensus rewards swept (partial validator withdrawals)\\n else if (ethRemaining < fuseIntervalStart) {\\n // solhint-disable-next-line reentrancy\\n consensusRewards += ethRemaining;\\n emit AccountingConsensusRewards(ethRemaining);\\n }\\n // Beacon chain consensus rewards swept but also a slashed validator fully exited\\n else if (ethRemaining > fuseIntervalEnd) {\\n IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: ethRemaining }();\\n // slither-disable-next-line unchecked-transfer\\n IWETH9(WETH_TOKEN_ADDRESS).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 {\\n require(\\n lastFixAccountingBlockNumber + MIN_FIX_ACCOUNTING_CADENCE <\\n block.number,\\n \\\"manuallyFixAccounting 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 emit AccountingManuallyFixed(\\n _validatorsDelta,\\n _consensusRewardsDelta,\\n _ethToVaultAmount\\n );\\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_TOKEN_ADDRESS).deposit{ value: _ethToVaultAmount }();\\n // slither-disable-next-line unchecked-transfer\\n IWETH9(WETH_TOKEN_ADDRESS).transfer(\\n VAULT_ADDRESS,\\n _ethToVaultAmount\\n );\\n _wethWithdrawnToVault(_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 Withdrawal event\\n function _wethWithdrawnToVault(uint256 _amount) internal virtual;\\n}\\n\",\"keccak256\":\"0x0adba45b3fa66233c9e9bc0575ca388ebcd027cba2546278c5887065b95da708\",\"license\":\"MIT\"},\"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 address of the Wrapped ETH (WETH) token contract\\n address public immutable WETH_TOKEN_ADDRESS;\\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_ADDRESS;\\n /// @notice Address of the OETH Vault proxy contract\\n address public immutable VAULT_ADDRESS;\\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 governor needs to approve further staking\\n uint256 public stakeETHThreshold;\\n /// @notice Amount of ETH that can has been staked since the last governor approval.\\n uint256 public stakeETHTally;\\n // For future use\\n uint256[47] private __gap;\\n\\n enum VALIDATOR_STATE {\\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 newAddress);\\n event StakingMonitorChanged(address newAddress);\\n event ETHStaked(bytes pubkey, uint256 amount, bytes withdrawal_credentials);\\n event SSVValidatorRegistered(bytes pubkey, uint64[] operatorIds);\\n event SSVValidatorExitInitiated(bytes pubkey, uint64[] operatorIds);\\n event SSVValidatorExitCompleted(bytes pubkey, uint64[] operatorIds);\\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 constructor(\\n address _wethAddress,\\n address _vaultAddress,\\n address _beaconChainDepositContract,\\n address _ssvNetwork\\n ) {\\n WETH_TOKEN_ADDRESS = _wethAddress;\\n BEACON_CHAIN_DEPOSIT_CONTRACT = _beaconChainDepositContract;\\n SSV_NETWORK_ADDRESS = _ssvNetwork;\\n VAULT_ADDRESS = _vaultAddress;\\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 emit RegistratorChanged(_address);\\n validatorRegistrator = _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 emit StakingMonitorChanged(_address);\\n stakingMonitor = _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 emit StakeETHThresholdChanged(_amount);\\n stakeETHThreshold = _amount;\\n }\\n\\n /// @notice Reset the stakeETHTally\\n function resetStakeETHTally() external onlyStakingMonitor {\\n emit StakeETHTallyReset();\\n stakeETHTally = 0;\\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 {\\n uint256 requiredETH = validators.length * 32 ether;\\n\\n // Check there is enough WETH from the deposits sitting in this strategy contract\\n require(\\n requiredETH <= IWETH9(WETH_TOKEN_ADDRESS).balanceOf(address(this)),\\n \\\"insufficient WETH\\\"\\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_TOKEN_ADDRESS).withdraw(requiredETH);\\n _wethWithdrawnAndStaked(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 withdrawal_credentials = abi.encodePacked(\\n bytes1(0x01),\\n bytes11(0),\\n address(this)\\n );\\n\\n uint256 validatorsLength = validators.length;\\n // For each validator\\n for (uint256 i = 0; i < validatorsLength; ) {\\n bytes32 pubkeyHash = keccak256(validators[i].pubkey);\\n VALIDATOR_STATE currentState = validatorsStates[pubkeyHash];\\n\\n require(\\n currentState == VALIDATOR_STATE.REGISTERED,\\n \\\"Validator not registered\\\"\\n );\\n\\n IDepositContract(BEACON_CHAIN_DEPOSIT_CONTRACT).deposit{\\n value: 32 ether\\n }(\\n validators[i].pubkey,\\n withdrawal_credentials,\\n validators[i].signature,\\n validators[i].depositDataRoot\\n );\\n\\n emit ETHStaked(\\n validators[i].pubkey,\\n 32 ether,\\n withdrawal_credentials\\n );\\n\\n validatorsStates[pubkeyHash] = VALIDATOR_STATE.STAKED;\\n\\n unchecked {\\n ++i;\\n }\\n }\\n // save gas by changing this storage variable only once rather each time in the loop.\\n activeDepositedValidators += validatorsLength;\\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 function registerSsvValidator(\\n bytes calldata publicKey,\\n uint64[] calldata operatorIds,\\n bytes calldata sharesData,\\n uint256 amount,\\n Cluster calldata cluster\\n ) external onlyRegistrator whenNotPaused {\\n ISSVNetwork(SSV_NETWORK_ADDRESS).registerValidator(\\n publicKey,\\n operatorIds,\\n sharesData,\\n amount,\\n cluster\\n );\\n validatorsStates[keccak256(publicKey)] = VALIDATOR_STATE.REGISTERED;\\n emit SSVValidatorRegistered(publicKey, operatorIds);\\n }\\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 // slither-disable-start reentrancy-no-eth\\n function exitSsvValidator(\\n bytes calldata publicKey,\\n uint64[] calldata operatorIds\\n ) external onlyRegistrator whenNotPaused {\\n VALIDATOR_STATE currentState = validatorsStates[keccak256(publicKey)];\\n require(currentState == VALIDATOR_STATE.STAKED, \\\"Validator not staked\\\");\\n\\n ISSVNetwork(SSV_NETWORK_ADDRESS).exitValidator(publicKey, operatorIds);\\n emit SSVValidatorExitInitiated(publicKey, operatorIds);\\n\\n validatorsStates[keccak256(publicKey)] = VALIDATOR_STATE.EXITING;\\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 // 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 VALIDATOR_STATE currentState = validatorsStates[keccak256(publicKey)];\\n require(\\n currentState == VALIDATOR_STATE.EXITING,\\n \\\"Validator not exiting\\\"\\n );\\n\\n ISSVNetwork(SSV_NETWORK_ADDRESS).removeValidator(\\n publicKey,\\n operatorIds,\\n cluster\\n );\\n emit SSVValidatorExitCompleted(publicKey, operatorIds);\\n\\n validatorsStates[keccak256(publicKey)] = VALIDATOR_STATE.EXIT_COMPLETE;\\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 cluster The SSV cluster details that must be derived from emitted events from the SSVNetwork contract.\\n function depositSSV(\\n uint64[] memory operatorIds,\\n uint256 amount,\\n Cluster memory cluster\\n ) external onlyStrategist {\\n ISSVNetwork(SSV_NETWORK_ADDRESS).deposit(\\n address(this),\\n operatorIds,\\n amount,\\n cluster\\n );\\n }\\n\\n /***************************************\\n Abstract\\n ****************************************/\\n\\n /// @dev allows for NativeStakingSSVStrategy contract know how much WETH had been staked\\n function _wethWithdrawnAndStaked(uint256 _amount) internal virtual;\\n}\\n\",\"keccak256\":\"0xe2aace3979938c643a5c5ece3869c0901cad82b86be03d64a64192071522da7f\",\"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/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\",\"keccak256\":\"0x5e17bb3db9f9e1014b7c5c836547f8fa81e02af7568c0bb8f2a2e0e7c2192db4\",\"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/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\\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\":\"0xcbdb87104749e20c8411bc2acbfa0b7d48e876e3f4e1c46c9a7b00fcdb9722d9\",\"license\":\"MIT\"}},\"version\":1}", + "bytecode": "0x6101806040523480156200001257600080fd5b506040516200518c3803806200518c833981016040819052620000359162000138565b8585876020015183868383838362000053336200010860201b60201c565b6000805160206200516c833981519152546040516001600160a01b03909116906000907fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a908290a36033805460ff191690556001600160601b0319606094851b811660805291841b821660a052831b811660c05290821b811660e0528651821b811661010052602090960151811b86166101205298891b851661014052505050509190931b1661016052506200021392505050565b6000805160206200516c83398151915255565b80516001600160a01b03811681146200013357600080fd5b919050565b60008060008060008086880360e08112156200015357600080fd5b60408112156200016257600080fd5b50604080519081016001600160401b03811182821017156200019457634e487b7160e01b600052604160045260246000fd5b604052620001a2886200011b565b8152620001b2602089016200011b565b60208201529550620001c7604088016200011b565b9450620001d7606088016200011b565b9350620001e7608088016200011b565b9250620001f760a088016200011b565b91506200020760c088016200011b565b90509295509295509295565b60805160601c60a05160601c60c05160601c60e05160601c6101005160601c6101205160601c6101405160601c6101605160601c614db5620003b76000396000818161038a01528181610af40152613287015260008181610680015261272d01526000818161053401528181610f0801528181611b8201528181611cfb01528181612a8c0152612d1401526000610ac001526000818161083b01528181610cd001528181611ab001528181611d4b0152818161210f015281816138730152613acd015260008181610b7e01528181610da601528181611982015281816126fd015281816128150152612c0a015260008181610a1501526116c40152600081816103bc015281816105de0152818161092c01528181610c3701528181610f7d015281816111c101528181611249015281816113f80152818161154901528181611c6c01528181611d1c015281816120890152818161213e01528181612d9f01528181612e470152818161338c015281816134110152818161348501528181613722015281816137ed015281816138a201528181613a470152613afc0152614db56000f3fe60806040526004361061037a5760003560e01c8063853828b6116101d1578063c7af335211610102578063dbe55e56116100a0578063e75292391161006f578063e752923914610b41578063ee7afe2d14610b57578063f1188e4014610b6c578063f6ca71b014610ba057600080fd5b8063dbe55e5614610aae578063dd505df614610ae2578063de34d71314610b16578063de5f626814610b2c57600080fd5b8063d059f6ef116100dc578063d059f6ef14610a37578063d38bfff414610a4e578063d9caed1214610a6e578063d9f00ec714610a8e57600080fd5b8063c7af3352146109d1578063c98517c5146109e6578063cceab75014610a0357600080fd5b8063a3b81e731161016f578063ab12edf511610149578063ab12edf51461095c578063ad1728cb1461097c578063bb1b918d14610991578063c2e1e3f4146109b157600080fd5b8063a3b81e73146108da578063a4f98af4146108fa578063aa388af61461090f57600080fd5b80639092c31c116101ab5780639092c31c146108295780639136616a1461085d57806396d538bb1461087d5780639da0e4621461089d57600080fd5b8063853828b6146107cf57806387bae867146107e45780638d7c0e461461080957600080fd5b80635d36b190116102ab5780636ef38795116102495780637b2d9b2c116102235780637b2d9b2c1461076e5780637b8962f71461078e578063842f5c46146107a45780638456cb59146107ba57600080fd5b80636ef387951461070e57806371a735f31461072e5780637260f8261461074e57600080fd5b8063630923831161028557806363092383146106a257806366e3667e146106b857806367c7066c146106ce5780636e811d38146106ee57600080fd5b80635d36b190146106395780635f5152261461064e5780636093d3801461066e57600080fd5b8063435356d1116103185780635205c380116102f25780635205c380146105ac578063579a7e1a146105cc5780635a063f63146106005780635c975abb1461061557600080fd5b8063435356d11461055657806347e7ef2414610576578063484be8121461059657600080fd5b80631072cbea116103545780631072cbea146104be57806322495dc8146104de5780633c864959146104fe578063430bf08a1461052257600080fd5b80630c340a24146104365780630ed57b3a146104685780630fc3b4c41461048857600080fd5b3661043157336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614806103de5750336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016145b61042f5760405162461bcd60e51b815260206004820152601e60248201527f657468206e6f742066726f6d20616c6c6f77656420636f6e747261637473000060448201526064015b60405180910390fd5b005b600080fd5b34801561044257600080fd5b5061044b610bc2565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561047457600080fd5b5061042f610483366004614158565b610bdf565b34801561049457600080fd5b5061044b6104a336600461411e565b609f602052600090815260409020546001600160a01b031681565b3480156104ca57600080fd5b5061042f6104d93660046141d2565b610c11565b3480156104ea57600080fd5b5061042f6104f93660046142c6565b610cce565b34801561050a57600080fd5b5061051460695481565b60405190815260200161045f565b34801561052e57600080fd5b5061044b7f000000000000000000000000000000000000000000000000000000000000000081565b34801561056257600080fd5b5061042f61057136600461423f565b610e18565b34801561058257600080fd5b5061042f6105913660046141d2565b610efd565b3480156105a257600080fd5b50610514606a5481565b3480156105b857600080fd5b5061042f6105c736600461439c565b61101c565b3480156105d857600080fd5b5061044b7f000000000000000000000000000000000000000000000000000000000000000081565b34801561060c57600080fd5b5061042f611078565b34801561062157600080fd5b5060335460ff165b604051901515815260200161045f565b34801561064557600080fd5b5061042f611117565b34801561065a57600080fd5b5061051461066936600461411e565b6111bd565b34801561067a57600080fd5b5061044b7f000000000000000000000000000000000000000000000000000000000000000081565b3480156106ae57600080fd5b50610514611c2081565b3480156106c457600080fd5b5061051460345481565b3480156106da57600080fd5b5060a35461044b906001600160a01b031681565b3480156106fa57600080fd5b5061042f61070936600461411e565b6112f1565b34801561071a57600080fd5b5061042f6107293660046141fe565b611379565b34801561073a57600080fd5b5061042f6107493660046144d4565b61188b565b34801561075a57600080fd5b5060365461044b906001600160a01b031681565b34801561077a57600080fd5b5061044b61078936600461439c565b611a84565b34801561079a57600080fd5b5061051460375481565b3480156107b057600080fd5b5061051460685481565b3480156107c657600080fd5b5061042f611aae565b3480156107db57600080fd5b5061042f611b77565b3480156107f057600080fd5b5060335461044b9061010090046001600160a01b031681565b34801561081557600080fd5b5061042f610824366004614555565b611d49565b34801561083557600080fd5b5061044b7f000000000000000000000000000000000000000000000000000000000000000081565b34801561086957600080fd5b5061042f61087836600461439c565b61221e565b34801561088957600080fd5b5061042f6108983660046141fe565b6123e9565b3480156108a957600080fd5b506108cd6108b836600461439c565b60356020526000908152604090205460ff1681565b60405161045f91906149c0565b3480156108e657600080fd5b5061042f6108f536600461411e565b612509565b34801561090657600080fd5b5061062961258b565b34801561091b57600080fd5b5061062961092a36600461411e565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0390811691161490565b34801561096857600080fd5b5061042f61097736600461459a565b6125ea565b34801561098857600080fd5b5061042f6126e6565b34801561099d57600080fd5b5061042f6109ac366004614420565b6127ac565b3480156109bd57600080fd5b5061042f6109cc36600461411e565b61291f565b3480156109dd57600080fd5b506106296129ac565b3480156109f257600080fd5b506105146801bc16d674ec80000081565b348015610a0f57600080fd5b5061044b7f000000000000000000000000000000000000000000000000000000000000000081565b348015610a4357600080fd5b506105146101075481565b348015610a5a57600080fd5b5061042f610a6936600461411e565b6129dd565b348015610a7a57600080fd5b5061042f610a89366004614191565b612a81565b348015610a9a57600080fd5b5061042f610aa93660046143b5565b612b14565b348015610aba57600080fd5b5061044b7f000000000000000000000000000000000000000000000000000000000000000081565b348015610aee57600080fd5b5061044b7f000000000000000000000000000000000000000000000000000000000000000081565b348015610b2257600080fd5b5061051460385481565b348015610b3857600080fd5b5061042f612d09565b348015610b4d57600080fd5b50610514606b5481565b348015610b6357600080fd5b5061042f612e76565b348015610b7857600080fd5b5061044b7f000000000000000000000000000000000000000000000000000000000000000081565b348015610bac57600080fd5b50610bb5612f00565b60405161045f9190614796565b6000610bda600080516020614d608339815191525490565b905090565b610be76129ac565b610c035760405162461bcd60e51b815260040161042690614a32565b610c0d8282612f62565b5050565b610c196129ac565b610c355760405162461bcd60e51b815260040161042690614a32565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b039081169083161415610cb25760405162461bcd60e51b815260206004820152601f60248201527f43616e6e6f74207472616e7366657220737570706f72746564206173736574006044820152606401610426565b610c0d610cbd610bc2565b6001600160a01b03841690836130c1565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b158015610d2757600080fd5b505afa158015610d3b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d5f919061413b565b6001600160a01b0316336001600160a01b031614610d8f5760405162461bcd60e51b815260040161042690614af2565b60405163bc26e7e560e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063bc26e7e590610de19030908790879087906004016146e6565b600060405180830381600087803b158015610dfb57600080fd5b505af1158015610e0f573d6000803e3d6000fd5b50505050505050565b610e206129ac565b610e3c5760405162461bcd60e51b815260040161042690614a32565b600054610100900460ff1680610e55575060005460ff16155b610eb85760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610426565b600054610100900460ff16158015610eda576000805461ffff19166101011790555b610ee5848484613113565b8015610ef7576000805461ff00191690555b50505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610f455760405162461bcd60e51b8152600401610426906149fb565b600080516020614d4083398151915280546002811415610f775760405162461bcd60e51b815260040161042690614aca565b600282557f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316846001600160a01b031614610ff05760405162461bcd60e51b8152602060048201526011602482015270155b9cdd5c1c1bdc9d195908185cdcd95d607a1b6044820152606401610426565b8261010760008282546110039190614c19565b90915550611013905084846131ce565b50600190555050565b6110246129ac565b6110405760405162461bcd60e51b815260040161042690614a32565b6040518181527fe26b067424903962f951f568e52ec9a3bbe1589526ea54a4e69ca6eaae1a4c779060200160405180910390a1603755565b60a3546001600160a01b031633146110d25760405162461bcd60e51b815260206004820152601b60248201527f43616c6c6572206973206e6f74207468652048617276657374657200000000006044820152606401610426565b600080516020614d40833981519152805460028114156111045760405162461bcd60e51b815260040161042690614aca565b60028255611110613260565b5060019055565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b0316146111b25760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b6064820152608401610426565b6111bb336134ae565b565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b0316146112345760405162461bcd60e51b8152602060048201526011602482015270155b9cdd5c1c1bdc9d195908185cdcd95d607a1b6044820152606401610426565b6040516370a0823160e01b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b15801561129357600080fd5b505afa1580156112a7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112cb9190614581565b6034546112e1906801bc16d674ec800000614c31565b6112eb9190614c19565b92915050565b6112f96129ac565b6113155760405162461bcd60e51b815260040161042690614a32565b6040516001600160a01b03821681527f83f29c79feb71f8fba9d0fbc4ba5f0982a28b6b1e868b3fc50e6400d100bca0f9060200160405180910390a1603380546001600160a01b0390921661010002610100600160a81b0319909216919091179055565b60335461010090046001600160a01b031633146113a85760405162461bcd60e51b815260040161042690614a93565b60335460ff16156113cb5760405162461bcd60e51b815260040161042690614a69565b60006113e0826801bc16d674ec800000614c31565b6040516370a0823160e01b81523060048201529091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b15801561144257600080fd5b505afa158015611456573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061147a9190614581565b8111156114bd5760405162461bcd60e51b81526020600482015260116024820152700d2dce6eaccccd2c6d2cadce840ae8aa89607b1b6044820152606401610426565b603754816038546114ce9190614c19565b111561151c5760405162461bcd60e51b815260206004820152601a60248201527f5374616b696e6720455448206f766572207468726573686f6c640000000000006044820152606401610426565b806038600082825461152e9190614c19565b9091555050604051632e1a7d4d60e01b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561159557600080fd5b505af11580156115a9573d6000803e3d6000fd5b505050506115b68161356f565b60408051600160f81b60208201526000602182018190526bffffffffffffffffffffffff193060601b16602c830152910160408051601f1981840301815291905290508260005b8181101561186c57600086868381811061161957611619614cf0565b905060200281019061162b9190614b6f565b6116359080614b29565b6040516116439291906146ba565b6040805191829003909120600081815260356020529182205490925060ff169081600381111561167557611675614cc4565b146116c25760405162461bcd60e51b815260206004820152601860248201527f56616c696461746f72206e6f74207265676973746572656400000000000000006044820152606401610426565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663228951186801bc16d674ec8000008a8a8781811061170d5761170d614cf0565b905060200281019061171f9190614b6f565b6117299080614b29565b898d8d8a81811061173c5761173c614cf0565b905060200281019061174e9190614b6f565b61175c906020810190614b29565b8f8f8c81811061176e5761176e614cf0565b90506020028101906117809190614b6f565b604001356040518863ffffffff1660e01b81526004016117a596959493929190614945565b6000604051808303818588803b1580156117be57600080fd5b505af11580156117d2573d6000803e3d6000fd5b50505050507ffeb31a79d38edb1b090d516e4df3e273651179c6f2c2ec53a9a22ae015b70ba988888581811061180a5761180a614cf0565b905060200281019061181c9190614b6f565b6118269080614b29565b6801bc16d674ec800000886040516118419493929190614994565b60405180910390a1506000908152603560205260409020805460ff19166001908117909155016115fd565b50806034600082825461187f9190614c19565b90915550505050505050565b60335461010090046001600160a01b031633146118ba5760405162461bcd60e51b815260040161042690614a93565b60335460ff16156118dd5760405162461bcd60e51b815260040161042690614a69565b60006035600087876040516118f39291906146ba565b604080519182900390912082526020820192909252016000205460ff169050600281600381111561192657611926614cc4565b1461196b5760405162461bcd60e51b815260206004820152601560248201527456616c696461746f72206e6f742065786974696e6760581b6044820152606401610426565b6040516312b3fc1960e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906312b3fc19906119bf9089908990899089908990600401614904565b600060405180830381600087803b1580156119d957600080fd5b505af11580156119ed573d6000803e3d6000fd5b505050507ff72821b8777f002ccdf6326f1242d9e0f762eb077668b67bebe640535378066d86868686604051611a26949392919061487b565b60405180910390a16003603560008888604051611a449291906146ba565b60408051918290039091208252602082019290925201600020805460ff19166001836003811115611a7757611a77614cc4565b0217905550505050505050565b60a48181548110611a9457600080fd5b6000918252602090912001546001600160a01b0316905081565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b158015611b0757600080fd5b505afa158015611b1b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b3f919061413b565b6001600160a01b0316336001600160a01b031614611b6f5760405162461bcd60e51b815260040161042690614af2565b6111bb61359c565b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161480611bc65750611bb1610bc2565b6001600160a01b0316336001600160a01b0316145b611c1e5760405162461bcd60e51b815260206004820152602360248201527f43616c6c6572206973206e6f7420746865205661756c74206f7220476f7665726044820152623737b960e91b6064820152608401610426565b600080516020614d4083398151915280546002811415611c505760405162461bcd60e51b815260040161042690614aca565b600282556040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b158015611cb657600080fd5b505afa158015611cca573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cee9190614581565b90508015611d4157611d417f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000083613611565b505060019055565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b158015611da257600080fd5b505afa158015611db6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dda919061413b565b6001600160a01b0316336001600160a01b031614611e0a5760405162461bcd60e51b815260040161042690614af2565b60335460ff16611e535760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610426565b43611c20606b54611e649190614c19565b10611ebf5760405162461bcd60e51b815260206004820152602560248201527f6d616e75616c6c794669784163636f756e74696e672063616c6c656420746f6f6044820152641039b7b7b760d91b6064820152608401610426565b6002198312158015611ed2575060038313155b8015611eec5750600083603454611ee99190614bd8565b12155b611f385760405162461bcd60e51b815260206004820152601760248201527f696e76616c69642076616c696461746f727344656c74610000000000000000006044820152606401610426565b6811ff6cf0fd15afffff198212158015611f5b57506811ff6cf0fd15b000008213155b8015611f755750600082606854611f729190614bd8565b12155b611fc15760405162461bcd60e51b815260206004820152601d60248201527f696e76616c696420636f6e73656e7375735265776172647344656c74610000006044820152606401610426565b68053444835ec580000081111561201a5760405162461bcd60e51b815260206004820152601960248201527f696e76616c69642077657468546f5661756c74416d6f756e74000000000000006044820152606401610426565b60408051848152602081018490529081018290527f80d022717ea022455c5886b8dd8a29c037570aae58aeb4d7b136d7a10ec2e4319060600160405180910390a1826034546120699190614bd8565b60345560685461207a908390614bd8565b60685543606b5580156121c8577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b1580156120e257600080fd5b505af11580156120f6573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb92506044019050602060405180830381600087803b15801561218657600080fd5b505af115801561219a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121be919061437f565b506121c881613709565b6121d26000613771565b6122115760405162461bcd60e51b815260206004820152601060248201526f333ab9b29039ba34b63610313637bbb760811b6044820152606401610426565b612219613bf0565b505050565b6122266129ac565b6122425760405162461bcd60e51b815260040161042690614a32565b60a05481106122835760405162461bcd60e51b815260206004820152600d60248201526c092dcecc2d8d2c840d2dcc8caf609b1b6044820152606401610426565b600060a0828154811061229857612298614cf0565b60009182526020808320909101546001600160a01b03908116808452609f90925260409092205460a054919350909116906122d590600190614c50565b8310156123575760a080546122ec90600190614c50565b815481106122fc576122fc614cf0565b60009182526020909120015460a080546001600160a01b03909216918590811061232857612328614cf0565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505b60a080548061236857612368614cda565b60008281526020808220600019908401810180546001600160a01b031990811690915593019093556001600160a01b03858116808352609f855260409283902080549094169093559051908416815290917f16b7600acff27e39a8a96056b3d533045298de927507f5c1d97e4accde60488c910160405180910390a2505050565b6123f16129ac565b61240d5760405162461bcd60e51b815260040161042690614a32565b8060005b818110156124c057600084848381811061242d5761242d614cf0565b9050602002016020810190612442919061411e565b6001600160a01b031614156124b05760405162461bcd60e51b815260206004820152602e60248201527f43616e206e6f742073657420616e20656d70747920616464726573732061732060448201526d30903932bbb0b932103a37b5b2b760911b6064820152608401610426565b6124b981614c93565b9050612411565b507f04c0b9649497d316554306e53678d5f5f5dbc3a06f97dec13ff4cfe98b986bbc60a484846040516124f5939291906147e3565b60405180910390a1610ef760a48484613e77565b6125116129ac565b61252d5760405162461bcd60e51b815260040161042690614a32565b6040516001600160a01b03821681527f3329861a0008b3348767567d2405492b997abd79a088d0f2cef6b1a09a8e7ff79060200160405180910390a1603680546001600160a01b0319166001600160a01b0392909216919091179055565b60335460009061010090046001600160a01b031633146125bd5760405162461bcd60e51b815260040161042690614a93565b60335460ff16156125e05760405162461bcd60e51b815260040161042690614a69565b610bda6001613771565b6125f26129ac565b61260e5760405162461bcd60e51b815260040161042690614a32565b808210801561262557506801bc16d674ec80000082105b801561263957506801bc16d674ec80000081105b80156126565750673782dace9d9000006126538383614c50565b10155b6126a25760405162461bcd60e51b815260206004820152601760248201527f696e636f7272656374206675736520696e74657276616c0000000000000000006044820152606401610426565b60408051838152602081018390527fcb8d24e46eb3c402bf344ee60a6576cba9ef2f59ea1af3b311520704924e901a910160405180910390a1606991909155606a55565b60405163095ea7b360e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015260001960248301527f0000000000000000000000000000000000000000000000000000000000000000169063095ea7b390604401602060405180830381600087803b15801561277157600080fd5b505af1158015612785573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127a9919061437f565b50565b60335461010090046001600160a01b031633146127db5760405162461bcd60e51b815260040161042690614a93565b60335460ff16156127fe5760405162461bcd60e51b815260040161042690614a69565b6040516301ba3ee760e21b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906306e8fb9c90612858908b908b908b908b908b908b908b908b906004016148a2565b600060405180830381600087803b15801561287257600080fd5b505af1158015612886573d6000803e3d6000fd5b505050506000603560008a8a6040516128a09291906146ba565b60408051918290039091208252602082019290925201600020805460ff191660018360038111156128d3576128d3614cc4565b02179055507f75c4a66b2c6c28cf46db7131182a812e4fbbb2f0591377aa83a737909a9b68c38888888860405161290d949392919061487b565b60405180910390a15050505050505050565b6129276129ac565b6129435760405162461bcd60e51b815260040161042690614a32565b60a354604080516001600160a01b03928316815291831660208301527fe48386b84419f4d36e0f96c10cc3510b6fb1a33795620c5098b22472bbe90796910160405180910390a160a380546001600160a01b0319166001600160a01b0392909216919091179055565b60006129c4600080516020614d608339815191525490565b6001600160a01b0316336001600160a01b031614905090565b6129e56129ac565b612a015760405162461bcd60e51b815260040161042690614a32565b612a29817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b0316612a49600080516020614d608339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614612ac95760405162461bcd60e51b8152600401610426906149fb565b600080516020614d4083398151915280546002811415612afb5760405162461bcd60e51b815260040161042690614aca565b60028255612b0a858585613611565b5060019055505050565b60335461010090046001600160a01b03163314612b435760405162461bcd60e51b815260040161042690614a93565b60335460ff1615612b665760405162461bcd60e51b815260040161042690614a69565b6000603560008686604051612b7c9291906146ba565b604080519182900390912082526020820192909252016000205460ff1690506001816003811115612baf57612baf614cc4565b14612bf35760405162461bcd60e51b815260206004820152601460248201527315985b1a59185d1bdc881b9bdd081cdd185ad95960621b6044820152606401610426565b604051633877322b60e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690633877322b90612c4590889088908890889060040161487b565b600060405180830381600087803b158015612c5f57600080fd5b505af1158015612c73573d6000803e3d6000fd5b505050507ff8821da16f5ed966b41e0343c3eff9903af782d74f99f1689dd9d4562b6545b385858585604051612cac949392919061487b565b60405180910390a16002603560008787604051612cca9291906146ba565b60408051918290039091208252602082019290925201600020805460ff19166001836003811115612cfd57612cfd614cc4565b02179055505050505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614612d515760405162461bcd60e51b8152600401610426906149fb565b600080516020614d4083398151915280546002811415612d835760405162461bcd60e51b815260040161042690614aca565b600282556040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b158015612de957600080fd5b505afa158015612dfd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e219190614581565b905060006101075482612e349190614c50565b90508015612e6c57610107829055612e6c7f0000000000000000000000000000000000000000000000000000000000000000826131ce565b5050600182555050565b6036546001600160a01b03163314612ed05760405162461bcd60e51b815260206004820152601960248201527f43616c6c6572206973206e6f7420746865204d6f6e69746f72000000000000006044820152606401610426565b6040517fe765a88a37047c5d793dce22b9ceb5a0f5039d276da139b4c7d29613f341f11090600090a16000603855565b606060a4805480602002602001604051908101604052809291908181526020018280548015612f5857602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612f3a575b5050505050905090565b6001600160a01b038281166000908152609f60205260409020541615612fbf5760405162461bcd60e51b81526020600482015260126024820152711c151bdad95b88185b1c9958591e481cd95d60721b6044820152606401610426565b6001600160a01b03821615801590612fdf57506001600160a01b03811615155b61301f5760405162461bcd60e51b8152602060048201526011602482015270496e76616c69642061646472657373657360781b6044820152606401610426565b6001600160a01b038281166000818152609f6020908152604080832080549587166001600160a01b0319968716811790915560a0805460018101825594527f78fdc8d422c49ced035a9edf18d00d3c6a8d81df210f3e5e448e045e77b41e8890930180549095168417909455925190815290917fef6485b84315f9b1483beffa32aae9a0596890395e3d7521f1c5fbb51790e765910160405180910390a25050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052612219908490613c6a565b82516131269060a4906020860190613eda565b508151815181146131705760405162461bcd60e51b8152602060048201526014602482015273496e76616c696420696e7075742061727261797360601b6044820152606401610426565b60005b818110156131c7576131b784828151811061319057613190614cf0565b60200260200101518483815181106131aa576131aa614cf0565b6020026020010151612f62565b6131c081614c93565b9050613173565b5050505050565b600081116132175760405162461bcd60e51b81526020600482015260166024820152754d757374206465706f73697420736f6d657468696e6760501b6044820152606401610426565b6040805160008152602081018390526001600160a01b038416917f5548c837ab068cf56a2c2479df0882a4922fd203edb7517321831d95078c5f62910160405180910390a25050565b60335460ff16156132835760405162461bcd60e51b815260040161042690614a69565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663e52253816040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156132e057600080fd5b505af11580156132f4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133189190614581565b905060006068548261332a9190614c19565b90508047101561337c5760405162461bcd60e51b815260206004820152601860248201527f696e73756666696369656e74206574682062616c616e636500000000000000006044820152606401610426565b8015610c0d5760006068819055507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b1580156133e557600080fd5b505af11580156133f9573d6000803e3d6000fd5b505060a354604080516001600160a01b0392831681527f0000000000000000000000000000000000000000000000000000000000000000909216602083015281018590527ff6c07a063ed4e63808eb8da7112d46dbcd38de2b40a73dbcc9353c5a94c723539350606001915061346c9050565b60405180910390a160a354610c0d906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081169116836130c1565b6001600160a01b0381166135045760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f7220697320616464726573732830290000000000006044820152606401610426565b806001600160a01b0316613524600080516020614d608339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a36127a981600080516020614d6083398151915255565b600061357e8261010754613d3c565b90508061010760008282546135939190614c50565b90915550505050565b60335460ff16156135bf5760405162461bcd60e51b815260040161042690614a69565b6033805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586135f43390565b6040516001600160a01b03909116815260200160405180910390a1565b600081116136615760405162461bcd60e51b815260206004820152601760248201527f4d75737420776974686472617720736f6d657468696e670000000000000000006044820152606401610426565b6001600160a01b0383166136b05760405162461bcd60e51b8152602060048201526016602482015275135d5cdd081cdc1958da599e481c9958da5c1a595b9d60521b6044820152606401610426565b6040805160008152602081018390526001600160a01b038416917f2717ead6b9200dd235aad468c9809ea400fe33ac69b5bfaa6d3e90fc922b6398910160405180910390a26122196001600160a01b03831684836130c1565b6040805160008152602081018390526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016917f2717ead6b9200dd235aad468c9809ea400fe33ac69b5bfaa6d3e90fc922b6398910160405180910390a250565b6000606854471015613786576112eb82613d54565b6000606854476137969190614c50565b9050600191506801bc16d674ec80000081106139735760006801bc16d674ec8000008204905080603460008282546137ce9190614c50565b90915550600090506137e9826801bc16d674ec800000614c31565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b15801561384657600080fd5b505af115801561385a573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb92506044019050602060405180830381600087803b1580156138ea57600080fd5b505af11580156138fe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613922919061437f565b5061392c81613709565b60345460408051848152602081019290925281018290527fbe7040030ff7b347853214bf49820c6d455fedf58f3815f85c7bc5216993682b9060600160405180910390a150505b6000606854476139839190614c50565b90506801bc16d674ec80000081106139d55760405162461bcd60e51b8152602060048201526015602482015274756e6578706563746564206163636f756e74696e6760581b6044820152606401610426565b806139e1575050919050565b606954811015613a3b5780606860008282546139fd9190614c19565b90915550506040518181527f7a745a2c63a535068f52ceca27debd5297bbad5f7f37ec53d044a59d0362445d906020015b60405180910390a1613be9565b606a54811115613bd8577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b158015613aa057600080fd5b505af1158015613ab4573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb92506044019050602060405180830381600087803b158015613b4457600080fd5b505af1158015613b58573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b7c919061437f565b50600160346000828254613b909190614c50565b90915550613b9f905081613709565b60345460408051918252602082018390527f6aa7e30787b26429ced603a7aba8b19c4b5d5bcf29a3257da953c8d53bcaa3a69101613a2e565b613be184613d54565b949350505050565b5050919050565b60335460ff16613c395760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610426565b6033805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa336135f4565b6000613cbf826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316613d6c9092919063ffffffff16565b8051909150156122195780806020019051810190613cdd919061437f565b6122195760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610426565b6000818310613d4b5781613d4d565b825b9392505050565b60008115613d6457613d6461359c565b506000919050565b6060613be1848460008585843b613dc55760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610426565b600080866001600160a01b03168587604051613de191906146ca565b60006040518083038185875af1925050503d8060008114613e1e576040519150601f19603f3d011682016040523d82523d6000602084013e613e23565b606091505b5091509150613e33828286613e3e565b979650505050505050565b60608315613e4d575081613d4d565b825115613e5d5782518084602001fd5b8160405162461bcd60e51b815260040161042691906149e8565b828054828255906000526020600020908101928215613eca579160200282015b82811115613eca5781546001600160a01b0319166001600160a01b03843516178255602090920191600190910190613e97565b50613ed6929150613f2f565b5090565b828054828255906000526020600020908101928215613eca579160200282015b82811115613eca57825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190613efa565b5b80821115613ed65760008155600101613f30565b60008083601f840112613f5657600080fd5b5081356001600160401b03811115613f6d57600080fd5b6020830191508360208260051b8501011115613f8857600080fd5b9250929050565b600082601f830112613fa057600080fd5b81356020613fb5613fb083614bb5565b614b85565b80838252828201915082860187848660051b8901011115613fd557600080fd5b60005b85811015613ffd578135613feb81614d1c565b84529284019290840190600101613fd8565b5090979650505050505050565b60008083601f84011261401c57600080fd5b5081356001600160401b0381111561403357600080fd5b602083019150836020828501011115613f8857600080fd5b600060a0828403121561405d57600080fd5b50919050565b600060a0828403121561407557600080fd5b60405160a081018181106001600160401b038211171561409757614097614d06565b6040529050806140a6836140ee565b81526140b460208401614107565b60208201526140c560408401614107565b604082015260608301356140d881614d31565b6060820152608092830135920191909152919050565b803563ffffffff8116811461410257600080fd5b919050565b80356001600160401b038116811461410257600080fd5b60006020828403121561413057600080fd5b8135613d4d81614d1c565b60006020828403121561414d57600080fd5b8151613d4d81614d1c565b6000806040838503121561416b57600080fd5b823561417681614d1c565b9150602083013561418681614d1c565b809150509250929050565b6000806000606084860312156141a657600080fd5b83356141b181614d1c565b925060208401356141c181614d1c565b929592945050506040919091013590565b600080604083850312156141e557600080fd5b82356141f081614d1c565b946020939093013593505050565b6000806020838503121561421157600080fd5b82356001600160401b0381111561422757600080fd5b61423385828601613f44565b90969095509350505050565b60008060006060848603121561425457600080fd5b83356001600160401b038082111561426b57600080fd5b61427787838801613f8f565b9450602086013591508082111561428d57600080fd5b61429987838801613f8f565b935060408601359150808211156142af57600080fd5b506142bc86828701613f8f565b9150509250925092565b600080600060e084860312156142db57600080fd5b83356001600160401b038111156142f157600080fd5b8401601f8101861361430257600080fd5b80356020614312613fb083614bb5565b8083825282820191508285018a848660051b880101111561433257600080fd5b600095505b8486101561435c5761434881614107565b835260019590950194918301918301614337565b509650508601359350614376915086905060408601614063565b90509250925092565b60006020828403121561439157600080fd5b8151613d4d81614d31565b6000602082840312156143ae57600080fd5b5035919050565b600080600080604085870312156143cb57600080fd5b84356001600160401b03808211156143e257600080fd5b6143ee8883890161400a565b9096509450602087013591508082111561440757600080fd5b5061441487828801613f44565b95989497509550505050565b600080600080600080600080610120898b03121561443d57600080fd5b88356001600160401b038082111561445457600080fd5b6144608c838d0161400a565b909a50985060208b013591508082111561447957600080fd5b6144858c838d01613f44565b909850965060408b013591508082111561449e57600080fd5b506144ab8b828c0161400a565b909550935050606089013591506144c58a60808b0161404b565b90509295985092959890939650565b600080600080600060e086880312156144ec57600080fd5b85356001600160401b038082111561450357600080fd5b61450f89838a0161400a565b9097509550602088013591508082111561452857600080fd5b5061453588828901613f44565b90945092506145499050876040880161404b565b90509295509295909350565b60008060006060848603121561456a57600080fd5b505081359360208301359350604090920135919050565b60006020828403121561459357600080fd5b5051919050565b600080604083850312156145ad57600080fd5b50508035926020909101359150565b8183526000602080850194508260005b858110156145f8576001600160401b036145e583614107565b16875295820195908201906001016145cc565b509495945050505050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b60008151808452614644816020860160208601614c67565b601f01601f19169290920160200192915050565b63ffffffff614666826140ee565b16825261467560208201614107565b6001600160401b0380821660208501528061469260408501614107565b166040850152505060608101356146a881614d31565b15156060830152608090810135910152565b8183823760009101908152919050565b600082516146dc818460208701614c67565b9190910192915050565b6001600160a01b03851681526101006020808301829052855191830182905260009161012084019187810191845b818110156147395783516001600160401b031685529382019392820192600101614714565b505082935086604086015263ffffffff865116606086015280860151925050506001600160401b0380821660808501528060408601511660a085015250506060830151151560c0830152608083015160e083015295945050505050565b6020808252825182820181905260009190848201906040850190845b818110156147d75783516001600160a01b0316835292840192918401916001016147b2565b50909695505050505050565b6000604082016040835280865480835260608501915087600052602092508260002060005b8281101561482d5781546001600160a01b031684529284019260019182019101614808565b505050838103828501528481528590820160005b8681101561486f57823561485481614d1c565b6001600160a01b031682529183019190830190600101614841565b50979650505050505050565b60408152600061488f604083018688614603565b8281036020840152613e338185876145bc565b60006101208083526148b78184018b8d614603565b905082810360208401526148cc81898b6145bc565b905082810360408401526148e1818789614603565b9150508360608301526148f76080830184614658565b9998505050505050505050565b60e08152600061491860e083018789614603565b828103602084015261492b8186886145bc565b91505061493b6040830184614658565b9695505050505050565b60808152600061495960808301888a614603565b828103602084015261496b818861462c565b90508281036040840152614980818688614603565b915050826060830152979650505050505050565b6060815260006149a8606083018688614603565b8460208401528281036040840152613e33818561462c565b60208101600483106149e257634e487b7160e01b600052602160045260246000fd5b91905290565b602081526000613d4d602083018461462c565b60208082526017908201527f43616c6c6572206973206e6f7420746865205661756c74000000000000000000604082015260600190565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b60208082526010908201526f14185d5cd8589b194e881c185d5cd95960821b604082015260600190565b6020808252601d908201527f43616c6c6572206973206e6f7420746865205265676973747261746f72000000604082015260600190565b6020808252600e908201526d1499595b9d1c985b9d0818d85b1b60921b604082015260600190565b6020808252601c908201527f43616c6c6572206973206e6f7420746865205374726174656769737400000000604082015260600190565b6000808335601e19843603018112614b4057600080fd5b8301803591506001600160401b03821115614b5a57600080fd5b602001915036819003821315613f8857600080fd5b60008235605e198336030181126146dc57600080fd5b604051601f8201601f191681016001600160401b0381118282101715614bad57614bad614d06565b604052919050565b60006001600160401b03821115614bce57614bce614d06565b5060051b60200190565b600080821280156001600160ff1b0384900385131615614bfa57614bfa614cae565b600160ff1b8390038412811615614c1357614c13614cae565b50500190565b60008219821115614c2c57614c2c614cae565b500190565b6000816000190483118215151615614c4b57614c4b614cae565b500290565b600082821015614c6257614c62614cae565b500390565b60005b83811015614c82578181015183820152602001614c6a565b83811115610ef75750506000910152565b6000600019821415614ca757614ca7614cae565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b03811681146127a957600080fd5b80151581146127a957600080fdfe53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac45357bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa264697066735822122036fc9aa0014d1fbbc8fbac98689c50c4cc2fb4601ee35cd2b4f5b5f97319fc4864736f6c634300080700337bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a", + "deployedBytecode": "0x60806040526004361061037a5760003560e01c8063853828b6116101d1578063c7af335211610102578063dbe55e56116100a0578063e75292391161006f578063e752923914610b41578063ee7afe2d14610b57578063f1188e4014610b6c578063f6ca71b014610ba057600080fd5b8063dbe55e5614610aae578063dd505df614610ae2578063de34d71314610b16578063de5f626814610b2c57600080fd5b8063d059f6ef116100dc578063d059f6ef14610a37578063d38bfff414610a4e578063d9caed1214610a6e578063d9f00ec714610a8e57600080fd5b8063c7af3352146109d1578063c98517c5146109e6578063cceab75014610a0357600080fd5b8063a3b81e731161016f578063ab12edf511610149578063ab12edf51461095c578063ad1728cb1461097c578063bb1b918d14610991578063c2e1e3f4146109b157600080fd5b8063a3b81e73146108da578063a4f98af4146108fa578063aa388af61461090f57600080fd5b80639092c31c116101ab5780639092c31c146108295780639136616a1461085d57806396d538bb1461087d5780639da0e4621461089d57600080fd5b8063853828b6146107cf57806387bae867146107e45780638d7c0e461461080957600080fd5b80635d36b190116102ab5780636ef38795116102495780637b2d9b2c116102235780637b2d9b2c1461076e5780637b8962f71461078e578063842f5c46146107a45780638456cb59146107ba57600080fd5b80636ef387951461070e57806371a735f31461072e5780637260f8261461074e57600080fd5b8063630923831161028557806363092383146106a257806366e3667e146106b857806367c7066c146106ce5780636e811d38146106ee57600080fd5b80635d36b190146106395780635f5152261461064e5780636093d3801461066e57600080fd5b8063435356d1116103185780635205c380116102f25780635205c380146105ac578063579a7e1a146105cc5780635a063f63146106005780635c975abb1461061557600080fd5b8063435356d11461055657806347e7ef2414610576578063484be8121461059657600080fd5b80631072cbea116103545780631072cbea146104be57806322495dc8146104de5780633c864959146104fe578063430bf08a1461052257600080fd5b80630c340a24146104365780630ed57b3a146104685780630fc3b4c41461048857600080fd5b3661043157336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614806103de5750336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016145b61042f5760405162461bcd60e51b815260206004820152601e60248201527f657468206e6f742066726f6d20616c6c6f77656420636f6e747261637473000060448201526064015b60405180910390fd5b005b600080fd5b34801561044257600080fd5b5061044b610bc2565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561047457600080fd5b5061042f610483366004614158565b610bdf565b34801561049457600080fd5b5061044b6104a336600461411e565b609f602052600090815260409020546001600160a01b031681565b3480156104ca57600080fd5b5061042f6104d93660046141d2565b610c11565b3480156104ea57600080fd5b5061042f6104f93660046142c6565b610cce565b34801561050a57600080fd5b5061051460695481565b60405190815260200161045f565b34801561052e57600080fd5b5061044b7f000000000000000000000000000000000000000000000000000000000000000081565b34801561056257600080fd5b5061042f61057136600461423f565b610e18565b34801561058257600080fd5b5061042f6105913660046141d2565b610efd565b3480156105a257600080fd5b50610514606a5481565b3480156105b857600080fd5b5061042f6105c736600461439c565b61101c565b3480156105d857600080fd5b5061044b7f000000000000000000000000000000000000000000000000000000000000000081565b34801561060c57600080fd5b5061042f611078565b34801561062157600080fd5b5060335460ff165b604051901515815260200161045f565b34801561064557600080fd5b5061042f611117565b34801561065a57600080fd5b5061051461066936600461411e565b6111bd565b34801561067a57600080fd5b5061044b7f000000000000000000000000000000000000000000000000000000000000000081565b3480156106ae57600080fd5b50610514611c2081565b3480156106c457600080fd5b5061051460345481565b3480156106da57600080fd5b5060a35461044b906001600160a01b031681565b3480156106fa57600080fd5b5061042f61070936600461411e565b6112f1565b34801561071a57600080fd5b5061042f6107293660046141fe565b611379565b34801561073a57600080fd5b5061042f6107493660046144d4565b61188b565b34801561075a57600080fd5b5060365461044b906001600160a01b031681565b34801561077a57600080fd5b5061044b61078936600461439c565b611a84565b34801561079a57600080fd5b5061051460375481565b3480156107b057600080fd5b5061051460685481565b3480156107c657600080fd5b5061042f611aae565b3480156107db57600080fd5b5061042f611b77565b3480156107f057600080fd5b5060335461044b9061010090046001600160a01b031681565b34801561081557600080fd5b5061042f610824366004614555565b611d49565b34801561083557600080fd5b5061044b7f000000000000000000000000000000000000000000000000000000000000000081565b34801561086957600080fd5b5061042f61087836600461439c565b61221e565b34801561088957600080fd5b5061042f6108983660046141fe565b6123e9565b3480156108a957600080fd5b506108cd6108b836600461439c565b60356020526000908152604090205460ff1681565b60405161045f91906149c0565b3480156108e657600080fd5b5061042f6108f536600461411e565b612509565b34801561090657600080fd5b5061062961258b565b34801561091b57600080fd5b5061062961092a36600461411e565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0390811691161490565b34801561096857600080fd5b5061042f61097736600461459a565b6125ea565b34801561098857600080fd5b5061042f6126e6565b34801561099d57600080fd5b5061042f6109ac366004614420565b6127ac565b3480156109bd57600080fd5b5061042f6109cc36600461411e565b61291f565b3480156109dd57600080fd5b506106296129ac565b3480156109f257600080fd5b506105146801bc16d674ec80000081565b348015610a0f57600080fd5b5061044b7f000000000000000000000000000000000000000000000000000000000000000081565b348015610a4357600080fd5b506105146101075481565b348015610a5a57600080fd5b5061042f610a6936600461411e565b6129dd565b348015610a7a57600080fd5b5061042f610a89366004614191565b612a81565b348015610a9a57600080fd5b5061042f610aa93660046143b5565b612b14565b348015610aba57600080fd5b5061044b7f000000000000000000000000000000000000000000000000000000000000000081565b348015610aee57600080fd5b5061044b7f000000000000000000000000000000000000000000000000000000000000000081565b348015610b2257600080fd5b5061051460385481565b348015610b3857600080fd5b5061042f612d09565b348015610b4d57600080fd5b50610514606b5481565b348015610b6357600080fd5b5061042f612e76565b348015610b7857600080fd5b5061044b7f000000000000000000000000000000000000000000000000000000000000000081565b348015610bac57600080fd5b50610bb5612f00565b60405161045f9190614796565b6000610bda600080516020614d608339815191525490565b905090565b610be76129ac565b610c035760405162461bcd60e51b815260040161042690614a32565b610c0d8282612f62565b5050565b610c196129ac565b610c355760405162461bcd60e51b815260040161042690614a32565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b039081169083161415610cb25760405162461bcd60e51b815260206004820152601f60248201527f43616e6e6f74207472616e7366657220737570706f72746564206173736574006044820152606401610426565b610c0d610cbd610bc2565b6001600160a01b03841690836130c1565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b158015610d2757600080fd5b505afa158015610d3b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d5f919061413b565b6001600160a01b0316336001600160a01b031614610d8f5760405162461bcd60e51b815260040161042690614af2565b60405163bc26e7e560e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063bc26e7e590610de19030908790879087906004016146e6565b600060405180830381600087803b158015610dfb57600080fd5b505af1158015610e0f573d6000803e3d6000fd5b50505050505050565b610e206129ac565b610e3c5760405162461bcd60e51b815260040161042690614a32565b600054610100900460ff1680610e55575060005460ff16155b610eb85760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610426565b600054610100900460ff16158015610eda576000805461ffff19166101011790555b610ee5848484613113565b8015610ef7576000805461ff00191690555b50505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610f455760405162461bcd60e51b8152600401610426906149fb565b600080516020614d4083398151915280546002811415610f775760405162461bcd60e51b815260040161042690614aca565b600282557f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316846001600160a01b031614610ff05760405162461bcd60e51b8152602060048201526011602482015270155b9cdd5c1c1bdc9d195908185cdcd95d607a1b6044820152606401610426565b8261010760008282546110039190614c19565b90915550611013905084846131ce565b50600190555050565b6110246129ac565b6110405760405162461bcd60e51b815260040161042690614a32565b6040518181527fe26b067424903962f951f568e52ec9a3bbe1589526ea54a4e69ca6eaae1a4c779060200160405180910390a1603755565b60a3546001600160a01b031633146110d25760405162461bcd60e51b815260206004820152601b60248201527f43616c6c6572206973206e6f74207468652048617276657374657200000000006044820152606401610426565b600080516020614d40833981519152805460028114156111045760405162461bcd60e51b815260040161042690614aca565b60028255611110613260565b5060019055565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b0316146111b25760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b6064820152608401610426565b6111bb336134ae565b565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b0316146112345760405162461bcd60e51b8152602060048201526011602482015270155b9cdd5c1c1bdc9d195908185cdcd95d607a1b6044820152606401610426565b6040516370a0823160e01b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b15801561129357600080fd5b505afa1580156112a7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112cb9190614581565b6034546112e1906801bc16d674ec800000614c31565b6112eb9190614c19565b92915050565b6112f96129ac565b6113155760405162461bcd60e51b815260040161042690614a32565b6040516001600160a01b03821681527f83f29c79feb71f8fba9d0fbc4ba5f0982a28b6b1e868b3fc50e6400d100bca0f9060200160405180910390a1603380546001600160a01b0390921661010002610100600160a81b0319909216919091179055565b60335461010090046001600160a01b031633146113a85760405162461bcd60e51b815260040161042690614a93565b60335460ff16156113cb5760405162461bcd60e51b815260040161042690614a69565b60006113e0826801bc16d674ec800000614c31565b6040516370a0823160e01b81523060048201529091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b15801561144257600080fd5b505afa158015611456573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061147a9190614581565b8111156114bd5760405162461bcd60e51b81526020600482015260116024820152700d2dce6eaccccd2c6d2cadce840ae8aa89607b1b6044820152606401610426565b603754816038546114ce9190614c19565b111561151c5760405162461bcd60e51b815260206004820152601a60248201527f5374616b696e6720455448206f766572207468726573686f6c640000000000006044820152606401610426565b806038600082825461152e9190614c19565b9091555050604051632e1a7d4d60e01b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561159557600080fd5b505af11580156115a9573d6000803e3d6000fd5b505050506115b68161356f565b60408051600160f81b60208201526000602182018190526bffffffffffffffffffffffff193060601b16602c830152910160408051601f1981840301815291905290508260005b8181101561186c57600086868381811061161957611619614cf0565b905060200281019061162b9190614b6f565b6116359080614b29565b6040516116439291906146ba565b6040805191829003909120600081815260356020529182205490925060ff169081600381111561167557611675614cc4565b146116c25760405162461bcd60e51b815260206004820152601860248201527f56616c696461746f72206e6f74207265676973746572656400000000000000006044820152606401610426565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663228951186801bc16d674ec8000008a8a8781811061170d5761170d614cf0565b905060200281019061171f9190614b6f565b6117299080614b29565b898d8d8a81811061173c5761173c614cf0565b905060200281019061174e9190614b6f565b61175c906020810190614b29565b8f8f8c81811061176e5761176e614cf0565b90506020028101906117809190614b6f565b604001356040518863ffffffff1660e01b81526004016117a596959493929190614945565b6000604051808303818588803b1580156117be57600080fd5b505af11580156117d2573d6000803e3d6000fd5b50505050507ffeb31a79d38edb1b090d516e4df3e273651179c6f2c2ec53a9a22ae015b70ba988888581811061180a5761180a614cf0565b905060200281019061181c9190614b6f565b6118269080614b29565b6801bc16d674ec800000886040516118419493929190614994565b60405180910390a1506000908152603560205260409020805460ff19166001908117909155016115fd565b50806034600082825461187f9190614c19565b90915550505050505050565b60335461010090046001600160a01b031633146118ba5760405162461bcd60e51b815260040161042690614a93565b60335460ff16156118dd5760405162461bcd60e51b815260040161042690614a69565b60006035600087876040516118f39291906146ba565b604080519182900390912082526020820192909252016000205460ff169050600281600381111561192657611926614cc4565b1461196b5760405162461bcd60e51b815260206004820152601560248201527456616c696461746f72206e6f742065786974696e6760581b6044820152606401610426565b6040516312b3fc1960e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906312b3fc19906119bf9089908990899089908990600401614904565b600060405180830381600087803b1580156119d957600080fd5b505af11580156119ed573d6000803e3d6000fd5b505050507ff72821b8777f002ccdf6326f1242d9e0f762eb077668b67bebe640535378066d86868686604051611a26949392919061487b565b60405180910390a16003603560008888604051611a449291906146ba565b60408051918290039091208252602082019290925201600020805460ff19166001836003811115611a7757611a77614cc4565b0217905550505050505050565b60a48181548110611a9457600080fd5b6000918252602090912001546001600160a01b0316905081565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b158015611b0757600080fd5b505afa158015611b1b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b3f919061413b565b6001600160a01b0316336001600160a01b031614611b6f5760405162461bcd60e51b815260040161042690614af2565b6111bb61359c565b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161480611bc65750611bb1610bc2565b6001600160a01b0316336001600160a01b0316145b611c1e5760405162461bcd60e51b815260206004820152602360248201527f43616c6c6572206973206e6f7420746865205661756c74206f7220476f7665726044820152623737b960e91b6064820152608401610426565b600080516020614d4083398151915280546002811415611c505760405162461bcd60e51b815260040161042690614aca565b600282556040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b158015611cb657600080fd5b505afa158015611cca573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cee9190614581565b90508015611d4157611d417f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000083613611565b505060019055565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b158015611da257600080fd5b505afa158015611db6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dda919061413b565b6001600160a01b0316336001600160a01b031614611e0a5760405162461bcd60e51b815260040161042690614af2565b60335460ff16611e535760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610426565b43611c20606b54611e649190614c19565b10611ebf5760405162461bcd60e51b815260206004820152602560248201527f6d616e75616c6c794669784163636f756e74696e672063616c6c656420746f6f6044820152641039b7b7b760d91b6064820152608401610426565b6002198312158015611ed2575060038313155b8015611eec5750600083603454611ee99190614bd8565b12155b611f385760405162461bcd60e51b815260206004820152601760248201527f696e76616c69642076616c696461746f727344656c74610000000000000000006044820152606401610426565b6811ff6cf0fd15afffff198212158015611f5b57506811ff6cf0fd15b000008213155b8015611f755750600082606854611f729190614bd8565b12155b611fc15760405162461bcd60e51b815260206004820152601d60248201527f696e76616c696420636f6e73656e7375735265776172647344656c74610000006044820152606401610426565b68053444835ec580000081111561201a5760405162461bcd60e51b815260206004820152601960248201527f696e76616c69642077657468546f5661756c74416d6f756e74000000000000006044820152606401610426565b60408051848152602081018490529081018290527f80d022717ea022455c5886b8dd8a29c037570aae58aeb4d7b136d7a10ec2e4319060600160405180910390a1826034546120699190614bd8565b60345560685461207a908390614bd8565b60685543606b5580156121c8577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b1580156120e257600080fd5b505af11580156120f6573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb92506044019050602060405180830381600087803b15801561218657600080fd5b505af115801561219a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121be919061437f565b506121c881613709565b6121d26000613771565b6122115760405162461bcd60e51b815260206004820152601060248201526f333ab9b29039ba34b63610313637bbb760811b6044820152606401610426565b612219613bf0565b505050565b6122266129ac565b6122425760405162461bcd60e51b815260040161042690614a32565b60a05481106122835760405162461bcd60e51b815260206004820152600d60248201526c092dcecc2d8d2c840d2dcc8caf609b1b6044820152606401610426565b600060a0828154811061229857612298614cf0565b60009182526020808320909101546001600160a01b03908116808452609f90925260409092205460a054919350909116906122d590600190614c50565b8310156123575760a080546122ec90600190614c50565b815481106122fc576122fc614cf0565b60009182526020909120015460a080546001600160a01b03909216918590811061232857612328614cf0565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505b60a080548061236857612368614cda565b60008281526020808220600019908401810180546001600160a01b031990811690915593019093556001600160a01b03858116808352609f855260409283902080549094169093559051908416815290917f16b7600acff27e39a8a96056b3d533045298de927507f5c1d97e4accde60488c910160405180910390a2505050565b6123f16129ac565b61240d5760405162461bcd60e51b815260040161042690614a32565b8060005b818110156124c057600084848381811061242d5761242d614cf0565b9050602002016020810190612442919061411e565b6001600160a01b031614156124b05760405162461bcd60e51b815260206004820152602e60248201527f43616e206e6f742073657420616e20656d70747920616464726573732061732060448201526d30903932bbb0b932103a37b5b2b760911b6064820152608401610426565b6124b981614c93565b9050612411565b507f04c0b9649497d316554306e53678d5f5f5dbc3a06f97dec13ff4cfe98b986bbc60a484846040516124f5939291906147e3565b60405180910390a1610ef760a48484613e77565b6125116129ac565b61252d5760405162461bcd60e51b815260040161042690614a32565b6040516001600160a01b03821681527f3329861a0008b3348767567d2405492b997abd79a088d0f2cef6b1a09a8e7ff79060200160405180910390a1603680546001600160a01b0319166001600160a01b0392909216919091179055565b60335460009061010090046001600160a01b031633146125bd5760405162461bcd60e51b815260040161042690614a93565b60335460ff16156125e05760405162461bcd60e51b815260040161042690614a69565b610bda6001613771565b6125f26129ac565b61260e5760405162461bcd60e51b815260040161042690614a32565b808210801561262557506801bc16d674ec80000082105b801561263957506801bc16d674ec80000081105b80156126565750673782dace9d9000006126538383614c50565b10155b6126a25760405162461bcd60e51b815260206004820152601760248201527f696e636f7272656374206675736520696e74657276616c0000000000000000006044820152606401610426565b60408051838152602081018390527fcb8d24e46eb3c402bf344ee60a6576cba9ef2f59ea1af3b311520704924e901a910160405180910390a1606991909155606a55565b60405163095ea7b360e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015260001960248301527f0000000000000000000000000000000000000000000000000000000000000000169063095ea7b390604401602060405180830381600087803b15801561277157600080fd5b505af1158015612785573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127a9919061437f565b50565b60335461010090046001600160a01b031633146127db5760405162461bcd60e51b815260040161042690614a93565b60335460ff16156127fe5760405162461bcd60e51b815260040161042690614a69565b6040516301ba3ee760e21b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906306e8fb9c90612858908b908b908b908b908b908b908b908b906004016148a2565b600060405180830381600087803b15801561287257600080fd5b505af1158015612886573d6000803e3d6000fd5b505050506000603560008a8a6040516128a09291906146ba565b60408051918290039091208252602082019290925201600020805460ff191660018360038111156128d3576128d3614cc4565b02179055507f75c4a66b2c6c28cf46db7131182a812e4fbbb2f0591377aa83a737909a9b68c38888888860405161290d949392919061487b565b60405180910390a15050505050505050565b6129276129ac565b6129435760405162461bcd60e51b815260040161042690614a32565b60a354604080516001600160a01b03928316815291831660208301527fe48386b84419f4d36e0f96c10cc3510b6fb1a33795620c5098b22472bbe90796910160405180910390a160a380546001600160a01b0319166001600160a01b0392909216919091179055565b60006129c4600080516020614d608339815191525490565b6001600160a01b0316336001600160a01b031614905090565b6129e56129ac565b612a015760405162461bcd60e51b815260040161042690614a32565b612a29817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b0316612a49600080516020614d608339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614612ac95760405162461bcd60e51b8152600401610426906149fb565b600080516020614d4083398151915280546002811415612afb5760405162461bcd60e51b815260040161042690614aca565b60028255612b0a858585613611565b5060019055505050565b60335461010090046001600160a01b03163314612b435760405162461bcd60e51b815260040161042690614a93565b60335460ff1615612b665760405162461bcd60e51b815260040161042690614a69565b6000603560008686604051612b7c9291906146ba565b604080519182900390912082526020820192909252016000205460ff1690506001816003811115612baf57612baf614cc4565b14612bf35760405162461bcd60e51b815260206004820152601460248201527315985b1a59185d1bdc881b9bdd081cdd185ad95960621b6044820152606401610426565b604051633877322b60e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690633877322b90612c4590889088908890889060040161487b565b600060405180830381600087803b158015612c5f57600080fd5b505af1158015612c73573d6000803e3d6000fd5b505050507ff8821da16f5ed966b41e0343c3eff9903af782d74f99f1689dd9d4562b6545b385858585604051612cac949392919061487b565b60405180910390a16002603560008787604051612cca9291906146ba565b60408051918290039091208252602082019290925201600020805460ff19166001836003811115612cfd57612cfd614cc4565b02179055505050505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614612d515760405162461bcd60e51b8152600401610426906149fb565b600080516020614d4083398151915280546002811415612d835760405162461bcd60e51b815260040161042690614aca565b600282556040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b158015612de957600080fd5b505afa158015612dfd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e219190614581565b905060006101075482612e349190614c50565b90508015612e6c57610107829055612e6c7f0000000000000000000000000000000000000000000000000000000000000000826131ce565b5050600182555050565b6036546001600160a01b03163314612ed05760405162461bcd60e51b815260206004820152601960248201527f43616c6c6572206973206e6f7420746865204d6f6e69746f72000000000000006044820152606401610426565b6040517fe765a88a37047c5d793dce22b9ceb5a0f5039d276da139b4c7d29613f341f11090600090a16000603855565b606060a4805480602002602001604051908101604052809291908181526020018280548015612f5857602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612f3a575b5050505050905090565b6001600160a01b038281166000908152609f60205260409020541615612fbf5760405162461bcd60e51b81526020600482015260126024820152711c151bdad95b88185b1c9958591e481cd95d60721b6044820152606401610426565b6001600160a01b03821615801590612fdf57506001600160a01b03811615155b61301f5760405162461bcd60e51b8152602060048201526011602482015270496e76616c69642061646472657373657360781b6044820152606401610426565b6001600160a01b038281166000818152609f6020908152604080832080549587166001600160a01b0319968716811790915560a0805460018101825594527f78fdc8d422c49ced035a9edf18d00d3c6a8d81df210f3e5e448e045e77b41e8890930180549095168417909455925190815290917fef6485b84315f9b1483beffa32aae9a0596890395e3d7521f1c5fbb51790e765910160405180910390a25050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052612219908490613c6a565b82516131269060a4906020860190613eda565b508151815181146131705760405162461bcd60e51b8152602060048201526014602482015273496e76616c696420696e7075742061727261797360601b6044820152606401610426565b60005b818110156131c7576131b784828151811061319057613190614cf0565b60200260200101518483815181106131aa576131aa614cf0565b6020026020010151612f62565b6131c081614c93565b9050613173565b5050505050565b600081116132175760405162461bcd60e51b81526020600482015260166024820152754d757374206465706f73697420736f6d657468696e6760501b6044820152606401610426565b6040805160008152602081018390526001600160a01b038416917f5548c837ab068cf56a2c2479df0882a4922fd203edb7517321831d95078c5f62910160405180910390a25050565b60335460ff16156132835760405162461bcd60e51b815260040161042690614a69565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663e52253816040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156132e057600080fd5b505af11580156132f4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133189190614581565b905060006068548261332a9190614c19565b90508047101561337c5760405162461bcd60e51b815260206004820152601860248201527f696e73756666696369656e74206574682062616c616e636500000000000000006044820152606401610426565b8015610c0d5760006068819055507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b1580156133e557600080fd5b505af11580156133f9573d6000803e3d6000fd5b505060a354604080516001600160a01b0392831681527f0000000000000000000000000000000000000000000000000000000000000000909216602083015281018590527ff6c07a063ed4e63808eb8da7112d46dbcd38de2b40a73dbcc9353c5a94c723539350606001915061346c9050565b60405180910390a160a354610c0d906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081169116836130c1565b6001600160a01b0381166135045760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f7220697320616464726573732830290000000000006044820152606401610426565b806001600160a01b0316613524600080516020614d608339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a36127a981600080516020614d6083398151915255565b600061357e8261010754613d3c565b90508061010760008282546135939190614c50565b90915550505050565b60335460ff16156135bf5760405162461bcd60e51b815260040161042690614a69565b6033805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586135f43390565b6040516001600160a01b03909116815260200160405180910390a1565b600081116136615760405162461bcd60e51b815260206004820152601760248201527f4d75737420776974686472617720736f6d657468696e670000000000000000006044820152606401610426565b6001600160a01b0383166136b05760405162461bcd60e51b8152602060048201526016602482015275135d5cdd081cdc1958da599e481c9958da5c1a595b9d60521b6044820152606401610426565b6040805160008152602081018390526001600160a01b038416917f2717ead6b9200dd235aad468c9809ea400fe33ac69b5bfaa6d3e90fc922b6398910160405180910390a26122196001600160a01b03831684836130c1565b6040805160008152602081018390526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016917f2717ead6b9200dd235aad468c9809ea400fe33ac69b5bfaa6d3e90fc922b6398910160405180910390a250565b6000606854471015613786576112eb82613d54565b6000606854476137969190614c50565b9050600191506801bc16d674ec80000081106139735760006801bc16d674ec8000008204905080603460008282546137ce9190614c50565b90915550600090506137e9826801bc16d674ec800000614c31565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b15801561384657600080fd5b505af115801561385a573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb92506044019050602060405180830381600087803b1580156138ea57600080fd5b505af11580156138fe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613922919061437f565b5061392c81613709565b60345460408051848152602081019290925281018290527fbe7040030ff7b347853214bf49820c6d455fedf58f3815f85c7bc5216993682b9060600160405180910390a150505b6000606854476139839190614c50565b90506801bc16d674ec80000081106139d55760405162461bcd60e51b8152602060048201526015602482015274756e6578706563746564206163636f756e74696e6760581b6044820152606401610426565b806139e1575050919050565b606954811015613a3b5780606860008282546139fd9190614c19565b90915550506040518181527f7a745a2c63a535068f52ceca27debd5297bbad5f7f37ec53d044a59d0362445d906020015b60405180910390a1613be9565b606a54811115613bd8577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b158015613aa057600080fd5b505af1158015613ab4573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb92506044019050602060405180830381600087803b158015613b4457600080fd5b505af1158015613b58573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b7c919061437f565b50600160346000828254613b909190614c50565b90915550613b9f905081613709565b60345460408051918252602082018390527f6aa7e30787b26429ced603a7aba8b19c4b5d5bcf29a3257da953c8d53bcaa3a69101613a2e565b613be184613d54565b949350505050565b5050919050565b60335460ff16613c395760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610426565b6033805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa336135f4565b6000613cbf826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316613d6c9092919063ffffffff16565b8051909150156122195780806020019051810190613cdd919061437f565b6122195760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610426565b6000818310613d4b5781613d4d565b825b9392505050565b60008115613d6457613d6461359c565b506000919050565b6060613be1848460008585843b613dc55760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610426565b600080866001600160a01b03168587604051613de191906146ca565b60006040518083038185875af1925050503d8060008114613e1e576040519150601f19603f3d011682016040523d82523d6000602084013e613e23565b606091505b5091509150613e33828286613e3e565b979650505050505050565b60608315613e4d575081613d4d565b825115613e5d5782518084602001fd5b8160405162461bcd60e51b815260040161042691906149e8565b828054828255906000526020600020908101928215613eca579160200282015b82811115613eca5781546001600160a01b0319166001600160a01b03843516178255602090920191600190910190613e97565b50613ed6929150613f2f565b5090565b828054828255906000526020600020908101928215613eca579160200282015b82811115613eca57825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190613efa565b5b80821115613ed65760008155600101613f30565b60008083601f840112613f5657600080fd5b5081356001600160401b03811115613f6d57600080fd5b6020830191508360208260051b8501011115613f8857600080fd5b9250929050565b600082601f830112613fa057600080fd5b81356020613fb5613fb083614bb5565b614b85565b80838252828201915082860187848660051b8901011115613fd557600080fd5b60005b85811015613ffd578135613feb81614d1c565b84529284019290840190600101613fd8565b5090979650505050505050565b60008083601f84011261401c57600080fd5b5081356001600160401b0381111561403357600080fd5b602083019150836020828501011115613f8857600080fd5b600060a0828403121561405d57600080fd5b50919050565b600060a0828403121561407557600080fd5b60405160a081018181106001600160401b038211171561409757614097614d06565b6040529050806140a6836140ee565b81526140b460208401614107565b60208201526140c560408401614107565b604082015260608301356140d881614d31565b6060820152608092830135920191909152919050565b803563ffffffff8116811461410257600080fd5b919050565b80356001600160401b038116811461410257600080fd5b60006020828403121561413057600080fd5b8135613d4d81614d1c565b60006020828403121561414d57600080fd5b8151613d4d81614d1c565b6000806040838503121561416b57600080fd5b823561417681614d1c565b9150602083013561418681614d1c565b809150509250929050565b6000806000606084860312156141a657600080fd5b83356141b181614d1c565b925060208401356141c181614d1c565b929592945050506040919091013590565b600080604083850312156141e557600080fd5b82356141f081614d1c565b946020939093013593505050565b6000806020838503121561421157600080fd5b82356001600160401b0381111561422757600080fd5b61423385828601613f44565b90969095509350505050565b60008060006060848603121561425457600080fd5b83356001600160401b038082111561426b57600080fd5b61427787838801613f8f565b9450602086013591508082111561428d57600080fd5b61429987838801613f8f565b935060408601359150808211156142af57600080fd5b506142bc86828701613f8f565b9150509250925092565b600080600060e084860312156142db57600080fd5b83356001600160401b038111156142f157600080fd5b8401601f8101861361430257600080fd5b80356020614312613fb083614bb5565b8083825282820191508285018a848660051b880101111561433257600080fd5b600095505b8486101561435c5761434881614107565b835260019590950194918301918301614337565b509650508601359350614376915086905060408601614063565b90509250925092565b60006020828403121561439157600080fd5b8151613d4d81614d31565b6000602082840312156143ae57600080fd5b5035919050565b600080600080604085870312156143cb57600080fd5b84356001600160401b03808211156143e257600080fd5b6143ee8883890161400a565b9096509450602087013591508082111561440757600080fd5b5061441487828801613f44565b95989497509550505050565b600080600080600080600080610120898b03121561443d57600080fd5b88356001600160401b038082111561445457600080fd5b6144608c838d0161400a565b909a50985060208b013591508082111561447957600080fd5b6144858c838d01613f44565b909850965060408b013591508082111561449e57600080fd5b506144ab8b828c0161400a565b909550935050606089013591506144c58a60808b0161404b565b90509295985092959890939650565b600080600080600060e086880312156144ec57600080fd5b85356001600160401b038082111561450357600080fd5b61450f89838a0161400a565b9097509550602088013591508082111561452857600080fd5b5061453588828901613f44565b90945092506145499050876040880161404b565b90509295509295909350565b60008060006060848603121561456a57600080fd5b505081359360208301359350604090920135919050565b60006020828403121561459357600080fd5b5051919050565b600080604083850312156145ad57600080fd5b50508035926020909101359150565b8183526000602080850194508260005b858110156145f8576001600160401b036145e583614107565b16875295820195908201906001016145cc565b509495945050505050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b60008151808452614644816020860160208601614c67565b601f01601f19169290920160200192915050565b63ffffffff614666826140ee565b16825261467560208201614107565b6001600160401b0380821660208501528061469260408501614107565b166040850152505060608101356146a881614d31565b15156060830152608090810135910152565b8183823760009101908152919050565b600082516146dc818460208701614c67565b9190910192915050565b6001600160a01b03851681526101006020808301829052855191830182905260009161012084019187810191845b818110156147395783516001600160401b031685529382019392820192600101614714565b505082935086604086015263ffffffff865116606086015280860151925050506001600160401b0380821660808501528060408601511660a085015250506060830151151560c0830152608083015160e083015295945050505050565b6020808252825182820181905260009190848201906040850190845b818110156147d75783516001600160a01b0316835292840192918401916001016147b2565b50909695505050505050565b6000604082016040835280865480835260608501915087600052602092508260002060005b8281101561482d5781546001600160a01b031684529284019260019182019101614808565b505050838103828501528481528590820160005b8681101561486f57823561485481614d1c565b6001600160a01b031682529183019190830190600101614841565b50979650505050505050565b60408152600061488f604083018688614603565b8281036020840152613e338185876145bc565b60006101208083526148b78184018b8d614603565b905082810360208401526148cc81898b6145bc565b905082810360408401526148e1818789614603565b9150508360608301526148f76080830184614658565b9998505050505050505050565b60e08152600061491860e083018789614603565b828103602084015261492b8186886145bc565b91505061493b6040830184614658565b9695505050505050565b60808152600061495960808301888a614603565b828103602084015261496b818861462c565b90508281036040840152614980818688614603565b915050826060830152979650505050505050565b6060815260006149a8606083018688614603565b8460208401528281036040840152613e33818561462c565b60208101600483106149e257634e487b7160e01b600052602160045260246000fd5b91905290565b602081526000613d4d602083018461462c565b60208082526017908201527f43616c6c6572206973206e6f7420746865205661756c74000000000000000000604082015260600190565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b60208082526010908201526f14185d5cd8589b194e881c185d5cd95960821b604082015260600190565b6020808252601d908201527f43616c6c6572206973206e6f7420746865205265676973747261746f72000000604082015260600190565b6020808252600e908201526d1499595b9d1c985b9d0818d85b1b60921b604082015260600190565b6020808252601c908201527f43616c6c6572206973206e6f7420746865205374726174656769737400000000604082015260600190565b6000808335601e19843603018112614b4057600080fd5b8301803591506001600160401b03821115614b5a57600080fd5b602001915036819003821315613f8857600080fd5b60008235605e198336030181126146dc57600080fd5b604051601f8201601f191681016001600160401b0381118282101715614bad57614bad614d06565b604052919050565b60006001600160401b03821115614bce57614bce614d06565b5060051b60200190565b600080821280156001600160ff1b0384900385131615614bfa57614bfa614cae565b600160ff1b8390038412811615614c1357614c13614cae565b50500190565b60008219821115614c2c57614c2c614cae565b500190565b6000816000190483118215151615614c4b57614c4b614cae565b500290565b600082821015614c6257614c62614cae565b500390565b60005b83811015614c82578181015183820152602001614c6a565b83811115610ef75750506000910152565b6000600019821415614ca757614ca7614cae565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b03811681146127a957600080fd5b80151581146127a957600080fdfe53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac45357bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa264697066735822122036fc9aa0014d1fbbc8fbac98689c50c4cc2fb4601ee35cd2b4f5b5f97319fc4864736f6c63430008070033", "libraries": {}, "devdoc": { "author": "Origin Protocol Inc", @@ -1587,6 +1691,9 @@ "removeSsvValidator(bytes,uint64[],(uint32,uint64,uint64,bool,uint256))": { "notice": "Remove a validator from the SSV Cluster. Make sure `exitSsvValidator` is called before and the validate has exited the Beacon chain. If removed before the validator has exited the beacon chain will result in the validator being slashed. Only the registrator can call this function." }, + "resetStakeETHTally()": { + "notice": "Reset the stakeETHTally" + }, "rewardTokenAddresses(uint256)": { "notice": "Address of the reward tokens. eg CRV, BAL, CVX, AURA" }, @@ -1608,9 +1715,24 @@ "setRewardTokenAddresses(address[])": { "notice": "Set the reward token addresses. Any old addresses will be overwritten." }, + "setStakeETHThreshold(uint256)": { + "notice": "Set the amount of ETH that can be staked before staking monitor" + }, + "setStakingMonitor(address)": { + "notice": "Set the address of the staking monitor that is allowed to reset stakeETHTally" + }, + "stakeETHTally()": { + "notice": "Amount of ETH that can has been staked since the last governor approval." + }, + "stakeETHThreshold()": { + "notice": "Amount of ETH that can be staked before staking on the contract is suspended and the governor needs to approve further staking" + }, "stakeEth((bytes,bytes,bytes32)[])": { "notice": "Stakes WETH to the node validators" }, + "stakingMonitor()": { + "notice": "The account that is allowed to modify stakeETHThreshold and reset stakeETHTally" + }, "supportsAsset(address)": { "notice": "Returns bool indicating whether asset is supported by strategy." }, @@ -1642,7 +1764,7 @@ "storageLayout": { "storage": [ { - "astId": 41769, + "astId": 5553, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "initialized", "offset": 0, @@ -1650,7 +1772,7 @@ "type": "t_bool" }, { - "astId": 41772, + "astId": 5556, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "initializing", "offset": 1, @@ -1658,7 +1780,7 @@ "type": "t_bool" }, { - "astId": 41812, + "astId": 5596, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "______gap", "offset": 0, @@ -1666,7 +1788,7 @@ "type": "t_array(t_uint256)50_storage" }, { - "astId": 656, + "astId": 17, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "_paused", "offset": 0, @@ -1674,7 +1796,7 @@ "type": "t_bool" }, { - "astId": 34884, + "astId": 3709, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "validatorRegistrator", "offset": 1, @@ -1682,7 +1804,7 @@ "type": "t_address" }, { - "astId": 34887, + "astId": 3712, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "activeDepositedValidators", "offset": 0, @@ -1690,23 +1812,47 @@ "type": "t_uint256" }, { - "astId": 34893, + "astId": 3718, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "validatorsStates", "offset": 0, "slot": "53", - "type": "t_mapping(t_bytes32,t_enum(VALIDATOR_STATE)34902)" + "type": "t_mapping(t_bytes32,t_enum(VALIDATOR_STATE)3736)" }, { - "astId": 34897, + "astId": 3721, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", - "label": "__gap", + "label": "stakingMonitor", "offset": 0, "slot": "54", - "type": "t_array(t_uint256)50_storage" + "type": "t_address" + }, + { + "astId": 3724, + "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", + "label": "stakeETHThreshold", + "offset": 0, + "slot": "55", + "type": "t_uint256" + }, + { + "astId": 3727, + "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", + "label": "stakeETHTally", + "offset": 0, + "slot": "56", + "type": "t_uint256" }, { - "astId": 34379, + "astId": 3731, + "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", + "label": "__gap", + "offset": 0, + "slot": "57", + "type": "t_array(t_uint256)47_storage" + }, + { + "astId": 3204, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "consensusRewards", "offset": 0, @@ -1714,7 +1860,7 @@ "type": "t_uint256" }, { - "astId": 34382, + "astId": 3207, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "fuseIntervalStart", "offset": 0, @@ -1722,7 +1868,7 @@ "type": "t_uint256" }, { - "astId": 34385, + "astId": 3210, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "fuseIntervalEnd", "offset": 0, @@ -1730,7 +1876,7 @@ "type": "t_uint256" }, { - "astId": 34388, + "astId": 3213, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "lastFixAccountingBlockNumber", "offset": 0, @@ -1738,7 +1884,7 @@ "type": "t_uint256" }, { - "astId": 34392, + "astId": 3217, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "__gap", "offset": 0, @@ -1746,7 +1892,7 @@ "type": "t_array(t_uint256)49_storage" }, { - "astId": 41892, + "astId": 5676, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "_deprecated_platformAddress", "offset": 0, @@ -1754,7 +1900,7 @@ "type": "t_address" }, { - "astId": 41895, + "astId": 5679, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "_deprecated_vaultAddress", "offset": 0, @@ -1762,7 +1908,7 @@ "type": "t_address" }, { - "astId": 41900, + "astId": 5684, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "assetToPToken", "offset": 0, @@ -1770,7 +1916,7 @@ "type": "t_mapping(t_address,t_address)" }, { - "astId": 41904, + "astId": 5688, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "assetsMapped", "offset": 0, @@ -1778,7 +1924,7 @@ "type": "t_array(t_address)dyn_storage" }, { - "astId": 41906, + "astId": 5690, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "_deprecated_rewardTokenAddress", "offset": 0, @@ -1786,7 +1932,7 @@ "type": "t_address" }, { - "astId": 41908, + "astId": 5692, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "_deprecated_rewardLiquidationThreshold", "offset": 0, @@ -1794,7 +1940,7 @@ "type": "t_uint256" }, { - "astId": 41911, + "astId": 5695, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "harvesterAddress", "offset": 0, @@ -1802,7 +1948,7 @@ "type": "t_address" }, { - "astId": 41915, + "astId": 5699, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "rewardTokenAddresses", "offset": 0, @@ -1810,7 +1956,7 @@ "type": "t_array(t_address)dyn_storage" }, { - "astId": 41919, + "astId": 5703, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "_reserved", "offset": 0, @@ -1818,7 +1964,7 @@ "type": "t_array(t_int256)98_storage" }, { - "astId": 33893, + "astId": 2718, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "depositedWethAccountedFor", "offset": 0, @@ -1826,7 +1972,7 @@ "type": "t_uint256" }, { - "astId": 33897, + "astId": 2722, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "__gap", "offset": 0, @@ -1852,6 +1998,12 @@ "label": "int256[98]", "numberOfBytes": "3136" }, + "t_array(t_uint256)47_storage": { + "base": "t_uint256", + "encoding": "inplace", + "label": "uint256[47]", + "numberOfBytes": "1504" + }, "t_array(t_uint256)49_storage": { "base": "t_uint256", "encoding": "inplace", @@ -1874,7 +2026,7 @@ "label": "bytes32", "numberOfBytes": "32" }, - "t_enum(VALIDATOR_STATE)34902": { + "t_enum(VALIDATOR_STATE)3736": { "encoding": "inplace", "label": "enum ValidatorRegistrator.VALIDATOR_STATE", "numberOfBytes": "1" @@ -1891,12 +2043,12 @@ "numberOfBytes": "32", "value": "t_address" }, - "t_mapping(t_bytes32,t_enum(VALIDATOR_STATE)34902)": { + "t_mapping(t_bytes32,t_enum(VALIDATOR_STATE)3736)": { "encoding": "mapping", "key": "t_bytes32", "label": "mapping(bytes32 => enum ValidatorRegistrator.VALIDATOR_STATE)", "numberOfBytes": "32", - "value": "t_enum(VALIDATOR_STATE)34902" + "value": "t_enum(VALIDATOR_STATE)3736" }, "t_uint256": { "encoding": "inplace", diff --git a/contracts/deployments/holesky/solcInputs/a7af3565925bcd06d3e7b2ed59f01c90.json b/contracts/deployments/holesky/solcInputs/a7af3565925bcd06d3e7b2ed59f01c90.json new file mode 100644 index 0000000000..3b7662b904 --- /dev/null +++ b/contracts/deployments/holesky/solcInputs/a7af3565925bcd06d3e7b2ed59f01c90.json @@ -0,0 +1,107 @@ +{ + "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/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/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" + }, + "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/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/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/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 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 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 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/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 function removeAsset(address _asset) external;\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/strategies/NativeStaking/FeeAccumulator.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { Address } from \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport { Governable } from \"../../governance/Governable.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 is Governable {\n /// @notice The address of the Native Staking Strategy\n address public immutable STRATEGY;\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 }\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_ADDRESS;\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 _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 address _feeAccumulator,\n address _beaconChainDepositContract\n )\n InitializableAbstractStrategy(_baseConfig)\n ValidatorAccountant(\n _wethAddress,\n _baseConfig.vaultAddress,\n _beaconChainDepositContract,\n _ssvNetwork\n )\n {\n SSV_TOKEN_ADDRESS = _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 /// @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_TOKEN_ADDRESS).deposit{ value: ethRewards }();\n\n emit RewardTokenCollected(\n harvesterAddress,\n WETH_TOKEN_ADDRESS,\n ethRewards\n );\n IERC20(WETH_TOKEN_ADDRESS).safeTransfer(\n harvesterAddress,\n ethRewards\n );\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_TOKEN_ADDRESS, \"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_TOKEN_ADDRESS).balanceOf(\n address(this)\n );\n uint256 newWeth = wethBalance - depositedWethAccountedFor;\n\n if (newWeth > 0) {\n depositedWethAccountedFor = wethBalance;\n\n _deposit(WETH_TOKEN_ADDRESS, newWeth);\n }\n }\n\n /// @notice Withdraw WETH from this contract. Used only if some WETH for is lingering on the contract. That\n /// can happen when:\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 _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 emit Withdrawal(_asset, address(0), _amount);\n IERC20(_asset).safeTransfer(_recipient, _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_TOKEN_ADDRESS).balanceOf(\n address(this)\n );\n if (wethBalance > 0) {\n _withdraw(vaultAddress, WETH_TOKEN_ADDRESS, wethBalance);\n }\n }\n\n function _abstractSetPToken(address _asset, address) internal override {}\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_TOKEN_ADDRESS, \"Unsupported asset\");\n\n balance =\n // add the ETH that has been staked in validators\n activeDepositedValidators *\n 32 ether +\n // add the WETH in the strategy from deposits that are still to be staked\n IERC20(WETH_TOKEN_ADDRESS).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_TOKEN_ADDRESS;\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_ADDRESS).approve(\n SSV_NETWORK_ADDRESS,\n type(uint256).max\n );\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 ||\n msg.sender == WETH_TOKEN_ADDRESS,\n \"eth not from allowed contracts\"\n );\n }\n\n function _wethWithdrawnToVault(uint256 _amount) internal override {\n emit Withdrawal(WETH_TOKEN_ADDRESS, address(0), _amount);\n }\n\n function _wethWithdrawnAndStaked(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 direclty\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 /// @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 MAX_STAKE = 32 ether;\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 constructor(\n address _wethAddress,\n address _vaultAddress,\n address _beaconChainDepositContract,\n address _ssvNetwork\n )\n ValidatorRegistrator(\n _wethAddress,\n _vaultAddress,\n _beaconChainDepositContract,\n _ssvNetwork\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 _fuseIntervalStart < 32 ether &&\n _fuseIntervalEnd < 32 ether &&\n _fuseIntervalEnd - _fuseIntervalStart >= 4 ether,\n \"incorrect fuse interval\"\n );\n\n emit FuseIntervalUpdated(_fuseIntervalStart, _fuseIntervalEnd);\n\n fuseIntervalStart = _fuseIntervalStart;\n fuseIntervalEnd = _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 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 >= MAX_STAKE) {\n uint256 fullyWithdrawnValidators;\n // safe since MAX_STAKE is hardcoded to 32ETH\n unchecked {\n // explicitly cast to uint256 as we want to round to a whole number of validators\n fullyWithdrawnValidators = uint256(newSweptETH / MAX_STAKE);\n }\n activeDepositedValidators -= fullyWithdrawnValidators;\n\n uint256 wethToVault = MAX_STAKE * fullyWithdrawnValidators;\n IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: wethToVault }();\n // slither-disable-next-line unchecked-transfer\n IWETH9(WETH_TOKEN_ADDRESS).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 < 32 ether, \"unexpected accounting\");\n\n // If no Beacon chain consensus rewards swept\n if (ethRemaining == 0) {\n // do nothing\n return accountingValid;\n }\n // Beacon chain consensus rewards swept (partial validator withdrawals)\n else if (ethRemaining < fuseIntervalStart) {\n // solhint-disable-next-line reentrancy\n consensusRewards += ethRemaining;\n emit AccountingConsensusRewards(ethRemaining);\n }\n // Beacon chain consensus rewards swept but also a slashed validator fully exited\n else if (ethRemaining > fuseIntervalEnd) {\n IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: ethRemaining }();\n // slither-disable-next-line unchecked-transfer\n IWETH9(WETH_TOKEN_ADDRESS).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 {\n require(\n lastFixAccountingBlockNumber + MIN_FIX_ACCOUNTING_CADENCE <\n block.number,\n \"manuallyFixAccounting 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 emit AccountingManuallyFixed(\n _validatorsDelta,\n _consensusRewardsDelta,\n _ethToVaultAmount\n );\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_TOKEN_ADDRESS).deposit{ value: _ethToVaultAmount }();\n // slither-disable-next-line unchecked-transfer\n IWETH9(WETH_TOKEN_ADDRESS).transfer(\n VAULT_ADDRESS,\n _ethToVaultAmount\n );\n _wethWithdrawnToVault(_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 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 address of the Wrapped ETH (WETH) token contract\n address public immutable WETH_TOKEN_ADDRESS;\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_ADDRESS;\n /// @notice Address of the OETH Vault proxy contract\n address public immutable VAULT_ADDRESS;\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 governor needs to approve further staking\n uint256 public stakeETHThreshold;\n /// @notice Amount of ETH that can has been staked since the last governor approval.\n uint256 public stakeETHTally;\n // For future use\n uint256[47] private __gap;\n\n enum VALIDATOR_STATE {\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 newAddress);\n event StakingMonitorChanged(address newAddress);\n event ETHStaked(bytes pubkey, uint256 amount, bytes withdrawal_credentials);\n event SSVValidatorRegistered(bytes pubkey, uint64[] operatorIds);\n event SSVValidatorExitInitiated(bytes pubkey, uint64[] operatorIds);\n event SSVValidatorExitCompleted(bytes pubkey, uint64[] operatorIds);\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 constructor(\n address _wethAddress,\n address _vaultAddress,\n address _beaconChainDepositContract,\n address _ssvNetwork\n ) {\n WETH_TOKEN_ADDRESS = _wethAddress;\n BEACON_CHAIN_DEPOSIT_CONTRACT = _beaconChainDepositContract;\n SSV_NETWORK_ADDRESS = _ssvNetwork;\n VAULT_ADDRESS = _vaultAddress;\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 emit RegistratorChanged(_address);\n validatorRegistrator = _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 emit StakingMonitorChanged(_address);\n stakingMonitor = _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 emit StakeETHThresholdChanged(_amount);\n stakeETHThreshold = _amount;\n }\n\n /// @notice Reset the stakeETHTally\n function resetStakeETHTally() external onlyStakingMonitor {\n emit StakeETHTallyReset();\n stakeETHTally = 0;\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 {\n uint256 requiredETH = validators.length * 32 ether;\n\n // Check there is enough WETH from the deposits sitting in this strategy contract\n require(\n requiredETH <= IWETH9(WETH_TOKEN_ADDRESS).balanceOf(address(this)),\n \"insufficient WETH\"\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_TOKEN_ADDRESS).withdraw(requiredETH);\n _wethWithdrawnAndStaked(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 withdrawal_credentials = abi.encodePacked(\n bytes1(0x01),\n bytes11(0),\n address(this)\n );\n\n uint256 validatorsLength = validators.length;\n // For each validator\n for (uint256 i = 0; i < validatorsLength; ) {\n bytes32 pubkeyHash = keccak256(validators[i].pubkey);\n VALIDATOR_STATE currentState = validatorsStates[pubkeyHash];\n\n require(\n currentState == VALIDATOR_STATE.REGISTERED,\n \"Validator not registered\"\n );\n\n IDepositContract(BEACON_CHAIN_DEPOSIT_CONTRACT).deposit{\n value: 32 ether\n }(\n validators[i].pubkey,\n withdrawal_credentials,\n validators[i].signature,\n validators[i].depositDataRoot\n );\n\n emit ETHStaked(\n validators[i].pubkey,\n 32 ether,\n withdrawal_credentials\n );\n\n validatorsStates[pubkeyHash] = VALIDATOR_STATE.STAKED;\n\n unchecked {\n ++i;\n }\n }\n // save gas by changing this storage variable only once rather each time in the loop.\n activeDepositedValidators += validatorsLength;\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 function registerSsvValidator(\n bytes calldata publicKey,\n uint64[] calldata operatorIds,\n bytes calldata sharesData,\n uint256 amount,\n Cluster calldata cluster\n ) external onlyRegistrator whenNotPaused {\n ISSVNetwork(SSV_NETWORK_ADDRESS).registerValidator(\n publicKey,\n operatorIds,\n sharesData,\n amount,\n cluster\n );\n validatorsStates[keccak256(publicKey)] = VALIDATOR_STATE.REGISTERED;\n emit SSVValidatorRegistered(publicKey, operatorIds);\n }\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 // slither-disable-start reentrancy-no-eth\n function exitSsvValidator(\n bytes calldata publicKey,\n uint64[] calldata operatorIds\n ) external onlyRegistrator whenNotPaused {\n VALIDATOR_STATE currentState = validatorsStates[keccak256(publicKey)];\n require(currentState == VALIDATOR_STATE.STAKED, \"Validator not staked\");\n\n ISSVNetwork(SSV_NETWORK_ADDRESS).exitValidator(publicKey, operatorIds);\n emit SSVValidatorExitInitiated(publicKey, operatorIds);\n\n validatorsStates[keccak256(publicKey)] = VALIDATOR_STATE.EXITING;\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 // 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 VALIDATOR_STATE currentState = validatorsStates[keccak256(publicKey)];\n require(\n currentState == VALIDATOR_STATE.EXITING,\n \"Validator not exiting\"\n );\n\n ISSVNetwork(SSV_NETWORK_ADDRESS).removeValidator(\n publicKey,\n operatorIds,\n cluster\n );\n emit SSVValidatorExitCompleted(publicKey, operatorIds);\n\n validatorsStates[keccak256(publicKey)] = VALIDATOR_STATE.EXIT_COMPLETE;\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 cluster The SSV cluster details that must be derived from emitted events from the SSVNetwork contract.\n function depositSSV(\n uint64[] memory operatorIds,\n uint256 amount,\n Cluster memory cluster\n ) external onlyStrategist {\n ISSVNetwork(SSV_NETWORK_ADDRESS).deposit(\n address(this),\n operatorIds,\n amount,\n cluster\n );\n }\n\n /***************************************\n Abstract\n ****************************************/\n\n /// @dev allows for NativeStakingSSVStrategy contract know how much WETH had been staked\n function _wethWithdrawnAndStaked(uint256 _amount) internal virtual;\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/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/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\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" + } + }, + "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/docs/NativeStakingSSVStrategySquashed.svg b/contracts/docs/NativeStakingSSVStrategySquashed.svg index 86d64e08ec..1efe2f1314 100644 --- a/contracts/docs/NativeStakingSSVStrategySquashed.svg +++ b/contracts/docs/NativeStakingSSVStrategySquashed.svg @@ -4,135 +4,145 @@ - - + + UmlClassDiagram - + 284 - -NativeStakingSSVStrategy -../contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol - -Private: -   governorPosition: bytes32 <<Governable>> -   pendingGovernorPosition: bytes32 <<Governable>> -   reentryStatusPosition: bytes32 <<Governable>> -   _paused: bool <<Pausable>> -   __gap: uint256[50] <<ValidatorRegistrator>> -   __gap: uint256[49] <<ValidatorAccountant>> -   initialized: bool <<Initializable>> -   initializing: bool <<Initializable>> -   ______gap: uint256[50] <<Initializable>> -   _deprecated_platformAddress: address <<InitializableAbstractStrategy>> -   _deprecated_vaultAddress: address <<InitializableAbstractStrategy>> -   _deprecated_rewardTokenAddress: address <<InitializableAbstractStrategy>> -   _deprecated_rewardLiquidationThreshold: uint256 <<InitializableAbstractStrategy>> -   _reserved: int256[98] <<InitializableAbstractStrategy>> -   __gap: uint256[49] <<NativeStakingSSVStrategy>> -Internal: -   assetsMapped: address[] <<InitializableAbstractStrategy>> -Public: -   _NOT_ENTERED: uint256 <<Governable>> -   _ENTERED: uint256 <<Governable>> -   WETH_TOKEN_ADDRESS: address <<ValidatorRegistrator>> -   BEACON_CHAIN_DEPOSIT_CONTRACT: address <<ValidatorRegistrator>> -   SSV_NETWORK_ADDRESS: address <<ValidatorRegistrator>> -   VAULT_ADDRESS: address <<ValidatorRegistrator>> -   validatorRegistrator: address <<ValidatorRegistrator>> -   activeDepositedValidators: uint256 <<ValidatorRegistrator>> -   validatorsStates: mapping(bytes32=>VALIDATOR_STATE) <<ValidatorRegistrator>> -   MIN_FIX_ACCOUNTING_CADENCE: uint256 <<ValidatorAccountant>> -   MAX_STAKE: uint256 <<ValidatorAccountant>> -   consensusRewards: uint256 <<ValidatorAccountant>> -   fuseIntervalStart: uint256 <<ValidatorAccountant>> -   fuseIntervalEnd: uint256 <<ValidatorAccountant>> -   lastFixAccountingBlockNumber: uint256 <<ValidatorAccountant>> -   platformAddress: address <<InitializableAbstractStrategy>> -   vaultAddress: address <<InitializableAbstractStrategy>> -   assetToPToken: mapping(address=>address) <<InitializableAbstractStrategy>> -   harvesterAddress: address <<InitializableAbstractStrategy>> -   rewardTokenAddresses: address[] <<InitializableAbstractStrategy>> -   SSV_TOKEN_ADDRESS: address <<NativeStakingSSVStrategy>> -   FEE_ACCUMULATOR_ADDRESS: address <<NativeStakingSSVStrategy>> -   depositedWethAccountedFor: uint256 <<NativeStakingSSVStrategy>> - -Internal: -    _governor(): (governorOut: address) <<Governable>> -    _pendingGovernor(): (pendingGovernor: address) <<Governable>> -    _setGovernor(newGovernor: address) <<Governable>> -    _setPendingGovernor(newGovernor: address) <<Governable>> -    _changeGovernor(_newGovernor: address) <<Governable>> -    _msgSender(): address <<Context>> -    _msgData(): bytes <<Context>> -    _pause() <<whenNotPaused>> <<Pausable>> -    _unpause() <<whenPaused>> <<Pausable>> -    _wethWithdrawnAndStaked(_amount: uint256) <<NativeStakingSSVStrategy>> -    _doAccounting(pauseOnFail: bool): (accountingValid: bool) <<ValidatorAccountant>> -    _failAccounting(pauseOnFail: bool): (accountingValid: bool) <<ValidatorAccountant>> -    _wethWithdrawnToVault(_amount: uint256) <<NativeStakingSSVStrategy>> -    _initialize(_rewardTokenAddresses: address[], _assets: address[], _pTokens: address[]) <<InitializableAbstractStrategy>> -    _collectRewardTokens() <<whenNotPaused>> <<NativeStakingSSVStrategy>> -    _setPTokenAddress(_asset: address, _pToken: address) <<InitializableAbstractStrategy>> -    _abstractSetPToken(_asset: address, address) <<NativeStakingSSVStrategy>> -    _deposit(_asset: address, _amount: uint256) <<NativeStakingSSVStrategy>> -    _withdraw(_recipient: address, _asset: address, _amount: uint256) <<NativeStakingSSVStrategy>> -External: -    <<payable>> null() <<NativeStakingSSVStrategy>> -    transferGovernance(_newGovernor: address) <<onlyGovernor>> <<Governable>> -    claimGovernance() <<Governable>> -    setRegistrator(_address: address) <<onlyGovernor>> <<ValidatorRegistrator>> -    stakeEth(validators: ValidatorStakeData[]) <<onlyRegistrator, whenNotPaused>> <<ValidatorRegistrator>> -    registerSsvValidator(publicKey: bytes, operatorIds: uint64[], sharesData: bytes, amount: uint256, cluster: Cluster) <<onlyRegistrator, whenNotPaused>> <<ValidatorRegistrator>> -    exitSsvValidator(publicKey: bytes, operatorIds: uint64[]) <<onlyRegistrator, whenNotPaused>> <<ValidatorRegistrator>> -    removeSsvValidator(publicKey: bytes, operatorIds: uint64[], cluster: Cluster) <<onlyRegistrator, whenNotPaused>> <<ValidatorRegistrator>> -    depositSSV(operatorIds: uint64[], amount: uint256, cluster: Cluster) <<onlyStrategist>> <<ValidatorRegistrator>> -    setFuseInterval(_fuseIntervalStart: uint256, _fuseIntervalEnd: uint256) <<onlyGovernor>> <<ValidatorAccountant>> -    doAccounting(): (accountingValid: bool) <<onlyRegistrator, whenNotPaused>> <<ValidatorAccountant>> -    manuallyFixAccounting(_validatorsDelta: int256, _consensusRewardsDelta: int256, _ethToVaultAmount: uint256) <<onlyStrategist, whenPaused>> <<ValidatorAccountant>> -    collectRewardTokens() <<onlyHarvester, nonReentrant>> <<InitializableAbstractStrategy>> -    setRewardTokenAddresses(_rewardTokenAddresses: address[]) <<onlyGovernor>> <<InitializableAbstractStrategy>> -    getRewardTokenAddresses(): address[] <<InitializableAbstractStrategy>> -    setPTokenAddress(_asset: address, _pToken: address) <<onlyGovernor>> <<InitializableAbstractStrategy>> -    removePToken(_assetIndex: uint256) <<onlyGovernor>> <<InitializableAbstractStrategy>> -    setHarvesterAddress(_harvesterAddress: address) <<onlyGovernor>> <<InitializableAbstractStrategy>> -    safeApproveAllTokens() <<NativeStakingSSVStrategy>> -    deposit(_asset: address, _amount: uint256) <<onlyVault, nonReentrant>> <<NativeStakingSSVStrategy>> -    depositAll() <<onlyVault, nonReentrant>> <<NativeStakingSSVStrategy>> -    withdraw(_recipient: address, _asset: address, _amount: uint256) <<onlyVault, nonReentrant>> <<NativeStakingSSVStrategy>> -    withdrawAll() <<onlyVaultOrGovernor, nonReentrant>> <<NativeStakingSSVStrategy>> -    checkBalance(_asset: address): (balance: uint256) <<NativeStakingSSVStrategy>> -    initialize(_rewardTokenAddresses: address[], _assets: address[], _pTokens: address[]) <<onlyGovernor, initializer>> <<NativeStakingSSVStrategy>> -    pause() <<onlyStrategist>> <<NativeStakingSSVStrategy>> -Public: -    <<event>> PendingGovernorshipTransfer(previousGovernor: address, newGovernor: address) <<Governable>> -    <<event>> GovernorshipTransferred(previousGovernor: address, newGovernor: address) <<Governable>> -    <<event>> Paused(account: address) <<Pausable>> -    <<event>> Unpaused(account: address) <<Pausable>> -    <<event>> RegistratorChanged(newAddress: address) <<ValidatorRegistrator>> -    <<event>> ETHStaked(pubkey: bytes, amount: uint256, withdrawal_credentials: bytes) <<ValidatorRegistrator>> -    <<event>> SSVValidatorRegistered(pubkey: bytes, operatorIds: uint64[]) <<ValidatorRegistrator>> -    <<event>> SSVValidatorExitInitiated(pubkey: bytes, operatorIds: uint64[]) <<ValidatorRegistrator>> -    <<event>> SSVValidatorExitCompleted(pubkey: bytes, operatorIds: uint64[]) <<ValidatorRegistrator>> -    <<event>> FuseIntervalUpdated(start: uint256, end: uint256) <<ValidatorAccountant>> -    <<event>> AccountingFullyWithdrawnValidator(noOfValidators: uint256, remainingValidators: uint256, wethSentToVault: uint256) <<ValidatorAccountant>> -    <<event>> AccountingValidatorSlashed(remainingValidators: uint256, wethSentToVault: uint256) <<ValidatorAccountant>> -    <<event>> AccountingConsensusRewards(amount: uint256) <<ValidatorAccountant>> -    <<event>> AccountingManuallyFixed(validatorsDelta: int256, consensusRewardsDelta: int256, wethToVault: uint256) <<ValidatorAccountant>> -    <<event>> PTokenAdded(_asset: address, _pToken: address) <<InitializableAbstractStrategy>> -    <<event>> PTokenRemoved(_asset: address, _pToken: address) <<InitializableAbstractStrategy>> -    <<event>> Deposit(_asset: address, _pToken: address, _amount: uint256) <<InitializableAbstractStrategy>> -    <<event>> Withdrawal(_asset: address, _pToken: address, _amount: uint256) <<InitializableAbstractStrategy>> -    <<event>> RewardTokenCollected(recipient: address, rewardToken: address, amount: uint256) <<InitializableAbstractStrategy>> -    <<event>> RewardTokenAddressesUpdated(_oldAddresses: address[], _newAddresses: address[]) <<InitializableAbstractStrategy>> -    <<event>> HarvesterAddressesUpdated(_oldHarvesterAddress: address, _newHarvesterAddress: address) <<InitializableAbstractStrategy>> -    <<modifier>> onlyGovernor() <<Governable>> -    <<modifier>> nonReentrant() <<Governable>> -    <<modifier>> whenNotPaused() <<Pausable>> -    <<modifier>> whenPaused() <<Pausable>> -    <<modifier>> onlyRegistrator() <<ValidatorRegistrator>> + +NativeStakingSSVStrategy +../contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol + +Private: +   governorPosition: bytes32 <<Governable>> +   pendingGovernorPosition: bytes32 <<Governable>> +   reentryStatusPosition: bytes32 <<Governable>> +   _paused: bool <<Pausable>> +   __gap: uint256[47] <<ValidatorRegistrator>> +   __gap: uint256[49] <<ValidatorAccountant>> +   initialized: bool <<Initializable>> +   initializing: bool <<Initializable>> +   ______gap: uint256[50] <<Initializable>> +   _deprecated_platformAddress: address <<InitializableAbstractStrategy>> +   _deprecated_vaultAddress: address <<InitializableAbstractStrategy>> +   _deprecated_rewardTokenAddress: address <<InitializableAbstractStrategy>> +   _deprecated_rewardLiquidationThreshold: uint256 <<InitializableAbstractStrategy>> +   _reserved: int256[98] <<InitializableAbstractStrategy>> +   __gap: uint256[49] <<NativeStakingSSVStrategy>> +Internal: +   assetsMapped: address[] <<InitializableAbstractStrategy>> +Public: +   _NOT_ENTERED: uint256 <<Governable>> +   _ENTERED: uint256 <<Governable>> +   WETH_TOKEN_ADDRESS: address <<ValidatorRegistrator>> +   BEACON_CHAIN_DEPOSIT_CONTRACT: address <<ValidatorRegistrator>> +   SSV_NETWORK_ADDRESS: address <<ValidatorRegistrator>> +   VAULT_ADDRESS: address <<ValidatorRegistrator>> +   validatorRegistrator: address <<ValidatorRegistrator>> +   activeDepositedValidators: uint256 <<ValidatorRegistrator>> +   validatorsStates: mapping(bytes32=>VALIDATOR_STATE) <<ValidatorRegistrator>> +   stakingMonitor: address <<ValidatorRegistrator>> +   stakeETHThreshold: uint256 <<ValidatorRegistrator>> +   stakeETHTally: uint256 <<ValidatorRegistrator>> +   MIN_FIX_ACCOUNTING_CADENCE: uint256 <<ValidatorAccountant>> +   MAX_STAKE: uint256 <<ValidatorAccountant>> +   consensusRewards: uint256 <<ValidatorAccountant>> +   fuseIntervalStart: uint256 <<ValidatorAccountant>> +   fuseIntervalEnd: uint256 <<ValidatorAccountant>> +   lastFixAccountingBlockNumber: uint256 <<ValidatorAccountant>> +   platformAddress: address <<InitializableAbstractStrategy>> +   vaultAddress: address <<InitializableAbstractStrategy>> +   assetToPToken: mapping(address=>address) <<InitializableAbstractStrategy>> +   harvesterAddress: address <<InitializableAbstractStrategy>> +   rewardTokenAddresses: address[] <<InitializableAbstractStrategy>> +   SSV_TOKEN_ADDRESS: address <<NativeStakingSSVStrategy>> +   FEE_ACCUMULATOR_ADDRESS: address <<NativeStakingSSVStrategy>> +   depositedWethAccountedFor: uint256 <<NativeStakingSSVStrategy>> + +Internal: +    _governor(): (governorOut: address) <<Governable>> +    _pendingGovernor(): (pendingGovernor: address) <<Governable>> +    _setGovernor(newGovernor: address) <<Governable>> +    _setPendingGovernor(newGovernor: address) <<Governable>> +    _changeGovernor(_newGovernor: address) <<Governable>> +    _msgSender(): address <<Context>> +    _msgData(): bytes <<Context>> +    _pause() <<whenNotPaused>> <<Pausable>> +    _unpause() <<whenPaused>> <<Pausable>> +    _wethWithdrawnAndStaked(_amount: uint256) <<NativeStakingSSVStrategy>> +    _doAccounting(pauseOnFail: bool): (accountingValid: bool) <<ValidatorAccountant>> +    _failAccounting(pauseOnFail: bool): (accountingValid: bool) <<ValidatorAccountant>> +    _wethWithdrawnToVault(_amount: uint256) <<NativeStakingSSVStrategy>> +    _initialize(_rewardTokenAddresses: address[], _assets: address[], _pTokens: address[]) <<InitializableAbstractStrategy>> +    _collectRewardTokens() <<whenNotPaused>> <<NativeStakingSSVStrategy>> +    _setPTokenAddress(_asset: address, _pToken: address) <<InitializableAbstractStrategy>> +    _abstractSetPToken(_asset: address, address) <<NativeStakingSSVStrategy>> +    _deposit(_asset: address, _amount: uint256) <<NativeStakingSSVStrategy>> +    _withdraw(_recipient: address, _asset: address, _amount: uint256) <<NativeStakingSSVStrategy>> +External: +    <<payable>> null() <<NativeStakingSSVStrategy>> +    transferGovernance(_newGovernor: address) <<onlyGovernor>> <<Governable>> +    claimGovernance() <<Governable>> +    setRegistrator(_address: address) <<onlyGovernor>> <<ValidatorRegistrator>> +    setStakingMonitor(_address: address) <<onlyGovernor>> <<ValidatorRegistrator>> +    setStakeETHThreshold(_amount: uint256) <<onlyGovernor>> <<ValidatorRegistrator>> +    resetStakeETHTally() <<onlyStakingMonitor>> <<ValidatorRegistrator>> +    stakeEth(validators: ValidatorStakeData[]) <<onlyRegistrator, whenNotPaused>> <<ValidatorRegistrator>> +    registerSsvValidator(publicKey: bytes, operatorIds: uint64[], sharesData: bytes, amount: uint256, cluster: Cluster) <<onlyRegistrator, whenNotPaused>> <<ValidatorRegistrator>> +    exitSsvValidator(publicKey: bytes, operatorIds: uint64[]) <<onlyRegistrator, whenNotPaused>> <<ValidatorRegistrator>> +    removeSsvValidator(publicKey: bytes, operatorIds: uint64[], cluster: Cluster) <<onlyRegistrator, whenNotPaused>> <<ValidatorRegistrator>> +    depositSSV(operatorIds: uint64[], amount: uint256, cluster: Cluster) <<onlyStrategist>> <<ValidatorRegistrator>> +    setFuseInterval(_fuseIntervalStart: uint256, _fuseIntervalEnd: uint256) <<onlyGovernor>> <<ValidatorAccountant>> +    doAccounting(): (accountingValid: bool) <<onlyRegistrator, whenNotPaused>> <<ValidatorAccountant>> +    manuallyFixAccounting(_validatorsDelta: int256, _consensusRewardsDelta: int256, _ethToVaultAmount: uint256) <<onlyStrategist, whenPaused>> <<ValidatorAccountant>> +    collectRewardTokens() <<onlyHarvester, nonReentrant>> <<InitializableAbstractStrategy>> +    setRewardTokenAddresses(_rewardTokenAddresses: address[]) <<onlyGovernor>> <<InitializableAbstractStrategy>> +    getRewardTokenAddresses(): address[] <<InitializableAbstractStrategy>> +    setPTokenAddress(_asset: address, _pToken: address) <<onlyGovernor>> <<InitializableAbstractStrategy>> +    removePToken(_assetIndex: uint256) <<onlyGovernor>> <<InitializableAbstractStrategy>> +    setHarvesterAddress(_harvesterAddress: address) <<onlyGovernor>> <<InitializableAbstractStrategy>> +    safeApproveAllTokens() <<NativeStakingSSVStrategy>> +    deposit(_asset: address, _amount: uint256) <<onlyVault, nonReentrant>> <<NativeStakingSSVStrategy>> +    depositAll() <<onlyVault, nonReentrant>> <<NativeStakingSSVStrategy>> +    withdraw(_recipient: address, _asset: address, _amount: uint256) <<onlyVault, nonReentrant>> <<NativeStakingSSVStrategy>> +    withdrawAll() <<onlyVaultOrGovernor, nonReentrant>> <<NativeStakingSSVStrategy>> +    checkBalance(_asset: address): (balance: uint256) <<NativeStakingSSVStrategy>> +    initialize(_rewardTokenAddresses: address[], _assets: address[], _pTokens: address[]) <<onlyGovernor, initializer>> <<NativeStakingSSVStrategy>> +    pause() <<onlyStrategist>> <<NativeStakingSSVStrategy>> +Public: +    <<event>> PendingGovernorshipTransfer(previousGovernor: address, newGovernor: address) <<Governable>> +    <<event>> GovernorshipTransferred(previousGovernor: address, newGovernor: address) <<Governable>> +    <<event>> Paused(account: address) <<Pausable>> +    <<event>> Unpaused(account: address) <<Pausable>> +    <<event>> RegistratorChanged(newAddress: address) <<ValidatorRegistrator>> +    <<event>> StakingMonitorChanged(newAddress: address) <<ValidatorRegistrator>> +    <<event>> ETHStaked(pubkey: bytes, amount: uint256, withdrawal_credentials: bytes) <<ValidatorRegistrator>> +    <<event>> SSVValidatorRegistered(pubkey: bytes, operatorIds: uint64[]) <<ValidatorRegistrator>> +    <<event>> SSVValidatorExitInitiated(pubkey: bytes, operatorIds: uint64[]) <<ValidatorRegistrator>> +    <<event>> SSVValidatorExitCompleted(pubkey: bytes, operatorIds: uint64[]) <<ValidatorRegistrator>> +    <<event>> StakeETHThresholdChanged(amount: uint256) <<ValidatorRegistrator>> +    <<event>> StakeETHTallyReset() <<ValidatorRegistrator>> +    <<event>> FuseIntervalUpdated(start: uint256, end: uint256) <<ValidatorAccountant>> +    <<event>> AccountingFullyWithdrawnValidator(noOfValidators: uint256, remainingValidators: uint256, wethSentToVault: uint256) <<ValidatorAccountant>> +    <<event>> AccountingValidatorSlashed(remainingValidators: uint256, wethSentToVault: uint256) <<ValidatorAccountant>> +    <<event>> AccountingConsensusRewards(amount: uint256) <<ValidatorAccountant>> +    <<event>> AccountingManuallyFixed(validatorsDelta: int256, consensusRewardsDelta: int256, wethToVault: uint256) <<ValidatorAccountant>> +    <<event>> PTokenAdded(_asset: address, _pToken: address) <<InitializableAbstractStrategy>> +    <<event>> PTokenRemoved(_asset: address, _pToken: address) <<InitializableAbstractStrategy>> +    <<event>> Deposit(_asset: address, _pToken: address, _amount: uint256) <<InitializableAbstractStrategy>> +    <<event>> Withdrawal(_asset: address, _pToken: address, _amount: uint256) <<InitializableAbstractStrategy>> +    <<event>> RewardTokenCollected(recipient: address, rewardToken: address, amount: uint256) <<InitializableAbstractStrategy>> +    <<event>> RewardTokenAddressesUpdated(_oldAddresses: address[], _newAddresses: address[]) <<InitializableAbstractStrategy>> +    <<event>> HarvesterAddressesUpdated(_oldHarvesterAddress: address, _newHarvesterAddress: address) <<InitializableAbstractStrategy>> +    <<modifier>> onlyGovernor() <<Governable>> +    <<modifier>> nonReentrant() <<Governable>> +    <<modifier>> whenNotPaused() <<Pausable>> +    <<modifier>> whenPaused() <<Pausable>> +    <<modifier>> onlyRegistrator() <<ValidatorRegistrator>> +    <<modifier>> onlyStakingMonitor() <<ValidatorRegistrator>>    <<modifier>> onlyStrategist() <<ValidatorRegistrator>>    <<modifier>> initializer() <<Initializable>>    <<modifier>> onlyVault() <<InitializableAbstractStrategy>> diff --git a/contracts/docs/NativeStakingSSVStrategyStorage.svg b/contracts/docs/NativeStakingSSVStrategyStorage.svg index 27ada6cae1..965a544007 100644 --- a/contracts/docs/NativeStakingSSVStrategyStorage.svg +++ b/contracts/docs/NativeStakingSSVStrategyStorage.svg @@ -4,26 +4,32 @@ - - + + StorageDiagram - + 3 - -NativeStakingSSVStrategy <<Contract>> - -slot + +NativeStakingSSVStrategy <<Contract>> + +slot + +0 + +1 + +2 -0 +3 -1 +4 -2 +5 -3-52 +6-52 53 @@ -60,20 +66,28 @@ 263 264-312 - -type: <inherited contract>.variable (bytes) + +type: <inherited contract>.variable (bytes) + +unallocated (11) + +address: ValidatorRegistrator.validatorRegistrator (20) + +bool: Pausable._paused (1) + +uint256: ValidatorRegistrator.activeDepositedValidators (32) + +mapping(bytes32=>VALIDATOR_STATE): ValidatorRegistrator.validatorsStates (32) -unallocated (11) - -address: ValidatorRegistrator.validatorRegistrator (20) - -bool: Pausable._paused (1) +unallocated (12) + +address: ValidatorRegistrator.stakingMonitor (20) -uint256: ValidatorRegistrator.activeDepositedValidators (32) +uint256: ValidatorRegistrator.stakeETHThreshold (32) -mapping(bytes32=>VALIDATOR_STATE): ValidatorRegistrator.validatorsStates (32) +uint256: ValidatorRegistrator.stakeETHTally (32) -uint256[50]: ValidatorRegistrator.__gap (1600) +uint256[47]: ValidatorRegistrator.__gap (1504) uint256: ValidatorAccountant.consensusRewards (32) @@ -126,48 +140,48 @@ 1 - -address[]: assetsMapped <<Array>> -0x78fdc8d422c49ced035a9edf18d00d3c6a8d81df210f3e5e448e045e77b41e88 - -offset - -0 - -type: variable (bytes) - -unallocated (12) - -address (20) + +address[]: assetsMapped <<Array>> +0x78fdc8d422c49ced035a9edf18d00d3c6a8d81df210f3e5e448e045e77b41e88 + +offset + +0 + +type: variable (bytes) + +unallocated (12) + +address (20) -3:18->1 - - +3:21->1 + + 2 - -address[]: rewardTokenAddresses <<Array>> -0xe434dc35da084cf8d7e8186688ea2dacb53db7003d427af3abf351bd9d0a4e8d - -offset - -0 - -type: variable (bytes) - -unallocated (12) - -address (20) + +address[]: rewardTokenAddresses <<Array>> +0xe434dc35da084cf8d7e8186688ea2dacb53db7003d427af3abf351bd9d0a4e8d + +offset + +0 + +type: variable (bytes) + +unallocated (12) + +address (20) -3:23->2 - - +3:26->2 + + diff --git a/contracts/tasks/validator.js b/contracts/tasks/validator.js index 992ac02b67..ee033a6162 100644 --- a/contracts/tasks/validator.js +++ b/contracts/tasks/validator.js @@ -264,11 +264,32 @@ const stakingContractPaused = async (contracts) => { const stakingContractHas32ETH = async (contracts) => { const address = contracts.nativeStakingStrategy.address; const wethBalance = await contracts.WETH.balanceOf(address); + log( + `Native Staking Strategy has ${formatUnits(wethBalance, 18)} WETH in total` + ); + + const stakeETHThreshold = contracts.nativeStakingStrategy.stakeETHThreshold(); + const stakeETHTally = contracts.nativeStakingStrategy.stakeETHTally(); + const remainingETH = stakeETHThreshold.sub(stakeETHTally); + log( + `Native Staking Strategy has staked ${formatUnits( + stakeETHTally + )} of ${formatUnits(stakeETHThreshold)} ETH with ${formatUnits( + remainingETH + )} ETH remaining` + ); + // Take the minimum of the remainingETH and the WETH balance + const availableETH = wethBalance.gt(remainingETH) + ? remainingETH + : wethBalance; log( - `Native staking contract has ${formatUnits(wethBalance, 18)} WETH in total` + `Native Staking Strategy has ${formatUnits( + availableETH + )} ETH available to stake` ); - return wethBalance.gte(parseEther("32")); + + return availableETH.gte(parseEther("32")); }; /* Make a GET or POST request to P2P service diff --git a/contracts/test/_fixture.js b/contracts/test/_fixture.js index 9c87c52f43..ab50a047b0 100644 --- a/contracts/test/_fixture.js +++ b/contracts/test/_fixture.js @@ -1617,6 +1617,7 @@ async function nativeStakingSSVStrategyFixture() { addresses.mainnet.SSVNetwork ); } else { + fixture.ssvNetwork = await ethers.getContract("MockSSVNetwork"); const { governorAddr } = await getNamedAccounts(); const { oethVault, weth, nativeStakingSSVStrategy } = fixture; const sGovernor = await ethers.provider.getSigner(governorAddr); @@ -1641,6 +1642,8 @@ async function nativeStakingSSVStrategyFixture() { await nativeStakingSSVStrategy .connect(sGovernor) .setRegistrator(governorAddr); + + fixture.validatorRegistrator = sGovernor; } return fixture; diff --git a/contracts/test/behaviour/ssvStrategy.js b/contracts/test/behaviour/ssvStrategy.js index 39c292fda6..afd756915e 100644 --- a/contracts/test/behaviour/ssvStrategy.js +++ b/contracts/test/behaviour/ssvStrategy.js @@ -82,6 +82,14 @@ const shouldBehaveLikeAnSsvStrategy = (context) => { addresses.validatorRegistrator, "Incorrect validator registrator" ); + await expect(await nativeStakingSSVStrategy.stakingMonitor()).to.equal( + addresses.Guardian, + "Incorrect staking monitor" + ); + await expect(await nativeStakingSSVStrategy.stakeETHThreshold()).to.gt( + 0, + "stake ETH threshold" + ); }); }); diff --git a/contracts/test/helpers.js b/contracts/test/helpers.js index bf9d563032..dffb37668a 100644 --- a/contracts/test/helpers.js +++ b/contracts/test/helpers.js @@ -489,9 +489,8 @@ const getAssetAddresses = async (deployments) => { BAL: (await deployments.get("MockBAL")).address, SSV: (await deployments.get("MockSSV")).address, SSVNetwork: (await deployments.get("MockSSVNetwork")).address, - beaconChainDepositContract: ( - await deployments.get("BeaconChainDepositContractMock") - ).address, + beaconChainDepositContract: (await deployments.get("MockDepositContract")) + .address, }; try { diff --git a/contracts/test/strategies/nativeSSVStaking.js b/contracts/test/strategies/nativeSSVStaking.js index 27fb8c92b3..26ac2fa84a 100644 --- a/contracts/test/strategies/nativeSSVStaking.js +++ b/contracts/test/strategies/nativeSSVStaking.js @@ -14,6 +14,8 @@ const { shouldBehaveLikeHarvestable } = require("../behaviour/harvestable"); const { shouldBehaveLikeStrategy } = require("../behaviour/strategy"); const { MAX_UINT256 } = require("../../utils/constants"); const { impersonateAndFund } = require("../../utils/signers"); +const { ethUnits } = require("../helpers"); +const { setERC20TokenBalance } = require("../_fund"); const { zero } = require("../../utils/addresses"); const minFixAccountingCadence = 7200 + 1; @@ -24,6 +26,26 @@ const { const loadFixture = createFixtureLoader(nativeStakingSSVStrategyFixture); +const testValidator = { + publicKey: + "0xaba6acd335d524a89fb89b9977584afdb23f34a6742547fa9ec1c656fbd2bfc0e7a234460328c2731828c9a43be06e25", + operatorIds: [348, 352, 361, 377], + sharesData: + "0x859f01c8f609cb5cb91f0c98e9b39b077775f10302d0db0edc4ea65e692c97920d5169f6281845a956404c0ba90b88060b74aa3755347441a5729b90bf30a449fa568e21915d11733c7135602b2a3d1a4dce41218ecb0fdb1788ee7e48a9ebd4b4b34f62deea20e9212ce78040dcad2e6382c2f4d4c8b3515a840e1693574068e26c0d58f17dc47d30efe4393f2660dc988aba6166b67732e8df7d9a69d316f330779b2fa4d14712d3bb60436d912bab4464c7c31ae8d2a966d7829063821fc899cc3ec4a8c7098b042323eb9d9cc4d5e945c6d5e6d4eb1b2484163d4b8cd83eea4cc195a68320f023b4d2405cda5110a2eea2c12b70abd9b6bfb567a7850a95fe073a0485c787744efc8658789b0faaff0d942b3c7b89540f594d007936f23c3e7c79fabfe1e2c49199a3f374198e231ca391909ca05ee3c89a7292207131653f6f2f5f5d638d4789a8029001b93827f6f45ef062c9a9d1360a3aedae00fbb8c34495056bacc98c6cecfc1171c84a1e47f3bc328539dbbcd6c79c2aebf7833c684bd807cc8c4dfd6b660e64aece6adf659a969851cf976dead050e9d14aa9c358326c0c0f0cb747041830e124ec872fcf6f82e7f05024da9e6bad10319ca085a0d1519b04c60738043babc1f5a144655e6a28922c2734701c5c93b845996589b8fd246e1bcd97570951cdbed032eeb9c2ac49ac8aeb2e988b6a5513ddcef9ca9bd592c0bce7d38041b52e69e85cda5fd0b84f905c7212b299cf265ee603add20d6459e0841dd05524e96574eebb46473151ec10a08873f7075e15342852f9f16aeb8305211706632475c39ccd8da33969390d035f8a68324e7adced66a726f80532b425cc82dd52a2edc10989db0167317b472a0016215dae35b4c26b28c0ebcf56e115eb32231449812e9ce866a8c0b3128878d3878f5be0670051a8bf94807123c54e6ea2f51607e32c2fe1b132c905c81965dd6d2a7474aa40b65f18d34084a74ba9a21fbdfba3bfaf6b11175d85f03181d655fda086d8dbe2f03dfa2e1b7140b1d9dc68fc9e22f184ed278599d29f6660af128e4c548de6926912d920e35575db90338a1a840f8d8842685f5b459fda573eaf5c5180e3369fc50faa681941dbe7dec83ee9649f30c1a0eac1f8a42fb3083d9274f4c622e2aa1e74b70fa6c027b4f23e1f80bfc4f69248b4d0b3e0eee9372869f97eb89d8d155e469191c48834ad58dd831f1b73409d71fccb958b6582a4ac3f98bcffff2abd393cbe64d7397ada699ecc75301e3be9e9b4ee92a990202c6a5e5112de5ea9cd666f41cdac4611575c8efe2137d6132cd4d4eea0de159eab44588a88f887e4263f673fb365415df537c77a4aaaee12dceff022eafcb8e6973eec7e18eb65cfeefa845b79754ec52a9270f0a7e570b1dd2171e629d498f34e6371726fa8cfe6863f9263c5222a953a44612944183789ad1020de8da527bf850429558dda7896059476e497284512c946d7a57acda3c3ee722d280c0d0daf758d6be88db48e96e14124832c38aa6d0dd38baeb4f246b01d7b0beb55c3983fb182cbf630b778384cc13ab6216611bc1eab94ffe17bb1e829700c99ec28fae1a87eaefd9c8edc4cdf3b6f2b07d85e0d8090ddfb2df4280dacd13a1f30cf946f5606940dc3f75622159b1c6f84bfdbd4ba9fa0f1d522f52bc2049da53f0d06931d650ef1274eb0247844c36349617095f9734e89be683fd7bd5001b416d800c53ec8e8eb533c418a83e803daf6fdfd552ca745bb2b24d8abe899ea89572524343386a035b675e9d5eeae81aefb3a24397f36fe501c66b27d1c0e453fcc975c888d9d6d5a4ca0a4b32b41deebed70", + signature: + "0x90157a1c1b26384f0b4d41bec867d1a000f75e7b634ac7c4c6d8dfc0b0eaeb73bcc99586333d42df98c6b0a8c5ef0d8d071c68991afcd8fbbaa8b423e3632ee4fe0782bc03178a30a8bc6261f64f84a6c833fb96a0f29de1c34ede42c4a859b0", + depositDataRoot: + "0xdbe778a625c68446f3cc8b2009753a5e7dd7c37b8721ee98a796bb9179dfe8ac", +}; + +const emptyCluster = [ + 0, // validatorCount + 0, // networkFeeIndex + 0, // index + true, // active + 0, // balance +]; + describe("Unit test: Native SSV Staking Strategy", function () { this.timeout(0); @@ -1015,6 +1037,116 @@ describe("Unit test: Native SSV Staking Strategy", function () { } }); + describe("Register and stake validators", async () => { + beforeEach(async () => { + const { weth, josh, anna, governor, ssv, nativeStakingSSVStrategy } = + fixture; + + await setERC20TokenBalance( + nativeStakingSSVStrategy.address, + ssv, + "1000", + hre + ); + + await weth + .connect(josh) + .transfer(nativeStakingSSVStrategy.address, ethUnits("256")); + + const stakeThreshold = ethers.utils.parseEther("64"); + + await nativeStakingSSVStrategy + .connect(governor) + .setStakingMonitor(anna.address); + + await nativeStakingSSVStrategy + .connect(governor) + .setStakeETHThreshold(stakeThreshold); + }); + + const stakeValidator = async (validators, stakeTresholdErrorTriggered) => { + const { nativeStakingSSVStrategy, validatorRegistrator } = fixture; + + // there is a limitation to this function as it will only check for + // a failure transaction with the last stake call + for (let i = 0; i < validators; i++) { + const stakeAmount = ethUnits("32"); + // Register a new validator with the SSV Network + await nativeStakingSSVStrategy + .connect(validatorRegistrator) + .registerSsvValidator( + testValidator.publicKey, + testValidator.operatorIds, + testValidator.sharesData, + stakeAmount, + emptyCluster + ); + + // Stake ETH to the new validator + const tx = nativeStakingSSVStrategy + .connect(validatorRegistrator) + .stakeEth([ + { + pubkey: testValidator.publicKey, + signature: testValidator.signature, + depositDataRoot: testValidator.depositDataRoot, + }, + ]); + + if (stakeTresholdErrorTriggered && i == validators - 1) { + await expect(tx).to.be.revertedWith("Staking ETH over threshold"); + } else { + await tx; + } + } + }; + + it("Should stake to a validator", async () => { + await stakeValidator(1, false); + }); + + it("Should stake to 2 validators", async () => { + await stakeValidator(2, false); + }); + + it("Should not stake to 3 validators as stake threshold is triggered", async () => { + await stakeValidator(3, true); + }); + + it("Should stake to 2 validators continually when threshold is reset", async () => { + const { anna, nativeStakingSSVStrategy } = fixture; + + const resetThreshold = async () => { + await nativeStakingSSVStrategy.connect(anna).resetStakeETHTally(); + }; + + await stakeValidator(2, false); + await resetThreshold(); + await stakeValidator(2, false); + await resetThreshold(); + await stakeValidator(2, false); + await resetThreshold(); + }); + + it("Should not reset stake tally if not governor", async () => { + const { josh, nativeStakingSSVStrategy } = fixture; + + await expect( + nativeStakingSSVStrategy.connect(josh).resetStakeETHTally() + ).to.be.revertedWith("Caller is not the Monitor"); + }); + + it("Should not set stake threshold if not governor", async () => { + const { josh, nativeStakingSSVStrategy } = fixture; + + await expect( + nativeStakingSSVStrategy + .connect(josh) + .setStakeETHThreshold(ethUnits("32")) + ).to.be.revertedWith("Caller is not the Governor"); + }); + }); + it("Deposit alternate deposit_data_root ", async () => { const { depositContractUtils } = fixture; diff --git a/contracts/test/strategies/ousd-metapool-balanced-pool.fork-test.js b/contracts/test/strategies/ousd-metapool-balanced-pool.fork-test.js index 1cfac51a8f..5267a2f62e 100644 --- a/contracts/test/strategies/ousd-metapool-balanced-pool.fork-test.js +++ b/contracts/test/strategies/ousd-metapool-balanced-pool.fork-test.js @@ -80,7 +80,7 @@ describe("ForkTest: Convex 3pool/OUSD Meta Strategy - Balanced Metapool", functi const currentBalance = await ousd.connect(anna).balanceOf(anna.address); // Now try to redeem the amount - const redeemAmount = ousdUnits("29990"); + const redeemAmount = ousdUnits("29900"); await vault.connect(anna).redeem(redeemAmount, 0); // User balance should be down by 30k diff --git a/contracts/utils/addresses.js b/contracts/utils/addresses.js index 9e99c8e283..c1d5e42395 100644 --- a/contracts/utils/addresses.js +++ b/contracts/utils/addresses.js @@ -126,7 +126,7 @@ addresses.mainnet.ccipWoethTokenPool = // WETH Token addresses.mainnet.WETH = "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"; // Deployed OUSD contracts -addresses.mainnet.Guardian = "0xbe2AB3d3d8F6a32b96414ebbd865dBD276d3d899"; // ERC 20 owner multisig. +addresses.mainnet.Guardian = "0xbe2AB3d3d8F6a32b96414ebbd865dBD276d3d899"; // 5/8 multisig. addresses.mainnet.VaultProxy = "0xE75D77B1865Ae93c7eaa3040B038D7aA7BC02F70"; addresses.mainnet.Vault = "0xf251Cb9129fdb7e9Ca5cad097dE3eA70caB9d8F9"; addresses.mainnet.OUSDProxy = "0x2A8e1E676Ec238d8A992307B495b45B3fEAa5e86"; @@ -279,8 +279,12 @@ addresses.holesky.NativeStakingSSVStrategyProxy = "0xcf4a9e80Ddb173cc17128A361B98B9A140e3932E"; addresses.holesky.OETHVaultProxy = "0x19d2bAaBA949eFfa163bFB9efB53ed8701aA5dD9"; + +addresses.holesky.Governor = "0x1b94CA50D3Ad9f8368851F8526132272d1a5028C"; // Address of the Holesky defender relayer addresses.holesky.validatorRegistrator = "0x3C6B0c7835a2E2E0A45889F64DcE4ee14c1D5CB4"; +// Address of the Holesky defender relayer +addresses.holesky.Guardian = "0x3C6B0c7835a2E2E0A45889F64DcE4ee14c1D5CB4"; module.exports = addresses; From 0a0e9da019a31cd132ffdcc127a070d88c120632 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Tue, 28 May 2024 23:23:12 +1000 Subject: [PATCH 110/273] Updated Buyback value flow for OETH --- .../docs/plantuml/oethValueFlows-buyback.png | Bin 105309 -> 107174 bytes contracts/docs/plantuml/oethValueFlows.png | Bin 491809 -> 490197 bytes contracts/docs/plantuml/oethValueFlows.puml | 23 ++++++++++-------- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/contracts/docs/plantuml/oethValueFlows-buyback.png b/contracts/docs/plantuml/oethValueFlows-buyback.png index b46c30de9c1320b5d2f2314687e1998011b03618..4a54ce58f296721ab144e374d07c47866e72cc99 100644 GIT binary patch literal 107174 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

fSu%3FR%T^g1xQlYqF{Du49zm1ikn-1N5{v; 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 literal 105309 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 diff --git a/contracts/docs/plantuml/oethValueFlows.png b/contracts/docs/plantuml/oethValueFlows.png index 6493f33d8be6c8f0734c689ea3f643d2106360b6..5f876f0766c11dd9fc5e5068c8035cfce1fed6d4 100644 GIT binary patch literal 490197 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ⅇ3oY^QqHuk( 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

fE3Iy66Q~Uu%?F$bVc3{JN)E zB)ZV4#BfEmoOGV5rVJJVjO_pskC(QsA6S@wLW9*Up@L_vWbC2@qqCmE>Joe1a2%Fc zodTC*S&$ta`2im;{oaMka2h0G55fa0a&xN*qAmo5;PF&7XQ3P`qOeYo6vii_)rF&R z!ryrDgJTx8r2@O#@=8izU<4fRq$S*&g;z9KNyn7A$L>Ol389@0ljtMiSJWR|+j@d6 zHc+32 zB#uR`99F+9+LkN-zGzPy)L!teiG^!$+J#8JX{;&f);H~UMm)?!52=VsZl779@84EU z+e)d~^CasI6ZBO-TFTy2m>trr_Pa!MZ-7dCW@bjr=700pkLf*Z06l$D)wf{$Dxg-9M*lZVJ>F|C$sF&e!Lq(Lw$c@ zx!@9%;`Q;`qxZ4IyVJBR%ME@8K@Kz3YQb2FAHW(qi``YaTq4&Eh7ygT#Ek?{W#a4b zXEtHV-YkdKS(le6N)${#mhx!>@~EHOyFJnE4;&xU%@uHWQ?OzqKHZ)ka+rQE<(CN> zDQ9r1^s-`elp>CUD8ss?=&ss@C0rP?MUJZyG`3PuO~MRw9DcAb z%m$no;$9did_i^iW=+pXc!D`XLO~o12fswtO4Uc8Qt#Ji7t85>ybR>z%d&G%cojW{ z8{?E0CKR49%wz}}fyXA5GKeMC#lp{e6I`yl3-l_{obUOsg z4bBeTzZlZlVOjqcKFPWJ`S=UyIxbV7+;2FY!9&_oXoWmtvvkbnn$DxxSoGki97=SZLi-pz6EV59Bm% zP9SaycAKNGtwUbcwcURool0X)s6e6I*&Nuxqm9B*S{d_&9%Sh(LY_!rfCTD2Fw*F` z+H!j6$gWy%XP=cfk=nI0QIo7Cb|57?}BJz^;EJ1Mqw+vmFZIe1%dgj;6l$$6KL-)vFYN~8D0 z^XzT$&8jLVU~JAM8mse1?WA18N5$^e@utNNESuF-8lQ$w!;mgqUVV4VBWfRyfxM3l z>^(y7SA)_TJH4L!r5qYCdoUzm3pTW8S)+7esWfR@YkWMJL`!iOlFkOVZpe7zUp(%N zdFz1lJf8r>(OhR=FRqji6iHUEZr!(lN zZ>*I3UMl`PeILtd=m=}mVwM8rRp0e9cno_otyUTMeX7^KzzTfo@loinU`kt|>oBpL z$C}yaYXW*fEkhff{UC0B+@i3*mU4d#rrK)I7{YetIQ(8wHy=yvc6q`THe;I-nQCHt z19o4iM=wwC#$`T|Dz~iewABQ1PRayoWSe3}8>d`k8RPAY20h zRAFQM^~~vS9AZn*Jfm_7fq>&_rZeV*hfc+sS_%M)Y5t_%Zg}y?#dq?y_>+5OyK0fiEI|vuCyM|Di$kW}~8pjfR2FSUD zyVMr=C_vRuhLJ}d3k+iS?yGVks*t;m#o;t+r9Q3LgVd*ce-ttqJiiv4yao_8AtFss zqcoO;<7uctu;BU?k$7Kb#fP9Da2`BKybnj3IPi9Lau*>hB9#AjvlD72C|#%IN5TBF znwc%1w);nK5I&k8+`>p)NQDF~All&I(sVKS1PYV9<=PyWJORs!wDN3fVc5V-?S-ks zrM9ClX;(;rdkViFH>*|RPA1~xTQ8*|0HRs9Ze8cZ&T`~5Ud*DLH8q{kIhSQQ>`7E{ zqovqS=4OOiX9BBAW~yi#+{c*)E4|Te_Fv9l!~9_U-8#6)^>al<7N=%Z%pi$e*lgZw zs8m?3b^{#lVhi)fOxGK1jU29(m9ZhHl=~dG92{>Wc-^+=gZ)5n^9X;+Yw{eN9OgHwlYfL04cK#K-zFYwZ2)=E{X>I=(KQTj}Gtt{9s$I z?LrAGEF1*1#id}lgpfmZ@yP(FfS+MiUAG=(-FNXLzP7ixtumc(iAIbA8J-Kvu zJ$GBq*#4RJkHNZTR}&r2^)nMw22YK{2+jy5S(h)@Jf!Ee`Fw(Yc}M}pm---hvNp%( z{%y5$fBkw6(>o^T{HJsHR;iv8oMkQ_;21tlPgX?DEPb}^UJ@%Hfx;!#@HL`so@4J2 zYR>xrH>8J0cFH3PRUDloxhMv`MQi4AwmkYnk!EPh9>-SIS+6!fm z;p21D%{1u98gmaRh9%gphxBKH2fzyY^fdiq%1kzs=+e()>Suj^B3K~7C!Pksd}$x9 zX4<*bvYd`wMDe?kkKV%1C*6h4)i(v&*Ce}`L;K>o?yBWmW(+M*=$Y2E-BF3TMl$I~ zh59){DJC;Z;OIVrDWFbR=6A+vMP^TMZhd#ALoN#LqJP$S(;0#zU&0GRT+;m($C?cy zI=E^q$L*Ta9~GBNY-j=;Ot87B#8E%y-*nO`Dw}Bia^ft*Lfx z_Z2Xc_ML)uZwQCpNprNO3?`Z7&6UFX0?yn4yV#c;-#E?7KGg@?6DJccZ~C@FRVmT2 zJW&gqS1V_a%^Rt{_YS!O!F~nnKYs(BV0H6N5L!~+eZzl75Q#r}?wkMYxf7ltE8C@h zi-M&LXtjf=GhuKlPYwt&K*Wg1SYt3!5&8&mY!zFArJrl}Zu9?P@4dsKJk$SCTs9Kx zBsN48k{Cp!MNyGDF&3gIsHliEu^~|yPrTo= zd9M=hk0sBEaTS+VT$9fhP*-w$PHECr`=<}uXe7JpwaZi1sW$N0B%QmKr3JqQ4!kYt zsvNFIl{|yWV%LugT=Gd#$?{&N!TwXs&?{nkeJguk5R{4<{Zw+_Ek~Qg%!{fdmHve9 zybm*`5uX#Jhl`6SWpR6eV?mGTi7k@*PX_HOvGcCnuzG&L%B_+%Tc)oBR`KK9Hks~< zsJrDEs#<`NMwW~#j)@%%91}#DY)cmkyX(d&I_nG+PtCwF@r>F=O+puURf&HzfO9lD zZAp`HQ6MFicYy2EYr>h4oYP)%3*VHsp!KAN=SunO>aI^{`AdAJkgGNKy7x6oEw(S` z)*K0y)~N}U(-u75mHoJ=1$~B}zfpBW7Rn0}31EFE9y>hCi)&3wI$k@IL!|@(EmUYg z@qXW8hP>k%Dm9(FkR?egN7;wD7zC(37OsAL9u8SyKbVXmv?1& zQ6P!j+t$6Sx?O1%Web+vjhyRk#ZkgMYpad@)bW$J))89zm4!!0RdNO5y~XN5xYE#- z^cq^t)3Z5&y)DN}&;|82@49|XUTRWn@XT&;k1^?JpO8;yaH`*$db2%cqy!-eu`~8V z5mY3_2_nbQdyLK1>)yj?BR57G-0hL}2{xg~e(h3IcmO?|ruP8RTTPMQ7T736{Zn-JnGGr0RqEO`g=3+#+k^#-FvX3{ zbNNK$@ax{bkNVW>#t$|3ZBQR%<{;LT2ox_W8BpBI_EG@nlNmFaYrxdG+kB)kKjL*< z!=FGGPUzcUu5~|lj@6{1s5e)EPnb3jvSPL;I9Q=HowbC`6LA6!y*<-k31_2$l^iP& z!<{ZzrAV*T8|05?BzFu#0{e(UH}9V(PhH%WH8pUu=>)fG91ynRWlJp*`!hqt1J>ka zy)QCB?i>0~OuB_$BtSK(;bL^=1u^?|&{%=aBXo8sLxJvA#t+ekaqkgK0K3oTqo0W} zdCFGEyU4iAu-{mF4h;8b(Px9`v*IaOTK9LE@R zezyNvb>;&iR&d~cR$#ETC}_oGEqBgE$P9*f_}%0FE?gc&PU3Rv-+Uu2=$0aLt50dN z$*s4$h@^RZv8#h)2WxRe{vqm&F`qc>wOGsgGKf}eOcUi@U*T_Afxcd|a;TJ1P@^+y zlEggvnCOz1s=;GujUCYoJ&bjdEj%Ctz z^Aj}p1N=3SJBge2V*W`0pafp}W8AEaYeN8Npyvh5>K*|=71@RVloTD`hOpl;3~8B< zAl%JE+v3L9gEPOdEn=KU4d*ME;pDGwI3$^ab+ucQ)LK;yo7hr z2cP|_{|^x=GCNS}5mX*#`WPnNI03o<$%7 z!GuzYOtWK?WHDD!OHhi0qi*?qXvTD)xH?g7UgUp57eO*0+^OII4U=|5vd7wp2Qp1q z3WG=%?+P@1MPpZnPLum7tOax*P&+V0&YUVY8lOgfN-q^D(!CcQSeKXp6}RG8fuF;+ zeH(2maH2>rjfD}Ws6^uYLp2GBO(TTGSGlx}-m5ga(8V^wu~Y%m50HXufp?I3@en{F zs?)Mmk3;CAY9KxJeaRCLNJt*g4i6;C@fPvt4W&PP#Y57lWUx< z&8#V*-^X~vceW+gN?5)>c9Pqcc7>;CGhOh)k7*#7$`1KYy$0P-iob(4#c^I`M>@X~ zlGRE_kue$=JiiFf)~I24aN6K;k>fnwwGa;CU%+;i3$o;@>^$`a`(P&cHV%i?cl8h7 z7%5*aQfo@O`<|HWxbsc%X?z31!l03BQp{U!WqK)yV)U3o6~^L2&B8J9AjI zgh=U*Nn@AOMg5UE2}0~7VA*Ggc%{1n=eQJaEb;>hMiudzaIDk)rB0=HFkbo6piRe0 zrEq&H#Qf<(KZi@Hx1oXb3thQ9Ll4?pVV*ie#m7=YqW%0RI`!9!Yemf0Qh=k7!dw99 zC!J}7@*FAHprf7oE6_t+eTA|Y=vl{K-_LC=iG|VXO!FTBX6{8^%KeV3h#eN_gj;PM z`-Ig&z-Xj7+7AH~6QhZ*Rv@B%7oKhQ>_ab)zy{KBy2T4C0Z|$v+{%T;HKY>V<|{|8 zg<=7&qTqt@2RraZ7p=!Y#BC_10eG}K|&%=%RjGCeQ~*Vfqka{m1Ji47Ocjey=< zlNlpXx@9!2Y_{O?IzmkyU>MmrR&wcr@-QaW?`BISU5HVa;Da7V-SVCe$=jgq9ei3#ptc7rB zTMWlY{Q6DLhvNQU*E00~z6KdmW?&!T_Wpan3iR|RWm8#JTJkVk9_k@feRJ;ShS60m z*inKV7|8wU(~?b(HeBjU)aH%)tninAwL%*@&v2~|-#->5+o_z^8N+>R<3PeX!;8P! zya&X-J^Pj*CSHLHE>=GA$=*4N;Qx;W{2&42m zo-k85cGp)=f`X}hm$7Y_M=l^_PN}raNLx*)Q$FC^Um)r$TK=RJ-+o%buxzcbf0!NN zkYfKzH9@cw#g)}7VvYPT0gVXhI}8%pE&7w`%gnJOk^K}~fLhQz-uM=ivxiE~-4i8; zWHLcKDXJt@F;Wkcg+)nAXhmnPVtOW{I*-u#NbH{e@lS1=$j!9tyXdDW>b+d3&wr^b zJM>ee;h!=ofUbf4P!jD+kcq`uLDWmGp~qQb>I7BTW=&9aK7;)jz_D(PbTxEQ5CGDy zRzNoG-S{%ZD)UY6qSNnNq!CHU72}H~hMyGhxn($RKm3-HV+BPg#m8i0)u4DV^gOFH ze?Df(tOvpbM8@--nXLfJS%WwySHFfq zYqw{~jeo2j_3Hb^aK;?nfwBiWY304fy`9{FQ-A}~jOm9uWi?W7Oc>EvIC!;nTc_$C z@|H=6uhiTjJeEL_)#}bBi=M7goKuz1m6T~}FA9}!;H8a7u9w~60{TVe`!-9kBec&%}*0@zV z`Aa*Bw+w5Yra>8W?EVL7&h}3l*YASIhyf9#v5w_k?;Dn6c!t}5a{@JF88Eh2SIIiK z63Z01t*`x79J4Tq-+KxfSPBk0w5Nw`rXOlFGEC1rCwKdXNfPA=^a1jb z_~`Is#^Kfr{Xd`5&n9%r)2w&nf2U6gcX}>^;8QhW1~#?D7Kx6m3`Z);EgY|^?23P+ zo*b?0`f#@jzl_pB4bf6w<$uyN!O-colN&Fo1zWsMX>Ne}VA|uK7lxl&dcAZ)uu8ZY zpr3kUchcF*F#w$F3kcBG263R&Azb*{xf?XAkm{iZmo_`b2ukM`0C0nsMU{vpIiEae$ zt_75Oilpds$wzapZG=bfnIB6mK>qMM&5>g#DF=~9K35fusl@j*g4=L)*e#Oz*Zp$+7)*@9wVIIn5GPbe_7H0EUgVTbiNI z@yayqs;8Jw>#TpZqGFwoYrBR?7s(dbze?qb#MCuGtAYNCSqAZYQ@Q?++8U)V+o}s4 z8(IGH2M1deg>|Q*l*zQ~uO1Jyx@4S=o!a$aUytEUYwnBdjB(QG3Eh5<1ih3oLrwg% zIxl9t-i9@@7EZF=k#?kG%12-5%<2A2qqEH9K+bO`7BmFjg*DP=FigXKaD}X9n)&m2 z&pIVoy=N0ho`2-}5Nn@MEpgI0RgMI+B1h%(?r2_TtlWgU_PeXsCNRnD$JeZ<{L;vo zySBV{+V$y{maPNly8g&CrAYHn-bT#rFJA2S?^sWzj${dklyFSHL@9rzHl%7X~WiBTSQZrre zEEl|)iIHU8o|H{$g4Q-SBz*YPof2m9^nD6iis~-CW^72iF)1c-l6x~tCu7CY@)XS) z^{Cyw*Vgjpw!LjT8cxmeKED2V)tD)aNpl>MTXL~it)%aZ-FmP5whm={Q>LG)x!kt? z*a_#oSi!cZjnliW=_0R_J~$Z8KWs>urt0AmRbrSPeNHqx&*zC4>+jSY9X1-$K`7p7 zJtwS-Z*SZM@cNn6OiLP0G028(LTSB0boU<#?T_!`MKwc$-{Ex`c*^yrPu(iO`FvXc%p9Lf zIs;>9wb3Pky1m^vExiHJ-?VUVx!KfEzt|GZ1l_=x_ll2#BWD*(T$!@5Lg+aj0Ix zq&F>ify8K{Zv(VpK`4rRH_hxO)TBeyPD11y?up4<=~SV2V$S)2BM46}j^6 zj=Poms+u3~qLO#MQ=Xa`lAT>8V=3yM%a}|CNpOx^+&hZPfwZb8sr8%@E9SVvx~s&# za=%XJc_DhIM(8`FbzU0jZfKFU_+IvY>xqPn27)5EFh-0`ZdFrengaA77uQ*BUO?Nu zhq9@CayL{=0bPG`2?f*Y8k*pZB&$~>EM$6hwJPg-rTr%Uizox+61+Hb&#BK|cHbJX z#te0jq#LTn3ftF28$Pfq60H)?cJq2-oqOUXI#NQ(gTAS&|2OvS;GUOkEG78e+G~!G z)b#GQyBZCtkVlH>{+!0oL={>Ur^M#2tK^A?l^M0_L|ENvonGwcay|z(gTcN&M0|kA z-&YbdU@aOfMJ3ymPnYvKGk8Cfi^qbujt!Ee1D?;OOHT`rumbf2Om2I;tJT$egB6Cx)!0l( zm52≦8^kfq9A^9!Yv3#un* zJfAeXl+t*2oZsOv$KMh(4 zAv&vnjrUqum?Uv+Gkkv2cJkz&we~mf;A;1@;!V5vKiH^Xd1=`sc_&Nm+x{jwwHA%q z9Mb0Yv8K&q4=8UFq@*|ioN(yB!de$=rMOaj=xF^9S247#OZwVCyT^gVUuJa&Z;pF) z?YMBRVS3-9rAl^ErI#7a^+72HCkEfzm%z>w?ZdCk67TuJLX;33q2g)UV6`l)Q%3J0 zM38S?zx5ipmq|N|7olVxvG(D)t=JjrQx>!o7Wp#s+_&=j=wbvvy@7%V%+?LK!o@|nmxDsx>=W? zPyMRRniAgLHYw{EwY|~DRZ-3OiC*L;tWnZ=l3U0uy)5oBBzU?9;qN)Q#6=VQ?Y+cD zq%-xVm8ZUTs|sJO?CO%TUHzHu(J^4=bKC=DXpRuSJR*=MNnu=t)~b)1+*gXBpAz-= zDA?nyXw{3GAO72~C!HJLkOr;HUC85w!O8Bja_ zawkwI;sD6c&lk2B)3gC>3k2SKh^irdJ=0hIhtm_eC>w~zH)ss`MiKmn*GZjx z<@?W%nrKBy>hHmrzY>Ki1eU7)vxM8k_uTt~<0ZLUwp&L_rhCP9q~`3z=ZpDN!G!+m z$~5SRKlmg%?4+O?KX!7#(?Tjceq)G2-`4Z_c`thv6puzadRp)Pa$EA5KO)zxf%fjP z3Oo}0-HsQ%-)T)CzwR(;-!xxEXPB%U>BO5?+QpUW!c7u4 z&q+f0!>GO8;t-Gn1(0#h|&pW?z%yR257-e za@t{bRmlVVE{41sz%fOVcJr0fD8rFNzOY8!IWyd0wX;8Kd8Xz1uw_MRWBx|1bH5J$ z=I%i9`8e^@C77HHP(8+)p>Gifn*k91bU|+(5cKujp3m5^l_qRld3gMa#NFTui<;^X z&NIt_+ihj=bEhsZ<}j!g&`zs8u56^!@vuIB=F$V(fD>edzzWiV)E+|2-Ews* zObZ1^`FBlYt3lFkjj;&P9k~^P2|_U~z4Qq|u`L*OHC;&g1SbBlI>z@R?g(nF82tTH z=dJtQVjIFXvZTwAZ8iu=FA*>&CrUX0?z2cmKp;`QFXmo1Hn=E-3DcG2Lb{NdvTgSQJu_iby2=**8Rt{G0L>&7xgII9~B?}2*kZN2A( z(6uZFkA%#(nK2s3cmzSUj;=4{&B0Q-=-m{MLNFAlUF0oiI=tt-ezuNBeizs*oyJSM z$$k4NiD|943p)0Pq!{b2kQ<)(jNUv^R$;mUxRPSYn zprHj9qfaIiu_+|6B?i&8W~rpo#3FFu)`-al>&&k9>hhQKoG(~l(T9KlqjYhW>|R3;J;7qQmlWPez_zWqn}ZVc=zl9V!SQh`q!&`IyrsaeLqB=QfS<^zb)? z?G^G-G-`-r^lQ!ls7Mf9xEicM#Akn_XOli}L@!5E@cx(_fGn`BS5?aropvQQ4pCm)a#tu8c&F5L zDG*m)*&UascH;e&{+_-> zapr?YY&O?MQ>Ht(4%XX41RD{PlG`+-JNuzxL@$)-u&73z3Dal?cQ!+YO#J!X(!+(s zXrXQ6Kw;w^bccLj@&y^%1KJ?`Rme_!r5u|&MVJWXCWfCOB~NG23BU&{8&F0i98!`& zy2y?~wvyboFvt>)DjQ#3tkm-zB8|rd+h&@m7+S6V0-sZH=re;i;?p*M5Uq(1SlxnI zbs|@+QOAh8Awye38$_51f!K@* zD9-v8801!!6^o-}MvQmM&ER>RG(gBKeIovm=Qm1nc;`6bxeoMfQ2vw={$SId#LaU@ zARA%+-O3A0878}e!zXj6YKU-1-V{YbEL~DxU%#?RYU0fAtY&Dtb3)jOIl~{NbFJV`!qstKfSG9mvgU&W6rZ3o`H2GLvia3=2I) zK_afDqAT&our*<~$Q;yYrV7^QmiZ*tK5}db2s`-mWtur7G9AgRFGdki@OR34i4 z<<3ySFlTjp$-MUl5eoGc+ulntDS^8`GaiF$?tDP6>3VfFf0cCjoN)SLkN(q?0LJ{m zo&d$JKPnSh@E{~5scwIy-Hhz4lSXxl0%#+eRySofphhziwASsRkxbM3U-wPnFkGty zj&#ry+nr}q+aFj`5?Q_LW_6334hj5hVIORPllB%CEFxaVm5^)^|0*lDAH)>uuzMgD zkh6nhDIQbh`I$QFF8%T&uMuKwguA+OXq8B-9xM1L4dGkD?|<9$`_X>?kEEI8&|ouX z6(6vL2M=CejTO)wUuRycvyyBDRl2lAcc$a5S1&N&Kc_@pj)uW6MOS!!=-_GL5+ zsFA}S=bbaWX6f&&QHl&ZN6=7o(f0b@8E&)LpimV7| zb*L~6==L^KuH_MG^{jBF3+D_fQEjIt1P%?LN;Qi#>bNOiFp)fYj%&w2iFmQf9h1lv zwqRG9|B&|);e$$wm@?>nH=GmF)lK~^AE0V;?K#4W19)Bim%?85q($tE!^(g{f*c#2H?U4tN&fW zO8ISs2ONOumZ(h)@fXB@?PXV`$oIU;bUXTnJ5HSPW(*DCE`;IHd6ozN3UJB*QbQBP zy!ghN>wt;H0Gc$c1ew6~PNW?yP5qo)I+{mXwnKb%1#O09(?#DLIuZ$QBi@x%8X3}FWA*O1IZz58ItYK7PGXrB!c_B+vb zFJq}fW#NkoskF^~W}=$Bq%3TKjB)FtPhPh#Glpa-WEp z@s-XZYii=uDHL{-_0dOW*-sie^Ga8EW6MQn%J0oncdJWS__vlAH#rEqk*qqEj#jscQ*}++E6N0Dl@9`T3rVAlkUA&)C662ECC}Z2t^?nnEy=KkXI{A+8(VM%Wm*gla*Keuqwti=$x zab2^2*H=;fqIt0-f>50N>IeNG)_VSs4$efNp3eQrLXPSM#i#A-b7@}?gA+SWyRSH@ zNxrN{wTDl505SrPNLgB~KexA=4`K((+mDCtWjt>?n7( z`xV@h|2Lz2Eujf26Ww|VV`ZNC!xvheiF0uxwiactej8}dDa+Ag?EWmWBhIWy zMr;(xM~>^K0y@H{NB2`t_v(cP6h2i$9MF%atDIiltCOxE;^%1a#eCJCIj$~G$b;23 ztK|E;Gf6UVR6B>iyBBI2wdp3zOX*@^-Bvh>;3e5*{I@5G-^14 z-#%z}W-KQZ|8S12e5E)&M?*y9v^pn?5fe-}4ZJ2rN6J^Km>3D zsdolVZrXK$N+T#+>H4vP;f#t6-=B-*7p)`+H`MjH0}p@fBnxb7>J)5ALr7P&v~ z8u2fr#M6CD~6%u7}VQsxS-ZKV_Y`y zw{oM-Ju5%W;#p2_zx(MPay}jh^@vJU!z%>J$7)f>rpV*^!q&&jF*%?NM_orf+NaNU zrj;);K3~&B$^j&r`=8KlB46>^PIZC2{U*x$G?Q^?xJ>_up6dTG^CJ!BkdKtu(#8rx zG;2uW$~c#ebbV>)Vr*Rxs?Ys`VROqz6vN0;@g>id60jaR^<|t;OTN-C!=N>>7ya~k zAl9+BU&$xHckq(v{uD^u%of}RyVGZ@67wyif;I>hUG|foiTnVJ$&i|1i^M`!ZqU5- zYb#x`!LSY%s(&Q5{U;H;R2=>7m!b-cm;Qo-38#IXxF@i%qQz~X>(0N?LOP^?E$i0S z7|BVQ?>4d*Y`FFkb5DlFkIF)A`09M%G+$HaD`w*IThgl23KuYCXfWD;=ml?Dlnw6> z3r>&JrsoOcc86Q#FKF|!>;?~!NOIm=dKCiR43YN{%UU9`>|q0)sYYAU6?M(ctBE3I z?BjYM>1Cc_QuKS#;#vle@QW8lp>lt{tVT?0uadg7xuL4t=6J?y!_8YSKl#VuAAaAw z`PT<&;~)HdQT?&+WzE&+ZU=lbeeMjEOFOQO`{UZqYvZoY|91Sm!^f|vjX!*4;o-l& znKEO!-KLcnd-ZIrnr0<Z!-=RXn7%Kar(fU z#Y5zfuU-)D?iwQW0_4|jsjbmckKF?+eW6a*!>m2U%}h(@BC~)t8#o{y1z8X7%gJLs zhiAaGHyy_i$-k}3pJ^em!BN;>zMp3CV_$Evzo-4XAl8&@h++;2kp9X8t{Z)Zz87ve zpzd;I#QeG_>jh3vm`HW@Vk`!EGMq9|x*jancZlDbu0kf0S1Td_ui|AJy(~|~{s~<> z-Z;&|ofQJudO_XuJrlWZZyIi2PxebI&y*6Nw)%cku)EBn`paly9uNbV$wH`>;a*{v zwH%(H_PcOXfTRdmLj><8WQj|>@Gj9w0s z0BzZeln*_jmD?#!OzOCkHLxbgV75;`3#z`VyJkUtUHaDb7xg^7b$H(bvfkcRZSZr9 z@g?q#SS$aV`o&NF3@%1)0f>6E>ByO(1;M&puPANdGZ1)raarX4lGBBH;*u;M^7h`| z07drQEy|J5Q`*w2G_`6-q=7tZk&1UPf+ZN@r~Tdc(SrW&{!-0Sd!0|G`uA>)jpkG< zfleo+dj4Bp7&Bv=Im35&gowHu5wuoED1CB=BXGtW{hF?#x{A4SNy-+hPl>8Z(003Z zc^0M}nHsF)Kbd$9f&)IRcdPiF72MZ`h5VXK8RCMWZDzBjuR;^ zI`h5la*MMgXg0f%3vf$vFody6X`XXjk#MlOGNhIX zbwl5T_ukkkGE0Ut)|Sf;oSVp?lmOHWO4Lh^Ni~PNs2#ot{l5i$ z=fPTd^0H|ih?-(QWA%{q9`@ZWo4R(kyV$-s4VAkX_eLgbt5oi12-97d!h{%Rcj5L& z2dB^jjfHxGXS7vfY-*xs7u_-kbUIV#RVr9`_!OAf#LCGne8`P$CMA&aRN^FAUT_cw z5yCg(+80_%isB2j+m5J%R9E3CNK(bU3x+}$KU$eqvt+t;ZVv?uj7l_Qo)kOyve?9@8;gFq6AxxZ63XzlE7MT)!{hx`i!BEnEC%=Mu&0>+5dI@a~-biNxS zM!N;>Kw4zB+Y2A{g=xU;45>=BzGAr8`bKKoAv5bLBJ0i|ZM^N1t}8=Xcg+*IQ9Iy# zTBzM)DykkjP4>dS98lO3=;Q4U)l@8l`fHCYq7+z2M-vy{xu7A=w_Ppjh`{p-b1feS z0fJSJzjo_w2jO7&Mz*gQowpqOk4mo8lnQ^Qn<2h)>Bzvf)K}t?%oq?(Zg#c{0MkA< zrlHZsmFDH=heN$#x(ml95$HL@%zyhKs_+>R=z031K+hKKo}ftxMx?uJrDGXKBnoWH zULppKQrREtFPDBO=e6lp>LMaJO>%6Qwcz=RuH>b(@3!4&g-!PYvKAXsg71(8rLUb8m$!mweH?L zzM=yLz?{H)!!xL(i6Tv(_LdxHa_`YZb9D>enu_Q5WM`7P;+RzCTESXDvH$pBK}g-? zWmn3qytWv7_v#NAaw>HaAzBV-qsh8Z?rqm%EzF!un(e;k;1jwhU)Aq~(Xy)s+)ctk z7lik2j6`iN9PC>GS)zP$*Lr~;Uw9|*^ z(c98GsAzPmM+LKfqg*Gxm?jm$Ri;riVrhHT-}ur)nE zHK?PP<%jr<)@K_(U6vm#LbIT{iCjy)Lhi8>ArZk{X}Fx5|M8}8b#mqxHVgV z@6;h0MPex4_b(`+6i1oRhzi4Kblfkt(~qv{>p8T#pZ@CcL;&2(@ZlHx^}JjU&?#N+ zqw;b;bo8-@{)GkW^WEOM>0jj6x@{QBuXTQ(Izw~|1q-cqBYX71%3nXu9z7ZLFZN^e zMg-k0JWv|Teweq#RJfB=8GSstzx6EwwOl5Dq1ix)iYZT)bjEKUQbTK`z0*f-plZc~@i6xQdXG4!%t{D#tf_}y{G zW8fYPTx87y+nsTBYKZ+W_6%0QBAM>GERwYiQa{Gf67QNbYG8+kgWy8lcf|e@ z=Rdp)L>@+Zb#`->HO~tjss<$l5CcxSy#gHkdu15WWWz7r9n@OJpWa>MVJHApMhaAq zyu~%f7y`erjtsQZkZ&n8J9y?xSj&%It#G(~aUoDVr3BGi89jvw^d%RVK9H`OF>F{U zsjO?8xI&$T;O|l0e3qaH7vPbhAie7vH6yCC^cIG1|V zKbdume#>Ev)y3(lvmA8yws!?_gx-CJ?+Y&o6kV~AH6?7TWY8F3fq0q|zu1bpq7{`I z$__I4koSj9ICPSvC_;|}zqq_&~Dt!=*Cj}YKuaWO{etutL~z>**%e0quXzD zFIpu%BczA#<}kF?eyYve_R-aTlUG<6I8yvqFJe6PrMZ##f!cQ}{G=ny*!J%z#QC8?@!jXgy@ zp^93yMlpQzwr!W}rIPTDH-4PXW*{FINu;xVUXVngNTWThZm=XwhH@$jG9eq+Rmz;1dmyV#%>>6PqQvY;-?^BqF0r+?t@N zqM0$XJ@++re`~`>aZ50f`dr87hYH0m`Q^MEsigKe5i6H3zmCkUk!19R@3PI0=u1gMa?g786XP1KF}g0}0y-#f1#tjTW|zPQ5Oyh_)8@9i_PN-bUv}R|5JYnyc+|sM zn@HKom!u`C3Y^$&Q#0$3>;=b@PT^&}t1q%Ur%H-qg*Q2xRn9y#8WBMz@f2ot-gv9^ z!q@xbBM!W}QhjAPS*ho=hlgrrLg&{S90T5T;mv!Vnv=M6kH!#!`F887hIeuhn?iV{ zJ~YBmU?EkZ385G6pg9avyDZ(RT-G1&-hh0f%q0pitA48~r{j8{HyxuqCRYfx)rn`o z-8)i?c29qX&@Ps+QghyPneITjKEC5kbP+_IYY{Qijdr$7a4};QiYtDDI_+X&Pgs(% z;^RW9&rWV#opGgfOrf`n1)qH{Q{Gr_fID5;n)w!RLfq~aWpvu%p7E&g?;sZI-ijEN z4z-jz(|+l)ibY$~bjAuwti0@j<{l%-Q^8RlrSyZYR(wpPw;=Md2q`7Z1dMy-jK|Ou zH7XMr0U=A^+=R5zKjr5b{|@Y9>#24*=M;uu4ky4IB{7q*hr~t>xsSaihfgK?ctE!{ zs)Yf7Zk<9E=s#B9%Tv*>q4nKk`0qMEG$XXxRHkYaxEuJOPKe1}LGipSA9-%3y@u7S zsWH0jU@?CSFHq28$_nIZWGjf(C9u4$z`C}@%5SLkCG(WWeOa_WrzpiytS`=^Wf}GRG zxQmmrwxzzz*q_df3fTXU&UEh6b7}hBUNNPtL955MT3n%HD55l^xP;)9vM?6!jaAxY zFRWyA!gq;it}$Y~O8?mhH{gZQ!+V>XLZx4Zl6lt^)D`#k!B-K^e}3Zv{bdVNd=kC# z&^hwz*7_6OKTyQ`*CsZcHE`Wu!S=oHRCkM}*WVp(crks7LnY9ZF_H!9`ZeOGq;$gd z077^=^8wnD@fR60T<5i~KtGg`V0fVGT?b*H%}2{r+T_SkPyIDKIr={d2;c%rzDwNVBLQWC1V)t|(?{0- z6yZ6c5}uPBd=1fYCM7X*ni#xwJ2zFMMRUx9-c?X2?q9G?w7nM5)7~`=!5m|w9@20# zMk96<9oLL;dKuT>##(E7bI{cPE;=Ue_T92+He8_!les38H}@)*qb-uh3RDnEqGErx?inFTlBvVB6u01pf0c^#c@SkY)}w zYUH{IPc!szd%lUCf!)SDAuRzPub;W}^rW8S7h-9>EtNmXn#P7m%iTEnBL~Qjq4&f4 zdhKtqU)U>IJd8flSLLRZo}dup={Au|Np86Xho82hVkAT-(85Mp<0)-L7C1zln``G_ zY#=(Qa@)uWYKcD#7~&B?-{jF4j8yc^lGK0y>bJv_uO7v)WZo16Q@WK0p(Wl9MJ^%W zNZK>l-vSrD+@jsT+qv~94+`_5zaZae+4*&x!+bAKO2Db2wbk3oExg2BFDd$qEJSdV zYiqHRlMnhtZrC>5<(-uEcFZ*HH7r{?3dJbC9yF&tfO)O1)ao_E7n$UQK{i}i)$D<7^%+BQ)`p& zS>7qipEPxz{-x(*$lqDx?dMjtpt<#iFdiqx&2hM--K60z)A*ZcL1FcUrYyP#ecH=& zh5DWE_RNs)rc|-5DjrKYH=l8XbJUxYq9}*Dy9BDZ%gN2+=!D*pm~AcW|sm3okFWb&1NSn%^;^?TZ@vfWi(zk1QcyrKc=sDyQtZq z>8NsSp~nK<7cM21mj#<@ofhy8_U2?0Ip!U-^=pJWlS1`rws16D=u;l_xx$3}Nk(O1 zow4_M2CM}*K7MbN8XOJ_A4%aQreqMzT-~QByhL+*LAQp6Q^@gTl~dCa>y(8S*mRNp zJ$cRP9N1Xxiq_nP&oLz)zNu%Zq9X)QE6s+%adYpe5f%G<~+3leSP|eR-njXL7 zk3{`}BnG~F`xZvu2@)5%9+#Nahw51VZd$-gtq*v(wLRt}yLQ0%t7lE`E5^}Mm|vyo zltfRzP*zgzvMg;hjE*UpEumkYB`!sl}T{ssmA z3q>Hs{G_SjQ?j2FJW&m*)Xl) zWbpH&rvilyomukoyf?8K@|mjFCzhL17bzal#lcY|B~a+x1_{=mFE!w=2Ct^NSy)9$_abQwpS}dpu3$1rZD%(X-0!1~Oxty7-o9 zY$nV->7DTj8LF85d?qxdYZooaiD9k}Pww8=&h|iTM@c%TqeN>d#h{Ki2!< zz{zF%7`%&ge@Zb!EMucZY_Y9}Xi3|}$2iN-&DF)zdb{D)~-i?8Hm%Y!*d6K3d3 zFQs;~PFAM{ek+R=SblrskpN@8#G8&q;}rY9HHTo%i$BMdDBD-~r#j}X>RPWO=vE6b z*jN5Ar#H~n?^Iu-ac6Oq<<4F2tKV9$Io{oW!reEbmkBQxUm+p#LDD-Pcxb>s`xbQ*Sy#l z=UNp?G{{xGX!gy=OZzFe>3b=AFBvdxqb2|0a5g1&8*fmNULf4d^aSZA@4c*!P9djY zN7?9LU4D8C_t~%pU{UB-P()OlmapBF7S$Ad z&{MNsv!<%#b&?`I?D|&QE z_-OLqze9L@{;(EqNge^mzn;qXsX8Ly<5a#c+!SObLpM2;()R^!hCY7jt+ky0;ypcR zqOkG2WeyNgmq-n&+O%yO5psq3kGC8w0Jy%sX{bTrVdAd^2B4lll`{Clo^7BA5#YMO z(O)??)uT^$u7vN&5#SClr*tY{6GMy}u7uqa9CT6rb0kdZX=)~5bPRS#FN~j@DjNv) z8D-m1Rg5xsKbzAJ$1OHNUNJ_lW9ktGV^@=k5CJ^bmh~S;?@&xczwwOht{Vs@n z6%`qAxs(f8AyG$wm&7e4cP6);(-albL_wjU=8!7q%6CJvOhY_fKpT9fe1Kq#r$=t= zc|t4O6MS>2%0@dIH;yl1xWUtkAk)%qr6kVSjGTOUVO}w6mdQU$35eO^Fhydr&5Rft zpc1r#>b)lh)e~zD6V75MA6x;Nsdm(iMfgFKIuOo1+E?_Gcgt1Og%A1?zIliYhJ_&_ zK2ux`mn7uV*SPtI5jIEn>P&(NdtY@b4~-%Qz*c~uhF7TjX24X%2>6OwxeCD+Q$!l7 zkdvqO6;uGQKxsqRQ6C4wvWzy@W}Kd9|L@+n$USf2rbPJIX_l-Wa{HomLM{a}59X<| zmLioy4q2wBV<#7#An)kWTUSkm=@NN<D(6Rk2egBo>|ga58-L>n(D)pj|_Q z_#Kw-^8zCJ2|j@ff;!k#tuJ*^CY;(|`SRV-e@#@j)M@2G~exE3bF|257tks;Q zqFQOjzKX{k5Z@A1G?GCty2nE@ve==LdnY<(5Z;RM_-Dd|%;(+KyRlv;CCFC|AXP55M zGf%6G8lK2`>@5-6@bUgSls&p=8^jF=kcCIwh^mCS#9B3U4O=6;)2Z_O>IZ$nY?K{* zc`-K|Kp!kOJtYj03y{$q9iy;i5AfWjJK(xVbE#8 zRVK#P&EMc!IwjbomU^*N)rnJYJ!`%b8EWZg#SCP>o{{?p)%L^`dW95+kyZ^pI-$X-S&!!K*+(oN zxZ#hQJK%!^_}*TX!a2QZUhSHISh&#BSSf+{7%<&v97mNu=0ulGFB@#29c+5UGe@oq zENk;CA#!+1Y+u6DtgF}t&kRnG$lahj{FNBCZ-r>7mO5Ex(Qd>zM@UQjdW`U$eyA$i z1LSZz5vj|b1LL(;0%h}+ShI5Z=2moiIyJtMQ)B_EghNw;LGQS=LOPjzzymSr(Kmiy zCp76m*1)R9S30hu?OY@zEVX<6v$soo=>w20o86xfaiHEU_-qE?wlm$ZVS`|=jw`h? z71~;xV3?Nraf^PcrdA$%aCBu@3Hu|->nC%&utPhB64MG7KBVF?W<1B7@uvEEY)^^U zI^ zkxqW%JP$|UG9-D=Cts~oGvm^PB#qP%yaE=*wfyGSO~$Z z6(o;4o=GOdLttMcMlk=ccSkY=JT;6^wJiq~^3bj&V z*t$Qmg_=#)gI&$Od@-e3S8xb{9s#Ee=D2KzV*%`vD~19D>jf1U!K_Xa+jAR3DXST< zF_;^{ibNs{9D}Lft&to%@pkV`IPl}bbm9#`MlJrMcs|)#;)h*?yZ^%?WvhT%x2w%X zgr_%D;qzh`fH(=7_OZP=DiLH0XkR$a9jh^rr>a_a^$bG?1MzQU2EY{7Ypr zQ4ACJC+N;Z`zZ6vj$cuqxp`~3U?ia=LURrww_o11)W)U`6?f+I_ai^hGTG$eM9oaN zq;+U->8Y@=FsQ5zQgS z)bZyNk2}`w3eS_9y6_eyVcP`hz*j2NZ-)WEH^ z3t-ttEqnzjEBim{mN$zv|mA**Y6{MU<-1C`M~d(;*N#0xEW#CYNu7NU8w$>|(P4JnM_I>C#DNo64BY zm~{LiCnu+{P~A!OS@3Kp#ULyQ&OM5cvXc*jo9eOynOKJ}&dx>2S%Dcic+cnAN9K2? zFom5M0(2qyW>&b86S3mcyzHWpG(t2ax&{)yFKa&Vqy!cbe;2x^?1I4i@=jUbV>t^? zhrj70W=T6eo8IO&h@RerLL~Q~f~)pyyT{s#p!zl3R!H+POs^0AYrMq2i_=>L_-Kit zEEyNz&f+u|&9yK?AOUJQJ;(wa`574*xXzWSySV9iVXRPS`BU)Otb2Lq1XCsIA?5#I z@67|DUi&}pI-R3bsH6pPS|lM(l!T_85EX@lCRr+_RAikxNTnz#DodrJD726)6OyfR zELpOQU1b|f493j!zR-3$-P`lu^Zd?VcikHEy}s9VeYV%<{W*f-U1BMMsq_9Dd~7E#umB zl{N9ZSEvQ=P36e@7>3)xETlWQoL+kRWn4?~nrHNMly7I5AjuGmWhF{Wh}Q9KOiLF- zj0^{mxd{hzv&X z5xF;5A^n)2=G^WbM5qGsb||!cdQjDj=KMv@T6<7@H`<+xJvCwc_$l0UmdP{o($<5F zf&<%B?LI1Ly4kr7JEWXFD0-I7idY7M55q zZ7u}4hc4Xd^~%i+IwOO*@BF-&!xPw|gkdXciNR=qR^qx30{Q7T$V*h|h>W^(% z{~-(izoPo3|JWrk$rh&R71E3a=&M2gXYfOKsLp{sEKpQu_~$)*~ya?cNPtS~Jyc)_K{H^CyD`_;Hc zq&c@S{29LNhm814aO|5l|9$lB4-_G}Y5!JA=~25;fC&!ho<`vR2selmtmL{BWK)U? zc(?$QkP&6;s$N%J4{=Ku}_8jzp|G%Kebmt5Yum3Wa z=-bNtmonMsSaD%KiVpjVA`X$+^6?N$Oh&Q?7Eh{mQAfYfAivPJv$xg77eD;RBHdA+ zVcl5$tN)0HF)nH>m(&r zov8;ooh8^JR*x77~*N6S7`uZ!`54~cn|5P54^+ta!;3?(@^xlc=Bi@vlBN;h$)Pn~*JRM`$4<8J=g+q)&d1~`*!;cS}0 zo?ynuW<$dng%aB6ty5CM=j5rAdfGRQBBPFXJ0ov%*x@6@qs9oR#(-1XNPc9>S6Ab> zS{e!$3{-!RsIfW z6-!XOp&bb+q}KH)f3X^>>Qddo~o?BPGmh|W_-R^x7@kM@53(;!1H{$NK!!Ds-MD^Gu8 z*9h zbNsBub9xgxf#0woiiGj3n}R-{@^3rBMy|@fB!bosBX{)9P}U%C;=`sdThGtz${~A4_PBJ3*wd zsMH&h7Ysxohd5?fc8SbP`?jzCpS(*~-3R(T$0<9Y+;5aaP4->V zh9)V={-fh<^m&2J+G zIjjIWXZ}&8{%+;Qmm;*wN$nU1d6|XED z5@iOoMp#52GFZW&yc#NI&_T4Mcr>>!a=HN)c&Pt|p?suT zu&#|ZV5aBvX?Y81X>Ils_X4qbF5WSrq-RCGBbB_?9m?H*y}4nyXP1 z8RVIf06Z_wAE<9^6X6KeqDzaGw5#WpL8fQ31OF@*TKmz_BlaNg8b$e!=PUZ(r_)P2 z4?J}Pfeuvz!3Rkzn(iKS_fnrI%aQK)Mu$H`N!9IXhr2-K=AP)@&=uxKO2s%=W)yfe z*IYZFsJEwf1DqtjCZGze{Jf8v%-8Oztd0R^iZxAO*OBH}4~ zO5eWd8Ou3n%&KcCk-QwYen@7;{?gZAJ&Qn)nEbU14NFz%Fp9P44rF-If-#A39ceoX zkbGHbwtFWR+^6=$7(v>Yosfq}v43vHPVuE2G8<~!3Q!wr(U~3>3e88`!I52k9;%zhOHz`N8YA-^V!^P@?@#SUD-AKQch%a{7t^wx2fzvCh z&9*V|j<<5z?_*x{;FL(=ub%WHO?#Dmw`ez4*V=+)=Mvl_`%78&oLAhoCOKN)BXBEd zq*-t%UL8sk%vrXHgZEHVxNoF_vgx7zh^#G2p$Rc!UIi)8cQLuc3E)Bs9 z449S8BX;X2))M^@x@FkC)4udEayvi_2t(vkwgusPm(4f)oH88F_Xr z?IGRu?O~zrTD;+Do;)&)dIuQYSV4=;=nXeW^n|5#qwRe!i&|HQ|FU z&o__vv}n4vb!Y|JKVrwtVQZ1@KkzW}9e2m3zZ}-7;MyK{h1v`fm6x7!;y3peEY}r`4fIeuHqTVp7eWWQ@x**(w2ib3yG~6+@ z&c$Oy@j@hepyhtd#{~ipq3{ywvOGRWYiV`w-nnG(Y80vf?nDST=$lyZOHcUch;nM5 zsgi!n%4h5V#6W}odOpZ$XbDh~wD2y(X|*Y8`vs)C(8Kh0JsI!0%5Z4DXZL1Xug@Rq z;Q3XK@SA6QSI5KV9_z_dVsv&vZS^Udy6Jx0wM%t-`B=&CG`^eO^iwT}k@7Ii?PF+f znAm3?Cz0+~Tirdo_{W%ND63Q2MFe$!yr6T375?C9etYMQXa=_Qed}fltFrD<(+}8} znahFeviHZ}nvrDucXBoV1rNH=uz?%$c8KzgPqWN!Pk5bX*3_&tL+eJ&kC5<{?LRol zpVh5DM`)-2Gh+91D&hyVfPV&pKktlxoKf?&YyW?)S7G>KHRd)D-A7n*VJthl-b=e=~(rizW;8%t)- zIwNZsa~%R|c5W^xw3t5Jy`k2Lb!WnKs6`#!rz}nwn<3bCO2dU*qob&+o30sk-R_%m z_i>E}7#0B;wnG4lkdIss@dMaAFWOrgfoBa!sj4V?1u~)MxD@B!F%AtbT!AD?znKGV zYJ36x(j2LC!r832Q=Xo#N;cM<49k?pJoc447HQ*U%Ogt9+|rm*b}Axa-Oa^4W<_&-Bd~yi)$u&G0b4;1~;@l+eHCwiv-xhteA=lnX_4K3L>lo<-z> zMV7W83yFdZ>TPj}a_3MS6GfqlfR=^PDgAq?R4Qp0MJ^_&3251l28vsUx0(Nw)Urob z;zx@%FWFl(12sq+%YNB_l0I7H(UOgU@~K{wQTn6kO=Giycqj*u$XL1F2Sac{#)hZa zPiO27rqDRZ5!KSJrq}|-BJ)-o*52z_vvH9^x=>;1ToHES2mQ0_o;}Kd^zNG3^~go5 z+uA0!#-a3WkuH^tB(SYp*EJIRJdRdA+=u}$5bhN#z3)X5!^w?T_uc$ZmF&y_NtVw| z@S@I>aRjC+Af|e3&_1@?k5s84Cu|q46I?68{t&;zw23yu5D?>Z8N=!>@lp0l-+cAw zJ|?J4;xS8sz(H30DU(d8X~m);+lL{hGu2KJh781oj9H4Rwl17~Ad%&94vP3d6<}TH z&ZpJBI30Wc6SM~~y4B}SG`3RA%D`oYDXP6Egw zcJTS=Fm+!Y`T-{XNf4$b;}uVgB#?8*nsb+~Y*@y-WWMigi%oxI=e8e=$ge?=pu&$y zM=@>4pcdFFEQC(@0bUxUjFs)XFA8M7X_MyYYp)QsnAOIl`A}_u9tNWP4hT`EWsWGePfg~FRWH1BOjDhF-8i@0Dct$-uSur#Wna*0Q%UV8&YBUSg>s;pC2<*jJ9xi`;(1v@^R`eNM za$%B5cfb@s%6KxzTmW@fC~kduXAL&HE{Q20sf%Xiw>kDn>t)|OFTX3mZ_>PrlB@QY zJ-iJ!4E5Ju)V967y;1j7MYA4Sph*p060<|&TDc$XS#n)~VdS+5j}7XhoKu)j#u+hi z$cYSf+!Io3ZmU$$_P7FA@Jx!eD?H0k8mDiruWA9RlSnK z$QO;sbrUYZ%=OdOoRL?&p9?y0qU3(XSv;aAg$Fi+(lvE#xWxKvQDV!(m|zb4Uc3wy zw%3@UgDCp(zTWMAe!W>BX1X0_tyZSKX(@YTF8&+d(^=Q49{0!yCx=N6#wW7WS9D&e zYTIVS=hk%XlzwoNXOnfdFuPur_6T{hh3j#wK)9yJV<3?(@Fiogn=s~fsPt)Zs0%rztQ46oPR z*EQ&7;Ka4IwxV>heu9^~m~-QbhFFamEBnpWkW@x&NCXMFT@>!&)ZeD-w@J-9i~-GL zo>IN|wZo8l1I-g1#Y3|@H*?XnayOeRJ5f04XfjEZ- z)4}L0@WH1o7j1tW0b7I8jIZslpeq)oq=t4f7PkW^hKepApe%3=Hsw|KFu{gQ>cX@P z<84ZcG6|3%SC7o>x6hV7;N5)kj_BUb2((Z*7j9G%nmTo!%XEjUo7YV^E4%~^`irE(~CD+Ka;doaOxQuysGTS6XS;berL|MaMuF(Cl{WZ z>gWFgeB;69u$Q=-L>j#^Zf?)n?f{q%w_rcGb-f)s$X<-dm?5&4ec54#4*N{DxyDR= z?at0C6PLIasySZE@5Fqzaki4WA)>BQPC4nZj|Sdtvv;R?d8xR%QyOAV@%{cf)@Ly9 zgQ;`tTi`A4%Q`ewZ=0tro*jwXLY+}S!B)fUk zC>AR!u(<;$i0z8>IJ4RsFUq!%#(AN{%6(@yuS*}cUwAx@s*Yl{zxZz`W+tH9$b~cJ zd0S&Id(@S}>dbSdtBVP z=ai~6s@{QB!VIH>*%AS3Z3ASDi{a|Tye7C0-VF2Lz=k zqj0eLx&NAtGv1<83b$SbN{r-s>3XHm;jXQ4uXHguET~rG17s?PrD2^slyia%7KH7f z+E9H7+9f``_N&if?fDm)rjfOGJ60I3>#H`~qz`P;RJ#H1?&#W^`~=9GK%R~uH85gd1RW@^X;NA@zHk4*T;UTAg!8n6jGBviR;ajKd=LSB0)g^y_ zjA@-iZ6uvtYAHz*($3_YKS42(aAmpMZNQY~*JXV$m?(&~)mA9_6>z)u%+2$|#^)06 zt=}r&;pu_SowZ)i^oB2xdfd^<={MRAo{!!CGDHer=1;Zs+dE_Bs#U4Ea`YhP=1JF5I$ny92~s^Z2c#$U!S)qIj=J== z+9Bn%##=|zV?LLoQgz=9v*iyrUZn+}(A3|uWicE=(w`CE)__~f6x7H+xT?5fN#GKc#wi`Z47>3;klpufRvSBWOvpL5n6_?eO|8F70qd$9+MOOJ$|3L z>h!qTT5Dpq2#xE!;Ola$_o)6hcShg*Ia`|?Ym~P?oA3p5R?eOht zR&h3+Hd2*m-;5(AH}C8z1zvHvk#ApnE)~x`~g^{W4E`k^CbtN%HWsUF!42-ZhkNcnGOXM)h zt8(K?Hqw)OB$4A3s~~>I?+$%my^saEWo6X@Vg0-6obdy?Knp+2KsW9At?Ur--wzA3 zpQ7C3A0D-z=|xeRPODZPq9eZ9QO7&|U-NO8XF}>qhCbVQWcNu~ty{P5hgY=aPZ?Wg z`vo<(=@+iAows|>?}m5Buf>}ZP!2Y=Si%anowMa=$n=mfiG57HH;AtJYU%H+e>Ls4i_Q#6d z=VMB5`&X`ceS(J;l}Wd2&vyTaWwy`&Px|C z>zyIKSi`VoOHSL3#`W%$q@~koF;=RX?Q^F1pTZ&iReI}?Z%w_%L+{$S_TIK*ZvNzQ z`TMphQ!835!j8_P)!vI-6hyDi4&I+9Kp*VSyyLU5mxn9XWiq&E&i6Yp4%-TQcduuY zIy`m%M>lWY6n)lVz_#v9Vqdzud$Y!jSS_g!w23)3OfJ)FFpU<^W@QdKl={;8E=ko0 zIXf3^_JR_|bk|@W?)6mxo+oa*RCbr|LxU^J&u_|)&#(EzEt8b<4DbIIjz6v8o+D_u zanVS$)8g#i`rX(NY=e|*p?#b;{S%|T?PJ%Vm=O;6cNfqCUA$H=KKg@g_pj18x$SAR zXBD5kQe*qX2b*t;v#(>G(#AAhl_S=Pd%A7{0+ZKPvfd<@l*~O*p1xQzlpQ=<$z<|; zonZp# zY!u$z=DIr&;NYV)w%2^0iG{kVj5wx2sppD9=(#$?vRo z7dU0=tIaVtUBWV1`~6*4f5hqUW>h(n#o(s}i*Q4FW44E=x&?UY&UA{|GIh!{6=nY| zcJ8#-R?#TgH%C3vNoaK_SsyK?_6%~#JJVk(d7Jh#yxM7>B10vVSm+lm!cuhzR2jh^ zxaQ`(4(X!e2gZ|}|D<&X-cT8M&34vy{~wS2MjNItYcLu>d~)NX67$0$$2zN+;_|ea zDmGf#wTn#nWn^rYwsC4gqmDIn>#vSjCgh2=|Z zQ`#k^O?ef(O|K&N>WympipDDAwDL9lA6Q+Xp@PPPep+r*r@2|Qna3)(%LNO?O|yib z`s7gEN$l<0slG!u?YL>fH?42CohJ|dqUPK226hNUv-_l1xl;rvE|umkS-(?ppCo!Y z4K8xoz{%O#wJq9F*6mF(jh@(&K3ywidr;r{;`?T-j!xy2nX-mBA2nP_g{n#V}vi$q)Di8 zG`gge)pn?#f=BT6HEzB9H#Z_YXe+zU%&h4py-6+VvZODgp+@hdSkzQcj|`t-2kJYI zqUgsb`){2DWtxOF6UoqM=d%Jc=gHVh@s7?Or@40ZWu8AT-CGH_r7tG)R`|cNUsHbZ zoBX}S^4*~8&e(8!ucx#!Ed9`hqM6Xq+s@!ZD*$dcBf+YyYhg~);;tkZ8^acj4dedy z5wmp*no(J}t;mv23A^zj3?F6WE)MY?M1uG)%S4D#J@&6^FHI)WxE!(JzqCLT#f{5j zj}N^W@>eaqLob;8&)>&d!}6awbLQ-}bvgPE7tA|bdVAil?De%C=Wov*axIAGe=+bB@y!BM_}n`CVbl%o_^mrJ z-}L>9-Y{{p@*j$3I3g5BS1dS5hOWd(MKW~m0^+cIJx23Ro(h_ARW4z*duUP$JU(KO z$pIp3G;E=K9I=Pflr?L0CcX~XaU)e%S$g5Z#oL9Xz9w0}x~vxjh|4+; zZZ-~410oEvAo$Pj>q^y+8rtIIZ?i_@1o%54OAl_^nam)aXzz~HS{3ig?PP(uzY`If z>oUVHc23yV3yTlO*8}_AHhR>;JP6x4b0;^@6+FLsFsq!Vz>CCP^^m*+cwd%}7jCg^ zyX=AwC(|}n7=3RxEiiy!^Krf?`c-Fo{UfCC?N^R(Q zTm-N$KCe^#uatqZynFh07aw{5SKjp$>bcV}c?#gV&`b2GJl2bO(O)X=j3F8*PIHoUQ?ehwPn{N}{Js?8pm z^ed}$1Cc!|rq+*^ng=iVyU~tywDz=Q3VyHAvN*e`dwDH@QCswD_q#$GR4q{KqQ&n{Uev|x~(>CvJW^Ma_kzRDf3`%)(r ziyVJm!TE^FT^t@?7VLTQh>ugbd?_}}u7%fAiE8o62ZbY_h>HaR{63{Fox>0d-gs;*(n`8E6-5~BUroUvtM>TjbLg$-{^ zOxV?gW@8ikVZ+7wv(Vdy;ffd&L}R1(Vtr)Z)g{nw=--AyTiO{^I@}CfP_5JvqdxW| zBFz~($YnnKINs}bnWd;l$PYrV#Os5(kMjI?X)~>YCZ7zrbH3gr3H=hWv7W6+VqFw0 z-$(=nVi+iYJf0U1x1W=Uf6qWGAYePUbK437>zYU7tZln1!Rvr zSi*uvNHvmnZ;`G;Vj6kBjl;Skp{S5ibCs%&nJYHowes3pLA&v+0C(YiM2Ys3j8DgFjGZlUYs}nnP)sK#SUU4QIt z?Wl^-N&)l3wC>pX60PVKr;>EUY{So<*qU8)5X2r%-p%KhQ-&U1VoG0C`q6dV zY1lWUwY_Mek1#vF(%!iHHIr;%q$EQts%f|Y{hSMGP71s7afoOWj0H=w61p2R2Lc*% zJ7L24#aAR@DL4DhqnhnGIrUr(Qs|^RwR8aWN(Eac_fs^DuaNBVakJ0HKuvz;QdVJ+ z5RbSU;HyF;$mq!QLu&DEqRF!L@p3OP>B#YR>VXJwWDV7zKK->A9zy!P#g z<2-ad4LCU`cU~BFax?^nOn=@dza^~fX85j1Tj?;53bRwO-$^^9FqmeuZbuo)<{#>S)Us9U-k6@~O}^c)eHq4(m) z>HQxg_r1L*bSGT<$`rS5oHZgUokVKzk1w!7x*_8)r1nDmN$FhZ->*RJ6Zeg`Rb;k4O+(x(uoH_h!Mq41=q)GhW8nHRQavozaalF4d-^5Y?`o1-CZf+LT_f zfK=wmL~~{sZo1oNrBe#Jk9zJ*e|60^MOmAIYn4h?3WCvF`)w{d9D=3+w0-8jQboP! z4JxPdhZ-&!+}Y65?46>&(qY7+2mhxQopA#-7?plbAIWT>B725QRMUt8wx00-Zf>F~ z9g!VeK<0BMoVd}hD2yxtH-F*sP$CSdrI zSW$cnK4{A?sGRzJ$@`7%)6g9{XqS@KeD7mb=2zzl<{MO?5l5z!umo=%&F2<=p5%~H=M3kNE{F|zU?I)Oe~sC+a4%+!6&n?nZWx-Vd14GK z@IYm|Tkpf%Md*Rf?3DMwKFxeIFe)($z5|TesQTsP%)eNuHge{}cqlE4KkqGjqu-F& zT>ZUoszIEjV-EtNQUzAth5NV-jvj~*S26plAmzh5){aViB{=laE$88{-+nx8)N_*= z_)W*7ZsT7_-T!UW!Rb8s^Y8nJ9o5`7dQ^ocaXhoOlSMhb)oI54GyYc+C9G)sW()YH z48=$1CA0OPo0Lk;`!12`^ozsWbALv z^HAMz=a;s$f8}KPTa6w4pFiLz|AOtKMmbQ)_jq_2nOs6rj98E|#`diAFga@MT#4EB z8x{*4oNhm!7#C|s*J+}>K{iAtRHto*~UovKwBcQvW|R5;hE9# z=85}q^X43{u!k}x&$?0SsHoY6sthy^_p^ii{QPhV2Jr7SA8qRkA#2lefGp+kS4{Dt z*-qc+F{U3XRkwD`XIrDRf5k>N?t+JGxX~aw;P>M!J8nIKYJbm%LM!|M%#D-d{x1BQ zi4ywAC!m&%17x>a_gSrg(R`HHM_1k_B3I}de~g=`Ca?-JQ5LdGQI`$#S$+@B3uO4t zy>@|-pDEH)nw*xRRv>K;yW zhV+~n93_0|3?-oLZScw+)Wzk9jm-%9`{Kmyx9vyewC6L&;|TgFpN;GJK3rpXr8EE7 zwbmw2R zOWtBXEj(+L=D|y~WGVOyZWC2=I+F9)9ZkSBXBFO9qmVKqok)9FP9$0zQ#wy?DAh1> zyrWuNV|a_<20s`Hs~YQmxYq)QBmyp<-;GvDbDHOzSLj37SF3akuh*gV9nmhK&LI1v zzbkGSKLRhbMh1wFV<61r(PiU#&5A-@(&iZi+u7VeI(Uf0+9rkFAhf|f)NX04roc#y z+F~nPUy~mYQ+mN~Qs=xYh3Byjq>V(lo{|FJS_nzfge}QN} z8197R2sIm#LkiwQig&2peHKZLvg_VUwF1ZT5Puz{tRMr^KS+dIwC39;V86nSCPK^) zEE6+kS0Dqi70>`0`cYx+STz#9x1t6iXg6Qju+$bgP2xL&w3D=vZHa|j1nR{IZ~&k` z7r0U{drARcNoZXT!k&QdnE0vKn1F$B3b3IUO|vVi=Au)s9r~J>XSs(eM;*vFn3@C! z=|%x^p)!t-sj-_%AZ9n&k^q~xZq0i=gS?(94WrzEqeTU_H0Z|RH&n$9%KZUi=RLeQ z-9@r1vIinXSAe1eIJO&G+NHDvL{Od5Q}7K~bx(H@4jVPug3#x9q=RuUC>>^~>_f#( zqGxFX@5LQQJ4*>-CC~b8!ZaI%bJ$L86WZcN3Th+S2_ao_>4wbu6_;P!Aj7LAtPxG} zh3VZ08-W7d#igOjJ_0Sq{9Vz>J=<+E(AGVVcEK&@38*D7?wc}wW|iDGE`d{s_;LqG z0isBVrsTQ+?NYEkbkRGZ5T~CeyWQjTOa)6Kr^L24u26a)DIiCkXVI#(;tbrfN{~?5 z#uF0xoe7j0$UnD&NFRZRlU2Y~B7YbPJa7ijP9vg#Kn8b}pA}})IiI4@qZR}lLuKMI z1VYF)3&)sXh6uzEgH+$4@6rv}527}Y4_9L=+qaY= ze)dw%zAZ72%wO`{ispC~=+)r1kqA0Nhae#csiTA^iZp14>)D4fD~N<>L6ar>r*Je} z+=(Jqd~3AnAfi9Cb}A6fT7+6r82o_^WqXx}rq~5F!?VJ# zuu01xU>J5^LXl;zqA9k)XyBahoExd)-uP^Y^J&s5g;cpD&33)?Dk?B$ChA}%=Dc&M6;9xsVKz+Yu(57QHeORCw zhfxU#(=@oh{Ss4XP)awj{+^!Ceyl}J5U+?R6ch8t!y!2n{>34&EC(kGYG#3y)D`e# z-A5aU_5!@n^dJ%lhLR(kpqB`9xsH3&rA7Tpln@3RM#6eP4h9g93D^x1BRkJf+rHQ_ zx4c&P6)uwr3Lv%0KqHbJE+xXwo-4JF-Z4fxGL?=`#T$n|Id>jWk`)Cf%$vKrpqkJR z&kn>N>!^+Cec!I=G5J7g%xuTUc-#XZQV5X?whD+gLZUrh<{Af{OWMwB=-lJ;j$ecg z2$lx=0zu7cp_=`6d$J{;6T85yqi^3?-ecHPb^wGVVH1Q^gda|oW zm>#wt*2~{YBds*eu@h=79;e};XQbSKk9Pdbt?yRs1vKk>VO&V^AwugJ!XO~JMG#TN z4o2Hcr2~8r>sVGuGolF4I`Rk(N_`g_NpJt7H@2mbJ*Ns| z7bc;%l+_D56Km^9UCYpx#~FiP(F#rxjso9=aM4y+d#KEd@5NQs0lgXfWhYrKyQVDl zv+Gk--|tn@ zj`t(_lk;BcW@)?BHCJa{+`X`RQOndE)tjXX#YDyxrqO(YM_<1AYk)RquGVI!u|Xug z%*)<=UwfXdaw>AKXS}@&Wj2}4JuM|AWdzMO$6zn&F(TZ6o9=4<{PsiBU!Koi*l=y@ z>OH)BzyzkC?;S4CqJ5um-sK!CCrXe29cOuWgZE?Xc)8g>n8%{X*qds;((vAaeBW z5I7H2tX3_)w9cK8@Rj>m^`$t|j_8uq=CVFVZ6fTEs7-&{xbWbfWb|b9jE`=9koa&) zFQ?U3oM`$5J)Mx~^Dnkf8H!K8Tb9N&bCX-uqBUuQJ&ln_D6*p&bq+&8>zD0&evKmQ zQN0lVi4MMsH?4`VnA9?F*b7yq)7A3^^; z9@?>Wc^&O`zF+^}?_cVd7&vD<%C6suB| z17ni0VbX%dXunl>nyCLQs{i{-XxKC^p}ZPBg^iiHO)Ynk#q=eT1ZDQq?PvWoJpEh? zL!Isd!D!aZzGcH?K!kt*49sVTUtD)!IL}s5sfFO-)9!-9i+3DjwU$tp9@Rgvgq0q7 zEVnk;)yK@8p?>Zs>65>0#4Y@u=O0E_pwA!Dm?%BO3oq#*1F;6QtQwr$xe;Of7#As* zlfc7WsTzj0P|xn*|v zHEdZNXP|P24bzGXCA-|TSdBg?21O3jGJY}%|G{3H@9NHVx1f>60M^*{iG^B}Kv#B$ zIuR_`cx^CT)n4~;{rPJTSjF-D_qRq`1}qx8LZOah-KfrW`Y@LA9zsYL<>_m@;(!#4 zSD>&X-WTclLMfAaEZD7|m)p;}ZC!Iwm-FVFJGUuETCUWAamOT4OtG$PtY79uJ9o19 z^?u?K(Sddvh$h?`onNIi4JZs=s~*mre97S0X&CWwQe5e-nZZg&+N&C}<|Yc+IuiWg znY~(sZfKZka4##5=B7iXKC;ff5x-+FtDch5mluxKWH`{xr{t{wO{@`UMK4uYO+1F( z#)pLTvm$`mcp1bW2nN$sQ0=}4+(~lc{01I}r@Pqa z{m}c=8!=or3fV|3l=H!TH()K{zbSW7#NbdMoLO5)#pU$LoI-}`8L|N0ZLq0CBEi!T z!1N-kap$)d(AIHV=(=P}3(!j2Z=9Z+?p697dSh7aOA{`5*x&|eS&_Zq;~jOa6&>}- z9U^Bf-#G8z-fiC&sh3{vCEmAYb@QN)imk?h`0$FISA{Nm`B#9FSH~*izaATsgsX5$ zJDTS#rlcDp|0aFxUFoQLMA$8MQ+d?}jv*3lLk8izWlhpv=D^Kg0DyR{)?ic%L~{mx zBlW`VyJrl(|6@(vbZ3qyFSRky*_OAEE@HpGXrr9d2U-C8ZM54odOZfirN27VE8tsI z)!S5_Rvxo^eru1vh|InW|1|~G4zv0qCVwf+W{v$^n62A`GV@|C-<|w>8dr=A?Ru10 z4$1&#N&-r6KW_5ew9TE1L(yA&(@N|LJM+#)5p>T{jWwr<{}X%Tnq%JUp&JL94%0by zVR#vUN!P(9TMvoEBg)8?mpvWuqCKp=lo@`mDyHLgOb(WNu}oJZC6vEe?9keHsBU;& zx$?MN??6nHkRJaAcgE5Bu=QUO@pHvLC*pm;gnl+`f2t*>GLS(Zh;x2_!>g9&|1gz- zLc(M&NpM>;fh$^2#{qzgv?&3(GeJ((JilBa?Nx8Uo8^sxww_mr=U?%(rYKW=zmyR> zxV?Mg;ql`?a(f!3QIS1deWEqZ&pY5%OI5PgW6#Fdy@R_mq^XS{!Ngpcqw`-qFcH`u zbI|E=^e_p;<=PJf&*kwvH_unHfk*FwVe$Fe>2G%X3bP-~{T7s*`?(~)=-ZOKv%Ndf z5S6s)g}BZFjymESaUhk{y_Y{{46{J{YgddLgm*E#| zrqJfH6_*l1FtQ}+a!h}?w3*41{wF5;?64+_f<<-4p^Ze8*{moxU6h-Z%S*vBsyROxLRhNwX%P&~($ouQtHk59C zNKd8bf**81mmi%g4kf-rE$YJTl|BXdmqbnMcZM~o3kz7wqW)>wS)W~#=h26dGjd8e z0+(2Ei_&T?#1pC~j(&KChuh|Szpv#JEvZjw_~1P}M{>G$&z>-Iq@$7fgof5Zg#7#x z=LHm54vglI%}QP(wIHh^hYR!D05D$HUlccuj9kD4iS)ws14@T#*Je)65)@`55rF^d zMG#{cZQgu=oR^ex?1UQ!U+CoAWV{5Mft3b2)~9b3S!w<);ylQ)DbR5BjPx2;CCx z)vRAW5?I?63JNdGx6Kq|7cq_8bs*R(?8*-|GjEa24NOH-uR3b3=-PB@Riix z^fXhbt%e3WHfE!$=?Z|;PrU$k#oUb%CA|XH;O6vLrMdA=BF`er@?)ay6Y!=Wk}eEta76Ayw4!#NZR`uUcO|<&?g25X%PGGNsk&)76rDHu1-@Uom^S z3w58qzp0S+;xFR|Zo50h8SJLQWT#miGw#u~ot6ZAyfw8^b@0_wt56YwCT@18T&&r{ z9PnK*!IUCx>vee2nw z(3Hfs4s^_mxE2;qdp2-~NlaN7e{a6JgIraoPGE}T`>l94J}Lbvj$N(-Dp6eka7p78 zqCb4I&!NI`O;L#N)%UZOKj!mBEuvl5AVv6l?6yv4{|z)A8cmQyg3ft^vftZ%rjhUz z;8C)xdiy<0f?Rv4BE&MWSmCL3A4bK9d6Y2nvyj(n~x(a z;r)-^0Nh5`IuTjo-oB=-P@|<@R2R*^?>bOSwKQt&J7>l@3;;QIh07tBIN9wj&KR+| z&KQmMI(UtP<%QB)UL@>yd9Yyy(X#!8-zfPZO-T>CZyGgoR+b>8k{!%wG=LpN07tv?SS{QVQVw@Eky zT7i8ZatsXayUC`H4Qol2IRIh2CiogHmx4L}D&2 zZc%%hO8WreWblL^;+fI3!ALmaxJF@bSnhrindjTjj53EkQoOqX$ZIWYkQm3rj@p%gMa5UMH1 zs-K^TUE!2=hRA{&#-cMDGZQA-k^&;ytDzGUj}l$JUR^#KP{+C}`!c*ALT1wuUeohMFp8 z70>KL4V%~9cS(yLzY0}8wt6Z}gHRJY|pw8P#YG0dD3Ga#i zS9ucfkbACp^~gQPJ6qT9?(xJJy#*Ifxv}fS2}S~Onu_$vS3nMfCm^F5Q6ln+N2hX- zl5N!!)ZZ{A$jgHCIjeaL0*ZNysu{MecYi9ccLq^rF0KA5bn>zhx;jts9jUdbblad1 zi208pNe9ymy1h=L9*AE33e@(1vYxVKN=7|}@Q{2G;TVo3qEFrz^>DP1a=uTj7JrZR3tNM;!8k4Ru#m5FTA&~7n^+}2ubY-@sJ z2c8=_r-V*T%dGRWy+rLaj{M>!4zUOo$6SkGw+_h-%TD2CM-BX$cz@-2^mTq|_V|s! z>%)B3vOLJ-t-Ig_9a#$rqobd=P>AN3GHk^9SYwh=T&wSml5h1zax!W$ z+p!V73(zUeP2bgFmYsqi9l?Va1zyuG_mF!>2 zlD`+DS=7d7TslG2y1}yrRQ&0vD;!DmY8apLzNVmznv2ZejPAo9rxoJ7v5BGMU?q4|_vEmHB)~#ly37)rMscaYqU$sQZXQZ7Rn!TuKo$;Cl_TVl}G0{}Lu}iDwa%V0kY_r2w=x zJvLAT-AY-l1VimWg42MLI*Wk_H=3U9ADAAFz0S&->no~Ysh#5qRDqfebsx%hwPJPM zgaAW1N04TO7k-=rhzV|S9Hw?X5eC(~5)DxJex4^E;7&-G{2Wp^RGzmV^ONEex2r+wve; zLPcTrBxru3=HZMQd(C6zT1wgmp^w2zwx;Z9X!cS!|154I5ynGvlo0edgOOsTSkw0y zYm>W2hhDlKhGLS)Y;vKm|8k*ggYMZ|9HqRc;1({#x7a;kLSn5d1efaPaZ}$}Ctgu6#qnK|7ISWe+W=wRj)MGPh#K z3V+JiYqLQ2$2BOd2VzRCISv#WAY$?B$V3Wkp|T#Db4|z1J|Y`pd=30V8hz>{S!CO# z#>T;XA?xKO!2sY28?}y)gQB|<;2|Y?-^N3SI`9V47H8i*IfhJj@$ei=bW9>#y)N7l zcNyBFacn5B5F-3j(OhcA!K7O8UR`sLy*ivfJxW()$E2E>X4{l=vfPdwP_NUivb$O+ z7k2?0f*?LC{=ix-3>@*ipPK{%HwE(F{4F~W-%61!B_>>(9HpLP{diFj2Yn3E3NXSE zY!(aIX{5mdm+Ib<2d)_V`FLLmnW%JttqbvwQV?5OixO@{d76v(GIH@JjKUr6A1NXm zZj-*DB@7<5AGLt-6ut?#zFm-W<9(aq-AE=il3B`G^ZNImsQ0|66lk|IRSx29fSS++ zfQdkqbFTEk5#r$T2yx)2XY%wQm9-hr#JhM~E{x~y8G97pkcn$iso|pbX*+l2;!{7N z<%R0SKdV-y0khw#py0Du`R?l3a1wB89e3lvIzo>~U28obr&Du2z!hF~D%^lrWnN>Q z!~GdLC1d!P?QE+^__B!qjx}w)bBb^@fS^_TODYtMmVKOL3vs4?m0!(hHP~WPr%!J` zm?2NNHS1@$ZtVu+cIE6+C+h*|h?Szka#cd_fV|_*RM)L3GnXc&zrCmjYuxbW&SQXA zOslKp(N5OZQ}V?@Or?mnBoT%jdf`Km4L938@D%O z@=8rY8sZB+y`zITa}8yyKoXw}e3wylF2c?4D;o`PT7Ct5#0-wB zHPUVC+K9E2Z@>L@?X*p+47b&D`|LR9x`MCFI(d|8AK26tD%MV6@v%sd|$I{8i>}AhMapLxlE1E%#8(rT4cxjBu6r zz9*8MYvN;m-dr)7^=BUcFUJ`}%(cD|jDyQ6z}@U=1opn3gC?Qs2?V;1AA+#A0)8H4 z_7`Ai`Vjpc@lcU)r0=~o+Fj(DXT-~J(}(Yrt@c&`%ulV4Rt#{eE|Uo zzHKSTp7t*=>Pv8@HjnVvTffHOguv-Zv!(tVw!c^cSr9jig~}&*C_|DRzhANW8QG9X z$Oh8Bd+F}ykQ$8}4}VHF_@S3{aJcPsB*sUJXg0u`e{Lqw5@zc^{F;Ke_qA%>xq4aG zE4}sSo@MB=5(a&)^)$Bie;R1SeSWwjKIZ4S>oH7EdZ$^8I z_XYt5x8bTpH3HmV}9xVec>kgbKZ{$bjfBPe))dJkgZE-HlYH?@?v1G|n zdu|#wvPbPs@zCr=*fmzU#TMvtJY?Z&Kp);qEm)6BUrCRIkMYwwneVmGU3@nQiHS#5 z)xJ(_1CvkbF#e4%Y^l*h#jAhH^M(5X)5{qKMiM?ML38En$3!Ca`LTnGE4#l_jg!nY zE^Yqlna*zh9&1saiZ*=-j(-&GQ#+TXl_AXD?8~*H3_xaSgAiA?<>%>+`cESrN!L?- z(O`UAbo`C+OIhmNy;*Y~wdZE=aK$l8kIhrT={s`Fod7@JfUO_&qlX3A5!mdFeHhJuwE+b#6V6#2c*KDgB~Q)H2;#lh?72=^XjB>iSJP zENJV0K4AK$K>So8F0vRCcfTv+ViXgUw($Qh}Mz_vZ0b@9X=pJ(NmP2}O|# zl`&&7H5Z8_Ql?ObD5A`)%2b3hBuOfYk`Ng(g(P#5p=6#jFEfkvTp!wdtJC?O^L>7= z=lSc`UuSprX06ZX{l4$(zVGY4F59NhMq|EW;~Wl@83>3cQDKfP;yuzt zn(Unml?WfRVLU1h%BU@`w*!+yyz%{|r`V(0$|sFIv6|PIFwzfAdzsW|10R$nWmTpQ zHKDMvp9nlaBKy-J<1v?T%y?y^`3ohPGV`pVi@EM2REvglZT#smW)sNB<)CJiXR(sY zs;N7s%BKotHQC#f&sI9t#6>@fsk1C%qUHFyRnawOozulg5R~6h(}&;RWzbn-h1Cth z2XQrb&PnapYcGs9x#9cwHyxN+&g~=B7ZsOp96UW5ZAUK94U_D)!8Tpr=b`8V8FHK= zGB8|LZ{)LQQT-2-l-WCgG1+5MUYu5W6?!`hj^egeC#Ic;!>w}OzORi9+cuO;9q-V^ zZpI{arlHzT0unHCIg4`dWyx+c$@W+Ek!(j1#j(F0Q;uCOrA|g|BAoH`Y`Q1|i4^n= zi{BQBT1wF`-67bjVHMj)X;D5Zxs+&Mn`R=mAe*`2AE^f?7dD({YIQ7 zs#Lg6h@{`$U++9^wNK=UoT#{>pmXnFXHhRy?_|L(o%wd$SGqUR{K<*!ckM7V;x?1S z@Oy%H67vTZoqJ44jMIm%4h*F=G_bN~4wHL~gYnYUU-y;>In}=J{#F&^4=O-xLv_WC zp({@fP!XiQI9(pb?Xv`k)44GtYdVi7WQIM7nHor=S9(}NyB>ZjttFY1!f-v+mi{c6 zCf>TKXB<$T~)y z!@3iN+1S}O9u_fZHxG}jx3$`3`wX*%yna~>3XR(hd>g1-sMW1?PKff{rG6|*$j$XI z{K}T4IG#FHog7fz=!=5kUbg}>)_<)E|HzstwV8CkqHU4ACNivEVs`S>$xG`zm9|3f zCjUuMdfs;u;|3w#Gcj)-9p^Y?JaB*-@xUN|Pfo5mDXomwR2K{E-(Om!Ut1LmU%!Jc zZ77efMW{zZOGdQ<@WFzHW}P#PRgE_KhfMlCj@0vvLoqCvQaO!-{|%u5a8lcG(58Y< zYnVbUO`mAz#cSN-PT77J8q)n(@D@yIywUoOB2uPAR~sy9cTtp-!_mK#A@?2chepBJ zD7+u>Q*Y$;MyhWYhmzmKvWY(@eKBcRE86*W;8RXy#5 zMb!<`)-x_yIQ0fIE#PRE4K2)K)Kp-i<4n!Y`hIoeTR2G*-Ea9dgZObMNys_H90*$& zwNH#qmB|TRQtSyCQWaQh$Zl1v$FC_KB5F7MO^iC!dGA7qICUc*Wh8boH!TwkZyNc% zyN=oPtJq6h_{>-g z)gPdgQ%PvBz3KX^Xb8~GPiT=7ms)q2}qgio*i)b_q>jIXldvSD+L|M zzT}FDjxY}DvBHHUbW+PGzVML-d$Lq!i`sfuh?kDrAv!>e*m3wAnA99Xh1lfj!&0x2-r8;+ zxm2O5MnQXL!!&DJx84IBLDLR z?2EnJ#v;)F6Foa%UNim$9kI36tBykVxgM?_QQ7@53+IcyeP0HCu>;CI|DcvIL5#1N zrj^XL^tLTODn1?_<_$X$QYGCQ@d#Cc^wHeoRe^k-VX6pEu9ETQ34+dJsZj~{DMQ&` zg5l!-w+E%Yr~U3*!D(yjee|15=iaW$@p|cUPJZsGhmh z`QhQod)TRZd%rL)n}pVc=L&1Dh2Mkc1ktGxH0F;xgodYxQRz}D(}L65ZMgGUBcIMs zyG{9xfcVBiDleU50i81cUg$(@!$uKWIj_thc#YW9i3qds^i(=DWy=;{k# zq4qmN(mrb)l*f6 zY4^N%H62Z13BIh(%KW*}XU!NyUkbhp??5de+L@TPIWsd7I?8DGVZ*8$>ISec?!#u8 z9roMyw!Xc6v~ux7%dAJ#A_xF=^PC;?>+utm9*B zf4-i=aaVgq9CzjKm`_~BY+M=ZW*$gLy||$hbTey9NWX-Vi|J?TGt%lstTjZZae>ha z95Mahz%klc&Sf_0 z#$vS3Dn}plezC*ghPyVwvO2ze*r>MQY~Aa;UKz*pvxy#IdU^o7MzFO7ze z1v({3>*Zl?&%kD_ChAnge|)W@MYK@-^biw3+zRHYZbpA*Y00)b2Ftv}#%)q7;=C|4 zNK}oCm6o;1X}IsO*^H-+u-Gzozu{9 z(ewIbQAb;2I~&@R!g%klV9qrEdaf(0o?uZMI1deRP#Sv>*}tkMQ9OAC#(`pFMO*5z zCIxJT;@N&&65wI4sng4@eo#=-n%sBkP3F**byh?kU{0H2rPQBY4kaf@Jg%Qpa+(uJ zl2Q2a+bE|*MRh{Zxa)W(IgpU+z>bkUW$u6y@A66i%m}|q>~yxtm}~MR05ZvjjZ(qE z%BHS0{LLWEY=Ea<^z6s1m&Qum^fQsnO7vx=&cm7DNemBcBpoy!;34fJjV~4l+(-kbBkpB<74}FM`^fZ zbxu&H|Agwi?kzOfPrvsK?;0wjDt&6yeR)ww<3juMhJ8c%^-|J93#n7lI#D1Z0mgc^ zW2*QV)uNtrZBk6`YII1CBD>(FDa#F=(%@by*3%d68}xUY|3@ZnPMl<{^6!xCUuPPM zaGm&1U}Z8LFz3~DF5c#WXlwSdwLH3-QWkFY?%WrOud7?u%t#;Z+oeHMU$FMMn#Oj2 zYGjbZ92A_%Zh-k2(F@1W`xiDJ@CbvrQ_?=KClK4ogR-N7%fb=NEAC5=qpaYD9WXg= zFx!Q+d}^5VJe!2tq~5ustFxn_UydVYwfltdVdqOxV^9P~aFq@bXH z?muBGtFp7|vDp9zs;DqZYffvIuJ0Ob_|_TQ|BNv<@ks-f+?9|c)~A4Jmx!R0pnc*4 zH4r6@XdKtUu$;2fk*MW{$1-iu+dja+PJy6TES9@;uzP9Vw}zQ}W_o6bfL7ym9XZ1{ zg0twQP9ilY?tHbKxaOKRZ)2)mC4I|6=k%W5$P$xgq&u2fB26)=%6Yu-wcoxr8BM&b zfU@)aP8&y4Czeo$zg@zhd0pU$QuoG2kX!k+z_3z%>-`j6(ZZ|dQXQ(qpVea(QE;p9@g9%~Noj{0FXKk`P zCH^|Yf2$Mzv;XxAEIlh9QAo#`%!*;8Y9Jfsmw9AX&En@4-FMc@+?DwyfoEQL`o82s z@M`98>MvQu^Kj}s=FZq`7w4B$pRM!Ay8tU4b4%_=?KqdNvmc65v6);fSFI(I@@=Uh zK#bbxf6>$X-fn%b`Cs*CubrgB=Hs{+O`MHeLl*uM{DEfRd>95@Aex;?J>|%|I(vV` zyq?mS4K9#i_)g0qWGb?rej&#E4RiW;J!u854S52Ow2YSgBhTydx3FFL-+AxlWoSl6JHyg0K+|X%k93BO6qN+wCa{|hLsk4M0p$AvOX*@$zy~Bt1hilYp84v0Imf?+morQ->N;UE(4l@{PsIT!I|2tDTa3Q( zz7&f!l9sLZr^-S^jFfEi__b0#gv`E>V=IsdViN$*-|u6k+(ex?7xQQ)5c3G(>YHcM zY8wSVZ}ATvgh*97tPrv$+5sj2l7}$DBL=OmXL5?;iXnCo#2fmByre)yE#{sR`QEIU zFwNzy2j~4Dh+a5o%-|dNgiUyxJBFi0WKwk&d-59Hpnn{?x0cveh*8=RZ%J}ue)Cq z#hsWM$Yp>n(j{;}nM|ujA^eR6PdaA4_x6!V>AN#2M-q-2I7+HvzCQIn(2n|5@E@E#8JSvE;&7j%nK*(K4n5v%t=FWDW*h|mV$41l|Xqwzf z!0tQ5^kvMl9z1w}HUo;T8|uEJ!kFa8wLxKp|Dk8Ak*Pr^FEFvsjOWWagN6mIm^zHMT|E$* z;g@Kd%M6Sn3yYc>9khqC@ZY&b9(CR!J!%I12hc2_erE>*wXyDML1{4vXm;v~h(c&e zT6*M@DlG%M76=&QE8Z=cz!8GX0Q(cd1Pt0_%UDG>+eK~hNbESv7yHOKvPtjG8h2Li zK5%|qEmtnQ`SSIjZR^JF5E1}-&JYB7kePizzv3tLY z+8JAS&r_4dD1`F>8wC;Lw8mrX>_ZbKRK~&jP9~0B3yVg&?I1)r7~2`ZbvT@0jk&&F z^W{I5X@Jl3Y54HW>yg&O>%c&3YC@uiB4b?kILS`v)SJsSI`3|*@o(>LFermGTNXWo z?~ZR#1aplLxS52!A>9xa57xa4OsSxNfK9$anb6zQ1!JF}1epoKF-;^wM#aF6X#t)k z9n-!81MoXioCq8r{9|+M>(d2pZ=dUAyheI!dYWq00i6qRvw`OcrG+t8PmV5KBfN?A z&e+*%i(e|jK3g_l?72GDb?vzUT0%KfqZ`*^yw4^}6EBBg8L04#U!@bc_Bx_G=uxD3 z6=8*^*9_;WgEJ1_OvITQp40!aXjZ-MQ6%w#2IBDa7CR_X$Lb7f7eAxsqm8(>J#vj+ z&i*Hg!GwL5@kX2;TNqXpnL=RU^#N17PA6JRhZqAd7o&$Mlnp>+Hv*3c3a}qsCYzdYU-MJD3 zd#Uh#C0(c$^!OK=+l_6~wsO{@ z=*^4LywsQ4kM*r{l7s*{$*grtw3ocZ{)^A<+2^GvNkn_!P!fkD#V~G)j_@wF}+?PJrEu`XtuZwYjFd-;F=Z8DXId2P* z(0`z1w>@=-=mo%ThY(`zLgz$4ZzC8{glrQO;L;EZ1;M6UERx%HD(48^djG@O=U|l+ z??4&M53eMyeXC+K?Gc?zXm$j+ZR*5k&cy&iW%Hhtk)!o&S{haR3{m;k4fM|MUt%EX zLi}XCJkUPhwm;WOCF44I&Fq~d3~Q$8E_-k|ZnQ;^pxL#ELCU&kHG65892J4cmo)<_TB$&a;n{EdxlWM5yP7g1)}qlEa>{mq z#^R$1tokyDF|S&65B_)My4D;!E*j_T&oPF!BF8IgZZWv#`$(L!dQpp|>MF#ZJl{M? znIvQkpMWN@#wlV3;ulIaCn+?A(E|Q0_t$@M&^QH3i=<8Ic#kZRf_tLT=n@8;JE7hL zMi-$8*lF4X4(xQbF3BmV2*j;P+?cO*hxt#uB$QeQIW%

g1R{@I7nFradYh1f_a6ffcH7| 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

2$ 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

n?2E*aVkHb! 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

;P@86$Hl+z>}GI(c9 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 diff --git a/contracts/docs/plantuml/oethValueFlows.puml b/contracts/docs/plantuml/oethValueFlows.puml index bf3cfab347..5088813018 100644 --- a/contracts/docs/plantuml/oethValueFlows.puml +++ b/contracts/docs/plantuml/oethValueFlows.puml @@ -43,7 +43,7 @@ zap -> weth : ETH note left : swap ETH for WETH weth o-> zap : WETH -vault o-> trust : OETH +vault o-> buyBack : OETH note left : 20% performance\nfee from rebase zap -> vault : WETH @@ -57,7 +57,7 @@ end ' Mint group User mint [< 10 OETH] -vault o-> trust : OETH +vault o-> buyBack : OETH note left : 20% performance\nfee from rebase user -> vault : WETH @@ -196,7 +196,7 @@ end ' Redeem group User redeem OETH -vault o-> trust : OETH +vault o-> buyBack : OETH note left : 20% performance\nfee from rebase user -x vault : OETH @@ -309,17 +309,18 @@ group Rebase [increase in underlying assets] vault o-> vault : 80% OETH note left : 80% of rebased\nto OETH holders -vault o-> trust : 20% OETH -note left : 20% of rebase\nto trustee as\nperformance fee +vault o-> buyBack : 20% OETH +note left : 20% of rebase\nto Buyback as\nperformance fee end end group OETH rewards group OGV buyback for OGV stakers -trust -> uniRouter : OETH -uniRouter -> uniOeth : 50% OETH -note left : swap 50% OETH for WETH\nusing OETH/WETH V3 pool +buyBack -> uniRouter : 50% OETH +note left : transfer to Uniswap Router +uniRouter -> uniOeth : OETH +note left : swap OETH for WETH\nusing OETH/WETH V3 pool uniOeth -> uniOgv : WETH note left : swap WETH for OGV\nusing OGV/WETH V3 pool uniOgv -> ogvRewards : OGV @@ -327,8 +328,10 @@ note left : transfer OGV\nto Staking Rewards end group CVX buyback and locking for increased Convex rewards -uniRouter -> uniOeth : 50% OETH -note left : swap 50% OETH for WETH\nusing OETH/WETH V3 pool +buyBack -> uniRouter : 50% OETH +note left : transfer to Uniswap Router +uniRouter -> uniOeth : OETH +note left : swap OETH for WETH\nusing OETH/WETH V3 pool uniOeth -> uniRouter : WETH uniRouter -> uniCvx : WETH note left : swap WETH for CVX\nusing CVX/WETH V3 pool From 93b3cdfa52e23dc1fa83df5c8c78ca6f94695cdf Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Wed, 29 May 2024 10:45:51 +1000 Subject: [PATCH 111/273] Updated Native staking process diagram --- .../docs/plantuml/oethProcesses-register.png | Bin 0 -> 167449 bytes contracts/docs/plantuml/oethProcesses.png | Bin 436788 -> 448529 bytes contracts/docs/plantuml/oethProcesses.puml | 27 ++++++++++++++++-- 3 files changed, 24 insertions(+), 3 deletions(-) create mode 100644 contracts/docs/plantuml/oethProcesses-register.png diff --git a/contracts/docs/plantuml/oethProcesses-register.png b/contracts/docs/plantuml/oethProcesses-register.png new file mode 100644 index 0000000000000000000000000000000000000000..a1f1021dba4a1a0113fd4b47e6006a50de698850 GIT binary patch literal 167449 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 z z5?VY}nkwV3|w>;R(YE#RV?&cdaH3|x^q01}hchW3r%1WK?ZXdhJV%~+z zhBx^++1c}Q94=?b5pGY~w_d4#I9g!>Iix0IN8DCcZwMXDm8Q&Mb#LwS^Yd>kksj<3 zmt)=jYV5r_A(id6Mp+xMH|s**`U=Z5&uxz#Q50^INq!D6-I*Ow=jo;o_UzBg%B%^}66~rSKr@a5Ni{ z^4OLC)Kd$ zvE4?lEx*=`V|)CH4%y-ko{ov}@jU%{O!)**l_xvX&v_H--mzXeF5Oa&P{p6n_r-XD zc;EqhgNewKZ*Lb|wU$c~+rM}mhRro;xObbb-GAjU)8RJpsWD@;rF|sMZOT;MOZ}ET0C^JP2evj{^_&LD?#Hot zecl1yp>#noQ}R8Cq)tyP4=9n!(G`2#h#mSyc(0_OnUdJz^XQcGGds;nCqGTSQk&qN z6w~}?eFwX_%T%*p?5j1#$X)`l5RRb~-v|~b2m#g*_ z7G?mHh;!RZOG%mbJbzhr3JRTJibVxh9Iww`R)@zIpxJkqf*z8NRW5jhrGSj>Bpd9mX<)XEYiB@U;@Gbp6Tak1ZBQc zpS)Rhz3}&Jva(*p23Z)l!!eB5nutjpWua-DVk}_coc8F}0mvS8RP^@*q2tRpU;j z%npM+f+&9 z7oen-mZzMucV8-- zXR)w^BYqbyvXtKc(b!@fZ##lr*!6`pxhfiTTA(yeVVB z3__8D^`*0p2}cLyOg%eC;hEq2VlB3oI;ll(JLjtek$o;&BLDTPa+3VpHY*7alGmt> z;AXG;>ePeWv_;lzp2OJoH|nOE1;(o>BDX^};nqN4!HAj6CP|xKgXu(Qe}`3KyW)y& zTKdzujWdOedo)qbTb8A|ex~A0lElL|{FGl4+?YvO!gM>3`S2)XPC!8An619_b}hm5 z?_)=A#K;TE?i6@128`l*wrAnWGT!I{ROJA)q}@yetYyzu6C$S+DeYNw$_zG|Knz&1 zzf^9|#POBx3=58*DG?ByYj2)HqE4wySebn8qIY4?&FL5hcI5{-pMTCU!@Vtp_zK(Q+9jspLF00FcA4k4fEW`-R9FrRJ9rOFHMp6lH z8Q>LxgGM{S@*3(>sO!1j#isdko(jqH5_Ep34)VppO~{w!Cihdenn1s>R~b>gzTet2 zb?tc>Po%+a4mE2^GJWO#XlG6}-*ywVyPcg~s&mR0<9P0m%cGSUE+hA%928wS+Pq)x z#0lH3geodR=Akr)aEa=HsY2vJNN5xb9fz?}2{0IVce1|2Co5;Lj%|w>sq+;+n3+5} zH&nH|_5DJQDrUL;dW2W?gK*Y3>>D`0mzNXip538Dau_LuMHl*wL|xD8yf9B{(ezf} z0`>y^K8udiabaVhdvK~%bq1b5+0$I5ufY1fb2xd{sgcqIc;0X=NfSuO;Qc)7S3gWE zE3K%w>=Fc$Mb-y-lYnCKs3bUTVro|KDnyNbA1E!T%ym@2P8nHFU@}NsRJEx{hDpUs~+s_tPHyIdJ@iun}uerI6!g1(WGM_E>PMDbu zb-DBj@m@attYLR$39N=fy@F^&38O5Sc@|?JULzCges6`({YY+w9aVnpz3EyVUSGM( z>eRqhmTSa^Gc7%lkbYkBH1~7O*9K3(ZtT$t-#PFLS%t;(xDn@Y+kqmh zVNpkl3ep6ZFXNp*`Td_k>wk-2^nyzkf?Y!(p#nTZKuF5V2dSO$(|?4zh0oHYBUg%q z`1+;K+T{*3*x1s{1xt}3w?Eoh3C(&Saz9fbBe>4Ip#55hcXB>(Vg7cdyGShaf`xlX z!}9ksVs^wyJORSe-;W>A{dI`2<L@EKJGuW6Ix=b^`)H9@MJf!YS{ff% zHsj%Qc;NVMNZyuWHNA_oHQ2hVL5n@}qr`eCTfr|BaeA z(Ej}A$=^8n+kR)!MF0F{_&udlT%?Qm2xl}+i}KGYH!4~N_5wOTeSM68Fou79>bDFf zy6>MvN@MtAWyvI<#!`I-nX}pyxfIARq7l*hPoq z&|YxCv(^K^Kfvf8Qdj1w%X}zBE>X;neX!{Qt}7@<@xt{h&Z7PGa7G|N24mBia2MiD9UUC5`|vp|^g~80DJf|^ z4wM^l7W?`81N9F4|Gw+?$n^AdN;F~%?3QWip~1m$ZFi>MXL5Ahh8_&2V{0gUx3&)6 z1IRc8FY#iZnW%w*0V)d))e3G?0E=U5S+sP^)C+)jAQ7HDjA5jKM8r*-tAA|l7(Cd$ zG%YI>uYv?&djNIHkPbCJe_3j3ld(YZQJ!JzjZ8GOKd&G+J#w59^vMvzqb~-a{$&gd z+{1p*VmA3jMMbHmrlnzAx-`?9H3Vusa4X{z5vB9_{l24|0)h!xVxf2nas(YAtxh=y zg8HDk1n}6fhzNh&n`GKKXJ7*+<~DyjQ4Ma@wcwK}wa(N)2!0q?1i*GKDCh#L%PYL( zEV-ei;Jn?w>Z8r%ce;3bKZwkq;Z#btcsErg=t2lz!t=Zzz-XG3>IzI0Y+V5eJ4`-+j6C^yM%|_AU+|(2D7?DI?131$@qYUQi8;-gvVQZ& zxo7=;2pWKtc`c{1xY+SaPSU4OmIHZrF|U&FJ`_*rewP{-7w5vMU*`+pfrJQ~(~4tY zWgjP0#~|~-0OBtXc5vNm*$?s?K!nxPbN}^2&4jRc6I{%xW z^KM~h8@cOs=ljMLA8Cvh2X+HEGf?m9TQovn#D{l?w5Ypah40By($+RNGNMOjdTzzj7zdc9{ z%HGc$2~`wMBhnrdvm;JhFow)GELVo50(`2PC>|3oWW zi3>Sb#h~z+o123@6J8p*=kS0-`V`@9O-_de4Qm?fTb2Khv^S5daqr&8%|oK>N`oQI zgG4kSitN%TyFqgip;CmT*{qT@iZrk*&7o47PZVj?OsR;bor>l`^}FsJ=Ww3${rvO$ z=XpKPBij4E-|w}qwbpfA%M~j%3Vp~MA^2|Z>jTOBoG$3Co_TqBRwV-yD{O@+ygN}O z1oekG_hs%2ii(bYbIi#pOL_l=3j|8>-w;U>z-Ul09%cc0(+W`qs#Kb+hb>?9VKBJ| zEZyAl(hmG6dHs5yMnO!&{>(ctl)C#*+)|)&sQS-gR~Ex9f$%EJ_B6K6VVT*ujG1~I zel4xj8bJd7`wigyVd=}xv5!}%0#1`))p$4;i(?Fl!L6u>NL8O4y6#@dv6J#jOvw#% zimId4q8o9eq_S6UJN+OK9S%Vro`)!*AYKXL`)fhl z12^rKTP=bl`UqT8u?URkfqtE_F@W`wWm$nn)}UBeP|D#XK<=H{o8Gi@=T7O9?;e!k;v(B6)nlx}#>pA?rW$XZv8P8h za1CUM(N?*!u_s{ohIfk4|7~zEAvw98-wI{$$jAr;|Fv9aApwL^_~t=JM@Ps%R6I|@ zsox}Fvpua={>LXK#upcntvz{J{<-VTTRchQmQ~bi7bpmWceUW_i6TL$J#2@)Vaid@ z_*D4Ce;243wii$}dW=B7e7Q|)Uam_~2U1f^OagZrn+9?zYzIpH& zOvgoB#y;I>XQds^$Hl#QF8AAuW&eBtnoPlOr;trqM_t|9&>fP+FJ_aSP>`gNIg?K5 zP*YM-EW}zduZM4(OijbjJ@u$La(kB`8!SG$y1PY^ zExNC4HtiGA0II0BMy-Wm!WITjBq?}s*gXM%Ms~-J>E2WBHKOocJotDZ-KHsOC!7J{{D=C{ zn`zFRy~HWU`KGN>3(U`-!AsN(+rh@d^7+e`D7USnKC*pX=p37xw!lSTliA!Xe0(?8 ze)7V_i?cH`Z9Y8zj`lQlFYE_9WOt+vqRdOimXM6*^G)v4o$m4Mgm@EHZw4kN8)M|$ zemvjdf&7+s7{|ph6&W3?bB?}Zm~#=Rdm;X_d7dW?N;@c90B#!7ZL*;i(+v*~Z+UuT zpNO}Y7m2SrC>B7RqaGTLYJOFRDJ+1as^n*1f9@MwD?2mlKn4HHLR(H$RCEVO3s^o^ z8+auHmL1O3r+|L6#vs+SE??Dr#@^lnI769rJw@ZvZ`ZfyLg-_xzJ$}0Mp%p;WKggW z?5TSk8+)NADZ{&7rT{HkMkZZuOmcM{G9=+k0|KK=vp@DFpg1tN!!`?N zzB%-U7#@gW&V}!29i3a&L!)tAor?fMQWR8Xu;Z~;o+OK35p0;fTnuLrQo;2v@VU#_85u+~y72d3Su$#B^ z%^Q)88>L)LoA+9h1oHT^i(}lUdd$q6x&^AX3Q*2qzQ3dJ)ho#5&LO5^UEi1J9&GeMM6VoR}UN91JK2w<$0v=-$kFZ_7u&N=lImzuD7Ex@n^VJ;0qGgL$yE zewOJr<@8=>MuVbvY#N)@)iPZ+#>r9$tSIYa+YaJN@0}_ywhiY5RI{JW{xYkVxSP7; z1O}9SdNt9*0!Hkc^q*YZ!|~a0{cO96!@z$&;E1x$Srr|7`)B&9_`vY1L~y_0bNlvf zR?&OtE6Zae8m>Lr4SGooMe4HE@gwNR1zM$)VkR|QCbV&*M&1_eMJ@{bQjClU4{a@s zM#$JHi$ZKsrL_+AD!O>Z;&?GZZtP}SBpen2Ej=vi=soA)5FzK96~7Z2KZr!OE;(Yn zY_{$ut~N?$&n!QZfXB-P3l{w7LgSk4}xmXyFDTS7(nj;D> z@|~#7!otd<@AEIsU#xl!w}YRbKMl(U@ca9Xox3V(YP3UDo1^0Uac8thQuZ{RXVV|f zR(h7IOreMK>hD#` zQfiAj{oE93Pph&o7kDWEW|STv*5Iur4jRy8 zc$%PXMVNA}XGC=O72dLkN=JP!{KG!8T2(JSYo9}vq4i^VY6hPpZ_ ze*U8fC-E*oaHtFIPoG}0Vnxd{>tIo|0=`fcZ@#+C-T(Eg@qq*2P!Z_u@6da1+s$P1 zQs63tFMRglunm92S{*ZIj;j*MKRYe|j!_7x-6%Ovp8SeTUKEH-Ea{n&k%1mbG4A6e zsB@3a~(jCX8aYL`kNwnEJt z&)N=;<*Kuu4?Qj5MJ|Tbt8j468@Vf=^FcETRYpBOMP2N$AN^QJ8BkHYfm;e$vxp(p zNZgclQZYZ7t2BX?{5Xci10Y40LDedR!tfmS|;& zLpd}YR@(L1#mRoooJ5XC+xF250V6Srsxy+$7w+-dIA&=YmCN!BgI^75eWJlKD6ClEP^KFN~$LIzTuQ|E{kv@6Y-oP}p8xR6s!S zt3|=(g@XK|;3eiQgR`)OYmpb5l7MQnr(yPan~Pu!E$!Nk8%<43*!)e?O{Ql;=o%ps zIBsum56p+~)+2jUSqHuNJ$o+cpp5OrDg{ut9)!0i^c%yMIM52WSCEDi=YTDsjC}az zz#p+r;C%e*85U6m;;GaZ_%&!_6cikO`(O{SXZ%its6i^22hVJq4VP9!fZpEo0Irx| zuWEsw=a5_S0tX07r=mmFq@xt#-98+q$WL=QFEj1>*_z zB=D{3#4hd%vv2=85Jfqae;1x?J1g`|P2JGiRSJ)WOysNLL5NB;z6x+dBP=s6CRm{h zQG~vJY{{+q_rRS|@g_r(EfwjwlE)Vq3Xtl{Abw@`mTm_G5v)7(L;AXNkte+BIvi3<49FXa=-HGqEWg z%i5ovYHh)$M;Vz>PoZ#_4q_w7ol^^RJHbbUeV(nut*)*vOx|?SK+mId8m#K#frNVR zGVL0A3z7o5A$t`RAk*7;jj)flf?B;0}E0LBH4v4>84`z+Fe)5V*_I6Km(TxliXL zZZb+Q1BW}P>EmY?^{pDe!Vq4RL?HiMabNwD`-yPC7ykKIG{6R5t6f+BX-XBhlOc)oC-hNJg3dM!p}9 zmRAv>3b2LtGoC;QpvlmmKjRkn;Q?7A zbX!$JLk8M4HpFO;xcWqiPyZ$Hod3G~j~*TS_}8U@O)h8{V|TkD2pYKGA}HauY^0=! zhp;j;f6KPMdiClWn9SF$6zGAV3)uk6&eo6vgqx2f8$MI5h^~h#GI7&eYnMxG4+bC7 zp6SJZ)G1aeWD(SWMUM!yF@W_k4ffTr%p>YJws3j(mM3o)AhuywMEvqu#Buxq(1ghB zPzV4)XHYfJKmuY+%=i|~r6UHSGR0NS-B7gTe+C;RCx4rc6p0GZP>^CSDf6)0%7?+| z%Kr%|s>6J84DRi6K96{uwEVwA44{t+)ihV>a}R{BK;L z3d(Z(dRSkd3B?Upc?0p?BBpg;5hB{#qj#mtz-?dg=BiuV@-6S*XFhnao^D5x7Zvr} zhi&HnvzVE!yy#t>g+IGGW;u01v1q4mG)N&Q-TVPG9=o zfpVdloY${k_XNoZQ*bo;`ugC_#%fmGOc}M4v;Q{R^Z5x2!gq`z+MF9bbN>8(W#vPs zadbTYIXY+QSGhf66i<)NO+ulNG6^j+pfTt#YdW1?|;9Kq^qsX0?m3yM>;lN2MB4}Hl_EL%e2-GhRXImk2K47Lx*m()ji*ZUDy*I zFeF*{OZ@{5blYL)G%+y&HFiG1PMNKA5|fkf@L_`U;Q$p992o1K?kMBT8>1&0n&9vK zwCKtT2WVW-K%MF1qVAqW!Mmg@s-uu@+YkR+b1+a@cprV7B41B*>y=Jh`O8LIg zCRy1g%-mX9cZX1$<*y&;PBHTK`>^5`&|JuDojmaq+uifK<@8sROwJ-&rU1he*_Z zlqOYtYD}oVbuv;c{190SumQuQfddNsT}2MvcjtN^UT9Tx6k)H$=Nc&mM-BCTB|z=PkIL62^E>f1YQS#O8lGVHmO#f7)S7|5IYDOH8B* zvWR!BpK#V9ne~4ry&~ncU0fe7KA@wepUo{2M(^jAe>S{KaI-KuPPn}0uKs1rt~uiP zDALOY1(<&u#G=25Pn#}A>EK*RuMQ-%=pcT!M`a%6L$3Pu)zMP3fASzXE-4ACqCNm| zfZk~#XNQXYyUctd50o$ajrpL=s(+#(bf=@%{$9k5jt;?fb$3m$H)Y-9m*`fVx{v_V z<{ONhXL6k-%;x>)@NEzE!M&`GI%`R@1a#s*q8>9cY8o?vxgM>(U20nI=%Ld`?(6(L z7B=noDf^&73_5;4mIUsk^@hx*04cKsi0C*uIAZnm_4JM#QVB_kiw4P+q{0&PVmV64 z-vI?N<8Nq?0)oRt2=N^^o|x!-QjWe!G)P6etG~ZL;{N@~LKaP&RcxOs-MqKX z@0FNQdgAt1r$6`SI+xenPTl$KFYfZx!L?aGI(Boz!Z!0RqQ7?JNB1imd;%l`j?#QWA@<)q(G0DZMn;2Y2Eq(OwA*sf;6<}kp zgSt98%II}|g8v~bdB2Rc5kAPgCbL6`+2&x)idbhYKjH0Tr45+%K0X|VB=Gj_0lO#w z3keAWIH<=snICwjVQh`yaApl94ngx&Q@TbnB~8O5g;6@HytKn$%6?>2Q_vHZ*fe(JL2kUJH6gQa*S_S(1^Y$P+To+;+x2$=jkzqXqX5N#- z*i9GU8sP7r_R#xeM@L7z6`zv#f!oUvTXmBSz18X)l8l7x3*Tb1o<%z`YgT?db{Bj{~Nr#gTH2(RiU zFz^f_!*KCU2|610BbWIK4+aa5w{pAfoOvx@krLQB;VZoL_AIHwS9o<$ERaHEGS#*b zR%Ww+`ey-N^!~jgD)3=?y`8jlkCiuBWF={n)_n*agEfZD;#LR7f{kk6r^HK<-atul znVd4ZKybn61sbd5Q)|KfphZc;TSX~tLgxFZ z!bnqR930pkwgkq8gm69OLKOu}eNayi+yHEY%2`Shm~?V>RtrEdXm5fmttGwzO=n(dv=jdx3sczOaJZ60qK5UM*NBaeXVl}~C!5GhNaoJ3 z7os@X7lzH7H_y#s`S!dKp8(ru6Z~jeM58B(GK~I-j#B#feIhaF}iI{=^ar~FGxN|kEeB- z(v0+>_$nx9#&~th;TN&fQ_l5z&#mgNfNnlBonzdT0a_ksdYIhVCrjC_4+2XLsuN)F zpJw94G495zK>v+rkp_x^o% zi??CASl+(d7ay4`mzDy1+b^QFzw%lzE^qx&?pk?y4 z((QF$zkI>n7zT6m{O;xetMUyypNgFtKAgJjx-OuDT#811TR&=H;rhX^2q{rHYuV(DlO@muiM4bz{2E!SU0Vmda znn&5Xl3+7*|K7b!z`u+Zr<)uaZ?Ad^6zYSN$t8RK-J9yr+j8Q%(-0&O9-k||^*ZQU z2e6DDi^($xl0R`^4D?IM*C*aryOrJLc|V!nVz)2i()>x4PeBP%wzg|KDsQ`v=0@_8 zBHSrF*Vx5Z?GKTJmTRBSOy!I?DPv_hhm>gi*IMi|`Mks7JUuNmuTt8_?z|O& zS@yRwGHzsNTW8p|WRarl#s}RKbs8T?@@;;r*~~XF7O(}pWC80`7ttHEpTzFfTmAOh zG|Rtu>5R;l>;CDv=L?9iJhD7SJTz?F?Q*+s>fYLJKXI{<)z!az7i7RA+qR|omwWg2 zq`9uH8Cz8Ii}r!%IFfvC``KfM4z2H&N+6equpQB%PE&kE_#)W1_*=NXOx*y2wEg0a zQ_fnD>gXlvA7~AWwb_(t^Wx+MAusQ*33~dchuGeSN*uW?*O?*r$@k6_31k&?jd_HB*)-M1`Vu2|ArRSp{6_ z5iLmAZn!W6(UT^j^lkOn!VQFeWDZdB8*R)P-oQE_wUc z?)-)U2RHZ3tQ=m=W^%kHb-Jgx6aoP#DTau1HBihAN+GR9WV2zcirQ$ONpyM5qvj*E zd(Uk;$n`eqeuiqMddj4}$AHg7_XI3KfQjc_|4zpR6B7T;2^6uYOZ+I zX=uq(iEgzoM=u{%FwZoe zM)K^v9y{zh>2{A}JuKZ;OVCHd@zNmdWo7L!h}dBtzsC3%P(#h1xaHHMsr`Xjm(G4N zCt{eA{1o`tPethbYnwaQChoYqo3TF8XFJKOOb8 z#y!mT$4ai&F{MWZtey41qyIEKeT6rhd16qi-E&`NW`H__A!O|%5C92E;bTJ(qfeZO zHEexu$44qMe>h7h{|BurP~8#$-=?-mT)g1dXq-PC>^ZlVMT!n==wrvCVt>@u;!3Ek z`BlxR@d*i_(t*B&wlaFgn3VyKM-g3hIyYDWmJ@%JYm(XxXpRv?wI=MmuKudb?7*;O ztkrXFR3qR$W5RnMvXqVa(&46OGs49?O`msW_qT2_x;FN;^>{_@c;l^I$25BVl=7Od zl1=)#?=M%KeK&N-7pSYMb3}N<23gSFmdbcQGxw*IF#g_x^^VO0fg3excTRp78uN2M zDm}dfmuCy(WOwHdmKgnXG1EKkrJZjk5G9tcOO?piyavX|-%WooJ{mr3A%uIs&_&|B z2X1-Y&whku&EtzdJ6}L`|EHcF%yXX?T;U@xi9X}L(m76tgZFD28PHol3kh-TwCf^>IsZROOIX!R{@jfDARBhAD4GK8Pv`wF51=NnM zhBEB90sd zyGu2&ioyS))$Y@$M>Eg%2L$TOuiu#~2{|8d4wBpB{HJQFB$m$>sWwLJajDj$f-LOO z!JFw7WCrQC>4mTG18dvu&@;8YD0%@ifU(KRP_goH2>V1HKS@m`9QN)8f3Ir@0<7iT zygjqKjV%S9FPg(2BXm+TGT2$hCf)m(oiP}7C6oK77N=uPwmN@dEZNgyYI^jDQQ8SR zs<4qBHQ6{x!f90%n@F(L_~V)3Z|=GLSyX;iIp{aYA0Ewu2uTgh3=Iw@>aWlK(UV#; z+)Gu#x2%2w73Jm2S?y~Z-EvOfmQ+f8{_Kq>gifuACESw2E@R*3s%8|v|1u!(24E+t zpE^XEMxX~vjqAUN_w=uOzs;rKa(A0hmgaNCeN2>|B7w=HUjpugM@eVM&7_^YbEiGt zYV^Za1 zHKp52xP(@oJ7@Sp-Og5nRK(i(OLVi)bKcqR5WUBHoFKJH6Z&BKrcsP9LOX^jR>N-2 z`wyuOH%*_74<4BuS+3h7JCjv)mHfu*t2kTu1@otZ6pR($lyz@iJiJD!uD`xKd*AIj z&%T!LmlCCX|6bFWW>>%e@bjDJ*_1ZKKC)U~6BG+2SWfOPNWm=F30_MVJ$f*w_MnoU~&4ETus`n%SRcmt^=1)8~W4gQ++; zZE`SW)JC^m#3;NLV`Rv=uE)F$iq)L4pGa?NR1e#+KfCJa^P4SU!nq9G#-iz|sZCD@ z4W8Y*%kh}&+wIHhy{q2i=5?voCK^aIu&t#ZVaA8W^sYaeAge$8Z;J=xTW|E$o26hQ zebdWpN%}ZH4T`MhEJr3T*6CxqZjOpA7v~;E{bE)9t(BJ&;o=mp9pj^=p%UnsinOX& zvP|(N(PV$&}DIVpBWk&N=uU@`Ygv`Z2Dd_1i4gf z8GA(+u2R$2x(z43x6Q~Gvd`_R;``{(;A@2x%z2Q-lVO>)K6N_9@mcykD6MpiGNvgt z$5*mjH8-j-SUB`5`3B}gqxNtwpM`c}$4C=hz;%qmzGjW#n=0}O`KboWUT-Cbs$7Oh zHu9TC``5CsYw7uPqchQP_<=|0mSjJ^#j52^w$_8{T9;GL_I&)Q?to#n$RP*0jrrB6-cmqE!It5GHN{sX+*-%DqZ-+$fWI+6SN)pGZts_~U8 zbJ5GMEo08Gn$;Bj9Q(ggrPFCEOD6Cy+*&OYUq0O9?r6~ZVco+$)I`hi%7*iaZUYY? z!bh583xDTqz4{88SwB0{n6c49{+>USI)RY|IRe^#z`meljRg^uEdPxp3&^gB9+=F! zKO!`$o;MX0BY5o@84#!6(I8mqGp+{m{QO@~^)5)b&xXHt@6A7H`!{mtZ+(fwglbFc z;6XUlTk_ULT55-;#zsFHDIVUheYli}Iz$`mcNoG@rbiW@9xTinzU{MS`(|-*LHnMN z35J;z$KgTC%C6qY+K_!H8{&-ob8H<;?g-hdN!vR8D3;%HDupUJ-g*BgQu#^eCvs}K z07XE^EGYW>-th$ax{1lj1&bZba-H5>T^d=N*s8QlFUjfcn>UoHu|z}Bigo@EYl-mX zrl87TR@xfZvz6v>p~omWqx@%{2D+LH`I(pB4$?vyb?VO~ev7+=yR6jr)7v-IYkGtI zXd4otwydbwKYFYd-U+*$7H~|jcnt63p5bAcPFjGl{a=C^oU^#9WZNIN@X#_7EKIkk zD7S`o4We})pA|MuS&(@4Hs-4A3Swv3I)RJwW{cyQv`*bGx$dz^{h^0qdv9Qf zF;ZuH*uJ~X_QFjSeo@i*{I7XO-<(8U*FSY6av#(AGiO*!ouq`ypOnvEJkk`JVyNqL zYwf1vIz33UP{ZGUj&g|JrZ|e~z0;v(<6C-Tpt=K%fy?BnJMz-21OH)T<6*~V{v5it zpTG2w?74G@#s*EtlYr>$+^)t>5Sr`jpHTM5=kVaTnTQss_LqI99(Q%|Y~ju73|~pt zw&y)Ra)mWdcPc9pU6ABe8x1|GIaF)Ux;wUw=5ud|2p2A?M>?~QkmHF|QVa@f%)ek~ z+*x6J-6mXa%JjRi$V|iWn7XuE@pIeM20Jvi+9{q{g_$L;#T7@+RyVz9e%j4Vl_i{z zYY*aH^HDk&iEclExA^S&OI)%sFNh^5XwZp6jG%vu+`WrS&p1W%`i?)u+Mlc`DAF6V zo&|_yn@yy85}CB&(XGMA+ZDm~RcwANFBb`W5=FF3#)^jzr_DEoklEOdtIe+${Jq+b zY3K;v8bP3#D~(7w@1G(E7->cL52|i$*_P8($fjbkQoi~1ILiCw+;R^b`VUb=VEIM| z;PklA6(UHQC8yY&ot;dl9Hdw6jQ0D(QSt=0f9%49V_w8jfyG^;a4r(o5a2Aj=e5{w6T<%7edr;2OLM%(sA1 z-3l5MDA$V7a6ZUII|52N%n4Mk&F0$g34f&8Bp3LY2(8>~ABsknr&IU3v)~}ZVy+hh zhkUoGs3%|tfcmxKK2%$VhN1#g%`F^b#DxC(Qklc%OARo);$Z%mAjmrdpA58paK)k3 zHZ%2;IkX$Ad2h4Q>Sz8BvG~*Q5cgA!Y0lnRmy*e@1Kn|$Q>a=9P~=VHx|?JqH^1#i zxm3+)>7P{)-E?eNO`CQ-Xomu*L`MgKwvSGDVNfrO zzd-Vd`sD54?apfPBtLOVn3GLR!V)2%&>g|Hrodr{rryZd>+06!x#s6A4FG>=x!}>Q zGBOQmWJNMLRNmdRK6s;12X^-k*~y{xwVj8jfRV+vk+oCEE5+4ir%`&EI}e|Mbde+) z1qZfD4t29=*^T&`PQjpneV@N3(ObCwKfMJZ3Od+^O=T?^x}uMbW?~yzC06f{)KZ0} z!ZttGq;LA%OKH9ENzFK4-_3fxq?J`h>R(IhxSkobvJKPN(k^_T2^O{)ynm{dwVU?t z=~PoE6Qsh^^k?voK;bg^Qsy}<>9sCAYiweI8r)uhnCK+Ee)S6Gm+`~M{-RL1j0ejc zCI&SnKL<4s*U5I21a0UE5SEY`KLPr~K|TuYSQT76LhOqNz6)7IO!u5~jdYANm>OA~ zqITt)jMX?=o`Ag4&BtnPc5g`WSV+%8VA;_bQ3MiL?x1n(SjQ&K^8&w-qVUA|=&UHS zma7z|CJ*wiZ-32?cX@Gj=`BBE>XW2Gc)|<&NkYZ2ijFS-(M@2cCO`_hb4Rc>=l?%L zs;}``X+gm!l+{p-(~--nO_V<}D1l?OwdwPj0h{0FGve)Fv*DT5D+bJ)H$AFx*Voq< zGnTj=)T3x^rJ?fl^74oDE84jXJ;FDcwN6+u27T0+5k{SuvcLhGduD9kp!#!57Bwi$ z%fG)qc7;B(7on#Ul7%ZNT6p6|0vlpJiE+1Sg9=731d&_s0@$)I6<9oEVb8C+I^1>S zJz6C3uOv5szPW{VU~q2BZe-IEtKWOLrCnT{fw7%SPt60Rz~A%s?aJjpDx3ap-~5#J z)~kaM(rLY5(V}Gir)?Se9zoAt-h{+(AAkB*@xCsJ07S?fvvc`je>#^z;1e+b23rB5 zj*gL*g@i_UiV2;u9bf(`Bn`=uKoamwIe1&E*vVDq(YFL8g#!nD>1sfkMSn=j$9hfX z--^Oa*Gd5Pss$xKK5@P%Rm9K!d!XJG;$#2;^vJPV5NvsQd9ivY!ev0kUdT&_7%`~R ziJrUXos*#d>UpkLXf-jFFs1^zZ4`52r03@C^(t&Qti=mv84iTzo?tk<&0iet+~bLV zh8V@iu3q#r2l?=C-RctKRLV?3`?EjvNC?9>5uNRD90CaZXp=(^yVChFC5xiKFCx{ zVekk(`}dKNgZV)iFDqRCQNTy}gOKJWA@I_b&m{W;2RJBT%GvbHntkrT;@jju z<%_QZ8AoR{8@igENPW4Zrta?Uj9&5=_-9#%2EP&U@ReFyq?9nixWuS&RB`zM{RX4{ z56r}?{`-4DBnnADey%mvfCPkwet-rQ8yfI$w$H(U^#evJ7##mnH~9*02o`Rhc_4ed zVog;HggPH7KdCbGqb(J0owi!LtYY!6XOEhu*8Uu^TMJHH*k?kg=&ok`<2_3{G@!mc z2G%CtCcoti>7`)t@Y7j5wv1(y>i;l;cQ<@Eb2sxo!SNy3=fC*>1Q_&6F8E0j`kUJ+ zp|$uQ3eDeovSE^aN7+3v8cJriC__8kK!Wy7IWS1=cO#F3>nUiFFJWLXXV}JHa^^Sw z4srCv^r)cTflboZ+gpAc9va|H{!(EyhxkogU%q-`xF_a=h^S~uW#uU#2A6)`+2=&B z@P^%$Xigd7SD|QaXl>=bLJ;2Rp&Z1bl49j%;bp7DF8uiZ+Cnjxv&`viqRf&j>*x>e zKErPhZWTWTTL>Xt>TAWa>_ZRo^Ygj#CdbB33(*8$mQE3j#}jA{ftDmf`Rys{x5-il zuF3rK{$#ix-4pz&)ucbwpK59z3PbNJ*3>}>UjZ#Tx#*YBI-ifSTrIHgR-9?B6Ub$Z zME6(rKM=sCH_ZR(#$ORAS;;p}kuGUY&H*s_C zal;AQ08#zNroFrHG-es7zQWokTl02-Li}nuM%RZ!iIdk#S2PlF@$x6@cJOi#&XIc( zCfWlKjEp#5N%YL2+vFj;iTsOW9@w|wH6%3opM7KlWdY-Jz_x^8b=ECLfqOF{A{E^Z zh#M)aztiA9XbGtH*9V-2%nrP@MxQ+rFO;b8ssbI0St)Aw0cBQqJ!PFE25BcK$Bz&? zXeGTA>MQ+&`N>bhdY%;wBL$z?++;sI#WUk<-5@KoAd-908oa)%biq#T%(O#SrQGC6 zjBUU^fbt1w)GF~~Pfux>aG&z&OGDWj&7S6Ih3mbQFF_YGP1sC5oHWc#++>=gKNJUV z?eq>x*^b%d5WV=6@BNMEmj6=g5W4F?p2k}u_d~*%z?Yvh=ZO;`uFc|{@!TOM=G}_x zPvjtaX`Yq0nvfUepX(<5@d^k&9PuN&smY6f>qOkupV!4jS9DtZFKEOs`R5ORM^kf6 z_C_t3HIw;C948{Z2kY;eg1Mxk6P|STFAwGDWwO-5|MR!be!P<)lz!YF~c=*;-ke;by(KoT-wcoH@Y3|&)V9Ds&Yk~jiJ&zFN z6M?brt8s&MyF-g(CurI3H_1~!1}h;|#+9r&9@l@7s>yqZswG3F-nG9-H$78jYFRI1 z^z(83w12cyPBE7fZt*;)xr z-69qJXi&G?kIV10Ir!;&g$6=YKP$jDx=l98b*d{bw}DU?4v*o=rR-)dJlA0RX8VW5 zqngT@GbyoWQ3qiA?sX>av$pYY`Sly;EKKq_W>Ouk3*Y%|MfcOL_D96%EH&LZ)!tlVWgwVwu+ryZ62?Q(EiYOsmE_8>gnhRd-}5| znjLxN%{jcQLI%P|_!v;?5y_jf?5zz%goS;tgzj=)<@rJaWOA=6(v{8Yi4aO)ikm!v zCo~a{B`3q3`{0tK=}jw#;0u*Ob8|C<+>bU;KrTx8jIZ!41d;_U-nySQjm9&w6#ppy zSg1hW%&iRFeueyr15$@yXPu4#nswB34o*Yk+W$WFby1N8v``@}Wg${(NeRw-V54fa z2LC=}91sZQ`g;bO{UtMeu@jkyT%KYtp z(ub^^?b-c#ET2|V#^K5dwE?@B{(};v8%{_RU@}+g1lo?Vj;(DU!GB-Qb@bG!nL0f) z%ZkC5O!DM?`)(S5$^>4>2EB=q-qqOB5)t8!5(l6LA5GX3YZ3;s^9k*9S6H;1C+W*Y zO-L6pb)(1izi5XM5aKz+Q6YuEN?^&~UN|2PoD&c-%AHkNks{T4pHy*Ve) zpg3a!nY|I5h_Ku7^yw$H-E|2K@EWveZ#tFFmWj$OGUNkJWy|Uv=VEJvU$(eS_CmR= zM;ex0i!td?1=V@?Cs=s|u*406@cukA69E4>au2{G9orl$fFD9~Ipf1g?^Y~n#fgrW zmY*IwLJW#&36B{!tmY-m>1q#2<)+rYrqw0DwIYUJl!xaN6gA%a<`PkrK%4WlV;kCL zXZL3tOdM7&`TIBgL8Vm}n>!ny8&m$*7en1{#Xo;ol&PVnV`Gz46&yy}aQv4e)NcCC zB9vX_DCD zQnU`={KkBg90f=NR<*g?nqFoLuc|bHQpE&Cq_+f^o zhDZdDT}nHoGt*$wg@uMfLI?kpD6%whx}-i%PxiZaJ-os3d7l0*d`~!!&GMA%hGf+s zt7hKRh{z1`>Y6oc@}?)OMMl4U)6aE!7M}{KA>oh_M8(!QAaXjC1WiJs82eA08lq47YcU+(n1} z`Kmwv)ij5DkTO-n{DQOV?j7OC;ph(q1$)HZK~QNdz{2RLC^Uz5xe34*siYt0@#Dvj z*oOvliCu$bTN%awK1N$)Y0gQ;dS0M=L{GtDFvmakHMhHQ5LPI@j3syDqh4FazW?5q zXf$0=cVszGO)q>}m>aNe+v(jUgar)V8lKMEHD{izon?v-eO!Jf^;$B|?}i=mr!F7y zi$Il)dI&q6Vj$L{?xx9{1&Mph>5qTm8>3lRqS%eW@`P$Kg7*zbVBo3&Lz*}vUC3;g zGcuM{R_42mr>yBkV@M0@&vmg$Y5P~gG$Ba<>PGjmm)y3xuq@UNt${2IZe z;a0FI1SzNqz}$i03HtWtJl9E`aj08l?P>hiAnQSbc$!QGM*Hx@4VN-1B++HEHv{Bn zT=~yPhZciBFMT2JFeKLJwL{HhC9pVQ_M4 ze%|%TDtJQpbcAzCVIIff0K&gX!jOKc z==E61Jbs#>Oh=8TyiIe~v%+YjZIGGw%CY^&?`}57o82iTHH;~ZOr`|*JFab>Leo?I z?merffe~PX+H~pvc_rzxggJ9&aSj2;W~0uQQ_#H!-oIaZcNX8#SzYlIvZCTfv%DXR z)_waT#XlvsIirc&xs3|8ddxePDdM>kR3(*&~dXyQc7H2^cew3-iFB+>qP+qoh zAv?1kYgtm7q{h~*YCV(gL$y<_tz}`Q7cagn8_cP=*^qg>V%KPB=ZAaaIhmv3Pfx?T zP5$<>VJxjl8ODBcs3YN40ktxrnEdvQS?9_QoLj;YD>Cv3dYW)v5uqK~hoTl+vB08s zhljo}y1WI)f<$$n^h4cvfP_T>t5zv z8vcTD6Nh%Rkvc;i6aue5zw@-fOM9=HCF?FpK@a@DujW&jxaHsv#DOS;o49*V#;Mj- z?bWyUJyd{Y-OgRR@V~>c+A+mKjq$*4R+>(t{!<)phz+dJ@j^5x%EO_We;jlrhNvO< z?k!NB=eL##Hhx3494ne_bpwcF1eg_0e> z?bua~#oKl(uto|jI?TE;nlj|etmxrX!ozyH7?=+M;;+??nF|QRpw}KyYlxSykVs#c z*;rYJkn(ut9r}!|t*srG?S26G7^xa0>Xk7Vw_697r}+4>V{Q7ow+x|QvAnpmqhrg9 zNAuUL=b=L(uRGPkPRbs<1kpDg#NyhYvp>1{H?VUm0NveiH(; z#ful?wadxKI6z1e`*;b3Y2D6m`0C%j!6OwN7dcV0taD4-Sp?NDd@o|>WYN~iWC`9D zBkV<0=cF>$@G9uootqr7fvMAJzvyTS;9_^+Wl9UgAwXbWxB{Jv897iCPQn94BSNkj zdtb6EfP!pJo?I{vN$Fo#5%w$YZC!i~w?tST40y!W4F?m2#kFkSr$l3fvd#9y31Ke3 z^{Op`=b)Q_6zqXiZ6YOd(TKuf7@W+t_uePs#jHqSRis=MR;bmkL3QLd-p=l71si9= zRpYG{@bP>N9%y0K#fwjT)5tCrsoS1iq zY(9}XS!1pfC-p=LbCE#BQn-k9&snT&w1hJI|Kq#j2qXBy#di>vB%G?WNca_nUPvUq z8bm6LkGAh_RPdl~lfuy?o=KpHf)1*uA)~D57|eX4A3YMylXRc{;dxsMg7hy0cHrF? z7=p&F!}knwBZP!5!?e1?4G=k?w!|(w4)wDa)2=Zq&VKAAl&i5b_ZnZ2Eap>CNFL(% zlONNsR)gciIeYuHn-A?iaNq!hfmQcnV`FiH6Ve`4U8cT0i3A8(8;|*$bVH(nc22nU znhn4dyIBum&1yXSAB`8(80)`~EV?G3Qz%rt{9q`Tp=xB;Ly0}C?01BNnWJx~@x-TH zibvmdQ_i=`q32Cu&*L|PlEch(Sa;|+*0@e&JXl6Wm+Ly?1;&&0IDn+?qy?1XQD}rf zI`gg-iQlP!H^yq=f`E86wz>{jL1FLSq@*NNL6gHhLVIeFTw$YcZeh_*qlq>r)C1b# zZ(lhZulKkQM(kE~qLgVA=&)sIxR8jBX&6-v?7-oz$*h6 z0%05$ZYZ;2=2G68xlh$48f-mu`(2^w^z`&Q0)^tU2bnKxwEx1q@R_67uhezGyGn=l|p2Z-w<&w7R-0>1rK2Td6E7Hl}o zXmv35z+uqh(JbtG_mr=ztHI3Ob?h4t*W4?3`|~n`$F!R0^; zMeSD31TCQ$gRgboSami^^cb?wYpkX|5Yc}0Kn>P=WH&r#z)46_bq*c+h;?I;?=GKT zyOfH^k^xJ&G}Np&6oP(zkH3VzAiP%YzDLFJ#gpgpVzww_UZ|vS18nSvcCuzz5cK@E zEiCmu3VZ>iS~!ChZ8|z~jsyH9_-&yX!7#Zp#B$}v4Uj;*N;KiuQITSt`{W*?O~;^$+=XH6!B&5 z5!fxfb3rBc7^a$x9sr#2#+fO_5GaEmux-Z<>XEGVs!vyh;3CYqZh$z8dithBCDWtK!c0pqwa^3)YtGe)^dM5T_sC^o zaXZ_c%nKnx-?Vx2X}mDxwnelh9$1Ta301|78~dD`CLn^qOWcHR&e-dwCRrh&PB^Gz z-kz484vPvn&762U=T;~HgcQ1lJ$-#XFVM!E`%>I2&$|RNMsOu+ug8KdEooH?+gKw~ zFILNrB8i+3l8{)rY5TTq7d5|Wsj4ze+zAO`C@y%4Jv<9@i;dpu?#p{Z2A&cV6Z=a( zD=R6%I6LEv2afV%Y%@lbKfb7D&3YRiGKC&f=wZE>haqv^Dus+aT#y%5(_Bz=b-jH! zUmB`XtJ>J77Nx5SoY0yjFuaM)5+WERa37lTRwZNhIx!v9@=gs{53pVK{8QNo_0e=Z3Jg$vh z@q9O8VfIlMr@h#C!7J^r>B*l?j2^r!yloZG&P31St#>=-Se9yEg@L!2%M$J#=RAn6 z&ficb$Z5$iP(!hvt#41TnOi2(*sER__o?9qc;mouD3&sgoO-jb`ayEs2; z<8?<_Zn;a=@&^GRzYqI@SkNWza{0rdqPU0Al3we$SjcvVJkZ`qR%{~B#m-z4A>!n0dW>vD zxDgZsns>E+0u|N0{94<-r5Z%Y~hnQ;)7P}J35-TC(D`RJtO>00E9 zrSy;b^QjOe01k$^x#$||x6#VQ3mW>h#Kp^q61piwFPg-Mgx5sJ?~6vHtDC z;$nvvtUGgfDeU1j8028*d3N@Bl;|YW|Ekwq$`|?}{P_%3 zIj956&YNV0#F=(>RBjjA-?#bdNBxKvt}*74l!T)6guq6T^H;KHJp-zf8Wg7<^#jBc zraxY0i!;o1X>qR;9xHkMc%i7Rt;LeoBc^uu%Ht>b({iJ=bN9A1@d}viy({BhUFb>C zQf}!vz3|5|;c9Umn=bQ{sJMS&fb^d9uX!Lon<_F0WSvguR+JV(O zSm+r!i@7MKxBH6cw!cKA^#L>&%>%GY64Kx@^?oAP^YK`e5M$!7WmF+g{Na~Q$;tM7 zyiQ($WAATl%6q5xg<_hSa%-r%NNw`Kcy#cD%4ADc*iGr+!ivpnJgUDvd3QcYM|ROd zih#WtH~XCnXY39yeJPJZ!^yKpu4XZd-9_z_PtuvGj0>n(cRJN>#^N6k>B$UsKekJ@p~_* zs83rxjoW^_0d`(Klfw%gXcW`Ai`wcQTef>Zq!cb~w}j^L1K&kq?|dw)%gJp9EEK#J-*~IAkbF2*mCcBWDdSnss)t`*6v6g) z0q$Z}R(*45in{Db^PO~F;o`~{R5W})-%FKcTTSWj4NACo!M^@$gJNdeO8eyx8P|($ zeyb-sbLjifinTukZX7RLBXju0=6(AnS8dG6Z_M1Eo8a|Xf$vn__C+;T*4Bf)I>B1P61 zMki#2k~PXKj~?AN_9eqPChCfnbL@rZ3PQ@2=Ovv6dYV}p%S9`mB`>0I%FVf@rN#2s zp<LWE-hdYQbIkXJS}>;S*C?UH`*(S zfy}ewl|%jO4ISNCma35}$D7R-Z;_#HnZtL)eV}u-xu1N<{YQ4$!2tn$ZAS{buC-Le zG&jY@UOFU7uG}pW#J6h40?(Uo?>%{PD5~I!GaCbCn6`bmyGA$acto!bqXz@Sz~tx3 z)Z)r}vQ>?Zszo*?`>8934pugOOJmaOTG0J|_Ek$Ycr8D6%;tqDM_w#T{*cYdbvr^0 zqqYXn6WvN`$^PG>d(jf2=#PfAOswzSyJNMF$voGtrZFvFJ~riMS{_m-Z#o-=Xy?{aMsza@18y!;BESk@ZY=5O< znagFE1uXw`UM^}l!tKzpV2WsCcJ9iJ=f>wQC`?b6)_&w&YfJwB7<=z{tlRg0+$^hHR(3WQ z4HY4KT(;s8QCX2)MnX1aT()G(=t2n@MT(4yh-7DmL?L@+`yDU3*ZcSR<9k2ekM|$< zZCuXR`8va1(9PPl0!={=o0)^NN)AUry4GACvQ7OobTtuAiTdYvS+`@_?#+L5P}i(iHUt$ zT3Y;GyBINIxL`UHXa@(i!7~&8d4s^b3Kr%w+2VJ;|GcVNU$n5cCb~NBG;qIq&WF$wloh@7D``*&UEt39vAB5imhL)%;>R>(VQ*dxz;!PlC?k zjZ5^+9^@eTy8vo(;+mSwQ$yt>!FfpLefN{Fdz2=n$b`o4T?w9=Gg(7qM17ixB1fe^ zCFXt0Ic6Z@dUj{&Syn%Ln@zS_mA*8x2^BWr{TFwz0SLw)pdKq_jh-o&UV(IfKTbi{Mn^=63S?F>J+hpxn#my6bkKl$z46|K}AO*Ii9l4C%&qC{Vl`bud*wQ9GgRgRqP0Qdd4s<8omaz zS2sgJ`e=d}kWX99*CFWjpr;)>X;7=s(e2e%aMK3j;iiRpAFyWlUI<1MKXxp9@7woo zBc2fSzlv#dQPhea6sqQ-D7Jse^v?Rsgz3u}gh;k+^@(?0q49soC4En%&*c-LKjM(U0G8QTWa6Iw$l%TcJ$%ufq5AWgGws27t$S!U*&s zOikmaoe`$=P|b+u6xR)($0OwWz$#2idIi`zaK%{{J@8L*RGb#$re3S!;P4LOEmW0Z zh(aDGE&kQ4h|ejSgA(-z?8BXvx?nT_5I()>;`}@=B0_K22U_5@4G949)gw>C9A83$ zDH&jEU?R7H<)x_TZGg9Rg8-XF!e4TifGU6l@`XierHBe@@Qa=WZa1Ha%FXWU}3_=@F0%p%~N-^z`&`dIIB5F5dr47wJ;eo50V< zclpW{V2g#rwSPtf=Xr$<**Sl2$4NcF!ofav2|nu@Nh6`gM@sF75@3OJ+UgUN?ZxXr z+JuvlnTF;O8B$ME5|cc6s`rHy3n&gm&QcsYbcmAD<@Rmx@b{cTt&F{-WHv)Yx^>%0i=-l+yG0$ZJ)yMVPYqEG~QCwKR`FV9lx*|G#P4@W_f@WSi2gXpjC z-|vZ4y?Fx&MZUJR(*!8g?5M86)03!!0WZUQ_j;$-qMQ^!pQfOqnr?e^Z}dAM(++Tk z1C7h$>|Ra$1bg{uU{jp?FZ~V>^na{ ze@beq#d9)jkYd-pkaY+K_FCl+ZL#m6)_%xTwp*)G;_=-|Oe}zH>4&zWiiYig0jMdi zm~ivS(+COpRAVIT=6)~fq?gEDPCb+&wsL2syYabotR;DL%uZ2Ft8E;J$ln5SNb20V zFNHG%Q9>%sIoIR3Hxd>k>Go>me^r(_MoL{StuhC1EAUH6ZOTRS&E8ft3!5-HO31^z zvb+p)Jqy4>fPh}7Nv1-h4R|QP!HT8#Bw(RG+_42E0x-^0*^ZMophZPQD5A!3#4lkgX(C;;OWuzPo?T~(=8$s$ zuNoSf66@BZoW~{%%#GPJGgNybbd`+_i7rqxcU&El8%9z70;3&nu^zvTfGVHJ5I+Xd z8-}gjWeymO_I+Bp&G~x9%`oYvV+Jqpn^fGfuJ)y> zkP@>u^$xG&B05~Ri;vI!`o4Gk?m;#6!MQNb;L$x;3b{-Kgf{RDtXooo!?@XH;L|K`J^713O~yw>hOW}tXgM z)Tke@V8T#2Hxnf>-wfYXKun0)hCFE_@m3q5fI(rGFq2UB zh56?#TB&RBe@cVGub^gdXb!zUDK_hX-RJY5!)a68} zhPO;nQLE4e9oNUP$a-@M!8EPAKIgMQ{t(@GKtQ$bHuVwhxwf~aV_vIN9!o8!X=r4? z_qAH4hBZ~hDk}BVHKvU|e9&(Lsh&_f#*?!%9ej;VO5vp?c2@$;iOK2VawWO!(3 zc6-CMGdS1%hgL2O3WJpS0B-qxL`&i0_}pqpi2GA)7K`q1^|fKsbD6!7XZ+DC*KNf6 z_kl_ae*j-vi(rsNb_{0PQQBUC&w!QO;YkH2t?}#~wXFI!_eP(m1}WZQ=OM8~ba;l(W}-zSE?*Q-sGDw|#U2vKZQaoc z+=PPRO35u*-BD|fBTWY&>x5tnC+cnzL4o;(8_8`IuXCH8p!R>g^ou;M=jlcJ4-vrR z?k_z(a_p&W1wAu!^@*GH&?8=ZVXnMXXnarHA*_L>U8&>@i9f}g+iQ&p@E+LrxSoy1Ezn&FeI|4|Cj^KgCh${|ZnQd2<9+(Hoq6 z(taqiBr*8!erQTizAIb(0dPykAVB7BE-7Nf*AwLr6P`o05}wPsk_-|sIp5ge7Z8A$ z4}!P(+!z>TQjJ3qK!(Hi4GtO&=06@{_OG)qs^T}k4m(7#8Ojrtvx4tb(%=rw>>F#) z-6A(|!WtU(&ie8BjXas=%7a51#x&p>=`|j2&~^*U1u-)0gJeY`1pSa}OCL=Ia{RZ+ zkhN0!28a#}I7N1*sLMcZP_-P<0IEU#(gh)u>&EgV+!uHOm|q!WTm;12HGRSk<2(EG zw&9TMaU%7*Ro9}jvUomlHvyHv{@S(s4<0C8?>LB$K}JJGrscxbM*1(TR)*((0wDPL z;Y$C**K`Ury07NO#+Z&Ai4eWxRHWFKX(A&)5USQHJD^UA4?cW|ah*su-}91GDa{SFdWeUgkz6k6B{(4KuUz-HD^AJAz3Sm z0@8#2TEHdK%#`t{kyk5r2;E{z?kc<-fc>c`}`jpLK;RhfraUWo!im^~Kh zeE0ElmzR^&SbQ2!-_?5ldGb`&SUFw4xMrN=&;2X--yP88)`d8ng2m ze-s51;Ol>>l>F4|@xb@uR$mLu6&I>40B?2CVTA6zP5KLMEv>rLeq>U&V1L?Iz;2T< zgOjZEMgC!W54O1Im!+k-hV9kTgB z2WcZ62kC{yEaXxyqcJmmn-l4}3u;UqP1;AlUKBdwCw?B`lm$W(&|bqIh*nDc;CLin zHTlOOv0yVn#beHXna*V2F3&V9uB_CzEx%SRVM4k7?4gtApL`c?mIrC2yX%~$6u*Ix zxw*RKa6g;xNIDxH@b(ujFO7F6)d1y1t8J}1I60-R&Rk`0InOG$6W`#zdxQ|*X3dfD z0ZcljIt+GUyb)>irj&XdkX6zH8&=cWCS{%h&z_xsgbMOu6?J-h5}>QB`}@$9>a|BG zeU`nBJ>vKz02%ajfJ;QI30}EE0x_*{gd#(0QPD0?41gwjit#ZFbJT#!QUG_6p#)*O zcMt_b-7_EESHd-Nmpm_N_=({FdIUb%lGatoTWfI7xpcpfKF2{lSN~T#dof&U77Z#I zsP2Mf0kNE~wLy&YJD0xy})a_9_6tlyNL)?VQ4o z40Z7LK2?9ArhkAYIrZ-V$nzK4t4{(*IF=Z^tkqM`M$^pgw< z|1SC26aYGSoC)bRxK9veK=JHGF{)lK>d$<0Z@{&nL9d)#5E~oIB5E@-GjqcEzM-z} z@tdaE(WD4@N&@rGEKw*h6XIS-W#LnP%8&z+=l)C%K{fW~cl65JS%HBhGmzG?SR(%i zarz6pV18CNhk<}7dm~TyyAjaEGgN!vlN8Mgkl_i`F$#MB8Ybo9o7#@Pdz>?V0ghub zI(Y9iRxMykh&vM{&dH@A?EKaGKd=mR{#WdhI4B>0Ar2G=4?J1qe8)OxY6C;FjvP-4 zs@c#31VQXAeDB{gR=`xVLC3n#i&uv&5!0t}yL^ z|Ey0~K4+V*@A3KTB0vuPU%+PnqZ}3g=cB+#_|JqIcx6lrox1QD_8t(EMhD^H7?|Jf z{mnUn@G(*F0sa}wHgR5o#BJR;Eug5eL4I0XEZh)SkB_l@9o0~pqQMBps;eHCkwA;z zU#(!ie_dSWgD8EVPy@=cx@EA&Jpl&Sjah>qKB#yisVTXGkW^$l426TYJNQ=I!zKp5 zq98iKhgtaN&)RE*awrhYBOkyPh{zI(M-VX_UW@Qwi@A@SAs6S~H;j|u5k|mn$@~c& zG^Wg^-F%}4vPXeH0t=6P)&8vfAQtw;+i0k-ixjz-qj?2nvuKL(lieu#D+95N;q082$h#L8u&ZETB1+yWL>d zha6hAf?Qz&tou{#ee!@J&NCa@F398E>K?)GHX^cUykZwzH_WbZQtbUy1P4_5>(o{u z#R8N6_u`^r5KK2!)b@WU^5;cx;QzHXHP?fX9 zzsm**O@PkhZW^p1X%wU(ov`46Rl^1g|IICkw=Ly`p#eCRaOMKU3C`*hltJiPf4dKVDeT%Db1M3tk2ESwog{sYR^yJq}73vZg6^6m%{Ec|TnVbpW* z|6*(?qWE?N%%MSDMOpVu(5J7?p58n{ZnF}vikRNu=g+j-l}_N1hTmBva9fI)CTcM%)zJB^Pu6F zeexIRy~n{Z`knkAs)&(Q%3o9w7!)vLAg&R}-rd8)eh~|Hpj_dYcmkYLKePTbo_lDo zCUAhCFb9J=s=EEe8_CEsRNtDz`S&Qy;ZJ~#`z`;V-*^xXMht;ypP&b8a>!{0|Fi5* zk@b;;{hU)|;=69SEClIjg{SQxjEd;#=_=)@-Kfbv4XzQ)WW=J5`+^8>eb6x zfw@Ty{a}^32rq}GqT)LUAAz)4L$OZhxgi-gnbW6BNCrFrg9dIKAS|L&V`F2P7u?)d zAGmLVWCI0$ivx~y+|w^ywgoq zl5N&(G)Y(P&P>?3Ko5g91%T@0vDz5VqYl76mhoJcw+Ggx02NS4{&07=G0AKg5G$$O z5OWyp?d~o+{v=D3a|&oOa6`fqJ4TBEc-alYu6KE0Seb$_YWA-cWc?&C$PWeWkCHkN z3c(%c1yBpIss2)(?v1R0(C&61E(^# z9~hz~ArD|CVI0LLxsD`p{^a_R1OE8{k1(M4hN~c~Di=&~BNGb>3ZVAN{#n~h34Ap2 z|BEW6MTQ5iq7fW1G|SparwB`7I(>k)P5^gb+MR4Co^W9a{3SM0(Y#WXQ zs95`ME-=CY77EaOpLKHA>B+f1sk|nMHdk{gJ z11uT>yxDnGbykN83(&M`_I2>N}q^yUMaOBsdh4`0G?Y1sw8w4t%+oq$Epr7nI}lz^JDe zASkE>gRK_2CxH*EG53JSr*yPI5#;$Ri&lQ1nS!32!fg>^&ptawCb%lZ+0fBtJ4g9w1)y%>B3Wmg;Kg|)?JiOJ2u^vr8>adJeDg-7 zuWyZO)LSQ$jM>Q3i<;Mw#bwdBxGaHa&}1t5jioUv==VL63v0&~`ztANw5^!Qb5010 z3#EKICI`;f{ew72N$)gA7v6?0q_@UTZpsKm zv>Z6eTVptXZL?@}yTfHh42-16)IRQzFwf*Zns*v?cVl=L5N+fh2M+M^6rlG0-b7n< zp*ht_L$Q3C2-}|mGAUZ6m#El?6F{{Dm;Fn4hIt|2Lkb%S$fyE5aPL~7FWL57p zp#!E%?LUEJWdb#CXVX!OBFgaDm9x&N<8bJXRl@so<@Sw*(Rx55RCYo*eA}!?5D^7X zN#MxNT62>7hlI%_hv5p2DdhJ7S=G?c(C9m|+DUjT7+r72Q{rG41cL~r$50Buc_f1T zEj5}C!H0Sqpc1`;c^IC;31U}}^kj&0YImW5!<j=gJGh;dJE@Pq){f4AM-^0i`fPQD=!j@Mpd zID&+RG-&%-Rt&>>{Lsc4=g%`#tMekVjlWOs_y~>35YOD1xJ{f-BjY?IT$#s@_8Y z%ErGY;&)8;`kvxRf+tDvL4k|fj!2mH8JRpc_L?Mw-OAM1@#o*?KB2?{@Gbehao4$< z@Z|Bgdq1x!`ah2oIJIX=O`ue;JM-7D+UmaBIoBzAo>Q<|JonJ=OL6e~kTTQ~hXT(x z8fNCFe%oMwHZo%7TX}K6&qS7Xj}Vv2kx#-UBrM$8-R%ko*p?gUn*OSopaw?a0T=Cq zxD0`STtJmSiU(*T(p8Oxfi&bd05^C8sqh0|O%X6AjJ%=4haJR%a%p~PDPQktY*yBH z*cMn?1_n#0+wJXtLE;zaBjO?;f~}!pPwoWjx^Dkmh(>-Brfq?(hOGzIYY@1h(+RgJ zhASmS!kN3KKj?qg0QQoi(Qb<7Ll>wn>-{0Y-5bmafs70)@q(-6CxIIi1ab&4+WcoI zrvurJbl?$@o<95Q7rbIu&tYJW^J!q95{6r#NL09{pg<@FupIowcMTwp5_50u6};2d zYkYN@y83PM=_$>GPs(qy13m&fxIpgVW9~F7F#`!EFICdmzJt z3a1dx7*OeelQSD0sWjL@GA!I}^!z%xhR(CSA&91ihT=Ck>6m=?&)lQ?9LPTq)raEZ zI*6`?@gJNyVAC(CKrd^oY+|IEBJOx}5#)OJmAc@K1|tM3NL`g&Jcfm59$%hu|9*fX z+ud)B#FvpKfeVgwOVs~7c0$A!f@q%L7PyO!PE1I^cnUjI>Fx-i3|Luk*8tJLyB9*f zVA=!lH%xRnK%+k3mk}xnlyfJiQ;kBPtsQ8fzI+yHGboRMI{>#joczH5P&!9p3gPg< zrnGh)`)x|Q{JtIv_^pDlT^U&Mw_IExXC2UPsHcdCi4o1VBL*sJRyVst}pO2l>e8o4u}m`pikPDiL^$KcoD)9C08CQG`?j;_{l$K&RpRON@EKv({ppeZ;^VV?3X4AqC+Qv%|LDa z&uP#Mx86w@lkoMjiQ2?;1;E(!&Dv-4DdEfk#cY~{GtoHEAHt%dj<|wom)JzNNSKqtcx83f0W|F}BhxX|(eZEb z_xFb(&4@k-Md_GdygHJv(v9Gx)E*AoBcGTl=t z0Mfs#)|FgyB|S*!ZG=LDI3pi)T>2sC`i)TveK>@Gv%xzx0Ns-iWH>^+6LCchZ?frrzjRU~p|1I~KimB~4ys|kY*p3%kFvy1fg5b0p9ZqXo<`1dh^sIc zQpYJ)c+KhU?)Y?_oBGHFMz7ViKl9cc4qzgW%3O(qS)eA2a#ygjP_IKf3+)q#W15Qg z=7Qfd0Z&o&fN3oh@bDV0#sB%-%uVlT1JOX|$O=Gbo6e;}^mb~Kj}JT+clX~=kb^Rs zS6Z5ljMrDB{67P&`D@3J^&%<+z7)hp-mte%O-T_tssEpo!Ui%reei?r?KCZr_G>)# z5t<+HH?gNMo&V2!6LAxvwb9W%IIR#jk_#e}sfwfeH*i343Tsa^c z(ffiegRZv!Rfw#8j0$v4w*3oTK?r;@Wy|wLcOBgXW}ADR=6-iZu#{c&eOn0h$Vp;4 zuBmn(pPIBOSe?-mPTIGmOrZ(}17cs_>a85O1FWpA?YmlAT4W$*+}wu&ZZIvQ;#g7e zeE^kqqb9sxq#OS(HtyZaEuA@*g+JgnF|s@8^62WzlZj0)4m+fu-CQXy9+{Y6T%FxC zI-QdIM?j%?5iXg8L^X06xjp(!|8Jn%qFZ}23cgNL%N>Qw_2q*H7Bl@oCDWy-Z_DV7 zhEwjy$&`v;shI7n^4oD;fdZ57VN~7f=YC5~ZL_g){?%IF#$4~dh$BHIF}>KrGFii} zSes9ME)9m}a=&LB-cPn>tG~ZL{6hSrnE-adWqN4N14tC~nt_S*nD_c%6D@GraKcp7Bdfu_eC?DDain=X_fo!N}f9|iajjzK;pNTwL z*u>V~Lj-cqKxG+G^X(-Jaowg3BY#%H25jJrz$4%la?u~CDy}PX*EYOzMJrWI<;KwZ zN?@b(og~xzOD!}!-1Nl4=NLbBQVK8Ib~WnfJf}e3W|A1416UqO|5_U29y&Z~(cDN` z21L3U7mp7oyi~mKME9&u6rK{V!7HQQuQChraKFWuiZQH9q$_pxzR(*>WC z>@TqFl3+IVPbNKrs2Ch%iEH4_Rb_mAGV94m=d{Mv0G!DlM_X6&X^6pVmwO~ zM}1_3k$xf^~}aka=F1Psppe>!@UeE#e2 zg9oT4zKxiL++s5@I-~1lk4_^Oa%@EiRrWtFSH8Sgf$e-!6IKNp?lAFwAgw%@CDoq} z9;H`%kUQ#hKlX#%?jD}6vWHK5+M!k!!aS5hf_a`RB!QL9kLBIMc2WbfHxPGOW}{N`s@e@65zJyiVYVV^rq!65F+3c55BtT?Q%3 z{K)+M6Uf|gAy+z}+U(tnR<|bMUOt+j57<&KZuX5;;RYw%g|z;!yWb;L8HC1;T@sz^ zKYQo<<2w@3$+SHT(A$qq_Ho|aZ1Q1dHRG4el$qSPttBg5^HoYe*CH%B zYPap;TB=XeUv6^zs$dII@u%Za!91)fJ{U+K+mrj$P@#uJaO1Izx1jBtK#NI9<+B&$ z*hXQP{_Xh9p2Bf>SGv17Zd&Ym$IN~2WU^iZeVcaL1?{h~{`d0O44g4RJ4)A^;(&Y4 zD*i%0;+>cE+I&EUBW|X*onr|ZBv({CvX9DE*K>Xanmiza4WBVgo)Vt3$^{o8E0n&B2vfX}tQLtz!FSwTqyoJRNtXa3e52);NfEz%}(|M4;)`f#uP!&CvqFw6ZdWj*6AJ{K2m5b~-jmAv;b*J0{XN-8U`N z9$LrnE@MAGrQwv+43cRRb}cv`>H(N8$)BL~ABE~sR2Z2Oh!`})(pjgxQCKMt9>sNW zQOuE+&Tq#P3#q^zb5bZn;x+Mjs+e$h_aS2!UO9_!_sSc6O7w>x*_Ryjxs;tG^0Qst zB#&AuzU3Vg-&qucT=Ol7KTUV8`Os(g$y>p|>GD7=waj8zS?wn;m7MY7*I>nGpZW#D zquyU|5|)IHP$683j$AQwOdzoI?weLwJpv`xy{}k8Ucr!DxKVM=?Cdiz-4~?C$0#cH zhXfzsqzCuFjSx*MHRJkOGokySX%qC+cba829k!}14o_UQ(7ej!sMA^=?2Vb4v()h%ZxZulS^0Ty z3!rZ}zM0}3(4Vm$fw>@U2mcYHF>$#gTzP68r_Rp`AUF}UA$eOTj&ogVqBX$A+=_B| zQC5cK%6&qFuzs%3Qa2}zsmLGQ#^bhrr(Sw&`06R; zD3Xqvp|er1b~>pESaB->X``3;7Irs56V)xS_#Tzrw3sz9MSfVuu4}}1yMl{Tg?*cA zs;OIR*`<4mv|~wH2$j=uI&yWzS*sltzjLFng3UvV@9~c*>dQfeg#lHv!>Dj|aPiA7 z{DoblsNh#4#gD!3@kdYc#b4B;!N-6FeMA;|Rkhvlv>@jZkMlCaES`#8pko2&eQ7g! zYMDq$w=K%9P}7Z<8}ns9)rj%8&)q04Ujm)Za~RO7P+^6(yN=@0@4>RDjdR^l)LW=q zp|y#dywe!OM~2n54t1#$$LY`vPOF(3KT?FC8o#?qaKIYmUn1qge%QI5O()=vK49Xr z8SLZbTduZva6*$D?^~16lNq21N9f0klOUk#e|d9q*2GjgVwo4^y8VO)%2&);LTu{A z1i*q*{J(uS1k`f$b1j#Wr-hE(uw>rXl0P!8RnPVDosQif?FV67Fohq*mydcz#Z?cj zOv14M#E$iq*-&uX=dLsiu)aAbSa zy~wEV09Dqv2wC<{8&i&k+sycUIUsC6dLaICT)r?C_fZ+=H+k#851PtGgKU&~$=$-8 ziN*64Ym2;o>f`j?65IahCrdl2Z%%(6s#cMgx3AwpvxKMIxz`1R?n~?68t!GbRMw<* zEj@cggdMGl@R2)j6!A?$qBk^zRzG5K)vfh&-vNV#*8x@mb$dtZm`|tEop*uPK-*gm z^g0+Ph**6>tphv&F(={P;3Kp4bpZU=fVsp&_dnnk%`Dgl-2rwOl>UIX0tKILb9SIy zn3J;>*!N$*R)MJitykvL(-t2_(BOaoD3!_!Fmtx)Y;Lv(p3TN>6)#4g-0#p0!@LP{ zyWU4lctf&`oAv7KS5|s@P<&km{MWKM;VCty*8a!ja`kl#k`MRU^I!q; zvArF!=%g~yuZyp=MYay&qoaKg4~K|TK9bSzWS98d9QdU^^ron zV%&$;uVG+6F#?jWoEEDV>4vE7T}C!kG9nFSqv^f{GO)q}xLC<7Sk7vx`(h4Zs%7hQ z7mi@Ft~dWJZ=GBl8XFh=cN<$soXW4Rn`ZNqk>-VE6?Pd`Rx}D4##Dxtt*W59D+hsoIDSkqVEFA{JsbzB2Rj=G64>=)7(29ReN` z!(U+KVR^fOm(OI=+J|yIXI4;i6)mJ6gvngy%lNOx0gzBnJ?ROhG^>;sb!w zZ)5OfJQ#1=tEu&H!>LW%-xNIdVfXr92O=ny$;ShK`UUMn_??Z-L8zRs|Gc5}%1WnZ zC@Y=7Ymu`^v?IFbFuArb2s5v|A#^jYc(^cfjpog}YL;f#MuSMD<%k1i0?NMh_33e4 z+G!d!Iaed17+Oy=D2Z-}c(2K8w;u3}8VB8GcT2mzLXO-9wdrP#c?Q0JyWN$@Xm_$P zGPTcg^-J4C(kmSF!bHm2^p)5NHiqxp`lG0_I}7H4JN^lzlt(zdi!Q(T0Y+K`43{ol z8od(6hAnmc2`P$FkfFW^`h~iajRYr-8jq)oYj@orCJoszql!E{VhDq!=VfKxPel4F z=_#;a)#JTo(S&6gU;K=dluy}1VO8@(vvYDLS#ai-#tz>3-;b)T*G;k|(sM%arvipR7f7V|FKXU9Ak&l8Ao4&UdVa~?0YqX|KLP@l4+a9BxUzGwQ^GPh zS!0DUBZGUN4=(|FqR6PI4+27GAnvr}#ft}py}9yn%e2+?q+(=+y)SR3a$`Q)S_9?N zb*ifbQlx;4L58)lE_H`Hy?8V0tnH#4}z_ywZ(dO#*Pl`e7S1j zxbyJ6pvb3X>|g;P1Ci8tP6+dcPLgK=AQUNC1DckQz(BxnY#NqF2>l}^F+L0R-}S{u zzbhlOO$IK=q6cEP2%wkbTzZmO_KZG-7$6s@km50EfG#&3n?M%T71tqlD01Q)8yk&; zwS|QU@V*Ze35|M^i#FYs9s?*S_sN^ObFj%TdT8?zVZm31Ht|x79DEsIbj7cIw>@W) zkZ}O8l~kjT>NgyKd7Y{0Fg!bCUu+lz=2|u%J;5Cd$8cO+U=v(b4bdD1a}kBc6h8a_ zx;(%YY{>`+-y_}^axo9HEid~5a4Oo z?-Je9OV3i)WQ>f7u>}Rqhm0S?EdbPsTHeDjbD;r$-}rbw7Ls=$Bok5FS1hCSRZuG< z*L=0Ky3(uEJMN8u>R-KP;?|yw3Ps6y{=E8m^r{lgl-y6dwN|S*yT2N}o4?8^UjS z>pF5^_|FC>V%rz+uH#LS^xawmYqI4@`O|JRFsoGq?|4skQRo++{**60#`wNeF~ntg z0vovqcW)@^Faq);<21|Le0k8;Lq!t4^^^6ejHtBdGHSBNVrIr(dMlrkGjjz{B;{*g z-nOVgGY}hWaEmouG)&Q5@0?9Z8V#k%oSNwgM~yAqCG|)HnQwJ2?nQIs-A(`*m{cj| z@NJ4l>3UvBP-*CbPyYmESxj`Jt0Q(bOGgFqzQfs@{#C}Gxnf9E@)$CH8>87-L%-$> z=dw$Rdbef%6rK9x-oeCyd3syBa@R9T`F;L#g}2=2W18eiFt01VY_H6c%W&o8e%GIS z|FV=}k>hJ@-lR*MZqSs#WRh%D{FGD>%2F2UUS3fke85WY)Enai6A|4zz}m6 z$GI32I59Foe4oW{nuHnGQTq@f8kIBPls5j^8FOo2q=NBiP3L+sd^B21ODhiCJ)rFZ zwy=HA3EK9lTYt@Bc6^q%sB!Y)A#CRg2D;6W| z?ZP%nac;Z%A6SnZk-pi_^wd&9Sgd>VZv5Z@q>QWP-8E8e4-VfdFCs$GyIt>9 zUq-OABKVHRF2|03rt#%O@-P$iv@SpT#aqi9@)G8lx^+q~)bemeT0Zt-D|yFR)FIrJ zt#4PM?rylubreJ#duuCYp>i8cR7l>Yx9qa~nCnZ;*5;5mb=v8(mI`%|UqB087>)bD zCFyGC4t0G0;bW4-A^!nMoLJB%nC>SQLFrR0m1q{I;6<#f4#Xe;34t$=M4k=E^2;LA zal|VWd6i*gwOR5Nj;`fjJu~6L2H*F2xVGMUJ3Ys ztfKsntc;V%5~np%)w5-Bl4MRIs{-Mw@1lM@o}8+I0)T(Q#X3zkD<(0E8hr4cT@{a? zMHLVc9MBNF5P%mM6}tFt@!XUnPW_86v&&mowz_&26$W(0yMNngqPnk^0QAFMf?1y7x^bGD5 z>d~$UR(JUJAq*=%rY~lTMyO`xi{Uwp;Hv3(8yDA%k`l511i=b*;-|J3)Z7dYH$U{0 zGoPAY*n&}6NpIsGU2Std*YWzR z-)G!EJVg^*&GcqLs9rR>~^ByQyd1qI*QbE5HHH>7MR z#sOB2V4`{SJe=EiT5f*AbQ6q+RMOOStPu?e!|fH*lIM~b08+BCHi=mRwbECwrV3tE z5mMB9M3-&P8HNg4-dd7@X*`aH0@u;)7q4V-ln^in#H_^_x3R2XA*5`%j@5g}2AYN% z->;`ky4pD)L%9Vb2Rxd&uBRH}UzXT`HroNhMahy}bU|0XJ4-CG5G+u8aTr+6; z)kDyy>Q|>FxyxtM-X#DEfd_M@c4x4>@@y1-c5GYjb6^nZJ;TH77rN>2F?ZeD3YjIxahyLV_O_OkHl>z71rJCupiYz5Sa;kgiMZ zHRWLF6^wYbgCRjCOBb`a!ywEKr)Oq>X#puC0^m)}!NEaENhvH`1SB*(#D7wxLhaV; z4uos;!pce-%o}o}=X_xbIQa@$t-`y*AeZkFlF5v0J7s~cWH`% z7m+~zsWPbr`!{Y6)Ze*8jmgzr4pV%n)hSO zO_kZr$&RgaFyaa+a(vNa;$^$BY!J}K0`bPDW%kcO>||@Ht%VM=j;fQ;Wu&_;hqyQ# z4x&D&(P(jTgE+4{cQ7g{VHEH?fd~B-Qu)Mh^tQcP$Rd>^!8|(538HlgS=nl^^aTYZ z?dAuVqJuZ#lPCA$0Ny%w>QiUu3$Usb6chw%hN3!r4G=PveRM9SNxEi#AB`iUrast@ z@BnTc@Ew2@Vae|!BejkGf4EI{z~tvxeSQ0!l1`*X#co6LToD_(w2Y&Ooi_0e(i>MF zkSCwL1=tz**W~voNEsAbP4)TBG}X`NF%dIPA`S4bU*{B*S#aswJ-cli%Y-vyY3me+ z@~De@FC0mM`bP8rXq~ek(}ti&V!$39xUB)=i?_(}u@5+eUF58z(5fnjv9O;(8K>+E zG)U-*7mxVM@Atb5sVs;GIDM{Gg&au(QS2k?l9K53AuUZ!3nzIjJvpNO5jqH7G}r5F zp;+}?zGJmGMgwCPASsLS`dv@je!bI40~hTA8_&g1pdejxcJV5`tNDk5M2O|^S+;o_ z4b)4}4(IYz*Yn|0WW2;O8v*BnMQ1|smA$_HF^g2KO)bk0{5%>)U?FLVfLE|We$hLoelCH@t+aq&HRWr&E)L?KN_F?2Q`*k&!Kp_j%5m z@rx|A-{pYJEz~#`i=9HnC#~67-iNM=OAh+aa~SX-ZsxLEo@nPD22)mL9IXNV$LBPA z@Bf+lYng|-0P}!fF)ka3mjSxal>Ea}x|swXXwZLih*)U>X_4@Xnb3?RE$DJr;a7n@ zH$+;S4yzsu2Ty3WaiBN4xw>xq%~X*a>AUXi&V}9OEDWF^I{C_8NW)GeB{}f&^}^(+ zgsZdm8nJOt1+B(d9>2aG7I19hRrXzfbkk^<|I3z$PSL*A{F3KCHvJl`e|*{=_IhoC zT6St(T9=?c8sZ}N^I@xpPt2yT=j?h+e0)wn(PagM+}G z_qrgYs-~&gS^X7|8F_gEWhMwXLL#{#NTsB>xOieYdS-QQxCY(|(6!hPtVWZ|T`Ds1 z@f&7WQdI0ZAsB{404XAgx_M&)31rk649x2(3JEyexeu=mE%<9uzr+%lMLyJ&pr@;k z_mjBi2w}nVKLyHN8yhf>wt#=;HY>AIzTmaqzu${*LsqtqHcG7i96_zj2n0*De;iN| zREJcwi53)+(zO>H*Ab4fw6Z!1hPC2mUa!2@&v5+-mn0xiNkn(TyYCqo6vVKq(+Mei zALviPRR3~xXsFAa5o^D2Z;R9EFnS?s`i5tb53G``a!R%`>T?&&BU&^ z_)%h_fts2cysJQWIF`l?2KTTpBD0d&-wNF_1iJ-jVc{V*odzoqlQ-$9>6#=(z<~nL z7($kS7qubXsvk z#B24&X0%Qc2I3_QFV!{FwE*o-GrJrDIqtyK8t%+?bXM3I9(=@uy@X3XmqTKYCB*3= zYKFI#^vtZ9-f3Q;bLUka-d?0=-kZYi^f-#{!Xd_BnpUG@YWFgp4E0Smj zC<)X;k6(tjKt0q@_Xy!%ZgCvTK>s2tg2zv@0@qEm<#y()Kf$RSsM#znX3j%tJua zyLJ>ywokR(4u$A5%ZF6Sdyh7^Slu5IBxhe>LWN;y(*a5#upUBa+Y36he5;5P`Tcwl zS46@}bu!srhGr5RoeO}^aO#xK^aObS!wY;1=pUQ(=07e_7s@Nd*#NNv=4Qs^6!PswdO|#?ZY;?wdGpg@ zm{6XN!X04Sk?U9%y;NUc|FpHe{=saJif0oYzuFGmKi{NR&yZM}Z({9dW zaRwgLxCD5Cn{%48KNjfbovLVwUJ``ZAs*GvSsHTuO+c`~!y=`d$M7ak$cf*kR-cj{ zIg~McnR)l}s!U>dcryTsg4dtglkdf`P=w;+cnMF&7)EeoHDZ8;)xv8Bl+EW5<@j~E z22kJ+pZpdV7s0~jl=CR2`wkdz+f}Xwdsl+f)GtzwxZg`l4;;N#rd$D1HCO8b9TG;b z3)t#V&jRM>I;GY?@c^BFbF3Knh_{kwXJ>&dtj9|E>t$r~X{kgK{W3fKc4>;sQ&;xW z!h|f4SDeC%-OQZ)1AC}YFos?Fj*jnr7_?vVVWpwD<|$wY9DJ*p^V_O3$L93m41IiY z=!9{FUUhf6NJ3Uq+xeI!Fac}hU zFP&JqTn)B%1{+7%*-yms{LBOC0%WOtiqbJ;?F{9^e1zBVjo2X=q_ zC@3QG;5jWp#BuCK1lj)CD5M-pYe2&oYx=~T1*+zDtDit#20=ocBM=DZW@ig`qzl)y zVPcB8aXkxab2m!O>sg>#ntGH4VfFwf%8LOPE<93A^K>LgAPiIMVf<~Cf`RP|X%+G} zRKLo095tbBy-ytG{#1~!kkQ+-7}(~EvHAJGVA}!P59R_lko8Z}h+~@%ICvB#Oxy6H zf9BoEhH0Z%U3db(COcpC_o2(Ai4O!dM9SwuvnI&&01|hpWB2)Nh(U{sqd$G*#RqsD zyC16Z96P3Y*gR{%oaa)sRXn&lbuWSiSO2w^D6_K2Lj`V?#WVe{xp{c*-Mu?KEk-aA z1J|(T>8Jby5VO0VDJ+zN>5HBeSh(}xQU(Kw|MO<>{u+1BijLN1_Pjy`tEcgUCCO0n zEfNy<_7xBIw>;j&Yo-j+tQQaaB+fg@-KUN7#Q_j_ycP~7s2$wBo9>75E$_NO?wIQ# zE$2eB9s9=;)`RzRy*RNt+^1SZ;X4X(p`i_O`*%w0o1hYZN zFwQHe-MeumMRUPpj`ZL`=+ExJDT%yoezgRlLRaM=!Sj9*L`3fGt1xHkrsXdW()}ut zuwUe|-21;l@vh-eJFhYzlP&ZXF9c_Xo)N_UYdQBm?Ox@j7RRGbkAyYH#lmez8}7^} zBqHJh#fMhWrCf;8@ z{aDAPOJGsw4cS5kxvdt(pCx}4yl{9q>mjgL)DaOl8HP4}`UE-zb&y_eZzDefKeXxN z?fr_5ltAYt72)1CfB?bSm4g>XNB_U>-a9I)tcxB51Bjw%2?j)vP*7wgBLXTp2o^aA z7zmO?5kZLxDinwc6hWdEIY!i8%r3GK*1Yh%~$$@Z}XmgS|6okR*oRA{n!r zF^3z`q!4)s%ORRwMO8Jvzp{7_JdSzZyK$}rLXLYXeEHYpMsX5bi}KerjrD2S9pq`Z zZd@R|j{A{g50%)zuFh`U=1N3T$4V8N;o$f>Ffhm-%|v$l(MMNF;@za%OVB9sF%0kB&cn z?n1Kev5mmo-=96;Fparj3^~6D-K+s`nJ_$auZpjf=RJ9|k<|w)Hb%(qAdY91dla_s zSvvw`s-3@nf$$Li{M6>t?|J!R543O4vcR79db9L-iMe_cZq;UHGn<0-dBQO}CQmaQ z!!ud9#V;|=5Ft$X&@?}I_2sT(*L%t#EBwQ!jks4IWT&c*+K5qy1-Q|K?AQ!rMy>%o zXgiSa`RBjky1X0WXKU-fObGj3D=OyzsM;Qc;}6#qWzChL6d!+Ls229gYjYlsuFrt0v}! zMs8(cUC)HI!{{@im%NDDg# z5zzrIc#bY-pC`zx6XZWeBJq2hsmMF!ntL2Jljw+3M|ks%(hLZmtGQyZ z+W0CTvDP2AW2z?q#?#74z7ZsSM2?{EcqcXK*Sv#sQ%vFHL;F@Sag;wg^aho z#@qE7^T{YV#z9K2z*+%I)pV20D|t4iK*aNE80@8pU?|qn(|2()hW+hUU!k`o7KtFQ zgsMYLfihik@2;VTD73=On-PG_t=fxBH8m(fZ}uKCqTplaFBBx|JIz$d9FN;}GypCK7cM{O@!%f<*Mtk~&=<<*Bwo>%64IEaLVrTku1n+o?gsoOT zmBi&mg?k=$3l^GwkVZL8b0;KYc>YrOxrG@>&R4*W`DFskzn{r#I7Lo z*Rt_b?_?yVYP_9ZL|kXClJU`X8S!65Ue;%Yp9J-WzyD0oO>a!QVJ_@y0j*anBtr_Wu@oKQ7Mgk4)8aaI)(5|mnHOOhga6Ns>XI zM6w=D)lZI?)tu=&VocR%&si!TAd!1W-)hML8M>QGGax|{62rxn%CGPG0`hbZ*|UA z9|R*HJ|>tYg(>}%EA$tu%&QD4DvEIIN-;=ralCf~Ha^VkX+Ua-@X(7vvnAEjtG(WP zJtIIv>ie%JZjD+rik1dhXG@%M%U#}?&<+d?ln+se@;-Z8|UO(`V!;^R~u{=nS36}tYIiPj?>~Xc4SxF$(`!=;B(47_C1#CJBSOh4BBu^tRpqnw(THK`XM6mcaH(=` z(%uEpiGf_u+);=&7s?%`>sV|m;_`axv?k@r2M@!IUyIiQoM^>z{_8B7u1{}6< zx%{f@02u62_%FKn`yy=JWo6oLz1lsZWp4=MM|zl= z=ATTkoAKSeEPMWZh-s7b6L)14X+~$M^==_}@LCe$W$Qs$l-i>{9RY^IIP)rLJ3GM% z=~wUkXfB+5tCxSIW0<0{+^VQ%es(q>Ks`Z7biTb*aLu_hy&*n!z|oN!tTM0;%lqK| zA&KrEUIRe2G`TYClJ8@zTod7vn{er7RV;1b5Z=fiSvvWBL*wxuVC`q6TFe15oeC!CaTX>S!cuKA=eTvzANLA+9o-ke$ z3wbjOxs$eY!ELAm7LtTGj;cq1vA_vVwpBjx;j9;T1JHqVdr-v^bO?JGk%GVzUQA~q zMP2pq!6cx!086cxalTJtC#s51Z4`Tu`HYkgzu^g_M1*r|=V?fhU79Vm;D!)1k7rld z45r!}Q@uPZ>(MY!w|(_|wBOx+gVd^o)RS1&M_YBmMlA&k02b^fxY+UZZ+{=70=^eY z4@|xXYul@{zBJEX5=kU=Y1y!2Q3r+&NJvDTzkDFz%>lH$6?9{iMCXq`d@&23%m*zW zacFyuZ8l=3V8v}VSjcBbYCU`}+Vk&!Cln#KS@se=6oLQeLl|aqqaNN|u24>HetY=j z$ScU_N4`rmxpJ4E+Xc9c_fG6PtUv@GZI{$j=>X^-z9_-Z*}+1B_v_y16_MlpKP#f` z10Sis>|J-s4+?^T4UGgf zRvsReu6Mv1!ni9~3U`;5A}V0B8vsO(HODjR0;6TFv1$cPEG$hJEiI~;Qf}LOnSEyR z_Kz>c11BZtTezCa%L%j}NkHcY5vj`Z^65RbW~ox5npp7vy{M)}*+Q{dUK62=!eB5P z%+wR*{Fq}<5CeI1u22XPF#%_d_ZG36tOX5SLj%R0J;y*{+`0(v_1CWe%dntNxT2>A zokHdci)Qi_R(2FWIDs^gzg5vnjpoF{MEb(~yppW!YoZ+ps*F6kdy$aGV9BAuL12Up z-rc^?3T||gYPDj`3(cy^Fy>?M)=PCa2?-DkO>J#$DxicTfZZ$$H)7V)GdD9mjcr+9 znJVJuv7H-LuQ4uxf*LI30g3)LGV%(9bzxx>Lqq<6ZE;J<$Si#SETQp~{5ZqZ9>Q^D zv8AZ{PnuU59;Z7&=>agXH5s^pTwaK2PCRtz(152k0sIWK&sM?Li}o%mT8A>GPO@y~ zVSs3Jr$M2kb{@+Nt0m&x0||2Z`S~e2S=Hmu_|2Myz-PewP}-rSvw`F}9Yb34O=h>) zyrIohXlNQQ|7ToN$}+eA&Y#)Shag z<2-4*;3@qO7Pl_f41gWx>Ff7QDsSZQY7+nnivt-28J z+-&>o`Ey%qYwFAAp_T%v^xgMY3q9e9sn$nqhLSqq&H%7|^X%s*>c=m;#){R)3O6`R zy=QS|IKX&fNLN@%TKcK|Jp{JKQdgq2&f@Y$qCQ$c*Og6ivqPdq|Dyz6nnqFEJ0c?D zSY(08t7uDmGLW3k0TyO_{SI)RSU_5th`Wk)-qR$mX3}GWgS01N20bTdotodEqyUqA9t(;J zMu#?U63_yGdtNe)5%4ssGLnC2Oy}+O;zb+ZJ;W2PE!qFEl(nm?D@42wrDnTj*$Zo| znDPtO$Ru#A9H*k9I(YCr@viOtxC4#72!WB(_=l~Z4C1dbS}T{ zfSnOP&i>0I(&ls4!N;J%ki#qLd>bBydStbiRhxYyx0J zofLghY%%z#`LQU=-#Ft3a8^(__Q24$Z^i<#j@PtEw%468$|x%Wkh}=+=G}ep_ZGMN zPAot!>X70M{{o|!%O@7bJ0fF*7JmLz%gB_Y(y!lTq!Hucpryo-cD-z`k2kOcm5E@} z2um(tr{}#&1u(#XN+mmZ_CwOEJWB@oQ+n2Rc3@rc&f+*YIRZNotqJr?8Mrv{d%- zW2FLt3&8l%5pGqI12h=I^#&qs65aM8t%+EpTgFYrUYB0YsXErSwP`w&U>}-Ji z+nY^H7qQn0ce(N?JyqmDiil$iN|fE)jZIB}P2OuiGoftt=c#~`eiLr^?}HX+?T8!r zQ;2?nUe@8$(92&t6;m{`{f^*vrilyzIed|zx_r~q`2dojN@;?ff|FcEJ`E9KG zH(>D+BNMpw;mCK;4NE|QfqdBQ!*A;vY*k@MT@j>J^5zujCcMpi-}Oq)X})c){v)az zesH5uxy|A!g5Y3(Dl-I=MT(qFXmGQ3Qe!RspIFfU;S2b>84Y~x5?EirnG{zOdWIp zu?1Z8^pEZU{JmMHtX04f2^f4XSdC>&D2vX41IB8d0KgvaAkPS{CIG z#>!=xK)FV&{bb1qgkiF=(a}68I-0zZ8e%8Z5I|EMjiPC&sR2SYfwJ4{D0h8zwXcpi zlnaUDkb(ii??M=P%Yjx;pinhA%tBFC_8r*F0U2hb0Ahns1}-k8JS#CTLWq^7`J(=B@|7z&g- zz(txVdawi}K+)?jpeqcqDr7YQ<~yTa>;1vRH}O5IHMz9lj)qFLr)m^BeflL&oa||X z9or-+5fQl^i~Q&}p!I=a%7VQgc)QkY1*ysY{x>}lpS1u923=q@Ut4woSkYYH1EPR* z=Pw_KAMi6WO89>peeTKkQX;;(7qadvDrB4;5}hCw2O^`kS4mNt3Gq|i{whyfCHlb`2%?P}74ahwL;>p{!lu0Z{LM;q3UJ5v*EQm`CZ4tI zOQXj^6|X6iVNV5xn4tf8BBIR}=V<`O`_rdSKr|=J!3hBp8?XCX0>Hh8wO7It&EjOx zY1DcPmoW+~0Kg+D#xwm|DT#W=J^};O5x4K%Q>UZQ&AjOYMp1nCiylH|w}>6z+#|47 zH21vTs#rRY`$!{602`>c$Rg|Nkn>(#Tm*q#93&qIdhHt;8p4(D+PzzDJVr*~#2y70 zXYI+cGEl(rj3J+zI(UdtJwWr&X7zCVclEIPD7fL2px{C=DIG|q3V1xh2M$sYX08*% zf<9vz0g=b>bO3`Zmw{M`0ZO5V5{Ht<+}U{z>e`m!!X%A(Ff#=S2%ajwUc~16DR$tK zz(}kSZ1keu-+vMcPux%eLDaetR3`7hBe9y4BgB-_mhj`p?Il}~b-=6*eogoNks5{U z3_ogXFxn7oa?qY9fBXYtuwe>Q*_^Rwc7FayX>O#XHnNgl$>CcP;R#xPOm-OKwsEW? z^tw1$cs<3a!gCH8&R{agrW;klWpWV^p*mabLdRUn@8AY_cdHQ4PQCg_ZP*$U{{^yJ z-uQnr6LW(D-`?I{pL_Ajt8s>*{1-18pki zjQHBLkJtOR)Kl8h2fTSTd25dCV+Ev2L75}5d1ur;e`JaZA7dhZs+E&QDMtVSg;J=H z4>;XKE$r+-nDFczEkgLutk5W>(Z$S6zB!^7`#J2?W+l4QUbP%HwY&OJu9kU!jy>o6 zmDk=G&=U!Rh9x7CaNr|6_aIPm1iCn%CZ^;fufv|MpKLJ@zW$B(F+;H<*@j*QXs{hb zr@O;2r7E2+`c=MQLz_WmX=K05g4^#C?fD|6Rrs0q{DZdS`JbM=PoQafi6Ljd2SJTou_TTu5 zKUx^@muHe#PV8f1An6e9l5*q4qaJ^MaaxID6Lf{2RO@(&`BORm3)#RjqqnFcw-0^4 zL6X}CLH8$QSo!k9hYuk7NiitW?<#~)6XrFEX5JK{VhcLu4()Paxt4@Z z;nKGdH&Tk$`MRnqp9!$tBHylE&TC(X>iEr@Hz4i&4ti;|dXPLl>g&1;vYk0*Xi#p0b^sKVS!~z_v6ZBjNKr_xD=aLGd5U00XrjMiMls`kMFwoc zuxaWR4o*$=ftekt-xdvB(D0joqa5Di->yTS2VV$!Sww~jJZPLXc}^@jeO`V5djJ4 zU7$+SZ|5>v{_6NoS;5BNT-;*}GRF#VeomMJ^K^)eKS6?Ux(mdATPZCH@K%LzNx#*F zu&c!#q^3^D&H))*T^%QgY_lK2mDcu;19cwrS|I3c{pq(@=}oM;+Yan~*>-0nCME)+ za;&){!=z;%K=(l2{x|Nl>1@~-%a8etTWm_YVv)8~h>< z;>eG+81<@Fz))Nbozt2Rs>+`A|Hdx795RmdzC<<@DXLCLI_%T zwTB5*2SO9l{cj@cn_>>eY;MRvu zo(7b#=JtY);gH7%|LZ-^6V@ugLAJSvWun!u z-UY#Gzx?U1u5AO|pRj28)i4YwNSbt&&#vbpGSzA##XF!#IKYa9+Zu25Q)Vcx_e|j@K1n&eytoiFkHOy^e-KVfm1LAhP$TKVYA0#z-I6X)?aBRLZ zXUcLB68la)aH__q1JgE1Z1V7a(U)-{eTMo4HhZ+wRSA4A^1hxsEK9kqy&y)A?cMf1 zacHahSN!JBI1Z&;TA6)wsc1FaMbP)ht)C3>y)Nqu{MrU<8tuR&qNC|vX-_v+C5=BO zOlmRoVB*cw&hDD8<$d(8<@Wk0&aC_0HDKb3i!bn-sRfoe06mFDW5Jp_6bKGEIq(Rj zw;t>-jVQcP(_~^>LvYe9xP`C0FpkGKe0%lp4*8Rh;h2Q(J zvA{gZh_9WuTpynu?0uh)>&?9Rd9cI8jUVSbpTZq_&7p5Bf+@i%M9_+(2TT?-*sl82 z46DZv{9KDMvi_l-$e20dvNRTd!R;a_tI#Rcg}}$Z5_Nc%l%K2aXO-jpBfwM;ya&&? ztVvq-y^)Ae>#I%#Vy{{sx-D^Qn?#GWI|sE37ZnnAsb|FGa{#@!I@YJuQCLpsj`g(p zg|Hn+kk~ae!H5Wq1<&)Qu(GYk?^=z4_ca)E@p>rcL8G7FuDy!r>a1s1Vy5#jdOb zQ3jp#@DRHsAS2{hZWuaE`*x(=G3U|~`vsh)sDoHkb8@O%C2Ld!!OLM@+DpG$zT)}Y z7B@qUltWwF^9N#db!p`DAYZkfft>^7v5f4>dy?2N;aIW*8 zlkzeV7SZ&lI>c%EqxUH~fNq%A4^!hbwAd(Qzsk@>w_8!MlfG*x5k;>Z=vSRLI-I0^ z!@>onJXQ{*CQit*Z~A#sjsAdDjKgXX9d~_*U~%2s;0d>=uwFEae{#YEj7HWh}1XtG`Uv1yk)p}~`+I~#J?=8SGT74$Z`dI$Ie)o$b5gzzR}2kKT(=9^lV>W zQ2)TduL--3^dZRs+XEcOW3*l!L@b?5 z&M~oTZExAlm=``rk|uD1&V;>hvf~7&Et4h|fZQpUcUQljLdn7&);QBRRO(wRL6K$E z_)$jG1Qf8lXT^RqgsP!CHyOfcdhF=*o7b<;$Cs9wnYG&V}?R_ZFm0xOs>G@u3!$xyhKf7fSzAT!j>S)o+-p%V&BPhSzNw>%s%X*R9nug-P3=il1m-R0oxjSD^uu;oA8h)`yX1Vv%Zoe6T>it@Gl;oK>`56jTgV{ z_)X6L=Zn1~kNyzzCs0(X$-MWNgpbj0blu-I2uw8p-Ru!PQvovkb15z6s`A+DnJ>pn|hVljxY&6fGhwUs4%#Lu%{Nf%Bf2^mJ#fXj5k2N z4owxbjtkK{qwln%Xjl_*h*K~(_f#*rfw8f%wRQUZ1hkDXP&WB4(1>^B$LB~HOS=`W zyTF3U{O0;!Q~IQ50ksZ&Dt_+>ZRlj*`dZE}UtyQE0-fC3{jMX42u%g^p%&xpcrsj` z#zP&S8pzHMjf)T^}HffaC;N?6wd%GH+n< zf>u=e*|9fHkm}3|To}MyRJM8=6`k|49m3rK9<{qjNb+)X0d35E_pY*NVBlnhGZ>e{ zpl~=I|FgnHs^X&!w8cON!jx3@T1BT$2Fx1*o(yWZZ_ro@ln-#Zlz@f#K`JUKCo<^b zK;M4ebo!G7#ru`X{DpCwV96?b4GrY~7!QmC4qbs>mzk-$rG+1m*%jq!0GlXp$VAGi zfux}C{#S35c*+q|EVoAQUi2W$2+vJG>_a!CeRQ=M3Abj;RM+CrI@VY0 z`ldvf=<*D(1(D!w0}Yh(cv{7vZv1^v|f5oR~K7b{3`z# zCM@(_R_{R<9~5+K;wHSl_C4}Nvpwk1`Cj@%CRRCsw9Obcw(4;uJk20{?eytV3UR!I zoE}C!m>Fv<@*M1mYyo+q0p_|TS!Z5;`4h}|L%U@5zA<&&zoQWF*Fc6Oz$PKDRnQMZ z_U3{ciAq0AmnIqvG``zJ{~O=KJHQy1tR|2dD}#Q@@=rJ`e9Y1TmxU=6l?elYJz(kT z(pKBZENLvm0HSD>3(Sa{$t+QE#=g{-+Y^9}Fy66S5madTsf4EEBFd{B>KXd+jT)Y15Ck*=f)c^}+llWR=l%Jb^|+UIbF%m!R7A^X z$|rmPV*&*_2!FYI_wLa3GGfC>wP+Q}>Hx&$;i3nF8Pz<0FwTAj*_Y)`eQY0<7m>!o0jsJ$eGLe0nQ)Yn7ICm??zGEw1s!giA1O z2pQ{QH$S}wXH9@{Sy)-+3Ur(=U!pJ?BCY5N=5y2&7BMH+ z!Mtup!o2i36tKBkxr!6$rHU+vgly}3%CezQa>EVv3^ee#o+>fD5AN_o^hC)O;J0~_V z!2!a*eDC?FP*6~GRq(BT54I*+>i0PreM6-iIH(xh)O^m%Ce03aL0$pAFXK5G_$Qg4^-ICkqqTinoV zdU1CKtZz}gWK}>3Q}xWoT`@3M4LZ5H)Zj8{;%ZuF(m4*h9^Y!Ne*~Q>E}d8K_<<@o zY(*Q{mq?Sx70P>HmrOW1ag)I!V1RU6PItKkl?BHXDee99mbHM=c22{Mi9ux<)f`d9 zsWkAv`V7<=;A9~Fk;TT5SG2UuLB810w`_`psOZ4Jz)n4A!%kj8SDR^aI?PSv^i`*5 zvPPAZmR=Gujnqtdq~@n039%nE9A9P|#M_wU_g;zDK-l7YZ`elQm|}?@213hH0l$2# z5uPdZ5BOc8PRID=7!jaKW%VJbqjY6Aj55~f1Nl0-7=SWD9;IMg<$3IOCm=wh`L4D+e*TAV%h!NQ5XdL`pi%+^}w_Sm>YIDO|S=a2L&oXoq-AgalX$7((;TdP2O)HQV2{EnE zT(`U?K^S~U7kn!4YSybOS-;pd#HoXUX=}FIRRS^guC6B!9hwNf{)&> z0j>+vC-20JZU((piz*F_vSi{hSW4|fPN-qB{rlCS`HZwk(o6}beE#HKOOj?EoT4zR z&CGuNGE6h^Pegg^$CIeEt0!O4PLS*1s%y@|;2`lu9}e*7M>LW>1t>4Su`m$&%06j+ zl2CcLLeqF28mb=3`cOB*eYCUyo=I3o% zvfH(2RkH$Rhq{1=i+iC7#eiJ(mE-o>5khwe%jD|V1|tbV5^bL|F8%Bg9a4^z&qNgSaKATX!y0G!u}fM- zwflBTIkCGAj*YQb069>kc2W7<^yBQ5kqc3nKv!K`$Nncr@siq;m=n?Sz5;M{H+Q2$ zayagRHrS6q#}#DTD4mii0DHF|wbJM~$c@Ikb5;E?@w31TL=jE&k4 zQl>M!gdwLuPB^4}tw0WCc6K6*vO0YlQV5&mrE4TiMG_h=%W*Uk=N?3ps4#lE$+5EY z93E0t4OLhR$QbT;6(ZzMWBB1Au^IQYBJQFy6)@2-w*w;-noC}BL!awOMpapi zA?xnjR{$p<2p~+erx8uSJl##-lPykBP=c-gD5ZG9zXHSmE=xm4PlzOF8A_e2lh&+T z1Q6G=huswBtoF|h`ZHq_GS$~lIuBJ-@izn|jDqO&#&U?BzOQ`!yp>C$J5LXm8jL~X zWsE36e8?AuJ^w~@#Jsh)KDjr|uk%cn17qWU%So#f?y$34+!l1t`>Lh&?MgE?L(&^R zBGGO~GfB|@ip*Q5={wD-WAPxf1X5jj<#yOmg!jghWrg@e8t`Qd4%T6icmVZ&$y$5z zkn%h2Td4SD$z=P2IyJkjIS^X~T{?a9Jg9|;c?_?U0ZaPfQ0h7aK(j5(OvzvH$pj;! zgkvt&39?bKu`JBYqy6@!B_%qUH?KurFqI+RAXYbUHqZ0WBaIZ?CRzx8wxg058Or*b zL}^s4{o)Johqe1ZihB>-CnoQ@+JLm@f(wLq&1h_QPDXO z>`c{MFbEjWShY17DV2kwI&wrhw-iR&4&vRA*~rGO1}YRnDFD5?F~Edy3Q|uIHf-a? z-3;4A!+*Y5(6ogT!B46~iNeqC{~sE7ux7=JY>*bhT2Jj5u~5uji~a!Q{*>_oFs2Z} z!w4{5xhrcuG0|&9Sv5n$_M-KvyxxG_hcZaOpwyLi)6@fCkLMiN#zdFi0uEYmG0^^_ zZ=2-6&dha9-BlQM{;hl$DwM1uOv?1Um!Zen7XO9qphw+XK&h+1yZ;^Zg7HfD=l=HB z|K~L!@ddKWQ?y~%U#?fVZ(M$;$&UZVNlH}$<7$%@!KlH|h=o%9Q9uz@wuzMuPNBKS zF_{7eEdNF(*5rYO2n|Ea+K+zazRwSoB04y|<}Crb8m>L=Ac&%(6_Yw^d{6t}8FmZ? z!_7?rYx*`H5N*I)WlB2DHGut%ztJ7rN1NB7TXcZ-UD&cp^_ za#&cRr@X1|z+nN|jv~{$gDE+)FhManqHR~xI^?oGQ(L$?R+iKpmI$m=mfSBz^r%5j zG6?PTZ0SVpUyrz{udO+|AFwK%yQ`#OTLSZnFwK8?@cia5{^s9wP1_&yIZAxh^x;TA zpL4^)eDYCBO3c`Ur3#UIX1d7_m*+$!qYZBWg+muX0-iRGR;8$=>`NiWU?Tm=HsW-@ zu&E=n(~ImOxIKe6)6;-T;Wy8NwE=UM7kzea4PtL1)JE!raqYt8;oKA}>(oBks&8}L2cLHL=6WxunTq6 zJ&`R%g1baF_l$1clc-J;l4NyMp1vO^)QIA&#dR=Gy;7<8B~%|D3G7 z29vdj{$fkk^DnKB8t!kq{hN&maF~?3gB%+)6fr_F$c=u4hVQ=M2@q+u?h8ls-mVQU zAGsj*yO3`QzfM1toZb?N1!?VZe?yE6=`$T>N-(^-H2{7l?cf24orp|XmRXjvR2oju z-Kc&2r};JxP(vWi@4kzd-?;b8M@p{Ugo$rY@~Z9kM>Z(r7qZNdU;q03Lx+-e(sd43 V%Y_8*Ipojfq?9C+FJ5*1zX0rvt>yp# literal 0 HcmV?d00001 diff --git a/contracts/docs/plantuml/oethProcesses.png b/contracts/docs/plantuml/oethProcesses.png index fcc51c0e34967ac65db31f1d102c0b6f370f4564..35e31411c8a9e8a01074c7c2b99f7636e6a14baa 100644 GIT binary patch literal 448529 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 &XY>WRi3H@L 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�~?Xd--50R~81Y)VQ>+VEF2 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

US2 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 z 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 }e-8c62CE`L-&8o~n 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

  • sCoQmltJ7#vtCc^T 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 -actor "Governor" as gov <> +actor "Registrator\n(Relayer)" as reg <> +actor "Admin\n(5/8 Safe)" as admin <> +actor "Governor\n(Timelock)" as gov <> actor "Treasury" as treasury <> participant "API" as api <> actor "Operators" as ssvOp <> @@ -47,6 +48,24 @@ return end group +group Governor sets staked ETH threshold + +gov -> nativeStrat : setStakeETHThreshold() +activate nativeStrat +note right: set ETH that can be staked before the staking monitor has to reset +return + +end group + +group Staking monitor resets staked ETH + +admin -> nativeStrat : resetStakeETHTally() +activate nativeStrat +note right: resets the ETH that can be staked going forward +return + +end group + group Registrator creates a new SSV validator reg -> api: POST\neth/staking/ssv/request/create\nuuid,\nvalidatorsCount,\ntype,\nwithdrawalAddress,\nfeeRecipientAddress,\nssvOwnerAddress,\noperationPeriodInDays @@ -89,6 +108,8 @@ return reg -> nativeStrat : stakeEth([\npubkey,\nsignature,\ndepositDataRoot]) activate nativeStrat +nativeStrat -> nativeStrat +note right : validate staked ETH under the threshold nativeStrat -> weth : withdraw(32 ETH * number of validators) activate weth note right : WETH burned for ETH @@ -115,7 +136,7 @@ dep -> val : 32 ETH note over val : Pending Activation -... four validators are activated each epoch from the Validator Queue (~1.5 days) ... +... four validators are activated each epoch from the Validator Queue (1-10 days) ... note over val : Active From 003fcdbc28b6ac25d63c0ad426b1e7a5536b27f7 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Wed, 29 May 2024 10:57:41 +1000 Subject: [PATCH 112/273] Updated OETH Vault diagrams --- contracts/docs/OETHVaultAdminSquashed.svg | 199 ++++----- contracts/docs/OETHVaultCoreSquashed.svg | 278 ++++++------ contracts/docs/OETHVaultHierarchy.svg | 402 +++++++++--------- contracts/docs/OETHVaultStorage.svg | 492 ++++++++++++---------- 4 files changed, 719 insertions(+), 652 deletions(-) diff --git a/contracts/docs/OETHVaultAdminSquashed.svg b/contracts/docs/OETHVaultAdminSquashed.svg index 3a14885577..f95c5d2dc2 100644 --- a/contracts/docs/OETHVaultAdminSquashed.svg +++ b/contracts/docs/OETHVaultAdminSquashed.svg @@ -4,106 +4,109 @@ - - + + UmlClassDiagram - - + + -200 - -OETHVaultAdmin -../contracts/vault/OETHVaultAdmin.sol - -Private: -   initialized: bool <<Initializable>> -   initializing: bool <<Initializable>> -   ______gap: uint256[50] <<Initializable>> -   governorPosition: bytes32 <<Governable>> -   pendingGovernorPosition: bytes32 <<Governable>> -   reentryStatusPosition: bytes32 <<Governable>> -   _deprecated_rebaseHooksAddr: address <<VaultStorage>> -   _deprecated_uniswapAddr: address <<VaultStorage>> -   _deprecated_swapTokens: address[] <<VaultStorage>> -Internal: -   assets: mapping(address=>Asset) <<VaultStorage>> -   allAssets: address[] <<VaultStorage>> -   strategies: mapping(address=>Strategy) <<VaultStorage>> -   allStrategies: address[] <<VaultStorage>> -   oUSD: OUSD <<VaultStorage>> -   swapConfig: SwapConfig <<VaultStorage>> -Public: -   _NOT_ENTERED: uint256 <<Governable>> -   _ENTERED: uint256 <<Governable>> -   priceProvider: address <<VaultStorage>> -   rebasePaused: bool <<VaultStorage>> -   capitalPaused: bool <<VaultStorage>> -   redeemFeeBps: uint256 <<VaultStorage>> -   vaultBuffer: uint256 <<VaultStorage>> -   autoAllocateThreshold: uint256 <<VaultStorage>> -   rebaseThreshold: uint256 <<VaultStorage>> -   adminImplPosition: bytes32 <<VaultStorage>> -   strategistAddr: address <<VaultStorage>> -   assetDefaultStrategies: mapping(address=>address) <<VaultStorage>> -   maxSupplyDiff: uint256 <<VaultStorage>> -   trusteeAddress: address <<VaultStorage>> -   trusteeFeeBps: uint256 <<VaultStorage>> -   MINT_MINIMUM_UNIT_PRICE: uint256 <<VaultStorage>> -   ousdMetaStrategy: address <<VaultStorage>> -   netOusdMintedForStrategy: int256 <<VaultStorage>> -   netOusdMintForStrategyThreshold: uint256 <<VaultStorage>> -   MIN_UNIT_PRICE_DRIFT: uint256 <<VaultStorage>> -   MAX_UNIT_PRICE_DRIFT: uint256 <<VaultStorage>> - -Internal: -    _governor(): (governorOut: address) <<Governable>> -    _pendingGovernor(): (pendingGovernor: address) <<Governable>> -    _setGovernor(newGovernor: address) <<Governable>> -    _setPendingGovernor(newGovernor: address) <<Governable>> -    _changeGovernor(_newGovernor: address) <<Governable>> -    _depositToStrategy(_strategyToAddress: address, _assets: address[], _amounts: uint256[]) <<VaultAdmin>> -    _withdrawFromStrategy(_recipient: address, _strategyFromAddress: address, _assets: address[], _amounts: uint256[]) <<VaultAdmin>> -    _cacheDecimals(token: address) <<VaultAdmin>> -External: -    transferGovernance(_newGovernor: address) <<onlyGovernor>> <<Governable>> -    claimGovernance() <<Governable>> -    setAdminImpl(newImpl: address) <<onlyGovernor>> <<VaultStorage>> -    setPriceProvider(_priceProvider: address) <<onlyGovernor>> <<VaultAdmin>> -    setRedeemFeeBps(_redeemFeeBps: uint256) <<onlyGovernor>> <<VaultAdmin>> -    setVaultBuffer(_vaultBuffer: uint256) <<onlyGovernorOrStrategist>> <<VaultAdmin>> -    setAutoAllocateThreshold(_threshold: uint256) <<onlyGovernor>> <<VaultAdmin>> -    setRebaseThreshold(_threshold: uint256) <<onlyGovernor>> <<VaultAdmin>> -    setStrategistAddr(_address: address) <<onlyGovernor>> <<VaultAdmin>> -    setAssetDefaultStrategy(_asset: address, _strategy: address) <<onlyGovernorOrStrategist>> <<VaultAdmin>> -    setNetOusdMintForStrategyThreshold(_threshold: uint256) <<onlyGovernor>> <<VaultAdmin>> -    swapCollateral(_fromAsset: address, _toAsset: address, _fromAssetAmount: uint256, _minToAssetAmount: uint256, _data: bytes): (toAssetAmount: uint256) <<nonReentrant, onlyGovernorOrStrategist>> <<VaultAdmin>> -    setSwapper(_swapperAddr: address) <<onlyGovernor>> <<VaultAdmin>> -    swapper(): (swapper_: address) <<VaultAdmin>> -    setSwapAllowedUndervalue(_basis: uint16) <<onlyGovernor>> <<VaultAdmin>> -    allowedSwapUndervalue(): (value: uint256) <<VaultAdmin>> -    setOracleSlippage(_asset: address, _allowedOracleSlippageBps: uint16) <<onlyGovernor>> <<VaultAdmin>> -    supportAsset(_asset: address, _unitConversion: uint8) <<onlyGovernor>> <<VaultAdmin>> -    cacheDecimals(_asset: address) <<onlyGovernor>> <<VaultAdmin>> -    approveStrategy(_addr: address) <<onlyGovernor>> <<VaultAdmin>> -    removeStrategy(_addr: address) <<onlyGovernor>> <<VaultAdmin>> -    depositToStrategy(_strategyToAddress: address, _assets: address[], _amounts: uint256[]) <<onlyGovernorOrStrategist, nonReentrant>> <<VaultAdmin>> -    withdrawFromStrategy(_strategyFromAddress: address, _assets: address[], _amounts: uint256[]) <<onlyGovernorOrStrategist, nonReentrant>> <<VaultAdmin>> -    setMaxSupplyDiff(_maxSupplyDiff: uint256) <<onlyGovernor>> <<VaultAdmin>> -    setTrusteeAddress(_address: address) <<onlyGovernor>> <<VaultAdmin>> -    setTrusteeFeeBps(_basis: uint256) <<onlyGovernor>> <<VaultAdmin>> -    setOusdMetaStrategy(_ousdMetaStrategy: address) <<onlyGovernor>> <<VaultAdmin>> -    pauseRebase() <<onlyGovernorOrStrategist>> <<VaultAdmin>> -    unpauseRebase() <<onlyGovernorOrStrategist>> <<VaultAdmin>> -    pauseCapital() <<onlyGovernorOrStrategist>> <<VaultAdmin>> -    unpauseCapital() <<onlyGovernorOrStrategist>> <<VaultAdmin>> -    transferToken(_asset: address, _amount: uint256) <<onlyGovernor>> <<VaultAdmin>> -    withdrawAllFromStrategy(_strategyAddr: address) <<onlyGovernorOrStrategist>> <<VaultAdmin>> -    withdrawAllFromStrategies() <<onlyGovernorOrStrategist>> <<VaultAdmin>> -Public: -    <<event>> PendingGovernorshipTransfer(previousGovernor: address, newGovernor: address) <<Governable>> -    <<event>> GovernorshipTransferred(previousGovernor: address, newGovernor: address) <<Governable>> -    <<event>> AssetSupported(_asset: address) <<VaultStorage>> +218 + +OETHVaultAdmin +../contracts/vault/OETHVaultAdmin.sol + +Private: +   initialized: bool <<Initializable>> +   initializing: bool <<Initializable>> +   ______gap: uint256[50] <<Initializable>> +   governorPosition: bytes32 <<Governable>> +   pendingGovernorPosition: bytes32 <<Governable>> +   reentryStatusPosition: bytes32 <<Governable>> +   _deprecated_rebaseHooksAddr: address <<VaultStorage>> +   _deprecated_uniswapAddr: address <<VaultStorage>> +   _deprecated_swapTokens: address[] <<VaultStorage>> +   __gap: uint256[50] <<VaultStorage>> +Internal: +   assets: mapping(address=>Asset) <<VaultStorage>> +   allAssets: address[] <<VaultStorage>> +   strategies: mapping(address=>Strategy) <<VaultStorage>> +   allStrategies: address[] <<VaultStorage>> +   oUSD: OUSD <<VaultStorage>> +   swapConfig: SwapConfig <<VaultStorage>> +Public: +   _NOT_ENTERED: uint256 <<Governable>> +   _ENTERED: uint256 <<Governable>> +   priceProvider: address <<VaultStorage>> +   rebasePaused: bool <<VaultStorage>> +   capitalPaused: bool <<VaultStorage>> +   redeemFeeBps: uint256 <<VaultStorage>> +   vaultBuffer: uint256 <<VaultStorage>> +   autoAllocateThreshold: uint256 <<VaultStorage>> +   rebaseThreshold: uint256 <<VaultStorage>> +   adminImplPosition: bytes32 <<VaultStorage>> +   strategistAddr: address <<VaultStorage>> +   assetDefaultStrategies: mapping(address=>address) <<VaultStorage>> +   maxSupplyDiff: uint256 <<VaultStorage>> +   trusteeAddress: address <<VaultStorage>> +   trusteeFeeBps: uint256 <<VaultStorage>> +   MINT_MINIMUM_UNIT_PRICE: uint256 <<VaultStorage>> +   ousdMetaStrategy: address <<VaultStorage>> +   netOusdMintedForStrategy: int256 <<VaultStorage>> +   netOusdMintForStrategyThreshold: uint256 <<VaultStorage>> +   MIN_UNIT_PRICE_DRIFT: uint256 <<VaultStorage>> +   MAX_UNIT_PRICE_DRIFT: uint256 <<VaultStorage>> + +Internal: +    _governor(): (governorOut: address) <<Governable>> +    _pendingGovernor(): (pendingGovernor: address) <<Governable>> +    _setGovernor(newGovernor: address) <<Governable>> +    _setPendingGovernor(newGovernor: address) <<Governable>> +    _changeGovernor(_newGovernor: address) <<Governable>> +    _depositToStrategy(_strategyToAddress: address, _assets: address[], _amounts: uint256[]) <<VaultAdmin>> +    _withdrawFromStrategy(_recipient: address, _strategyFromAddress: address, _assets: address[], _amounts: uint256[]) <<VaultAdmin>> +    _cacheDecimals(token: address) <<VaultAdmin>> +External: +    transferGovernance(_newGovernor: address) <<onlyGovernor>> <<Governable>> +    claimGovernance() <<Governable>> +    setAdminImpl(newImpl: address) <<onlyGovernor>> <<VaultStorage>> +    setPriceProvider(_priceProvider: address) <<onlyGovernor>> <<VaultAdmin>> +    setRedeemFeeBps(_redeemFeeBps: uint256) <<onlyGovernor>> <<VaultAdmin>> +    setVaultBuffer(_vaultBuffer: uint256) <<onlyGovernorOrStrategist>> <<VaultAdmin>> +    setAutoAllocateThreshold(_threshold: uint256) <<onlyGovernor>> <<VaultAdmin>> +    setRebaseThreshold(_threshold: uint256) <<onlyGovernor>> <<VaultAdmin>> +    setStrategistAddr(_address: address) <<onlyGovernor>> <<VaultAdmin>> +    setAssetDefaultStrategy(_asset: address, _strategy: address) <<onlyGovernorOrStrategist>> <<VaultAdmin>> +    setNetOusdMintForStrategyThreshold(_threshold: uint256) <<onlyGovernor>> <<VaultAdmin>> +    swapCollateral(_fromAsset: address, _toAsset: address, _fromAssetAmount: uint256, _minToAssetAmount: uint256, _data: bytes): (toAssetAmount: uint256) <<nonReentrant, onlyGovernorOrStrategist>> <<VaultAdmin>> +    setSwapper(_swapperAddr: address) <<onlyGovernor>> <<VaultAdmin>> +    swapper(): (swapper_: address) <<VaultAdmin>> +    setSwapAllowedUndervalue(_basis: uint16) <<onlyGovernor>> <<VaultAdmin>> +    allowedSwapUndervalue(): (value: uint256) <<VaultAdmin>> +    setOracleSlippage(_asset: address, _allowedOracleSlippageBps: uint16) <<onlyGovernor>> <<VaultAdmin>> +    supportAsset(_asset: address, _unitConversion: uint8) <<onlyGovernor>> <<VaultAdmin>> +    removeAsset(_asset: address) <<onlyGovernor>> <<VaultAdmin>> +    cacheDecimals(_asset: address) <<onlyGovernor>> <<VaultAdmin>> +    approveStrategy(_addr: address) <<onlyGovernor>> <<VaultAdmin>> +    removeStrategy(_addr: address) <<onlyGovernor>> <<VaultAdmin>> +    depositToStrategy(_strategyToAddress: address, _assets: address[], _amounts: uint256[]) <<onlyGovernorOrStrategist, nonReentrant>> <<VaultAdmin>> +    withdrawFromStrategy(_strategyFromAddress: address, _assets: address[], _amounts: uint256[]) <<onlyGovernorOrStrategist, nonReentrant>> <<VaultAdmin>> +    setMaxSupplyDiff(_maxSupplyDiff: uint256) <<onlyGovernor>> <<VaultAdmin>> +    setTrusteeAddress(_address: address) <<onlyGovernor>> <<VaultAdmin>> +    setTrusteeFeeBps(_basis: uint256) <<onlyGovernor>> <<VaultAdmin>> +    setOusdMetaStrategy(_ousdMetaStrategy: address) <<onlyGovernor>> <<VaultAdmin>> +    pauseRebase() <<onlyGovernorOrStrategist>> <<VaultAdmin>> +    unpauseRebase() <<onlyGovernorOrStrategist>> <<VaultAdmin>> +    pauseCapital() <<onlyGovernorOrStrategist>> <<VaultAdmin>> +    unpauseCapital() <<onlyGovernorOrStrategist>> <<VaultAdmin>> +    transferToken(_asset: address, _amount: uint256) <<onlyGovernor>> <<VaultAdmin>> +    withdrawAllFromStrategy(_strategyAddr: address) <<onlyGovernorOrStrategist>> <<VaultAdmin>> +    withdrawAllFromStrategies() <<onlyGovernorOrStrategist>> <<VaultAdmin>> +Public: +    <<event>> PendingGovernorshipTransfer(previousGovernor: address, newGovernor: address) <<Governable>> +    <<event>> GovernorshipTransferred(previousGovernor: address, newGovernor: address) <<Governable>> +    <<event>> AssetSupported(_asset: address) <<VaultStorage>> +    <<event>> AssetRemoved(_asset: address) <<VaultStorage>>    <<event>> AssetDefaultStrategyUpdated(_asset: address, _strategy: address) <<VaultStorage>>    <<event>> AssetAllocated(_asset: address, _strategy: address, _amount: uint256) <<VaultStorage>>    <<event>> StrategyApproved(_addr: address) <<VaultStorage>> diff --git a/contracts/docs/OETHVaultCoreSquashed.svg b/contracts/docs/OETHVaultCoreSquashed.svg index e2dbd8c5ef..320d7fd8d5 100644 --- a/contracts/docs/OETHVaultCoreSquashed.svg +++ b/contracts/docs/OETHVaultCoreSquashed.svg @@ -4,143 +4,151 @@ - - + + UmlClassDiagram - - + + -201 - -OETHVaultCore -../contracts/vault/OETHVaultCore.sol - -Private: -   initialized: bool <<Initializable>> -   initializing: bool <<Initializable>> -   ______gap: uint256[50] <<Initializable>> -   governorPosition: bytes32 <<Governable>> -   pendingGovernorPosition: bytes32 <<Governable>> -   reentryStatusPosition: bytes32 <<Governable>> -   _deprecated_rebaseHooksAddr: address <<VaultStorage>> -   _deprecated_uniswapAddr: address <<VaultStorage>> -   _deprecated_swapTokens: address[] <<VaultStorage>> -Internal: -   assets: mapping(address=>Asset) <<VaultStorage>> -   allAssets: address[] <<VaultStorage>> -   strategies: mapping(address=>Strategy) <<VaultStorage>> -   allStrategies: address[] <<VaultStorage>> -   oUSD: OUSD <<VaultStorage>> -   swapConfig: SwapConfig <<VaultStorage>> -   MAX_INT: uint256 <<VaultCore>> -   MAX_UINT: uint256 <<VaultCore>> -Public: -   _NOT_ENTERED: uint256 <<Governable>> -   _ENTERED: uint256 <<Governable>> -   priceProvider: address <<VaultStorage>> -   rebasePaused: bool <<VaultStorage>> -   capitalPaused: bool <<VaultStorage>> -   redeemFeeBps: uint256 <<VaultStorage>> -   vaultBuffer: uint256 <<VaultStorage>> -   autoAllocateThreshold: uint256 <<VaultStorage>> -   rebaseThreshold: uint256 <<VaultStorage>> -   adminImplPosition: bytes32 <<VaultStorage>> -   strategistAddr: address <<VaultStorage>> -   assetDefaultStrategies: mapping(address=>address) <<VaultStorage>> -   maxSupplyDiff: uint256 <<VaultStorage>> -   trusteeAddress: address <<VaultStorage>> -   trusteeFeeBps: uint256 <<VaultStorage>> -   MINT_MINIMUM_UNIT_PRICE: uint256 <<VaultStorage>> -   ousdMetaStrategy: address <<VaultStorage>> -   netOusdMintedForStrategy: int256 <<VaultStorage>> -   netOusdMintForStrategyThreshold: uint256 <<VaultStorage>> -   MIN_UNIT_PRICE_DRIFT: uint256 <<VaultStorage>> -   MAX_UNIT_PRICE_DRIFT: uint256 <<VaultStorage>> - -Private: -    abs(x: int256): uint256 <<VaultCore>> -Internal: -    _governor(): (governorOut: address) <<Governable>> -    _pendingGovernor(): (pendingGovernor: address) <<Governable>> -    _setGovernor(newGovernor: address) <<Governable>> -    _setPendingGovernor(newGovernor: address) <<Governable>> -    _changeGovernor(_newGovernor: address) <<Governable>> -    _redeem(_amount: uint256, _minimumUnitAmount: uint256) <<VaultCore>> -    _allocate() <<VaultCore>> -    _rebase(): uint256 <<whenNotRebasePaused>> <<VaultCore>> -    _totalValue(): (value: uint256) <<VaultCore>> -    _totalValueInVault(): (value: uint256) <<VaultCore>> -    _totalValueInStrategies(): (value: uint256) <<VaultCore>> -    _totalValueInStrategy(_strategyAddr: address): (value: uint256) <<VaultCore>> -    _checkBalance(_asset: address): (balance: uint256) <<VaultCore>> -    _calculateRedeemOutputs(_amount: uint256): (outputs: uint256[]) <<VaultCore>> -    _toUnits(_raw: uint256, _asset: address): uint256 <<VaultCore>> -    _toUnitPrice(_asset: address, isMint: bool): (price: uint256) <<VaultCore>> -    _getDecimals(_asset: address): (decimals: uint256) <<VaultCore>> -External: -    <<payable>> null() <<VaultCore>> -    transferGovernance(_newGovernor: address) <<onlyGovernor>> <<Governable>> -    claimGovernance() <<Governable>> -    setAdminImpl(newImpl: address) <<onlyGovernor>> <<VaultStorage>> -    initialize(_priceProvider: address, _oToken: address) <<onlyGovernor, initializer>> <<VaultInitializer>> -    mint(_asset: address, _amount: uint256, _minimumOusdAmount: uint256) <<whenNotCapitalPaused, nonReentrant>> <<VaultCore>> -    mintForStrategy(_amount: uint256) <<whenNotCapitalPaused, onlyOusdMetaStrategy>> <<VaultCore>> -    redeem(_amount: uint256, _minimumUnitAmount: uint256) <<whenNotCapitalPaused, nonReentrant>> <<VaultCore>> -    burnForStrategy(_amount: uint256) <<whenNotCapitalPaused, onlyOusdMetaStrategy>> <<VaultCore>> -    redeemAll(_minimumUnitAmount: uint256) <<whenNotCapitalPaused, nonReentrant>> <<VaultCore>> -    allocate() <<whenNotCapitalPaused, nonReentrant>> <<VaultCore>> -    rebase() <<nonReentrant>> <<VaultCore>> -    totalValue(): (value: uint256) <<VaultCore>> -    checkBalance(_asset: address): uint256 <<VaultCore>> -    calculateRedeemOutputs(_amount: uint256): uint256[] <<VaultCore>> -    priceUnitMint(asset: address): (price: uint256) <<VaultCore>> -    priceUnitRedeem(asset: address): (price: uint256) <<VaultCore>> -    getAllAssets(): address[] <<VaultCore>> -    getStrategyCount(): uint256 <<VaultCore>> -    getAllStrategies(): address[] <<VaultCore>> -    isSupportedAsset(_asset: address): bool <<VaultCore>> -Public: -    <<event>> PendingGovernorshipTransfer(previousGovernor: address, newGovernor: address) <<Governable>> -    <<event>> GovernorshipTransferred(previousGovernor: address, newGovernor: address) <<Governable>> -    <<event>> AssetSupported(_asset: address) <<VaultStorage>> -    <<event>> AssetDefaultStrategyUpdated(_asset: address, _strategy: address) <<VaultStorage>> -    <<event>> AssetAllocated(_asset: address, _strategy: address, _amount: uint256) <<VaultStorage>> -    <<event>> StrategyApproved(_addr: address) <<VaultStorage>> -    <<event>> StrategyRemoved(_addr: address) <<VaultStorage>> -    <<event>> Mint(_addr: address, _value: uint256) <<VaultStorage>> -    <<event>> Redeem(_addr: address, _value: uint256) <<VaultStorage>> -    <<event>> CapitalPaused() <<VaultStorage>> -    <<event>> CapitalUnpaused() <<VaultStorage>> -    <<event>> RebasePaused() <<VaultStorage>> -    <<event>> RebaseUnpaused() <<VaultStorage>> -    <<event>> VaultBufferUpdated(_vaultBuffer: uint256) <<VaultStorage>> -    <<event>> OusdMetaStrategyUpdated(_ousdMetaStrategy: address) <<VaultStorage>> -    <<event>> RedeemFeeUpdated(_redeemFeeBps: uint256) <<VaultStorage>> -    <<event>> PriceProviderUpdated(_priceProvider: address) <<VaultStorage>> -    <<event>> AllocateThresholdUpdated(_threshold: uint256) <<VaultStorage>> -    <<event>> RebaseThresholdUpdated(_threshold: uint256) <<VaultStorage>> -    <<event>> StrategistUpdated(_address: address) <<VaultStorage>> -    <<event>> MaxSupplyDiffChanged(maxSupplyDiff: uint256) <<VaultStorage>> -    <<event>> YieldDistribution(_to: address, _yield: uint256, _fee: uint256) <<VaultStorage>> -    <<event>> TrusteeFeeBpsChanged(_basis: uint256) <<VaultStorage>> -    <<event>> TrusteeAddressChanged(_address: address) <<VaultStorage>> -    <<event>> NetOusdMintForStrategyThresholdChanged(_threshold: uint256) <<VaultStorage>> -    <<event>> SwapperChanged(_address: address) <<VaultStorage>> -    <<event>> SwapAllowedUndervalueChanged(_basis: uint256) <<VaultStorage>> -    <<event>> SwapSlippageChanged(_asset: address, _basis: uint256) <<VaultStorage>> -    <<event>> Swapped(_fromAsset: address, _toAsset: address, _fromAssetAmount: uint256, _toAssetAmount: uint256) <<VaultStorage>> -    <<modifier>> initializer() <<Initializable>> -    <<modifier>> onlyGovernor() <<Governable>> -    <<modifier>> nonReentrant() <<Governable>> -    <<modifier>> whenNotRebasePaused() <<VaultCore>> -    <<modifier>> whenNotCapitalPaused() <<VaultCore>> -    <<modifier>> onlyOusdMetaStrategy() <<VaultCore>> -    constructor() <<Governable>> -    governor(): address <<Governable>> -    isGovernor(): bool <<Governable>> -    getAssetCount(): uint256 <<VaultCore>> -    getAssetConfig(_asset: address): (config: Asset) <<VaultCore>> +219 + +OETHVaultCore +../contracts/vault/OETHVaultCore.sol + +Private: +   initialized: bool <<Initializable>> +   initializing: bool <<Initializable>> +   ______gap: uint256[50] <<Initializable>> +   governorPosition: bytes32 <<Governable>> +   pendingGovernorPosition: bytes32 <<Governable>> +   reentryStatusPosition: bytes32 <<Governable>> +   _deprecated_rebaseHooksAddr: address <<VaultStorage>> +   _deprecated_uniswapAddr: address <<VaultStorage>> +   _deprecated_swapTokens: address[] <<VaultStorage>> +   __gap: uint256[50] <<VaultStorage>> +Internal: +   assets: mapping(address=>Asset) <<VaultStorage>> +   allAssets: address[] <<VaultStorage>> +   strategies: mapping(address=>Strategy) <<VaultStorage>> +   allStrategies: address[] <<VaultStorage>> +   oUSD: OUSD <<VaultStorage>> +   swapConfig: SwapConfig <<VaultStorage>> +   MAX_INT: uint256 <<VaultCore>> +   MAX_UINT: uint256 <<VaultCore>> +Public: +   _NOT_ENTERED: uint256 <<Governable>> +   _ENTERED: uint256 <<Governable>> +   priceProvider: address <<VaultStorage>> +   rebasePaused: bool <<VaultStorage>> +   capitalPaused: bool <<VaultStorage>> +   redeemFeeBps: uint256 <<VaultStorage>> +   vaultBuffer: uint256 <<VaultStorage>> +   autoAllocateThreshold: uint256 <<VaultStorage>> +   rebaseThreshold: uint256 <<VaultStorage>> +   adminImplPosition: bytes32 <<VaultStorage>> +   strategistAddr: address <<VaultStorage>> +   assetDefaultStrategies: mapping(address=>address) <<VaultStorage>> +   maxSupplyDiff: uint256 <<VaultStorage>> +   trusteeAddress: address <<VaultStorage>> +   trusteeFeeBps: uint256 <<VaultStorage>> +   MINT_MINIMUM_UNIT_PRICE: uint256 <<VaultStorage>> +   ousdMetaStrategy: address <<VaultStorage>> +   netOusdMintedForStrategy: int256 <<VaultStorage>> +   netOusdMintForStrategyThreshold: uint256 <<VaultStorage>> +   MIN_UNIT_PRICE_DRIFT: uint256 <<VaultStorage>> +   MAX_UNIT_PRICE_DRIFT: uint256 <<VaultStorage>> +   weth: address <<OETHVaultCore>> +   wethAssetIndex: uint256 <<OETHVaultCore>> + +Private: +    abs(x: int256): uint256 <<VaultCore>> +Internal: +    _governor(): (governorOut: address) <<Governable>> +    _pendingGovernor(): (pendingGovernor: address) <<Governable>> +    _setGovernor(newGovernor: address) <<Governable>> +    _setPendingGovernor(newGovernor: address) <<Governable>> +    _changeGovernor(_newGovernor: address) <<Governable>> +    _mint(_asset: address, _amount: uint256, _minimumOusdAmount: uint256) <<OETHVaultCore>> +    _redeem(_amount: uint256, _minimumUnitAmount: uint256) <<OETHVaultCore>> +    _postRedeem(_amount: uint256) <<VaultCore>> +    _allocate() <<VaultCore>> +    _rebase(): uint256 <<whenNotRebasePaused>> <<VaultCore>> +    _totalValue(): (value: uint256) <<VaultCore>> +    _totalValueInVault(): (value: uint256) <<VaultCore>> +    _totalValueInStrategies(): (value: uint256) <<VaultCore>> +    _totalValueInStrategy(_strategyAddr: address): (value: uint256) <<VaultCore>> +    _checkBalance(_asset: address): (balance: uint256) <<VaultCore>> +    _calculateRedeemOutputs(_amount: uint256): (outputs: uint256[]) <<OETHVaultCore>> +    _toUnits(_raw: uint256, _asset: address): uint256 <<VaultCore>> +    _toUnitPrice(_asset: address, isMint: bool): (price: uint256) <<VaultCore>> +    _getDecimals(_asset: address): (decimals: uint256) <<VaultCore>> +External: +    transferGovernance(_newGovernor: address) <<onlyGovernor>> <<Governable>> +    claimGovernance() <<Governable>> +    setAdminImpl(newImpl: address) <<onlyGovernor>> <<VaultStorage>> +    initialize(_priceProvider: address, _oToken: address) <<onlyGovernor, initializer>> <<VaultInitializer>> +    mint(_asset: address, _amount: uint256, _minimumOusdAmount: uint256) <<whenNotCapitalPaused, nonReentrant>> <<VaultCore>> +    mintForStrategy(_amount: uint256) <<whenNotCapitalPaused, onlyOusdMetaStrategy>> <<VaultCore>> +    redeem(_amount: uint256, _minimumUnitAmount: uint256) <<whenNotCapitalPaused, nonReentrant>> <<VaultCore>> +    burnForStrategy(_amount: uint256) <<whenNotCapitalPaused, onlyOusdMetaStrategy>> <<VaultCore>> +    redeemAll(_minimumUnitAmount: uint256) <<whenNotCapitalPaused, nonReentrant>> <<VaultCore>> +    allocate() <<whenNotCapitalPaused, nonReentrant>> <<VaultCore>> +    rebase() <<nonReentrant>> <<VaultCore>> +    totalValue(): (value: uint256) <<VaultCore>> +    checkBalance(_asset: address): uint256 <<VaultCore>> +    calculateRedeemOutputs(_amount: uint256): uint256[] <<VaultCore>> +    priceUnitMint(asset: address): (price: uint256) <<VaultCore>> +    priceUnitRedeem(asset: address): (price: uint256) <<VaultCore>> +    getAllAssets(): address[] <<VaultCore>> +    getStrategyCount(): uint256 <<VaultCore>> +    getAllStrategies(): address[] <<VaultCore>> +    isSupportedAsset(_asset: address): bool <<VaultCore>> +    null() <<VaultCore>> +    cacheWETHAssetIndex() <<onlyGovernor>> <<OETHVaultCore>> +Public: +    <<event>> PendingGovernorshipTransfer(previousGovernor: address, newGovernor: address) <<Governable>> +    <<event>> GovernorshipTransferred(previousGovernor: address, newGovernor: address) <<Governable>> +    <<event>> AssetSupported(_asset: address) <<VaultStorage>> +    <<event>> AssetRemoved(_asset: address) <<VaultStorage>> +    <<event>> AssetDefaultStrategyUpdated(_asset: address, _strategy: address) <<VaultStorage>> +    <<event>> AssetAllocated(_asset: address, _strategy: address, _amount: uint256) <<VaultStorage>> +    <<event>> StrategyApproved(_addr: address) <<VaultStorage>> +    <<event>> StrategyRemoved(_addr: address) <<VaultStorage>> +    <<event>> Mint(_addr: address, _value: uint256) <<VaultStorage>> +    <<event>> Redeem(_addr: address, _value: uint256) <<VaultStorage>> +    <<event>> CapitalPaused() <<VaultStorage>> +    <<event>> CapitalUnpaused() <<VaultStorage>> +    <<event>> RebasePaused() <<VaultStorage>> +    <<event>> RebaseUnpaused() <<VaultStorage>> +    <<event>> VaultBufferUpdated(_vaultBuffer: uint256) <<VaultStorage>> +    <<event>> OusdMetaStrategyUpdated(_ousdMetaStrategy: address) <<VaultStorage>> +    <<event>> RedeemFeeUpdated(_redeemFeeBps: uint256) <<VaultStorage>> +    <<event>> PriceProviderUpdated(_priceProvider: address) <<VaultStorage>> +    <<event>> AllocateThresholdUpdated(_threshold: uint256) <<VaultStorage>> +    <<event>> RebaseThresholdUpdated(_threshold: uint256) <<VaultStorage>> +    <<event>> StrategistUpdated(_address: address) <<VaultStorage>> +    <<event>> MaxSupplyDiffChanged(maxSupplyDiff: uint256) <<VaultStorage>> +    <<event>> YieldDistribution(_to: address, _yield: uint256, _fee: uint256) <<VaultStorage>> +    <<event>> TrusteeFeeBpsChanged(_basis: uint256) <<VaultStorage>> +    <<event>> TrusteeAddressChanged(_address: address) <<VaultStorage>> +    <<event>> NetOusdMintForStrategyThresholdChanged(_threshold: uint256) <<VaultStorage>> +    <<event>> SwapperChanged(_address: address) <<VaultStorage>> +    <<event>> SwapAllowedUndervalueChanged(_basis: uint256) <<VaultStorage>> +    <<event>> SwapSlippageChanged(_asset: address, _basis: uint256) <<VaultStorage>> +    <<event>> Swapped(_fromAsset: address, _toAsset: address, _fromAssetAmount: uint256, _toAssetAmount: uint256) <<VaultStorage>> +    <<modifier>> initializer() <<Initializable>> +    <<modifier>> onlyGovernor() <<Governable>> +    <<modifier>> nonReentrant() <<Governable>> +    <<modifier>> whenNotRebasePaused() <<VaultCore>> +    <<modifier>> whenNotCapitalPaused() <<VaultCore>> +    <<modifier>> onlyOusdMetaStrategy() <<VaultCore>> +    constructor() <<Governable>> +    governor(): address <<Governable>> +    isGovernor(): bool <<Governable>> +    getAssetCount(): uint256 <<VaultCore>> +    getAssetConfig(_asset: address): (config: Asset) <<VaultCore>> +    constructor(_weth: address) <<OETHVaultCore>> diff --git a/contracts/docs/OETHVaultHierarchy.svg b/contracts/docs/OETHVaultHierarchy.svg index 6e3546cc1d..2d05c5e79d 100644 --- a/contracts/docs/OETHVaultHierarchy.svg +++ b/contracts/docs/OETHVaultHierarchy.svg @@ -4,268 +4,280 @@ - + UmlClassDiagram - + 20 - -Governable -../contracts/governance/Governable.sol + +Governable +../contracts/governance/Governable.sol - + -42 - -<<Interface>> -IGetExchangeRateToken -../contracts/interfaces/IGetExchangeRateToken.sol +43 + +<<Interface>> +IGetExchangeRateToken +../contracts/interfaces/IGetExchangeRateToken.sol - + -48 - -<<Interface>> -IOracle -../contracts/interfaces/IOracle.sol +50 + +<<Interface>> +IOracle +../contracts/interfaces/IOracle.sol - + -52 - -<<Interface>> -IStrategy -../contracts/interfaces/IStrategy.sol +56 + +<<Interface>> +IStrategy +../contracts/interfaces/IStrategy.sol - + -53 - -<<Interface>> -ISwapper -../contracts/interfaces/ISwapper.sol +57 + +<<Interface>> +ISwapper +../contracts/interfaces/ISwapper.sol - + -55 - -<<Interface>> -IVault -../contracts/interfaces/IVault.sol +60 + +<<Interface>> +IVault +../contracts/interfaces/IVault.sol - + -207 - -VaultStorage -../contracts/vault/VaultStorage.sol +225 + +VaultStorage +../contracts/vault/VaultStorage.sol - + -55->207 - - +60->225 + + - + -186 - -OUSD -../contracts/token/OUSD.sol +203 + +OUSD +../contracts/token/OUSD.sol - + -186->20 - - +203->20 + + - + -194 - -<<Abstract>> -Initializable -../contracts/utils/Initializable.sol +212 + +<<Abstract>> +Initializable +../contracts/utils/Initializable.sol - + -186->194 - - +203->212 + + - + -197 - -<<Abstract>> -InitializableERC20Detailed -../contracts/utils/InitializableERC20Detailed.sol +215 + +<<Abstract>> +InitializableERC20Detailed +../contracts/utils/InitializableERC20Detailed.sol - + -186->197 - - +203->215 + + - + -392 - -<<Interface>> -IERC20 -../node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol +694 + +<<Interface>> +IERC20 +../node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol - + -197->392 - - +215->694 + + - + -200 - -OETHVaultAdmin -../contracts/vault/OETHVaultAdmin.sol +218 + +OETHVaultAdmin +../contracts/vault/OETHVaultAdmin.sol - + -204 - -VaultAdmin -../contracts/vault/VaultAdmin.sol +222 + +VaultAdmin +../contracts/vault/VaultAdmin.sol - + -200->204 - - +218->222 + + - + -201 - -OETHVaultCore -../contracts/vault/OETHVaultCore.sol +219 + +OETHVaultCore +../contracts/vault/OETHVaultCore.sol - + + +219->56 + + + + -205 - -VaultCore -../contracts/vault/VaultCore.sol +223 + +VaultCore +../contracts/vault/VaultCore.sol - + -201->205 - - +219->223 + + - - -204->48 - - + + +219->694 + + - - -204->52 - - + + +222->50 + + - + -204->53 - - +222->56 + + - + -204->55 - - +222->57 + + - - -204->207 - - + + +222->60 + + - + -204->392 - - - - - -205->42 - - +222->225 + + - - -205->48 - - + + +222->694 + + - - -205->52 - - + + +223->43 + + - - -206 - -VaultInitializer -../contracts/vault/VaultInitializer.sol + + +223->50 + + - - -205->206 - - + + +223->56 + + - - -205->392 - - + + +224 + +VaultInitializer +../contracts/vault/VaultInitializer.sol - - -206->186 - - + + +223->224 + + - - -206->207 - - + + +223->694 + + - + -207->20 - - +224->203 + + - - -207->186 - - - - + -207->194 - - +224->225 + + + + + +225->20 + + + + + +225->203 + + + + + +225->212 + + diff --git a/contracts/docs/OETHVaultStorage.svg b/contracts/docs/OETHVaultStorage.svg index c950373509..0d73565a93 100644 --- a/contracts/docs/OETHVaultStorage.svg +++ b/contracts/docs/OETHVaultStorage.svg @@ -4,262 +4,306 @@ - - + + StorageDiagram - - + + -6 - -OETHVaultCore <<Contract>> - -slot - -0 - -1-50 - -51 - -52 - -53 - -54 - -55 - -56 - -57 - -58 - -59 - -60 - -61 - -62 - -63 - -64 - -65 - -66 - -67 - -68 - -69 - -70 - -71 - -72 - -type: <inherited contract>.variable (bytes) - -unallocated (30) - -bool: Initializable.initializing (1) - -bool: Initializable.initialized (1) - -uint256[50]: Initializable.______gap (1600) - -mapping(address=>Asset): VaultStorage.assets (32) - -address[]: VaultStorage.allAssets (32) - -mapping(address=>Strategy): VaultStorage.strategies (32) - -address[]: VaultStorage.allStrategies (32) - -unallocated (10) - -bool: VaultStorage.capitalPaused (1) - -bool: VaultStorage.rebasePaused (1) - -address: VaultStorage.priceProvider (20) - -uint256: VaultStorage.redeemFeeBps (32) - -uint256: VaultStorage.vaultBuffer (32) - -uint256: VaultStorage.autoAllocateThreshold (32) - -uint256: VaultStorage.rebaseThreshold (32) - -unallocated (12) - -OUSD: VaultStorage.oUSD (20) - -unallocated (12) - -address: VaultStorage._deprecated_rebaseHooksAddr (20) - -unallocated (12) - -address: VaultStorage._deprecated_uniswapAddr (20) - -unallocated (12) - -address: VaultStorage.strategistAddr (20) - -mapping(address=>address): VaultStorage.assetDefaultStrategies (32) - -uint256: VaultStorage.maxSupplyDiff (32) - -unallocated (12) - -address: VaultStorage.trusteeAddress (20) - -uint256: VaultStorage.trusteeFeeBps (32) - -address[]: VaultStorage._deprecated_swapTokens (32) - -unallocated (12) - -address: VaultStorage.ousdMetaStrategy (20) - -int256: VaultStorage.netOusdMintedForStrategy (32) - -uint256: VaultStorage.netOusdMintForStrategyThreshold (32) - -SwapConfig: VaultStorage.swapConfig (32) +7 + +OETHVaultCore <<Contract>> + +slot + +0 + +1-50 + +51 + +52 + +53 + +54 + +55 + +56 + +57 + +58 + +59 + +60 + +61 + +62 + +63 + +64 + +65 + +66 + +67 + +68 + +69 + +70 + +71 + +72 + +73-122 + +123 + +type: <inherited contract>.variable (bytes) + +unallocated (30) + +bool: Initializable.initializing (1) + +bool: Initializable.initialized (1) + +uint256[50]: Initializable.______gap (1600) + +mapping(address=>Asset): VaultStorage.assets (32) + +address[]: VaultStorage.allAssets (32) + +mapping(address=>Strategy): VaultStorage.strategies (32) + +address[]: VaultStorage.allStrategies (32) + +unallocated (10) + +bool: VaultStorage.capitalPaused (1) + +bool: VaultStorage.rebasePaused (1) + +address: VaultStorage.priceProvider (20) + +uint256: VaultStorage.redeemFeeBps (32) + +uint256: VaultStorage.vaultBuffer (32) + +uint256: VaultStorage.autoAllocateThreshold (32) + +uint256: VaultStorage.rebaseThreshold (32) + +unallocated (12) + +OUSD: VaultStorage.oUSD (20) + +unallocated (12) + +address: VaultStorage._deprecated_rebaseHooksAddr (20) + +unallocated (12) + +address: VaultStorage._deprecated_uniswapAddr (20) + +unallocated (12) + +address: VaultStorage.strategistAddr (20) + +mapping(address=>address): VaultStorage.assetDefaultStrategies (32) + +uint256: VaultStorage.maxSupplyDiff (32) + +unallocated (12) + +address: VaultStorage.trusteeAddress (20) + +uint256: VaultStorage.trusteeFeeBps (32) + +address[]: VaultStorage._deprecated_swapTokens (32) + +unallocated (12) + +address: VaultStorage.ousdMetaStrategy (20) + +int256: VaultStorage.netOusdMintedForStrategy (32) + +uint256: VaultStorage.netOusdMintForStrategyThreshold (32) + +SwapConfig: VaultStorage.swapConfig (32) + +uint256[50]: VaultStorage.__gap (1600) + +uint256: wethAssetIndex (32) 1 - -Asset <<Struct>> - -offset - -0 - -type: variable (bytes) - -unallocated (27) - -uint16: allowedOracleSlippageBps (2) - -uint8: decimals (1) - -UnitConversion: unitConversion (1) - -bool: isSupported (1) + +Asset <<Struct>> + +offset + +0 + +type: variable (bytes) + +unallocated (27) + +uint16: allowedOracleSlippageBps (2) + +uint8: decimals (1) + +UnitConversion: unitConversion (1) + +bool: isSupported (1) - + -6:8->1 - - +7:8->1 + + 2 - -address[]: allAssets <<Array>> -0x46bddb1178e94d7f2892ff5f366840eb658911794f2c3a44c450aa2c505186c1 - -offset - -0 - -type: variable (bytes) - -unallocated (12) - -address (20) + +address[]: allAssets <<Array>> +0x46bddb1178e94d7f2892ff5f366840eb658911794f2c3a44c450aa2c505186c1 + +offset + +0 + +type: variable (bytes) + +unallocated (12) + +address (20) - + -6:10->2 - - +7:10->2 + + 3 - -Strategy <<Struct>> - -offset - -0 - -1 - -type: variable (bytes) - -unallocated (31) - -bool: isSupported (1) - -uint256: _deprecated (32) + +Strategy <<Struct>> + +offset + +0 + +1 + +type: variable (bytes) + +unallocated (31) + +bool: isSupported (1) + +uint256: _deprecated (32) - + -6:13->3 - - +7:13->3 + + 4 - -address[]: allStrategies <<Array>> -0x4a11f94e20a93c79f6ec743a1954ec4fc2c08429ae2122118bf234b2185c81b8 - -offset - -0 - -type: variable (bytes) - -unallocated (12) - -address (20) + +address[]: allStrategies <<Array>> +0x4a11f94e20a93c79f6ec743a1954ec4fc2c08429ae2122118bf234b2185c81b8 + +offset + +0 + +type: variable (bytes) + +unallocated (12) + +address (20) - + -6:15->4 - - +7:15->4 + + 5 - -SwapConfig <<Struct>> - -slot - -72 - -type: variable (bytes) - -unallocated (10) - -uint16: allowedUndervalueBps (2) - -address: swapper (20) + +SwapConfig <<Struct>> + +slot + +72 + +type: variable (bytes) + +unallocated (10) + +uint16: allowedUndervalueBps (2) + +address: swapper (20) - + -6:37->5 - - +7:37->5 + + + + + +6 + +uint256[50]: __gap <<Array>> + +slot + +73 + +74 + +75-120 + +121 + +122 + +type: variable (bytes) + +uint256 (32) + +uint256 (32) + +---- (1472) + +uint256 (32) + +uint256 (32) + + + +7:43->6 + + From 9295fe76602ac0121ee59ebaf689962cbe93812e Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Wed, 29 May 2024 13:58:08 +1000 Subject: [PATCH 113/273] Add process for pausing the Native Staking Strategy --- .../docs/plantuml/oethProcesses-pause.png | Bin 0 -> 28166 bytes contracts/docs/plantuml/oethProcesses.png | Bin 448529 -> 454951 bytes contracts/docs/plantuml/oethProcesses.puml | 21 ++++++++++++++++++ 3 files changed, 21 insertions(+) create mode 100644 contracts/docs/plantuml/oethProcesses-pause.png diff --git a/contracts/docs/plantuml/oethProcesses-pause.png b/contracts/docs/plantuml/oethProcesses-pause.png new file mode 100644 index 0000000000000000000000000000000000000000..30ad48ee42193c7931a5ac30ce659c8ed0d1a277 GIT binary patch literal 28166 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 XDr~d1rc2=m*+>*+)$V_kHh=j)8zaHv literal 0 HcmV?d00001 diff --git a/contracts/docs/plantuml/oethProcesses.png b/contracts/docs/plantuml/oethProcesses.png index 35e31411c8a9e8a01074c7c2b99f7636e6a14baa..18f51ef248cba6bf42372ff7eb43409f5c172b50 100644 GIT binary patch literal 454951 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
    #$ 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

    8M5p>cyS$0$+Rdy7k~_%uIs@h z9-a<}cV3xuM%@gF*3b~rF=)9s&|=x%_$aO2?eJ>1L%M|fky1vbgKepnt%I5lGSQ#q z`m2MKf7A#@q?eSiALkssxhi3xR}-QxmY_(B zrKRP80|yMd*K7;$>?Yb@-cn7~H#7)%1amn*UMftFV%+c9H2-CeERmAt8PwSfK0Iu3 zgexk6EZ20^A#*UUAtZz|X<~Tz$RQa!gDLiOY`R8)D8oDF_2g)5L!jMkj{_u3QHIHsE?mT74iU0rt3u}Itw=DDdzLz@uKl2dI8RZ?)sSz6<_{Cj&f zFkKTBlYaDHh~_d|Gro4sAR_(waa?zG0vYEm3x!N!hi@sfezVqoB~BKV@+H z?y&1S>%fym;i$m$DX*{oMVgf4_d1he%_+;bU2%T98Mezuo{2vby6l-;aSi&Nzb_3x zIj78{%^uCYTbpyW*yN_srrM&S+xyQoL^h|}ER&0Vbp2|T*=MMqtBBqscl+K%bmK<@*mG9Mip(y&a^XgidwOqj4x4b|wg`t0wv9;mca z4C2<0?$X%1Qj6PC&qFd?Y+`u1BK_ewQ7@+TD;p;#hp%HN$im7>VNC$OxsSF^0i6c1 zFzmL`?qIdm`Z4two8;{M*@ zPsxiWAs&aLNX_%Qd1#tXeXPQad5E@Eo6}Nx>@w^4XY?}6w%%G(H;SWe>T6AZSPfbv z<5e0<bGj|?C{N<5GGdd0IL z_f0FGxyd_9Z<8AwKft@6-{VWlU)eWHqv zG(pmv*0R;t5xJ;2YMG2aYE$o3@lOZJb8eRDxTXknzFZrS00|qHW4D*V#e%s+S1eN` zoKvE~TYyBvD3hJoq!_(I4b5dus=aE5m#qN}WF*5+3APouRZaJY4ULBFGb@O&RbI=s z+0koipW4B5l`RQAPq^(bz{CvSh^Uo_lz6RDxD8i-J(H)CbChM@rcj`e+0=uPOhPbMCobJFe?%M!K$NJNEG03Gv2X&>Ozj%}e zgT08terDzef)5chTwC&~5 ziiGRVU8!7j8Uvv|el+{Lo|m<|K8O$15b3Uc@G$hqzM(w`OQ;#ynQOOPsWijaCsUm8 zfBb_JrGg|Yq993t&b6be*S@|H6)Sp(i7LU5mvqPF{CmKub#Qc~6AI_KpD{Gxu9UBW<$5iz$h(ZI>=RPq06KUUBl9nK$jpU-hH3fO6CU+w-5ik!#dH|9D&M zAl5jTtxywp!BAH;yv)*a{kasr*Jn*Tvg=vJ&>JViuv~zALa7sO~b>r^&rf3 zHZ@)HbY%s%bCBU%Mw~sbnO5 z!|PH^v((RSs^if1DGxb8R`%g5s|a~;?A$2E;s*Rhg5N3tX$ODrq`!54h7pRO4OO9 zB)kn?Lk#cSS0vt^VWr!BJSXq1vJvTL4*RZ4zi#uLzPDn;8~+`^m=ofJX; z!v#l$!~cu+Z8Zu>ZJ+6AUpDn-<@k8RMN~a$99r?(;~ptSLx>*Z-8EZ(C#W>5t}AhJ znnzJ5BL4MNFXt$fgFqm(=lqV1vwPXgmy_30g(+%QWNpBb+?AYUvX(P&zyx^K)35!- zO!;t-5Iz01qOR)YUg!ucqzWT|sZigarv*;NM|!_FqtO z9PZyi@mbo+>~O;2H{n$c!b|WMcjU%||C2>nb$!k(6wcr*$z1lnc9;7cu>&-%P@Zs< zbP!IQ1LU8+87!k;^)G5We~=pH+POS8B&zurueE<%Beb7BQaqji$(N^_Pg$v-!Lr$^ z{$C*emClle|1&etV#SKBd@mgSg7&P{H#aV;hYTDXvgT8m_Y8g5Dqy3Kg6Yu1jd+Fx z)bsP^-1G6oh|9FSG-k?WLMHuOy1CxDl=SrU&PJ#cyL8oM*;-G=gI;ndfkDJ|n+Rom z@LFK54E?u<FiG-Bmypq95`?_lMZBUq`W7GD5_XxD+s`vgXv%2N6U3l z`V!w*2l85>^NMa|%De#ttA(?&*+RqvFNxGGQG^;v{PeczB7i#Zb2I#5zlr_g>R@WY zV-JOvL5u*9^-ri9N~r{0<0y4-*@q9|uLYA}ULac1-qu#tmCXm)B}d7LCD2y@*A001 zpJd0sB^)KQUKZKzBer?gZKCLf4*c^44tygq@C*!53W@tqYzh9>F*3*Pa0ICw%^!;l z22u|nK6IPb0>DSatIOi-d*@872x4XHE)X=JFyK6)%fvISbp+ZrCd@q0;5nH=VVzI} z4T#KVkpU%WhugOyFu8m8?gzvG44?nkaA|-VziJbkwm4=Lw$s}M1OmnJBjlW^)AP^n zR!?&fxe&|&)hEYp^O$vDstEI4jP>0d`}1eM)pp?5xFTh1gb91y<8IC&6+da6F51F6 zDk^lrWf$(3R0+NT_*wzm-f{eAY)qYdAirjAZK4D!lv$pWKZ`}Vxw&4@*)uaQgogPED~;6 zQ-4VfnYKY#<^&`CN_w*T2#$gjjsZEoy}Cd~0a{t${wyn4=lk&C30i#q(G#Y6a}}_oL%k?8Q%J^XFX? z*%ufl6wdh@zs@^Dtyw+&%D^WuV1Nor3iwm*(J%V0_XHD9OL61$;XD&yHWX$T@g|6y z;yuB_qm^d&Z8cP4XRgkwe_nmX{`;hI&rZ!%)C3d#2DP||Cp{(k6k)dbkI^a_lijo2 zr8`)L_qj|WeFHiA9KHX9A4>h_{)J)6^N1uan9_u zXtZ3VvgI?5UYl6mIGsQ>jii@m9o!dvnO!Y2Y+CllC1m~N$ zTW45N^|+Is(m~xtHx-uNanW?i+TAM0tq%kCVP2&_UM!|nk{vD23jRVMmBHH{E&Aol zm}u6nJ*+M?T^SR?!0^nEU+lS1+i~;uCSGm+cn1~WxOg;%FZs@N(;Dt87x*LnM zo~tG@7^*LFDHo}qG!=Nza)C!%Ox=5a?iFqu%>dIb6z57C0Y#oZ`{f7UJ(2N5k=eNqRYU^Rmdk@Kj{OYuO+1bVSLplfY zi(UJVY?ybAAp}9X(2*h$ic_WYT(}J&R$r-D;qrBR?$^?Lj-3v^`L}x61rB$bn>4vgEl9cVYRsrsJCdK?7qit)-_V8$T39$X?Q0eZPPCg;vY#?LTZwbA zH~f=ejPC(k&l(-2H+vHS-Qh(aJh(D?q^xiCzX2ZErn!Cjy>@m2_wUONHO7h(r3j_I zL2Nr>%9BL$^b&T-evl*h<8jav*zUB19MTHx$N744%$M%p01ksu^Cq9tXgbxfEJ?6&Yu$rSos0Aeuc%Mzw@u$G!TIniXhu6=8CytiF?+2zSZryNhx*>^oPnQvZ_ zlF-g(Q~PPCYcGf|4f19QTE29t=Lw9->?d;5MQm%m{npW`sPdafZG{v4%;y~?XSUh? zicE;%-(A9(&m5by_iV&t2Z!{v0hnWXE&>q6&>8eTTPLC$zJ(f-a5NP-Z z8$~9ODuh3SlwqTVGrQ~Qnq4s4lkyk>YVXg<>gpT?8Ff=&aMcZI11=c-tE6XDl@HdZ zjf=&r3pYpf)T^CQp2|BFtD0$i`SK_bc5ogtxD36l_Mgd~c+upqyEH^Hum(-wg5Hd> z`giX}e>k~`=){*(n{}Y`#TDxt9Q+(_;_DVH<6V>dZ2X6(&GaOf8UV|tH$6N7MSC{^ zZ!FJZaZ+6N_KbZ(PbjLl6Nw4+5e|@?VYhux!f;yaiza=JuFL9x(ayPF`d=%$qQ%(h zKw^# ztnVoc_n=e%@$5b>6olGS49eS00kZqBNFC^U6p0OQ88HPAjiOq3qC8V_SgxixK~Iq5BBG?=vA(OH$34OH`I5T>(qO1_f5%0Ge_}4 zPJ?HFeO;fMG!>{E%xYP#>^mkgmdfiI2%PB-$g562(;i{wiL}?gI+*Q4%h%8?_FAF& zd4q`B?LzQo&2Qh5L~9}spwrA>9EURia#q>C|a7raB zAs@3*T)Qqtcx(j!{Yx@@V0w<>+hM}K`xeP&XTE)9!6qb^&!0JOE*`1#OHfFhJXxDM zc9Uvs(%cXlXYPU-qhw*e9mlQL!t&r2ne=q|G-@%x2}B?BNdPpjn&0&B@IU?0uN3V` zcuHS;UY9A*p>DKf{|t3#VlVZ;0kT#IQR&Z2$l5%p0~AL}7q9Gy2Szv4kD!ZSdZOC< zsjBLvVQL03Av>tCIN#Y$G1*E^rEc>b<-z>4fyjh`H@#WqL0^f%?WJLw1DFzlT2v{* z>isN$zWWf%1<$8`w$m0_)B%n<2@j*X5+z@tdL zr4Rg$XFk|4Z~y##q2fVfpF3h85Mj)Hpzgt4p>VgJQuC707g{8?VxbdX{MH6gsTix; zI$AvNB(RAi%YX9s{_LmOs)9{&OCyaxHZgQ+g36tzl|Kd^d3{E*;P})P`k)5@iKi8W zb%1&06@jA6DAO8QZ6Y8Gzw#gT2qV}ecW`i+h`SURnaGw7R+q!+BK>FoOl%+_Ad>SkYSAt zPDs+H8R$$i)U!`q2@fnHH)0qvF=^{gch1OagP1L+HBoz=Sc+VH=3T}pwX5GD<*-|o z;Zl3bhE3Lgaq`$KyAH58EO4CJp9guTw0at<2tD zt)tJ&OY?GQ{IBZ$4#=A}K&U~la-*#Pnb+HVufnHD#l%G?#llW3ewy<;k>|zn>}Y_h z+dEaqFfGQ@M8Q{^rf->T7oU~Y5GKVaB6QY!QPou6&=@_6n_XbEo}!T=F4o<~ zbVN7&l$SF+gcXvlD!pS|o@y{T)3E_ZId$!q?DN&A@}B?zhUQMrl8Soe5v5s^1C7%< zk{FEiXm2$)Gb1Kf7y`LEMnqrrK}mwTMH8EcX6~@7R?NmYFftTIX3>sCm?T6DVfg*= zl9;z-MfNx{*>Q*A?}LMJgDeJRTRLWFMCW*VTU(i!L4&4AOSBW7~f_29$f+*DelPDDV8soIruUlGTP)DU> zhBoxK>zIMn2Ik;017Gi&V%clPsyRg)g)i*F){*hwL`Myn;3OF)AciNe061$~9ww8%*h`2;7R&*~(1$NY>4vkKUZRX<663qw_7Z%L&6qRPt$mBT`b3yJ{F6L6`h&LY_sL+(3Lrb@Y|6A5%BN#i^FuHSI7 zf&fy+(D?Nm3j+qJdKh~ZpPpy}4`!$*;avJdbVX6Zf(wdsT#9fH>aFE4n_=cmar5`@ z#9tsT#nex}kW8VgW(4KyoLmZ~8SWHfojvF&sP?iaKO7x$@x~*riVm>m8tB7JCA`?+ zV25&bf?es4pM)Xi^gX=t5vN5`==qZ5+@oan?AROe$bh}}%P+D|WKm;dILK_A&XQs} z_fv_yQkn&Bk~FV&ep0#J^ZA}YKRN^ib~V~h7y78`5t&3Xylk2&VhH-`zk?D|XHBC- z7rJa1%J8ujkIY4YiinNxtZ&I)@oCyTygS&WRGy(wFH6L&!@`;dWr4Bz(BCa;itQ-8 zWW$C$q!-lH*B?7JU&~rS0j^o&0k7ws>;FrhM?!Y~giZ#+owN zi7;y1Y1e~$$9sZ%?88Q_amtM8Yz+8`ekn%DHH}F}88Zk*PwBgNX(v4*253_Jcb|_$ zlzEWA5~;#HO}wvc`Y5#mZ{3v1x43gt&4)t}R%drVdNrOvn_SjJp#`BuK#K6Q&Cz=PNUG@>RD_k0HE36J>`=&5!f zY39<1eQ;-mQrpFk_f(VhZg-mUaIlo-u!@UlF8&QL&}pEir|&%-^7VISc4V~!R0{Up zwHYn;<7N=a0+mf0;0U^Z!6@y4j^l4Vo|1*-l|KFt^9b*WcvMTf$YTBkuuT+BvrC6$ zzL@4w)32iU=3~8{vKje{^F3iUJH@#^XJVnZ?2m~~Fjzdj*^TyfFAjS-?M-x{hhWTdpl_9_wVslxVvQQdT4j63;bt3e7F{wXg_bB$Tprxni;`p zP}>Wnf=$4E&S^SGO-+3qOYfAoD6oP>DG9s$tj$t~;I}QlHBRsNV2J;{DtQzFj@`(rMeVJFPppfO8mrJ@bcGxH~H(=E;D6Pb6|G)xp`I;g8eud z(7*mqK!4=Ks^zmTDEFUC{wqX@_4SRjVq(N=JYqU)G7{{ePw;^@92lE@vXtXG{$f|{ zOEY~;s-WL96*lbX>}*A>f^(h6#twDRVZ6<+LLYL9qRb19CM7EPvFje%Cw1SRWyJ!~ z+dm&>-*(HX(Y6*fQ}P+u%fPUJq5Vkkz!h=-ZSup}!~-Dzr{5F5Z9e6H`jlyXHSGah zrub;*v5S9j-_jCN11nC}d9SwX)+DuGCjNzwLAc+?riAy{uf4qs`$f23MWV0#jj|Z! zOCg;Q``5KQit*~VZO+<{weOiSUvyc#e}ap=kNqkTb|LzFSmPpKBfKb_IZ97Mrk0hA z;?r?0*s9uC5F}_1T`=s6mW7>r33YW?CBi8+$I)>~T5eK;4)MV>EU}^%G9>DC$IURW zDM1+`5hCiA{Tml)F&6LfSc~8O>k#bVDI7Swo55-x;j#ZMGZn@-m|{JcI2Gf+y3Twt!;tgr_7;5 z{-Ket=ELk8=vOhte$Dq@BZptl|I?Jv?39%Ny1N~VutrF=>CjX3r3q6o`4EW9QUn&G zuKpF{4}N+r=D3dD&pG^(DCdwhATcp zgwtSVGPa!I9cf`{nJa+h<*Maj7-&H+ur?Jmj5QdOe2S0`DOWD$8*t6wGbP=N zhVfV!)=fc-eX!xpn>U*I_qHF0iD%0??3qrDWKYL567R0`EY?3YT^{Y-u><0W^|iIu z5U7WwI;Zs)SR1HWG%ajbxW7X<&~B_9o1QtVHgZOUV`v2*+fqk(@^vxLXXJS?=R1!v zB|SP;87}Ut9zycGr!|d<-N!Mku4-mp$hp%IgM%>y&&q@1IZ4w|g?NlraO|-7{uSh_ zEYtP}JT?ekV-}$j$8YOssH6-Qp4u0t6CY@@^ay)8X2!-3{No{~SFMBX=!8l5C}LHyKLO$^ zM%j}obn2vsgGwFv-o(Qlg3bZF$0OxqRr`DJ&w{Kv7^{C^9oJ^OJ9TWbn64vH*Pe?>=N^Sxb-2{C~>qbM-ij*r14aNK?3;Zs(l;?_gjdi=B8t7 z8yCF}&usa6rk$)6@&Iz=qDTp1s-g!x2>g^6pvcb1~lJJLSxuyb%iz+pPYlAxMl@qKKl zGvAA$v(&HT9VZM$s`rP>u!eH97h}D2-+Fc3ZPDR_KlVQny*)v5Lh>MtPc&D{!gt5R ze%XRq1_CiuS&BHbk7qr|j?D7U&q66IaG!FNT#TQeACG?JKE=DPuAbd68j;Ixjoi&j zJegf3k(JmCe~G!)WIK+kr#wg9G~9H!Ix2`WXgefpssGk-P1s^4wcQ`0Qq?syyy6o| z9|vPMr@seO&KOkzSMcxJ&tOBApO0_9YKB6%$vtQodJ%_gcW2(kyPMcVDkbcD24K3B*YR96 za}4%7#uoUb(Rb6Uug3+JYGmHp8o2%Vo#rPkm?N!19ww)d+2l?XG+0a&mGM}E`^vI& z=i5(%j9VB;Q(_p64@xb;%%ZWYn1NO=5;jqu`xMV`^y3&r89Dk7*;+YRU}%n=;|RA7 zm-pH%ULDFXGpbMyvK{u#aCLP2_&t@C{t0QFQi=g%E%n;9*av_K`guhkmKf#K=ck|C z&}EQYCclZPMAtf_@>^cK5x2ACq@uC7^1>f*9{M;2x4c2xlCBJqyp9y3M%CQB^~`b# ztZ%!HD4cA+qIT?Vv!Z1CgMi7x5L>tcp-!NE&A!Ba#cvsuAO_Uzp&Hm60HdLjc2mNc zCN6$#%ewslO8Q51n^!wKO$d=>;3|^Tp0JT2()_zf^v4 z8j?kky$tk%b}F&ARGop!rt6JeCAuk>kC&ubd{gpIqZcn)gdisOTx^KJ zAEgxJ;>Lb_|K`PzZZ)Lmw04)KHGUa_KzUWL*Hbo6A%qVnH@5&h06z|Wm>g+-gS+sM zWXEk9)dLg!LJTJIsh7?vGRi-H6b&N^WgZRF^N^uH*V>|mz2iL+eox2J&cD7<=Umj+ zci9qqam-rWAWmQ{{i(aNv-25~FA+Y^mc?J%EK@%`!RlX;(`miLO<9py}_*tmzv1Ig=Gl#%Cc#F*f?{=*>luqlVu5&*@ox!BQ!z5w9jD?0ApGiM zJDtrC$z_Eiib*>7*1FG0x@E-5xQNbYcP~z4r>Lrsfwp2FGu=M?>M%D2#=6s{QS>j) z-u1f!L51!bS-C-(ub;QdyW1wNb%e7RY*%ynO)Lt+^v(U z$7+IXm;6@r(6iF|x|04nttLD&JS-=b!#_D#)}bpg@6(sA<5FLYwsu1u1zWCVOTvy` z*4$`28(!v;CG5q66Hz2EZ{33cflbg%oWDxk@u|si+?3dP^Qa*T5&T+*`yb^HRuit= zZI1g@+13P+%4^IB>Jd`p(s{H;Z#F83&PF#E|KrEb|JDSw-c(K~2@%crDn|htlq3op z5c~P>-`v-el8_KyB+Wr4-@V}en_%v(TSCxf{uXMxc>spkg{miicNM*K>l(#O;22S7 zzFsBV_U$3((fnYKYBqAG69u1!5=X*}QS{Ew>KWA=xr6JbW^o}lQ$9J8f&F;^`IQ!s z2mF}8QAVFLgt6d(rN&*K<8h{x8{0tc!MeYV_?8zYZL30v-h*i7$m=cmmkVOyId=i3 zZrY7Jpdmrk3#piH^JZSHJWmyl@fII7Nq^45i{C`)ZIhr3kT@<6Aqk_#tjcuHd-t|! zT*0Ll-TLOqaR+sE^&e*!%=sKbrh4;-WmoGg58B~ zO}-E^DRmVUL&(izEI4}}JCVaYLP+dgXPygTTh(w68(X6KJ7>r;mDMEssGZ+HvzsB9 zATwCr&|OWp`M3I#7<&|0fBp7t%PCW(*pa^iZERY7bzYixM^)mJ@4DUlIsV&gB@e16 zlHqJN5jgMHLBEYp%6>vh5`su>+;j@T`nh)PT0wz$%sK1Pg`&^v?^DMmlGnQlWdSe} z>lnD_7&Z>?;Yl_>N4UabGX{lYeUh$>ynGdY1+12{r!D;s?cAw}+F8#5IZ#MQNF~!s zwi0qVp;O1egu4e%Dkxt-Ed-WjGG{>Z#ZlYLk%hR1=K*(JO!nyctJ zs9J0(&j#g;ga&Qhx)p_t=cGjb+XrM{NrFK6kA6@{ zN43%)0z5bckoy7$5xc#`RaNqa(|tKq0goObx<++hPcMCV@GofmEc4lxT|*@ z9I)=J%OEo8^E@y9$&)8gx)GC<^!EDr@x)TmWYz#zH@9=BUE%Y%!*IW1!rx-Y2p=mj zE>jg=k!JKLXLJvdMWVRC(&XVox#j8Ui9$KoN=eD@!5wfiA)ccN;TR~agf=#QIzVeX zgcqkg<$YzGc;^u!@B#;FHKe9XBZ(AL)}A#vT$?@JJ5q*=MAWA!us&KD7<3T@#Ahi> ztgt@`3=EVLYJ-v3(`l#}o~@P0etD_f@xnAh(0<-d+a5f!mKMA`+3~SR2dFUZtsQ|_ z->xSVK}`?kedh;fJe+1!7nEQ$aqISSno|zUXCqFxWbfRyD>4=KlT1eKrY~JxS11dG ze?{U)Q1uMK$q5nCyL>s$s&oJqp8`G>E-5Klvt|uW zEPBP%omhZwSFdS>f82`N4EyP+U}2Z10V568Qih|g{zj%e_3*3v+SBtqtN1xmuLs>{ zw6k1XsqmSboNU~)x8k@TxUN`DKq^_8Ek6YxOvV!3$Tc}r%s07>8u*5Yl-Yk~*+Cw8 z5s^CvKE^*zEST4FS?rkG&BlD=%NrEp_BBr zx3>{yz-C|YWkELBT}aDxHdJWAf(2UR;L1g%fL)rO50x0hh74{dro7zTlS_fe%j{K7 ziSF`#@Zb>sFclTmE*=&Ryotz64CDKI5U_XNqL4=;>DO}jHJ$r9h6_B3Z}uyb5Rhf^ zJG8O1oCXnDp*<}v$v{AGPdDsSxC~hvJqJ872-8Hwnt|SmKpVP%?0Tiz;kd3)8eGT51oICM*!QQVDr3`1YqoO7aE^7aJ(u38jXF(YyK z6W%P~9&F;!^Gr{-hJ&6o*NQ6OeozY3oPPD{6{@Y7SCpR*MLs6ksEJN`D1?MfZH*Y@JmHic$0-rS5&KYS8`d%JV90X^F z_$y>^G<-L}QH%3ijg2p0q@#)c!g!;WP}@>eHwOQ#ZW`00Z1(Wbi&7*o4xcAWVEoVc z2|z0f(T4DuO?x;0ml`9$EaD@~D2J%j{u`>fgJ(c26UY@Cui^dB?rW5wap>OxP!W(o zUt^0{uQAIu#wh5(g*R|Zjb=Xtl}I#}&xUxf_Izwyg2R0IQSky|N9(`1$^uLVYXY#Q zwVBT%&PxPU_Ykis$`z1&0n4Bd3p7M9G4N_X%JC5(fWxS0Y--?CGg= z1A7pnMO-&N8Q#QcpnzsMy4Pqg&rl~sNbp!e|Nn7oDYYHMrm%^M%P-|r1nH$TA*Z!4 zpe!5N$;+FLSAr;r4E~@yD=RDEdk&SLr%VKEN)Wfndq_^8wYCYyc_f4B5tGK;^x6(;ygwmN zXzz8R8v?fg&=D=|gbQLW-X{bsK55Bax__;Y+{bOF!JM3jX4#QRS&aGRT+S*pu*7p6m zd(8VRE$FJYCVR{SN)zAAKd z8`av`xIzx-#4ZcPHid}s#N#CXG0PPsL5TDzS&g6)6GB@xd;No{>7WC(NjmF%!NY?t z8(0q22clb&h6Z3`mo%~tWGE{Qq{T&=2@`f=_EbbIe)G%c-&$0H%{()l#Hgg)pV@B8 zp>C^emdz*q=s=4Rl7&$Ls3k~XVK%*4XgY5u0&Ihz`F65J()Gv03p!$2lSazGrVQFH zTt;LrB5v?_~ybd;hn*Ccv{#|wU{i7c&K@)x0>L0OWz!B6Zdt;NIGzeV!I ziPNm%k^xMtSE0jqO9O>U`7q95-Y^CqVPRo;d9a9onmpU0)Nn%qHsU+#OQ3A!Wo0s% z>=PXzrqgnU(hz#34{VVkBU3uFU+(`gI*R?tp3m_)5eraVV|B~;-hW@AYXO}uZ9Oqe*P6VRx;+odaKT4SMl zyd*NC12NN8C_FkmENs!@#rf#jlvT5A6uY+>rKP30ZQ=F4OAkpsiGLK|2os5>77ZDe z9W6-hEiE|JuD8CSLe&~an5v)zalH?h+Yn$n=ri$Gxz+`Yi3%C=#XcdOwN*&abgCh0 z|4ou2JDG83`}_JVdNW7Ly%FeS%@tl;-cBz_-sMFEAkzCaQj$rDudgp?*tgMxqA$nv zt^zq_@7@!fOideUX z5E%4Q-ri`T(dF){#RF8qYy$_R%|dminx}(c=g(@sw=RuM;#xRaI3u5Bs=XxNrf9L55dTON--Dor3w^GfzKa5C?V&{0TJ2@t6@{<>SsD9f}JN z#i81T_OdCtN>!#43bP2j#ESA4WIaz(1^^@?-LT>QV^kwu7M(u~kb~%YY=+6T%H5kt zclm-7s4kBZ0*K`4EL$%&SC8*k%d#2jkj-J~$jt+agf9;KU{g0Cs!HHox_u~SP(39W zcUH1gD;lB?%#zj*YfCPgDcsAtQP)=m2|wh$`rIZ;BHi#qm8#u!MU^?lc^u7JYHC|s zTYT-HXMbr84scNHoL|H8H;-!0KAlrhU8Vlu`u>S`#K{_INzVQDVz_^~yGlC4p7T1g zCYx%H{*1y2RJ)}DyT+-YQF^a7hTnSlz}WCgiZ0IM+bcM*S4aVm93?fH>3fifT5D#O zdT%-s!$Tm$tTWIm7_pZ$)(nOpK%`dwJw%KX74= zPBtAIRl+!G`arA*gTB^a@G9r zbbl-fUqeo=GoPJ+FopJ9^m+SM2;#7K^_%(MkT)tR-2(YXkC+~tIuAV2*ghFhH{A$% zQ-M;Le^~V=(}M5h>VVGzX-4IoBOGOu_w_k(TaaS>UhjQcu9+HmTEh<)G zWAgfjL*>=gKnT6Yoi?3a~bk!<%H@D=5Rs@S?wG50V?3)#_gO!5jU4?Cy17ouC&o}Woh=j{c zbZ1IxV^n&X$RCIoxa<|ZX_!fkju2yMlXU@i3|mi`(wcuE6pPQxdRaHFk`~bszIXKK z-|Ma%Ie7LF$3S5;$un}jR?E7G&?k5Nv_%U}-;F&y@02g?{fo}WL<_>|P!--t*k(HV1%AU=+h~cefGwXwKLF_-UDN zcyb}Ue~6m&mvx0?{3~bBKyAm7VOlymI(mD9yuHmMC)5itsWP0}r2g%??Fi#r4Qu$tQJnBU4jH5ZSa8Yx1ph>o7e>p$IuS!=N`v zryA<&b#--0sh47k0z66Vbxs#BZ9aV9;-|-pTCmpsuwG-n1rZ!b>fGz zG85!?s~cx33B0Mh_9}uuR<7@JAWsL{96?zczAqLh43#N9)4dj8=IEaR`7~$LdTsHa+9`4_wZkMPj<_FROvRL(QZEglXBhOe>HPF}{RliYrgf!}{ zMJqNwPOe(-Y1K$4XgikV;P3%8ycRbnX9^Da%f%1maaDTT+jT)*Yi&J6C|bu>ZniT! zXSC<#76QLyue=rg$TP1Dz;nc;e(F{Nq#D8s_@i2eIh60V$ybGQmw8`oTBDFnLTMUl z6SZQ=k|m>5NOSV6=wQTDjg5_&_U?sg+cGKsAy2$~91qY80P{VTLuZo;zzpMkuaJi{ z0eMM!Bdn$C14OO{*Zw8@u`))vg7_dG%K$*OZ(-);tu0`A5WTp85{i6YY`V`=iEPR&Y6V#mXROjl0MH*k?SckyUwXqcsr{rGlQ%jmA) z)C+(AT7Z!IC)<{tGP~aj?W{tVqGEw@@e%75lhy+1;IeW_Q{KlbT9KD3%1}gqlriIs zu#UcQW4>aLpI_cBq#fmT0hL6*HV%F4`goM1t1F}eWg=o?9)juy=n=-&(koTLTB4z$8H(wPi#s4eixXE; zTr8!emmOspIWbI1c!uef#M5C?$?-}s$gTpG#}plPr`34LIdBV{{Qdotj7oyvfhFff zVo#>dT-Dst0)Gg;(~>|!lIg#e*H4G`vwlR6rBE-l7116~jzHIlf}v!o`3|1-1nFhp zzKp7y-d1)@mnPwbK<`8^=(s*1Dnq5 zuWMkdb6qk!_k@U@|C;M7og_syK-#LTXBDU zd_6tia)W4BqU+Mvx{EMtkGr!X=Cr9&ZN@P&81u^psCnJ;)d8>keF$#s?6j0(Z6mbD z1Pn+?C>*n;vM@$>IpuWIqRl7r`^Ewwf^^>#uFszq0t)bwu65LpTACTW@>5=e}CrA%!~}p7X8@F-43VK41mLACngS{&ENR*V{k0M>zWa6fLKnGw$ORz zU^dtyunSe@&~4XqS~j#Hljzzo*DiFC4C!`rE<&rH7hVal7;Xs|84C^+u;CBZOjgT& z!|3_mbezqou_C_c^p`JR5a5WLJT8)9n?pJJuV@b?9V^i_93bclD2z3Z64=j*9l;(l z`{K@&jKX9(1{qD0p3k~aiuY(5<;x5CqmMA8=G1_K_Pi6+vHt0Njr`?e`5#Y>(!!LuuY01R8h0o$L z8goFarDx26{4VHL?#8Gwp+DrVz}LFD1;38On?JMlXJs4oIc&5x0jlL}?b&{E;H>lL&q%#+dj~Ot6R^z7D0#MX@rsS$ zyY!XINL9qDWuufLidCg-L=}vR(_X%WF1o%NmCt(|3|yI^zP`_x7J*;IYu3^H^(&St ziR$~*O@e_W16l>>Ge`lxg3o)No03P?bL#PEPZHQA#B>alif`TBKrr`L9A;+D2e1jS zk|+?DT>rHc80^7jGN;LWT_mi7FaxqMa3qv9m|kmc-?1Y&De0{0vXv{bK2(WYCnF;R z%X$2Mld(Zv%ShZ^ygeKv+zTK^dV-~&b8{IvIn6QO!>gAN7gqsd4W}sh8DZ|RdnIP+ z)IdtXV<`0JB1WzgSIn-4Iu#`(9I6&lox~6tI87sv=3P8m@__2L9#nq|jx1O$@+vCP zFEMo5t{Vp$WKs8;UAM>rLS&#KvGj}fPlGM&Oe2p*tC>Q!{-l6xkw2FdZ-_^@a*BcU zn}Z1HF&Jj1N2{e7hl(>Po)8x=z|34i!mA}CgRkNR=yX=RD9i`ZD*>3Ukg1P-?oT{! z_7Y!Y5<_x5t`CoujLb~1O*oAjqO1Ob2@H_T&tGQ`*NeA>js_Q0$ro58cnKNgA$$_I^A+T-Rwr0V7YFR3=gi%%< z7>mHw&nkh;xM8cjyeU&Gtamy2OCpQL2(mR{RCRYNe-!OUF<@>$@wAZHuGKqA>d&Q! zMGKp1>*(Z%=K*hy3SYiq-@Wh-y*1~WejwiGT5*@j$eZrov!}CLH1&#{oVR&<3yN)o zGjpei+aD^{2Sia}(0jVGt-v?Lnr(+7FajLcja-)=DPe4OR5uP3)>cH4-+}>7RU4-5 z0E}<~fa~4&@xewt;7&0`K-V~FsfM-q$MK&(D}a;n=FPF8T0f{tq0GInosf%ubEr!b z?U>CO2^{{SB5!_BYl3*pPE`tie@hL!DEN0p^t})f4u=;dvp*MNU_8V@}%NH+*Fvf+D^m|RapXWBHN4Tns^K?--*x6+%(StYz3J%yWyxiPK zwNmMx#xwC;p_1$3r)~WF=j1@qY_}`U6urB(^f91YVA@x%UZq;KD(mdjLK8tjL5wWS z;=?1qb@ZHaD#EHjWD9ul&}=_Bj_Sd6E5DLc(buo)x(o!ftR1Mw%fgq@y*0_5*#3C? zHg2<~X3I_zKD^Lh6f`t(H%gOPCppSNH#la>1SXFajHBu~I`Z;LOG|Mi9z0l^IZUb2 z*%ObO>6*RELmM!AXmtqa#KN%ymxZN{T3YyPq;|LVI*t=ZqY09CwlYQmEhZTn1CiP80{I z4hvPjoP1ay^$Y%N{w;LJF_$bo|KZl{+mW~NqUAq76r`E>c5K%5wwM0WZ(?JGj<2GG z_N=L1oncvs1$QgFW(k!=ixz=#mLH^ICcLM2Ve1|UMQw4ByaYmGlGNPfyW{FBcNQH? z80OEPzty@c9%we+Rm1XmUzP-y)ldLToKApjLVI3K5_O!}`tY7zk1}ZfII{Q&|Lx4o zV%o-_C^!8357d4^;P1^CkUVaS#X!I6dAu&l++?QSgwf6=1|IHrH}brBg@uI?S`JuI>3=D7A^nYqx1A^V zALgqe2Ncrls^M$~R5$dfoZNrJp+rfFaGn3oi8*FkBGQ9H8BcgXMj;uK=r|s zp;!JiCAkwj_x{HyebqHD0P!|^uv84O2(KLdi=3H$w)DHwLi)hnFS&r3F!F4|W4i$tE$?oPYQBjyN@IqAL;Uv(uw zZV3f8{IB|rvue#~39}{Y%+8(r68XGGTtZ^k@!1adI)~=P+c=)+S;!~~rBm7jna6O2 z(*waW-#nxQmM&lJu?Q%|+mDvNi7@_oJ0+YYg{7rSZY*4mvRUZCqYrE6Alr}v)GnG8 zeuk-&fvoBLw&A%J)XaCVTuEtIJh3KunJnBl1CQ1g-t)(@>zaUyTO4Gvbllpx*!N5_ zoEir|Z!^~=&*?*IKr~90;`meAQIxLMZ0#s>@Xj9;SEJ9@PCy?{*$^bJZO(_HlTaHH z38u)wAtAPTxkW|VVZZ;(4L86TS({4G48XLJX5+?r9a+ScB@5CLGCo~!1XJsB`rw2@5?KFbP67Brx(#uwA~pqr8P=Y zWcZ+!CgN?&bc0&E=r`fT9X!2h4WMe6gVT)5QM0(yf!^*gJG&<{Pg;)?q5il@=s5{E z%OC4#HLj#`Z?vJGQTm~n8UOJEBmQqZ6cCu;v2p*wW5b*0=`TF~ZJ`G$nRzFLj-GW~ zXGLRSTxI4TXiYH|eye^w*rRsa;X}W1MuEZvmkGpcm*_6CJdTizKh@Qc>7To7-aK8d(4P%C3hm4hH#j{Bc8Z4`=F}<^RaXKfkyE z*Ks2J3z^bxCoIqYW6u0zIUy;@{fuPy>8*25X zneZ2%bG+{r&yKd;^1vwzjL^zX~TCqwVjYj_LzUv6Ala zr~3L#Al0$ZG6&xS?VhYZiU)DuL+@&9)6wptvp<8(VQk#r+s=aT|C2ZQGj52W3c9kl zL~%V?opI-vYqD%^y^P+dJghA(!9ExU^%KA4C0H9u^lR4KzjyC3Z4%lnV4r&v#KUix2h^%k(?zVvF18(2B zm!{mXr|q$lFx`6i@{y_bf{!0hccMQt6V?Gh0hS<*BG4D}t5mB@ zVFwYhAtcKl3D~|2B;g)KL97q^Ipt%R&kh6+ zU|?5zWcUv0Z^>CF`eUXKmg2>aW+QsfDk4Pjcn8^y!6Hgl{<+HN)OhdY!~{z3@I5@Y zNu-NLM!nd$<-_6-P)2YN4;f%?^8}3!v9BtDI_u__kH7J!nzbP{J^q$FbT~3(0;m#i z2dhHB0UWkkkz(y9pDCda90#ru(Gr_A2KBNFpz~nWxF%XL5#CuVYr*S(3tt8nqt9`# z^Yc5AH2(b#ID@7^>_2!XxjH$uV;X(CP#d#T?ShRI>M?~bMjpT>A24qI2#8V~W*=aI z;Jx9wdm9W{+wEIFb0=`KDR<&@t^qzE*sJIa@I_++gN_K3X)naZI4>XU@n;@9KWhRR zSHFS?f&j#CH4b=jVfyhOK=c3g6zaK!CMChJ>={U5e})iZh8Mq+5{WtK#4s>}Udf!p z;tWj`@?inaux}}aqZM2RL!D0_ru2JwPx8?BO4R7wz>z^3syygbo{+eLv$r z;>u};6oxe zcbis}%@1kk#hr`B7-2Kz$YYXz%F)p=0ze3`cus@QpHhv~XlQ&0%+ZfDfy>T=P8N_W zTKnz9FMJ&mB^*96(#lE`WZ6oE4pA7{gm|~a?}M^Wrc)8<$f_*h?21f1A!2OB7;v5u z94A0QK%9=7nJ+EL#TZ3&LqPwJ@8Kp=f?HfV|DHkdi8y)9nmVAy=nB}&vDjqsJE(C- zsrT#G9n+VzwYB9;d{zhWS@d1LT%y>+Q!Fs`;}f9u5X_p0LeqM6z_0PkBRxl9dDB4j z)l*MEy9`wlw43+=%1K^*y)91is$IlG#S=%D7uAXR96d7=Q^K8W3IM~&LVo0lttdnO z5j#1&@yH00kkcTzb@cE$?CG%skw@ZM19Tl%k zP+H%p!Xotb@Q-gbjV`e7QZ*|Jp$+rh<#0eYEK`7q%RDEWGtUe$@$viVwPexnnk3Rc zl4pFBkPh}OFaUV;=n*aZ#W>xv-O0H3!_>RQ@7)HnjS+Pq&|U1-2J^YOx?)#D#I&Id z&<^|d?L{K|MQ?;p`lmkSbxevXRWB=T%UxW;do@4mqSe_P_A>rkk zRjsWtE|^RfV19aE;>DgD^C{z&pM3n&*Gb|hPGAwQ2$ZQym@70r2cxecQAbKhCpq%o zaR)&!(Ump94RiHI%KqN@O_SC6U z_kMmugEOWm7=Fg_?cSKWx3#q?XFWp!EoWvFGp#KI&BDO{L)>@AW4-tPSEo~_J%p&J zB-v#Z!l^`&kv)orku6=wZjvO~B9y(Ak(CrBTbGd#a_n6~w%_w}X{dAG-{1H5*YEss zKkjqt;<`T9d%RxH^%CUOvJ*P@N`7>tWNzy%_if(+lzF!)w9Kq}_vO~GxkOUaIP|J(%J)b2lf^=HOWlQ zm9SSHYw^+GvE^uTAs@N$I?@FTw~aenFzNMv zit!l>yRK^I8?yNU9kI4IVn%1*ustY~sD2k*oUMMJt=gQ$xk+F&i5y(ZLu2c0@-AU% z?yJ@N$+j14+?|`^&378yx4)DwKQ=b@p-$$tR%?LDcuZ$1=|7*5i&SmS#p`)xa}S?D;oO|5#qQRm4yD z?BNF<9{w6)T?2IypSyD26(8!W{c=J&G`j2JYT@u`JDo2Zn4BHQy4GF0uE}Tm;jvNO z+AK}p2!}Hd^J3eiE@)}F0|xqB+mUP0-M9a?Od_8~PMUEY*Dj6(Wi7|f*=uXO@)V4t z3~Lyo);^*(GOUb}DCyo1nQOdfz`B3hypFaHF_Pz{Nblm5jmiRALyeCOH15}M9%7t3 z$XRgKaqAkFg5kT$2kw`b@tN#4D%C52G)601$91SHSJu{C(*Hxc?Cyv=9QSkZOYvDh~teENzm#y%pcRnd2-qd$uq8 zbk2J9JqH19>s@d(e_dkT-s2gr$w3|Fm;XPSAbss@X5v(Jl6u>~n2H z8lGYks+6kEc3nwLy;PFF9|E5=l~%_ieVF=r}t&D=IeK=EIR(VXwOOGd`j_gKERnq^&j9 z$9R!mli3t~5}t9t)R=e3KDi<3>L|m6PwO?FM2#66M%-ce-2LQ~Ix-6#Z)%@*nw?Nf zx1TJtGDz*I_NBfXPEJnJeE(!6OX~gmdV7S}ITRs&X%d)ABI~6yyV9A4jeZI-tQpX{ z*%KQM2o>SfrWiYxg-6P}MS~{_7bDSq5REl1+?d?}TGMn(X@u7YqgFVqq0xY$4>qee zzdir)ML?)oh*?!cs}uLkKzui&KDVz2-J82+%4_a!ZQ3cfznvrX6v@zpX3ijrm7Hb& z`c(ZZoJ8>|izPCBUIRy#4tlH0=TsSm+F-5CVSxonf)xhBzCjB;x(W;wnIql4t zZIzt7>4QsmO(5EbFvV!|^kF5{LW3{!-5)(VH0(vvJl(Hn7u@XAPHBa_+lK7AVCqb$@MXNYMGuOW5CRyD+<7sN6aszu36=M73YJ zj{ynK=;^1^=g*$A4eAz6e&x4LJ>2wUe&hxy# zLl_QZlI4*$lpE&+q#VAIP)#fqqY_cCV zER5619nBc>S-W*J6&>ARPtWHnX}KUkSNem>cqU2N&xgI DmlseW@`11G6j5>3e- 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

    US2 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 actor "Admin\n(5/8 Safe)" as admin <> +actor "Strategist\n(2/9 Safe)" as strategist <> actor "Governor\n(Timelock)" as gov <> actor "Treasury" as treasury <> participant "API" as api <> @@ -306,4 +307,24 @@ return end group + +group Strategist pauses Native Staking Strategy + +strategist -> nativeStrat : pause() +activate nativeStrat +return + +end group + +group Strategist unpauses Native Staking Strategy + +strategist -> nativeStrat : manuallyFixAccounting(0, 0, 0) +activate nativeStrat +note right : params _validatorsDelta, _consensusRewardsDelta\nand _ethToVaultAmount all set to zero +nativeStrat -> nativeStrat +note right : unpause +return + +end group + @enduml \ No newline at end of file From 270a3f6bc0d52cd26dafe79618f0b638e02ce868 Mon Sep 17 00:00:00 2001 From: Nick Addison Date: Sun, 2 Jun 2024 15:27:36 +1000 Subject: [PATCH 114/273] Removed the redundant condition in the fuse interval check (#2082) --- .../contracts/strategies/NativeStaking/ValidatorAccountant.sol | 1 - 1 file changed, 1 deletion(-) diff --git a/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol b/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol index 02d5b42500..441d046ad2 100644 --- a/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol +++ b/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol @@ -71,7 +71,6 @@ abstract contract ValidatorAccountant is ValidatorRegistrator { ) external onlyGovernor { require( _fuseIntervalStart < _fuseIntervalEnd && - _fuseIntervalStart < 32 ether && _fuseIntervalEnd < 32 ether && _fuseIntervalEnd - _fuseIntervalStart >= 4 ether, "incorrect fuse interval" From 706da2e60cafd51854b3cfcf63858049b10510f7 Mon Sep 17 00:00:00 2001 From: Nick Addison Date: Sun, 2 Jun 2024 15:40:33 +1000 Subject: [PATCH 115/273] OZ - Native Staking - M-01 All Addresses Are Registered Validators by Default (#2081) * Added default NON_REGISTERED to VALIDATOR_STATE * Added explicit check that a validator has not already been registered * Added new Holesky deploy script --- .../NativeStaking/ValidatorRegistrator.sol | 9 +++ .../deploy/holesky/010_upgrade_strategy.js | 1 - .../deploy/holesky/011_upgrade_strategy.js | 18 ++++++ contracts/test/behaviour/ssvStrategy.js | 25 ++++++-- contracts/test/strategies/nativeSSVStaking.js | 63 ++++++++++++++++--- 5 files changed, 102 insertions(+), 14 deletions(-) create mode 100644 contracts/deploy/holesky/011_upgrade_strategy.js diff --git a/contracts/contracts/strategies/NativeStaking/ValidatorRegistrator.sol b/contracts/contracts/strategies/NativeStaking/ValidatorRegistrator.sol index 219ebfb45e..9a407261e0 100644 --- a/contracts/contracts/strategies/NativeStaking/ValidatorRegistrator.sol +++ b/contracts/contracts/strategies/NativeStaking/ValidatorRegistrator.sol @@ -48,6 +48,7 @@ abstract contract ValidatorRegistrator is Governable, Pausable { uint256[47] private __gap; enum VALIDATOR_STATE { + NON_REGISTERED, // validator is not registered on the SSV network REGISTERED, // validator is registered on the SSV network STAKED, // validator has funds staked EXITING, // exit message has been posted and validator is in the process of exiting @@ -207,6 +208,7 @@ abstract contract ValidatorRegistrator is Governable, Pausable { /// @notice Registers a new validator in the SSV Cluster. /// Only the registrator can call this function. + // slither-disable-start reentrancy-no-eth function registerSsvValidator( bytes calldata publicKey, uint64[] calldata operatorIds, @@ -214,6 +216,11 @@ abstract contract ValidatorRegistrator is Governable, Pausable { uint256 amount, Cluster calldata cluster ) external onlyRegistrator whenNotPaused { + require( + validatorsStates[keccak256(publicKey)] == + VALIDATOR_STATE.NON_REGISTERED, + "Validator already registered" + ); ISSVNetwork(SSV_NETWORK_ADDRESS).registerValidator( publicKey, operatorIds, @@ -225,6 +232,8 @@ abstract contract ValidatorRegistrator is Governable, Pausable { emit SSVValidatorRegistered(publicKey, operatorIds); } + // slither-disable-end reentrancy-no-eth + /// @notice Exit a validator from the Beacon chain. /// The staked ETH will eventually swept to this native staking strategy. /// Only the registrator can call this function. diff --git a/contracts/deploy/holesky/010_upgrade_strategy.js b/contracts/deploy/holesky/010_upgrade_strategy.js index a073a9d2b1..89f152e13e 100644 --- a/contracts/deploy/holesky/010_upgrade_strategy.js +++ b/contracts/deploy/holesky/010_upgrade_strategy.js @@ -3,7 +3,6 @@ const { withConfirmation } = require("../../utils/deploy"); const { resolveContract } = require("../../utils/resolvers"); const addresses = require("../../utils/addresses"); const { parseEther } = require("ethers/lib/utils"); -// const { impersonateAndFund } = require("../../utils/signers.js"); const mainExport = async () => { console.log("Running 010 deployment on Holesky..."); diff --git a/contracts/deploy/holesky/011_upgrade_strategy.js b/contracts/deploy/holesky/011_upgrade_strategy.js new file mode 100644 index 0000000000..1dc95a7268 --- /dev/null +++ b/contracts/deploy/holesky/011_upgrade_strategy.js @@ -0,0 +1,18 @@ +const { upgradeNativeStakingSSVStrategy } = require("../deployActions"); + +const mainExport = async () => { + console.log("Running 011 deployment on Holesky..."); + + console.log("Upgrading native staking strategy"); + await upgradeNativeStakingSSVStrategy(); + + console.log("Running 011 deployment done"); + return true; +}; + +mainExport.id = "011_upgrade_strategy"; +mainExport.tags = []; +mainExport.dependencies = []; +mainExport.skip = () => false; + +module.exports = mainExport; diff --git a/contracts/test/behaviour/ssvStrategy.js b/contracts/test/behaviour/ssvStrategy.js index afd756915e..0a86594136 100644 --- a/contracts/test/behaviour/ssvStrategy.js +++ b/contracts/test/behaviour/ssvStrategy.js @@ -9,7 +9,7 @@ const hre = require("hardhat"); const { oethUnits } = require("../helpers"); const { impersonateAndFund } = require("../../utils/signers"); const { getClusterInfo } = require("../../utils/ssv"); -const { parseEther } = require("ethers/lib/utils"); +const { parseEther, keccak256 } = require("ethers/lib/utils"); const { setERC20TokenBalance } = require("../_fund"); /** @@ -181,6 +181,12 @@ const shouldBehaveLikeAnSsvStrategy = (context) => { const stakeAmount = oethUnits("32"); + expect( + await nativeStakingSSVStrategy.validatorsStates( + keccak256(testValidator.publicKey) + ) + ).to.equal(0, "Validator state not 0 (NON_REGISTERED)"); + // Register a new validator with the SSV Network const regTx = await nativeStakingSSVStrategy .connect(validatorRegistrator) @@ -195,6 +201,12 @@ const shouldBehaveLikeAnSsvStrategy = (context) => { .to.emit(nativeStakingSSVStrategy, "SSVValidatorRegistered") .withArgs(testValidator.publicKey, testValidator.operatorIds); + expect( + await nativeStakingSSVStrategy.validatorsStates( + keccak256(testValidator.publicKey) + ) + ).to.equal(1, "Validator state not 1 (REGISTERED)"); + // Stake stakeAmount ETH to the new validator const stakeTx = await nativeStakingSSVStrategy .connect(validatorRegistrator) @@ -213,6 +225,12 @@ const shouldBehaveLikeAnSsvStrategy = (context) => { amount: oethUnits("32"), }); + expect( + await nativeStakingSSVStrategy.validatorsStates( + keccak256(testValidator.publicKey) + ) + ).to.equal(2, "Validator state not 2 (STAKED)"); + expect(await weth.balanceOf(nativeStakingSSVStrategy.address)).to.equal( strategyWethBalanceBefore.sub( stakeAmount, @@ -283,10 +301,7 @@ const shouldBehaveLikeAnSsvStrategy = (context) => { emptyCluster ); - // Waffle's custom error matcher is not working here. - // Checking the trace, the error thrown is ValidatorAlreadyExistsWithData - // which is what we expect. - await expect(tx2).to.be.reverted; + await expect(tx2).to.be.revertedWith("Validator already registered"); }); it("Should emit correct values in deposit event", async () => { diff --git a/contracts/test/strategies/nativeSSVStaking.js b/contracts/test/strategies/nativeSSVStaking.js index 26ac2fa84a..9a116a1fe4 100644 --- a/contracts/test/strategies/nativeSSVStaking.js +++ b/contracts/test/strategies/nativeSSVStaking.js @@ -1,6 +1,6 @@ const { expect } = require("chai"); const { BigNumber } = require("ethers"); -const { parseEther } = require("ethers").utils; +const { keccak256, parseEther } = require("ethers").utils; const { setBalance, setStorageAt, @@ -37,6 +37,14 @@ const testValidator = { depositDataRoot: "0xdbe778a625c68446f3cc8b2009753a5e7dd7c37b8721ee98a796bb9179dfe8ac", }; +const testPublicKeys = [ + "0xaba6acd335d524a89fb89b9977584afdb23f34a6742547fa9ec1c656fbd2bfc0e7a234460328c2731828c9a43be06e25", + "0xa8adaec39a6738b09053a3ed9d44e481d5b2dfafefe0059da48756db951adf4f2956c1149f3bd0634e4cde009a770afb", + "0xaa8cdeb9efe0cb2f703332a46051214464796e7de7b882abd243c175b2d96250ad227846f713876445f864b2e2f695c1", + "0xb22b68e2a4f524e96c7818dbfca3de0f7fb4e87449fe8166fd310bea3e3e4295db41b21e65612d1d4bd8a14f2d47e49a", + "0x92fe1f554b8110fa5c74af8181ca2afaad12f6d22cad933ef1978b5d4d099d75045e4d6d15066c290aee29990858cb90", + "0xb27b34f6931ba70a11c2ba82f194e9b98093a5a482bb035a836df9aa4b5f57542354da453538b651c18eefc0ea3a7689", +]; const emptyCluster = [ 0, // validatorCount @@ -1064,30 +1072,46 @@ describe("Unit test: Native SSV Staking Strategy", function () { .setStakeETHThreshold(stakeThreshold); }); - const stakeValidator = async (validators, stakeTresholdErrorTriggered) => { + const stakeValidator = async ( + validators, + stakeTresholdErrorTriggered, + startingIndex = 0 + ) => { const { nativeStakingSSVStrategy, validatorRegistrator } = fixture; // there is a limitation to this function as it will only check for // a failure transaction with the last stake call - for (let i = 0; i < validators; i++) { + for (let i = startingIndex; i < validators; i++) { + expect( + await nativeStakingSSVStrategy.validatorsStates( + keccak256(testPublicKeys[i]) + ) + ).to.equal(0, "Validator state not 0 (NON_REGISTERED)"); + const stakeAmount = ethUnits("32"); // Register a new validator with the SSV Network await nativeStakingSSVStrategy .connect(validatorRegistrator) .registerSsvValidator( - testValidator.publicKey, + testPublicKeys[i], testValidator.operatorIds, testValidator.sharesData, stakeAmount, emptyCluster ); + expect( + await nativeStakingSSVStrategy.validatorsStates( + keccak256(testPublicKeys[i]) + ) + ).to.equal(1, "Validator state not 1 (REGISTERED)"); + // Stake ETH to the new validator const tx = nativeStakingSSVStrategy .connect(validatorRegistrator) .stakeEth([ { - pubkey: testValidator.publicKey, + pubkey: testPublicKeys[i], signature: testValidator.signature, depositDataRoot: testValidator.depositDataRoot, }, @@ -1097,6 +1121,12 @@ describe("Unit test: Native SSV Staking Strategy", function () { await expect(tx).to.be.revertedWith("Staking ETH over threshold"); } else { await tx; + + expect( + await nativeStakingSSVStrategy.validatorsStates( + keccak256(testPublicKeys[i]) + ) + ).to.equal(2, "Validator state not 2 (STAKED)"); } } }; @@ -1113,6 +1143,23 @@ describe("Unit test: Native SSV Staking Strategy", function () { await stakeValidator(3, true); }); + it("Fail to stake a validator that hasn't been registered", async () => { + const { nativeStakingSSVStrategy, validatorRegistrator } = fixture; + + // Stake ETH to the unregistered validator + const tx = nativeStakingSSVStrategy + .connect(validatorRegistrator) + .stakeEth([ + { + pubkey: testValidator.publicKey, + signature: testValidator.signature, + depositDataRoot: testValidator.depositDataRoot, + }, + ]); + + await expect(tx).to.be.revertedWith("Validator not registered"); + }); + it("Should stake to 2 validators continually when threshold is reset", async () => { const { anna, nativeStakingSSVStrategy } = fixture; @@ -1120,11 +1167,11 @@ describe("Unit test: Native SSV Staking Strategy", function () { await nativeStakingSSVStrategy.connect(anna).resetStakeETHTally(); }; - await stakeValidator(2, false); + await stakeValidator(2, false, 0); await resetThreshold(); - await stakeValidator(2, false); + await stakeValidator(2, false, 2); await resetThreshold(); - await stakeValidator(2, false); + await stakeValidator(2, false, 4); await resetThreshold(); }); From 71adea71aec1f9106931ad860f1286955dab5fa1 Mon Sep 17 00:00:00 2001 From: Nick Addison Date: Sun, 2 Jun 2024 16:21:25 +1000 Subject: [PATCH 116/273] OZ - Native Staking - N-07 Lack of Indexed Event Parameters (#2083) * Indexed the RegistratorChanged and StakingMonitorChanged events * Added indexed pubKeyHash to validator events --- .../NativeStaking/ValidatorRegistrator.sol | 59 +++++++++++++------ contracts/test/behaviour/ssvStrategy.js | 21 +++++-- contracts/test/strategies/nativeSSVStaking.js | 26 ++++++-- 3 files changed, 79 insertions(+), 27 deletions(-) diff --git a/contracts/contracts/strategies/NativeStaking/ValidatorRegistrator.sol b/contracts/contracts/strategies/NativeStaking/ValidatorRegistrator.sol index 9a407261e0..9b6455e012 100644 --- a/contracts/contracts/strategies/NativeStaking/ValidatorRegistrator.sol +++ b/contracts/contracts/strategies/NativeStaking/ValidatorRegistrator.sol @@ -55,12 +55,29 @@ abstract contract ValidatorRegistrator is Governable, Pausable { EXIT_COMPLETE // validator has funds withdrawn to the EigenPod and is removed from the SSV } - event RegistratorChanged(address newAddress); - event StakingMonitorChanged(address newAddress); - event ETHStaked(bytes pubkey, uint256 amount, bytes withdrawal_credentials); - event SSVValidatorRegistered(bytes pubkey, uint64[] operatorIds); - event SSVValidatorExitInitiated(bytes pubkey, uint64[] operatorIds); - event SSVValidatorExitCompleted(bytes pubkey, uint64[] operatorIds); + event RegistratorChanged(address indexed newAddress); + event StakingMonitorChanged(address indexed newAddress); + event ETHStaked( + bytes32 indexed pubKeyHash, + bytes pubKey, + uint256 amount, + bytes withdrawal_credentials + ); + event SSVValidatorRegistered( + bytes32 indexed pubKeyHash, + bytes pubKey, + uint64[] operatorIds + ); + event SSVValidatorExitInitiated( + bytes32 indexed pubKeyHash, + bytes pubKey, + uint64[] operatorIds + ); + event SSVValidatorExitCompleted( + bytes32 indexed pubKeyHash, + bytes pubKey, + uint64[] operatorIds + ); event StakeETHThresholdChanged(uint256 amount); event StakeETHTallyReset(); @@ -171,8 +188,8 @@ abstract contract ValidatorRegistrator is Governable, Pausable { uint256 validatorsLength = validators.length; // For each validator for (uint256 i = 0; i < validatorsLength; ) { - bytes32 pubkeyHash = keccak256(validators[i].pubkey); - VALIDATOR_STATE currentState = validatorsStates[pubkeyHash]; + bytes32 pubKeyHash = keccak256(validators[i].pubkey); + VALIDATOR_STATE currentState = validatorsStates[pubKeyHash]; require( currentState == VALIDATOR_STATE.REGISTERED, @@ -189,12 +206,13 @@ abstract contract ValidatorRegistrator is Governable, Pausable { ); emit ETHStaked( + pubKeyHash, validators[i].pubkey, 32 ether, withdrawal_credentials ); - validatorsStates[pubkeyHash] = VALIDATOR_STATE.STAKED; + validatorsStates[pubKeyHash] = VALIDATOR_STATE.STAKED; unchecked { ++i; @@ -216,9 +234,9 @@ abstract contract ValidatorRegistrator is Governable, Pausable { uint256 amount, Cluster calldata cluster ) external onlyRegistrator whenNotPaused { + bytes32 pubKeyHash = keccak256(publicKey); require( - validatorsStates[keccak256(publicKey)] == - VALIDATOR_STATE.NON_REGISTERED, + validatorsStates[pubKeyHash] == VALIDATOR_STATE.NON_REGISTERED, "Validator already registered" ); ISSVNetwork(SSV_NETWORK_ADDRESS).registerValidator( @@ -228,8 +246,9 @@ abstract contract ValidatorRegistrator is Governable, Pausable { amount, cluster ); - validatorsStates[keccak256(publicKey)] = VALIDATOR_STATE.REGISTERED; - emit SSVValidatorRegistered(publicKey, operatorIds); + emit SSVValidatorRegistered(pubKeyHash, publicKey, operatorIds); + + validatorsStates[pubKeyHash] = VALIDATOR_STATE.REGISTERED; } // slither-disable-end reentrancy-no-eth @@ -242,13 +261,14 @@ abstract contract ValidatorRegistrator is Governable, Pausable { bytes calldata publicKey, uint64[] calldata operatorIds ) external onlyRegistrator whenNotPaused { - VALIDATOR_STATE currentState = validatorsStates[keccak256(publicKey)]; + bytes32 pubKeyHash = keccak256(publicKey); + VALIDATOR_STATE currentState = validatorsStates[pubKeyHash]; require(currentState == VALIDATOR_STATE.STAKED, "Validator not staked"); ISSVNetwork(SSV_NETWORK_ADDRESS).exitValidator(publicKey, operatorIds); - emit SSVValidatorExitInitiated(publicKey, operatorIds); + emit SSVValidatorExitInitiated(pubKeyHash, publicKey, operatorIds); - validatorsStates[keccak256(publicKey)] = VALIDATOR_STATE.EXITING; + validatorsStates[pubKeyHash] = VALIDATOR_STATE.EXITING; } // slither-disable-end reentrancy-no-eth @@ -263,7 +283,8 @@ abstract contract ValidatorRegistrator is Governable, Pausable { uint64[] calldata operatorIds, Cluster calldata cluster ) external onlyRegistrator whenNotPaused { - VALIDATOR_STATE currentState = validatorsStates[keccak256(publicKey)]; + bytes32 pubKeyHash = keccak256(publicKey); + VALIDATOR_STATE currentState = validatorsStates[pubKeyHash]; require( currentState == VALIDATOR_STATE.EXITING, "Validator not exiting" @@ -274,9 +295,9 @@ abstract contract ValidatorRegistrator is Governable, Pausable { operatorIds, cluster ); - emit SSVValidatorExitCompleted(publicKey, operatorIds); + emit SSVValidatorExitCompleted(pubKeyHash, publicKey, operatorIds); - validatorsStates[keccak256(publicKey)] = VALIDATOR_STATE.EXIT_COMPLETE; + validatorsStates[pubKeyHash] = VALIDATOR_STATE.EXIT_COMPLETE; } // slither-disable-end reentrancy-no-eth diff --git a/contracts/test/behaviour/ssvStrategy.js b/contracts/test/behaviour/ssvStrategy.js index 0a86594136..b748c0fdfc 100644 --- a/contracts/test/behaviour/ssvStrategy.js +++ b/contracts/test/behaviour/ssvStrategy.js @@ -199,7 +199,11 @@ const shouldBehaveLikeAnSsvStrategy = (context) => { ); await expect(regTx) .to.emit(nativeStakingSSVStrategy, "SSVValidatorRegistered") - .withArgs(testValidator.publicKey, testValidator.operatorIds); + .withArgs( + keccak256(testValidator.publicKey), + testValidator.publicKey, + testValidator.operatorIds + ); expect( await nativeStakingSSVStrategy.validatorsStates( @@ -221,7 +225,8 @@ const shouldBehaveLikeAnSsvStrategy = (context) => { await expect(stakeTx) .to.emit(nativeStakingSSVStrategy, "ETHStaked") .withNamedArgs({ - pubkey: testValidator.publicKey, + pubKeyHash: keccak256(testValidator.publicKey), + pubKey: testValidator.publicKey, amount: oethUnits("32"), }); @@ -397,7 +402,11 @@ const shouldBehaveLikeAnSsvStrategy = (context) => { await expect(exitTx) .to.emit(nativeStakingSSVStrategy, "SSVValidatorExitInitiated") - .withArgs(testValidator.publicKey, testValidator.operatorIds); + .withArgs( + keccak256(testValidator.publicKey), + testValidator.publicKey, + testValidator.operatorIds + ); const removeTx = await nativeStakingSSVStrategy .connect(validatorRegistrator) @@ -409,7 +418,11 @@ const shouldBehaveLikeAnSsvStrategy = (context) => { await expect(removeTx) .to.emit(nativeStakingSSVStrategy, "SSVValidatorExitCompleted") - .withArgs(testValidator.publicKey, testValidator.operatorIds); + .withArgs( + keccak256(testValidator.publicKey), + testValidator.publicKey, + testValidator.operatorIds + ); }); }); diff --git a/contracts/test/strategies/nativeSSVStaking.js b/contracts/test/strategies/nativeSSVStaking.js index 9a116a1fe4..382419ebc2 100644 --- a/contracts/test/strategies/nativeSSVStaking.js +++ b/contracts/test/strategies/nativeSSVStaking.js @@ -1090,7 +1090,7 @@ describe("Unit test: Native SSV Staking Strategy", function () { const stakeAmount = ethUnits("32"); // Register a new validator with the SSV Network - await nativeStakingSSVStrategy + const regTx = await nativeStakingSSVStrategy .connect(validatorRegistrator) .registerSsvValidator( testPublicKeys[i], @@ -1100,6 +1100,14 @@ describe("Unit test: Native SSV Staking Strategy", function () { emptyCluster ); + await expect(regTx) + .to.emit(nativeStakingSSVStrategy, "SSVValidatorRegistered") + .withArgs( + keccak256(testPublicKeys[i]), + testPublicKeys[i], + testValidator.operatorIds + ); + expect( await nativeStakingSSVStrategy.validatorsStates( keccak256(testPublicKeys[i]) @@ -1107,7 +1115,7 @@ describe("Unit test: Native SSV Staking Strategy", function () { ).to.equal(1, "Validator state not 1 (REGISTERED)"); // Stake ETH to the new validator - const tx = nativeStakingSSVStrategy + const stakeTx = nativeStakingSSVStrategy .connect(validatorRegistrator) .stakeEth([ { @@ -1118,9 +1126,19 @@ describe("Unit test: Native SSV Staking Strategy", function () { ]); if (stakeTresholdErrorTriggered && i == validators - 1) { - await expect(tx).to.be.revertedWith("Staking ETH over threshold"); + await expect(stakeTx).to.be.revertedWith( + "Staking ETH over threshold" + ); } else { - await tx; + await stakeTx; + + await expect(stakeTx) + .to.emit(nativeStakingSSVStrategy, "ETHStaked") + .withNamedArgs({ + pubKeyHash: keccak256(testPublicKeys[i]), + pubKey: testPublicKeys[i], + amount: parseEther("32"), + }); expect( await nativeStakingSSVStrategy.validatorsStates( From 8f8118d2a906f44a48a8d251217a70b3538b1626 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Sun, 2 Jun 2024 16:39:15 +1000 Subject: [PATCH 117/273] Deployed new Native Staking Strategy --- .../deployments/holesky/.migrations.json | 3 +- .../holesky/NativeStakingSSVStrategy.json | 140 ++-- .../2f3753d8399260cc3346b6a657c1cb6c.json | 689 ++++++++++++++++++ 3 files changed, 773 insertions(+), 59 deletions(-) create mode 100644 contracts/deployments/holesky/solcInputs/2f3753d8399260cc3346b6a657c1cb6c.json diff --git a/contracts/deployments/holesky/.migrations.json b/contracts/deployments/holesky/.migrations.json index f9a0e00a78..662b06449b 100644 --- a/contracts/deployments/holesky/.migrations.json +++ b/contracts/deployments/holesky/.migrations.json @@ -8,5 +8,6 @@ "007_upgrade_strategy": 1715251466, "008_upgrade_strategy": 1715341541, "009_upgrade_strategy": 1716360052, - "010_upgrade_strategy": 1716890877 + "010_upgrade_strategy": 1716890877, + "011_upgrade_strategy": 1717309951 } \ No newline at end of file diff --git a/contracts/deployments/holesky/NativeStakingSSVStrategy.json b/contracts/deployments/holesky/NativeStakingSSVStrategy.json index 4600085e5f..a188d99206 100644 --- a/contracts/deployments/holesky/NativeStakingSSVStrategy.json +++ b/contracts/deployments/holesky/NativeStakingSSVStrategy.json @@ -1,5 +1,5 @@ { - "address": "0x0D875FD10401F57e117bd53f82411c706247AD4f", + "address": "0x66629294466DaD7173c44c813F89deC17226BB18", "abi": [ { "inputs": [ @@ -159,10 +159,16 @@ { "anonymous": false, "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "pubKeyHash", + "type": "bytes32" + }, { "indexed": false, "internalType": "bytes", - "name": "pubkey", + "name": "pubKey", "type": "bytes" }, { @@ -312,7 +318,7 @@ "anonymous": false, "inputs": [ { - "indexed": false, + "indexed": true, "internalType": "address", "name": "newAddress", "type": "address" @@ -368,10 +374,16 @@ { "anonymous": false, "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "pubKeyHash", + "type": "bytes32" + }, { "indexed": false, "internalType": "bytes", - "name": "pubkey", + "name": "pubKey", "type": "bytes" }, { @@ -387,10 +399,16 @@ { "anonymous": false, "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "pubKeyHash", + "type": "bytes32" + }, { "indexed": false, "internalType": "bytes", - "name": "pubkey", + "name": "pubKey", "type": "bytes" }, { @@ -406,10 +424,16 @@ { "anonymous": false, "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "pubKeyHash", + "type": "bytes32" + }, { "indexed": false, "internalType": "bytes", - "name": "pubkey", + "name": "pubKey", "type": "bytes" }, { @@ -445,7 +469,7 @@ "anonymous": false, "inputs": [ { - "indexed": false, + "indexed": true, "internalType": "address", "name": "newAddress", "type": "address" @@ -1419,34 +1443,34 @@ "type": "receive" } ], - "transactionHash": "0x065cc099e02ada3882563847d84334b70335d2c03ef455ffb1710506b00a329c", + "transactionHash": "0xf97b37d50f68cd13725be2f6e3ac057240fb6a8f3df3c13829286aa39b713e38", "receipt": { "to": null, "from": "0x1b94CA50D3Ad9f8368851F8526132272d1a5028C", - "contractAddress": "0x0D875FD10401F57e117bd53f82411c706247AD4f", - "transactionIndex": 130, - "gasUsed": "4375470", - "logsBloom": "0x00000000000000000002000000000000000000000000000000000000000000000000000000000000000000040000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000000004000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000018000000000010000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000", - "blockHash": "0xb813c87a79b54dfd4eeb9cebc658d24eb347d0b2e94ec4f40934550ef9e6681b", - "transactionHash": "0x065cc099e02ada3882563847d84334b70335d2c03ef455ffb1710506b00a329c", + "contractAddress": "0x66629294466DaD7173c44c813F89deC17226BB18", + "transactionIndex": 99, + "gasUsed": "4363797", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000000004000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000010000000000010000000000000000000000000000000000000000020000400000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x8054d9658e27d7ec653db16ec011178c1bebe788407cbbc36b0ea2168187dad6", + "transactionHash": "0xf97b37d50f68cd13725be2f6e3ac057240fb6a8f3df3c13829286aa39b713e38", "logs": [ { - "transactionIndex": 130, - "blockNumber": 1626892, - "transactionHash": "0x065cc099e02ada3882563847d84334b70335d2c03ef455ffb1710506b00a329c", - "address": "0x0D875FD10401F57e117bd53f82411c706247AD4f", + "transactionIndex": 99, + "blockNumber": 1656029, + "transactionHash": "0xf97b37d50f68cd13725be2f6e3ac057240fb6a8f3df3c13829286aa39b713e38", + "address": "0x66629294466DaD7173c44c813F89deC17226BB18", "topics": [ "0xc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000001b94ca50d3ad9f8368851f8526132272d1a5028c" ], "data": "0x", - "logIndex": 209, - "blockHash": "0xb813c87a79b54dfd4eeb9cebc658d24eb347d0b2e94ec4f40934550ef9e6681b" + "logIndex": 191, + "blockHash": "0x8054d9658e27d7ec653db16ec011178c1bebe788407cbbc36b0ea2168187dad6" } ], - "blockNumber": 1626892, - "cumulativeGasUsed": "13590958", + "blockNumber": 1656029, + "cumulativeGasUsed": "18040571", "status": 1, "byzantium": true }, @@ -1461,11 +1485,11 @@ "0x65a289f4BF934c964C942eFF6E6F83b6481BE550", "0x4242424242424242424242424242424242424242" ], - "numDeployments": 5, - "solcInputHash": "a7af3565925bcd06d3e7b2ed59f01c90", - "metadata": "{\"compiler\":{\"version\":\"0.8.7+commit.e28d00a7\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"platformAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"vaultAddress\",\"type\":\"address\"}],\"internalType\":\"struct InitializableAbstractStrategy.BaseStrategyConfig\",\"name\":\"_baseConfig\",\"type\":\"tuple\"},{\"internalType\":\"address\",\"name\":\"_wethAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_ssvToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_ssvNetwork\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_feeAccumulator\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_beaconChainDepositContract\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"AccountingConsensusRewards\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"noOfValidators\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"remainingValidators\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"wethSentToVault\",\"type\":\"uint256\"}],\"name\":\"AccountingFullyWithdrawnValidator\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"validatorsDelta\",\"type\":\"int256\"},{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"consensusRewardsDelta\",\"type\":\"int256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"wethToVault\",\"type\":\"uint256\"}],\"name\":\"AccountingManuallyFixed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"remainingValidators\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"wethSentToVault\",\"type\":\"uint256\"}],\"name\":\"AccountingValidatorSlashed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"Deposit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"pubkey\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"withdrawal_credentials\",\"type\":\"bytes\"}],\"name\":\"ETHStaked\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"start\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"end\",\"type\":\"uint256\"}],\"name\":\"FuseIntervalUpdated\",\"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\":\"address\",\"name\":\"_oldHarvesterAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_newHarvesterAddress\",\"type\":\"address\"}],\"name\":\"HarvesterAddressesUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"}],\"name\":\"PTokenAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"}],\"name\":\"PTokenRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Paused\",\"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\":\"newAddress\",\"type\":\"address\"}],\"name\":\"RegistratorChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"_oldAddresses\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"_newAddresses\",\"type\":\"address[]\"}],\"name\":\"RewardTokenAddressesUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"rewardToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"RewardTokenCollected\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"pubkey\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"}],\"name\":\"SSVValidatorExitCompleted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"pubkey\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"}],\"name\":\"SSVValidatorExitInitiated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"pubkey\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"}],\"name\":\"SSVValidatorRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"StakeETHTallyReset\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"StakeETHThresholdChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newAddress\",\"type\":\"address\"}],\"name\":\"StakingMonitorChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Unpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"Withdrawal\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"BEACON_CHAIN_DEPOSIT_CONTRACT\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_ACCUMULATOR_ADDRESS\",\"outputs\":[{\"internalType\":\"address payable\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MAX_STAKE\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MIN_FIX_ACCOUNTING_CADENCE\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"SSV_NETWORK_ADDRESS\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"SSV_TOKEN_ADDRESS\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"VAULT_ADDRESS\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"WETH_TOKEN_ADDRESS\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"activeDepositedValidators\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"assetToPToken\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"}],\"name\":\"checkBalance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"claimGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"collectRewardTokens\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"consensusRewards\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"depositAll\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"validatorCount\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"networkFeeIndex\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"index\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"active\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"internalType\":\"struct Cluster\",\"name\":\"cluster\",\"type\":\"tuple\"}],\"name\":\"depositSSV\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"depositedWethAccountedFor\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"doAccounting\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"accountingValid\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"publicKey\",\"type\":\"bytes\"},{\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"}],\"name\":\"exitSsvValidator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fuseIntervalEnd\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fuseIntervalStart\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRewardTokenAddresses\",\"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\":\"harvesterAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"_rewardTokenAddresses\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"_assets\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"_pTokens\",\"type\":\"address[]\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isGovernor\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastFixAccountingBlockNumber\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"int256\",\"name\":\"_validatorsDelta\",\"type\":\"int256\"},{\"internalType\":\"int256\",\"name\":\"_consensusRewardsDelta\",\"type\":\"int256\"},{\"internalType\":\"uint256\",\"name\":\"_ethToVaultAmount\",\"type\":\"uint256\"}],\"name\":\"manuallyFixAccounting\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"paused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"platformAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"publicKey\",\"type\":\"bytes\"},{\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"},{\"internalType\":\"bytes\",\"name\":\"sharesData\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"validatorCount\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"networkFeeIndex\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"index\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"active\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"internalType\":\"struct Cluster\",\"name\":\"cluster\",\"type\":\"tuple\"}],\"name\":\"registerSsvValidator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_assetIndex\",\"type\":\"uint256\"}],\"name\":\"removePToken\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"publicKey\",\"type\":\"bytes\"},{\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"validatorCount\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"networkFeeIndex\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"index\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"active\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"internalType\":\"struct Cluster\",\"name\":\"cluster\",\"type\":\"tuple\"}],\"name\":\"removeSsvValidator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"resetStakeETHTally\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"rewardTokenAddresses\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"safeApproveAllTokens\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_fuseIntervalStart\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_fuseIntervalEnd\",\"type\":\"uint256\"}],\"name\":\"setFuseInterval\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_harvesterAddress\",\"type\":\"address\"}],\"name\":\"setHarvesterAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"}],\"name\":\"setPTokenAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"setRegistrator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"_rewardTokenAddresses\",\"type\":\"address[]\"}],\"name\":\"setRewardTokenAddresses\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"setStakeETHThreshold\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"setStakingMonitor\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"stakeETHTally\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"stakeETHThreshold\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"pubkey\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"depositDataRoot\",\"type\":\"bytes32\"}],\"internalType\":\"struct ValidatorStakeData[]\",\"name\":\"validators\",\"type\":\"tuple[]\"}],\"name\":\"stakeEth\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"stakingMonitor\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"}],\"name\":\"supportsAsset\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"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\":\"validatorRegistrator\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"validatorsStates\",\"outputs\":[{\"internalType\":\"enum ValidatorRegistrator.VALIDATOR_STATE\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"vaultAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"withdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdrawAll\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"author\":\"Origin Protocol Inc\",\"details\":\"This contract handles WETH and ETH and in some operations interchanges between the two. Any WETH that is on the contract across multiple blocks (and not just transitory within a transaction) is considered an asset. Meaning deposits increase the balance of the asset and withdrawal decrease it. As opposed to all our other strategies the WETH doesn't immediately get deposited into an underlying strategy and can be present across multiple blocks waiting to be unwrapped to ETH and staked to validators. This separation of WETH and ETH is required since the rewards (reward token) is also in ETH. To simplify the accounting of WETH there is another difference in behavior compared to the other strategies. To withdraw WETH asset - exit message is posted to validators and the ETH hits this contract with multiple days delay. In order to simplify the WETH accounting upon detection of such an event the ValidatorAccountant immediately wraps ETH to WETH and sends it to the Vault. On the other hand any ETH on the contract (across multiple blocks) is there either: - as a result of already accounted for consensus rewards - as a result of not yet accounted for consensus rewards - as a results of not yet accounted for full validator withdrawals (or validator slashes) Even though the strategy assets and rewards are a very similar asset the consensus layer rewards and the execution layer rewards are considered rewards and those are dripped to the Vault over a configurable time interval and not immediately.\",\"kind\":\"dev\",\"methods\":{\"checkBalance(address)\":{\"params\":{\"_asset\":\"Address of weth asset\"},\"returns\":{\"balance\":\" Total value of (W)ETH\"}},\"constructor\":{\"params\":{\"_baseConfig\":\"Base strategy config with platformAddress (ERC-4626 Vault contract), eg sfrxETH or sDAI, and vaultAddress (OToken Vault contract), eg VaultProxy or OETHVaultProxy\",\"_beaconChainDepositContract\":\"Address of the beacon chain deposit contract\",\"_feeAccumulator\":\"Address of the fee accumulator receiving execution layer validator rewards\",\"_ssvNetwork\":\"Address of the SSV Network contract\",\"_ssvToken\":\"Address of the Erc20 SSV Token contract\",\"_wethAddress\":\"Address of the Erc20 WETH Token contract\"}},\"deposit(address,uint256)\":{\"params\":{\"_amount\":\"Amount of assets that were transferred to the strategy by the vault.\",\"_asset\":\"Address of asset to deposit. Has to be WETH.\"}},\"depositSSV(uint64[],uint256,(uint32,uint64,uint64,bool,uint256))\":{\"details\":\"A SSV cluster is defined by the SSVOwnerAddress and the set of operatorIds. uses \\\"onlyStrategist\\\" modifier so continuous front-running can't DOS our maintenance service that tries to top up SSV tokens.\",\"params\":{\"cluster\":\"The SSV cluster details that must be derived from emitted events from the SSVNetwork contract.\"}},\"doAccounting()\":{\"details\":\"This function could in theory be permission-less but lets allow only the Registrator (Defender Action) to call it for now.\",\"returns\":{\"accountingValid\":\"true if accounting was successful, false if fuse is blown\"}},\"getRewardTokenAddresses()\":{\"returns\":{\"_0\":\"address[] the reward token addresses.\"}},\"initialize(address[],address[],address[])\":{\"params\":{\"_assets\":\"Addresses of initial supported assets\",\"_pTokens\":\"Platform Token corresponding addresses\",\"_rewardTokenAddresses\":\"Address of reward token for platform\"}},\"manuallyFixAccounting(int256,int256,uint256)\":{\"details\":\"There is a case when a validator(s) gets slashed so much that the eth swept from the beacon chain enters the fuse area and there are no consensus rewards on the contract to \\\"dip into\\\"/use. To increase the amount of unaccounted ETH over the fuse end interval we need to reduce the amount of active deposited validators and immediately send WETH to the vault, so it doesn't interfere with further accounting.\",\"params\":{\"_consensusRewardsDelta\":\"adjust the accounted for consensus rewards up or down\",\"_ethToVaultAmount\":\"the amount of ETH that gets wrapped into WETH and sent to the Vault\",\"_validatorsDelta\":\"adjust the active validators by up to plus three or minus three\"}},\"paused()\":{\"details\":\"Returns true if the contract is paused, and false otherwise.\"},\"removePToken(uint256)\":{\"params\":{\"_assetIndex\":\"Index of the asset to be removed\"}},\"setHarvesterAddress(address)\":{\"params\":{\"_harvesterAddress\":\"Address of the harvester contract.\"}},\"setPTokenAddress(address,address)\":{\"params\":{\"_asset\":\"Address for the asset\",\"_pToken\":\"Address for the corresponding platform token\"}},\"setRewardTokenAddresses(address[])\":{\"params\":{\"_rewardTokenAddresses\":\"Array of reward token addresses\"}},\"stakeEth((bytes,bytes,bytes32)[])\":{\"params\":{\"validators\":\"A list of validator data needed to stake. The `ValidatorStakeData` struct contains the pubkey, signature and depositDataRoot. Only the registrator can call this function.\"}},\"supportsAsset(address)\":{\"params\":{\"_asset\":\"The address of the asset token.\"}},\"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\"}},\"withdraw(address,address,uint256)\":{\"params\":{\"_amount\":\"Amount of WETH to withdraw\",\"_asset\":\"WETH to withdraw\",\"_recipient\":\"Address to receive withdrawn assets\"}}},\"stateVariables\":{\"FEE_ACCUMULATOR_ADDRESS\":{\"details\":\"this address will receive Execution layer rewards - These are rewards earned for executing transactions on the Ethereum network as part of block proposals. They include priority fees (fees paid by users for their transactions to be included) and MEV rewards (rewards for arranging transactions in a way that benefits the validator).\"},\"depositedWethAccountedFor\":{\"details\":\"This contract receives WETH as the deposit asset, but unlike other strategies doesn't immediately deposit it to an underlying platform. Rather a special privilege account stakes it to the validators. For that reason calling WETH.balanceOf(this) in a deposit function can contain WETH that has just been deposited and also WETH that has previously been deposited. To keep a correct count we need to keep track of WETH that has already been accounted for. This value represents the amount of WETH balance of this contract that has already been accounted for by the deposit events. It is important to note that this variable is not concerned with WETH that is a result of full/partial withdrawal of the validators. It is strictly concerned with WETH that has been deposited and is waiting to be staked.\"}},\"title\":\"Native Staking SSV Strategy\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"BEACON_CHAIN_DEPOSIT_CONTRACT()\":{\"notice\":\"The address of the beacon chain deposit contract\"},\"FEE_ACCUMULATOR_ADDRESS()\":{\"notice\":\"Fee collector address\"},\"MAX_STAKE()\":{\"notice\":\"The maximum amount of ETH that can be staked by a validator\"},\"MIN_FIX_ACCOUNTING_CADENCE()\":{\"notice\":\"The minimum amount of blocks that need to pass between two calls to manuallyFixAccounting\"},\"SSV_NETWORK_ADDRESS()\":{\"notice\":\"The address of the SSV Network contract used to interface with\"},\"SSV_TOKEN_ADDRESS()\":{\"notice\":\"SSV ERC20 token that serves as a payment for operating SSV validators\"},\"VAULT_ADDRESS()\":{\"notice\":\"Address of the OETH Vault proxy contract\"},\"WETH_TOKEN_ADDRESS()\":{\"notice\":\"The address of the Wrapped ETH (WETH) token contract\"},\"activeDepositedValidators()\":{\"notice\":\"The number of validators that have 32 (!) ETH actively deposited. When a new deposit to a validator happens this number increases, when a validator exit is detected this number decreases.\"},\"assetToPToken(address)\":{\"notice\":\"asset => pToken (Platform Specific Token Address)\"},\"checkBalance(address)\":{\"notice\":\"Returns the total value of (W)ETH that is staked to the validators and WETH deposits that are still to be staked. This does not include ETH from consensus rewards sitting in this strategy or ETH from MEV rewards in the FeeAccumulator. These rewards are harvested and sent to the Dripper so will eventually be sent to the Vault as WETH.\"},\"claimGovernance()\":{\"notice\":\"Claim Governance of the contract to a new account (`newGovernor`). Can only be called by the new Governor.\"},\"collectRewardTokens()\":{\"notice\":\"Collect accumulated reward token and send to Vault.\"},\"consensusRewards()\":{\"notice\":\"Keeps track of the total consensus rewards swept from the beacon chain\"},\"deposit(address,uint256)\":{\"notice\":\"Unlike other strategies, this does not deposit assets into the underlying platform. It just checks the asset is WETH and emits the Deposit event. To deposit WETH into validators `registerSsvValidator` and `stakeEth` must be used. Will NOT revert if the strategy is paused from an accounting failure.\"},\"depositAll()\":{\"notice\":\"Unlike other strategies, this does not deposit assets into the underlying platform. It just emits the Deposit event. To deposit WETH into validators `registerSsvValidator` and `stakeEth` must be used. Will NOT revert if the strategy is paused from an accounting failure.\"},\"depositSSV(uint64[],uint256,(uint32,uint64,uint64,bool,uint256))\":{\"notice\":\"Deposits more SSV Tokens to the SSV Network contract which is used to pay the SSV Operators.\"},\"doAccounting()\":{\"notice\":\"This notion page offers a good explanation of how the accounting functions https://www.notion.so/originprotocol/Limited-simplified-native-staking-accounting-67a217c8420d40678eb943b9da0ee77d In short, after dividing by 32, if the ETH remaining on the contract falls between 0 and fuseIntervalStart, the accounting function will treat that ETH as Beacon chain consensus rewards. On the contrary, if after dividing by 32, the ETH remaining on the contract falls between fuseIntervalEnd and 32, the accounting function will treat that as a validator slashing.Perform the accounting attributing beacon chain ETH to either full or partial withdrawals. Returns true when accounting is valid and fuse isn't \\\"blown\\\". Returns false when fuse is blown.\"},\"exitSsvValidator(bytes,uint64[])\":{\"notice\":\"Exit a validator from the Beacon chain. The staked ETH will eventually swept to this native staking strategy. Only the registrator can call this function.\"},\"fuseIntervalEnd()\":{\"notice\":\"end of fuse interval\"},\"fuseIntervalStart()\":{\"notice\":\"start of fuse interval\"},\"getRewardTokenAddresses()\":{\"notice\":\"Get the reward token addresses.\"},\"governor()\":{\"notice\":\"Returns the address of the current Governor.\"},\"harvesterAddress()\":{\"notice\":\"Address of the Harvester contract allowed to collect reward tokens\"},\"initialize(address[],address[],address[])\":{\"notice\":\"initialize function, to set up initial internal state\"},\"isGovernor()\":{\"notice\":\"Returns true if the caller is the current Governor.\"},\"lastFixAccountingBlockNumber()\":{\"notice\":\"last block number manuallyFixAccounting has been called\"},\"manuallyFixAccounting(int256,int256,uint256)\":{\"notice\":\"Allow the Strategist to fix the accounting of this strategy and unpause.\"},\"platformAddress()\":{\"notice\":\"Address of the underlying platform\"},\"registerSsvValidator(bytes,uint64[],bytes,uint256,(uint32,uint64,uint64,bool,uint256))\":{\"notice\":\"Registers a new validator in the SSV Cluster. Only the registrator can call this function.\"},\"removePToken(uint256)\":{\"notice\":\"Remove a supported asset by passing its index. This method can only be called by the system Governor\"},\"removeSsvValidator(bytes,uint64[],(uint32,uint64,uint64,bool,uint256))\":{\"notice\":\"Remove a validator from the SSV Cluster. Make sure `exitSsvValidator` is called before and the validate has exited the Beacon chain. If removed before the validator has exited the beacon chain will result in the validator being slashed. Only the registrator can call this function.\"},\"resetStakeETHTally()\":{\"notice\":\"Reset the stakeETHTally\"},\"rewardTokenAddresses(uint256)\":{\"notice\":\"Address of the reward tokens. eg CRV, BAL, CVX, AURA\"},\"safeApproveAllTokens()\":{\"notice\":\"Approves the SSV Network contract to transfer SSV tokens for deposits\"},\"setFuseInterval(uint256,uint256)\":{\"notice\":\"set fuse interval values\"},\"setHarvesterAddress(address)\":{\"notice\":\"Set the Harvester contract that can collect rewards.\"},\"setPTokenAddress(address,address)\":{\"notice\":\"Provide support for asset by passing its pToken address. This method can only be called by the system Governor\"},\"setRegistrator(address)\":{\"notice\":\"Set the address of the registrator which can register, exit and remove validators\"},\"setRewardTokenAddresses(address[])\":{\"notice\":\"Set the reward token addresses. Any old addresses will be overwritten.\"},\"setStakeETHThreshold(uint256)\":{\"notice\":\"Set the amount of ETH that can be staked before staking monitor\"},\"setStakingMonitor(address)\":{\"notice\":\"Set the address of the staking monitor that is allowed to reset stakeETHTally\"},\"stakeETHTally()\":{\"notice\":\"Amount of ETH that can has been staked since the last governor approval.\"},\"stakeETHThreshold()\":{\"notice\":\"Amount of ETH that can be staked before staking on the contract is suspended and the governor needs to approve further staking\"},\"stakeEth((bytes,bytes,bytes32)[])\":{\"notice\":\"Stakes WETH to the node validators\"},\"stakingMonitor()\":{\"notice\":\"The account that is allowed to modify stakeETHThreshold and reset stakeETHTally\"},\"supportsAsset(address)\":{\"notice\":\"Returns bool indicating whether asset is supported by strategy.\"},\"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 strategy contracts, i.e. mistaken sends.\"},\"validatorRegistrator()\":{\"notice\":\"Address of the registrator - allowed to register, exit and remove validators\"},\"validatorsStates(bytes32)\":{\"notice\":\"State of the validators keccak256(pubKey) => state\"},\"vaultAddress()\":{\"notice\":\"Address of the OToken vault\"},\"withdraw(address,address,uint256)\":{\"notice\":\"Withdraw WETH from this contract. Used only if some WETH for is lingering on the contract. That can happen when: - the deposit was not a multiple of 32 WETH - someone sent WETH directly to this contract Will NOT revert if the strategy is paused from an accounting failure.\"},\"withdrawAll()\":{\"notice\":\"transfer all WETH deposits back to the vault. This does not withdraw from the validators. That has to be done separately with the `exitSsvValidator` and `removeSsvValidator` operations. This does not withdraw any execution rewards from the FeeAccumulator or consensus rewards in this strategy. Any ETH in this strategy that was swept from a full validator withdrawal will not be withdrawn. ETH from full validator withdrawals is sent to the Vault using `doAccounting`. Will NOT revert if the strategy is paused from an accounting failure.\"}},\"notice\":\"Strategy to deploy funds into DVT validators powered by the SSV Network\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol\":\"NativeStakingSSVStrategy\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"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\",\"keccak256\":\"0xe68ed7fb8766ed1e888291f881e36b616037f852b37d96877045319ad298ba87\",\"license\":\"MIT\"},\"@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/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\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@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\",\"keccak256\":\"0xfaad496c1c944b6259b7dc70b4865eb1775d6402bc0c81b38a0b24d9f525ae37\",\"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/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\",\"keccak256\":\"0x598f90bdbc854250bbd5991426bfb43367207e64e33109c41aa8b54323fd8d8e\",\"license\":\"MIT\"},\"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 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 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 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\",\"keccak256\":\"0xbef02bd5257e61dec0a6be4b1531064a7fdfeb4043885443a1902fb5d1b23e1b\",\"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/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 function removeAsset(address _asset) external;\\n}\\n\",\"keccak256\":\"0xa03ba17b6224bec26290794760fc807e017260406037b4f812970701888e72c8\",\"license\":\"MIT\"},\"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\",\"keccak256\":\"0x05b7dce6c24d3cd4e48b5c6346d86e5e40ecc3291bcdf3f3ef091c98fc826519\",\"license\":\"MIT\"},\"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\\nimport { Governable } from \\\"../../governance/Governable.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 is Governable {\\n /// @notice The address of the Native Staking Strategy\\n address public immutable STRATEGY;\\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 }\\n\\n /**\\n * @dev Accept ETH\\n */\\n receive() external payable {}\\n}\\n\",\"keccak256\":\"0xb8fda3b87dc5d6f8aee4bf1d015a585211e5b5a319dfa4b0f4770e3f5a2d5939\",\"license\":\"MIT\"},\"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_ADDRESS;\\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 _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 address _feeAccumulator,\\n address _beaconChainDepositContract\\n )\\n InitializableAbstractStrategy(_baseConfig)\\n ValidatorAccountant(\\n _wethAddress,\\n _baseConfig.vaultAddress,\\n _beaconChainDepositContract,\\n _ssvNetwork\\n )\\n {\\n SSV_TOKEN_ADDRESS = _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 /// @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_TOKEN_ADDRESS).deposit{ value: ethRewards }();\\n\\n emit RewardTokenCollected(\\n harvesterAddress,\\n WETH_TOKEN_ADDRESS,\\n ethRewards\\n );\\n IERC20(WETH_TOKEN_ADDRESS).safeTransfer(\\n harvesterAddress,\\n ethRewards\\n );\\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_TOKEN_ADDRESS, \\\"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_TOKEN_ADDRESS).balanceOf(\\n address(this)\\n );\\n uint256 newWeth = wethBalance - depositedWethAccountedFor;\\n\\n if (newWeth > 0) {\\n depositedWethAccountedFor = wethBalance;\\n\\n _deposit(WETH_TOKEN_ADDRESS, newWeth);\\n }\\n }\\n\\n /// @notice Withdraw WETH from this contract. Used only if some WETH for is lingering on the contract. That\\n /// can happen when:\\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 _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 emit Withdrawal(_asset, address(0), _amount);\\n IERC20(_asset).safeTransfer(_recipient, _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_TOKEN_ADDRESS).balanceOf(\\n address(this)\\n );\\n if (wethBalance > 0) {\\n _withdraw(vaultAddress, WETH_TOKEN_ADDRESS, wethBalance);\\n }\\n }\\n\\n function _abstractSetPToken(address _asset, address) internal override {}\\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_TOKEN_ADDRESS, \\\"Unsupported asset\\\");\\n\\n balance =\\n // add the ETH that has been staked in validators\\n activeDepositedValidators *\\n 32 ether +\\n // add the WETH in the strategy from deposits that are still to be staked\\n IERC20(WETH_TOKEN_ADDRESS).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_TOKEN_ADDRESS;\\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_ADDRESS).approve(\\n SSV_NETWORK_ADDRESS,\\n type(uint256).max\\n );\\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 ||\\n msg.sender == WETH_TOKEN_ADDRESS,\\n \\\"eth not from allowed contracts\\\"\\n );\\n }\\n\\n function _wethWithdrawnToVault(uint256 _amount) internal override {\\n emit Withdrawal(WETH_TOKEN_ADDRESS, address(0), _amount);\\n }\\n\\n function _wethWithdrawnAndStaked(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 direclty\\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\",\"keccak256\":\"0x937ce31cd4b90ad532fdde874dc02eaf0a29a800c2c2292d2d6cb71afa75f32d\",\"license\":\"MIT\"},\"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 /// @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 MAX_STAKE = 32 ether;\\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 constructor(\\n address _wethAddress,\\n address _vaultAddress,\\n address _beaconChainDepositContract,\\n address _ssvNetwork\\n )\\n ValidatorRegistrator(\\n _wethAddress,\\n _vaultAddress,\\n _beaconChainDepositContract,\\n _ssvNetwork\\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 _fuseIntervalStart < 32 ether &&\\n _fuseIntervalEnd < 32 ether &&\\n _fuseIntervalEnd - _fuseIntervalStart >= 4 ether,\\n \\\"incorrect fuse interval\\\"\\n );\\n\\n emit FuseIntervalUpdated(_fuseIntervalStart, _fuseIntervalEnd);\\n\\n fuseIntervalStart = _fuseIntervalStart;\\n fuseIntervalEnd = _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 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 >= MAX_STAKE) {\\n uint256 fullyWithdrawnValidators;\\n // safe since MAX_STAKE is hardcoded to 32ETH\\n unchecked {\\n // explicitly cast to uint256 as we want to round to a whole number of validators\\n fullyWithdrawnValidators = uint256(newSweptETH / MAX_STAKE);\\n }\\n activeDepositedValidators -= fullyWithdrawnValidators;\\n\\n uint256 wethToVault = MAX_STAKE * fullyWithdrawnValidators;\\n IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: wethToVault }();\\n // slither-disable-next-line unchecked-transfer\\n IWETH9(WETH_TOKEN_ADDRESS).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 < 32 ether, \\\"unexpected accounting\\\");\\n\\n // If no Beacon chain consensus rewards swept\\n if (ethRemaining == 0) {\\n // do nothing\\n return accountingValid;\\n }\\n // Beacon chain consensus rewards swept (partial validator withdrawals)\\n else if (ethRemaining < fuseIntervalStart) {\\n // solhint-disable-next-line reentrancy\\n consensusRewards += ethRemaining;\\n emit AccountingConsensusRewards(ethRemaining);\\n }\\n // Beacon chain consensus rewards swept but also a slashed validator fully exited\\n else if (ethRemaining > fuseIntervalEnd) {\\n IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: ethRemaining }();\\n // slither-disable-next-line unchecked-transfer\\n IWETH9(WETH_TOKEN_ADDRESS).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 {\\n require(\\n lastFixAccountingBlockNumber + MIN_FIX_ACCOUNTING_CADENCE <\\n block.number,\\n \\\"manuallyFixAccounting 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 emit AccountingManuallyFixed(\\n _validatorsDelta,\\n _consensusRewardsDelta,\\n _ethToVaultAmount\\n );\\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_TOKEN_ADDRESS).deposit{ value: _ethToVaultAmount }();\\n // slither-disable-next-line unchecked-transfer\\n IWETH9(WETH_TOKEN_ADDRESS).transfer(\\n VAULT_ADDRESS,\\n _ethToVaultAmount\\n );\\n _wethWithdrawnToVault(_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 Withdrawal event\\n function _wethWithdrawnToVault(uint256 _amount) internal virtual;\\n}\\n\",\"keccak256\":\"0x0adba45b3fa66233c9e9bc0575ca388ebcd027cba2546278c5887065b95da708\",\"license\":\"MIT\"},\"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 address of the Wrapped ETH (WETH) token contract\\n address public immutable WETH_TOKEN_ADDRESS;\\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_ADDRESS;\\n /// @notice Address of the OETH Vault proxy contract\\n address public immutable VAULT_ADDRESS;\\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 governor needs to approve further staking\\n uint256 public stakeETHThreshold;\\n /// @notice Amount of ETH that can has been staked since the last governor approval.\\n uint256 public stakeETHTally;\\n // For future use\\n uint256[47] private __gap;\\n\\n enum VALIDATOR_STATE {\\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 newAddress);\\n event StakingMonitorChanged(address newAddress);\\n event ETHStaked(bytes pubkey, uint256 amount, bytes withdrawal_credentials);\\n event SSVValidatorRegistered(bytes pubkey, uint64[] operatorIds);\\n event SSVValidatorExitInitiated(bytes pubkey, uint64[] operatorIds);\\n event SSVValidatorExitCompleted(bytes pubkey, uint64[] operatorIds);\\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 constructor(\\n address _wethAddress,\\n address _vaultAddress,\\n address _beaconChainDepositContract,\\n address _ssvNetwork\\n ) {\\n WETH_TOKEN_ADDRESS = _wethAddress;\\n BEACON_CHAIN_DEPOSIT_CONTRACT = _beaconChainDepositContract;\\n SSV_NETWORK_ADDRESS = _ssvNetwork;\\n VAULT_ADDRESS = _vaultAddress;\\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 emit RegistratorChanged(_address);\\n validatorRegistrator = _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 emit StakingMonitorChanged(_address);\\n stakingMonitor = _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 emit StakeETHThresholdChanged(_amount);\\n stakeETHThreshold = _amount;\\n }\\n\\n /// @notice Reset the stakeETHTally\\n function resetStakeETHTally() external onlyStakingMonitor {\\n emit StakeETHTallyReset();\\n stakeETHTally = 0;\\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 {\\n uint256 requiredETH = validators.length * 32 ether;\\n\\n // Check there is enough WETH from the deposits sitting in this strategy contract\\n require(\\n requiredETH <= IWETH9(WETH_TOKEN_ADDRESS).balanceOf(address(this)),\\n \\\"insufficient WETH\\\"\\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_TOKEN_ADDRESS).withdraw(requiredETH);\\n _wethWithdrawnAndStaked(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 withdrawal_credentials = abi.encodePacked(\\n bytes1(0x01),\\n bytes11(0),\\n address(this)\\n );\\n\\n uint256 validatorsLength = validators.length;\\n // For each validator\\n for (uint256 i = 0; i < validatorsLength; ) {\\n bytes32 pubkeyHash = keccak256(validators[i].pubkey);\\n VALIDATOR_STATE currentState = validatorsStates[pubkeyHash];\\n\\n require(\\n currentState == VALIDATOR_STATE.REGISTERED,\\n \\\"Validator not registered\\\"\\n );\\n\\n IDepositContract(BEACON_CHAIN_DEPOSIT_CONTRACT).deposit{\\n value: 32 ether\\n }(\\n validators[i].pubkey,\\n withdrawal_credentials,\\n validators[i].signature,\\n validators[i].depositDataRoot\\n );\\n\\n emit ETHStaked(\\n validators[i].pubkey,\\n 32 ether,\\n withdrawal_credentials\\n );\\n\\n validatorsStates[pubkeyHash] = VALIDATOR_STATE.STAKED;\\n\\n unchecked {\\n ++i;\\n }\\n }\\n // save gas by changing this storage variable only once rather each time in the loop.\\n activeDepositedValidators += validatorsLength;\\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 function registerSsvValidator(\\n bytes calldata publicKey,\\n uint64[] calldata operatorIds,\\n bytes calldata sharesData,\\n uint256 amount,\\n Cluster calldata cluster\\n ) external onlyRegistrator whenNotPaused {\\n ISSVNetwork(SSV_NETWORK_ADDRESS).registerValidator(\\n publicKey,\\n operatorIds,\\n sharesData,\\n amount,\\n cluster\\n );\\n validatorsStates[keccak256(publicKey)] = VALIDATOR_STATE.REGISTERED;\\n emit SSVValidatorRegistered(publicKey, operatorIds);\\n }\\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 // slither-disable-start reentrancy-no-eth\\n function exitSsvValidator(\\n bytes calldata publicKey,\\n uint64[] calldata operatorIds\\n ) external onlyRegistrator whenNotPaused {\\n VALIDATOR_STATE currentState = validatorsStates[keccak256(publicKey)];\\n require(currentState == VALIDATOR_STATE.STAKED, \\\"Validator not staked\\\");\\n\\n ISSVNetwork(SSV_NETWORK_ADDRESS).exitValidator(publicKey, operatorIds);\\n emit SSVValidatorExitInitiated(publicKey, operatorIds);\\n\\n validatorsStates[keccak256(publicKey)] = VALIDATOR_STATE.EXITING;\\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 // 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 VALIDATOR_STATE currentState = validatorsStates[keccak256(publicKey)];\\n require(\\n currentState == VALIDATOR_STATE.EXITING,\\n \\\"Validator not exiting\\\"\\n );\\n\\n ISSVNetwork(SSV_NETWORK_ADDRESS).removeValidator(\\n publicKey,\\n operatorIds,\\n cluster\\n );\\n emit SSVValidatorExitCompleted(publicKey, operatorIds);\\n\\n validatorsStates[keccak256(publicKey)] = VALIDATOR_STATE.EXIT_COMPLETE;\\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 cluster The SSV cluster details that must be derived from emitted events from the SSVNetwork contract.\\n function depositSSV(\\n uint64[] memory operatorIds,\\n uint256 amount,\\n Cluster memory cluster\\n ) external onlyStrategist {\\n ISSVNetwork(SSV_NETWORK_ADDRESS).deposit(\\n address(this),\\n operatorIds,\\n amount,\\n cluster\\n );\\n }\\n\\n /***************************************\\n Abstract\\n ****************************************/\\n\\n /// @dev allows for NativeStakingSSVStrategy contract know how much WETH had been staked\\n function _wethWithdrawnAndStaked(uint256 _amount) internal virtual;\\n}\\n\",\"keccak256\":\"0xe2aace3979938c643a5c5ece3869c0901cad82b86be03d64a64192071522da7f\",\"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/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\",\"keccak256\":\"0x5e17bb3db9f9e1014b7c5c836547f8fa81e02af7568c0bb8f2a2e0e7c2192db4\",\"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/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\\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\":\"0xcbdb87104749e20c8411bc2acbfa0b7d48e876e3f4e1c46c9a7b00fcdb9722d9\",\"license\":\"MIT\"}},\"version\":1}", - "bytecode": "0x6101806040523480156200001257600080fd5b506040516200518c3803806200518c833981016040819052620000359162000138565b8585876020015183868383838362000053336200010860201b60201c565b6000805160206200516c833981519152546040516001600160a01b03909116906000907fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a908290a36033805460ff191690556001600160601b0319606094851b811660805291841b821660a052831b811660c05290821b811660e0528651821b811661010052602090960151811b86166101205298891b851661014052505050509190931b1661016052506200021392505050565b6000805160206200516c83398151915255565b80516001600160a01b03811681146200013357600080fd5b919050565b60008060008060008086880360e08112156200015357600080fd5b60408112156200016257600080fd5b50604080519081016001600160401b03811182821017156200019457634e487b7160e01b600052604160045260246000fd5b604052620001a2886200011b565b8152620001b2602089016200011b565b60208201529550620001c7604088016200011b565b9450620001d7606088016200011b565b9350620001e7608088016200011b565b9250620001f760a088016200011b565b91506200020760c088016200011b565b90509295509295509295565b60805160601c60a05160601c60c05160601c60e05160601c6101005160601c6101205160601c6101405160601c6101605160601c614db5620003b76000396000818161038a01528181610af40152613287015260008181610680015261272d01526000818161053401528181610f0801528181611b8201528181611cfb01528181612a8c0152612d1401526000610ac001526000818161083b01528181610cd001528181611ab001528181611d4b0152818161210f015281816138730152613acd015260008181610b7e01528181610da601528181611982015281816126fd015281816128150152612c0a015260008181610a1501526116c40152600081816103bc015281816105de0152818161092c01528181610c3701528181610f7d015281816111c101528181611249015281816113f80152818161154901528181611c6c01528181611d1c015281816120890152818161213e01528181612d9f01528181612e470152818161338c015281816134110152818161348501528181613722015281816137ed015281816138a201528181613a470152613afc0152614db56000f3fe60806040526004361061037a5760003560e01c8063853828b6116101d1578063c7af335211610102578063dbe55e56116100a0578063e75292391161006f578063e752923914610b41578063ee7afe2d14610b57578063f1188e4014610b6c578063f6ca71b014610ba057600080fd5b8063dbe55e5614610aae578063dd505df614610ae2578063de34d71314610b16578063de5f626814610b2c57600080fd5b8063d059f6ef116100dc578063d059f6ef14610a37578063d38bfff414610a4e578063d9caed1214610a6e578063d9f00ec714610a8e57600080fd5b8063c7af3352146109d1578063c98517c5146109e6578063cceab75014610a0357600080fd5b8063a3b81e731161016f578063ab12edf511610149578063ab12edf51461095c578063ad1728cb1461097c578063bb1b918d14610991578063c2e1e3f4146109b157600080fd5b8063a3b81e73146108da578063a4f98af4146108fa578063aa388af61461090f57600080fd5b80639092c31c116101ab5780639092c31c146108295780639136616a1461085d57806396d538bb1461087d5780639da0e4621461089d57600080fd5b8063853828b6146107cf57806387bae867146107e45780638d7c0e461461080957600080fd5b80635d36b190116102ab5780636ef38795116102495780637b2d9b2c116102235780637b2d9b2c1461076e5780637b8962f71461078e578063842f5c46146107a45780638456cb59146107ba57600080fd5b80636ef387951461070e57806371a735f31461072e5780637260f8261461074e57600080fd5b8063630923831161028557806363092383146106a257806366e3667e146106b857806367c7066c146106ce5780636e811d38146106ee57600080fd5b80635d36b190146106395780635f5152261461064e5780636093d3801461066e57600080fd5b8063435356d1116103185780635205c380116102f25780635205c380146105ac578063579a7e1a146105cc5780635a063f63146106005780635c975abb1461061557600080fd5b8063435356d11461055657806347e7ef2414610576578063484be8121461059657600080fd5b80631072cbea116103545780631072cbea146104be57806322495dc8146104de5780633c864959146104fe578063430bf08a1461052257600080fd5b80630c340a24146104365780630ed57b3a146104685780630fc3b4c41461048857600080fd5b3661043157336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614806103de5750336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016145b61042f5760405162461bcd60e51b815260206004820152601e60248201527f657468206e6f742066726f6d20616c6c6f77656420636f6e747261637473000060448201526064015b60405180910390fd5b005b600080fd5b34801561044257600080fd5b5061044b610bc2565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561047457600080fd5b5061042f610483366004614158565b610bdf565b34801561049457600080fd5b5061044b6104a336600461411e565b609f602052600090815260409020546001600160a01b031681565b3480156104ca57600080fd5b5061042f6104d93660046141d2565b610c11565b3480156104ea57600080fd5b5061042f6104f93660046142c6565b610cce565b34801561050a57600080fd5b5061051460695481565b60405190815260200161045f565b34801561052e57600080fd5b5061044b7f000000000000000000000000000000000000000000000000000000000000000081565b34801561056257600080fd5b5061042f61057136600461423f565b610e18565b34801561058257600080fd5b5061042f6105913660046141d2565b610efd565b3480156105a257600080fd5b50610514606a5481565b3480156105b857600080fd5b5061042f6105c736600461439c565b61101c565b3480156105d857600080fd5b5061044b7f000000000000000000000000000000000000000000000000000000000000000081565b34801561060c57600080fd5b5061042f611078565b34801561062157600080fd5b5060335460ff165b604051901515815260200161045f565b34801561064557600080fd5b5061042f611117565b34801561065a57600080fd5b5061051461066936600461411e565b6111bd565b34801561067a57600080fd5b5061044b7f000000000000000000000000000000000000000000000000000000000000000081565b3480156106ae57600080fd5b50610514611c2081565b3480156106c457600080fd5b5061051460345481565b3480156106da57600080fd5b5060a35461044b906001600160a01b031681565b3480156106fa57600080fd5b5061042f61070936600461411e565b6112f1565b34801561071a57600080fd5b5061042f6107293660046141fe565b611379565b34801561073a57600080fd5b5061042f6107493660046144d4565b61188b565b34801561075a57600080fd5b5060365461044b906001600160a01b031681565b34801561077a57600080fd5b5061044b61078936600461439c565b611a84565b34801561079a57600080fd5b5061051460375481565b3480156107b057600080fd5b5061051460685481565b3480156107c657600080fd5b5061042f611aae565b3480156107db57600080fd5b5061042f611b77565b3480156107f057600080fd5b5060335461044b9061010090046001600160a01b031681565b34801561081557600080fd5b5061042f610824366004614555565b611d49565b34801561083557600080fd5b5061044b7f000000000000000000000000000000000000000000000000000000000000000081565b34801561086957600080fd5b5061042f61087836600461439c565b61221e565b34801561088957600080fd5b5061042f6108983660046141fe565b6123e9565b3480156108a957600080fd5b506108cd6108b836600461439c565b60356020526000908152604090205460ff1681565b60405161045f91906149c0565b3480156108e657600080fd5b5061042f6108f536600461411e565b612509565b34801561090657600080fd5b5061062961258b565b34801561091b57600080fd5b5061062961092a36600461411e565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0390811691161490565b34801561096857600080fd5b5061042f61097736600461459a565b6125ea565b34801561098857600080fd5b5061042f6126e6565b34801561099d57600080fd5b5061042f6109ac366004614420565b6127ac565b3480156109bd57600080fd5b5061042f6109cc36600461411e565b61291f565b3480156109dd57600080fd5b506106296129ac565b3480156109f257600080fd5b506105146801bc16d674ec80000081565b348015610a0f57600080fd5b5061044b7f000000000000000000000000000000000000000000000000000000000000000081565b348015610a4357600080fd5b506105146101075481565b348015610a5a57600080fd5b5061042f610a6936600461411e565b6129dd565b348015610a7a57600080fd5b5061042f610a89366004614191565b612a81565b348015610a9a57600080fd5b5061042f610aa93660046143b5565b612b14565b348015610aba57600080fd5b5061044b7f000000000000000000000000000000000000000000000000000000000000000081565b348015610aee57600080fd5b5061044b7f000000000000000000000000000000000000000000000000000000000000000081565b348015610b2257600080fd5b5061051460385481565b348015610b3857600080fd5b5061042f612d09565b348015610b4d57600080fd5b50610514606b5481565b348015610b6357600080fd5b5061042f612e76565b348015610b7857600080fd5b5061044b7f000000000000000000000000000000000000000000000000000000000000000081565b348015610bac57600080fd5b50610bb5612f00565b60405161045f9190614796565b6000610bda600080516020614d608339815191525490565b905090565b610be76129ac565b610c035760405162461bcd60e51b815260040161042690614a32565b610c0d8282612f62565b5050565b610c196129ac565b610c355760405162461bcd60e51b815260040161042690614a32565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b039081169083161415610cb25760405162461bcd60e51b815260206004820152601f60248201527f43616e6e6f74207472616e7366657220737570706f72746564206173736574006044820152606401610426565b610c0d610cbd610bc2565b6001600160a01b03841690836130c1565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b158015610d2757600080fd5b505afa158015610d3b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d5f919061413b565b6001600160a01b0316336001600160a01b031614610d8f5760405162461bcd60e51b815260040161042690614af2565b60405163bc26e7e560e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063bc26e7e590610de19030908790879087906004016146e6565b600060405180830381600087803b158015610dfb57600080fd5b505af1158015610e0f573d6000803e3d6000fd5b50505050505050565b610e206129ac565b610e3c5760405162461bcd60e51b815260040161042690614a32565b600054610100900460ff1680610e55575060005460ff16155b610eb85760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610426565b600054610100900460ff16158015610eda576000805461ffff19166101011790555b610ee5848484613113565b8015610ef7576000805461ff00191690555b50505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610f455760405162461bcd60e51b8152600401610426906149fb565b600080516020614d4083398151915280546002811415610f775760405162461bcd60e51b815260040161042690614aca565b600282557f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316846001600160a01b031614610ff05760405162461bcd60e51b8152602060048201526011602482015270155b9cdd5c1c1bdc9d195908185cdcd95d607a1b6044820152606401610426565b8261010760008282546110039190614c19565b90915550611013905084846131ce565b50600190555050565b6110246129ac565b6110405760405162461bcd60e51b815260040161042690614a32565b6040518181527fe26b067424903962f951f568e52ec9a3bbe1589526ea54a4e69ca6eaae1a4c779060200160405180910390a1603755565b60a3546001600160a01b031633146110d25760405162461bcd60e51b815260206004820152601b60248201527f43616c6c6572206973206e6f74207468652048617276657374657200000000006044820152606401610426565b600080516020614d40833981519152805460028114156111045760405162461bcd60e51b815260040161042690614aca565b60028255611110613260565b5060019055565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b0316146111b25760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b6064820152608401610426565b6111bb336134ae565b565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b0316146112345760405162461bcd60e51b8152602060048201526011602482015270155b9cdd5c1c1bdc9d195908185cdcd95d607a1b6044820152606401610426565b6040516370a0823160e01b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b15801561129357600080fd5b505afa1580156112a7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112cb9190614581565b6034546112e1906801bc16d674ec800000614c31565b6112eb9190614c19565b92915050565b6112f96129ac565b6113155760405162461bcd60e51b815260040161042690614a32565b6040516001600160a01b03821681527f83f29c79feb71f8fba9d0fbc4ba5f0982a28b6b1e868b3fc50e6400d100bca0f9060200160405180910390a1603380546001600160a01b0390921661010002610100600160a81b0319909216919091179055565b60335461010090046001600160a01b031633146113a85760405162461bcd60e51b815260040161042690614a93565b60335460ff16156113cb5760405162461bcd60e51b815260040161042690614a69565b60006113e0826801bc16d674ec800000614c31565b6040516370a0823160e01b81523060048201529091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b15801561144257600080fd5b505afa158015611456573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061147a9190614581565b8111156114bd5760405162461bcd60e51b81526020600482015260116024820152700d2dce6eaccccd2c6d2cadce840ae8aa89607b1b6044820152606401610426565b603754816038546114ce9190614c19565b111561151c5760405162461bcd60e51b815260206004820152601a60248201527f5374616b696e6720455448206f766572207468726573686f6c640000000000006044820152606401610426565b806038600082825461152e9190614c19565b9091555050604051632e1a7d4d60e01b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561159557600080fd5b505af11580156115a9573d6000803e3d6000fd5b505050506115b68161356f565b60408051600160f81b60208201526000602182018190526bffffffffffffffffffffffff193060601b16602c830152910160408051601f1981840301815291905290508260005b8181101561186c57600086868381811061161957611619614cf0565b905060200281019061162b9190614b6f565b6116359080614b29565b6040516116439291906146ba565b6040805191829003909120600081815260356020529182205490925060ff169081600381111561167557611675614cc4565b146116c25760405162461bcd60e51b815260206004820152601860248201527f56616c696461746f72206e6f74207265676973746572656400000000000000006044820152606401610426565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663228951186801bc16d674ec8000008a8a8781811061170d5761170d614cf0565b905060200281019061171f9190614b6f565b6117299080614b29565b898d8d8a81811061173c5761173c614cf0565b905060200281019061174e9190614b6f565b61175c906020810190614b29565b8f8f8c81811061176e5761176e614cf0565b90506020028101906117809190614b6f565b604001356040518863ffffffff1660e01b81526004016117a596959493929190614945565b6000604051808303818588803b1580156117be57600080fd5b505af11580156117d2573d6000803e3d6000fd5b50505050507ffeb31a79d38edb1b090d516e4df3e273651179c6f2c2ec53a9a22ae015b70ba988888581811061180a5761180a614cf0565b905060200281019061181c9190614b6f565b6118269080614b29565b6801bc16d674ec800000886040516118419493929190614994565b60405180910390a1506000908152603560205260409020805460ff19166001908117909155016115fd565b50806034600082825461187f9190614c19565b90915550505050505050565b60335461010090046001600160a01b031633146118ba5760405162461bcd60e51b815260040161042690614a93565b60335460ff16156118dd5760405162461bcd60e51b815260040161042690614a69565b60006035600087876040516118f39291906146ba565b604080519182900390912082526020820192909252016000205460ff169050600281600381111561192657611926614cc4565b1461196b5760405162461bcd60e51b815260206004820152601560248201527456616c696461746f72206e6f742065786974696e6760581b6044820152606401610426565b6040516312b3fc1960e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906312b3fc19906119bf9089908990899089908990600401614904565b600060405180830381600087803b1580156119d957600080fd5b505af11580156119ed573d6000803e3d6000fd5b505050507ff72821b8777f002ccdf6326f1242d9e0f762eb077668b67bebe640535378066d86868686604051611a26949392919061487b565b60405180910390a16003603560008888604051611a449291906146ba565b60408051918290039091208252602082019290925201600020805460ff19166001836003811115611a7757611a77614cc4565b0217905550505050505050565b60a48181548110611a9457600080fd5b6000918252602090912001546001600160a01b0316905081565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b158015611b0757600080fd5b505afa158015611b1b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b3f919061413b565b6001600160a01b0316336001600160a01b031614611b6f5760405162461bcd60e51b815260040161042690614af2565b6111bb61359c565b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161480611bc65750611bb1610bc2565b6001600160a01b0316336001600160a01b0316145b611c1e5760405162461bcd60e51b815260206004820152602360248201527f43616c6c6572206973206e6f7420746865205661756c74206f7220476f7665726044820152623737b960e91b6064820152608401610426565b600080516020614d4083398151915280546002811415611c505760405162461bcd60e51b815260040161042690614aca565b600282556040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b158015611cb657600080fd5b505afa158015611cca573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cee9190614581565b90508015611d4157611d417f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000083613611565b505060019055565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b158015611da257600080fd5b505afa158015611db6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dda919061413b565b6001600160a01b0316336001600160a01b031614611e0a5760405162461bcd60e51b815260040161042690614af2565b60335460ff16611e535760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610426565b43611c20606b54611e649190614c19565b10611ebf5760405162461bcd60e51b815260206004820152602560248201527f6d616e75616c6c794669784163636f756e74696e672063616c6c656420746f6f6044820152641039b7b7b760d91b6064820152608401610426565b6002198312158015611ed2575060038313155b8015611eec5750600083603454611ee99190614bd8565b12155b611f385760405162461bcd60e51b815260206004820152601760248201527f696e76616c69642076616c696461746f727344656c74610000000000000000006044820152606401610426565b6811ff6cf0fd15afffff198212158015611f5b57506811ff6cf0fd15b000008213155b8015611f755750600082606854611f729190614bd8565b12155b611fc15760405162461bcd60e51b815260206004820152601d60248201527f696e76616c696420636f6e73656e7375735265776172647344656c74610000006044820152606401610426565b68053444835ec580000081111561201a5760405162461bcd60e51b815260206004820152601960248201527f696e76616c69642077657468546f5661756c74416d6f756e74000000000000006044820152606401610426565b60408051848152602081018490529081018290527f80d022717ea022455c5886b8dd8a29c037570aae58aeb4d7b136d7a10ec2e4319060600160405180910390a1826034546120699190614bd8565b60345560685461207a908390614bd8565b60685543606b5580156121c8577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b1580156120e257600080fd5b505af11580156120f6573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb92506044019050602060405180830381600087803b15801561218657600080fd5b505af115801561219a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121be919061437f565b506121c881613709565b6121d26000613771565b6122115760405162461bcd60e51b815260206004820152601060248201526f333ab9b29039ba34b63610313637bbb760811b6044820152606401610426565b612219613bf0565b505050565b6122266129ac565b6122425760405162461bcd60e51b815260040161042690614a32565b60a05481106122835760405162461bcd60e51b815260206004820152600d60248201526c092dcecc2d8d2c840d2dcc8caf609b1b6044820152606401610426565b600060a0828154811061229857612298614cf0565b60009182526020808320909101546001600160a01b03908116808452609f90925260409092205460a054919350909116906122d590600190614c50565b8310156123575760a080546122ec90600190614c50565b815481106122fc576122fc614cf0565b60009182526020909120015460a080546001600160a01b03909216918590811061232857612328614cf0565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505b60a080548061236857612368614cda565b60008281526020808220600019908401810180546001600160a01b031990811690915593019093556001600160a01b03858116808352609f855260409283902080549094169093559051908416815290917f16b7600acff27e39a8a96056b3d533045298de927507f5c1d97e4accde60488c910160405180910390a2505050565b6123f16129ac565b61240d5760405162461bcd60e51b815260040161042690614a32565b8060005b818110156124c057600084848381811061242d5761242d614cf0565b9050602002016020810190612442919061411e565b6001600160a01b031614156124b05760405162461bcd60e51b815260206004820152602e60248201527f43616e206e6f742073657420616e20656d70747920616464726573732061732060448201526d30903932bbb0b932103a37b5b2b760911b6064820152608401610426565b6124b981614c93565b9050612411565b507f04c0b9649497d316554306e53678d5f5f5dbc3a06f97dec13ff4cfe98b986bbc60a484846040516124f5939291906147e3565b60405180910390a1610ef760a48484613e77565b6125116129ac565b61252d5760405162461bcd60e51b815260040161042690614a32565b6040516001600160a01b03821681527f3329861a0008b3348767567d2405492b997abd79a088d0f2cef6b1a09a8e7ff79060200160405180910390a1603680546001600160a01b0319166001600160a01b0392909216919091179055565b60335460009061010090046001600160a01b031633146125bd5760405162461bcd60e51b815260040161042690614a93565b60335460ff16156125e05760405162461bcd60e51b815260040161042690614a69565b610bda6001613771565b6125f26129ac565b61260e5760405162461bcd60e51b815260040161042690614a32565b808210801561262557506801bc16d674ec80000082105b801561263957506801bc16d674ec80000081105b80156126565750673782dace9d9000006126538383614c50565b10155b6126a25760405162461bcd60e51b815260206004820152601760248201527f696e636f7272656374206675736520696e74657276616c0000000000000000006044820152606401610426565b60408051838152602081018390527fcb8d24e46eb3c402bf344ee60a6576cba9ef2f59ea1af3b311520704924e901a910160405180910390a1606991909155606a55565b60405163095ea7b360e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015260001960248301527f0000000000000000000000000000000000000000000000000000000000000000169063095ea7b390604401602060405180830381600087803b15801561277157600080fd5b505af1158015612785573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127a9919061437f565b50565b60335461010090046001600160a01b031633146127db5760405162461bcd60e51b815260040161042690614a93565b60335460ff16156127fe5760405162461bcd60e51b815260040161042690614a69565b6040516301ba3ee760e21b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906306e8fb9c90612858908b908b908b908b908b908b908b908b906004016148a2565b600060405180830381600087803b15801561287257600080fd5b505af1158015612886573d6000803e3d6000fd5b505050506000603560008a8a6040516128a09291906146ba565b60408051918290039091208252602082019290925201600020805460ff191660018360038111156128d3576128d3614cc4565b02179055507f75c4a66b2c6c28cf46db7131182a812e4fbbb2f0591377aa83a737909a9b68c38888888860405161290d949392919061487b565b60405180910390a15050505050505050565b6129276129ac565b6129435760405162461bcd60e51b815260040161042690614a32565b60a354604080516001600160a01b03928316815291831660208301527fe48386b84419f4d36e0f96c10cc3510b6fb1a33795620c5098b22472bbe90796910160405180910390a160a380546001600160a01b0319166001600160a01b0392909216919091179055565b60006129c4600080516020614d608339815191525490565b6001600160a01b0316336001600160a01b031614905090565b6129e56129ac565b612a015760405162461bcd60e51b815260040161042690614a32565b612a29817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b0316612a49600080516020614d608339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614612ac95760405162461bcd60e51b8152600401610426906149fb565b600080516020614d4083398151915280546002811415612afb5760405162461bcd60e51b815260040161042690614aca565b60028255612b0a858585613611565b5060019055505050565b60335461010090046001600160a01b03163314612b435760405162461bcd60e51b815260040161042690614a93565b60335460ff1615612b665760405162461bcd60e51b815260040161042690614a69565b6000603560008686604051612b7c9291906146ba565b604080519182900390912082526020820192909252016000205460ff1690506001816003811115612baf57612baf614cc4565b14612bf35760405162461bcd60e51b815260206004820152601460248201527315985b1a59185d1bdc881b9bdd081cdd185ad95960621b6044820152606401610426565b604051633877322b60e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690633877322b90612c4590889088908890889060040161487b565b600060405180830381600087803b158015612c5f57600080fd5b505af1158015612c73573d6000803e3d6000fd5b505050507ff8821da16f5ed966b41e0343c3eff9903af782d74f99f1689dd9d4562b6545b385858585604051612cac949392919061487b565b60405180910390a16002603560008787604051612cca9291906146ba565b60408051918290039091208252602082019290925201600020805460ff19166001836003811115612cfd57612cfd614cc4565b02179055505050505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614612d515760405162461bcd60e51b8152600401610426906149fb565b600080516020614d4083398151915280546002811415612d835760405162461bcd60e51b815260040161042690614aca565b600282556040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b158015612de957600080fd5b505afa158015612dfd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e219190614581565b905060006101075482612e349190614c50565b90508015612e6c57610107829055612e6c7f0000000000000000000000000000000000000000000000000000000000000000826131ce565b5050600182555050565b6036546001600160a01b03163314612ed05760405162461bcd60e51b815260206004820152601960248201527f43616c6c6572206973206e6f7420746865204d6f6e69746f72000000000000006044820152606401610426565b6040517fe765a88a37047c5d793dce22b9ceb5a0f5039d276da139b4c7d29613f341f11090600090a16000603855565b606060a4805480602002602001604051908101604052809291908181526020018280548015612f5857602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612f3a575b5050505050905090565b6001600160a01b038281166000908152609f60205260409020541615612fbf5760405162461bcd60e51b81526020600482015260126024820152711c151bdad95b88185b1c9958591e481cd95d60721b6044820152606401610426565b6001600160a01b03821615801590612fdf57506001600160a01b03811615155b61301f5760405162461bcd60e51b8152602060048201526011602482015270496e76616c69642061646472657373657360781b6044820152606401610426565b6001600160a01b038281166000818152609f6020908152604080832080549587166001600160a01b0319968716811790915560a0805460018101825594527f78fdc8d422c49ced035a9edf18d00d3c6a8d81df210f3e5e448e045e77b41e8890930180549095168417909455925190815290917fef6485b84315f9b1483beffa32aae9a0596890395e3d7521f1c5fbb51790e765910160405180910390a25050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052612219908490613c6a565b82516131269060a4906020860190613eda565b508151815181146131705760405162461bcd60e51b8152602060048201526014602482015273496e76616c696420696e7075742061727261797360601b6044820152606401610426565b60005b818110156131c7576131b784828151811061319057613190614cf0565b60200260200101518483815181106131aa576131aa614cf0565b6020026020010151612f62565b6131c081614c93565b9050613173565b5050505050565b600081116132175760405162461bcd60e51b81526020600482015260166024820152754d757374206465706f73697420736f6d657468696e6760501b6044820152606401610426565b6040805160008152602081018390526001600160a01b038416917f5548c837ab068cf56a2c2479df0882a4922fd203edb7517321831d95078c5f62910160405180910390a25050565b60335460ff16156132835760405162461bcd60e51b815260040161042690614a69565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663e52253816040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156132e057600080fd5b505af11580156132f4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133189190614581565b905060006068548261332a9190614c19565b90508047101561337c5760405162461bcd60e51b815260206004820152601860248201527f696e73756666696369656e74206574682062616c616e636500000000000000006044820152606401610426565b8015610c0d5760006068819055507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b1580156133e557600080fd5b505af11580156133f9573d6000803e3d6000fd5b505060a354604080516001600160a01b0392831681527f0000000000000000000000000000000000000000000000000000000000000000909216602083015281018590527ff6c07a063ed4e63808eb8da7112d46dbcd38de2b40a73dbcc9353c5a94c723539350606001915061346c9050565b60405180910390a160a354610c0d906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081169116836130c1565b6001600160a01b0381166135045760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f7220697320616464726573732830290000000000006044820152606401610426565b806001600160a01b0316613524600080516020614d608339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a36127a981600080516020614d6083398151915255565b600061357e8261010754613d3c565b90508061010760008282546135939190614c50565b90915550505050565b60335460ff16156135bf5760405162461bcd60e51b815260040161042690614a69565b6033805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586135f43390565b6040516001600160a01b03909116815260200160405180910390a1565b600081116136615760405162461bcd60e51b815260206004820152601760248201527f4d75737420776974686472617720736f6d657468696e670000000000000000006044820152606401610426565b6001600160a01b0383166136b05760405162461bcd60e51b8152602060048201526016602482015275135d5cdd081cdc1958da599e481c9958da5c1a595b9d60521b6044820152606401610426565b6040805160008152602081018390526001600160a01b038416917f2717ead6b9200dd235aad468c9809ea400fe33ac69b5bfaa6d3e90fc922b6398910160405180910390a26122196001600160a01b03831684836130c1565b6040805160008152602081018390526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016917f2717ead6b9200dd235aad468c9809ea400fe33ac69b5bfaa6d3e90fc922b6398910160405180910390a250565b6000606854471015613786576112eb82613d54565b6000606854476137969190614c50565b9050600191506801bc16d674ec80000081106139735760006801bc16d674ec8000008204905080603460008282546137ce9190614c50565b90915550600090506137e9826801bc16d674ec800000614c31565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b15801561384657600080fd5b505af115801561385a573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb92506044019050602060405180830381600087803b1580156138ea57600080fd5b505af11580156138fe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613922919061437f565b5061392c81613709565b60345460408051848152602081019290925281018290527fbe7040030ff7b347853214bf49820c6d455fedf58f3815f85c7bc5216993682b9060600160405180910390a150505b6000606854476139839190614c50565b90506801bc16d674ec80000081106139d55760405162461bcd60e51b8152602060048201526015602482015274756e6578706563746564206163636f756e74696e6760581b6044820152606401610426565b806139e1575050919050565b606954811015613a3b5780606860008282546139fd9190614c19565b90915550506040518181527f7a745a2c63a535068f52ceca27debd5297bbad5f7f37ec53d044a59d0362445d906020015b60405180910390a1613be9565b606a54811115613bd8577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b158015613aa057600080fd5b505af1158015613ab4573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb92506044019050602060405180830381600087803b158015613b4457600080fd5b505af1158015613b58573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b7c919061437f565b50600160346000828254613b909190614c50565b90915550613b9f905081613709565b60345460408051918252602082018390527f6aa7e30787b26429ced603a7aba8b19c4b5d5bcf29a3257da953c8d53bcaa3a69101613a2e565b613be184613d54565b949350505050565b5050919050565b60335460ff16613c395760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610426565b6033805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa336135f4565b6000613cbf826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316613d6c9092919063ffffffff16565b8051909150156122195780806020019051810190613cdd919061437f565b6122195760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610426565b6000818310613d4b5781613d4d565b825b9392505050565b60008115613d6457613d6461359c565b506000919050565b6060613be1848460008585843b613dc55760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610426565b600080866001600160a01b03168587604051613de191906146ca565b60006040518083038185875af1925050503d8060008114613e1e576040519150601f19603f3d011682016040523d82523d6000602084013e613e23565b606091505b5091509150613e33828286613e3e565b979650505050505050565b60608315613e4d575081613d4d565b825115613e5d5782518084602001fd5b8160405162461bcd60e51b815260040161042691906149e8565b828054828255906000526020600020908101928215613eca579160200282015b82811115613eca5781546001600160a01b0319166001600160a01b03843516178255602090920191600190910190613e97565b50613ed6929150613f2f565b5090565b828054828255906000526020600020908101928215613eca579160200282015b82811115613eca57825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190613efa565b5b80821115613ed65760008155600101613f30565b60008083601f840112613f5657600080fd5b5081356001600160401b03811115613f6d57600080fd5b6020830191508360208260051b8501011115613f8857600080fd5b9250929050565b600082601f830112613fa057600080fd5b81356020613fb5613fb083614bb5565b614b85565b80838252828201915082860187848660051b8901011115613fd557600080fd5b60005b85811015613ffd578135613feb81614d1c565b84529284019290840190600101613fd8565b5090979650505050505050565b60008083601f84011261401c57600080fd5b5081356001600160401b0381111561403357600080fd5b602083019150836020828501011115613f8857600080fd5b600060a0828403121561405d57600080fd5b50919050565b600060a0828403121561407557600080fd5b60405160a081018181106001600160401b038211171561409757614097614d06565b6040529050806140a6836140ee565b81526140b460208401614107565b60208201526140c560408401614107565b604082015260608301356140d881614d31565b6060820152608092830135920191909152919050565b803563ffffffff8116811461410257600080fd5b919050565b80356001600160401b038116811461410257600080fd5b60006020828403121561413057600080fd5b8135613d4d81614d1c565b60006020828403121561414d57600080fd5b8151613d4d81614d1c565b6000806040838503121561416b57600080fd5b823561417681614d1c565b9150602083013561418681614d1c565b809150509250929050565b6000806000606084860312156141a657600080fd5b83356141b181614d1c565b925060208401356141c181614d1c565b929592945050506040919091013590565b600080604083850312156141e557600080fd5b82356141f081614d1c565b946020939093013593505050565b6000806020838503121561421157600080fd5b82356001600160401b0381111561422757600080fd5b61423385828601613f44565b90969095509350505050565b60008060006060848603121561425457600080fd5b83356001600160401b038082111561426b57600080fd5b61427787838801613f8f565b9450602086013591508082111561428d57600080fd5b61429987838801613f8f565b935060408601359150808211156142af57600080fd5b506142bc86828701613f8f565b9150509250925092565b600080600060e084860312156142db57600080fd5b83356001600160401b038111156142f157600080fd5b8401601f8101861361430257600080fd5b80356020614312613fb083614bb5565b8083825282820191508285018a848660051b880101111561433257600080fd5b600095505b8486101561435c5761434881614107565b835260019590950194918301918301614337565b509650508601359350614376915086905060408601614063565b90509250925092565b60006020828403121561439157600080fd5b8151613d4d81614d31565b6000602082840312156143ae57600080fd5b5035919050565b600080600080604085870312156143cb57600080fd5b84356001600160401b03808211156143e257600080fd5b6143ee8883890161400a565b9096509450602087013591508082111561440757600080fd5b5061441487828801613f44565b95989497509550505050565b600080600080600080600080610120898b03121561443d57600080fd5b88356001600160401b038082111561445457600080fd5b6144608c838d0161400a565b909a50985060208b013591508082111561447957600080fd5b6144858c838d01613f44565b909850965060408b013591508082111561449e57600080fd5b506144ab8b828c0161400a565b909550935050606089013591506144c58a60808b0161404b565b90509295985092959890939650565b600080600080600060e086880312156144ec57600080fd5b85356001600160401b038082111561450357600080fd5b61450f89838a0161400a565b9097509550602088013591508082111561452857600080fd5b5061453588828901613f44565b90945092506145499050876040880161404b565b90509295509295909350565b60008060006060848603121561456a57600080fd5b505081359360208301359350604090920135919050565b60006020828403121561459357600080fd5b5051919050565b600080604083850312156145ad57600080fd5b50508035926020909101359150565b8183526000602080850194508260005b858110156145f8576001600160401b036145e583614107565b16875295820195908201906001016145cc565b509495945050505050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b60008151808452614644816020860160208601614c67565b601f01601f19169290920160200192915050565b63ffffffff614666826140ee565b16825261467560208201614107565b6001600160401b0380821660208501528061469260408501614107565b166040850152505060608101356146a881614d31565b15156060830152608090810135910152565b8183823760009101908152919050565b600082516146dc818460208701614c67565b9190910192915050565b6001600160a01b03851681526101006020808301829052855191830182905260009161012084019187810191845b818110156147395783516001600160401b031685529382019392820192600101614714565b505082935086604086015263ffffffff865116606086015280860151925050506001600160401b0380821660808501528060408601511660a085015250506060830151151560c0830152608083015160e083015295945050505050565b6020808252825182820181905260009190848201906040850190845b818110156147d75783516001600160a01b0316835292840192918401916001016147b2565b50909695505050505050565b6000604082016040835280865480835260608501915087600052602092508260002060005b8281101561482d5781546001600160a01b031684529284019260019182019101614808565b505050838103828501528481528590820160005b8681101561486f57823561485481614d1c565b6001600160a01b031682529183019190830190600101614841565b50979650505050505050565b60408152600061488f604083018688614603565b8281036020840152613e338185876145bc565b60006101208083526148b78184018b8d614603565b905082810360208401526148cc81898b6145bc565b905082810360408401526148e1818789614603565b9150508360608301526148f76080830184614658565b9998505050505050505050565b60e08152600061491860e083018789614603565b828103602084015261492b8186886145bc565b91505061493b6040830184614658565b9695505050505050565b60808152600061495960808301888a614603565b828103602084015261496b818861462c565b90508281036040840152614980818688614603565b915050826060830152979650505050505050565b6060815260006149a8606083018688614603565b8460208401528281036040840152613e33818561462c565b60208101600483106149e257634e487b7160e01b600052602160045260246000fd5b91905290565b602081526000613d4d602083018461462c565b60208082526017908201527f43616c6c6572206973206e6f7420746865205661756c74000000000000000000604082015260600190565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b60208082526010908201526f14185d5cd8589b194e881c185d5cd95960821b604082015260600190565b6020808252601d908201527f43616c6c6572206973206e6f7420746865205265676973747261746f72000000604082015260600190565b6020808252600e908201526d1499595b9d1c985b9d0818d85b1b60921b604082015260600190565b6020808252601c908201527f43616c6c6572206973206e6f7420746865205374726174656769737400000000604082015260600190565b6000808335601e19843603018112614b4057600080fd5b8301803591506001600160401b03821115614b5a57600080fd5b602001915036819003821315613f8857600080fd5b60008235605e198336030181126146dc57600080fd5b604051601f8201601f191681016001600160401b0381118282101715614bad57614bad614d06565b604052919050565b60006001600160401b03821115614bce57614bce614d06565b5060051b60200190565b600080821280156001600160ff1b0384900385131615614bfa57614bfa614cae565b600160ff1b8390038412811615614c1357614c13614cae565b50500190565b60008219821115614c2c57614c2c614cae565b500190565b6000816000190483118215151615614c4b57614c4b614cae565b500290565b600082821015614c6257614c62614cae565b500390565b60005b83811015614c82578181015183820152602001614c6a565b83811115610ef75750506000910152565b6000600019821415614ca757614ca7614cae565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b03811681146127a957600080fd5b80151581146127a957600080fdfe53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac45357bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa264697066735822122036fc9aa0014d1fbbc8fbac98689c50c4cc2fb4601ee35cd2b4f5b5f97319fc4864736f6c634300080700337bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a", - "deployedBytecode": "0x60806040526004361061037a5760003560e01c8063853828b6116101d1578063c7af335211610102578063dbe55e56116100a0578063e75292391161006f578063e752923914610b41578063ee7afe2d14610b57578063f1188e4014610b6c578063f6ca71b014610ba057600080fd5b8063dbe55e5614610aae578063dd505df614610ae2578063de34d71314610b16578063de5f626814610b2c57600080fd5b8063d059f6ef116100dc578063d059f6ef14610a37578063d38bfff414610a4e578063d9caed1214610a6e578063d9f00ec714610a8e57600080fd5b8063c7af3352146109d1578063c98517c5146109e6578063cceab75014610a0357600080fd5b8063a3b81e731161016f578063ab12edf511610149578063ab12edf51461095c578063ad1728cb1461097c578063bb1b918d14610991578063c2e1e3f4146109b157600080fd5b8063a3b81e73146108da578063a4f98af4146108fa578063aa388af61461090f57600080fd5b80639092c31c116101ab5780639092c31c146108295780639136616a1461085d57806396d538bb1461087d5780639da0e4621461089d57600080fd5b8063853828b6146107cf57806387bae867146107e45780638d7c0e461461080957600080fd5b80635d36b190116102ab5780636ef38795116102495780637b2d9b2c116102235780637b2d9b2c1461076e5780637b8962f71461078e578063842f5c46146107a45780638456cb59146107ba57600080fd5b80636ef387951461070e57806371a735f31461072e5780637260f8261461074e57600080fd5b8063630923831161028557806363092383146106a257806366e3667e146106b857806367c7066c146106ce5780636e811d38146106ee57600080fd5b80635d36b190146106395780635f5152261461064e5780636093d3801461066e57600080fd5b8063435356d1116103185780635205c380116102f25780635205c380146105ac578063579a7e1a146105cc5780635a063f63146106005780635c975abb1461061557600080fd5b8063435356d11461055657806347e7ef2414610576578063484be8121461059657600080fd5b80631072cbea116103545780631072cbea146104be57806322495dc8146104de5780633c864959146104fe578063430bf08a1461052257600080fd5b80630c340a24146104365780630ed57b3a146104685780630fc3b4c41461048857600080fd5b3661043157336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614806103de5750336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016145b61042f5760405162461bcd60e51b815260206004820152601e60248201527f657468206e6f742066726f6d20616c6c6f77656420636f6e747261637473000060448201526064015b60405180910390fd5b005b600080fd5b34801561044257600080fd5b5061044b610bc2565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561047457600080fd5b5061042f610483366004614158565b610bdf565b34801561049457600080fd5b5061044b6104a336600461411e565b609f602052600090815260409020546001600160a01b031681565b3480156104ca57600080fd5b5061042f6104d93660046141d2565b610c11565b3480156104ea57600080fd5b5061042f6104f93660046142c6565b610cce565b34801561050a57600080fd5b5061051460695481565b60405190815260200161045f565b34801561052e57600080fd5b5061044b7f000000000000000000000000000000000000000000000000000000000000000081565b34801561056257600080fd5b5061042f61057136600461423f565b610e18565b34801561058257600080fd5b5061042f6105913660046141d2565b610efd565b3480156105a257600080fd5b50610514606a5481565b3480156105b857600080fd5b5061042f6105c736600461439c565b61101c565b3480156105d857600080fd5b5061044b7f000000000000000000000000000000000000000000000000000000000000000081565b34801561060c57600080fd5b5061042f611078565b34801561062157600080fd5b5060335460ff165b604051901515815260200161045f565b34801561064557600080fd5b5061042f611117565b34801561065a57600080fd5b5061051461066936600461411e565b6111bd565b34801561067a57600080fd5b5061044b7f000000000000000000000000000000000000000000000000000000000000000081565b3480156106ae57600080fd5b50610514611c2081565b3480156106c457600080fd5b5061051460345481565b3480156106da57600080fd5b5060a35461044b906001600160a01b031681565b3480156106fa57600080fd5b5061042f61070936600461411e565b6112f1565b34801561071a57600080fd5b5061042f6107293660046141fe565b611379565b34801561073a57600080fd5b5061042f6107493660046144d4565b61188b565b34801561075a57600080fd5b5060365461044b906001600160a01b031681565b34801561077a57600080fd5b5061044b61078936600461439c565b611a84565b34801561079a57600080fd5b5061051460375481565b3480156107b057600080fd5b5061051460685481565b3480156107c657600080fd5b5061042f611aae565b3480156107db57600080fd5b5061042f611b77565b3480156107f057600080fd5b5060335461044b9061010090046001600160a01b031681565b34801561081557600080fd5b5061042f610824366004614555565b611d49565b34801561083557600080fd5b5061044b7f000000000000000000000000000000000000000000000000000000000000000081565b34801561086957600080fd5b5061042f61087836600461439c565b61221e565b34801561088957600080fd5b5061042f6108983660046141fe565b6123e9565b3480156108a957600080fd5b506108cd6108b836600461439c565b60356020526000908152604090205460ff1681565b60405161045f91906149c0565b3480156108e657600080fd5b5061042f6108f536600461411e565b612509565b34801561090657600080fd5b5061062961258b565b34801561091b57600080fd5b5061062961092a36600461411e565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0390811691161490565b34801561096857600080fd5b5061042f61097736600461459a565b6125ea565b34801561098857600080fd5b5061042f6126e6565b34801561099d57600080fd5b5061042f6109ac366004614420565b6127ac565b3480156109bd57600080fd5b5061042f6109cc36600461411e565b61291f565b3480156109dd57600080fd5b506106296129ac565b3480156109f257600080fd5b506105146801bc16d674ec80000081565b348015610a0f57600080fd5b5061044b7f000000000000000000000000000000000000000000000000000000000000000081565b348015610a4357600080fd5b506105146101075481565b348015610a5a57600080fd5b5061042f610a6936600461411e565b6129dd565b348015610a7a57600080fd5b5061042f610a89366004614191565b612a81565b348015610a9a57600080fd5b5061042f610aa93660046143b5565b612b14565b348015610aba57600080fd5b5061044b7f000000000000000000000000000000000000000000000000000000000000000081565b348015610aee57600080fd5b5061044b7f000000000000000000000000000000000000000000000000000000000000000081565b348015610b2257600080fd5b5061051460385481565b348015610b3857600080fd5b5061042f612d09565b348015610b4d57600080fd5b50610514606b5481565b348015610b6357600080fd5b5061042f612e76565b348015610b7857600080fd5b5061044b7f000000000000000000000000000000000000000000000000000000000000000081565b348015610bac57600080fd5b50610bb5612f00565b60405161045f9190614796565b6000610bda600080516020614d608339815191525490565b905090565b610be76129ac565b610c035760405162461bcd60e51b815260040161042690614a32565b610c0d8282612f62565b5050565b610c196129ac565b610c355760405162461bcd60e51b815260040161042690614a32565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b039081169083161415610cb25760405162461bcd60e51b815260206004820152601f60248201527f43616e6e6f74207472616e7366657220737570706f72746564206173736574006044820152606401610426565b610c0d610cbd610bc2565b6001600160a01b03841690836130c1565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b158015610d2757600080fd5b505afa158015610d3b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d5f919061413b565b6001600160a01b0316336001600160a01b031614610d8f5760405162461bcd60e51b815260040161042690614af2565b60405163bc26e7e560e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063bc26e7e590610de19030908790879087906004016146e6565b600060405180830381600087803b158015610dfb57600080fd5b505af1158015610e0f573d6000803e3d6000fd5b50505050505050565b610e206129ac565b610e3c5760405162461bcd60e51b815260040161042690614a32565b600054610100900460ff1680610e55575060005460ff16155b610eb85760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610426565b600054610100900460ff16158015610eda576000805461ffff19166101011790555b610ee5848484613113565b8015610ef7576000805461ff00191690555b50505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610f455760405162461bcd60e51b8152600401610426906149fb565b600080516020614d4083398151915280546002811415610f775760405162461bcd60e51b815260040161042690614aca565b600282557f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316846001600160a01b031614610ff05760405162461bcd60e51b8152602060048201526011602482015270155b9cdd5c1c1bdc9d195908185cdcd95d607a1b6044820152606401610426565b8261010760008282546110039190614c19565b90915550611013905084846131ce565b50600190555050565b6110246129ac565b6110405760405162461bcd60e51b815260040161042690614a32565b6040518181527fe26b067424903962f951f568e52ec9a3bbe1589526ea54a4e69ca6eaae1a4c779060200160405180910390a1603755565b60a3546001600160a01b031633146110d25760405162461bcd60e51b815260206004820152601b60248201527f43616c6c6572206973206e6f74207468652048617276657374657200000000006044820152606401610426565b600080516020614d40833981519152805460028114156111045760405162461bcd60e51b815260040161042690614aca565b60028255611110613260565b5060019055565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b0316146111b25760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b6064820152608401610426565b6111bb336134ae565b565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b0316146112345760405162461bcd60e51b8152602060048201526011602482015270155b9cdd5c1c1bdc9d195908185cdcd95d607a1b6044820152606401610426565b6040516370a0823160e01b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b15801561129357600080fd5b505afa1580156112a7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112cb9190614581565b6034546112e1906801bc16d674ec800000614c31565b6112eb9190614c19565b92915050565b6112f96129ac565b6113155760405162461bcd60e51b815260040161042690614a32565b6040516001600160a01b03821681527f83f29c79feb71f8fba9d0fbc4ba5f0982a28b6b1e868b3fc50e6400d100bca0f9060200160405180910390a1603380546001600160a01b0390921661010002610100600160a81b0319909216919091179055565b60335461010090046001600160a01b031633146113a85760405162461bcd60e51b815260040161042690614a93565b60335460ff16156113cb5760405162461bcd60e51b815260040161042690614a69565b60006113e0826801bc16d674ec800000614c31565b6040516370a0823160e01b81523060048201529091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b15801561144257600080fd5b505afa158015611456573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061147a9190614581565b8111156114bd5760405162461bcd60e51b81526020600482015260116024820152700d2dce6eaccccd2c6d2cadce840ae8aa89607b1b6044820152606401610426565b603754816038546114ce9190614c19565b111561151c5760405162461bcd60e51b815260206004820152601a60248201527f5374616b696e6720455448206f766572207468726573686f6c640000000000006044820152606401610426565b806038600082825461152e9190614c19565b9091555050604051632e1a7d4d60e01b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561159557600080fd5b505af11580156115a9573d6000803e3d6000fd5b505050506115b68161356f565b60408051600160f81b60208201526000602182018190526bffffffffffffffffffffffff193060601b16602c830152910160408051601f1981840301815291905290508260005b8181101561186c57600086868381811061161957611619614cf0565b905060200281019061162b9190614b6f565b6116359080614b29565b6040516116439291906146ba565b6040805191829003909120600081815260356020529182205490925060ff169081600381111561167557611675614cc4565b146116c25760405162461bcd60e51b815260206004820152601860248201527f56616c696461746f72206e6f74207265676973746572656400000000000000006044820152606401610426565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663228951186801bc16d674ec8000008a8a8781811061170d5761170d614cf0565b905060200281019061171f9190614b6f565b6117299080614b29565b898d8d8a81811061173c5761173c614cf0565b905060200281019061174e9190614b6f565b61175c906020810190614b29565b8f8f8c81811061176e5761176e614cf0565b90506020028101906117809190614b6f565b604001356040518863ffffffff1660e01b81526004016117a596959493929190614945565b6000604051808303818588803b1580156117be57600080fd5b505af11580156117d2573d6000803e3d6000fd5b50505050507ffeb31a79d38edb1b090d516e4df3e273651179c6f2c2ec53a9a22ae015b70ba988888581811061180a5761180a614cf0565b905060200281019061181c9190614b6f565b6118269080614b29565b6801bc16d674ec800000886040516118419493929190614994565b60405180910390a1506000908152603560205260409020805460ff19166001908117909155016115fd565b50806034600082825461187f9190614c19565b90915550505050505050565b60335461010090046001600160a01b031633146118ba5760405162461bcd60e51b815260040161042690614a93565b60335460ff16156118dd5760405162461bcd60e51b815260040161042690614a69565b60006035600087876040516118f39291906146ba565b604080519182900390912082526020820192909252016000205460ff169050600281600381111561192657611926614cc4565b1461196b5760405162461bcd60e51b815260206004820152601560248201527456616c696461746f72206e6f742065786974696e6760581b6044820152606401610426565b6040516312b3fc1960e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906312b3fc19906119bf9089908990899089908990600401614904565b600060405180830381600087803b1580156119d957600080fd5b505af11580156119ed573d6000803e3d6000fd5b505050507ff72821b8777f002ccdf6326f1242d9e0f762eb077668b67bebe640535378066d86868686604051611a26949392919061487b565b60405180910390a16003603560008888604051611a449291906146ba565b60408051918290039091208252602082019290925201600020805460ff19166001836003811115611a7757611a77614cc4565b0217905550505050505050565b60a48181548110611a9457600080fd5b6000918252602090912001546001600160a01b0316905081565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b158015611b0757600080fd5b505afa158015611b1b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b3f919061413b565b6001600160a01b0316336001600160a01b031614611b6f5760405162461bcd60e51b815260040161042690614af2565b6111bb61359c565b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161480611bc65750611bb1610bc2565b6001600160a01b0316336001600160a01b0316145b611c1e5760405162461bcd60e51b815260206004820152602360248201527f43616c6c6572206973206e6f7420746865205661756c74206f7220476f7665726044820152623737b960e91b6064820152608401610426565b600080516020614d4083398151915280546002811415611c505760405162461bcd60e51b815260040161042690614aca565b600282556040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b158015611cb657600080fd5b505afa158015611cca573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cee9190614581565b90508015611d4157611d417f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000083613611565b505060019055565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b158015611da257600080fd5b505afa158015611db6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dda919061413b565b6001600160a01b0316336001600160a01b031614611e0a5760405162461bcd60e51b815260040161042690614af2565b60335460ff16611e535760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610426565b43611c20606b54611e649190614c19565b10611ebf5760405162461bcd60e51b815260206004820152602560248201527f6d616e75616c6c794669784163636f756e74696e672063616c6c656420746f6f6044820152641039b7b7b760d91b6064820152608401610426565b6002198312158015611ed2575060038313155b8015611eec5750600083603454611ee99190614bd8565b12155b611f385760405162461bcd60e51b815260206004820152601760248201527f696e76616c69642076616c696461746f727344656c74610000000000000000006044820152606401610426565b6811ff6cf0fd15afffff198212158015611f5b57506811ff6cf0fd15b000008213155b8015611f755750600082606854611f729190614bd8565b12155b611fc15760405162461bcd60e51b815260206004820152601d60248201527f696e76616c696420636f6e73656e7375735265776172647344656c74610000006044820152606401610426565b68053444835ec580000081111561201a5760405162461bcd60e51b815260206004820152601960248201527f696e76616c69642077657468546f5661756c74416d6f756e74000000000000006044820152606401610426565b60408051848152602081018490529081018290527f80d022717ea022455c5886b8dd8a29c037570aae58aeb4d7b136d7a10ec2e4319060600160405180910390a1826034546120699190614bd8565b60345560685461207a908390614bd8565b60685543606b5580156121c8577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b1580156120e257600080fd5b505af11580156120f6573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb92506044019050602060405180830381600087803b15801561218657600080fd5b505af115801561219a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121be919061437f565b506121c881613709565b6121d26000613771565b6122115760405162461bcd60e51b815260206004820152601060248201526f333ab9b29039ba34b63610313637bbb760811b6044820152606401610426565b612219613bf0565b505050565b6122266129ac565b6122425760405162461bcd60e51b815260040161042690614a32565b60a05481106122835760405162461bcd60e51b815260206004820152600d60248201526c092dcecc2d8d2c840d2dcc8caf609b1b6044820152606401610426565b600060a0828154811061229857612298614cf0565b60009182526020808320909101546001600160a01b03908116808452609f90925260409092205460a054919350909116906122d590600190614c50565b8310156123575760a080546122ec90600190614c50565b815481106122fc576122fc614cf0565b60009182526020909120015460a080546001600160a01b03909216918590811061232857612328614cf0565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505b60a080548061236857612368614cda565b60008281526020808220600019908401810180546001600160a01b031990811690915593019093556001600160a01b03858116808352609f855260409283902080549094169093559051908416815290917f16b7600acff27e39a8a96056b3d533045298de927507f5c1d97e4accde60488c910160405180910390a2505050565b6123f16129ac565b61240d5760405162461bcd60e51b815260040161042690614a32565b8060005b818110156124c057600084848381811061242d5761242d614cf0565b9050602002016020810190612442919061411e565b6001600160a01b031614156124b05760405162461bcd60e51b815260206004820152602e60248201527f43616e206e6f742073657420616e20656d70747920616464726573732061732060448201526d30903932bbb0b932103a37b5b2b760911b6064820152608401610426565b6124b981614c93565b9050612411565b507f04c0b9649497d316554306e53678d5f5f5dbc3a06f97dec13ff4cfe98b986bbc60a484846040516124f5939291906147e3565b60405180910390a1610ef760a48484613e77565b6125116129ac565b61252d5760405162461bcd60e51b815260040161042690614a32565b6040516001600160a01b03821681527f3329861a0008b3348767567d2405492b997abd79a088d0f2cef6b1a09a8e7ff79060200160405180910390a1603680546001600160a01b0319166001600160a01b0392909216919091179055565b60335460009061010090046001600160a01b031633146125bd5760405162461bcd60e51b815260040161042690614a93565b60335460ff16156125e05760405162461bcd60e51b815260040161042690614a69565b610bda6001613771565b6125f26129ac565b61260e5760405162461bcd60e51b815260040161042690614a32565b808210801561262557506801bc16d674ec80000082105b801561263957506801bc16d674ec80000081105b80156126565750673782dace9d9000006126538383614c50565b10155b6126a25760405162461bcd60e51b815260206004820152601760248201527f696e636f7272656374206675736520696e74657276616c0000000000000000006044820152606401610426565b60408051838152602081018390527fcb8d24e46eb3c402bf344ee60a6576cba9ef2f59ea1af3b311520704924e901a910160405180910390a1606991909155606a55565b60405163095ea7b360e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015260001960248301527f0000000000000000000000000000000000000000000000000000000000000000169063095ea7b390604401602060405180830381600087803b15801561277157600080fd5b505af1158015612785573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127a9919061437f565b50565b60335461010090046001600160a01b031633146127db5760405162461bcd60e51b815260040161042690614a93565b60335460ff16156127fe5760405162461bcd60e51b815260040161042690614a69565b6040516301ba3ee760e21b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906306e8fb9c90612858908b908b908b908b908b908b908b908b906004016148a2565b600060405180830381600087803b15801561287257600080fd5b505af1158015612886573d6000803e3d6000fd5b505050506000603560008a8a6040516128a09291906146ba565b60408051918290039091208252602082019290925201600020805460ff191660018360038111156128d3576128d3614cc4565b02179055507f75c4a66b2c6c28cf46db7131182a812e4fbbb2f0591377aa83a737909a9b68c38888888860405161290d949392919061487b565b60405180910390a15050505050505050565b6129276129ac565b6129435760405162461bcd60e51b815260040161042690614a32565b60a354604080516001600160a01b03928316815291831660208301527fe48386b84419f4d36e0f96c10cc3510b6fb1a33795620c5098b22472bbe90796910160405180910390a160a380546001600160a01b0319166001600160a01b0392909216919091179055565b60006129c4600080516020614d608339815191525490565b6001600160a01b0316336001600160a01b031614905090565b6129e56129ac565b612a015760405162461bcd60e51b815260040161042690614a32565b612a29817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b0316612a49600080516020614d608339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614612ac95760405162461bcd60e51b8152600401610426906149fb565b600080516020614d4083398151915280546002811415612afb5760405162461bcd60e51b815260040161042690614aca565b60028255612b0a858585613611565b5060019055505050565b60335461010090046001600160a01b03163314612b435760405162461bcd60e51b815260040161042690614a93565b60335460ff1615612b665760405162461bcd60e51b815260040161042690614a69565b6000603560008686604051612b7c9291906146ba565b604080519182900390912082526020820192909252016000205460ff1690506001816003811115612baf57612baf614cc4565b14612bf35760405162461bcd60e51b815260206004820152601460248201527315985b1a59185d1bdc881b9bdd081cdd185ad95960621b6044820152606401610426565b604051633877322b60e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690633877322b90612c4590889088908890889060040161487b565b600060405180830381600087803b158015612c5f57600080fd5b505af1158015612c73573d6000803e3d6000fd5b505050507ff8821da16f5ed966b41e0343c3eff9903af782d74f99f1689dd9d4562b6545b385858585604051612cac949392919061487b565b60405180910390a16002603560008787604051612cca9291906146ba565b60408051918290039091208252602082019290925201600020805460ff19166001836003811115612cfd57612cfd614cc4565b02179055505050505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614612d515760405162461bcd60e51b8152600401610426906149fb565b600080516020614d4083398151915280546002811415612d835760405162461bcd60e51b815260040161042690614aca565b600282556040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b158015612de957600080fd5b505afa158015612dfd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e219190614581565b905060006101075482612e349190614c50565b90508015612e6c57610107829055612e6c7f0000000000000000000000000000000000000000000000000000000000000000826131ce565b5050600182555050565b6036546001600160a01b03163314612ed05760405162461bcd60e51b815260206004820152601960248201527f43616c6c6572206973206e6f7420746865204d6f6e69746f72000000000000006044820152606401610426565b6040517fe765a88a37047c5d793dce22b9ceb5a0f5039d276da139b4c7d29613f341f11090600090a16000603855565b606060a4805480602002602001604051908101604052809291908181526020018280548015612f5857602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612f3a575b5050505050905090565b6001600160a01b038281166000908152609f60205260409020541615612fbf5760405162461bcd60e51b81526020600482015260126024820152711c151bdad95b88185b1c9958591e481cd95d60721b6044820152606401610426565b6001600160a01b03821615801590612fdf57506001600160a01b03811615155b61301f5760405162461bcd60e51b8152602060048201526011602482015270496e76616c69642061646472657373657360781b6044820152606401610426565b6001600160a01b038281166000818152609f6020908152604080832080549587166001600160a01b0319968716811790915560a0805460018101825594527f78fdc8d422c49ced035a9edf18d00d3c6a8d81df210f3e5e448e045e77b41e8890930180549095168417909455925190815290917fef6485b84315f9b1483beffa32aae9a0596890395e3d7521f1c5fbb51790e765910160405180910390a25050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052612219908490613c6a565b82516131269060a4906020860190613eda565b508151815181146131705760405162461bcd60e51b8152602060048201526014602482015273496e76616c696420696e7075742061727261797360601b6044820152606401610426565b60005b818110156131c7576131b784828151811061319057613190614cf0565b60200260200101518483815181106131aa576131aa614cf0565b6020026020010151612f62565b6131c081614c93565b9050613173565b5050505050565b600081116132175760405162461bcd60e51b81526020600482015260166024820152754d757374206465706f73697420736f6d657468696e6760501b6044820152606401610426565b6040805160008152602081018390526001600160a01b038416917f5548c837ab068cf56a2c2479df0882a4922fd203edb7517321831d95078c5f62910160405180910390a25050565b60335460ff16156132835760405162461bcd60e51b815260040161042690614a69565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663e52253816040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156132e057600080fd5b505af11580156132f4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133189190614581565b905060006068548261332a9190614c19565b90508047101561337c5760405162461bcd60e51b815260206004820152601860248201527f696e73756666696369656e74206574682062616c616e636500000000000000006044820152606401610426565b8015610c0d5760006068819055507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b1580156133e557600080fd5b505af11580156133f9573d6000803e3d6000fd5b505060a354604080516001600160a01b0392831681527f0000000000000000000000000000000000000000000000000000000000000000909216602083015281018590527ff6c07a063ed4e63808eb8da7112d46dbcd38de2b40a73dbcc9353c5a94c723539350606001915061346c9050565b60405180910390a160a354610c0d906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081169116836130c1565b6001600160a01b0381166135045760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f7220697320616464726573732830290000000000006044820152606401610426565b806001600160a01b0316613524600080516020614d608339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a36127a981600080516020614d6083398151915255565b600061357e8261010754613d3c565b90508061010760008282546135939190614c50565b90915550505050565b60335460ff16156135bf5760405162461bcd60e51b815260040161042690614a69565b6033805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586135f43390565b6040516001600160a01b03909116815260200160405180910390a1565b600081116136615760405162461bcd60e51b815260206004820152601760248201527f4d75737420776974686472617720736f6d657468696e670000000000000000006044820152606401610426565b6001600160a01b0383166136b05760405162461bcd60e51b8152602060048201526016602482015275135d5cdd081cdc1958da599e481c9958da5c1a595b9d60521b6044820152606401610426565b6040805160008152602081018390526001600160a01b038416917f2717ead6b9200dd235aad468c9809ea400fe33ac69b5bfaa6d3e90fc922b6398910160405180910390a26122196001600160a01b03831684836130c1565b6040805160008152602081018390526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016917f2717ead6b9200dd235aad468c9809ea400fe33ac69b5bfaa6d3e90fc922b6398910160405180910390a250565b6000606854471015613786576112eb82613d54565b6000606854476137969190614c50565b9050600191506801bc16d674ec80000081106139735760006801bc16d674ec8000008204905080603460008282546137ce9190614c50565b90915550600090506137e9826801bc16d674ec800000614c31565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b15801561384657600080fd5b505af115801561385a573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb92506044019050602060405180830381600087803b1580156138ea57600080fd5b505af11580156138fe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613922919061437f565b5061392c81613709565b60345460408051848152602081019290925281018290527fbe7040030ff7b347853214bf49820c6d455fedf58f3815f85c7bc5216993682b9060600160405180910390a150505b6000606854476139839190614c50565b90506801bc16d674ec80000081106139d55760405162461bcd60e51b8152602060048201526015602482015274756e6578706563746564206163636f756e74696e6760581b6044820152606401610426565b806139e1575050919050565b606954811015613a3b5780606860008282546139fd9190614c19565b90915550506040518181527f7a745a2c63a535068f52ceca27debd5297bbad5f7f37ec53d044a59d0362445d906020015b60405180910390a1613be9565b606a54811115613bd8577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b158015613aa057600080fd5b505af1158015613ab4573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb92506044019050602060405180830381600087803b158015613b4457600080fd5b505af1158015613b58573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b7c919061437f565b50600160346000828254613b909190614c50565b90915550613b9f905081613709565b60345460408051918252602082018390527f6aa7e30787b26429ced603a7aba8b19c4b5d5bcf29a3257da953c8d53bcaa3a69101613a2e565b613be184613d54565b949350505050565b5050919050565b60335460ff16613c395760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610426565b6033805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa336135f4565b6000613cbf826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316613d6c9092919063ffffffff16565b8051909150156122195780806020019051810190613cdd919061437f565b6122195760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610426565b6000818310613d4b5781613d4d565b825b9392505050565b60008115613d6457613d6461359c565b506000919050565b6060613be1848460008585843b613dc55760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610426565b600080866001600160a01b03168587604051613de191906146ca565b60006040518083038185875af1925050503d8060008114613e1e576040519150601f19603f3d011682016040523d82523d6000602084013e613e23565b606091505b5091509150613e33828286613e3e565b979650505050505050565b60608315613e4d575081613d4d565b825115613e5d5782518084602001fd5b8160405162461bcd60e51b815260040161042691906149e8565b828054828255906000526020600020908101928215613eca579160200282015b82811115613eca5781546001600160a01b0319166001600160a01b03843516178255602090920191600190910190613e97565b50613ed6929150613f2f565b5090565b828054828255906000526020600020908101928215613eca579160200282015b82811115613eca57825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190613efa565b5b80821115613ed65760008155600101613f30565b60008083601f840112613f5657600080fd5b5081356001600160401b03811115613f6d57600080fd5b6020830191508360208260051b8501011115613f8857600080fd5b9250929050565b600082601f830112613fa057600080fd5b81356020613fb5613fb083614bb5565b614b85565b80838252828201915082860187848660051b8901011115613fd557600080fd5b60005b85811015613ffd578135613feb81614d1c565b84529284019290840190600101613fd8565b5090979650505050505050565b60008083601f84011261401c57600080fd5b5081356001600160401b0381111561403357600080fd5b602083019150836020828501011115613f8857600080fd5b600060a0828403121561405d57600080fd5b50919050565b600060a0828403121561407557600080fd5b60405160a081018181106001600160401b038211171561409757614097614d06565b6040529050806140a6836140ee565b81526140b460208401614107565b60208201526140c560408401614107565b604082015260608301356140d881614d31565b6060820152608092830135920191909152919050565b803563ffffffff8116811461410257600080fd5b919050565b80356001600160401b038116811461410257600080fd5b60006020828403121561413057600080fd5b8135613d4d81614d1c565b60006020828403121561414d57600080fd5b8151613d4d81614d1c565b6000806040838503121561416b57600080fd5b823561417681614d1c565b9150602083013561418681614d1c565b809150509250929050565b6000806000606084860312156141a657600080fd5b83356141b181614d1c565b925060208401356141c181614d1c565b929592945050506040919091013590565b600080604083850312156141e557600080fd5b82356141f081614d1c565b946020939093013593505050565b6000806020838503121561421157600080fd5b82356001600160401b0381111561422757600080fd5b61423385828601613f44565b90969095509350505050565b60008060006060848603121561425457600080fd5b83356001600160401b038082111561426b57600080fd5b61427787838801613f8f565b9450602086013591508082111561428d57600080fd5b61429987838801613f8f565b935060408601359150808211156142af57600080fd5b506142bc86828701613f8f565b9150509250925092565b600080600060e084860312156142db57600080fd5b83356001600160401b038111156142f157600080fd5b8401601f8101861361430257600080fd5b80356020614312613fb083614bb5565b8083825282820191508285018a848660051b880101111561433257600080fd5b600095505b8486101561435c5761434881614107565b835260019590950194918301918301614337565b509650508601359350614376915086905060408601614063565b90509250925092565b60006020828403121561439157600080fd5b8151613d4d81614d31565b6000602082840312156143ae57600080fd5b5035919050565b600080600080604085870312156143cb57600080fd5b84356001600160401b03808211156143e257600080fd5b6143ee8883890161400a565b9096509450602087013591508082111561440757600080fd5b5061441487828801613f44565b95989497509550505050565b600080600080600080600080610120898b03121561443d57600080fd5b88356001600160401b038082111561445457600080fd5b6144608c838d0161400a565b909a50985060208b013591508082111561447957600080fd5b6144858c838d01613f44565b909850965060408b013591508082111561449e57600080fd5b506144ab8b828c0161400a565b909550935050606089013591506144c58a60808b0161404b565b90509295985092959890939650565b600080600080600060e086880312156144ec57600080fd5b85356001600160401b038082111561450357600080fd5b61450f89838a0161400a565b9097509550602088013591508082111561452857600080fd5b5061453588828901613f44565b90945092506145499050876040880161404b565b90509295509295909350565b60008060006060848603121561456a57600080fd5b505081359360208301359350604090920135919050565b60006020828403121561459357600080fd5b5051919050565b600080604083850312156145ad57600080fd5b50508035926020909101359150565b8183526000602080850194508260005b858110156145f8576001600160401b036145e583614107565b16875295820195908201906001016145cc565b509495945050505050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b60008151808452614644816020860160208601614c67565b601f01601f19169290920160200192915050565b63ffffffff614666826140ee565b16825261467560208201614107565b6001600160401b0380821660208501528061469260408501614107565b166040850152505060608101356146a881614d31565b15156060830152608090810135910152565b8183823760009101908152919050565b600082516146dc818460208701614c67565b9190910192915050565b6001600160a01b03851681526101006020808301829052855191830182905260009161012084019187810191845b818110156147395783516001600160401b031685529382019392820192600101614714565b505082935086604086015263ffffffff865116606086015280860151925050506001600160401b0380821660808501528060408601511660a085015250506060830151151560c0830152608083015160e083015295945050505050565b6020808252825182820181905260009190848201906040850190845b818110156147d75783516001600160a01b0316835292840192918401916001016147b2565b50909695505050505050565b6000604082016040835280865480835260608501915087600052602092508260002060005b8281101561482d5781546001600160a01b031684529284019260019182019101614808565b505050838103828501528481528590820160005b8681101561486f57823561485481614d1c565b6001600160a01b031682529183019190830190600101614841565b50979650505050505050565b60408152600061488f604083018688614603565b8281036020840152613e338185876145bc565b60006101208083526148b78184018b8d614603565b905082810360208401526148cc81898b6145bc565b905082810360408401526148e1818789614603565b9150508360608301526148f76080830184614658565b9998505050505050505050565b60e08152600061491860e083018789614603565b828103602084015261492b8186886145bc565b91505061493b6040830184614658565b9695505050505050565b60808152600061495960808301888a614603565b828103602084015261496b818861462c565b90508281036040840152614980818688614603565b915050826060830152979650505050505050565b6060815260006149a8606083018688614603565b8460208401528281036040840152613e33818561462c565b60208101600483106149e257634e487b7160e01b600052602160045260246000fd5b91905290565b602081526000613d4d602083018461462c565b60208082526017908201527f43616c6c6572206973206e6f7420746865205661756c74000000000000000000604082015260600190565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b60208082526010908201526f14185d5cd8589b194e881c185d5cd95960821b604082015260600190565b6020808252601d908201527f43616c6c6572206973206e6f7420746865205265676973747261746f72000000604082015260600190565b6020808252600e908201526d1499595b9d1c985b9d0818d85b1b60921b604082015260600190565b6020808252601c908201527f43616c6c6572206973206e6f7420746865205374726174656769737400000000604082015260600190565b6000808335601e19843603018112614b4057600080fd5b8301803591506001600160401b03821115614b5a57600080fd5b602001915036819003821315613f8857600080fd5b60008235605e198336030181126146dc57600080fd5b604051601f8201601f191681016001600160401b0381118282101715614bad57614bad614d06565b604052919050565b60006001600160401b03821115614bce57614bce614d06565b5060051b60200190565b600080821280156001600160ff1b0384900385131615614bfa57614bfa614cae565b600160ff1b8390038412811615614c1357614c13614cae565b50500190565b60008219821115614c2c57614c2c614cae565b500190565b6000816000190483118215151615614c4b57614c4b614cae565b500290565b600082821015614c6257614c62614cae565b500390565b60005b83811015614c82578181015183820152602001614c6a565b83811115610ef75750506000910152565b6000600019821415614ca757614ca7614cae565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b03811681146127a957600080fd5b80151581146127a957600080fdfe53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac45357bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa264697066735822122036fc9aa0014d1fbbc8fbac98689c50c4cc2fb4601ee35cd2b4f5b5f97319fc4864736f6c63430008070033", + "numDeployments": 6, + "solcInputHash": "2f3753d8399260cc3346b6a657c1cb6c", + "metadata": "{\"compiler\":{\"version\":\"0.8.7+commit.e28d00a7\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"platformAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"vaultAddress\",\"type\":\"address\"}],\"internalType\":\"struct InitializableAbstractStrategy.BaseStrategyConfig\",\"name\":\"_baseConfig\",\"type\":\"tuple\"},{\"internalType\":\"address\",\"name\":\"_wethAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_ssvToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_ssvNetwork\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_feeAccumulator\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_beaconChainDepositContract\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"AccountingConsensusRewards\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"noOfValidators\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"remainingValidators\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"wethSentToVault\",\"type\":\"uint256\"}],\"name\":\"AccountingFullyWithdrawnValidator\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"validatorsDelta\",\"type\":\"int256\"},{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"consensusRewardsDelta\",\"type\":\"int256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"wethToVault\",\"type\":\"uint256\"}],\"name\":\"AccountingManuallyFixed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"remainingValidators\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"wethSentToVault\",\"type\":\"uint256\"}],\"name\":\"AccountingValidatorSlashed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"Deposit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"pubKeyHash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"pubKey\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"withdrawal_credentials\",\"type\":\"bytes\"}],\"name\":\"ETHStaked\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"start\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"end\",\"type\":\"uint256\"}],\"name\":\"FuseIntervalUpdated\",\"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\":\"address\",\"name\":\"_oldHarvesterAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_newHarvesterAddress\",\"type\":\"address\"}],\"name\":\"HarvesterAddressesUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"}],\"name\":\"PTokenAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"}],\"name\":\"PTokenRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Paused\",\"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\":true,\"internalType\":\"address\",\"name\":\"newAddress\",\"type\":\"address\"}],\"name\":\"RegistratorChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"_oldAddresses\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"_newAddresses\",\"type\":\"address[]\"}],\"name\":\"RewardTokenAddressesUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"rewardToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"RewardTokenCollected\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"pubKeyHash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"pubKey\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"}],\"name\":\"SSVValidatorExitCompleted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"pubKeyHash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"pubKey\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"}],\"name\":\"SSVValidatorExitInitiated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"pubKeyHash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"pubKey\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"}],\"name\":\"SSVValidatorRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"StakeETHTallyReset\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"StakeETHThresholdChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newAddress\",\"type\":\"address\"}],\"name\":\"StakingMonitorChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Unpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"Withdrawal\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"BEACON_CHAIN_DEPOSIT_CONTRACT\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_ACCUMULATOR_ADDRESS\",\"outputs\":[{\"internalType\":\"address payable\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MAX_STAKE\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MIN_FIX_ACCOUNTING_CADENCE\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"SSV_NETWORK_ADDRESS\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"SSV_TOKEN_ADDRESS\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"VAULT_ADDRESS\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"WETH_TOKEN_ADDRESS\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"activeDepositedValidators\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"assetToPToken\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"}],\"name\":\"checkBalance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"claimGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"collectRewardTokens\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"consensusRewards\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"depositAll\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"validatorCount\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"networkFeeIndex\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"index\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"active\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"internalType\":\"struct Cluster\",\"name\":\"cluster\",\"type\":\"tuple\"}],\"name\":\"depositSSV\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"depositedWethAccountedFor\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"doAccounting\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"accountingValid\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"publicKey\",\"type\":\"bytes\"},{\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"}],\"name\":\"exitSsvValidator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fuseIntervalEnd\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fuseIntervalStart\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRewardTokenAddresses\",\"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\":\"harvesterAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"_rewardTokenAddresses\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"_assets\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"_pTokens\",\"type\":\"address[]\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isGovernor\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastFixAccountingBlockNumber\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"int256\",\"name\":\"_validatorsDelta\",\"type\":\"int256\"},{\"internalType\":\"int256\",\"name\":\"_consensusRewardsDelta\",\"type\":\"int256\"},{\"internalType\":\"uint256\",\"name\":\"_ethToVaultAmount\",\"type\":\"uint256\"}],\"name\":\"manuallyFixAccounting\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"paused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"platformAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"publicKey\",\"type\":\"bytes\"},{\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"},{\"internalType\":\"bytes\",\"name\":\"sharesData\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"validatorCount\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"networkFeeIndex\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"index\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"active\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"internalType\":\"struct Cluster\",\"name\":\"cluster\",\"type\":\"tuple\"}],\"name\":\"registerSsvValidator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_assetIndex\",\"type\":\"uint256\"}],\"name\":\"removePToken\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"publicKey\",\"type\":\"bytes\"},{\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"validatorCount\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"networkFeeIndex\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"index\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"active\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"internalType\":\"struct Cluster\",\"name\":\"cluster\",\"type\":\"tuple\"}],\"name\":\"removeSsvValidator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"resetStakeETHTally\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"rewardTokenAddresses\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"safeApproveAllTokens\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_fuseIntervalStart\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_fuseIntervalEnd\",\"type\":\"uint256\"}],\"name\":\"setFuseInterval\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_harvesterAddress\",\"type\":\"address\"}],\"name\":\"setHarvesterAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"}],\"name\":\"setPTokenAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"setRegistrator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"_rewardTokenAddresses\",\"type\":\"address[]\"}],\"name\":\"setRewardTokenAddresses\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"setStakeETHThreshold\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"setStakingMonitor\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"stakeETHTally\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"stakeETHThreshold\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"pubkey\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"depositDataRoot\",\"type\":\"bytes32\"}],\"internalType\":\"struct ValidatorStakeData[]\",\"name\":\"validators\",\"type\":\"tuple[]\"}],\"name\":\"stakeEth\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"stakingMonitor\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"}],\"name\":\"supportsAsset\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"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\":\"validatorRegistrator\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"validatorsStates\",\"outputs\":[{\"internalType\":\"enum ValidatorRegistrator.VALIDATOR_STATE\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"vaultAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"withdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdrawAll\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"author\":\"Origin Protocol Inc\",\"details\":\"This contract handles WETH and ETH and in some operations interchanges between the two. Any WETH that is on the contract across multiple blocks (and not just transitory within a transaction) is considered an asset. Meaning deposits increase the balance of the asset and withdrawal decrease it. As opposed to all our other strategies the WETH doesn't immediately get deposited into an underlying strategy and can be present across multiple blocks waiting to be unwrapped to ETH and staked to validators. This separation of WETH and ETH is required since the rewards (reward token) is also in ETH. To simplify the accounting of WETH there is another difference in behavior compared to the other strategies. To withdraw WETH asset - exit message is posted to validators and the ETH hits this contract with multiple days delay. In order to simplify the WETH accounting upon detection of such an event the ValidatorAccountant immediately wraps ETH to WETH and sends it to the Vault. On the other hand any ETH on the contract (across multiple blocks) is there either: - as a result of already accounted for consensus rewards - as a result of not yet accounted for consensus rewards - as a results of not yet accounted for full validator withdrawals (or validator slashes) Even though the strategy assets and rewards are a very similar asset the consensus layer rewards and the execution layer rewards are considered rewards and those are dripped to the Vault over a configurable time interval and not immediately.\",\"kind\":\"dev\",\"methods\":{\"checkBalance(address)\":{\"params\":{\"_asset\":\"Address of weth asset\"},\"returns\":{\"balance\":\" Total value of (W)ETH\"}},\"constructor\":{\"params\":{\"_baseConfig\":\"Base strategy config with platformAddress (ERC-4626 Vault contract), eg sfrxETH or sDAI, and vaultAddress (OToken Vault contract), eg VaultProxy or OETHVaultProxy\",\"_beaconChainDepositContract\":\"Address of the beacon chain deposit contract\",\"_feeAccumulator\":\"Address of the fee accumulator receiving execution layer validator rewards\",\"_ssvNetwork\":\"Address of the SSV Network contract\",\"_ssvToken\":\"Address of the Erc20 SSV Token contract\",\"_wethAddress\":\"Address of the Erc20 WETH Token contract\"}},\"deposit(address,uint256)\":{\"params\":{\"_amount\":\"Amount of assets that were transferred to the strategy by the vault.\",\"_asset\":\"Address of asset to deposit. Has to be WETH.\"}},\"depositSSV(uint64[],uint256,(uint32,uint64,uint64,bool,uint256))\":{\"details\":\"A SSV cluster is defined by the SSVOwnerAddress and the set of operatorIds. uses \\\"onlyStrategist\\\" modifier so continuous front-running can't DOS our maintenance service that tries to top up SSV tokens.\",\"params\":{\"cluster\":\"The SSV cluster details that must be derived from emitted events from the SSVNetwork contract.\"}},\"doAccounting()\":{\"details\":\"This function could in theory be permission-less but lets allow only the Registrator (Defender Action) to call it for now.\",\"returns\":{\"accountingValid\":\"true if accounting was successful, false if fuse is blown\"}},\"getRewardTokenAddresses()\":{\"returns\":{\"_0\":\"address[] the reward token addresses.\"}},\"initialize(address[],address[],address[])\":{\"params\":{\"_assets\":\"Addresses of initial supported assets\",\"_pTokens\":\"Platform Token corresponding addresses\",\"_rewardTokenAddresses\":\"Address of reward token for platform\"}},\"manuallyFixAccounting(int256,int256,uint256)\":{\"details\":\"There is a case when a validator(s) gets slashed so much that the eth swept from the beacon chain enters the fuse area and there are no consensus rewards on the contract to \\\"dip into\\\"/use. To increase the amount of unaccounted ETH over the fuse end interval we need to reduce the amount of active deposited validators and immediately send WETH to the vault, so it doesn't interfere with further accounting.\",\"params\":{\"_consensusRewardsDelta\":\"adjust the accounted for consensus rewards up or down\",\"_ethToVaultAmount\":\"the amount of ETH that gets wrapped into WETH and sent to the Vault\",\"_validatorsDelta\":\"adjust the active validators by up to plus three or minus three\"}},\"paused()\":{\"details\":\"Returns true if the contract is paused, and false otherwise.\"},\"removePToken(uint256)\":{\"params\":{\"_assetIndex\":\"Index of the asset to be removed\"}},\"setHarvesterAddress(address)\":{\"params\":{\"_harvesterAddress\":\"Address of the harvester contract.\"}},\"setPTokenAddress(address,address)\":{\"params\":{\"_asset\":\"Address for the asset\",\"_pToken\":\"Address for the corresponding platform token\"}},\"setRewardTokenAddresses(address[])\":{\"params\":{\"_rewardTokenAddresses\":\"Array of reward token addresses\"}},\"stakeEth((bytes,bytes,bytes32)[])\":{\"params\":{\"validators\":\"A list of validator data needed to stake. The `ValidatorStakeData` struct contains the pubkey, signature and depositDataRoot. Only the registrator can call this function.\"}},\"supportsAsset(address)\":{\"params\":{\"_asset\":\"The address of the asset token.\"}},\"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\"}},\"withdraw(address,address,uint256)\":{\"params\":{\"_amount\":\"Amount of WETH to withdraw\",\"_asset\":\"WETH to withdraw\",\"_recipient\":\"Address to receive withdrawn assets\"}}},\"stateVariables\":{\"FEE_ACCUMULATOR_ADDRESS\":{\"details\":\"this address will receive Execution layer rewards - These are rewards earned for executing transactions on the Ethereum network as part of block proposals. They include priority fees (fees paid by users for their transactions to be included) and MEV rewards (rewards for arranging transactions in a way that benefits the validator).\"},\"depositedWethAccountedFor\":{\"details\":\"This contract receives WETH as the deposit asset, but unlike other strategies doesn't immediately deposit it to an underlying platform. Rather a special privilege account stakes it to the validators. For that reason calling WETH.balanceOf(this) in a deposit function can contain WETH that has just been deposited and also WETH that has previously been deposited. To keep a correct count we need to keep track of WETH that has already been accounted for. This value represents the amount of WETH balance of this contract that has already been accounted for by the deposit events. It is important to note that this variable is not concerned with WETH that is a result of full/partial withdrawal of the validators. It is strictly concerned with WETH that has been deposited and is waiting to be staked.\"}},\"title\":\"Native Staking SSV Strategy\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"BEACON_CHAIN_DEPOSIT_CONTRACT()\":{\"notice\":\"The address of the beacon chain deposit contract\"},\"FEE_ACCUMULATOR_ADDRESS()\":{\"notice\":\"Fee collector address\"},\"MAX_STAKE()\":{\"notice\":\"The maximum amount of ETH that can be staked by a validator\"},\"MIN_FIX_ACCOUNTING_CADENCE()\":{\"notice\":\"The minimum amount of blocks that need to pass between two calls to manuallyFixAccounting\"},\"SSV_NETWORK_ADDRESS()\":{\"notice\":\"The address of the SSV Network contract used to interface with\"},\"SSV_TOKEN_ADDRESS()\":{\"notice\":\"SSV ERC20 token that serves as a payment for operating SSV validators\"},\"VAULT_ADDRESS()\":{\"notice\":\"Address of the OETH Vault proxy contract\"},\"WETH_TOKEN_ADDRESS()\":{\"notice\":\"The address of the Wrapped ETH (WETH) token contract\"},\"activeDepositedValidators()\":{\"notice\":\"The number of validators that have 32 (!) ETH actively deposited. When a new deposit to a validator happens this number increases, when a validator exit is detected this number decreases.\"},\"assetToPToken(address)\":{\"notice\":\"asset => pToken (Platform Specific Token Address)\"},\"checkBalance(address)\":{\"notice\":\"Returns the total value of (W)ETH that is staked to the validators and WETH deposits that are still to be staked. This does not include ETH from consensus rewards sitting in this strategy or ETH from MEV rewards in the FeeAccumulator. These rewards are harvested and sent to the Dripper so will eventually be sent to the Vault as WETH.\"},\"claimGovernance()\":{\"notice\":\"Claim Governance of the contract to a new account (`newGovernor`). Can only be called by the new Governor.\"},\"collectRewardTokens()\":{\"notice\":\"Collect accumulated reward token and send to Vault.\"},\"consensusRewards()\":{\"notice\":\"Keeps track of the total consensus rewards swept from the beacon chain\"},\"deposit(address,uint256)\":{\"notice\":\"Unlike other strategies, this does not deposit assets into the underlying platform. It just checks the asset is WETH and emits the Deposit event. To deposit WETH into validators `registerSsvValidator` and `stakeEth` must be used. Will NOT revert if the strategy is paused from an accounting failure.\"},\"depositAll()\":{\"notice\":\"Unlike other strategies, this does not deposit assets into the underlying platform. It just emits the Deposit event. To deposit WETH into validators `registerSsvValidator` and `stakeEth` must be used. Will NOT revert if the strategy is paused from an accounting failure.\"},\"depositSSV(uint64[],uint256,(uint32,uint64,uint64,bool,uint256))\":{\"notice\":\"Deposits more SSV Tokens to the SSV Network contract which is used to pay the SSV Operators.\"},\"doAccounting()\":{\"notice\":\"This notion page offers a good explanation of how the accounting functions https://www.notion.so/originprotocol/Limited-simplified-native-staking-accounting-67a217c8420d40678eb943b9da0ee77d In short, after dividing by 32, if the ETH remaining on the contract falls between 0 and fuseIntervalStart, the accounting function will treat that ETH as Beacon chain consensus rewards. On the contrary, if after dividing by 32, the ETH remaining on the contract falls between fuseIntervalEnd and 32, the accounting function will treat that as a validator slashing.Perform the accounting attributing beacon chain ETH to either full or partial withdrawals. Returns true when accounting is valid and fuse isn't \\\"blown\\\". Returns false when fuse is blown.\"},\"exitSsvValidator(bytes,uint64[])\":{\"notice\":\"Exit a validator from the Beacon chain. The staked ETH will eventually swept to this native staking strategy. Only the registrator can call this function.\"},\"fuseIntervalEnd()\":{\"notice\":\"end of fuse interval\"},\"fuseIntervalStart()\":{\"notice\":\"start of fuse interval\"},\"getRewardTokenAddresses()\":{\"notice\":\"Get the reward token addresses.\"},\"governor()\":{\"notice\":\"Returns the address of the current Governor.\"},\"harvesterAddress()\":{\"notice\":\"Address of the Harvester contract allowed to collect reward tokens\"},\"initialize(address[],address[],address[])\":{\"notice\":\"initialize function, to set up initial internal state\"},\"isGovernor()\":{\"notice\":\"Returns true if the caller is the current Governor.\"},\"lastFixAccountingBlockNumber()\":{\"notice\":\"last block number manuallyFixAccounting has been called\"},\"manuallyFixAccounting(int256,int256,uint256)\":{\"notice\":\"Allow the Strategist to fix the accounting of this strategy and unpause.\"},\"platformAddress()\":{\"notice\":\"Address of the underlying platform\"},\"registerSsvValidator(bytes,uint64[],bytes,uint256,(uint32,uint64,uint64,bool,uint256))\":{\"notice\":\"Registers a new validator in the SSV Cluster. Only the registrator can call this function.\"},\"removePToken(uint256)\":{\"notice\":\"Remove a supported asset by passing its index. This method can only be called by the system Governor\"},\"removeSsvValidator(bytes,uint64[],(uint32,uint64,uint64,bool,uint256))\":{\"notice\":\"Remove a validator from the SSV Cluster. Make sure `exitSsvValidator` is called before and the validate has exited the Beacon chain. If removed before the validator has exited the beacon chain will result in the validator being slashed. Only the registrator can call this function.\"},\"resetStakeETHTally()\":{\"notice\":\"Reset the stakeETHTally\"},\"rewardTokenAddresses(uint256)\":{\"notice\":\"Address of the reward tokens. eg CRV, BAL, CVX, AURA\"},\"safeApproveAllTokens()\":{\"notice\":\"Approves the SSV Network contract to transfer SSV tokens for deposits\"},\"setFuseInterval(uint256,uint256)\":{\"notice\":\"set fuse interval values\"},\"setHarvesterAddress(address)\":{\"notice\":\"Set the Harvester contract that can collect rewards.\"},\"setPTokenAddress(address,address)\":{\"notice\":\"Provide support for asset by passing its pToken address. This method can only be called by the system Governor\"},\"setRegistrator(address)\":{\"notice\":\"Set the address of the registrator which can register, exit and remove validators\"},\"setRewardTokenAddresses(address[])\":{\"notice\":\"Set the reward token addresses. Any old addresses will be overwritten.\"},\"setStakeETHThreshold(uint256)\":{\"notice\":\"Set the amount of ETH that can be staked before staking monitor\"},\"setStakingMonitor(address)\":{\"notice\":\"Set the address of the staking monitor that is allowed to reset stakeETHTally\"},\"stakeETHTally()\":{\"notice\":\"Amount of ETH that can has been staked since the last governor approval.\"},\"stakeETHThreshold()\":{\"notice\":\"Amount of ETH that can be staked before staking on the contract is suspended and the governor needs to approve further staking\"},\"stakeEth((bytes,bytes,bytes32)[])\":{\"notice\":\"Stakes WETH to the node validators\"},\"stakingMonitor()\":{\"notice\":\"The account that is allowed to modify stakeETHThreshold and reset stakeETHTally\"},\"supportsAsset(address)\":{\"notice\":\"Returns bool indicating whether asset is supported by strategy.\"},\"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 strategy contracts, i.e. mistaken sends.\"},\"validatorRegistrator()\":{\"notice\":\"Address of the registrator - allowed to register, exit and remove validators\"},\"validatorsStates(bytes32)\":{\"notice\":\"State of the validators keccak256(pubKey) => state\"},\"vaultAddress()\":{\"notice\":\"Address of the OToken vault\"},\"withdraw(address,address,uint256)\":{\"notice\":\"Withdraw WETH from this contract. Used only if some WETH for is lingering on the contract. That can happen when: - the deposit was not a multiple of 32 WETH - someone sent WETH directly to this contract Will NOT revert if the strategy is paused from an accounting failure.\"},\"withdrawAll()\":{\"notice\":\"transfer all WETH deposits back to the vault. This does not withdraw from the validators. That has to be done separately with the `exitSsvValidator` and `removeSsvValidator` operations. This does not withdraw any execution rewards from the FeeAccumulator or consensus rewards in this strategy. Any ETH in this strategy that was swept from a full validator withdrawal will not be withdrawn. ETH from full validator withdrawals is sent to the Vault using `doAccounting`. Will NOT revert if the strategy is paused from an accounting failure.\"}},\"notice\":\"Strategy to deploy funds into DVT validators powered by the SSV Network\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol\":\"NativeStakingSSVStrategy\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"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\",\"keccak256\":\"0xe68ed7fb8766ed1e888291f881e36b616037f852b37d96877045319ad298ba87\",\"license\":\"MIT\"},\"@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/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\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@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\",\"keccak256\":\"0xfaad496c1c944b6259b7dc70b4865eb1775d6402bc0c81b38a0b24d9f525ae37\",\"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/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\",\"keccak256\":\"0x598f90bdbc854250bbd5991426bfb43367207e64e33109c41aa8b54323fd8d8e\",\"license\":\"MIT\"},\"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 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 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 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\",\"keccak256\":\"0xbef02bd5257e61dec0a6be4b1531064a7fdfeb4043885443a1902fb5d1b23e1b\",\"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/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 function removeAsset(address _asset) external;\\n}\\n\",\"keccak256\":\"0xa03ba17b6224bec26290794760fc807e017260406037b4f812970701888e72c8\",\"license\":\"MIT\"},\"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\",\"keccak256\":\"0x05b7dce6c24d3cd4e48b5c6346d86e5e40ecc3291bcdf3f3ef091c98fc826519\",\"license\":\"MIT\"},\"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\\nimport { Governable } from \\\"../../governance/Governable.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 is Governable {\\n /// @notice The address of the Native Staking Strategy\\n address public immutable STRATEGY;\\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 }\\n\\n /**\\n * @dev Accept ETH\\n */\\n receive() external payable {}\\n}\\n\",\"keccak256\":\"0xb8fda3b87dc5d6f8aee4bf1d015a585211e5b5a319dfa4b0f4770e3f5a2d5939\",\"license\":\"MIT\"},\"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_ADDRESS;\\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 _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 address _feeAccumulator,\\n address _beaconChainDepositContract\\n )\\n InitializableAbstractStrategy(_baseConfig)\\n ValidatorAccountant(\\n _wethAddress,\\n _baseConfig.vaultAddress,\\n _beaconChainDepositContract,\\n _ssvNetwork\\n )\\n {\\n SSV_TOKEN_ADDRESS = _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 /// @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_TOKEN_ADDRESS).deposit{ value: ethRewards }();\\n\\n emit RewardTokenCollected(\\n harvesterAddress,\\n WETH_TOKEN_ADDRESS,\\n ethRewards\\n );\\n IERC20(WETH_TOKEN_ADDRESS).safeTransfer(\\n harvesterAddress,\\n ethRewards\\n );\\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_TOKEN_ADDRESS, \\\"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_TOKEN_ADDRESS).balanceOf(\\n address(this)\\n );\\n uint256 newWeth = wethBalance - depositedWethAccountedFor;\\n\\n if (newWeth > 0) {\\n depositedWethAccountedFor = wethBalance;\\n\\n _deposit(WETH_TOKEN_ADDRESS, newWeth);\\n }\\n }\\n\\n /// @notice Withdraw WETH from this contract. Used only if some WETH for is lingering on the contract. That\\n /// can happen when:\\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 _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 emit Withdrawal(_asset, address(0), _amount);\\n IERC20(_asset).safeTransfer(_recipient, _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_TOKEN_ADDRESS).balanceOf(\\n address(this)\\n );\\n if (wethBalance > 0) {\\n _withdraw(vaultAddress, WETH_TOKEN_ADDRESS, wethBalance);\\n }\\n }\\n\\n function _abstractSetPToken(address _asset, address) internal override {}\\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_TOKEN_ADDRESS, \\\"Unsupported asset\\\");\\n\\n balance =\\n // add the ETH that has been staked in validators\\n activeDepositedValidators *\\n 32 ether +\\n // add the WETH in the strategy from deposits that are still to be staked\\n IERC20(WETH_TOKEN_ADDRESS).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_TOKEN_ADDRESS;\\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_ADDRESS).approve(\\n SSV_NETWORK_ADDRESS,\\n type(uint256).max\\n );\\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 ||\\n msg.sender == WETH_TOKEN_ADDRESS,\\n \\\"eth not from allowed contracts\\\"\\n );\\n }\\n\\n function _wethWithdrawnToVault(uint256 _amount) internal override {\\n emit Withdrawal(WETH_TOKEN_ADDRESS, address(0), _amount);\\n }\\n\\n function _wethWithdrawnAndStaked(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 direclty\\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\",\"keccak256\":\"0x937ce31cd4b90ad532fdde874dc02eaf0a29a800c2c2292d2d6cb71afa75f32d\",\"license\":\"MIT\"},\"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 /// @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 MAX_STAKE = 32 ether;\\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 constructor(\\n address _wethAddress,\\n address _vaultAddress,\\n address _beaconChainDepositContract,\\n address _ssvNetwork\\n )\\n ValidatorRegistrator(\\n _wethAddress,\\n _vaultAddress,\\n _beaconChainDepositContract,\\n _ssvNetwork\\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 emit FuseIntervalUpdated(_fuseIntervalStart, _fuseIntervalEnd);\\n\\n fuseIntervalStart = _fuseIntervalStart;\\n fuseIntervalEnd = _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 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 >= MAX_STAKE) {\\n uint256 fullyWithdrawnValidators;\\n // safe since MAX_STAKE is hardcoded to 32ETH\\n unchecked {\\n // explicitly cast to uint256 as we want to round to a whole number of validators\\n fullyWithdrawnValidators = uint256(newSweptETH / MAX_STAKE);\\n }\\n activeDepositedValidators -= fullyWithdrawnValidators;\\n\\n uint256 wethToVault = MAX_STAKE * fullyWithdrawnValidators;\\n IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: wethToVault }();\\n // slither-disable-next-line unchecked-transfer\\n IWETH9(WETH_TOKEN_ADDRESS).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 < 32 ether, \\\"unexpected accounting\\\");\\n\\n // If no Beacon chain consensus rewards swept\\n if (ethRemaining == 0) {\\n // do nothing\\n return accountingValid;\\n }\\n // Beacon chain consensus rewards swept (partial validator withdrawals)\\n else if (ethRemaining < fuseIntervalStart) {\\n // solhint-disable-next-line reentrancy\\n consensusRewards += ethRemaining;\\n emit AccountingConsensusRewards(ethRemaining);\\n }\\n // Beacon chain consensus rewards swept but also a slashed validator fully exited\\n else if (ethRemaining > fuseIntervalEnd) {\\n IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: ethRemaining }();\\n // slither-disable-next-line unchecked-transfer\\n IWETH9(WETH_TOKEN_ADDRESS).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 {\\n require(\\n lastFixAccountingBlockNumber + MIN_FIX_ACCOUNTING_CADENCE <\\n block.number,\\n \\\"manuallyFixAccounting 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 emit AccountingManuallyFixed(\\n _validatorsDelta,\\n _consensusRewardsDelta,\\n _ethToVaultAmount\\n );\\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_TOKEN_ADDRESS).deposit{ value: _ethToVaultAmount }();\\n // slither-disable-next-line unchecked-transfer\\n IWETH9(WETH_TOKEN_ADDRESS).transfer(\\n VAULT_ADDRESS,\\n _ethToVaultAmount\\n );\\n _wethWithdrawnToVault(_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 Withdrawal event\\n function _wethWithdrawnToVault(uint256 _amount) internal virtual;\\n}\\n\",\"keccak256\":\"0xabaf2d9369a02523060af32100515478a585c40749c630e68d7ce24258d8ca43\",\"license\":\"MIT\"},\"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 address of the Wrapped ETH (WETH) token contract\\n address public immutable WETH_TOKEN_ADDRESS;\\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_ADDRESS;\\n /// @notice Address of the OETH Vault proxy contract\\n address public immutable VAULT_ADDRESS;\\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 governor needs to approve further staking\\n uint256 public stakeETHThreshold;\\n /// @notice Amount of ETH that can has been staked since the last governor approval.\\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(\\n bytes32 indexed pubKeyHash,\\n bytes pubKey,\\n uint256 amount,\\n bytes withdrawal_credentials\\n );\\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 constructor(\\n address _wethAddress,\\n address _vaultAddress,\\n address _beaconChainDepositContract,\\n address _ssvNetwork\\n ) {\\n WETH_TOKEN_ADDRESS = _wethAddress;\\n BEACON_CHAIN_DEPOSIT_CONTRACT = _beaconChainDepositContract;\\n SSV_NETWORK_ADDRESS = _ssvNetwork;\\n VAULT_ADDRESS = _vaultAddress;\\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 emit RegistratorChanged(_address);\\n validatorRegistrator = _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 emit StakingMonitorChanged(_address);\\n stakingMonitor = _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 emit StakeETHThresholdChanged(_amount);\\n stakeETHThreshold = _amount;\\n }\\n\\n /// @notice Reset the stakeETHTally\\n function resetStakeETHTally() external onlyStakingMonitor {\\n emit StakeETHTallyReset();\\n stakeETHTally = 0;\\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 {\\n uint256 requiredETH = validators.length * 32 ether;\\n\\n // Check there is enough WETH from the deposits sitting in this strategy contract\\n require(\\n requiredETH <= IWETH9(WETH_TOKEN_ADDRESS).balanceOf(address(this)),\\n \\\"insufficient WETH\\\"\\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_TOKEN_ADDRESS).withdraw(requiredETH);\\n _wethWithdrawnAndStaked(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 withdrawal_credentials = abi.encodePacked(\\n bytes1(0x01),\\n bytes11(0),\\n address(this)\\n );\\n\\n uint256 validatorsLength = validators.length;\\n // For each validator\\n for (uint256 i = 0; i < validatorsLength; ) {\\n bytes32 pubKeyHash = keccak256(validators[i].pubkey);\\n VALIDATOR_STATE currentState = validatorsStates[pubKeyHash];\\n\\n require(\\n currentState == VALIDATOR_STATE.REGISTERED,\\n \\\"Validator not registered\\\"\\n );\\n\\n IDepositContract(BEACON_CHAIN_DEPOSIT_CONTRACT).deposit{\\n value: 32 ether\\n }(\\n validators[i].pubkey,\\n withdrawal_credentials,\\n validators[i].signature,\\n validators[i].depositDataRoot\\n );\\n\\n emit ETHStaked(\\n pubKeyHash,\\n validators[i].pubkey,\\n 32 ether,\\n withdrawal_credentials\\n );\\n\\n validatorsStates[pubKeyHash] = VALIDATOR_STATE.STAKED;\\n\\n unchecked {\\n ++i;\\n }\\n }\\n // save gas by changing this storage variable only once rather each time in the loop.\\n activeDepositedValidators += validatorsLength;\\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 // slither-disable-start reentrancy-no-eth\\n function registerSsvValidator(\\n bytes calldata publicKey,\\n uint64[] calldata operatorIds,\\n bytes calldata sharesData,\\n uint256 amount,\\n Cluster calldata cluster\\n ) external onlyRegistrator whenNotPaused {\\n bytes32 pubKeyHash = keccak256(publicKey);\\n require(\\n validatorsStates[pubKeyHash] == VALIDATOR_STATE.NON_REGISTERED,\\n \\\"Validator already registered\\\"\\n );\\n ISSVNetwork(SSV_NETWORK_ADDRESS).registerValidator(\\n publicKey,\\n operatorIds,\\n sharesData,\\n amount,\\n cluster\\n );\\n emit SSVValidatorRegistered(pubKeyHash, publicKey, operatorIds);\\n\\n validatorsStates[pubKeyHash] = VALIDATOR_STATE.REGISTERED;\\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 // 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_ADDRESS).exitValidator(publicKey, operatorIds);\\n emit SSVValidatorExitInitiated(pubKeyHash, publicKey, operatorIds);\\n\\n validatorsStates[pubKeyHash] = VALIDATOR_STATE.EXITING;\\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 // 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_ADDRESS).removeValidator(\\n publicKey,\\n operatorIds,\\n cluster\\n );\\n emit SSVValidatorExitCompleted(pubKeyHash, publicKey, operatorIds);\\n\\n validatorsStates[pubKeyHash] = VALIDATOR_STATE.EXIT_COMPLETE;\\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 cluster The SSV cluster details that must be derived from emitted events from the SSVNetwork contract.\\n function depositSSV(\\n uint64[] memory operatorIds,\\n uint256 amount,\\n Cluster memory cluster\\n ) external onlyStrategist {\\n ISSVNetwork(SSV_NETWORK_ADDRESS).deposit(\\n address(this),\\n operatorIds,\\n amount,\\n cluster\\n );\\n }\\n\\n /***************************************\\n Abstract\\n ****************************************/\\n\\n /// @dev allows for NativeStakingSSVStrategy contract know how much WETH had been staked\\n function _wethWithdrawnAndStaked(uint256 _amount) internal virtual;\\n}\\n\",\"keccak256\":\"0x2638c178c161bf6a311885701327eb0a55221f92513de009a9023807c95bfb0d\",\"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/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\",\"keccak256\":\"0x5e17bb3db9f9e1014b7c5c836547f8fa81e02af7568c0bb8f2a2e0e7c2192db4\",\"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/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\\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\":\"0xcbdb87104749e20c8411bc2acbfa0b7d48e876e3f4e1c46c9a7b00fcdb9722d9\",\"license\":\"MIT\"}},\"version\":1}", + "bytecode": "0x6101806040523480156200001257600080fd5b506040516200515638038062005156833981016040819052620000359162000138565b8585876020015183868383838362000053336200010860201b60201c565b60008051602062005136833981519152546040516001600160a01b03909116906000907fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a908290a36033805460ff191690556001600160601b0319606094851b811660805291841b821660a052831b811660c05290821b811660e0528651821b811661010052602090960151811b86166101205298891b851661014052505050509190931b1661016052506200021392505050565b6000805160206200513683398151915255565b80516001600160a01b03811681146200013357600080fd5b919050565b60008060008060008086880360e08112156200015357600080fd5b60408112156200016257600080fd5b50604080519081016001600160401b03811182821017156200019457634e487b7160e01b600052604160045260246000fd5b604052620001a2886200011b565b8152620001b2602089016200011b565b60208201529550620001c7604088016200011b565b9450620001d7606088016200011b565b9350620001e7608088016200011b565b9250620001f760a088016200011b565b91506200020760c088016200011b565b90509295509295509295565b60805160601c60a05160601c60c05160601c60e05160601c6101005160601c6101205160601c6101405160601c6101605160601c614d7f620003b76000396000818161038a01528181610af4015261325101526000818161068001526126d401526000818161053401528181610f0801528181611b4501528181611cbe01528181612a8d0152612cde01526000610ac001526000818161083b01528181610cd001528181611a7301528181611d0e015281816120d20152818161383d0152613a97015260008181610b7e01528181610da601528181611979015281816126a40152818161284a0152612c08015260008181610a1501526116be0152600081816103bc015281816105de0152818161092c01528181610c3701528181610f7d015281816111c101528181611249015281816113f00152818161154101528181611c2f01528181611cdf0152818161204c0152818161210101528181612d6901528181612e1101528181613356015281816133db0152818161344f015281816136ec015281816137b70152818161386c01528181613a110152613ac60152614d7f6000f3fe60806040526004361061037a5760003560e01c8063853828b6116101d1578063c7af335211610102578063dbe55e56116100a0578063e75292391161006f578063e752923914610b41578063ee7afe2d14610b57578063f1188e4014610b6c578063f6ca71b014610ba057600080fd5b8063dbe55e5614610aae578063dd505df614610ae2578063de34d71314610b16578063de5f626814610b2c57600080fd5b8063d059f6ef116100dc578063d059f6ef14610a37578063d38bfff414610a4e578063d9caed1214610a6e578063d9f00ec714610a8e57600080fd5b8063c7af3352146109d1578063c98517c5146109e6578063cceab75014610a0357600080fd5b8063a3b81e731161016f578063ab12edf511610149578063ab12edf51461095c578063ad1728cb1461097c578063bb1b918d14610991578063c2e1e3f4146109b157600080fd5b8063a3b81e73146108da578063a4f98af4146108fa578063aa388af61461090f57600080fd5b80639092c31c116101ab5780639092c31c146108295780639136616a1461085d57806396d538bb1461087d5780639da0e4621461089d57600080fd5b8063853828b6146107cf57806387bae867146107e45780638d7c0e461461080957600080fd5b80635d36b190116102ab5780636ef38795116102495780637b2d9b2c116102235780637b2d9b2c1461076e5780637b8962f71461078e578063842f5c46146107a45780638456cb59146107ba57600080fd5b80636ef387951461070e57806371a735f31461072e5780637260f8261461074e57600080fd5b8063630923831161028557806363092383146106a257806366e3667e146106b857806367c7066c146106ce5780636e811d38146106ee57600080fd5b80635d36b190146106395780635f5152261461064e5780636093d3801461066e57600080fd5b8063435356d1116103185780635205c380116102f25780635205c380146105ac578063579a7e1a146105cc5780635a063f63146106005780635c975abb1461061557600080fd5b8063435356d11461055657806347e7ef2414610576578063484be8121461059657600080fd5b80631072cbea116103545780631072cbea146104be57806322495dc8146104de5780633c864959146104fe578063430bf08a1461052257600080fd5b80630c340a24146104365780630ed57b3a146104685780630fc3b4c41461048857600080fd5b3661043157336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614806103de5750336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016145b61042f5760405162461bcd60e51b815260206004820152601e60248201527f657468206e6f742066726f6d20616c6c6f77656420636f6e747261637473000060448201526064015b60405180910390fd5b005b600080fd5b34801561044257600080fd5b5061044b610bc2565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561047457600080fd5b5061042f610483366004614122565b610bdf565b34801561049457600080fd5b5061044b6104a33660046140e8565b609f602052600090815260409020546001600160a01b031681565b3480156104ca57600080fd5b5061042f6104d936600461419c565b610c11565b3480156104ea57600080fd5b5061042f6104f9366004614290565b610cce565b34801561050a57600080fd5b5061051460695481565b60405190815260200161045f565b34801561052e57600080fd5b5061044b7f000000000000000000000000000000000000000000000000000000000000000081565b34801561056257600080fd5b5061042f610571366004614209565b610e18565b34801561058257600080fd5b5061042f61059136600461419c565b610efd565b3480156105a257600080fd5b50610514606a5481565b3480156105b857600080fd5b5061042f6105c7366004614366565b61101c565b3480156105d857600080fd5b5061044b7f000000000000000000000000000000000000000000000000000000000000000081565b34801561060c57600080fd5b5061042f611078565b34801561062157600080fd5b5060335460ff165b604051901515815260200161045f565b34801561064557600080fd5b5061042f611117565b34801561065a57600080fd5b506105146106693660046140e8565b6111bd565b34801561067a57600080fd5b5061044b7f000000000000000000000000000000000000000000000000000000000000000081565b3480156106ae57600080fd5b50610514611c2081565b3480156106c457600080fd5b5061051460345481565b3480156106da57600080fd5b5060a35461044b906001600160a01b031681565b3480156106fa57600080fd5b5061042f6107093660046140e8565b6112f1565b34801561071a57600080fd5b5061042f6107293660046141c8565b611371565b34801561073a57600080fd5b5061042f61074936600461449e565b611885565b34801561075a57600080fd5b5060365461044b906001600160a01b031681565b34801561077a57600080fd5b5061044b610789366004614366565b611a47565b34801561079a57600080fd5b5061051460375481565b3480156107b057600080fd5b5061051460685481565b3480156107c657600080fd5b5061042f611a71565b3480156107db57600080fd5b5061042f611b3a565b3480156107f057600080fd5b5060335461044b9061010090046001600160a01b031681565b34801561081557600080fd5b5061042f61082436600461451f565b611d0c565b34801561083557600080fd5b5061044b7f000000000000000000000000000000000000000000000000000000000000000081565b34801561086957600080fd5b5061042f610878366004614366565b6121e1565b34801561088957600080fd5b5061042f6108983660046141c8565b6123ac565b3480156108a957600080fd5b506108cd6108b8366004614366565b60356020526000908152604090205460ff1681565b60405161045f919061498a565b3480156108e657600080fd5b5061042f6108f53660046140e8565b6124cc565b34801561090657600080fd5b50610629612546565b34801561091b57600080fd5b5061062961092a3660046140e8565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0390811691161490565b34801561096857600080fd5b5061042f610977366004614564565b6125a5565b34801561098857600080fd5b5061042f61268d565b34801561099d57600080fd5b5061042f6109ac3660046143ea565b612753565b3480156109bd57600080fd5b5061042f6109cc3660046140e8565b612920565b3480156109dd57600080fd5b506106296129ad565b3480156109f257600080fd5b506105146801bc16d674ec80000081565b348015610a0f57600080fd5b5061044b7f000000000000000000000000000000000000000000000000000000000000000081565b348015610a4357600080fd5b506105146101075481565b348015610a5a57600080fd5b5061042f610a693660046140e8565b6129de565b348015610a7a57600080fd5b5061042f610a8936600461415b565b612a82565b348015610a9a57600080fd5b5061042f610aa936600461437f565b612b15565b348015610aba57600080fd5b5061044b7f000000000000000000000000000000000000000000000000000000000000000081565b348015610aee57600080fd5b5061044b7f000000000000000000000000000000000000000000000000000000000000000081565b348015610b2257600080fd5b5061051460385481565b348015610b3857600080fd5b5061042f612cd3565b348015610b4d57600080fd5b50610514606b5481565b348015610b6357600080fd5b5061042f612e40565b348015610b7857600080fd5b5061044b7f000000000000000000000000000000000000000000000000000000000000000081565b348015610bac57600080fd5b50610bb5612eca565b60405161045f9190614760565b6000610bda600080516020614d2a8339815191525490565b905090565b610be76129ad565b610c035760405162461bcd60e51b8152600401610426906149fc565b610c0d8282612f2c565b5050565b610c196129ad565b610c355760405162461bcd60e51b8152600401610426906149fc565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b039081169083161415610cb25760405162461bcd60e51b815260206004820152601f60248201527f43616e6e6f74207472616e7366657220737570706f72746564206173736574006044820152606401610426565b610c0d610cbd610bc2565b6001600160a01b038416908361308b565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b158015610d2757600080fd5b505afa158015610d3b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d5f9190614105565b6001600160a01b0316336001600160a01b031614610d8f5760405162461bcd60e51b815260040161042690614abc565b60405163bc26e7e560e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063bc26e7e590610de19030908790879087906004016146b0565b600060405180830381600087803b158015610dfb57600080fd5b505af1158015610e0f573d6000803e3d6000fd5b50505050505050565b610e206129ad565b610e3c5760405162461bcd60e51b8152600401610426906149fc565b600054610100900460ff1680610e55575060005460ff16155b610eb85760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610426565b600054610100900460ff16158015610eda576000805461ffff19166101011790555b610ee58484846130dd565b8015610ef7576000805461ff00191690555b50505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610f455760405162461bcd60e51b8152600401610426906149c5565b600080516020614d0a83398151915280546002811415610f775760405162461bcd60e51b815260040161042690614a94565b600282557f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316846001600160a01b031614610ff05760405162461bcd60e51b8152602060048201526011602482015270155b9cdd5c1c1bdc9d195908185cdcd95d607a1b6044820152606401610426565b8261010760008282546110039190614be3565b9091555061101390508484613198565b50600190555050565b6110246129ad565b6110405760405162461bcd60e51b8152600401610426906149fc565b6040518181527fe26b067424903962f951f568e52ec9a3bbe1589526ea54a4e69ca6eaae1a4c779060200160405180910390a1603755565b60a3546001600160a01b031633146110d25760405162461bcd60e51b815260206004820152601b60248201527f43616c6c6572206973206e6f74207468652048617276657374657200000000006044820152606401610426565b600080516020614d0a833981519152805460028114156111045760405162461bcd60e51b815260040161042690614a94565b6002825561111061322a565b5060019055565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b0316146111b25760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b6064820152608401610426565b6111bb33613478565b565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b0316146112345760405162461bcd60e51b8152602060048201526011602482015270155b9cdd5c1c1bdc9d195908185cdcd95d607a1b6044820152606401610426565b6040516370a0823160e01b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b15801561129357600080fd5b505afa1580156112a7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112cb919061454b565b6034546112e1906801bc16d674ec800000614bfb565b6112eb9190614be3565b92915050565b6112f96129ad565b6113155760405162461bcd60e51b8152600401610426906149fc565b6040516001600160a01b038216907f83f29c79feb71f8fba9d0fbc4ba5f0982a28b6b1e868b3fc50e6400d100bca0f90600090a2603380546001600160a01b0390921661010002610100600160a81b0319909216919091179055565b60335461010090046001600160a01b031633146113a05760405162461bcd60e51b815260040161042690614a5d565b60335460ff16156113c35760405162461bcd60e51b815260040161042690614a33565b60006113d8826801bc16d674ec800000614bfb565b6040516370a0823160e01b81523060048201529091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b15801561143a57600080fd5b505afa15801561144e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611472919061454b565b8111156114b55760405162461bcd60e51b81526020600482015260116024820152700d2dce6eaccccd2c6d2cadce840ae8aa89607b1b6044820152606401610426565b603754816038546114c69190614be3565b11156115145760405162461bcd60e51b815260206004820152601a60248201527f5374616b696e6720455448206f766572207468726573686f6c640000000000006044820152606401610426565b80603860008282546115269190614be3565b9091555050604051632e1a7d4d60e01b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561158d57600080fd5b505af11580156115a1573d6000803e3d6000fd5b505050506115ae81613539565b60408051600160f81b60208201526000602182018190526bffffffffffffffffffffffff193060601b16602c830152910160408051601f1981840301815291905290508260005b8181101561186657600086868381811061161157611611614cba565b90506020028101906116239190614b39565b61162d9080614af3565b60405161163b929190614684565b604080519182900390912060008181526035602052919091205490915060ff16600181600481111561166f5761166f614c8e565b146116bc5760405162461bcd60e51b815260206004820152601860248201527f56616c696461746f72206e6f74207265676973746572656400000000000000006044820152606401610426565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663228951186801bc16d674ec8000008a8a8781811061170757611707614cba565b90506020028101906117199190614b39565b6117239080614af3565b898d8d8a81811061173657611736614cba565b90506020028101906117489190614b39565b611756906020810190614af3565b8f8f8c81811061176857611768614cba565b905060200281019061177a9190614b39565b604001356040518863ffffffff1660e01b815260040161179f9695949392919061490f565b6000604051808303818588803b1580156117b857600080fd5b505af11580156117cc573d6000803e3d6000fd5b5050505050817fd44c8fde6d369f70d395b6cdee4641886d11e3a72cb537696ca04134881692ed89898681811061180557611805614cba565b90506020028101906118179190614b39565b6118219080614af3565b6801bc16d674ec8000008960405161183c949392919061495e565b60405180910390a2506000908152603560205260409020805460ff191660021790556001016115f5565b5080603460008282546118799190614be3565b90915550505050505050565b60335461010090046001600160a01b031633146118b45760405162461bcd60e51b815260040161042690614a5d565b60335460ff16156118d75760405162461bcd60e51b815260040161042690614a33565b600085856040516118e9929190614684565b604080519182900390912060008181526035602052919091205490915060ff16600381600481111561191d5761191d614c8e565b146119625760405162461bcd60e51b815260206004820152601560248201527456616c696461746f72206e6f742065786974696e6760581b6044820152606401610426565b6040516312b3fc1960e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906312b3fc19906119b6908a908a908a908a908a906004016148ce565b600060405180830381600087803b1580156119d057600080fd5b505af11580156119e4573d6000803e3d6000fd5b50505050817f6aecca20726a17c1b81989b2fd09dfdf636bae9e564d4066ca18df62dc1f3dc288888888604051611a1e9493929190614845565b60405180910390a2506000908152603560205260409020805460ff191660041790555050505050565b60a48181548110611a5757600080fd5b6000918252602090912001546001600160a01b0316905081565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b158015611aca57600080fd5b505afa158015611ade573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b029190614105565b6001600160a01b0316336001600160a01b031614611b325760405162461bcd60e51b815260040161042690614abc565b6111bb613566565b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161480611b895750611b74610bc2565b6001600160a01b0316336001600160a01b0316145b611be15760405162461bcd60e51b815260206004820152602360248201527f43616c6c6572206973206e6f7420746865205661756c74206f7220476f7665726044820152623737b960e91b6064820152608401610426565b600080516020614d0a83398151915280546002811415611c135760405162461bcd60e51b815260040161042690614a94565b600282556040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b158015611c7957600080fd5b505afa158015611c8d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cb1919061454b565b90508015611d0457611d047f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000836135db565b505060019055565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b158015611d6557600080fd5b505afa158015611d79573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d9d9190614105565b6001600160a01b0316336001600160a01b031614611dcd5760405162461bcd60e51b815260040161042690614abc565b60335460ff16611e165760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610426565b43611c20606b54611e279190614be3565b10611e825760405162461bcd60e51b815260206004820152602560248201527f6d616e75616c6c794669784163636f756e74696e672063616c6c656420746f6f6044820152641039b7b7b760d91b6064820152608401610426565b6002198312158015611e95575060038313155b8015611eaf5750600083603454611eac9190614ba2565b12155b611efb5760405162461bcd60e51b815260206004820152601760248201527f696e76616c69642076616c696461746f727344656c74610000000000000000006044820152606401610426565b6811ff6cf0fd15afffff198212158015611f1e57506811ff6cf0fd15b000008213155b8015611f385750600082606854611f359190614ba2565b12155b611f845760405162461bcd60e51b815260206004820152601d60248201527f696e76616c696420636f6e73656e7375735265776172647344656c74610000006044820152606401610426565b68053444835ec5800000811115611fdd5760405162461bcd60e51b815260206004820152601960248201527f696e76616c69642077657468546f5661756c74416d6f756e74000000000000006044820152606401610426565b60408051848152602081018490529081018290527f80d022717ea022455c5886b8dd8a29c037570aae58aeb4d7b136d7a10ec2e4319060600160405180910390a18260345461202c9190614ba2565b60345560685461203d908390614ba2565b60685543606b55801561218b577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b1580156120a557600080fd5b505af11580156120b9573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb92506044019050602060405180830381600087803b15801561214957600080fd5b505af115801561215d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121819190614349565b5061218b816136d3565b612195600061373b565b6121d45760405162461bcd60e51b815260206004820152601060248201526f333ab9b29039ba34b63610313637bbb760811b6044820152606401610426565b6121dc613bba565b505050565b6121e96129ad565b6122055760405162461bcd60e51b8152600401610426906149fc565b60a05481106122465760405162461bcd60e51b815260206004820152600d60248201526c092dcecc2d8d2c840d2dcc8caf609b1b6044820152606401610426565b600060a0828154811061225b5761225b614cba565b60009182526020808320909101546001600160a01b03908116808452609f90925260409092205460a0549193509091169061229890600190614c1a565b83101561231a5760a080546122af90600190614c1a565b815481106122bf576122bf614cba565b60009182526020909120015460a080546001600160a01b0390921691859081106122eb576122eb614cba565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505b60a080548061232b5761232b614ca4565b60008281526020808220600019908401810180546001600160a01b031990811690915593019093556001600160a01b03858116808352609f855260409283902080549094169093559051908416815290917f16b7600acff27e39a8a96056b3d533045298de927507f5c1d97e4accde60488c910160405180910390a2505050565b6123b46129ad565b6123d05760405162461bcd60e51b8152600401610426906149fc565b8060005b818110156124835760008484838181106123f0576123f0614cba565b905060200201602081019061240591906140e8565b6001600160a01b031614156124735760405162461bcd60e51b815260206004820152602e60248201527f43616e206e6f742073657420616e20656d70747920616464726573732061732060448201526d30903932bbb0b932103a37b5b2b760911b6064820152608401610426565b61247c81614c5d565b90506123d4565b507f04c0b9649497d316554306e53678d5f5f5dbc3a06f97dec13ff4cfe98b986bbc60a484846040516124b8939291906147ad565b60405180910390a1610ef760a48484613e41565b6124d46129ad565b6124f05760405162461bcd60e51b8152600401610426906149fc565b6040516001600160a01b038216907f3329861a0008b3348767567d2405492b997abd79a088d0f2cef6b1a09a8e7ff790600090a2603680546001600160a01b0319166001600160a01b0392909216919091179055565b60335460009061010090046001600160a01b031633146125785760405162461bcd60e51b815260040161042690614a5d565b60335460ff161561259b5760405162461bcd60e51b815260040161042690614a33565b610bda600161373b565b6125ad6129ad565b6125c95760405162461bcd60e51b8152600401610426906149fc565b80821080156125e057506801bc16d674ec80000081105b80156125fd5750673782dace9d9000006125fa8383614c1a565b10155b6126495760405162461bcd60e51b815260206004820152601760248201527f696e636f7272656374206675736520696e74657276616c0000000000000000006044820152606401610426565b60408051838152602081018390527fcb8d24e46eb3c402bf344ee60a6576cba9ef2f59ea1af3b311520704924e901a910160405180910390a1606991909155606a55565b60405163095ea7b360e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015260001960248301527f0000000000000000000000000000000000000000000000000000000000000000169063095ea7b390604401602060405180830381600087803b15801561271857600080fd5b505af115801561272c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127509190614349565b50565b60335461010090046001600160a01b031633146127825760405162461bcd60e51b815260040161042690614a5d565b60335460ff16156127a55760405162461bcd60e51b815260040161042690614a33565b600088886040516127b7929190614684565b60405190819003902090506000808281526035602052604090205460ff1660048111156127e6576127e6614c8e565b146128335760405162461bcd60e51b815260206004820152601c60248201527f56616c696461746f7220616c72656164792072656769737465726564000000006044820152606401610426565b6040516301ba3ee760e21b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906306e8fb9c9061288d908c908c908c908c908c908c908c908c9060040161486c565b600060405180830381600087803b1580156128a757600080fd5b505af11580156128bb573d6000803e3d6000fd5b50505050807facd38e900350661e325d592c959664c0000a306efb2004e7dc283f44e0ea04238a8a8a8a6040516128f59493929190614845565b60405180910390a26000908152603560205260409020805460ff191660011790555050505050505050565b6129286129ad565b6129445760405162461bcd60e51b8152600401610426906149fc565b60a354604080516001600160a01b03928316815291831660208301527fe48386b84419f4d36e0f96c10cc3510b6fb1a33795620c5098b22472bbe90796910160405180910390a160a380546001600160a01b0319166001600160a01b0392909216919091179055565b60006129c5600080516020614d2a8339815191525490565b6001600160a01b0316336001600160a01b031614905090565b6129e66129ad565b612a025760405162461bcd60e51b8152600401610426906149fc565b612a2a817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b0316612a4a600080516020614d2a8339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614612aca5760405162461bcd60e51b8152600401610426906149c5565b600080516020614d0a83398151915280546002811415612afc5760405162461bcd60e51b815260040161042690614a94565b60028255612b0b8585856135db565b5060019055505050565b60335461010090046001600160a01b03163314612b445760405162461bcd60e51b815260040161042690614a5d565b60335460ff1615612b675760405162461bcd60e51b815260040161042690614a33565b60008484604051612b79929190614684565b604080519182900390912060008181526035602052919091205490915060ff166002816004811115612bad57612bad614c8e565b14612bf15760405162461bcd60e51b815260206004820152601460248201527315985b1a59185d1bdc881b9bdd081cdd185ad95960621b6044820152606401610426565b604051633877322b60e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690633877322b90612c43908990899089908990600401614845565b600060405180830381600087803b158015612c5d57600080fd5b505af1158015612c71573d6000803e3d6000fd5b50505050817f8c2e15303eb94e531acc988c2a01d1193bdaaa15eda7f16dda85316ed463578d87878787604051612cab9493929190614845565b60405180910390a2506000908152603560205260409020805460ff1916600317905550505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614612d1b5760405162461bcd60e51b8152600401610426906149c5565b600080516020614d0a83398151915280546002811415612d4d5760405162461bcd60e51b815260040161042690614a94565b600282556040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b158015612db357600080fd5b505afa158015612dc7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612deb919061454b565b905060006101075482612dfe9190614c1a565b90508015612e3657610107829055612e367f000000000000000000000000000000000000000000000000000000000000000082613198565b5050600182555050565b6036546001600160a01b03163314612e9a5760405162461bcd60e51b815260206004820152601960248201527f43616c6c6572206973206e6f7420746865204d6f6e69746f72000000000000006044820152606401610426565b6040517fe765a88a37047c5d793dce22b9ceb5a0f5039d276da139b4c7d29613f341f11090600090a16000603855565b606060a4805480602002602001604051908101604052809291908181526020018280548015612f2257602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612f04575b5050505050905090565b6001600160a01b038281166000908152609f60205260409020541615612f895760405162461bcd60e51b81526020600482015260126024820152711c151bdad95b88185b1c9958591e481cd95d60721b6044820152606401610426565b6001600160a01b03821615801590612fa957506001600160a01b03811615155b612fe95760405162461bcd60e51b8152602060048201526011602482015270496e76616c69642061646472657373657360781b6044820152606401610426565b6001600160a01b038281166000818152609f6020908152604080832080549587166001600160a01b0319968716811790915560a0805460018101825594527f78fdc8d422c49ced035a9edf18d00d3c6a8d81df210f3e5e448e045e77b41e8890930180549095168417909455925190815290917fef6485b84315f9b1483beffa32aae9a0596890395e3d7521f1c5fbb51790e765910160405180910390a25050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b1790526121dc908490613c34565b82516130f09060a4906020860190613ea4565b5081518151811461313a5760405162461bcd60e51b8152602060048201526014602482015273496e76616c696420696e7075742061727261797360601b6044820152606401610426565b60005b818110156131915761318184828151811061315a5761315a614cba565b602002602001015184838151811061317457613174614cba565b6020026020010151612f2c565b61318a81614c5d565b905061313d565b5050505050565b600081116131e15760405162461bcd60e51b81526020600482015260166024820152754d757374206465706f73697420736f6d657468696e6760501b6044820152606401610426565b6040805160008152602081018390526001600160a01b038416917f5548c837ab068cf56a2c2479df0882a4922fd203edb7517321831d95078c5f62910160405180910390a25050565b60335460ff161561324d5760405162461bcd60e51b815260040161042690614a33565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663e52253816040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156132aa57600080fd5b505af11580156132be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132e2919061454b565b90506000606854826132f49190614be3565b9050804710156133465760405162461bcd60e51b815260206004820152601860248201527f696e73756666696369656e74206574682062616c616e636500000000000000006044820152606401610426565b8015610c0d5760006068819055507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b1580156133af57600080fd5b505af11580156133c3573d6000803e3d6000fd5b505060a354604080516001600160a01b0392831681527f0000000000000000000000000000000000000000000000000000000000000000909216602083015281018590527ff6c07a063ed4e63808eb8da7112d46dbcd38de2b40a73dbcc9353c5a94c72353935060600191506134369050565b60405180910390a160a354610c0d906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811691168361308b565b6001600160a01b0381166134ce5760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f7220697320616464726573732830290000000000006044820152606401610426565b806001600160a01b03166134ee600080516020614d2a8339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a361275081600080516020614d2a83398151915255565b60006135488261010754613d06565b905080610107600082825461355d9190614c1a565b90915550505050565b60335460ff16156135895760405162461bcd60e51b815260040161042690614a33565b6033805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586135be3390565b6040516001600160a01b03909116815260200160405180910390a1565b6000811161362b5760405162461bcd60e51b815260206004820152601760248201527f4d75737420776974686472617720736f6d657468696e670000000000000000006044820152606401610426565b6001600160a01b03831661367a5760405162461bcd60e51b8152602060048201526016602482015275135d5cdd081cdc1958da599e481c9958da5c1a595b9d60521b6044820152606401610426565b6040805160008152602081018390526001600160a01b038416917f2717ead6b9200dd235aad468c9809ea400fe33ac69b5bfaa6d3e90fc922b6398910160405180910390a26121dc6001600160a01b038316848361308b565b6040805160008152602081018390526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016917f2717ead6b9200dd235aad468c9809ea400fe33ac69b5bfaa6d3e90fc922b6398910160405180910390a250565b6000606854471015613750576112eb82613d1e565b6000606854476137609190614c1a565b9050600191506801bc16d674ec800000811061393d5760006801bc16d674ec8000008204905080603460008282546137989190614c1a565b90915550600090506137b3826801bc16d674ec800000614bfb565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b15801561381057600080fd5b505af1158015613824573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb92506044019050602060405180830381600087803b1580156138b457600080fd5b505af11580156138c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138ec9190614349565b506138f6816136d3565b60345460408051848152602081019290925281018290527fbe7040030ff7b347853214bf49820c6d455fedf58f3815f85c7bc5216993682b9060600160405180910390a150505b60006068544761394d9190614c1a565b90506801bc16d674ec800000811061399f5760405162461bcd60e51b8152602060048201526015602482015274756e6578706563746564206163636f756e74696e6760581b6044820152606401610426565b806139ab575050919050565b606954811015613a055780606860008282546139c79190614be3565b90915550506040518181527f7a745a2c63a535068f52ceca27debd5297bbad5f7f37ec53d044a59d0362445d906020015b60405180910390a1613bb3565b606a54811115613ba2577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b158015613a6a57600080fd5b505af1158015613a7e573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb92506044019050602060405180830381600087803b158015613b0e57600080fd5b505af1158015613b22573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b469190614349565b50600160346000828254613b5a9190614c1a565b90915550613b699050816136d3565b60345460408051918252602082018390527f6aa7e30787b26429ced603a7aba8b19c4b5d5bcf29a3257da953c8d53bcaa3a691016139f8565b613bab84613d1e565b949350505050565b5050919050565b60335460ff16613c035760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610426565b6033805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa336135be565b6000613c89826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316613d369092919063ffffffff16565b8051909150156121dc5780806020019051810190613ca79190614349565b6121dc5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610426565b6000818310613d155781613d17565b825b9392505050565b60008115613d2e57613d2e613566565b506000919050565b6060613bab848460008585843b613d8f5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610426565b600080866001600160a01b03168587604051613dab9190614694565b60006040518083038185875af1925050503d8060008114613de8576040519150601f19603f3d011682016040523d82523d6000602084013e613ded565b606091505b5091509150613dfd828286613e08565b979650505050505050565b60608315613e17575081613d17565b825115613e275782518084602001fd5b8160405162461bcd60e51b815260040161042691906149b2565b828054828255906000526020600020908101928215613e94579160200282015b82811115613e945781546001600160a01b0319166001600160a01b03843516178255602090920191600190910190613e61565b50613ea0929150613ef9565b5090565b828054828255906000526020600020908101928215613e94579160200282015b82811115613e9457825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190613ec4565b5b80821115613ea05760008155600101613efa565b60008083601f840112613f2057600080fd5b5081356001600160401b03811115613f3757600080fd5b6020830191508360208260051b8501011115613f5257600080fd5b9250929050565b600082601f830112613f6a57600080fd5b81356020613f7f613f7a83614b7f565b614b4f565b80838252828201915082860187848660051b8901011115613f9f57600080fd5b60005b85811015613fc7578135613fb581614ce6565b84529284019290840190600101613fa2565b5090979650505050505050565b60008083601f840112613fe657600080fd5b5081356001600160401b03811115613ffd57600080fd5b602083019150836020828501011115613f5257600080fd5b600060a0828403121561402757600080fd5b50919050565b600060a0828403121561403f57600080fd5b60405160a081018181106001600160401b038211171561406157614061614cd0565b604052905080614070836140b8565b815261407e602084016140d1565b602082015261408f604084016140d1565b604082015260608301356140a281614cfb565b6060820152608092830135920191909152919050565b803563ffffffff811681146140cc57600080fd5b919050565b80356001600160401b03811681146140cc57600080fd5b6000602082840312156140fa57600080fd5b8135613d1781614ce6565b60006020828403121561411757600080fd5b8151613d1781614ce6565b6000806040838503121561413557600080fd5b823561414081614ce6565b9150602083013561415081614ce6565b809150509250929050565b60008060006060848603121561417057600080fd5b833561417b81614ce6565b9250602084013561418b81614ce6565b929592945050506040919091013590565b600080604083850312156141af57600080fd5b82356141ba81614ce6565b946020939093013593505050565b600080602083850312156141db57600080fd5b82356001600160401b038111156141f157600080fd5b6141fd85828601613f0e565b90969095509350505050565b60008060006060848603121561421e57600080fd5b83356001600160401b038082111561423557600080fd5b61424187838801613f59565b9450602086013591508082111561425757600080fd5b61426387838801613f59565b9350604086013591508082111561427957600080fd5b5061428686828701613f59565b9150509250925092565b600080600060e084860312156142a557600080fd5b83356001600160401b038111156142bb57600080fd5b8401601f810186136142cc57600080fd5b803560206142dc613f7a83614b7f565b8083825282820191508285018a848660051b88010111156142fc57600080fd5b600095505b8486101561432657614312816140d1565b835260019590950194918301918301614301565b50965050860135935061434091508690506040860161402d565b90509250925092565b60006020828403121561435b57600080fd5b8151613d1781614cfb565b60006020828403121561437857600080fd5b5035919050565b6000806000806040858703121561439557600080fd5b84356001600160401b03808211156143ac57600080fd5b6143b888838901613fd4565b909650945060208701359150808211156143d157600080fd5b506143de87828801613f0e565b95989497509550505050565b600080600080600080600080610120898b03121561440757600080fd5b88356001600160401b038082111561441e57600080fd5b61442a8c838d01613fd4565b909a50985060208b013591508082111561444357600080fd5b61444f8c838d01613f0e565b909850965060408b013591508082111561446857600080fd5b506144758b828c01613fd4565b9095509350506060890135915061448f8a60808b01614015565b90509295985092959890939650565b600080600080600060e086880312156144b657600080fd5b85356001600160401b03808211156144cd57600080fd5b6144d989838a01613fd4565b909750955060208801359150808211156144f257600080fd5b506144ff88828901613f0e565b909450925061451390508760408801614015565b90509295509295909350565b60008060006060848603121561453457600080fd5b505081359360208301359350604090920135919050565b60006020828403121561455d57600080fd5b5051919050565b6000806040838503121561457757600080fd5b50508035926020909101359150565b8183526000602080850194508260005b858110156145c2576001600160401b036145af836140d1565b1687529582019590820190600101614596565b509495945050505050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6000815180845261460e816020860160208601614c31565b601f01601f19169290920160200192915050565b63ffffffff614630826140b8565b16825261463f602082016140d1565b6001600160401b0380821660208501528061465c604085016140d1565b1660408501525050606081013561467281614cfb565b15156060830152608090810135910152565b8183823760009101908152919050565b600082516146a6818460208701614c31565b9190910192915050565b6001600160a01b03851681526101006020808301829052855191830182905260009161012084019187810191845b818110156147035783516001600160401b0316855293820193928201926001016146de565b505082935086604086015263ffffffff865116606086015280860151925050506001600160401b0380821660808501528060408601511660a085015250506060830151151560c0830152608083015160e083015295945050505050565b6020808252825182820181905260009190848201906040850190845b818110156147a15783516001600160a01b03168352928401929184019160010161477c565b50909695505050505050565b6000604082016040835280865480835260608501915087600052602092508260002060005b828110156147f75781546001600160a01b0316845292840192600191820191016147d2565b505050838103828501528481528590820160005b8681101561483957823561481e81614ce6565b6001600160a01b03168252918301919083019060010161480b565b50979650505050505050565b6040815260006148596040830186886145cd565b8281036020840152613dfd818587614586565b60006101208083526148818184018b8d6145cd565b9050828103602084015261489681898b614586565b905082810360408401526148ab8187896145cd565b9150508360608301526148c16080830184614622565b9998505050505050505050565b60e0815260006148e260e0830187896145cd565b82810360208401526148f5818688614586565b9150506149056040830184614622565b9695505050505050565b60808152600061492360808301888a6145cd565b828103602084015261493581886145f6565b9050828103604084015261494a8186886145cd565b915050826060830152979650505050505050565b6060815260006149726060830186886145cd565b8460208401528281036040840152613dfd81856145f6565b60208101600583106149ac57634e487b7160e01b600052602160045260246000fd5b91905290565b602081526000613d1760208301846145f6565b60208082526017908201527f43616c6c6572206973206e6f7420746865205661756c74000000000000000000604082015260600190565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b60208082526010908201526f14185d5cd8589b194e881c185d5cd95960821b604082015260600190565b6020808252601d908201527f43616c6c6572206973206e6f7420746865205265676973747261746f72000000604082015260600190565b6020808252600e908201526d1499595b9d1c985b9d0818d85b1b60921b604082015260600190565b6020808252601c908201527f43616c6c6572206973206e6f7420746865205374726174656769737400000000604082015260600190565b6000808335601e19843603018112614b0a57600080fd5b8301803591506001600160401b03821115614b2457600080fd5b602001915036819003821315613f5257600080fd5b60008235605e198336030181126146a657600080fd5b604051601f8201601f191681016001600160401b0381118282101715614b7757614b77614cd0565b604052919050565b60006001600160401b03821115614b9857614b98614cd0565b5060051b60200190565b600080821280156001600160ff1b0384900385131615614bc457614bc4614c78565b600160ff1b8390038412811615614bdd57614bdd614c78565b50500190565b60008219821115614bf657614bf6614c78565b500190565b6000816000190483118215151615614c1557614c15614c78565b500290565b600082821015614c2c57614c2c614c78565b500390565b60005b83811015614c4c578181015183820152602001614c34565b83811115610ef75750506000910152565b6000600019821415614c7157614c71614c78565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b038116811461275057600080fd5b801515811461275057600080fdfe53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac45357bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa26469706673582212204d8c7ebaf4c2264e2fd90a3c201009d9efc50419a225e0b4f7f4c66aac9378b664736f6c634300080700337bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a", + "deployedBytecode": "0x60806040526004361061037a5760003560e01c8063853828b6116101d1578063c7af335211610102578063dbe55e56116100a0578063e75292391161006f578063e752923914610b41578063ee7afe2d14610b57578063f1188e4014610b6c578063f6ca71b014610ba057600080fd5b8063dbe55e5614610aae578063dd505df614610ae2578063de34d71314610b16578063de5f626814610b2c57600080fd5b8063d059f6ef116100dc578063d059f6ef14610a37578063d38bfff414610a4e578063d9caed1214610a6e578063d9f00ec714610a8e57600080fd5b8063c7af3352146109d1578063c98517c5146109e6578063cceab75014610a0357600080fd5b8063a3b81e731161016f578063ab12edf511610149578063ab12edf51461095c578063ad1728cb1461097c578063bb1b918d14610991578063c2e1e3f4146109b157600080fd5b8063a3b81e73146108da578063a4f98af4146108fa578063aa388af61461090f57600080fd5b80639092c31c116101ab5780639092c31c146108295780639136616a1461085d57806396d538bb1461087d5780639da0e4621461089d57600080fd5b8063853828b6146107cf57806387bae867146107e45780638d7c0e461461080957600080fd5b80635d36b190116102ab5780636ef38795116102495780637b2d9b2c116102235780637b2d9b2c1461076e5780637b8962f71461078e578063842f5c46146107a45780638456cb59146107ba57600080fd5b80636ef387951461070e57806371a735f31461072e5780637260f8261461074e57600080fd5b8063630923831161028557806363092383146106a257806366e3667e146106b857806367c7066c146106ce5780636e811d38146106ee57600080fd5b80635d36b190146106395780635f5152261461064e5780636093d3801461066e57600080fd5b8063435356d1116103185780635205c380116102f25780635205c380146105ac578063579a7e1a146105cc5780635a063f63146106005780635c975abb1461061557600080fd5b8063435356d11461055657806347e7ef2414610576578063484be8121461059657600080fd5b80631072cbea116103545780631072cbea146104be57806322495dc8146104de5780633c864959146104fe578063430bf08a1461052257600080fd5b80630c340a24146104365780630ed57b3a146104685780630fc3b4c41461048857600080fd5b3661043157336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614806103de5750336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016145b61042f5760405162461bcd60e51b815260206004820152601e60248201527f657468206e6f742066726f6d20616c6c6f77656420636f6e747261637473000060448201526064015b60405180910390fd5b005b600080fd5b34801561044257600080fd5b5061044b610bc2565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561047457600080fd5b5061042f610483366004614122565b610bdf565b34801561049457600080fd5b5061044b6104a33660046140e8565b609f602052600090815260409020546001600160a01b031681565b3480156104ca57600080fd5b5061042f6104d936600461419c565b610c11565b3480156104ea57600080fd5b5061042f6104f9366004614290565b610cce565b34801561050a57600080fd5b5061051460695481565b60405190815260200161045f565b34801561052e57600080fd5b5061044b7f000000000000000000000000000000000000000000000000000000000000000081565b34801561056257600080fd5b5061042f610571366004614209565b610e18565b34801561058257600080fd5b5061042f61059136600461419c565b610efd565b3480156105a257600080fd5b50610514606a5481565b3480156105b857600080fd5b5061042f6105c7366004614366565b61101c565b3480156105d857600080fd5b5061044b7f000000000000000000000000000000000000000000000000000000000000000081565b34801561060c57600080fd5b5061042f611078565b34801561062157600080fd5b5060335460ff165b604051901515815260200161045f565b34801561064557600080fd5b5061042f611117565b34801561065a57600080fd5b506105146106693660046140e8565b6111bd565b34801561067a57600080fd5b5061044b7f000000000000000000000000000000000000000000000000000000000000000081565b3480156106ae57600080fd5b50610514611c2081565b3480156106c457600080fd5b5061051460345481565b3480156106da57600080fd5b5060a35461044b906001600160a01b031681565b3480156106fa57600080fd5b5061042f6107093660046140e8565b6112f1565b34801561071a57600080fd5b5061042f6107293660046141c8565b611371565b34801561073a57600080fd5b5061042f61074936600461449e565b611885565b34801561075a57600080fd5b5060365461044b906001600160a01b031681565b34801561077a57600080fd5b5061044b610789366004614366565b611a47565b34801561079a57600080fd5b5061051460375481565b3480156107b057600080fd5b5061051460685481565b3480156107c657600080fd5b5061042f611a71565b3480156107db57600080fd5b5061042f611b3a565b3480156107f057600080fd5b5060335461044b9061010090046001600160a01b031681565b34801561081557600080fd5b5061042f61082436600461451f565b611d0c565b34801561083557600080fd5b5061044b7f000000000000000000000000000000000000000000000000000000000000000081565b34801561086957600080fd5b5061042f610878366004614366565b6121e1565b34801561088957600080fd5b5061042f6108983660046141c8565b6123ac565b3480156108a957600080fd5b506108cd6108b8366004614366565b60356020526000908152604090205460ff1681565b60405161045f919061498a565b3480156108e657600080fd5b5061042f6108f53660046140e8565b6124cc565b34801561090657600080fd5b50610629612546565b34801561091b57600080fd5b5061062961092a3660046140e8565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0390811691161490565b34801561096857600080fd5b5061042f610977366004614564565b6125a5565b34801561098857600080fd5b5061042f61268d565b34801561099d57600080fd5b5061042f6109ac3660046143ea565b612753565b3480156109bd57600080fd5b5061042f6109cc3660046140e8565b612920565b3480156109dd57600080fd5b506106296129ad565b3480156109f257600080fd5b506105146801bc16d674ec80000081565b348015610a0f57600080fd5b5061044b7f000000000000000000000000000000000000000000000000000000000000000081565b348015610a4357600080fd5b506105146101075481565b348015610a5a57600080fd5b5061042f610a693660046140e8565b6129de565b348015610a7a57600080fd5b5061042f610a8936600461415b565b612a82565b348015610a9a57600080fd5b5061042f610aa936600461437f565b612b15565b348015610aba57600080fd5b5061044b7f000000000000000000000000000000000000000000000000000000000000000081565b348015610aee57600080fd5b5061044b7f000000000000000000000000000000000000000000000000000000000000000081565b348015610b2257600080fd5b5061051460385481565b348015610b3857600080fd5b5061042f612cd3565b348015610b4d57600080fd5b50610514606b5481565b348015610b6357600080fd5b5061042f612e40565b348015610b7857600080fd5b5061044b7f000000000000000000000000000000000000000000000000000000000000000081565b348015610bac57600080fd5b50610bb5612eca565b60405161045f9190614760565b6000610bda600080516020614d2a8339815191525490565b905090565b610be76129ad565b610c035760405162461bcd60e51b8152600401610426906149fc565b610c0d8282612f2c565b5050565b610c196129ad565b610c355760405162461bcd60e51b8152600401610426906149fc565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b039081169083161415610cb25760405162461bcd60e51b815260206004820152601f60248201527f43616e6e6f74207472616e7366657220737570706f72746564206173736574006044820152606401610426565b610c0d610cbd610bc2565b6001600160a01b038416908361308b565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b158015610d2757600080fd5b505afa158015610d3b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d5f9190614105565b6001600160a01b0316336001600160a01b031614610d8f5760405162461bcd60e51b815260040161042690614abc565b60405163bc26e7e560e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063bc26e7e590610de19030908790879087906004016146b0565b600060405180830381600087803b158015610dfb57600080fd5b505af1158015610e0f573d6000803e3d6000fd5b50505050505050565b610e206129ad565b610e3c5760405162461bcd60e51b8152600401610426906149fc565b600054610100900460ff1680610e55575060005460ff16155b610eb85760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610426565b600054610100900460ff16158015610eda576000805461ffff19166101011790555b610ee58484846130dd565b8015610ef7576000805461ff00191690555b50505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610f455760405162461bcd60e51b8152600401610426906149c5565b600080516020614d0a83398151915280546002811415610f775760405162461bcd60e51b815260040161042690614a94565b600282557f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316846001600160a01b031614610ff05760405162461bcd60e51b8152602060048201526011602482015270155b9cdd5c1c1bdc9d195908185cdcd95d607a1b6044820152606401610426565b8261010760008282546110039190614be3565b9091555061101390508484613198565b50600190555050565b6110246129ad565b6110405760405162461bcd60e51b8152600401610426906149fc565b6040518181527fe26b067424903962f951f568e52ec9a3bbe1589526ea54a4e69ca6eaae1a4c779060200160405180910390a1603755565b60a3546001600160a01b031633146110d25760405162461bcd60e51b815260206004820152601b60248201527f43616c6c6572206973206e6f74207468652048617276657374657200000000006044820152606401610426565b600080516020614d0a833981519152805460028114156111045760405162461bcd60e51b815260040161042690614a94565b6002825561111061322a565b5060019055565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b0316146111b25760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b6064820152608401610426565b6111bb33613478565b565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b0316146112345760405162461bcd60e51b8152602060048201526011602482015270155b9cdd5c1c1bdc9d195908185cdcd95d607a1b6044820152606401610426565b6040516370a0823160e01b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b15801561129357600080fd5b505afa1580156112a7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112cb919061454b565b6034546112e1906801bc16d674ec800000614bfb565b6112eb9190614be3565b92915050565b6112f96129ad565b6113155760405162461bcd60e51b8152600401610426906149fc565b6040516001600160a01b038216907f83f29c79feb71f8fba9d0fbc4ba5f0982a28b6b1e868b3fc50e6400d100bca0f90600090a2603380546001600160a01b0390921661010002610100600160a81b0319909216919091179055565b60335461010090046001600160a01b031633146113a05760405162461bcd60e51b815260040161042690614a5d565b60335460ff16156113c35760405162461bcd60e51b815260040161042690614a33565b60006113d8826801bc16d674ec800000614bfb565b6040516370a0823160e01b81523060048201529091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b15801561143a57600080fd5b505afa15801561144e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611472919061454b565b8111156114b55760405162461bcd60e51b81526020600482015260116024820152700d2dce6eaccccd2c6d2cadce840ae8aa89607b1b6044820152606401610426565b603754816038546114c69190614be3565b11156115145760405162461bcd60e51b815260206004820152601a60248201527f5374616b696e6720455448206f766572207468726573686f6c640000000000006044820152606401610426565b80603860008282546115269190614be3565b9091555050604051632e1a7d4d60e01b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561158d57600080fd5b505af11580156115a1573d6000803e3d6000fd5b505050506115ae81613539565b60408051600160f81b60208201526000602182018190526bffffffffffffffffffffffff193060601b16602c830152910160408051601f1981840301815291905290508260005b8181101561186657600086868381811061161157611611614cba565b90506020028101906116239190614b39565b61162d9080614af3565b60405161163b929190614684565b604080519182900390912060008181526035602052919091205490915060ff16600181600481111561166f5761166f614c8e565b146116bc5760405162461bcd60e51b815260206004820152601860248201527f56616c696461746f72206e6f74207265676973746572656400000000000000006044820152606401610426565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663228951186801bc16d674ec8000008a8a8781811061170757611707614cba565b90506020028101906117199190614b39565b6117239080614af3565b898d8d8a81811061173657611736614cba565b90506020028101906117489190614b39565b611756906020810190614af3565b8f8f8c81811061176857611768614cba565b905060200281019061177a9190614b39565b604001356040518863ffffffff1660e01b815260040161179f9695949392919061490f565b6000604051808303818588803b1580156117b857600080fd5b505af11580156117cc573d6000803e3d6000fd5b5050505050817fd44c8fde6d369f70d395b6cdee4641886d11e3a72cb537696ca04134881692ed89898681811061180557611805614cba565b90506020028101906118179190614b39565b6118219080614af3565b6801bc16d674ec8000008960405161183c949392919061495e565b60405180910390a2506000908152603560205260409020805460ff191660021790556001016115f5565b5080603460008282546118799190614be3565b90915550505050505050565b60335461010090046001600160a01b031633146118b45760405162461bcd60e51b815260040161042690614a5d565b60335460ff16156118d75760405162461bcd60e51b815260040161042690614a33565b600085856040516118e9929190614684565b604080519182900390912060008181526035602052919091205490915060ff16600381600481111561191d5761191d614c8e565b146119625760405162461bcd60e51b815260206004820152601560248201527456616c696461746f72206e6f742065786974696e6760581b6044820152606401610426565b6040516312b3fc1960e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906312b3fc19906119b6908a908a908a908a908a906004016148ce565b600060405180830381600087803b1580156119d057600080fd5b505af11580156119e4573d6000803e3d6000fd5b50505050817f6aecca20726a17c1b81989b2fd09dfdf636bae9e564d4066ca18df62dc1f3dc288888888604051611a1e9493929190614845565b60405180910390a2506000908152603560205260409020805460ff191660041790555050505050565b60a48181548110611a5757600080fd5b6000918252602090912001546001600160a01b0316905081565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b158015611aca57600080fd5b505afa158015611ade573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b029190614105565b6001600160a01b0316336001600160a01b031614611b325760405162461bcd60e51b815260040161042690614abc565b6111bb613566565b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161480611b895750611b74610bc2565b6001600160a01b0316336001600160a01b0316145b611be15760405162461bcd60e51b815260206004820152602360248201527f43616c6c6572206973206e6f7420746865205661756c74206f7220476f7665726044820152623737b960e91b6064820152608401610426565b600080516020614d0a83398151915280546002811415611c135760405162461bcd60e51b815260040161042690614a94565b600282556040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b158015611c7957600080fd5b505afa158015611c8d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cb1919061454b565b90508015611d0457611d047f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000836135db565b505060019055565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b158015611d6557600080fd5b505afa158015611d79573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d9d9190614105565b6001600160a01b0316336001600160a01b031614611dcd5760405162461bcd60e51b815260040161042690614abc565b60335460ff16611e165760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610426565b43611c20606b54611e279190614be3565b10611e825760405162461bcd60e51b815260206004820152602560248201527f6d616e75616c6c794669784163636f756e74696e672063616c6c656420746f6f6044820152641039b7b7b760d91b6064820152608401610426565b6002198312158015611e95575060038313155b8015611eaf5750600083603454611eac9190614ba2565b12155b611efb5760405162461bcd60e51b815260206004820152601760248201527f696e76616c69642076616c696461746f727344656c74610000000000000000006044820152606401610426565b6811ff6cf0fd15afffff198212158015611f1e57506811ff6cf0fd15b000008213155b8015611f385750600082606854611f359190614ba2565b12155b611f845760405162461bcd60e51b815260206004820152601d60248201527f696e76616c696420636f6e73656e7375735265776172647344656c74610000006044820152606401610426565b68053444835ec5800000811115611fdd5760405162461bcd60e51b815260206004820152601960248201527f696e76616c69642077657468546f5661756c74416d6f756e74000000000000006044820152606401610426565b60408051848152602081018490529081018290527f80d022717ea022455c5886b8dd8a29c037570aae58aeb4d7b136d7a10ec2e4319060600160405180910390a18260345461202c9190614ba2565b60345560685461203d908390614ba2565b60685543606b55801561218b577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b1580156120a557600080fd5b505af11580156120b9573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb92506044019050602060405180830381600087803b15801561214957600080fd5b505af115801561215d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121819190614349565b5061218b816136d3565b612195600061373b565b6121d45760405162461bcd60e51b815260206004820152601060248201526f333ab9b29039ba34b63610313637bbb760811b6044820152606401610426565b6121dc613bba565b505050565b6121e96129ad565b6122055760405162461bcd60e51b8152600401610426906149fc565b60a05481106122465760405162461bcd60e51b815260206004820152600d60248201526c092dcecc2d8d2c840d2dcc8caf609b1b6044820152606401610426565b600060a0828154811061225b5761225b614cba565b60009182526020808320909101546001600160a01b03908116808452609f90925260409092205460a0549193509091169061229890600190614c1a565b83101561231a5760a080546122af90600190614c1a565b815481106122bf576122bf614cba565b60009182526020909120015460a080546001600160a01b0390921691859081106122eb576122eb614cba565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505b60a080548061232b5761232b614ca4565b60008281526020808220600019908401810180546001600160a01b031990811690915593019093556001600160a01b03858116808352609f855260409283902080549094169093559051908416815290917f16b7600acff27e39a8a96056b3d533045298de927507f5c1d97e4accde60488c910160405180910390a2505050565b6123b46129ad565b6123d05760405162461bcd60e51b8152600401610426906149fc565b8060005b818110156124835760008484838181106123f0576123f0614cba565b905060200201602081019061240591906140e8565b6001600160a01b031614156124735760405162461bcd60e51b815260206004820152602e60248201527f43616e206e6f742073657420616e20656d70747920616464726573732061732060448201526d30903932bbb0b932103a37b5b2b760911b6064820152608401610426565b61247c81614c5d565b90506123d4565b507f04c0b9649497d316554306e53678d5f5f5dbc3a06f97dec13ff4cfe98b986bbc60a484846040516124b8939291906147ad565b60405180910390a1610ef760a48484613e41565b6124d46129ad565b6124f05760405162461bcd60e51b8152600401610426906149fc565b6040516001600160a01b038216907f3329861a0008b3348767567d2405492b997abd79a088d0f2cef6b1a09a8e7ff790600090a2603680546001600160a01b0319166001600160a01b0392909216919091179055565b60335460009061010090046001600160a01b031633146125785760405162461bcd60e51b815260040161042690614a5d565b60335460ff161561259b5760405162461bcd60e51b815260040161042690614a33565b610bda600161373b565b6125ad6129ad565b6125c95760405162461bcd60e51b8152600401610426906149fc565b80821080156125e057506801bc16d674ec80000081105b80156125fd5750673782dace9d9000006125fa8383614c1a565b10155b6126495760405162461bcd60e51b815260206004820152601760248201527f696e636f7272656374206675736520696e74657276616c0000000000000000006044820152606401610426565b60408051838152602081018390527fcb8d24e46eb3c402bf344ee60a6576cba9ef2f59ea1af3b311520704924e901a910160405180910390a1606991909155606a55565b60405163095ea7b360e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015260001960248301527f0000000000000000000000000000000000000000000000000000000000000000169063095ea7b390604401602060405180830381600087803b15801561271857600080fd5b505af115801561272c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127509190614349565b50565b60335461010090046001600160a01b031633146127825760405162461bcd60e51b815260040161042690614a5d565b60335460ff16156127a55760405162461bcd60e51b815260040161042690614a33565b600088886040516127b7929190614684565b60405190819003902090506000808281526035602052604090205460ff1660048111156127e6576127e6614c8e565b146128335760405162461bcd60e51b815260206004820152601c60248201527f56616c696461746f7220616c72656164792072656769737465726564000000006044820152606401610426565b6040516301ba3ee760e21b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906306e8fb9c9061288d908c908c908c908c908c908c908c908c9060040161486c565b600060405180830381600087803b1580156128a757600080fd5b505af11580156128bb573d6000803e3d6000fd5b50505050807facd38e900350661e325d592c959664c0000a306efb2004e7dc283f44e0ea04238a8a8a8a6040516128f59493929190614845565b60405180910390a26000908152603560205260409020805460ff191660011790555050505050505050565b6129286129ad565b6129445760405162461bcd60e51b8152600401610426906149fc565b60a354604080516001600160a01b03928316815291831660208301527fe48386b84419f4d36e0f96c10cc3510b6fb1a33795620c5098b22472bbe90796910160405180910390a160a380546001600160a01b0319166001600160a01b0392909216919091179055565b60006129c5600080516020614d2a8339815191525490565b6001600160a01b0316336001600160a01b031614905090565b6129e66129ad565b612a025760405162461bcd60e51b8152600401610426906149fc565b612a2a817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b0316612a4a600080516020614d2a8339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614612aca5760405162461bcd60e51b8152600401610426906149c5565b600080516020614d0a83398151915280546002811415612afc5760405162461bcd60e51b815260040161042690614a94565b60028255612b0b8585856135db565b5060019055505050565b60335461010090046001600160a01b03163314612b445760405162461bcd60e51b815260040161042690614a5d565b60335460ff1615612b675760405162461bcd60e51b815260040161042690614a33565b60008484604051612b79929190614684565b604080519182900390912060008181526035602052919091205490915060ff166002816004811115612bad57612bad614c8e565b14612bf15760405162461bcd60e51b815260206004820152601460248201527315985b1a59185d1bdc881b9bdd081cdd185ad95960621b6044820152606401610426565b604051633877322b60e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690633877322b90612c43908990899089908990600401614845565b600060405180830381600087803b158015612c5d57600080fd5b505af1158015612c71573d6000803e3d6000fd5b50505050817f8c2e15303eb94e531acc988c2a01d1193bdaaa15eda7f16dda85316ed463578d87878787604051612cab9493929190614845565b60405180910390a2506000908152603560205260409020805460ff1916600317905550505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614612d1b5760405162461bcd60e51b8152600401610426906149c5565b600080516020614d0a83398151915280546002811415612d4d5760405162461bcd60e51b815260040161042690614a94565b600282556040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b158015612db357600080fd5b505afa158015612dc7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612deb919061454b565b905060006101075482612dfe9190614c1a565b90508015612e3657610107829055612e367f000000000000000000000000000000000000000000000000000000000000000082613198565b5050600182555050565b6036546001600160a01b03163314612e9a5760405162461bcd60e51b815260206004820152601960248201527f43616c6c6572206973206e6f7420746865204d6f6e69746f72000000000000006044820152606401610426565b6040517fe765a88a37047c5d793dce22b9ceb5a0f5039d276da139b4c7d29613f341f11090600090a16000603855565b606060a4805480602002602001604051908101604052809291908181526020018280548015612f2257602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612f04575b5050505050905090565b6001600160a01b038281166000908152609f60205260409020541615612f895760405162461bcd60e51b81526020600482015260126024820152711c151bdad95b88185b1c9958591e481cd95d60721b6044820152606401610426565b6001600160a01b03821615801590612fa957506001600160a01b03811615155b612fe95760405162461bcd60e51b8152602060048201526011602482015270496e76616c69642061646472657373657360781b6044820152606401610426565b6001600160a01b038281166000818152609f6020908152604080832080549587166001600160a01b0319968716811790915560a0805460018101825594527f78fdc8d422c49ced035a9edf18d00d3c6a8d81df210f3e5e448e045e77b41e8890930180549095168417909455925190815290917fef6485b84315f9b1483beffa32aae9a0596890395e3d7521f1c5fbb51790e765910160405180910390a25050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b1790526121dc908490613c34565b82516130f09060a4906020860190613ea4565b5081518151811461313a5760405162461bcd60e51b8152602060048201526014602482015273496e76616c696420696e7075742061727261797360601b6044820152606401610426565b60005b818110156131915761318184828151811061315a5761315a614cba565b602002602001015184838151811061317457613174614cba565b6020026020010151612f2c565b61318a81614c5d565b905061313d565b5050505050565b600081116131e15760405162461bcd60e51b81526020600482015260166024820152754d757374206465706f73697420736f6d657468696e6760501b6044820152606401610426565b6040805160008152602081018390526001600160a01b038416917f5548c837ab068cf56a2c2479df0882a4922fd203edb7517321831d95078c5f62910160405180910390a25050565b60335460ff161561324d5760405162461bcd60e51b815260040161042690614a33565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663e52253816040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156132aa57600080fd5b505af11580156132be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132e2919061454b565b90506000606854826132f49190614be3565b9050804710156133465760405162461bcd60e51b815260206004820152601860248201527f696e73756666696369656e74206574682062616c616e636500000000000000006044820152606401610426565b8015610c0d5760006068819055507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b1580156133af57600080fd5b505af11580156133c3573d6000803e3d6000fd5b505060a354604080516001600160a01b0392831681527f0000000000000000000000000000000000000000000000000000000000000000909216602083015281018590527ff6c07a063ed4e63808eb8da7112d46dbcd38de2b40a73dbcc9353c5a94c72353935060600191506134369050565b60405180910390a160a354610c0d906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811691168361308b565b6001600160a01b0381166134ce5760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f7220697320616464726573732830290000000000006044820152606401610426565b806001600160a01b03166134ee600080516020614d2a8339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a361275081600080516020614d2a83398151915255565b60006135488261010754613d06565b905080610107600082825461355d9190614c1a565b90915550505050565b60335460ff16156135895760405162461bcd60e51b815260040161042690614a33565b6033805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586135be3390565b6040516001600160a01b03909116815260200160405180910390a1565b6000811161362b5760405162461bcd60e51b815260206004820152601760248201527f4d75737420776974686472617720736f6d657468696e670000000000000000006044820152606401610426565b6001600160a01b03831661367a5760405162461bcd60e51b8152602060048201526016602482015275135d5cdd081cdc1958da599e481c9958da5c1a595b9d60521b6044820152606401610426565b6040805160008152602081018390526001600160a01b038416917f2717ead6b9200dd235aad468c9809ea400fe33ac69b5bfaa6d3e90fc922b6398910160405180910390a26121dc6001600160a01b038316848361308b565b6040805160008152602081018390526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016917f2717ead6b9200dd235aad468c9809ea400fe33ac69b5bfaa6d3e90fc922b6398910160405180910390a250565b6000606854471015613750576112eb82613d1e565b6000606854476137609190614c1a565b9050600191506801bc16d674ec800000811061393d5760006801bc16d674ec8000008204905080603460008282546137989190614c1a565b90915550600090506137b3826801bc16d674ec800000614bfb565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b15801561381057600080fd5b505af1158015613824573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb92506044019050602060405180830381600087803b1580156138b457600080fd5b505af11580156138c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138ec9190614349565b506138f6816136d3565b60345460408051848152602081019290925281018290527fbe7040030ff7b347853214bf49820c6d455fedf58f3815f85c7bc5216993682b9060600160405180910390a150505b60006068544761394d9190614c1a565b90506801bc16d674ec800000811061399f5760405162461bcd60e51b8152602060048201526015602482015274756e6578706563746564206163636f756e74696e6760581b6044820152606401610426565b806139ab575050919050565b606954811015613a055780606860008282546139c79190614be3565b90915550506040518181527f7a745a2c63a535068f52ceca27debd5297bbad5f7f37ec53d044a59d0362445d906020015b60405180910390a1613bb3565b606a54811115613ba2577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b158015613a6a57600080fd5b505af1158015613a7e573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb92506044019050602060405180830381600087803b158015613b0e57600080fd5b505af1158015613b22573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b469190614349565b50600160346000828254613b5a9190614c1a565b90915550613b699050816136d3565b60345460408051918252602082018390527f6aa7e30787b26429ced603a7aba8b19c4b5d5bcf29a3257da953c8d53bcaa3a691016139f8565b613bab84613d1e565b949350505050565b5050919050565b60335460ff16613c035760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610426565b6033805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa336135be565b6000613c89826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316613d369092919063ffffffff16565b8051909150156121dc5780806020019051810190613ca79190614349565b6121dc5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610426565b6000818310613d155781613d17565b825b9392505050565b60008115613d2e57613d2e613566565b506000919050565b6060613bab848460008585843b613d8f5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610426565b600080866001600160a01b03168587604051613dab9190614694565b60006040518083038185875af1925050503d8060008114613de8576040519150601f19603f3d011682016040523d82523d6000602084013e613ded565b606091505b5091509150613dfd828286613e08565b979650505050505050565b60608315613e17575081613d17565b825115613e275782518084602001fd5b8160405162461bcd60e51b815260040161042691906149b2565b828054828255906000526020600020908101928215613e94579160200282015b82811115613e945781546001600160a01b0319166001600160a01b03843516178255602090920191600190910190613e61565b50613ea0929150613ef9565b5090565b828054828255906000526020600020908101928215613e94579160200282015b82811115613e9457825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190613ec4565b5b80821115613ea05760008155600101613efa565b60008083601f840112613f2057600080fd5b5081356001600160401b03811115613f3757600080fd5b6020830191508360208260051b8501011115613f5257600080fd5b9250929050565b600082601f830112613f6a57600080fd5b81356020613f7f613f7a83614b7f565b614b4f565b80838252828201915082860187848660051b8901011115613f9f57600080fd5b60005b85811015613fc7578135613fb581614ce6565b84529284019290840190600101613fa2565b5090979650505050505050565b60008083601f840112613fe657600080fd5b5081356001600160401b03811115613ffd57600080fd5b602083019150836020828501011115613f5257600080fd5b600060a0828403121561402757600080fd5b50919050565b600060a0828403121561403f57600080fd5b60405160a081018181106001600160401b038211171561406157614061614cd0565b604052905080614070836140b8565b815261407e602084016140d1565b602082015261408f604084016140d1565b604082015260608301356140a281614cfb565b6060820152608092830135920191909152919050565b803563ffffffff811681146140cc57600080fd5b919050565b80356001600160401b03811681146140cc57600080fd5b6000602082840312156140fa57600080fd5b8135613d1781614ce6565b60006020828403121561411757600080fd5b8151613d1781614ce6565b6000806040838503121561413557600080fd5b823561414081614ce6565b9150602083013561415081614ce6565b809150509250929050565b60008060006060848603121561417057600080fd5b833561417b81614ce6565b9250602084013561418b81614ce6565b929592945050506040919091013590565b600080604083850312156141af57600080fd5b82356141ba81614ce6565b946020939093013593505050565b600080602083850312156141db57600080fd5b82356001600160401b038111156141f157600080fd5b6141fd85828601613f0e565b90969095509350505050565b60008060006060848603121561421e57600080fd5b83356001600160401b038082111561423557600080fd5b61424187838801613f59565b9450602086013591508082111561425757600080fd5b61426387838801613f59565b9350604086013591508082111561427957600080fd5b5061428686828701613f59565b9150509250925092565b600080600060e084860312156142a557600080fd5b83356001600160401b038111156142bb57600080fd5b8401601f810186136142cc57600080fd5b803560206142dc613f7a83614b7f565b8083825282820191508285018a848660051b88010111156142fc57600080fd5b600095505b8486101561432657614312816140d1565b835260019590950194918301918301614301565b50965050860135935061434091508690506040860161402d565b90509250925092565b60006020828403121561435b57600080fd5b8151613d1781614cfb565b60006020828403121561437857600080fd5b5035919050565b6000806000806040858703121561439557600080fd5b84356001600160401b03808211156143ac57600080fd5b6143b888838901613fd4565b909650945060208701359150808211156143d157600080fd5b506143de87828801613f0e565b95989497509550505050565b600080600080600080600080610120898b03121561440757600080fd5b88356001600160401b038082111561441e57600080fd5b61442a8c838d01613fd4565b909a50985060208b013591508082111561444357600080fd5b61444f8c838d01613f0e565b909850965060408b013591508082111561446857600080fd5b506144758b828c01613fd4565b9095509350506060890135915061448f8a60808b01614015565b90509295985092959890939650565b600080600080600060e086880312156144b657600080fd5b85356001600160401b03808211156144cd57600080fd5b6144d989838a01613fd4565b909750955060208801359150808211156144f257600080fd5b506144ff88828901613f0e565b909450925061451390508760408801614015565b90509295509295909350565b60008060006060848603121561453457600080fd5b505081359360208301359350604090920135919050565b60006020828403121561455d57600080fd5b5051919050565b6000806040838503121561457757600080fd5b50508035926020909101359150565b8183526000602080850194508260005b858110156145c2576001600160401b036145af836140d1565b1687529582019590820190600101614596565b509495945050505050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6000815180845261460e816020860160208601614c31565b601f01601f19169290920160200192915050565b63ffffffff614630826140b8565b16825261463f602082016140d1565b6001600160401b0380821660208501528061465c604085016140d1565b1660408501525050606081013561467281614cfb565b15156060830152608090810135910152565b8183823760009101908152919050565b600082516146a6818460208701614c31565b9190910192915050565b6001600160a01b03851681526101006020808301829052855191830182905260009161012084019187810191845b818110156147035783516001600160401b0316855293820193928201926001016146de565b505082935086604086015263ffffffff865116606086015280860151925050506001600160401b0380821660808501528060408601511660a085015250506060830151151560c0830152608083015160e083015295945050505050565b6020808252825182820181905260009190848201906040850190845b818110156147a15783516001600160a01b03168352928401929184019160010161477c565b50909695505050505050565b6000604082016040835280865480835260608501915087600052602092508260002060005b828110156147f75781546001600160a01b0316845292840192600191820191016147d2565b505050838103828501528481528590820160005b8681101561483957823561481e81614ce6565b6001600160a01b03168252918301919083019060010161480b565b50979650505050505050565b6040815260006148596040830186886145cd565b8281036020840152613dfd818587614586565b60006101208083526148818184018b8d6145cd565b9050828103602084015261489681898b614586565b905082810360408401526148ab8187896145cd565b9150508360608301526148c16080830184614622565b9998505050505050505050565b60e0815260006148e260e0830187896145cd565b82810360208401526148f5818688614586565b9150506149056040830184614622565b9695505050505050565b60808152600061492360808301888a6145cd565b828103602084015261493581886145f6565b9050828103604084015261494a8186886145cd565b915050826060830152979650505050505050565b6060815260006149726060830186886145cd565b8460208401528281036040840152613dfd81856145f6565b60208101600583106149ac57634e487b7160e01b600052602160045260246000fd5b91905290565b602081526000613d1760208301846145f6565b60208082526017908201527f43616c6c6572206973206e6f7420746865205661756c74000000000000000000604082015260600190565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b60208082526010908201526f14185d5cd8589b194e881c185d5cd95960821b604082015260600190565b6020808252601d908201527f43616c6c6572206973206e6f7420746865205265676973747261746f72000000604082015260600190565b6020808252600e908201526d1499595b9d1c985b9d0818d85b1b60921b604082015260600190565b6020808252601c908201527f43616c6c6572206973206e6f7420746865205374726174656769737400000000604082015260600190565b6000808335601e19843603018112614b0a57600080fd5b8301803591506001600160401b03821115614b2457600080fd5b602001915036819003821315613f5257600080fd5b60008235605e198336030181126146a657600080fd5b604051601f8201601f191681016001600160401b0381118282101715614b7757614b77614cd0565b604052919050565b60006001600160401b03821115614b9857614b98614cd0565b5060051b60200190565b600080821280156001600160ff1b0384900385131615614bc457614bc4614c78565b600160ff1b8390038412811615614bdd57614bdd614c78565b50500190565b60008219821115614bf657614bf6614c78565b500190565b6000816000190483118215151615614c1557614c15614c78565b500290565b600082821015614c2c57614c2c614c78565b500390565b60005b83811015614c4c578181015183820152602001614c34565b83811115610ef75750506000910152565b6000600019821415614c7157614c71614c78565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b038116811461275057600080fd5b801515811461275057600080fdfe53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac45357bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa26469706673582212204d8c7ebaf4c2264e2fd90a3c201009d9efc50419a225e0b4f7f4c66aac9378b664736f6c63430008070033", "libraries": {}, "devdoc": { "author": "Origin Protocol Inc", @@ -1764,7 +1788,7 @@ "storageLayout": { "storage": [ { - "astId": 5553, + "astId": 42141, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "initialized", "offset": 0, @@ -1772,7 +1796,7 @@ "type": "t_bool" }, { - "astId": 5556, + "astId": 42144, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "initializing", "offset": 1, @@ -1780,7 +1804,7 @@ "type": "t_bool" }, { - "astId": 5596, + "astId": 42184, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "______gap", "offset": 0, @@ -1788,7 +1812,7 @@ "type": "t_array(t_uint256)50_storage" }, { - "astId": 17, + "astId": 656, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "_paused", "offset": 0, @@ -1796,7 +1820,7 @@ "type": "t_bool" }, { - "astId": 3709, + "astId": 35132, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "validatorRegistrator", "offset": 1, @@ -1804,7 +1828,7 @@ "type": "t_address" }, { - "astId": 3712, + "astId": 35135, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "activeDepositedValidators", "offset": 0, @@ -1812,15 +1836,15 @@ "type": "t_uint256" }, { - "astId": 3718, + "astId": 35141, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "validatorsStates", "offset": 0, "slot": "53", - "type": "t_mapping(t_bytes32,t_enum(VALIDATOR_STATE)3736)" + "type": "t_mapping(t_bytes32,t_enum(VALIDATOR_STATE)35160)" }, { - "astId": 3721, + "astId": 35144, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "stakingMonitor", "offset": 0, @@ -1828,7 +1852,7 @@ "type": "t_address" }, { - "astId": 3724, + "astId": 35147, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "stakeETHThreshold", "offset": 0, @@ -1836,7 +1860,7 @@ "type": "t_uint256" }, { - "astId": 3727, + "astId": 35150, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "stakeETHTally", "offset": 0, @@ -1844,7 +1868,7 @@ "type": "t_uint256" }, { - "astId": 3731, + "astId": 35154, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "__gap", "offset": 0, @@ -1852,7 +1876,7 @@ "type": "t_array(t_uint256)47_storage" }, { - "astId": 3204, + "astId": 34631, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "consensusRewards", "offset": 0, @@ -1860,7 +1884,7 @@ "type": "t_uint256" }, { - "astId": 3207, + "astId": 34634, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "fuseIntervalStart", "offset": 0, @@ -1868,7 +1892,7 @@ "type": "t_uint256" }, { - "astId": 3210, + "astId": 34637, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "fuseIntervalEnd", "offset": 0, @@ -1876,7 +1900,7 @@ "type": "t_uint256" }, { - "astId": 3213, + "astId": 34640, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "lastFixAccountingBlockNumber", "offset": 0, @@ -1884,7 +1908,7 @@ "type": "t_uint256" }, { - "astId": 3217, + "astId": 34644, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "__gap", "offset": 0, @@ -1892,7 +1916,7 @@ "type": "t_array(t_uint256)49_storage" }, { - "astId": 5676, + "astId": 42264, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "_deprecated_platformAddress", "offset": 0, @@ -1900,7 +1924,7 @@ "type": "t_address" }, { - "astId": 5679, + "astId": 42267, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "_deprecated_vaultAddress", "offset": 0, @@ -1908,7 +1932,7 @@ "type": "t_address" }, { - "astId": 5684, + "astId": 42272, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "assetToPToken", "offset": 0, @@ -1916,7 +1940,7 @@ "type": "t_mapping(t_address,t_address)" }, { - "astId": 5688, + "astId": 42276, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "assetsMapped", "offset": 0, @@ -1924,7 +1948,7 @@ "type": "t_array(t_address)dyn_storage" }, { - "astId": 5690, + "astId": 42278, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "_deprecated_rewardTokenAddress", "offset": 0, @@ -1932,7 +1956,7 @@ "type": "t_address" }, { - "astId": 5692, + "astId": 42280, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "_deprecated_rewardLiquidationThreshold", "offset": 0, @@ -1940,7 +1964,7 @@ "type": "t_uint256" }, { - "astId": 5695, + "astId": 42283, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "harvesterAddress", "offset": 0, @@ -1948,7 +1972,7 @@ "type": "t_address" }, { - "astId": 5699, + "astId": 42287, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "rewardTokenAddresses", "offset": 0, @@ -1956,7 +1980,7 @@ "type": "t_array(t_address)dyn_storage" }, { - "astId": 5703, + "astId": 42291, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "_reserved", "offset": 0, @@ -1964,7 +1988,7 @@ "type": "t_array(t_int256)98_storage" }, { - "astId": 2718, + "astId": 34145, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "depositedWethAccountedFor", "offset": 0, @@ -1972,7 +1996,7 @@ "type": "t_uint256" }, { - "astId": 2722, + "astId": 34149, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "__gap", "offset": 0, @@ -2026,7 +2050,7 @@ "label": "bytes32", "numberOfBytes": "32" }, - "t_enum(VALIDATOR_STATE)3736": { + "t_enum(VALIDATOR_STATE)35160": { "encoding": "inplace", "label": "enum ValidatorRegistrator.VALIDATOR_STATE", "numberOfBytes": "1" @@ -2043,12 +2067,12 @@ "numberOfBytes": "32", "value": "t_address" }, - "t_mapping(t_bytes32,t_enum(VALIDATOR_STATE)3736)": { + "t_mapping(t_bytes32,t_enum(VALIDATOR_STATE)35160)": { "encoding": "mapping", "key": "t_bytes32", "label": "mapping(bytes32 => enum ValidatorRegistrator.VALIDATOR_STATE)", "numberOfBytes": "32", - "value": "t_enum(VALIDATOR_STATE)3736" + "value": "t_enum(VALIDATOR_STATE)35160" }, "t_uint256": { "encoding": "inplace", diff --git a/contracts/deployments/holesky/solcInputs/2f3753d8399260cc3346b6a657c1cb6c.json b/contracts/deployments/holesky/solcInputs/2f3753d8399260cc3346b6a657c1cb6c.json new file mode 100644 index 0000000000..4e30f2e3bf --- /dev/null +++ b/contracts/deployments/holesky/solcInputs/2f3753d8399260cc3346b6a657c1cb6c.json @@ -0,0 +1,689 @@ +{ + "language": "Solidity", + "sources": { + "@chainlink/contracts-ccip/src/v0.8/ccip/interfaces/IRouterClient.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {Client} from \"../libraries/Client.sol\";\n\ninterface IRouterClient {\n error UnsupportedDestinationChain(uint64 destChainSelector);\n error InsufficientFeeTokenAmount();\n error InvalidMsgValue();\n\n /// @notice Checks if the given chain ID is supported for sending/receiving.\n /// @param chainSelector The chain to check.\n /// @return supported is true if it is supported, false if not.\n function isChainSupported(uint64 chainSelector) external view returns (bool supported);\n\n /// @notice Gets a list of all supported tokens which can be sent or received\n /// to/from a given chain id.\n /// @param chainSelector The chainSelector.\n /// @return tokens The addresses of all tokens that are supported.\n function getSupportedTokens(uint64 chainSelector) external view returns (address[] memory tokens);\n\n /// @param destinationChainSelector The destination chainSelector\n /// @param message The cross-chain CCIP message including data and/or tokens\n /// @return fee returns execution fee for the message\n /// delivery to destination chain, denominated in the feeToken specified in the message.\n /// @dev Reverts with appropriate reason upon invalid message.\n function getFee(\n uint64 destinationChainSelector,\n Client.EVM2AnyMessage memory message\n ) external view returns (uint256 fee);\n\n /// @notice Request a message to be sent to the destination chain\n /// @param destinationChainSelector The destination chain ID\n /// @param message The cross-chain CCIP message including data and/or tokens\n /// @return messageId The message ID\n /// @dev Note if msg.value is larger than the required fee (from getFee) we accept\n /// the overpayment with no refund.\n /// @dev Reverts with appropriate reason upon invalid message.\n function ccipSend(\n uint64 destinationChainSelector,\n Client.EVM2AnyMessage calldata message\n ) external payable returns (bytes32);\n}\n" + }, + "@chainlink/contracts-ccip/src/v0.8/ccip/libraries/Client.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n// End consumer library.\nlibrary Client {\n /// @dev RMN depends on this struct, if changing, please notify the RMN maintainers.\n struct EVMTokenAmount {\n address token; // token address on the local chain.\n uint256 amount; // Amount of tokens.\n }\n\n struct Any2EVMMessage {\n bytes32 messageId; // MessageId corresponding to ccipSend on source.\n uint64 sourceChainSelector; // Source chain selector.\n bytes sender; // abi.decode(sender) if coming from an EVM chain.\n bytes data; // payload sent in original message.\n EVMTokenAmount[] destTokenAmounts; // Tokens and their amounts in their destination chain representation.\n }\n\n // If extraArgs is empty bytes, the default is 200k gas limit.\n struct EVM2AnyMessage {\n bytes receiver; // abi.encode(receiver address) for dest EVM chains\n bytes data; // Data payload\n EVMTokenAmount[] tokenAmounts; // Token transfers\n address feeToken; // Address of feeToken. address(0) means you will send msg.value.\n bytes extraArgs; // Populate this with _argsToBytes(EVMExtraArgsV1)\n }\n\n // bytes4(keccak256(\"CCIP EVMExtraArgsV1\"));\n bytes4 public constant EVM_EXTRA_ARGS_V1_TAG = 0x97a657c9;\n struct EVMExtraArgsV1 {\n uint256 gasLimit;\n }\n\n function _argsToBytes(EVMExtraArgsV1 memory extraArgs) internal pure returns (bytes memory bts) {\n return abi.encodeWithSelector(EVM_EXTRA_ARGS_V1_TAG, extraArgs);\n }\n}\n" + }, + "@openzeppelin/contracts/access/AccessControl.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/AccessControl.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IAccessControl.sol\";\nimport \"../utils/Context.sol\";\nimport \"../utils/Strings.sol\";\nimport \"../utils/introspection/ERC165.sol\";\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address => bool) members;\n bytes32 adminRole;\n }\n\n mapping(bytes32 => RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with a standardized message including the required role.\n *\n * The format of the revert reason is given by the following regular expression:\n *\n * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/\n *\n * _Available since v4.1._\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role, _msgSender());\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view override returns (bool) {\n return _roles[role].members[account];\n }\n\n /**\n * @dev Revert with a standard message if `account` is missing `role`.\n *\n * The format of the revert reason is given by the following regular expression:\n *\n * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/\n */\n function _checkRole(bytes32 role, address account) internal view {\n if (!hasRole(role, account)) {\n revert(\n string(\n abi.encodePacked(\n \"AccessControl: account \",\n Strings.toHexString(uint160(account), 20),\n \" is missing role \",\n Strings.toHexString(uint256(role), 32)\n )\n )\n );\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view override returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `account`.\n */\n function renounceRole(bytes32 role, address account) public virtual override {\n require(account == _msgSender(), \"AccessControl: can only renounce roles for self\");\n\n _revokeRole(role, account);\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event. Note that unlike {grantRole}, this function doesn't perform any\n * checks on the calling account.\n *\n * [WARNING]\n * ====\n * This function should only be called from the constructor when setting\n * up the initial roles for the system.\n *\n * Using this function in any other way is effectively circumventing the admin\n * system imposed by {AccessControl}.\n * ====\n *\n * NOTE: This function is deprecated in favor of {_grantRole}.\n */\n function _setupRole(bytes32 role, address account) internal virtual {\n _grantRole(role, account);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * Internal function without access restriction.\n */\n function _grantRole(bytes32 role, address account) internal virtual {\n if (!hasRole(role, account)) {\n _roles[role].members[account] = true;\n emit RoleGranted(role, account, _msgSender());\n }\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * Internal function without access restriction.\n */\n function _revokeRole(bytes32 role, address account) internal virtual {\n if (hasRole(role, account)) {\n _roles[role].members[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n }\n }\n}\n" + }, + "@openzeppelin/contracts/access/AccessControlEnumerable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/AccessControlEnumerable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IAccessControlEnumerable.sol\";\nimport \"./AccessControl.sol\";\nimport \"../utils/structs/EnumerableSet.sol\";\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 => EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view override returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view override returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override {\n super._grantRole(role, account);\n _roleMembers[role].add(account);\n }\n\n /**\n * @dev Overload {_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override {\n super._revokeRole(role, account);\n _roleMembers[role].remove(account);\n }\n}\n" + }, + "@openzeppelin/contracts/access/IAccessControl.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n *\n * _Available since v3.1._\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `account`.\n */\n function renounceRole(bytes32 role, address account) external;\n}\n" + }, + "@openzeppelin/contracts/access/IAccessControlEnumerable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/IAccessControlEnumerable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IAccessControl.sol\";\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n" + }, + "@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/introspection/ERC165.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC165.sol\";\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n *\n * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n" + }, + "@openzeppelin/contracts/utils/introspection/IERC165.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\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" + }, + "@openzeppelin/contracts/utils/structs/EnumerableSet.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/structs/EnumerableSet.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position of the value in the `values` array, plus 1 because index 0\n // means a value is not in the set.\n mapping(bytes32 => uint256) _indexes;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._indexes[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We read and store the value's index to prevent multiple reads from the same storage slot\n uint256 valueIndex = set._indexes[value];\n\n if (valueIndex != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 toDeleteIndex = valueIndex - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (lastIndex != toDeleteIndex) {\n bytes32 lastvalue = set._values[lastIndex];\n\n // Move the last value to the index where the value to delete is\n set._values[toDeleteIndex] = lastvalue;\n // Update the index for the moved value\n set._indexes[lastvalue] = valueIndex; // Replace lastvalue's index to valueIndex\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the index for the deleted slot\n delete set._indexes[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._indexes[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n return _values(set._inner);\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n assembly {\n result := store\n }\n\n return result;\n }\n}\n" + }, + "contracts/buyback/AbstractBuyback.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { Strategizable } from \"../governance/Strategizable.sol\";\nimport \"../interfaces/chainlink/AggregatorV3Interface.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { ICVXLocker } from \"../interfaces/ICVXLocker.sol\";\nimport { ISwapper } from \"../interfaces/ISwapper.sol\";\n\nimport { Initializable } from \"../utils/Initializable.sol\";\n\nabstract contract AbstractBuyback is Initializable, Strategizable {\n using SafeERC20 for IERC20;\n\n event SwapRouterUpdated(address indexed _address);\n\n event RewardsSourceUpdated(address indexed _address);\n event TreasuryManagerUpdated(address indexed _address);\n event CVXShareBpsUpdated(uint256 bps);\n\n // Emitted whenever OUSD/OETH is swapped for OGN/CVX or any other token\n event OTokenBuyback(\n address indexed oToken,\n address indexed swappedFor,\n uint256 swapAmountIn,\n uint256 amountOut\n );\n\n // Address of 1-inch Swap Router\n address public swapRouter;\n\n // slither-disable-next-line constable-states\n address private __deprecated_ousd;\n // slither-disable-next-line constable-states\n address private __deprecated_ogv;\n // slither-disable-next-line constable-states\n address private __deprecated_usdt;\n // slither-disable-next-line constable-states\n address private __deprecated_weth9;\n\n // Address that receives OGN after swaps\n address public rewardsSource;\n\n // Address that receives all other tokens after swaps\n address public treasuryManager;\n\n // slither-disable-next-line constable-states\n uint256 private __deprecated_treasuryBps;\n\n address public immutable oToken;\n address public immutable ogn;\n address public immutable cvx;\n address public immutable cvxLocker;\n\n // Amount of `oToken` balance to use for OGN buyback\n uint256 public balanceForOGN;\n\n // Amount of `oToken` balance to use for CVX buyback\n uint256 public balanceForCVX;\n\n // Percentage of `oToken` balance to be used for CVX\n uint256 public cvxShareBps; // 10000 = 100%\n\n constructor(\n address _oToken,\n address _ogn,\n address _cvx,\n address _cvxLocker\n ) {\n // Make sure nobody owns the implementation contract\n _setGovernor(address(0));\n\n oToken = _oToken;\n ogn = _ogn;\n cvx = _cvx;\n cvxLocker = _cvxLocker;\n }\n\n /**\n * @param _swapRouter Address of Uniswap V3 Router\n * @param _strategistAddr Address of Strategist multi-sig wallet\n * @param _treasuryManagerAddr Address that receives the treasury's share of OUSD\n * @param _rewardsSource Address of RewardsSource contract\n * @param _cvxShareBps Percentage of balance to use for CVX\n */\n function initialize(\n address _swapRouter,\n address _strategistAddr,\n address _treasuryManagerAddr,\n address _rewardsSource,\n uint256 _cvxShareBps\n ) external onlyGovernor initializer {\n _setStrategistAddr(_strategistAddr);\n\n _setSwapRouter(_swapRouter);\n _setRewardsSource(_rewardsSource);\n\n _setTreasuryManager(_treasuryManagerAddr);\n\n _setCVXShareBps(_cvxShareBps);\n }\n\n /**\n * @dev Set address of Uniswap Universal Router for performing liquidation\n * of platform fee tokens. Setting to 0x0 will pause swaps.\n *\n * @param _router Address of the Uniswap Universal router\n */\n function setSwapRouter(address _router) external onlyGovernor {\n _setSwapRouter(_router);\n }\n\n function _setSwapRouter(address _router) internal {\n address oldRouter = swapRouter;\n swapRouter = _router;\n\n if (oldRouter != address(0)) {\n // Remove allowance of old router, if any\n\n if (IERC20(ogn).allowance(address(this), oldRouter) != 0) {\n // slither-disable-next-line unused-return\n IERC20(ogn).safeApprove(oldRouter, 0);\n }\n\n if (IERC20(cvx).allowance(address(this), oldRouter) != 0) {\n // slither-disable-next-line unused-return\n IERC20(cvx).safeApprove(oldRouter, 0);\n }\n }\n\n emit SwapRouterUpdated(_router);\n }\n\n /**\n * @dev Sets the address that receives the OGN buyback rewards\n * @param _address Address\n */\n function setRewardsSource(address _address) external onlyGovernor {\n _setRewardsSource(_address);\n }\n\n function _setRewardsSource(address _address) internal {\n require(_address != address(0), \"Address not set\");\n rewardsSource = _address;\n emit RewardsSourceUpdated(_address);\n }\n\n /**\n * @dev Sets the address that can receive and manage the funds for Treasury\n * @param _address Address\n */\n function setTreasuryManager(address _address) external onlyGovernor {\n _setTreasuryManager(_address);\n }\n\n function _setTreasuryManager(address _address) internal {\n require(_address != address(0), \"Address not set\");\n treasuryManager = _address;\n emit TreasuryManagerUpdated(_address);\n }\n\n /**\n * @dev Sets the percentage of oToken to use for Flywheel tokens\n * @param _bps BPS, 10000 to 100%\n */\n function setCVXShareBps(uint256 _bps) external onlyGovernor {\n _setCVXShareBps(_bps);\n }\n\n function _setCVXShareBps(uint256 _bps) internal {\n require(_bps <= 10000, \"Invalid bps value\");\n cvxShareBps = _bps;\n emit CVXShareBpsUpdated(_bps);\n }\n\n /**\n * @dev Computes the split of oToken balance that can be\n * used for OGN and CVX buybacks.\n */\n function _updateBuybackSplits()\n internal\n returns (uint256 _balanceForOGN, uint256 _balanceForCVX)\n {\n _balanceForOGN = balanceForOGN;\n _balanceForCVX = balanceForCVX;\n\n uint256 totalBalance = IERC20(oToken).balanceOf(address(this));\n uint256 unsplitBalance = totalBalance - _balanceForOGN - _balanceForCVX;\n\n // Check if all balance is accounted for\n if (unsplitBalance != 0) {\n // If not, split unaccounted balance based on `cvxShareBps`\n uint256 addToCVX = (unsplitBalance * cvxShareBps) / 10000;\n _balanceForCVX = _balanceForCVX + addToCVX;\n _balanceForOGN = _balanceForOGN + unsplitBalance - addToCVX;\n\n // Update storage\n balanceForOGN = _balanceForOGN;\n balanceForCVX = _balanceForCVX;\n }\n }\n\n function updateBuybackSplits() external onlyGovernor {\n // slither-disable-next-line unused-return\n _updateBuybackSplits();\n }\n\n function _swapToken(\n address tokenOut,\n uint256 oTokenAmount,\n uint256 minAmountOut,\n bytes calldata swapData\n ) internal returns (uint256 amountOut) {\n require(oTokenAmount > 0, \"Invalid Swap Amount\");\n require(swapRouter != address(0), \"Swap Router not set\");\n require(minAmountOut > 0, \"Invalid minAmount\");\n\n // Transfer OToken to Swapper for swapping\n // slither-disable-next-line unchecked-transfer unused-return\n IERC20(oToken).transfer(swapRouter, oTokenAmount);\n\n // Swap\n amountOut = ISwapper(swapRouter).swap(\n oToken,\n tokenOut,\n oTokenAmount,\n minAmountOut,\n swapData\n );\n\n require(amountOut >= minAmountOut, \"Higher Slippage\");\n\n emit OTokenBuyback(oToken, tokenOut, oTokenAmount, amountOut);\n }\n\n /**\n * @dev Swaps `oTokenAmount` to OGN\n * @param oTokenAmount Amount of OUSD/OETH to swap\n * @param minOGN Minimum OGN to receive for oTokenAmount\n * @param swapData 1inch Swap Data\n */\n function swapForOGN(\n uint256 oTokenAmount,\n uint256 minOGN,\n bytes calldata swapData\n ) external onlyGovernorOrStrategist nonReentrant {\n (uint256 _amountForOGN, ) = _updateBuybackSplits();\n require(_amountForOGN >= oTokenAmount, \"Balance underflow\");\n require(rewardsSource != address(0), \"RewardsSource contract not set\");\n\n unchecked {\n // Subtract the amount to swap from net balance\n balanceForOGN = _amountForOGN - oTokenAmount;\n }\n\n uint256 ognReceived = _swapToken(ogn, oTokenAmount, minOGN, swapData);\n\n // Transfer OGN received to RewardsSource contract\n // slither-disable-next-line unchecked-transfer unused-return\n IERC20(ogn).transfer(rewardsSource, ognReceived);\n }\n\n /**\n * @dev Swaps `oTokenAmount` to CVX\n * @param oTokenAmount Amount of OUSD/OETH to swap\n * @param minCVX Minimum CVX to receive for oTokenAmount\n * @param swapData 1inch Swap Data\n */\n function swapForCVX(\n uint256 oTokenAmount,\n uint256 minCVX,\n bytes calldata swapData\n ) external onlyGovernorOrStrategist nonReentrant {\n (, uint256 _amountForCVX) = _updateBuybackSplits();\n require(_amountForCVX >= oTokenAmount, \"Balance underflow\");\n\n unchecked {\n // Subtract the amount to swap from net balance\n balanceForCVX = _amountForCVX - oTokenAmount;\n }\n\n uint256 cvxReceived = _swapToken(cvx, oTokenAmount, minCVX, swapData);\n\n // Lock all CVX\n _lockAllCVX(cvxReceived);\n }\n\n /**\n * @dev Locks all CVX held by the contract on behalf of the Treasury Manager\n */\n function lockAllCVX() external onlyGovernorOrStrategist {\n _lockAllCVX(IERC20(cvx).balanceOf(address(this)));\n }\n\n function _lockAllCVX(uint256 cvxAmount) internal {\n require(\n treasuryManager != address(0),\n \"Treasury manager address not set\"\n );\n\n // Lock all available CVX on behalf of `treasuryManager`\n ICVXLocker(cvxLocker).lock(treasuryManager, cvxAmount, 0);\n }\n\n /**\n * @dev Approve CVX Locker to move CVX held by this contract\n */\n function safeApproveAllTokens() external onlyGovernorOrStrategist {\n IERC20(cvx).safeApprove(cvxLocker, type(uint256).max);\n }\n\n /**\n * @notice Owner function to withdraw a specific amount of a token\n * @param token token to be transferered\n * @param amount amount of the token to be transferred\n */\n function transferToken(address token, uint256 amount)\n external\n onlyGovernor\n nonReentrant\n {\n IERC20(token).safeTransfer(_governor(), amount);\n }\n}\n" + }, + "contracts/buyback/OETHBuyback.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { AbstractBuyback } from \"./AbstractBuyback.sol\";\n\ncontract OETHBuyback is AbstractBuyback {\n constructor(\n address _oToken,\n address _ogn,\n address _cvx,\n address _cvxLocker\n ) AbstractBuyback(_oToken, _ogn, _cvx, _cvxLocker) {}\n}\n" + }, + "contracts/buyback/OUSDBuyback.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { AbstractBuyback } from \"./AbstractBuyback.sol\";\n\ncontract OUSDBuyback is AbstractBuyback {\n constructor(\n address _oToken,\n address _ogn,\n address _cvx,\n address _cvxLocker\n ) AbstractBuyback(_oToken, _ogn, _cvx, _cvxLocker) {}\n}\n" + }, + "contracts/compensation/CompensationClaims.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\";\n\nimport { Initializable } from \"../utils/Initializable.sol\";\nimport { Governable } from \"../governance/Governable.sol\";\n\n/**\n * @title Compensation Claims\n * @author Origin Protocol Inc\n * @dev Airdrop for ERC20 tokens.\n *\n * Provides a coin airdrop with a verification period in which everyone\n * can check that all claims are correct before any actual funds are moved\n * to the contract.\n *\n * - Users can claim funds during the claim period.\n *\n * - The adjuster can set the amount of each user's claim,\n * but only when unlocked, and not during the claim period.\n *\n * - The governor can unlock and lock the adjuster, outside the claim period.\n * - The governor can start the claim period, if it's not started.\n * - The governor can collect any remaining funds after the claim period is over.\n *\n * Intended use sequence:\n *\n * 1. Governor unlocks the adjuster\n * 2. Adjuster uploads claims\n * 3. Governor locks the adjuster\n * 4. Everyone verifies that the claim amounts and totals are correct\n * 5. Payout funds are moved to the contract\n * 6. The claim period starts\n * 7. Users claim funds\n * 8. The claim period ends\n * 9. Governor can collect any remaing funds\n *\n */\ncontract CompensationClaims is Governable {\n address public adjuster;\n address public token;\n uint256 public end;\n uint256 public totalClaims;\n mapping(address => uint256) claims;\n bool public isAdjusterLocked;\n\n using SafeMath for uint256;\n\n event Claim(address indexed recipient, uint256 amount);\n event ClaimSet(address indexed recipient, uint256 amount);\n event Start(uint256 end);\n event Lock();\n event Unlock();\n event Collect(address indexed coin, uint256 amount);\n\n constructor(address _token, address _adjuster) onlyGovernor {\n token = _token;\n adjuster = _adjuster;\n isAdjusterLocked = true;\n }\n\n function balanceOf(address _account) external view returns (uint256) {\n return claims[_account];\n }\n\n function decimals() external view returns (uint8) {\n return IERC20Decimals(token).decimals();\n }\n\n /* -- User -- */\n\n function claim(address _recipient) external onlyInClaimPeriod nonReentrant {\n uint256 amount = claims[_recipient];\n require(amount > 0, \"Amount must be greater than 0\");\n claims[_recipient] = 0;\n totalClaims = totalClaims.sub(amount);\n SafeERC20.safeTransfer(IERC20(token), _recipient, amount);\n emit Claim(_recipient, amount);\n }\n\n /* -- Adjustor -- */\n\n function setClaims(\n address[] calldata _addresses,\n uint256[] calldata _amounts\n ) external notInClaimPeriod onlyUnlockedAdjuster {\n require(\n _addresses.length == _amounts.length,\n \"Addresses and amounts must match\"\n );\n uint256 len = _addresses.length;\n for (uint256 i = 0; i < len; i++) {\n address recipient = _addresses[i];\n uint256 newAmount = _amounts[i];\n uint256 oldAmount = claims[recipient];\n claims[recipient] = newAmount;\n totalClaims = totalClaims.add(newAmount).sub(oldAmount);\n emit ClaimSet(recipient, newAmount);\n }\n }\n\n /* -- Governor -- */\n\n function lockAdjuster() external onlyGovernor notInClaimPeriod {\n _lockAdjuster();\n }\n\n function _lockAdjuster() internal {\n isAdjusterLocked = true;\n emit Lock();\n }\n\n function unlockAdjuster() external onlyGovernor notInClaimPeriod {\n isAdjusterLocked = false;\n emit Unlock();\n }\n\n function start(uint256 _seconds)\n external\n onlyGovernor\n notInClaimPeriod\n nonReentrant\n {\n require(totalClaims > 0, \"No claims\");\n uint256 funding = IERC20(token).balanceOf(address(this));\n require(funding >= totalClaims, \"Insufficient funds for all claims\");\n _lockAdjuster();\n end = block.timestamp.add(_seconds);\n require(end.sub(block.timestamp) < 31622400, \"Duration too long\"); // 31622400 = 366*24*60*60\n emit Start(end);\n }\n\n function collect(address _coin)\n external\n onlyGovernor\n notInClaimPeriod\n nonReentrant\n {\n uint256 amount = IERC20(_coin).balanceOf(address(this));\n SafeERC20.safeTransfer(IERC20(_coin), address(governor()), amount);\n emit Collect(_coin, amount);\n }\n\n /* -- modifiers -- */\n\n modifier onlyInClaimPeriod() {\n require(block.timestamp <= end, \"Should be in claim period\");\n _;\n }\n\n modifier notInClaimPeriod() {\n require(block.timestamp > end, \"Should not be in claim period\");\n _;\n }\n\n modifier onlyUnlockedAdjuster() {\n require(isAdjusterLocked == false, \"Adjuster must be unlocked\");\n require(msg.sender == adjuster, \"Must be adjuster\");\n _;\n }\n}\n\ninterface IERC20Decimals {\n function decimals() external view returns (uint8);\n}\n" + }, + "contracts/echidna/Debugger.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nlibrary Debugger {\n event Debug(string debugString);\n event Debug(string description, string data);\n event Debug(string prefix, string description, string data);\n event Debug(string description, bytes32 data);\n event Debug(string prefix, string description, bytes32 data);\n event Debug(string description, uint256 data);\n event Debug(string prefix, string description, uint256 data);\n event Debug(string description, int256 data);\n event Debug(string prefix, string description, int256 data);\n event Debug(string description, address data);\n event Debug(string prefix, string description, address data);\n event Debug(string description, bool data);\n event Debug(string prefix, string description, bool data);\n\n function log(string memory debugString) internal {\n emit Debug(debugString);\n }\n\n function log(string memory description, string memory data) internal {\n emit Debug(description, data);\n }\n\n function log(\n string memory prefix,\n string memory description,\n string memory data\n ) internal {\n emit Debug(prefix, description, data);\n }\n\n function log(string memory description, bytes32 data) internal {\n emit Debug(description, data);\n }\n\n function log(\n string memory prefix,\n string memory description,\n bytes32 data\n ) internal {\n emit Debug(prefix, description, data);\n }\n\n function log(string memory description, uint256 data) internal {\n emit Debug(description, data);\n }\n\n function log(\n string memory prefix,\n string memory description,\n uint256 data\n ) internal {\n emit Debug(prefix, description, data);\n }\n\n function log(string memory description, int256 data) internal {\n emit Debug(description, data);\n }\n\n function log(\n string memory prefix,\n string memory description,\n int256 data\n ) internal {\n emit Debug(prefix, description, data);\n }\n\n function log(string memory description, address data) internal {\n emit Debug(description, data);\n }\n\n function log(\n string memory prefix,\n string memory description,\n address data\n ) internal {\n emit Debug(prefix, description, data);\n }\n\n function log(string memory description, bool data) internal {\n emit Debug(description, data);\n }\n\n function log(\n string memory prefix,\n string memory description,\n bool data\n ) internal {\n emit Debug(prefix, description, data);\n }\n}\n" + }, + "contracts/echidna/Echidna.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./EchidnaTestApproval.sol\";\n\n/**\n * @title Echidna test contract for OUSD\n * @notice Target contract to be tested, containing all mixins\n * @author Rappie\n */\ncontract Echidna is EchidnaTestApproval {\n\n}\n" + }, + "contracts/echidna/EchidnaConfig.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @title Top-level mixin for configuring the desired fuzzing setup\n * @author Rappie\n */\ncontract EchidnaConfig {\n address internal constant ADDRESS_VAULT = address(0x10000);\n address internal constant ADDRESS_OUTSIDER_USER = address(0x20000);\n\n address internal constant ADDRESS_USER0 = address(0x30000);\n address internal constant ADDRESS_USER1 = address(0x40000);\n\n // Will be set in EchidnaSetup constructor\n address internal ADDRESS_OUTSIDER_CONTRACT;\n address internal ADDRESS_CONTRACT0;\n address internal ADDRESS_CONTRACT1;\n\n // Toggle known issues\n //\n // This can be used to skip tests that are known to fail. This is useful\n // when debugging a specific issue, but should be disabled when running\n // the full test suite.\n //\n // True => skip tests that are known to fail\n // False => run all tests\n //\n bool internal constant TOGGLE_KNOWN_ISSUES = false;\n\n // Toggle known issues within limits\n //\n // Same as TOGGLE_KNOWN_ISSUES, but also skip tests that are known to fail\n // within limits set by the variables below.\n //\n bool internal constant TOGGLE_KNOWN_ISSUES_WITHIN_LIMITS = true;\n\n // Starting balance\n //\n // Gives OUSD a non-zero starting supply, which can be useful to ignore\n // certain edge cases.\n //\n // The starting balance is given to outsider accounts that are not used as\n // accounts while fuzzing.\n //\n bool internal constant TOGGLE_STARTING_BALANCE = true;\n uint256 internal constant STARTING_BALANCE = 1_000_000e18;\n\n // Change supply\n //\n // Set a limit to the amount of change per rebase, which can be useful to\n // ignore certain edge cases.\n //\n // True => limit the amount of change to a percentage of total supply\n // False => no limit\n //\n bool internal constant TOGGLE_CHANGESUPPLY_LIMIT = true;\n uint256 internal constant CHANGESUPPLY_DIVISOR = 10; // 10% of total supply\n\n // Mint limit\n //\n // Set a limit the the amount minted per mint, which can be useful to\n // ignore certain edge cases.\n //\n // True => limit the amount of minted tokens\n // False => no limit\n //\n bool internal constant TOGGLE_MINT_LIMIT = true;\n uint256 internal constant MINT_MODULO = 1_000_000_000_000e18;\n\n // Known rounding errors\n uint256 internal constant TRANSFER_ROUNDING_ERROR = 1e18 - 1;\n uint256 internal constant OPT_IN_ROUNDING_ERROR = 1e18 - 1;\n uint256 internal constant MINT_ROUNDING_ERROR = 1e18 - 1;\n\n /**\n * @notice Modifier to skip tests that are known to fail\n * @dev see TOGGLE_KNOWN_ISSUES for more information\n */\n modifier hasKnownIssue() {\n if (TOGGLE_KNOWN_ISSUES) return;\n _;\n }\n\n /**\n * @notice Modifier to skip tests that are known to fail within limits\n * @dev see TOGGLE_KNOWN_ISSUES_WITHIN_LIMITS for more information\n */\n modifier hasKnownIssueWithinLimits() {\n if (TOGGLE_KNOWN_ISSUES_WITHIN_LIMITS) return;\n _;\n }\n\n /**\n * @notice Translate an account ID to an address\n * @param accountId The ID of the account\n * @return account The address of the account\n */\n function getAccount(uint8 accountId)\n internal\n view\n returns (address account)\n {\n accountId = accountId / 64;\n if (accountId == 0) return account = ADDRESS_USER0;\n if (accountId == 1) return account = ADDRESS_USER1;\n if (accountId == 2) return account = ADDRESS_CONTRACT0;\n if (accountId == 3) return account = ADDRESS_CONTRACT1;\n require(false, \"Unknown account ID\");\n }\n}\n" + }, + "contracts/echidna/EchidnaDebug.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { Address } from \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport \"./EchidnaHelper.sol\";\nimport \"./Debugger.sol\";\n\nimport \"../token/OUSD.sol\";\n\n/**\n * @title Room for random debugging functions\n * @author Rappie\n */\ncontract EchidnaDebug is EchidnaHelper {\n function debugOUSD() public pure {\n // assert(ousd.balanceOf(ADDRESS_USER0) == 1000);\n // assert(ousd.rebaseState(ADDRESS_USER0) != OUSD.RebaseOptions.OptIn);\n // assert(Address.isContract(ADDRESS_CONTRACT0));\n // Debugger.log(\"nonRebasingSupply\", ousd.nonRebasingSupply());\n // assert(false);\n }\n}\n" + }, + "contracts/echidna/EchidnaHelper.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./EchidnaSetup.sol\";\nimport \"./Debugger.sol\";\n\n/**\n * @title Mixin containing helper functions\n * @author Rappie\n */\ncontract EchidnaHelper is EchidnaSetup {\n /**\n * @notice Mint tokens to an account\n * @param toAcc Account to mint to\n * @param amount Amount to mint\n * @return Amount minted (in case of capped mint with modulo)\n */\n function mint(uint8 toAcc, uint256 amount) public returns (uint256) {\n address to = getAccount(toAcc);\n\n if (TOGGLE_MINT_LIMIT) {\n amount = amount % MINT_MODULO;\n }\n\n hevm.prank(ADDRESS_VAULT);\n ousd.mint(to, amount);\n\n return amount;\n }\n\n /**\n * @notice Burn tokens from an account\n * @param fromAcc Account to burn from\n * @param amount Amount to burn\n */\n function burn(uint8 fromAcc, uint256 amount) public {\n address from = getAccount(fromAcc);\n hevm.prank(ADDRESS_VAULT);\n ousd.burn(from, amount);\n }\n\n /**\n * @notice Change the total supply of OUSD (rebase)\n * @param amount New total supply\n */\n function changeSupply(uint256 amount) public {\n if (TOGGLE_CHANGESUPPLY_LIMIT) {\n amount =\n ousd.totalSupply() +\n (amount % (ousd.totalSupply() / CHANGESUPPLY_DIVISOR));\n }\n\n hevm.prank(ADDRESS_VAULT);\n ousd.changeSupply(amount);\n }\n\n /**\n * @notice Transfer tokens between accounts\n * @param fromAcc Account to transfer from\n * @param toAcc Account to transfer to\n * @param amount Amount to transfer\n */\n function transfer(\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public {\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n hevm.prank(from);\n // slither-disable-next-line unchecked-transfer\n ousd.transfer(to, amount);\n }\n\n /**\n * @notice Transfer approved tokens between accounts\n * @param authorizedAcc Account that is authorized to transfer\n * @param fromAcc Account to transfer from\n * @param toAcc Account to transfer to\n * @param amount Amount to transfer\n */\n function transferFrom(\n uint8 authorizedAcc,\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public {\n address authorized = getAccount(authorizedAcc);\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n hevm.prank(authorized);\n // slither-disable-next-line unchecked-transfer\n ousd.transferFrom(from, to, amount);\n }\n\n /**\n * @notice Opt in to rebasing\n * @param targetAcc Account to opt in\n */\n function optIn(uint8 targetAcc) public {\n address target = getAccount(targetAcc);\n hevm.prank(target);\n ousd.rebaseOptIn();\n }\n\n /**\n * @notice Opt out of rebasing\n * @param targetAcc Account to opt out\n */\n function optOut(uint8 targetAcc) public {\n address target = getAccount(targetAcc);\n hevm.prank(target);\n ousd.rebaseOptOut();\n }\n\n /**\n * @notice Approve an account to spend OUSD\n * @param ownerAcc Account that owns the OUSD\n * @param spenderAcc Account that is approved to spend the OUSD\n * @param amount Amount to approve\n */\n function approve(\n uint8 ownerAcc,\n uint8 spenderAcc,\n uint256 amount\n ) public {\n address owner = getAccount(ownerAcc);\n address spender = getAccount(spenderAcc);\n hevm.prank(owner);\n // slither-disable-next-line unused-return\n ousd.approve(spender, amount);\n }\n\n /**\n * @notice Increase the allowance of an account to spend OUSD\n * @param ownerAcc Account that owns the OUSD\n * @param spenderAcc Account that is approved to spend the OUSD\n * @param amount Amount to increase the allowance by\n */\n function increaseAllowance(\n uint8 ownerAcc,\n uint8 spenderAcc,\n uint256 amount\n ) public {\n address owner = getAccount(ownerAcc);\n address spender = getAccount(spenderAcc);\n hevm.prank(owner);\n // slither-disable-next-line unused-return\n ousd.increaseAllowance(spender, amount);\n }\n\n /**\n * @notice Decrease the allowance of an account to spend OUSD\n * @param ownerAcc Account that owns the OUSD\n * @param spenderAcc Account that is approved to spend the OUSD\n * @param amount Amount to decrease the allowance by\n */\n function decreaseAllowance(\n uint8 ownerAcc,\n uint8 spenderAcc,\n uint256 amount\n ) public {\n address owner = getAccount(ownerAcc);\n address spender = getAccount(spenderAcc);\n hevm.prank(owner);\n // slither-disable-next-line unused-return\n ousd.decreaseAllowance(spender, amount);\n }\n\n /**\n * @notice Get the sum of all OUSD balances\n * @return total Total balance\n */\n function getTotalBalance() public view returns (uint256 total) {\n total += ousd.balanceOf(ADDRESS_VAULT);\n total += ousd.balanceOf(ADDRESS_OUTSIDER_USER);\n total += ousd.balanceOf(ADDRESS_OUTSIDER_CONTRACT);\n total += ousd.balanceOf(ADDRESS_USER0);\n total += ousd.balanceOf(ADDRESS_USER1);\n total += ousd.balanceOf(ADDRESS_CONTRACT0);\n total += ousd.balanceOf(ADDRESS_CONTRACT1);\n }\n\n /**\n * @notice Get the sum of all non-rebasing OUSD balances\n * @return total Total balance\n */\n function getTotalNonRebasingBalance() public returns (uint256 total) {\n total += ousd._isNonRebasingAccountEchidna(ADDRESS_VAULT)\n ? ousd.balanceOf(ADDRESS_VAULT)\n : 0;\n total += ousd._isNonRebasingAccountEchidna(ADDRESS_OUTSIDER_USER)\n ? ousd.balanceOf(ADDRESS_OUTSIDER_USER)\n : 0;\n total += ousd._isNonRebasingAccountEchidna(ADDRESS_OUTSIDER_CONTRACT)\n ? ousd.balanceOf(ADDRESS_OUTSIDER_CONTRACT)\n : 0;\n total += ousd._isNonRebasingAccountEchidna(ADDRESS_USER0)\n ? ousd.balanceOf(ADDRESS_USER0)\n : 0;\n total += ousd._isNonRebasingAccountEchidna(ADDRESS_USER1)\n ? ousd.balanceOf(ADDRESS_USER1)\n : 0;\n total += ousd._isNonRebasingAccountEchidna(ADDRESS_CONTRACT0)\n ? ousd.balanceOf(ADDRESS_CONTRACT0)\n : 0;\n total += ousd._isNonRebasingAccountEchidna(ADDRESS_CONTRACT1)\n ? ousd.balanceOf(ADDRESS_CONTRACT1)\n : 0;\n }\n}\n" + }, + "contracts/echidna/EchidnaSetup.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./IHevm.sol\";\nimport \"./EchidnaConfig.sol\";\nimport \"./OUSDEchidna.sol\";\n\ncontract Dummy {}\n\n/**\n * @title Mixin for setup and deployment\n * @author Rappie\n */\ncontract EchidnaSetup is EchidnaConfig {\n IHevm hevm = IHevm(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D);\n OUSDEchidna ousd = new OUSDEchidna();\n\n /**\n * @notice Deploy the OUSD contract and set up initial state\n */\n constructor() {\n ousd.initialize(\"Origin Dollar\", \"OUSD\", ADDRESS_VAULT, 1e18);\n\n // Deploy dummny contracts as users\n Dummy outsider = new Dummy();\n ADDRESS_OUTSIDER_CONTRACT = address(outsider);\n Dummy dummy0 = new Dummy();\n ADDRESS_CONTRACT0 = address(dummy0);\n Dummy dummy1 = new Dummy();\n ADDRESS_CONTRACT1 = address(dummy1);\n\n // Start out with a reasonable amount of OUSD\n if (TOGGLE_STARTING_BALANCE) {\n // Rebasing tokens\n hevm.prank(ADDRESS_VAULT);\n ousd.mint(ADDRESS_OUTSIDER_USER, STARTING_BALANCE / 2);\n\n // Non-rebasing tokens\n hevm.prank(ADDRESS_VAULT);\n ousd.mint(ADDRESS_OUTSIDER_CONTRACT, STARTING_BALANCE / 2);\n }\n }\n}\n" + }, + "contracts/echidna/EchidnaTestAccounting.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./EchidnaDebug.sol\";\nimport \"./EchidnaTestSupply.sol\";\n\n/**\n * @title Mixin for testing accounting functions\n * @author Rappie\n */\ncontract EchidnaTestAccounting is EchidnaTestSupply {\n /**\n * @notice After opting in, balance should not increase. (Ok to lose rounding funds doing this)\n * @param targetAcc Account to opt in\n */\n function testOptInBalance(uint8 targetAcc) public {\n address target = getAccount(targetAcc);\n\n uint256 balanceBefore = ousd.balanceOf(target);\n optIn(targetAcc);\n uint256 balanceAfter = ousd.balanceOf(target);\n\n assert(balanceAfter <= balanceBefore);\n }\n\n /**\n * @notice After opting out, balance should remain the same\n * @param targetAcc Account to opt out\n */\n function testOptOutBalance(uint8 targetAcc) public {\n address target = getAccount(targetAcc);\n\n uint256 balanceBefore = ousd.balanceOf(target);\n optOut(targetAcc);\n uint256 balanceAfter = ousd.balanceOf(target);\n\n assert(balanceAfter == balanceBefore);\n }\n\n /**\n * @notice Account balance should remain the same after opting in minus rounding error\n * @param targetAcc Account to opt in\n */\n function testOptInBalanceRounding(uint8 targetAcc) public {\n address target = getAccount(targetAcc);\n\n uint256 balanceBefore = ousd.balanceOf(target);\n optIn(targetAcc);\n uint256 balanceAfter = ousd.balanceOf(target);\n\n int256 delta = int256(balanceAfter) - int256(balanceBefore);\n Debugger.log(\"delta\", delta);\n\n // slither-disable-next-line tautology\n assert(-1 * delta >= 0);\n assert(-1 * delta <= int256(OPT_IN_ROUNDING_ERROR));\n }\n\n /**\n * @notice After opting in, total supply should remain the same\n * @param targetAcc Account to opt in\n */\n function testOptInTotalSupply(uint8 targetAcc) public {\n uint256 totalSupplyBefore = ousd.totalSupply();\n optIn(targetAcc);\n uint256 totalSupplyAfter = ousd.totalSupply();\n\n assert(totalSupplyAfter == totalSupplyBefore);\n }\n\n /**\n * @notice After opting out, total supply should remain the same\n * @param targetAcc Account to opt out\n */\n function testOptOutTotalSupply(uint8 targetAcc) public {\n uint256 totalSupplyBefore = ousd.totalSupply();\n optOut(targetAcc);\n uint256 totalSupplyAfter = ousd.totalSupply();\n\n assert(totalSupplyAfter == totalSupplyBefore);\n }\n\n /**\n * @notice Account balance should remain the same when a smart contract auto converts\n * @param targetAcc Account to auto convert\n */\n function testAutoConvertBalance(uint8 targetAcc) public {\n address target = getAccount(targetAcc);\n\n uint256 balanceBefore = ousd.balanceOf(target);\n // slither-disable-next-line unused-return\n ousd._isNonRebasingAccountEchidna(target);\n uint256 balanceAfter = ousd.balanceOf(target);\n\n assert(balanceAfter == balanceBefore);\n }\n\n /**\n * @notice The `balanceOf` function should never revert\n * @param targetAcc Account to check balance of\n */\n function testBalanceOfShouldNotRevert(uint8 targetAcc) public {\n address target = getAccount(targetAcc);\n\n // slither-disable-next-line unused-return\n try ousd.balanceOf(target) {\n assert(true);\n } catch {\n assert(false);\n }\n }\n}\n" + }, + "contracts/echidna/EchidnaTestApproval.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./EchidnaTestMintBurn.sol\";\nimport \"./Debugger.sol\";\n\n/**\n * @title Mixin for testing approval related functions\n * @author Rappie\n */\ncontract EchidnaTestApproval is EchidnaTestMintBurn {\n /**\n * @notice Performing `transferFrom` with an amount inside the allowance should not revert\n * @param authorizedAcc The account that is authorized to transfer\n * @param fromAcc The account that is transferring\n * @param toAcc The account that is receiving\n * @param amount The amount to transfer\n */\n function testTransferFromShouldNotRevert(\n uint8 authorizedAcc,\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public {\n address authorized = getAccount(authorizedAcc);\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n\n require(amount <= ousd.balanceOf(from));\n require(amount <= ousd.allowance(from, authorized));\n\n hevm.prank(authorized);\n // slither-disable-next-line unchecked-transfer\n try ousd.transferFrom(from, to, amount) {\n // pass\n } catch {\n assert(false);\n }\n }\n\n /**\n * @notice Performing `transferFrom` with an amount outside the allowance should revert\n * @param authorizedAcc The account that is authorized to transfer\n * @param fromAcc The account that is transferring\n * @param toAcc The account that is receiving\n * @param amount The amount to transfer\n */\n function testTransferFromShouldRevert(\n uint8 authorizedAcc,\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public {\n address authorized = getAccount(authorizedAcc);\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n\n require(amount > 0);\n require(\n !(amount <= ousd.balanceOf(from) &&\n amount <= ousd.allowance(from, authorized))\n );\n\n hevm.prank(authorized);\n // slither-disable-next-line unchecked-transfer\n try ousd.transferFrom(from, to, amount) {\n assert(false);\n } catch {\n // pass\n }\n }\n\n /**\n * @notice Approving an amount should update the allowance and overwrite any previous allowance\n * @param ownerAcc The account that is approving\n * @param spenderAcc The account that is being approved\n * @param amount The amount to approve\n */\n function testApprove(\n uint8 ownerAcc,\n uint8 spenderAcc,\n uint256 amount\n ) public {\n address owner = getAccount(ownerAcc);\n address spender = getAccount(spenderAcc);\n\n approve(ownerAcc, spenderAcc, amount);\n uint256 allowanceAfter1 = ousd.allowance(owner, spender);\n\n assert(allowanceAfter1 == amount);\n\n approve(ownerAcc, spenderAcc, amount / 2);\n uint256 allowanceAfter2 = ousd.allowance(owner, spender);\n\n assert(allowanceAfter2 == amount / 2);\n }\n\n /**\n * @notice Increasing the allowance should raise it by the amount provided\n * @param ownerAcc The account that is approving\n * @param spenderAcc The account that is being approved\n * @param amount The amount to approve\n */\n function testIncreaseAllowance(\n uint8 ownerAcc,\n uint8 spenderAcc,\n uint256 amount\n ) public {\n address owner = getAccount(ownerAcc);\n address spender = getAccount(spenderAcc);\n\n uint256 allowanceBefore = ousd.allowance(owner, spender);\n increaseAllowance(ownerAcc, spenderAcc, amount);\n uint256 allowanceAfter = ousd.allowance(owner, spender);\n\n assert(allowanceAfter == allowanceBefore + amount);\n }\n\n /**\n * @notice Decreasing the allowance should lower it by the amount provided\n * @param ownerAcc The account that is approving\n * @param spenderAcc The account that is being approved\n * @param amount The amount to approve\n */\n function testDecreaseAllowance(\n uint8 ownerAcc,\n uint8 spenderAcc,\n uint256 amount\n ) public {\n address owner = getAccount(ownerAcc);\n address spender = getAccount(spenderAcc);\n\n uint256 allowanceBefore = ousd.allowance(owner, spender);\n decreaseAllowance(ownerAcc, spenderAcc, amount);\n uint256 allowanceAfter = ousd.allowance(owner, spender);\n\n assert(allowanceAfter == allowanceBefore - amount);\n }\n}\n" + }, + "contracts/echidna/EchidnaTestMintBurn.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./EchidnaDebug.sol\";\nimport \"./EchidnaTestAccounting.sol\";\n\n/**\n * @title Mixin for testing Mint and Burn functions\n * @author Rappie\n */\ncontract EchidnaTestMintBurn is EchidnaTestAccounting {\n /**\n * @notice Minting 0 tokens should not affect account balance\n * @param targetAcc Account to mint to\n */\n function testMintZeroBalance(uint8 targetAcc) public {\n address target = getAccount(targetAcc);\n\n uint256 balanceBefore = ousd.balanceOf(target);\n mint(targetAcc, 0);\n uint256 balanceAfter = ousd.balanceOf(target);\n\n assert(balanceAfter == balanceBefore);\n }\n\n /**\n * @notice Burning 0 tokens should not affect account balance\n * @param targetAcc Account to burn from\n */\n function testBurnZeroBalance(uint8 targetAcc) public {\n address target = getAccount(targetAcc);\n\n uint256 balanceBefore = ousd.balanceOf(target);\n burn(targetAcc, 0);\n uint256 balanceAfter = ousd.balanceOf(target);\n\n assert(balanceAfter == balanceBefore);\n }\n\n /**\n * @notice Minting tokens must increase the account balance by at least amount\n * @param targetAcc Account to mint to\n * @param amount Amount to mint\n * @custom:error testMintBalance(uint8,uint256): failed!💥\n * Call sequence:\n * changeSupply(1)\n * testMintBalance(0,1)\n * Event sequence:\n * Debug(«balanceBefore», 0)\n * Debug(«balanceAfter», 0)\n */\n function testMintBalance(uint8 targetAcc, uint256 amount)\n public\n hasKnownIssue\n hasKnownIssueWithinLimits\n {\n address target = getAccount(targetAcc);\n\n uint256 balanceBefore = ousd.balanceOf(target);\n uint256 amountMinted = mint(targetAcc, amount);\n uint256 balanceAfter = ousd.balanceOf(target);\n\n Debugger.log(\"amountMinted\", amountMinted);\n Debugger.log(\"balanceBefore\", balanceBefore);\n Debugger.log(\"balanceAfter\", balanceAfter);\n\n assert(balanceAfter >= balanceBefore + amountMinted);\n }\n\n /**\n * @notice Burning tokens must decrease the account balance by at least amount\n * @param targetAcc Account to burn from\n * @param amount Amount to burn\n * @custom:error testBurnBalance(uint8,uint256): failed!💥\n * Call sequence:\n * changeSupply(1)\n * mint(0,3)\n * testBurnBalance(0,1)\n * Event sequence:\n * Debug(«balanceBefore», 2)\n * Debug(«balanceAfter», 2)\n */\n function testBurnBalance(uint8 targetAcc, uint256 amount)\n public\n hasKnownIssue\n hasKnownIssueWithinLimits\n {\n address target = getAccount(targetAcc);\n\n uint256 balanceBefore = ousd.balanceOf(target);\n burn(targetAcc, amount);\n uint256 balanceAfter = ousd.balanceOf(target);\n\n Debugger.log(\"balanceBefore\", balanceBefore);\n Debugger.log(\"balanceAfter\", balanceAfter);\n\n assert(balanceAfter <= balanceBefore - amount);\n }\n\n /**\n * @notice Minting tokens should not increase the account balance by less than rounding error above amount\n * @param targetAcc Account to mint to\n * @param amount Amount to mint\n */\n function testMintBalanceRounding(uint8 targetAcc, uint256 amount) public {\n address target = getAccount(targetAcc);\n\n uint256 balanceBefore = ousd.balanceOf(target);\n uint256 amountMinted = mint(targetAcc, amount);\n uint256 balanceAfter = ousd.balanceOf(target);\n\n int256 delta = int256(balanceAfter) - int256(balanceBefore);\n\n // delta == amount, if no error\n // delta < amount, if too little is minted\n // delta > amount, if too much is minted\n int256 error = int256(amountMinted) - delta;\n\n assert(error >= 0);\n assert(error <= int256(MINT_ROUNDING_ERROR));\n }\n\n /**\n * @notice A burn of an account balance must result in a zero balance\n * @param targetAcc Account to burn from\n */\n function testBurnAllBalanceToZero(uint8 targetAcc) public hasKnownIssue {\n address target = getAccount(targetAcc);\n\n burn(targetAcc, ousd.balanceOf(target));\n assert(ousd.balanceOf(target) == 0);\n }\n\n /**\n * @notice You should always be able to burn an account's balance\n * @param targetAcc Account to burn from\n */\n function testBurnAllBalanceShouldNotRevert(uint8 targetAcc)\n public\n hasKnownIssue\n {\n address target = getAccount(targetAcc);\n uint256 balance = ousd.balanceOf(target);\n\n hevm.prank(ADDRESS_VAULT);\n try ousd.burn(target, balance) {\n assert(true);\n } catch {\n assert(false);\n }\n }\n}\n" + }, + "contracts/echidna/EchidnaTestSupply.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./EchidnaDebug.sol\";\nimport \"./EchidnaTestTransfer.sol\";\n\nimport { StableMath } from \"../utils/StableMath.sol\";\n\n/**\n * @title Mixin for testing supply related functions\n * @author Rappie\n */\ncontract EchidnaTestSupply is EchidnaTestTransfer {\n using StableMath for uint256;\n\n uint256 prevRebasingCreditsPerToken = type(uint256).max;\n\n /**\n * @notice After a `changeSupply`, the total supply should exactly\n * match the target total supply. (This is needed to ensure successive\n * rebases are correct).\n * @param supply New total supply\n * @custom:error testChangeSupply(uint256): failed!💥\n * Call sequence:\n * testChangeSupply(1044505275072865171609)\n * Event sequence:\n * TotalSupplyUpdatedHighres(1044505275072865171610, 1000000000000000000000000, 957391048054055578595)\n */\n function testChangeSupply(uint256 supply)\n public\n hasKnownIssue\n hasKnownIssueWithinLimits\n {\n hevm.prank(ADDRESS_VAULT);\n ousd.changeSupply(supply);\n\n assert(ousd.totalSupply() == supply);\n }\n\n /**\n * @notice The total supply must not be less than the sum of account balances.\n * (The difference will go into future rebases)\n * @custom:error testTotalSupplyLessThanTotalBalance(): failed!💥\n * Call sequence:\n * mint(0,1)\n * changeSupply(1)\n * optOut(64)\n * transfer(0,64,1)\n * testTotalSupplyLessThanTotalBalance()\n * Event sequence:\n * Debug(«totalSupply», 1000000000000000001000001)\n * Debug(«totalBalance», 1000000000000000001000002)\n */\n function testTotalSupplyLessThanTotalBalance()\n public\n hasKnownIssue\n hasKnownIssueWithinLimits\n {\n uint256 totalSupply = ousd.totalSupply();\n uint256 totalBalance = getTotalBalance();\n\n Debugger.log(\"totalSupply\", totalSupply);\n Debugger.log(\"totalBalance\", totalBalance);\n\n assert(totalSupply >= totalBalance);\n }\n\n /**\n * @notice Non-rebasing supply should not be larger than total supply\n * @custom:error testNonRebasingSupplyVsTotalSupply(): failed!💥\n * Call sequence:\n * mint(0,2)\n * changeSupply(3)\n * burn(0,1)\n * optOut(0)\n * testNonRebasingSupplyVsTotalSupply()\n */\n function testNonRebasingSupplyVsTotalSupply() public hasKnownIssue {\n uint256 nonRebasingSupply = ousd.nonRebasingSupply();\n uint256 totalSupply = ousd.totalSupply();\n\n assert(nonRebasingSupply <= totalSupply);\n }\n\n /**\n * @notice Global `rebasingCreditsPerToken` should never increase\n * @custom:error testRebasingCreditsPerTokenNotIncreased(): failed!💥\n * Call sequence:\n * testRebasingCreditsPerTokenNotIncreased()\n * changeSupply(1)\n * testRebasingCreditsPerTokenNotIncreased()\n */\n function testRebasingCreditsPerTokenNotIncreased() public hasKnownIssue {\n uint256 curRebasingCreditsPerToken = ousd\n .rebasingCreditsPerTokenHighres();\n\n Debugger.log(\n \"prevRebasingCreditsPerToken\",\n prevRebasingCreditsPerToken\n );\n Debugger.log(\"curRebasingCreditsPerToken\", curRebasingCreditsPerToken);\n\n assert(curRebasingCreditsPerToken <= prevRebasingCreditsPerToken);\n\n prevRebasingCreditsPerToken = curRebasingCreditsPerToken;\n }\n\n /**\n * @notice The rebasing credits per token ratio must greater than zero\n */\n function testRebasingCreditsPerTokenAboveZero() public {\n assert(ousd.rebasingCreditsPerTokenHighres() > 0);\n }\n\n /**\n * @notice The sum of all non-rebasing balances should not be larger than\n * non-rebasing supply\n * @custom:error testTotalNonRebasingSupplyLessThanTotalBalance(): failed!💥\n * Call sequence\n * mint(0,2)\n * changeSupply(1)\n * optOut(0)\n * burn(0,1)\n * testTotalNonRebasingSupplyLessThanTotalBalance()\n * Event sequence:\n * Debug(«totalNonRebasingSupply», 500000000000000000000001)\n * Debug(«totalNonRebasingBalance», 500000000000000000000002)\n */\n function testTotalNonRebasingSupplyLessThanTotalBalance()\n public\n hasKnownIssue\n hasKnownIssueWithinLimits\n {\n uint256 totalNonRebasingSupply = ousd.nonRebasingSupply();\n uint256 totalNonRebasingBalance = getTotalNonRebasingBalance();\n\n Debugger.log(\"totalNonRebasingSupply\", totalNonRebasingSupply);\n Debugger.log(\"totalNonRebasingBalance\", totalNonRebasingBalance);\n\n assert(totalNonRebasingSupply >= totalNonRebasingBalance);\n }\n\n /**\n * @notice An accounts credits / credits per token should not be larger it's balance\n * @param targetAcc The account to check\n */\n function testCreditsPerTokenVsBalance(uint8 targetAcc) public {\n address target = getAccount(targetAcc);\n\n (uint256 credits, uint256 creditsPerToken, ) = ousd\n .creditsBalanceOfHighres(target);\n uint256 expectedBalance = credits.divPrecisely(creditsPerToken);\n\n uint256 balance = ousd.balanceOf(target);\n\n Debugger.log(\"credits\", credits);\n Debugger.log(\"creditsPerToken\", creditsPerToken);\n Debugger.log(\"expectedBalance\", expectedBalance);\n Debugger.log(\"balance\", balance);\n\n assert(expectedBalance == balance);\n }\n}\n" + }, + "contracts/echidna/EchidnaTestTransfer.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./EchidnaDebug.sol\";\nimport \"./Debugger.sol\";\n\n/**\n * @title Mixin for testing transfer related functions\n * @author Rappie\n */\ncontract EchidnaTestTransfer is EchidnaDebug {\n /**\n * @notice The receiving account's balance after a transfer must not increase by\n * less than the amount transferred\n * @param fromAcc Account to transfer from\n * @param toAcc Account to transfer to\n * @param amount Amount to transfer\n * @custom:error testTransferBalanceReceivedLess(uint8,uint8,uint256): failed!💥\n * Call sequence:\n * changeSupply(1)\n * mint(64,2)\n * testTransferBalanceReceivedLess(64,0,1)\n * Event sequence:\n * Debug(«totalSupply», 1000000000000000000500002)\n * Debug(«toBalBefore», 0)\n * Debug(«toBalAfter», 0)\n */\n function testTransferBalanceReceivedLess(\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public hasKnownIssue hasKnownIssueWithinLimits {\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n\n require(from != to);\n\n uint256 toBalBefore = ousd.balanceOf(to);\n transfer(fromAcc, toAcc, amount);\n uint256 toBalAfter = ousd.balanceOf(to);\n\n Debugger.log(\"totalSupply\", ousd.totalSupply());\n Debugger.log(\"toBalBefore\", toBalBefore);\n Debugger.log(\"toBalAfter\", toBalAfter);\n\n assert(toBalAfter >= toBalBefore + amount);\n }\n\n /**\n * @notice The receiving account's balance after a transfer must not\n * increase by more than the amount transferred\n * @param fromAcc Account to transfer from\n * @param toAcc Account to transfer to\n * @param amount Amount to transfer\n */\n function testTransferBalanceReceivedMore(\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public {\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n\n require(from != to);\n\n uint256 toBalBefore = ousd.balanceOf(to);\n transfer(fromAcc, toAcc, amount);\n uint256 toBalAfter = ousd.balanceOf(to);\n\n Debugger.log(\"totalSupply\", ousd.totalSupply());\n Debugger.log(\"toBalBefore\", toBalBefore);\n Debugger.log(\"toBalAfter\", toBalAfter);\n\n assert(toBalAfter <= toBalBefore + amount);\n }\n\n /**\n * @notice The sending account's balance after a transfer must not\n * decrease by less than the amount transferred\n * @param fromAcc Account to transfer from\n * @param toAcc Account to transfer to\n * @param amount Amount to transfer\n * @custom:error testTransferBalanceSentLess(uint8,uint8,uint256): failed!💥\n * Call sequence:\n * mint(0,1)\n * changeSupply(1)\n * testTransferBalanceSentLess(0,64,1)\n * Event sequence:\n * Debug(«totalSupply», 1000000000000000000500001)\n * Debug(«fromBalBefore», 1)\n * Debug(«fromBalAfter», 1)\n */\n function testTransferBalanceSentLess(\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public hasKnownIssue hasKnownIssueWithinLimits {\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n\n require(from != to);\n\n uint256 fromBalBefore = ousd.balanceOf(from);\n transfer(fromAcc, toAcc, amount);\n uint256 fromBalAfter = ousd.balanceOf(from);\n\n Debugger.log(\"totalSupply\", ousd.totalSupply());\n Debugger.log(\"fromBalBefore\", fromBalBefore);\n Debugger.log(\"fromBalAfter\", fromBalAfter);\n\n assert(fromBalAfter <= fromBalBefore - amount);\n }\n\n /**\n * @notice The sending account's balance after a transfer must not\n * decrease by more than the amount transferred\n * @param fromAcc Account to transfer from\n * @param toAcc Account to transfer to\n * @param amount Amount to transfer\n */\n function testTransferBalanceSentMore(\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public {\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n\n require(from != to);\n\n uint256 fromBalBefore = ousd.balanceOf(from);\n transfer(fromAcc, toAcc, amount);\n uint256 fromBalAfter = ousd.balanceOf(from);\n\n Debugger.log(\"totalSupply\", ousd.totalSupply());\n Debugger.log(\"fromBalBefore\", fromBalBefore);\n Debugger.log(\"fromBalAfter\", fromBalAfter);\n\n assert(fromBalAfter >= fromBalBefore - amount);\n }\n\n /**\n * @notice The receiving account's balance after a transfer must not\n * increase by less than the amount transferred (minus rounding error)\n * @param fromAcc Account to transfer from\n * @param toAcc Account to transfer to\n * @param amount Amount to transfer\n */\n function testTransferBalanceReceivedLessRounding(\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public {\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n\n require(from != to);\n\n uint256 toBalBefore = ousd.balanceOf(to);\n transfer(fromAcc, toAcc, amount);\n uint256 toBalAfter = ousd.balanceOf(to);\n\n int256 toDelta = int256(toBalAfter) - int256(toBalBefore);\n\n // delta == amount, if no error\n // delta < amount, if too little is sent\n // delta > amount, if too much is sent\n int256 error = int256(amount) - toDelta;\n\n Debugger.log(\"totalSupply\", ousd.totalSupply());\n Debugger.log(\"toBalBefore\", toBalBefore);\n Debugger.log(\"toBalAfter\", toBalAfter);\n Debugger.log(\"toDelta\", toDelta);\n Debugger.log(\"error\", error);\n\n assert(error >= 0);\n assert(error <= int256(TRANSFER_ROUNDING_ERROR));\n }\n\n /**\n * @notice The sending account's balance after a transfer must\n * not decrease by less than the amount transferred (minus rounding error)\n * @param fromAcc Account to transfer from\n * @param toAcc Account to transfer to\n * @param amount Amount to transfer\n */\n function testTransferBalanceSentLessRounding(\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public {\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n\n require(from != to);\n\n uint256 fromBalBefore = ousd.balanceOf(from);\n transfer(fromAcc, toAcc, amount);\n uint256 fromBalAfter = ousd.balanceOf(from);\n\n int256 fromDelta = int256(fromBalAfter) - int256(fromBalBefore);\n\n // delta == -amount, if no error\n // delta < -amount, if too much is sent\n // delta > -amount, if too little is sent\n int256 error = int256(amount) + fromDelta;\n\n Debugger.log(\"totalSupply\", ousd.totalSupply());\n Debugger.log(\"fromBalBefore\", fromBalBefore);\n Debugger.log(\"fromBalAfter\", fromBalAfter);\n Debugger.log(\"fromDelta\", fromDelta);\n Debugger.log(\"error\", error);\n\n assert(error >= 0);\n assert(error <= int256(TRANSFER_ROUNDING_ERROR));\n }\n\n /**\n * @notice An account should always be able to successfully transfer\n * an amount within its balance.\n * @param fromAcc Account to transfer from\n * @param toAcc Account to transfer to\n * @param amount Amount to transfer\n * @custom:error testTransferWithinBalanceDoesNotRevert(uint8,uint8,uint8): failed!💥\n * Call sequence:\n * mint(0,1)\n * changeSupply(3)\n * optOut(0)\n * testTransferWithinBalanceDoesNotRevert(0,128,2)\n * optIn(0)\n * testTransferWithinBalanceDoesNotRevert(128,0,1)\n * Event sequence:\n * error Revert Panic(17): SafeMath over-/under-flows\n */\n function testTransferWithinBalanceDoesNotRevert(\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public hasKnownIssue {\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n\n require(amount > 0);\n amount = amount % ousd.balanceOf(from);\n\n Debugger.log(\"Total supply\", ousd.totalSupply());\n\n hevm.prank(from);\n // slither-disable-next-line unchecked-transfer\n try ousd.transfer(to, amount) {\n assert(true);\n } catch {\n assert(false);\n }\n }\n\n /**\n * @notice An account should never be able to successfully transfer\n * an amount greater than their balance.\n * @param fromAcc Account to transfer from\n * @param toAcc Account to transfer to\n * @param amount Amount to transfer\n */\n function testTransferExceedingBalanceReverts(\n uint8 fromAcc,\n uint8 toAcc,\n uint256 amount\n ) public {\n address from = getAccount(fromAcc);\n address to = getAccount(toAcc);\n\n amount = ousd.balanceOf(from) + 1 + amount;\n\n hevm.prank(from);\n // slither-disable-next-line unchecked-transfer\n try ousd.transfer(to, amount) {\n assert(false);\n } catch {\n assert(true);\n }\n }\n\n /**\n * @notice A transfer to the same account should not change that account's balance\n * @param targetAcc Account to transfer to\n * @param amount Amount to transfer\n */\n function testTransferSelf(uint8 targetAcc, uint256 amount) public {\n address target = getAccount(targetAcc);\n\n uint256 balanceBefore = ousd.balanceOf(target);\n transfer(targetAcc, targetAcc, amount);\n uint256 balanceAfter = ousd.balanceOf(target);\n\n assert(balanceBefore == balanceAfter);\n }\n\n /**\n * @notice Transfers to the zero account revert\n * @param fromAcc Account to transfer from\n * @param amount Amount to transfer\n */\n function testTransferToZeroAddress(uint8 fromAcc, uint256 amount) public {\n address from = getAccount(fromAcc);\n\n hevm.prank(from);\n // slither-disable-next-line unchecked-transfer\n try ousd.transfer(address(0), amount) {\n assert(false);\n } catch {\n assert(true);\n }\n }\n}\n" + }, + "contracts/echidna/IHevm.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n// https://github.com/ethereum/hevm/blob/main/doc/src/controlling-the-unit-testing-environment.md#cheat-codes\n\ninterface IHevm {\n function warp(uint256 x) external;\n\n function roll(uint256 x) external;\n\n function store(\n address c,\n bytes32 loc,\n bytes32 val\n ) external;\n\n function load(address c, bytes32 loc) external returns (bytes32 val);\n\n function sign(uint256 sk, bytes32 digest)\n external\n returns (\n uint8 v,\n bytes32 r,\n bytes32 s\n );\n\n function addr(uint256 sk) external returns (address addr);\n\n function ffi(string[] calldata) external returns (bytes memory);\n\n function prank(address sender) external;\n}\n" + }, + "contracts/echidna/OUSDEchidna.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../token/OUSD.sol\";\n\ncontract OUSDEchidna is OUSD {\n constructor() OUSD() {}\n\n function _isNonRebasingAccountEchidna(address _account)\n public\n returns (bool)\n {\n return _isNonRebasingAccount(_account);\n }\n}\n" + }, + "contracts/flipper/Flipper.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../governance/Governable.sol\";\nimport \"../token/OUSD.sol\";\nimport \"../interfaces/Tether.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Contract to exchange usdt, usdc, dai from and to ousd.\n// - 1 to 1. No slippage\n// - Optimized for low gas usage\n// - No guarantee of availability\n\ncontract Flipper is Governable {\n using SafeERC20 for IERC20;\n\n uint256 constant MAXIMUM_PER_TRADE = (25000 * 1e18);\n\n // Settable coin addresses allow easy testing and use of mock currencies.\n IERC20 immutable dai;\n OUSD immutable ousd;\n IERC20 immutable usdc;\n Tether immutable usdt;\n\n // ---------------------\n // Dev constructor\n // ---------------------\n constructor(\n address _dai,\n address _ousd,\n address _usdc,\n address _usdt\n ) {\n require(address(_dai) != address(0));\n require(address(_ousd) != address(0));\n require(address(_usdc) != address(0));\n require(address(_usdt) != address(0));\n dai = IERC20(_dai);\n ousd = OUSD(_ousd);\n usdc = IERC20(_usdc);\n usdt = Tether(_usdt);\n }\n\n // -----------------\n // Trading functions\n // -----------------\n\n /// @notice Purchase OUSD with Dai\n /// @param amount Amount of OUSD to purchase, in 18 fixed decimals.\n function buyOusdWithDai(uint256 amount) external {\n require(amount <= MAXIMUM_PER_TRADE, \"Amount too large\");\n require(\n dai.transferFrom(msg.sender, address(this), amount),\n \"DAI transfer failed\"\n );\n require(ousd.transfer(msg.sender, amount), \"OUSD transfer failed\");\n }\n\n /// @notice Sell OUSD for Dai\n /// @param amount Amount of OUSD to sell, in 18 fixed decimals.\n function sellOusdForDai(uint256 amount) external {\n require(amount <= MAXIMUM_PER_TRADE, \"Amount too large\");\n require(dai.transfer(msg.sender, amount), \"DAI transfer failed\");\n require(\n ousd.transferFrom(msg.sender, address(this), amount),\n \"OUSD transfer failed\"\n );\n }\n\n /// @notice Purchase OUSD with USDC\n /// @param amount Amount of OUSD to purchase, in 18 fixed decimals.\n function buyOusdWithUsdc(uint256 amount) external {\n require(amount <= MAXIMUM_PER_TRADE, \"Amount too large\");\n // Potential rounding error is an intentional trade off\n require(\n usdc.transferFrom(msg.sender, address(this), amount / 1e12),\n \"USDC transfer failed\"\n );\n require(ousd.transfer(msg.sender, amount), \"OUSD transfer failed\");\n }\n\n /// @notice Sell OUSD for USDC\n /// @param amount Amount of OUSD to sell, in 18 fixed decimals.\n function sellOusdForUsdc(uint256 amount) external {\n require(amount <= MAXIMUM_PER_TRADE, \"Amount too large\");\n require(\n usdc.transfer(msg.sender, amount / 1e12),\n \"USDC transfer failed\"\n );\n require(\n ousd.transferFrom(msg.sender, address(this), amount),\n \"OUSD transfer failed\"\n );\n }\n\n /// @notice Purchase OUSD with USDT\n /// @param amount Amount of OUSD to purchase, in 18 fixed decimals.\n function buyOusdWithUsdt(uint256 amount) external {\n require(amount <= MAXIMUM_PER_TRADE, \"Amount too large\");\n // Potential rounding error is an intentional trade off\n // USDT does not return a boolean and reverts,\n // so no need for a require.\n usdt.transferFrom(msg.sender, address(this), amount / 1e12);\n require(ousd.transfer(msg.sender, amount), \"OUSD transfer failed\");\n }\n\n /// @notice Sell OUSD for USDT\n /// @param amount Amount of OUSD to sell, in 18 fixed decimals.\n function sellOusdForUsdt(uint256 amount) external {\n require(amount <= MAXIMUM_PER_TRADE, \"Amount too large\");\n // USDT does not return a boolean and reverts,\n // so no need for a require.\n usdt.transfer(msg.sender, amount / 1e12);\n require(\n ousd.transferFrom(msg.sender, address(this), amount),\n \"OUSD transfer failed\"\n );\n }\n\n // --------------------\n // Governance functions\n // --------------------\n\n /// @dev Opting into yield reduces the gas cost per transfer by about 4K, since\n /// ousd needs to do less accounting and one less storage write.\n function rebaseOptIn() external onlyGovernor nonReentrant {\n ousd.rebaseOptIn();\n }\n\n /// @notice Owner function to withdraw a specific amount of a token\n function withdraw(address token, uint256 amount)\n external\n onlyGovernor\n nonReentrant\n {\n IERC20(token).safeTransfer(_governor(), amount);\n }\n\n /// @notice Owner function to withdraw all tradable tokens\n /// @dev Contract will not perform any swaps until liquidity is provided\n /// again by transferring assets to the contract.\n function withdrawAll() external onlyGovernor nonReentrant {\n IERC20(dai).safeTransfer(_governor(), dai.balanceOf(address(this)));\n IERC20(ousd).safeTransfer(_governor(), ousd.balanceOf(address(this)));\n IERC20(address(usdt)).safeTransfer(\n _governor(),\n usdt.balanceOf(address(this))\n );\n IERC20(usdc).safeTransfer(_governor(), usdc.balanceOf(address(this)));\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/governance/Governor.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./../timelock/Timelock.sol\";\n\n// Modeled off of Compound's Governor Alpha\n// https://github.com/compound-finance/compound-protocol/blob/master/contracts/Governance/GovernorAlpha.sol\ncontract Governor is Timelock {\n // @notice The total number of proposals\n uint256 public proposalCount;\n\n struct Proposal {\n // @notice Unique id for looking up a proposal\n uint256 id;\n // @notice Creator of the proposal\n address proposer;\n // @notice The timestamp that the proposal will be available for\n // execution, set once the vote succeeds\n uint256 eta;\n // @notice the ordered list of target addresses for calls to be made\n address[] targets;\n // @notice The ordered list of function signatures to be called\n string[] signatures;\n // @notice The ordered list of calldata to be passed to each call\n bytes[] calldatas;\n // @notice Flag marking whether the proposal has been executed\n bool executed;\n }\n\n // @notice The official record of all proposals ever proposed\n mapping(uint256 => Proposal) public proposals;\n\n // @notice An event emitted when a new proposal is created\n event ProposalCreated(\n uint256 id,\n address proposer,\n address[] targets,\n string[] signatures,\n bytes[] calldatas,\n string description\n );\n\n // @notice An event emitted when a proposal has been queued in the Timelock\n event ProposalQueued(uint256 id, uint256 eta);\n\n // @notice An event emitted when a proposal has been executed in the Timelock\n event ProposalExecuted(uint256 id);\n\n // @notice An event emitted when a proposal has been cancelled\n event ProposalCancelled(uint256 id);\n\n uint256 public constant MAX_OPERATIONS = 32;\n\n // @notice Possible states that a proposal may be in\n enum ProposalState {\n Pending,\n Queued,\n Expired,\n Executed\n }\n\n constructor(address admin_, uint256 delay_) Timelock(admin_, delay_) {}\n\n /**\n * @notice Propose Governance call(s)\n * @param targets Ordered list of targeted addresses\n * @param signatures Orderd list of function signatures to be called\n * @param calldatas Orderded list of calldata to be passed with each call\n * @param description Description of the governance\n * @return uint256 id of the proposal\n */\n function propose(\n address[] memory targets,\n string[] memory signatures,\n bytes[] memory calldatas,\n string memory description\n ) public returns (uint256) {\n // Allow anyone to propose for now, since only admin can queue the\n // transaction it should be harmless, you just need to pay the gas\n require(\n targets.length == signatures.length &&\n targets.length == calldatas.length,\n \"Governor::propose: proposal function information arity mismatch\"\n );\n require(targets.length != 0, \"Governor::propose: must provide actions\");\n require(\n targets.length <= MAX_OPERATIONS,\n \"Governor::propose: too many actions\"\n );\n\n proposalCount++;\n Proposal memory newProposal = Proposal({\n id: proposalCount,\n proposer: msg.sender,\n eta: 0,\n targets: targets,\n signatures: signatures,\n calldatas: calldatas,\n executed: false\n });\n\n proposals[newProposal.id] = newProposal;\n\n emit ProposalCreated(\n newProposal.id,\n msg.sender,\n targets,\n signatures,\n calldatas,\n description\n );\n return newProposal.id;\n }\n\n /**\n * @notice Queue a proposal for execution\n * @param proposalId id of the proposal to queue\n */\n function queue(uint256 proposalId) public onlyAdmin {\n require(\n state(proposalId) == ProposalState.Pending,\n \"Governor::queue: proposal can only be queued if it is pending\"\n );\n Proposal storage proposal = proposals[proposalId];\n proposal.eta = block.timestamp + delay;\n\n for (uint256 i = 0; i < proposal.targets.length; i++) {\n _queueOrRevert(\n proposal.targets[i],\n proposal.signatures[i],\n proposal.calldatas[i],\n proposal.eta\n );\n }\n\n emit ProposalQueued(proposal.id, proposal.eta);\n }\n\n /**\n * @notice Get the state of a proposal\n * @param proposalId id of the proposal\n * @return ProposalState\n */\n function state(uint256 proposalId) public view returns (ProposalState) {\n require(\n proposalCount >= proposalId && proposalId > 0,\n \"Governor::state: invalid proposal id\"\n );\n Proposal storage proposal = proposals[proposalId];\n if (proposal.executed) {\n return ProposalState.Executed;\n } else if (proposal.eta == 0) {\n return ProposalState.Pending;\n } else if (block.timestamp >= proposal.eta + GRACE_PERIOD) {\n return ProposalState.Expired;\n } else {\n return ProposalState.Queued;\n }\n }\n\n function _queueOrRevert(\n address target,\n string memory signature,\n bytes memory data,\n uint256 eta\n ) internal {\n require(\n !queuedTransactions[\n keccak256(abi.encode(target, signature, keccak256(data), eta))\n ],\n \"Governor::_queueOrRevert: proposal action already queued at eta\"\n );\n require(\n queuedTransactions[queueTransaction(target, signature, data, eta)],\n \"Governor::_queueOrRevert: failed to queue transaction\"\n );\n }\n\n /**\n * @notice Execute a proposal.\n * @param proposalId id of the proposal\n */\n function execute(uint256 proposalId) public {\n require(\n state(proposalId) == ProposalState.Queued,\n \"Governor::execute: proposal can only be executed if it is queued\"\n );\n Proposal storage proposal = proposals[proposalId];\n proposal.executed = true;\n for (uint256 i = 0; i < proposal.targets.length; i++) {\n executeTransaction(\n proposal.targets[i],\n proposal.signatures[i],\n proposal.calldatas[i],\n proposal.eta\n );\n }\n emit ProposalExecuted(proposalId);\n }\n\n /**\n * @notice Cancel a proposal.\n * @param proposalId id of the proposal\n */\n function cancel(uint256 proposalId) public onlyAdmin {\n ProposalState proposalState = state(proposalId);\n\n require(\n proposalState == ProposalState.Queued ||\n proposalState == ProposalState.Pending,\n \"Governor::execute: proposal can only be cancelled if it is queued or pending\"\n );\n Proposal storage proposal = proposals[proposalId];\n proposal.eta = 1; // To mark the proposal as `Expired`\n for (uint256 i = 0; i < proposal.targets.length; i++) {\n cancelTransaction(\n proposal.targets[i],\n proposal.signatures[i],\n proposal.calldatas[i],\n proposal.eta\n );\n }\n emit ProposalCancelled(proposalId);\n }\n\n /**\n * @notice Get the actions that a proposal will take.\n * @param proposalId id of the proposal\n */\n function getActions(uint256 proposalId)\n public\n view\n returns (\n address[] memory targets,\n string[] memory signatures,\n bytes[] memory calldatas\n )\n {\n Proposal storage p = proposals[proposalId];\n return (p.targets, p.signatures, p.calldatas);\n }\n}\n" + }, + "contracts/governance/InitializableGovernable.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @title OUSD InitializableGovernable Contract\n * @author Origin Protocol Inc\n */\nimport { Initializable } from \"../utils/Initializable.sol\";\n\nimport { Governable } from \"./Governable.sol\";\n\ncontract InitializableGovernable is Governable, Initializable {\n function _initialize(address _newGovernor) internal {\n _changeGovernor(_newGovernor);\n }\n}\n" + }, + "contracts/governance/Strategizable.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { Governable } from \"./Governable.sol\";\n\ncontract Strategizable is Governable {\n event StrategistUpdated(address _address);\n\n // Address of strategist\n address public strategistAddr;\n\n // For future use\n uint256[50] private __gap;\n\n /**\n * @dev Verifies that the caller is either 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 * @dev Set address of Strategist\n * @param _address Address of Strategist\n */\n function setStrategistAddr(address _address) external onlyGovernor {\n _setStrategistAddr(_address);\n }\n\n /**\n * @dev Set address of Strategist\n * @param _address Address of Strategist\n */\n function _setStrategistAddr(address _address) internal {\n strategistAddr = _address;\n emit StrategistUpdated(_address);\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/IOracleWeightedPool.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n// The three values that can be queried:\n//\n// - PAIR_PRICE: the price of the tokens in the Pool, expressed as the price of the second token in units of the\n// first token. For example, if token A is worth $2, and token B is worth $4, the pair price will be 2.0.\n// Note that the price is computed *including* the tokens decimals. This means that the pair price of a Pool with\n// DAI and USDC will be close to 1.0, despite DAI having 18 decimals and USDC 6.\n//\n// - BPT_PRICE: the price of the Pool share token (BPT), in units of the first token.\n// Note that the price is computed *including* the tokens decimals. This means that the BPT price of a Pool with\n// USDC in which BPT is worth $5 will be 5.0, despite the BPT having 18 decimals and USDC 6.\n//\n// - INVARIANT: the value of the Pool's invariant, which serves as a measure of its liquidity.\nenum Variable {\n PAIR_PRICE,\n BPT_PRICE,\n INVARIANT\n}\n\n/**\n * @dev Information for a Time Weighted Average query.\n *\n * Each query computes the average over a window of duration `secs` seconds that ended `ago` seconds ago. For\n * example, the average over the past 30 minutes is computed by settings secs to 1800 and ago to 0. If secs is 1800\n * and ago is 1800 as well, the average between 60 and 30 minutes ago is computed instead.\n */\nstruct OracleAverageQuery {\n Variable variable;\n uint256 secs;\n uint256 ago;\n}\n\ninterface IOracleWeightedPool {\n /**\n * @dev Returns the time average weighted price corresponding to each of `queries`. Prices are represented as 18\n * decimal fixed point values.\n */\n function getTimeWeightedAverage(OracleAverageQuery[] memory queries)\n external\n view\n returns (uint256[] memory results);\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/chainlink/AggregatorV3Interface.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface AggregatorV3Interface {\n function decimals() external view returns (uint8);\n\n function description() external view returns (string memory);\n\n function version() external view returns (uint256);\n\n // getRoundData and latestRoundData should both raise \"No data present\"\n // if they do not have data to report, instead of returning unset values\n // which could be misinterpreted as actual reported values.\n function getRoundData(uint80 _roundId)\n external\n view\n returns (\n uint80 roundId,\n int256 answer,\n uint256 startedAt,\n uint256 updatedAt,\n uint80 answeredInRound\n );\n\n function latestRoundData()\n external\n view\n returns (\n uint80 roundId,\n int256 answer,\n uint256 startedAt,\n uint256 updatedAt,\n uint80 answeredInRound\n );\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/IBuyback.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IBuyback {\n function swap() external;\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/ICVXLocker.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface ICVXLocker {\n function lock(\n address _account,\n uint256 _amount,\n uint256 _spendRatio\n ) external;\n\n function lockedBalanceOf(address _account) external view returns (uint256);\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/IEthUsdOracle.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IEthUsdOracle {\n /**\n * @notice Returns ETH price in USD.\n * @return Price in USD with 6 decimal digits.\n */\n function ethUsdPrice() external view returns (uint256);\n\n /**\n * @notice Returns token price in USD.\n * @param symbol. Asset symbol. For ex. \"DAI\".\n * @return Price in USD with 6 decimal digits.\n */\n function tokUsdPrice(string calldata symbol)\n external\n view\n returns (uint256);\n\n /**\n * @notice Returns the asset price in ETH.\n * @param symbol. Asset symbol. For ex. \"DAI\".\n * @return Price in ETH with 8 decimal digits.\n */\n function tokEthPrice(string calldata symbol)\n external\n view\n returns (uint256);\n}\n\ninterface IViewEthUsdOracle {\n /**\n * @notice Returns ETH price in USD.\n * @return Price in USD with 6 decimal digits.\n */\n function ethUsdPrice() external view returns (uint256);\n\n /**\n * @notice Returns token price in USD.\n * @param symbol. Asset symbol. For ex. \"DAI\".\n * @return Price in USD with 6 decimal digits.\n */\n function tokUsdPrice(string calldata symbol)\n external\n view\n returns (uint256);\n\n /**\n * @notice Returns the asset price in ETH.\n * @param symbol. Asset symbol. For ex. \"DAI\".\n * @return Price in ETH with 8 decimal digits.\n */\n function tokEthPrice(string calldata symbol)\n external\n view\n returns (uint256);\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/IMinMaxOracle.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IMinMaxOracle {\n //Assuming 8 decimals\n function priceMin(string calldata symbol) external view returns (uint256);\n\n function priceMax(string calldata symbol) external view returns (uint256);\n}\n" + }, + "contracts/interfaces/IOETHZapper.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IOETHZapper {\n function deposit() external payable returns (uint256);\n}\n" + }, + "contracts/interfaces/IOneInch.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/// 1Inch swap data\nstruct SwapDescription {\n IERC20 srcToken; // contract address of a token to sell\n IERC20 dstToken; // contract address of a token to buy\n address payable srcReceiver;\n address payable dstReceiver; // Receiver of destination currency. default: fromAddress\n uint256 amount;\n uint256 minReturnAmount;\n uint256 flags;\n}\n\n/// @title Interface for making arbitrary calls during swap\ninterface IAggregationExecutor {\n /// @notice propagates information about original msg.sender and executes arbitrary data\n function execute(address msgSender) external payable; // 0x4b64e492\n}\n\ninterface IOneInchRouter {\n /// @notice Performs a swap, delegating all calls encoded in `data` to `executor`.\n function swap(\n IAggregationExecutor executor,\n SwapDescription calldata desc,\n bytes calldata permit,\n bytes calldata data\n ) external returns (uint256 returnAmount, uint256 spentAmount);\n\n /// @notice Performs swap using Uniswap exchange. Wraps and unwraps ETH if required.\n function unoswapTo(\n address payable recipient,\n IERC20 srcToken,\n uint256 amount,\n uint256 minReturn,\n uint256[] calldata pools\n ) external payable returns (uint256 returnAmount);\n\n /// @notice Performs swap using Uniswap V3 exchange. Wraps and unwraps ETH if required.\n function uniswapV3SwapTo(\n address payable recipient,\n uint256 amount,\n uint256 minReturn,\n uint256[] calldata pools\n ) external payable returns (uint256 returnAmount);\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/IPriceOracle.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IPriceOracle {\n /**\n * @dev returns the asset price in USD, 6 decimal digits.\n * Compatible with the Open Price Feed.\n */\n function price(string calldata symbol) external view returns (uint256);\n}\n" + }, + "contracts/interfaces/IRETH.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IRETH {\n function getEthValue(uint256 _rethAmount) external view returns (uint256);\n\n function getRethValue(uint256 _ethAmount) external view returns (uint256);\n\n function getExchangeRate() external view returns (uint256);\n\n function totalSupply() external view returns (uint256);\n\n function balanceOf(address account) external view returns (uint256);\n\n function transfer(address recipient, uint256 amount)\n external\n returns (bool);\n\n function allowance(address owner, address spender)\n external\n view\n returns (uint256);\n\n function approve(address spender, uint256 amount) external returns (bool);\n\n function transferFrom(\n address sender,\n address recipient,\n uint256 amount\n ) external returns (bool);\n\n function name() external view returns (string memory);\n\n function symbol() external view returns (string memory);\n\n function decimals() external view returns (uint8);\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 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 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 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/ITimelock.sol": { + "content": "pragma solidity ^0.8.0;\n\ninterface ITimelock {\n function delay() external view returns (uint256);\n\n function GRACE_PERIOD() external view returns (uint256);\n\n function acceptAdmin() external;\n\n function queuedTransactions(bytes32 hash) external view returns (bool);\n\n function queueTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) external returns (bytes32);\n\n function cancelTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) external;\n\n function executeTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) external payable returns (bytes memory);\n}\n" + }, + "contracts/interfaces/ITimelockController.sol": { + "content": "pragma solidity ^0.8.0;\n\ninterface ITimelockController {\n function grantRole(bytes32 role, address account) external;\n\n function revokeRole(bytes32 role, address account) external;\n\n function renounceRole(bytes32 role, address account) external;\n\n function hasRole(bytes32 role, address account)\n external\n view\n returns (bool);\n\n function executeBatch(\n address[] calldata targets,\n uint256[] calldata values,\n bytes[] calldata payloads,\n bytes32 predecessor,\n bytes32 salt\n ) external payable;\n\n function scheduleBatch(\n address[] calldata targets,\n uint256[] calldata values,\n bytes[] calldata payloads,\n bytes32 predecessor,\n bytes32 salt,\n uint256 delay\n ) external;\n\n function hashOperationBatch(\n address[] calldata targets,\n uint256[] calldata values,\n bytes[] calldata payloads,\n bytes32 predecessor,\n bytes32 salt\n ) external;\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\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 function removeAsset(address _asset) external;\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/Tether.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface Tether {\n function transfer(address to, uint256 value) external;\n\n function transferFrom(\n address from,\n address to,\n uint256 value\n ) external;\n\n function balanceOf(address) external returns (uint256);\n}\n" + }, + "contracts/interfaces/uniswap/IUniswapUniversalRouter.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IUniswapUniversalRouter {\n /// @notice Executes encoded commands along with provided inputs. Reverts if deadline has expired.\n /// @param commands A set of concatenated commands, each 1 byte in length\n /// @param inputs An array of byte strings containing abi encoded inputs for each command\n /// @param deadline The deadline by which the transaction must be executed\n function execute(\n bytes calldata commands,\n bytes[] calldata inputs,\n uint256 deadline\n ) external payable;\n\n function execute(bytes calldata commands, bytes[] calldata inputs)\n external\n payable;\n}\n" + }, + "contracts/interfaces/uniswap/IUniswapV2Pair.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IUniswapV2Pair {\n function token0() external view returns (address);\n\n function token1() external view returns (address);\n\n function getReserves()\n external\n view\n returns (\n uint112 reserve0,\n uint112 reserve1,\n uint32 blockTimestampLast\n );\n\n function price0CumulativeLast() external view returns (uint256);\n\n function price1CumulativeLast() external view returns (uint256);\n\n function sync() external;\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/liquidity/LiquidityReward.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { SafeMath } from \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\n\nimport { Initializable } from \"../utils/Initializable.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\nimport { Governable } from \"../governance/Governable.sol\";\n\n//\n// LiquidityReward contract doles out reward for liquidity\n// base off of Sushiswap's MasterChef: https://github.com/sushiswap/sushiswap/blob/master/contracts/MasterChef.sol\n//\ncontract LiquidityReward is Initializable, Governable {\n using SafeMath for uint256;\n using StableMath for uint256;\n using SafeERC20 for IERC20;\n\n // Info of each user.\n struct UserInfo {\n uint256 amount; // How many LP tokens the user has provided.\n int256 rewardDebt; // Reward debt. See explanation below.\n //\n // We do some fancy math here. Basically, any point in time, the amount of Reward Tokens\n // entitled to a user but is pending to be distributed is:\n //\n // pending reward = (user.amount * pool.accRewardPerShare) - user.rewardDebt\n //\n // Whenever a user deposits or withdraws LP tokens to a pool. Here's what happens:\n // 1. The pool's `accRewardPerShare` (and `lastRewardBlock`) gets updated.\n // 2. User receives the pending reward sent to his/her address.\n // 3. User's `amount` gets updated.\n // 4. User's `rewardDebt` gets updated.\n //\n // NOTE: rewardDebt can go negative because we allow withdraws without claiming the reward\n // in that case we owe the account holder some reward.\n }\n\n // Info of each pool.\n struct PoolInfo {\n IERC20 lpToken; // Address of LP token contract.\n uint256 lastRewardBlock; // Last block number that Reward calculation occurs.\n uint256 accRewardPerShare; // Accumulated Reward per share in reward precision. See below.\n }\n\n // The Reward token\n IERC20 public reward;\n\n // Reward tokens created per block in 1e18 precision.\n uint256 public rewardPerBlock;\n\n // Info on the LP.\n PoolInfo public pool;\n // total Reward debt, useful to calculate if we have enough to pay out all rewards\n int256 public totalRewardDebt;\n // total Supply that is accounted for via deposit/withdraw so that our rewards calc are stable\n uint256 public totalSupply;\n // Info of each user that stakes LP tokens.\n mapping(address => UserInfo) public userInfo;\n // The block number when Liquidity rewards ends.\n uint256 public endBlock;\n\n event CampaignStarted(\n uint256 rewardRate,\n uint256 startBlock,\n uint256 endBlock\n );\n event CampaignStopped(uint256 endBlock);\n event Deposit(address indexed user, uint256 amount);\n event Withdraw(address indexed user, uint256 amount);\n event Claim(address indexed user, uint256 amount);\n event DrainExtraReward(address indexed user, uint256 amount);\n event DrainExtraLP(address indexed user, uint256 amount);\n\n /**\n * Initializer for setting up Liquidity Reward internal state.\n * @param _reward Address of the reward token(OGN)\n * @param _lpToken Address of the LP token(Uniswap Pair)\n */\n function initialize(IERC20 _reward, IERC20 _lpToken)\n external\n onlyGovernor\n initializer\n {\n reward = _reward;\n pool.lpToken = _lpToken;\n pool.lastRewardBlock = block.number;\n }\n\n /**\n * @dev start a new reward campaign.\n * This will calculate all rewards up to the current block at the old rate.\n * This ensures that we pay everyone at the promised rate before update to the new rate.\n * @param _rewardPerBlock Amount rewarded per block\n * @param _startBlock Block number that we want to start the rewards at (0 for current block)\n * @param _numBlocks number of blocks that the campaign should last\n */\n function startCampaign(\n uint256 _rewardPerBlock,\n uint256 _startBlock,\n uint256 _numBlocks\n ) external onlyGovernor {\n // Calculate up to the current block at the current rate for everyone.\n updatePool();\n\n // total Pending calculated at the current pool rate\n uint256 totalPending = subDebt(\n pool.accRewardPerShare.mulTruncate(totalSupply),\n totalRewardDebt\n );\n\n require(_numBlocks > 0, \"startCampaign: zero blocks\");\n\n require(\n reward.balanceOf(address(this)) >=\n _rewardPerBlock.mul(_numBlocks).add(totalPending),\n \"startCampaign: insufficient rewards\"\n );\n\n uint256 startBlock = _startBlock;\n if (startBlock == 0) {\n // start block number isn't given so we start at the current\n startBlock = block.number;\n }\n require(\n startBlock >= block.number,\n \"startCampaign: _startBlock can't be in the past\"\n );\n endBlock = startBlock.add(_numBlocks);\n // we don't start accrue until the startBlock\n pool.lastRewardBlock = startBlock;\n // new blocks start at the new reward rate\n rewardPerBlock = _rewardPerBlock;\n emit CampaignStarted(rewardPerBlock, startBlock, endBlock);\n }\n\n function stopCampaign() external onlyGovernor {\n //calculate until current pool\n updatePool();\n //end the block here (the CampaignMultiplier will be zero)\n endBlock = block.number;\n emit CampaignStopped(endBlock);\n }\n\n function drainExtraRewards() external onlyGovernor {\n require(endBlock < block.number, \"drainExtraRewards:Campaign active\");\n updatePool();\n uint256 extraRewards = reward.balanceOf(address(this)).sub(\n subDebt(\n pool.accRewardPerShare.mulTruncate(totalSupply),\n totalRewardDebt\n )\n );\n if (extraRewards > 0) {\n emit DrainExtraReward(msg.sender, extraRewards);\n reward.safeTransfer(msg.sender, extraRewards);\n }\n }\n\n function drainExtraLP() external onlyGovernor {\n uint256 extraLP = pool.lpToken.balanceOf(address(this)).sub(\n totalSupply\n );\n require(extraLP > 0, \"drainExtraLP:no extra\");\n emit DrainExtraLP(msg.sender, extraLP);\n pool.lpToken.safeTransfer(msg.sender, extraLP);\n }\n\n function campaignActive() external view returns (bool) {\n return endBlock > block.number && block.number >= pool.lastRewardBlock;\n }\n\n function balanceOf(address _account) external view returns (uint256) {\n return userInfo[_account].amount;\n }\n\n /**\n * @dev calculate the number of blocks since we last updated\n * within start and end as constraints\n * @param _to Block number of the ending point.\n * @return multiplier Multiplier over the given _from to _to block.\n */\n function getCampaignMultiplier(uint256 _to)\n internal\n view\n returns (uint256)\n {\n uint256 from = pool.lastRewardBlock;\n if (from > endBlock) {\n return 0;\n } else {\n return (_to < endBlock ? _to : endBlock).sub(from);\n }\n }\n\n /**\n * @dev View function to see pending rewards for each account on frontend.\n * @param _user Address of the account we're looking up.\n * @return reward Total rewards owed to this account.\n */\n function pendingRewards(address _user) external view returns (uint256) {\n UserInfo storage user = userInfo[_user];\n return _pendingRewards(user);\n }\n\n function _pendingRewards(UserInfo storage user)\n internal\n view\n returns (uint256)\n {\n uint256 accRewardPerShare = pool.accRewardPerShare;\n if (block.number > pool.lastRewardBlock) {\n if (totalSupply != 0) {\n uint256 multiplier = getCampaignMultiplier(block.number);\n uint256 incReward = multiplier.mul(rewardPerBlock);\n accRewardPerShare = accRewardPerShare.add(\n incReward.divPrecisely(totalSupply)\n );\n }\n }\n return\n subDebt(\n user.amount.mulTruncate(accRewardPerShare),\n user.rewardDebt\n );\n }\n\n /**\n * @dev View function to see total outstanding rewards for the entire contract.\n * This is how much is owed when everyone pulls out.\n * @return reward Total rewards owed to everyone.\n */\n function totalOutstandingRewards() external view returns (uint256) {\n if (block.number > pool.lastRewardBlock && totalSupply != 0) {\n uint256 multiplier = getCampaignMultiplier(block.number);\n uint256 incReward = multiplier.mul(rewardPerBlock);\n uint256 accRewardPerShare = pool.accRewardPerShare;\n accRewardPerShare = accRewardPerShare.add(\n incReward.divPrecisely(totalSupply)\n );\n return\n subDebt(\n accRewardPerShare.mulTruncate(totalSupply),\n totalRewardDebt\n );\n }\n // no supply or not even started\n return 0;\n }\n\n /**\n * @dev External call for updating the pool.\n */\n function doUpdatePool() external {\n // There should be no harm allowing anyone to call this function.\n // It just updates the latest accRewardPerShare for the pool.\n updatePool();\n }\n\n /**\n * @dev Update the Liquidity Pool reward multiplier.\n * This locks in the accRewardPerShare from the last update block number to now.\n * Will fail if we do not have enough to pay everyone.\n * Always call updatePool whenever the balance changes!\n */\n function updatePool() internal {\n if (\n block.number <= pool.lastRewardBlock ||\n endBlock <= pool.lastRewardBlock\n ) {\n return;\n }\n\n if (totalSupply == 0) {\n pool.lastRewardBlock = block.number;\n return;\n }\n\n uint256 incReward = getCampaignMultiplier(block.number).mul(\n rewardPerBlock\n );\n // we are of course assuming lpTokens are in 1e18 precision\n uint256 accRewardPerShare = pool.accRewardPerShare.add(\n incReward.divPrecisely(totalSupply)\n );\n\n pool.accRewardPerShare = accRewardPerShare;\n pool.lastRewardBlock = block.number;\n }\n\n /**\n * @dev Deposit LP tokens into contract, must be preapproved.\n * @param _amount Amount of LPToken to deposit.\n */\n function deposit(uint256 _amount) external {\n UserInfo storage user = userInfo[msg.sender];\n updatePool();\n if (_amount > 0) {\n user.amount = user.amount.add(_amount);\n // newDebt is equal to the change in amount * accRewardPerShare (note accRewardPerShare is historic)\n int256 newDebt = int256(\n _amount.mulTruncate(pool.accRewardPerShare)\n );\n user.rewardDebt += newDebt;\n totalRewardDebt += newDebt;\n totalSupply = totalSupply.add(_amount);\n emit Deposit(msg.sender, _amount);\n pool.lpToken.safeTransferFrom(\n address(msg.sender),\n address(this),\n _amount\n );\n }\n }\n\n /**\n * @dev Exit out of the contract completely, withdraw LP tokens and claim rewards\n */\n function exit() external {\n UserInfo storage user = userInfo[msg.sender];\n // withdraw everything\n _withdraw(user, user.amount, true);\n }\n\n /**\n * @dev Withdraw LP tokens from contract.\n * @param _amount Amount of LPToken to withdraw.\n * @param _claim Boolean do we want to claim our rewards or not\n */\n function withdraw(uint256 _amount, bool _claim) external {\n UserInfo storage user = userInfo[msg.sender];\n _withdraw(user, _amount, _claim);\n }\n\n function _withdraw(\n UserInfo storage user,\n uint256 _amount,\n bool _claim\n ) internal {\n require(user.amount >= _amount, \"withdraw: overflow\");\n updatePool();\n\n // newDebt is equal to the change in amount * accRewardPerShare (note accRewardPerShare is historic)\n int256 newDebt = -int256(_amount.mulTruncate(pool.accRewardPerShare));\n uint256 pending = 0;\n if (_claim) {\n //This is an optimization so we don't modify the storage variable twice\n pending = subDebt(\n user.amount.mulTruncate(pool.accRewardPerShare),\n user.rewardDebt\n );\n\n newDebt += int256(pending);\n }\n\n user.rewardDebt += newDebt;\n totalRewardDebt += newDebt;\n emit Withdraw(msg.sender, _amount);\n // actually make the changes to the amount and debt\n if (_amount > 0) {\n user.amount = user.amount.sub(_amount);\n totalSupply = totalSupply.sub(_amount, \"withdraw: total overflow\");\n }\n //putting this all at the end to avoid reentrancy error\n if (pending > 0) {\n emit Claim(msg.sender, pending);\n reward.safeTransfer(msg.sender, pending);\n }\n if (_amount > 0) {\n pool.lpToken.safeTransfer(address(msg.sender), _amount);\n }\n }\n\n /**\n * @dev Claim all pending rewards up to current block\n */\n function claim() external {\n UserInfo storage user = userInfo[msg.sender];\n uint256 pending = _pendingRewards(user);\n if (pending > 0) {\n emit Claim(msg.sender, pending);\n int256 debtDelta = int256(pending);\n user.rewardDebt += debtDelta;\n totalRewardDebt += debtDelta;\n reward.safeTransfer(msg.sender, pending);\n }\n }\n\n function subDebt(uint256 amount, int256 debt)\n internal\n pure\n returns (uint256 result)\n {\n if (debt < 0) {\n result = amount.add(uint256(-debt));\n } else {\n result = amount.sub(uint256(debt));\n }\n }\n}\n" + }, + "contracts/mocks/BurnableERC20.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { ERC20 } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ninterface IBurnableERC20 {\n function burn(uint256 value) external returns (bool);\n\n function burnFrom(address account, uint256 value) external returns (bool);\n}\n\n/**\n * @title BurnableERC20\n * @dev Exposes the burn function of ERC20 for tests\n */\nabstract contract BurnableERC20 is IBurnableERC20, ERC20 {\n /**\n * @dev Function to burn tokens\n * @param value The amount of tokens to burn.\n * @return A boolean that indicates if the operation was successful.\n */\n function burn(uint256 value) public virtual override returns (bool) {\n _burn(msg.sender, value);\n return true;\n }\n\n /**\n * @dev Function to burn tokens from a specific account\n * @param account The address with the tokens to burn.\n * @param value The amount of tokens to burn.\n * @return A boolean that indicates if the operation was successful.\n */\n function burnFrom(address account, uint256 value)\n public\n override\n returns (bool)\n {\n _burn(account, value);\n return true;\n }\n}\n" + }, + "contracts/mocks/curve/Mock3CRV.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { ERC20, MintableERC20 } from \"../MintableERC20.sol\";\nimport { BurnableERC20 } from \"../BurnableERC20.sol\";\n\ncontract Mock3CRV is MintableERC20, BurnableERC20 {\n constructor() ERC20(\"Curve.fi DAI/USDC/USDT\", \"3Crv\") {}\n\n function decimals() public pure override returns (uint8) {\n return 18;\n }\n}\n" + }, + "contracts/mocks/curve/MockBooster.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 { MockRewardPool } from \"./MockRewardPool.sol\";\n\nimport { IRewardStaking } from \"../../strategies/IRewardStaking.sol\";\nimport { IMintableERC20, MintableERC20, ERC20 } from \"../MintableERC20.sol\";\nimport { IBurnableERC20, BurnableERC20 } from \"../BurnableERC20.sol\";\n\ncontract MockDepositToken is MintableERC20, BurnableERC20 {\n constructor() ERC20(\"DCVX\", \"CVX Deposit Token\") {}\n}\n\ncontract MockBooster {\n using SafeERC20 for IERC20;\n\n struct PoolInfo {\n address lptoken;\n address token;\n address crvRewards;\n }\n\n address public minter; // this is CVx for the booster on live\n address public crv; // Curve rewards token\n address public cvx; // Convex rewards token\n mapping(uint256 => PoolInfo) public poolInfo;\n\n constructor(\n address _rewardsMinter,\n address _crv,\n address _cvx\n ) public {\n minter = _rewardsMinter;\n crv = _crv;\n cvx = _cvx;\n }\n\n function setPool(uint256 pid, address _lpToken)\n external\n returns (address rewards)\n {\n address token = address(new MockDepositToken());\n // Deploy a new Convex Rewards Pool\n rewards = address(\n new MockRewardPool(pid, token, crv, cvx, address(this))\n );\n\n poolInfo[pid] = PoolInfo({\n lptoken: _lpToken,\n token: token,\n crvRewards: rewards\n });\n }\n\n function deposit(\n uint256 _pid,\n uint256 _amount,\n bool _stake\n ) public returns (bool) {\n PoolInfo storage pool = poolInfo[_pid];\n\n address lptoken = pool.lptoken;\n\n // hold on to the Curve LP tokens\n IERC20(lptoken).safeTransferFrom(msg.sender, address(this), _amount);\n\n address token = pool.token;\n if (_stake) {\n // mint Convex pool LP tokens and stake in rewards contract on user behalf\n IMintableERC20(token).mint(_amount);\n address rewardContract = pool.crvRewards;\n IERC20(token).safeApprove(rewardContract, 0);\n IERC20(token).safeApprove(rewardContract, _amount);\n IRewardStaking(rewardContract).stakeFor(msg.sender, _amount);\n } else {\n // mint Convex pool LP tokens and send to user\n IMintableERC20(token).mint(_amount);\n IERC20(token).transfer(msg.sender, _amount);\n }\n return true;\n }\n\n // Deposit all Curve LP tokens and stake\n function depositAll(uint256 _pid, bool _stake) external returns (bool) {\n address lptoken = poolInfo[_pid].lptoken;\n uint256 balance = IERC20(lptoken).balanceOf(msg.sender);\n deposit(_pid, balance, _stake);\n return true;\n }\n\n // withdraw Curve LP tokens\n function _withdraw(\n uint256 _pid,\n uint256 _amount,\n address _from,\n address _to\n ) internal {\n PoolInfo storage pool = poolInfo[_pid];\n\n // burn the Convex pool LP tokens\n IBurnableERC20(pool.token).burnFrom(_from, _amount);\n\n // return the Curve LP tokens\n IERC20(pool.lptoken).safeTransfer(_to, _amount);\n }\n\n // withdraw Curve LP tokens\n function withdraw(uint256 _pid, uint256 _amount) public returns (bool) {\n _withdraw(_pid, _amount, msg.sender, msg.sender);\n return true;\n }\n\n // withdraw all Curve LP tokens\n function withdrawAll(uint256 _pid) public returns (bool) {\n address token = poolInfo[_pid].token;\n uint256 userBal = IERC20(token).balanceOf(msg.sender);\n withdraw(_pid, userBal);\n return true;\n }\n\n // allow reward contracts to send here and withdraw to user\n function withdrawTo(\n uint256 _pid,\n uint256 _amount,\n address _to\n ) external returns (bool) {\n address rewardContract = poolInfo[_pid].crvRewards;\n require(msg.sender == rewardContract, \"!auth\");\n\n _withdraw(_pid, _amount, msg.sender, _to);\n return true;\n }\n\n // callback from reward contract when crv is received.\n function rewardClaimed(\n uint256 _pid,\n // solhint-disable-next-line no-unused-vars\n address _address,\n uint256 _amount\n ) external returns (bool) {\n address rewardContract = poolInfo[_pid].crvRewards;\n require(msg.sender == rewardContract, \"!auth\");\n\n //mint reward tokens\n // and transfer it\n IMintableERC20(minter).mint(_amount);\n IERC20(minter).transfer(msg.sender, _amount);\n return true;\n }\n}\n" + }, + "contracts/mocks/curve/MockCRV.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../MintableERC20.sol\";\n\ncontract MockCRV is MintableERC20 {\n constructor() ERC20(\"Curve DAO Token\", \"CRV\") {}\n\n function decimals() public pure override returns (uint8) {\n return 18;\n }\n}\n" + }, + "contracts/mocks/curve/MockCRVMinter.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\nimport { IMintableERC20 } from \"../MintableERC20.sol\";\n\ncontract MockCRVMinter {\n address crv;\n\n constructor(address _crv) {\n crv = _crv;\n }\n\n function mint(address _address) external {\n uint256 amount = 2e18;\n IMintableERC20(crv).mint(amount);\n IERC20(crv).transfer(_address, amount);\n }\n}\n" + }, + "contracts/mocks/curve/MockCurveAbstractMetapool.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\nimport { MintableERC20, IMintableERC20 } from \"../MintableERC20.sol\";\nimport { StableMath } from \"../../utils/StableMath.sol\";\nimport \"../../utils/Helpers.sol\";\n\nabstract contract MockCurveAbstractMetapool is MintableERC20 {\n using StableMath for uint256;\n\n address[] public coins;\n uint256[2] public balances;\n\n // Returns the same amount of LP tokens in 1e18 decimals\n function add_liquidity(uint256[2] calldata _amounts, uint256 _minAmount)\n external\n returns (uint256 lpAmount)\n {\n for (uint256 i = 0; i < _amounts.length; i++) {\n if (_amounts[i] > 0) {\n IERC20(coins[i]).transferFrom(\n msg.sender,\n address(this),\n _amounts[i]\n );\n uint256 assetDecimals = Helpers.getDecimals(coins[i]);\n // Convert to 1e18 and add to sum\n lpAmount += _amounts[i].scaleBy(18, assetDecimals);\n balances[i] = balances[i] + _amounts[i];\n }\n }\n // Hacky way of simulating slippage to check _minAmount\n if (lpAmount == 29000e18) lpAmount = 14500e18;\n require(lpAmount >= _minAmount, \"Slippage ruined your day\");\n // Send LP token to sender, e.g. 3CRV\n _mint(msg.sender, lpAmount);\n }\n\n // Dumb implementation that returns the same amount\n function calc_withdraw_one_coin(uint256 _amount, int128 _index)\n public\n view\n returns (uint256 lpAmount)\n {\n uint256 assetDecimals = Helpers.getDecimals(coins[uint128(_index)]);\n lpAmount = _amount.scaleBy(assetDecimals, 18);\n }\n\n function remove_liquidity_one_coin(\n uint256 _lpAmount,\n int128 _index,\n // solhint-disable-next-line no-unused-vars\n uint256 _minAmount\n ) external returns (uint256 amount) {\n _burn(msg.sender, _lpAmount);\n uint256[] memory amounts = new uint256[](coins.length);\n amounts[uint128(_index)] = _lpAmount;\n amount = calc_withdraw_one_coin(_lpAmount, _index);\n balances[uint128(_index)] -= amount;\n IERC20(coins[uint128(_index)]).transfer(msg.sender, amount);\n }\n\n function get_virtual_price() external pure returns (uint256) {\n return 1e18;\n }\n\n // solhint-disable-next-line no-unused-vars\n function remove_liquidity(uint256 _amount, uint256[2] memory _min_amounts)\n public\n returns (uint256[2] memory amounts)\n {\n _burn(msg.sender, _amount);\n uint256 totalSupply = totalSupply();\n for (uint256 i = 0; i < 2; i++) {\n amounts[i] = totalSupply > 0\n ? (_amount * IERC20(coins[i]).balanceOf(address(this))) /\n totalSupply\n : IERC20(coins[i]).balanceOf(address(this));\n balances[i] -= amounts[i];\n IERC20(coins[i]).transfer(msg.sender, amounts[i]);\n }\n }\n\n function remove_liquidity_imbalance(\n uint256[2] memory _amounts,\n uint256 _max_burned_tokens\n ) public returns (uint256) {\n return\n _remove_liquidity_imbalance(\n _amounts,\n _max_burned_tokens,\n msg.sender\n );\n }\n\n function remove_liquidity_imbalance(\n uint256[2] memory _amounts,\n uint256 _max_burned_tokens,\n address _reveiver\n ) public returns (uint256) {\n return\n _remove_liquidity_imbalance(\n _amounts,\n _max_burned_tokens,\n _reveiver\n );\n }\n\n function _remove_liquidity_imbalance(\n uint256[2] memory _amounts,\n uint256 _max_burned_tokens,\n address _reveiver\n ) internal returns (uint256 lpTokens) {\n lpTokens = _max_burned_tokens;\n _burn(msg.sender, lpTokens);\n for (uint256 i = 0; i < _amounts.length; i++) {\n balances[i] -= _amounts[i];\n if (_amounts[i] > 0) {\n IERC20(coins[i]).transfer(_reveiver, _amounts[i]);\n }\n }\n }\n\n // Dumb implementation that sums the scaled amounts\n function calc_token_amount(uint256[2] memory _amounts, bool)\n public\n view\n returns (uint256 lpTokens)\n {\n for (uint256 i = 0; i < _amounts.length; i++) {\n uint256 assetDecimals = Helpers.getDecimals(coins[i]);\n // Convert to 1e18 and add to lpTokens\n lpTokens += _amounts[i].scaleBy(18, assetDecimals);\n }\n }\n\n /// @notice 0.02% fee\n function fee() external pure returns (uint256) {\n return 2000000;\n }\n\n function decimals() public pure override returns (uint8) {\n return 18;\n }\n\n function burnFrom(address from, uint256 value) public {\n _burn(from, value);\n }\n}\n" + }, + "contracts/mocks/curve/MockCurveGauge.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\nimport { ICurveGauge } from \"../../strategies/ICurveGauge.sol\";\n\ncontract MockCurveGauge is ICurveGauge {\n mapping(address => uint256) private _balances;\n address lpToken;\n\n constructor(address _lpToken) {\n lpToken = _lpToken;\n }\n\n function balanceOf(address account) public view override returns (uint256) {\n return _balances[account];\n }\n\n function deposit(uint256 _value, address _account) external override {\n IERC20(lpToken).transferFrom(msg.sender, address(this), _value);\n _balances[_account] += _value;\n }\n\n function withdraw(uint256 _value) external override {\n IERC20(lpToken).transfer(msg.sender, _value);\n // solhint-disable-next-line reentrancy\n _balances[msg.sender] -= _value;\n }\n}\n" + }, + "contracts/mocks/curve/MockCurveLUSDMetapool.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { MockCurveAbstractMetapool } from \"./MockCurveAbstractMetapool.sol\";\nimport \"../MintableERC20.sol\";\n\ncontract MockCurveLUSDMetapool is MockCurveAbstractMetapool {\n constructor(address[2] memory _coins)\n ERC20(\"Curve.fi Factory USD Metapool: LUSD\", \"LUSD3CRV-f\")\n {\n coins = _coins;\n }\n}\n" + }, + "contracts/mocks/curve/MockCurveMetapool.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { MockCurveAbstractMetapool } from \"./MockCurveAbstractMetapool.sol\";\nimport \"../MintableERC20.sol\";\n\ncontract MockCurveMetapool is MockCurveAbstractMetapool {\n constructor(address[2] memory _coins)\n ERC20(\"Curve.fi 3pool/OUSD metapool\", \"3crv_OUSD\")\n {\n coins = _coins;\n }\n}\n" + }, + "contracts/mocks/curve/MockCurvePool.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { IBurnableERC20 } from \"../BurnableERC20.sol\";\n\nimport { IMintableERC20 } from \"../MintableERC20.sol\";\nimport { ICurvePool } from \"../../strategies/ICurvePool.sol\";\nimport { StableMath } from \"../../utils/StableMath.sol\";\nimport \"../../utils/Helpers.sol\";\n\ncontract MockCurvePool {\n using StableMath for uint256;\n\n address[] public coins;\n uint256[3] public balances;\n address lpToken;\n uint256 public slippage = 1 ether;\n\n constructor(address[3] memory _coins, address _lpToken) {\n coins = _coins;\n lpToken = _lpToken;\n }\n\n function setCoins(address[] memory _coins) external {\n coins = _coins;\n }\n\n // Returns the same amount of LP tokens in 1e18 decimals\n function add_liquidity(uint256[3] calldata _amounts, uint256 _minAmount)\n external\n {\n uint256 sum = 0;\n for (uint256 i = 0; i < _amounts.length; i++) {\n if (_amounts[i] > 0) {\n IERC20(coins[i]).transferFrom(\n msg.sender,\n address(this),\n _amounts[i]\n );\n uint256 assetDecimals = Helpers.getDecimals(coins[i]);\n // Convert to 1e18 and add to sum\n sum += _amounts[i].scaleBy(18, assetDecimals);\n balances[i] = balances[i] + _amounts[i];\n }\n }\n // Hacky way of simulating slippage to check _minAmount\n if (sum == 29000e18) sum = 14500e18;\n require(sum >= _minAmount, \"Slippage ruined your day\");\n // Send LP token to sender, e.g. 3CRV\n IMintableERC20(lpToken).mint(sum);\n IERC20(lpToken).transfer(msg.sender, sum);\n }\n\n // Dumb implementation that returns the same amount\n function calc_withdraw_one_coin(uint256 _amount, int128 _index)\n public\n view\n returns (uint256)\n {\n uint256 assetDecimals = Helpers.getDecimals(coins[uint128(_index)]);\n return _amount.scaleBy(assetDecimals, 18);\n }\n\n function remove_liquidity_one_coin(\n uint256 _amount,\n int128 _index,\n // solhint-disable-next-line no-unused-vars\n uint256 _minAmount\n ) external {\n // Burn the Curve LP tokens\n IBurnableERC20(lpToken).burnFrom(msg.sender, _amount);\n uint256[] memory amounts = new uint256[](coins.length);\n amounts[uint128(_index)] = _amount;\n uint256 coinAmount = calc_withdraw_one_coin(_amount, _index);\n balances[uint128(_index)] -= coinAmount;\n IERC20(coins[uint128(_index)]).transfer(msg.sender, coinAmount);\n }\n\n function get_virtual_price() external pure returns (uint256) {\n return 1e18;\n }\n\n // solhint-disable-next-line no-unused-vars\n function remove_liquidity(uint256 _lpAmount, uint256[3] memory _min_amounts)\n public\n {\n // Burn the Curve LP tokens\n IBurnableERC20(lpToken).burnFrom(msg.sender, _lpAmount);\n uint256 totalSupply = IERC20(lpToken).totalSupply();\n for (uint256 i = 0; i < 3; i++) {\n uint256 coinAmount = totalSupply > 0\n ? (_lpAmount * IERC20(coins[i]).balanceOf(address(this))) /\n totalSupply\n : IERC20(coins[i]).balanceOf(address(this));\n balances[i] -= coinAmount;\n IERC20(coins[i]).transfer(msg.sender, coinAmount);\n }\n }\n\n function remove_liquidity_imbalance(\n uint256[3] memory _amounts,\n uint256 _max_burned_tokens\n ) public {\n // Burn the Curve LP tokens\n IBurnableERC20(lpToken).burnFrom(msg.sender, _max_burned_tokens);\n // For each coin, transfer to the caller\n for (uint256 i = 0; i < _amounts.length; i++) {\n balances[i] -= _amounts[i];\n if (_amounts[i] > 0) {\n IERC20(coins[i]).transfer(msg.sender, _amounts[i]);\n }\n }\n }\n\n // Dumb implementation that sums the scaled amounts\n function calc_token_amount(uint256[3] memory _amounts, bool)\n public\n view\n returns (uint256 lpTokens)\n {\n for (uint256 i = 0; i < _amounts.length; i++) {\n uint256 assetDecimals = Helpers.getDecimals(coins[i]);\n // Convert to 1e18 and add to lpTokens\n lpTokens += _amounts[i].scaleBy(18, assetDecimals);\n }\n }\n\n function fee() external pure returns (uint256) {\n return 1000000;\n }\n\n function exchange(\n uint256 coin0,\n uint256 coin1,\n uint256 amountIn,\n uint256 minAmountOut\n ) external returns (uint256 amountOut) {\n IERC20(coins[coin0]).transferFrom(msg.sender, address(this), amountIn);\n amountOut = (minAmountOut * slippage) / 1 ether;\n require(amountOut >= minAmountOut, \"Slippage error\");\n IMintableERC20(coins[coin1]).mintTo(msg.sender, amountOut);\n }\n\n function setSlippage(uint256 _slippage) external {\n slippage = _slippage;\n }\n}\n" + }, + "contracts/mocks/curve/MockCVX.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../MintableERC20.sol\";\n\ncontract MockCVX is MintableERC20 {\n constructor() ERC20(\"CVX\", \"CVX DAO Token\") {}\n}\n" + }, + "contracts/mocks/curve/MockLUSD.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../MintableERC20.sol\";\n\ncontract MockLUSD is MintableERC20 {\n constructor() ERC20(\"LUSD\", \"Liquity Token\") {}\n}\n" + }, + "contracts/mocks/curve/MockRewardPool.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 { IMintableERC20 } from \"../MintableERC20.sol\";\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\n\ninterface IDeposit {\n function poolInfo(uint256)\n external\n view\n returns (\n address,\n address,\n address,\n address,\n address,\n bool\n );\n\n function rewardClaimed(\n uint256,\n address,\n uint256\n ) external;\n\n function withdrawTo(\n uint256,\n uint256,\n address\n ) external;\n}\n\ncontract MockRewardPool {\n using SafeMath for uint256;\n using SafeERC20 for IERC20;\n\n uint256 public pid;\n address public stakingToken;\n address public rewardTokenA;\n address public rewardTokenB;\n address public operator;\n\n uint256 private _totalSupply;\n\n mapping(address => uint256) private _balances;\n mapping(address => uint256) public rewards;\n\n constructor(\n uint256 _pid,\n address _stakingToken,\n address _rewardTokenA,\n address _rewardTokenB,\n address _operator\n ) public {\n pid = _pid;\n stakingToken = _stakingToken;\n rewardTokenA = _rewardTokenA;\n rewardTokenB = _rewardTokenB;\n operator = _operator;\n }\n\n function totalSupply() public view returns (uint256) {\n return _totalSupply;\n }\n\n function balanceOf(address account) public view returns (uint256) {\n return _balances[account];\n }\n\n function stakeFor(address _for, uint256 _amount) public returns (bool) {\n require(_amount > 0, \"RewardPool : Cannot stake 0\");\n\n //give to _for\n _totalSupply = _totalSupply.add(_amount);\n _balances[_for] = _balances[_for].add(_amount);\n\n //take away from sender\n IERC20(stakingToken).safeTransferFrom(\n msg.sender,\n address(this),\n _amount\n );\n\n return true;\n }\n\n function withdrawAndUnwrap(uint256 amount, bool claim)\n public\n returns (bool)\n {\n _totalSupply = _totalSupply.sub(amount);\n _balances[msg.sender] = _balances[msg.sender].sub(amount);\n\n //tell operator to withdraw from here directly to user\n IDeposit(operator).withdrawTo(pid, amount, msg.sender);\n\n //get rewards too\n if (claim) {\n getReward(msg.sender, true);\n }\n return true;\n }\n\n function withdrawAllAndUnwrap(bool claim) external {\n withdrawAndUnwrap(_balances[msg.sender], claim);\n }\n\n // solhint-disable-next-line no-unused-vars\n function getReward(address _account, bool _claimExtras)\n public\n returns (bool)\n {\n IMintableERC20(rewardTokenA).mint(2 * 1e18);\n IERC20(rewardTokenA).transfer(_account, 2 * 1e18);\n\n IMintableERC20(rewardTokenB).mint(3 * 1e18);\n IERC20(rewardTokenB).transfer(_account, 3 * 1e18);\n\n return true;\n }\n\n function getReward() public returns (bool) {\n getReward(msg.sender, true);\n }\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/Mock1InchSwapRouter.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\";\n\nimport { SwapDescription } from \"../interfaces/IOneInch.sol\";\n\ncontract Mock1InchSwapRouter {\n using SafeERC20 for IERC20;\n\n event MockSwap(address executor, bytes permitData, bytes executorData);\n\n event MockSwapDesc(\n address srcToken,\n address dstToken,\n address srcReceiver,\n address dstReceiver,\n uint256 amount,\n uint256 minReturnAmount,\n uint256 flags\n );\n\n event MockUnoswapTo(\n address recipient,\n address srcToken,\n uint256 amount,\n uint256 minReturn,\n uint256[] pools\n );\n\n event MockUniswapV3SwapTo(\n address recipient,\n uint256 amount,\n uint256 minReturn,\n uint256[] pools\n );\n\n /**\n * @dev transfers the shource asset and returns the minReturnAmount of the destination asset.\n */\n function swap(\n address executor,\n SwapDescription calldata desc,\n bytes calldata permitData,\n bytes calldata executorData\n ) public returns (uint256 returnAmount, uint256 spentAmount) {\n // Transfer the source tokens to the receiver contract\n IERC20(desc.srcToken).safeTransferFrom(\n msg.sender,\n desc.srcReceiver,\n desc.amount\n );\n\n // Transfer the destination tokens to the recipient\n IERC20(desc.dstToken).safeTransfer(\n desc.dstReceiver,\n desc.minReturnAmount\n );\n\n emit MockSwap(executor, permitData, executorData);\n _swapDesc(desc);\n returnAmount = 0;\n spentAmount = 0;\n }\n\n function _swapDesc(SwapDescription calldata desc) public {\n emit MockSwapDesc(\n address(desc.srcToken),\n address(desc.dstToken),\n desc.srcReceiver,\n desc.dstReceiver,\n desc.amount,\n desc.minReturnAmount,\n desc.flags\n );\n }\n\n /**\n * @dev only transfers the source asset to this contract.\n * Ideally it would return the destination asset but that's encoded in the pools array.\n */\n function unoswapTo(\n address payable recipient,\n address srcToken,\n uint256 amount,\n uint256 minReturn,\n uint256[] calldata pools\n ) public returns (uint256 returnAmount) {\n // transfer the from asset from the caller\n IERC20(srcToken).safeTransferFrom(msg.sender, address(this), amount);\n\n emit MockUnoswapTo(recipient, srcToken, amount, minReturn, pools);\n returnAmount = 0;\n }\n\n /**\n * @dev does not do any transfers. Just emits MockUniswapV3SwapTo.\n */\n function uniswapV3SwapTo(\n address payable recipient,\n uint256 amount,\n uint256 minReturn,\n uint256[] calldata pools\n ) public returns (uint256 returnAmount) {\n emit MockUniswapV3SwapTo(recipient, amount, minReturn, pools);\n returnAmount = 0;\n }\n}\n" + }, + "contracts/mocks/MockAave.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { IERC20, ERC20 } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\nimport { MintableERC20 } from \"./MintableERC20.sol\";\nimport { IAaveLendingPool, ILendingPoolAddressesProvider } from \"../strategies/IAave.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\n\n// 1. User calls 'getLendingPool'\n// 2. User calls 'deposit' (Aave)\n// - Deposit their underlying\n// - Mint aToken to them\n// 3. User calls redeem (aToken)\n// - Retrieve their aToken\n// - Return equal amount of underlying\n\ncontract MockAToken is MintableERC20 {\n address public lendingPool;\n IERC20 public underlyingToken;\n using SafeERC20 for IERC20;\n\n constructor(\n address _lendingPool,\n string memory _name,\n string memory _symbol,\n IERC20 _underlyingToken\n ) ERC20(_name, _symbol) {\n lendingPool = _lendingPool;\n underlyingToken = _underlyingToken;\n // addMinter(_lendingPool);\n }\n\n function decimals() public view override returns (uint8) {\n return ERC20(address(underlyingToken)).decimals();\n }\n\n function poolRedeem(uint256 _amount, address _to) external {\n require(msg.sender == lendingPool, \"pool only\");\n // Redeem these a Tokens\n _burn(_to, _amount);\n // For the underlying\n underlyingToken.safeTransferFrom(lendingPool, _to, _amount);\n }\n}\n\ncontract MockAave is IAaveLendingPool, ILendingPoolAddressesProvider {\n using SafeERC20 for IERC20;\n using StableMath for uint256;\n\n mapping(address => address) reserveToAToken;\n address pool = address(this);\n address payable core = payable(address(this));\n uint256 factor;\n\n function addAToken(address _aToken, address _underlying) public {\n IERC20(_underlying).safeApprove(_aToken, 0);\n IERC20(_underlying).safeApprove(_aToken, type(uint256).max);\n reserveToAToken[_underlying] = _aToken;\n }\n\n // set the reserve factor / basically the interest on deposit\n // in 18 precision\n // so 0.5% would be 5 * 10 ^ 15\n function setFactor(uint256 factor_) public {\n factor = factor_;\n }\n\n function deposit(\n address _reserve,\n uint256 _amount,\n address _to,\n uint16 /*_referralCode*/\n ) external override {\n uint256 previousBal = IERC20(reserveToAToken[_reserve]).balanceOf(\n msg.sender\n );\n uint256 interest = previousBal.mulTruncate(factor);\n MintableERC20(reserveToAToken[_reserve]).mintTo(msg.sender, interest);\n // Take their reserve\n IERC20(_reserve).safeTransferFrom(msg.sender, address(this), _amount);\n // Credit them with aToken\n MintableERC20(reserveToAToken[_reserve]).mintTo(_to, _amount);\n }\n\n function withdraw(\n address asset,\n uint256 amount,\n address to\n ) external override returns (uint256) {\n MockAToken atoken = MockAToken(reserveToAToken[asset]);\n atoken.poolRedeem(amount, to);\n return amount;\n }\n\n function getLendingPool() external view override returns (address) {\n return pool;\n }\n}\n" + }, + "contracts/mocks/MockAaveIncentivesController.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { MockStkAave } from \"./MockStkAave.sol\";\n\ncontract MockAaveIncentivesController {\n mapping(address => uint256) private rewards;\n MockStkAave public REWARD_TOKEN;\n\n constructor(address _reward_token) {\n REWARD_TOKEN = MockStkAave(_reward_token);\n }\n\n function setRewardsBalance(address user, uint256 amount) external {\n rewards[user] = amount;\n }\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 // solhint-disable-next-line no-unused-vars\n function getRewardsBalance(address[] calldata assets, address user)\n external\n view\n returns (uint256)\n {\n return rewards[user];\n }\n\n /**\n * @dev Claims reward for an user, on all the assets of the lending pool, 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 // solhint-disable-next-line no-unused-vars\n address[] calldata assets,\n uint256 amount,\n address to\n ) external returns (uint256) {\n require(amount > 0);\n require(rewards[to] == amount);\n REWARD_TOKEN.mint(amount);\n require(REWARD_TOKEN.transfer(to, amount));\n // solhint-disable-next-line reentrancy\n rewards[to] = 0;\n return amount;\n }\n}\n" + }, + "contracts/mocks/MockAAVEToken.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./MintableERC20.sol\";\n\ncontract MockAAVEToken is MintableERC20 {\n constructor() ERC20(\"AAVE\", \"AAVE\") {}\n}\n" + }, + "contracts/mocks/MockAura.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./MintableERC20.sol\";\n\ncontract MockAura is MintableERC20 {\n constructor() ERC20(\"Aura\", \"AURA\") {}\n}\n" + }, + "contracts/mocks/MockBAL.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./MintableERC20.sol\";\n\ncontract MockBAL is MintableERC20 {\n constructor() ERC20(\"Balancer\", \"BAL\") {}\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/MockChainlinkOracleFeed.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../interfaces/chainlink/AggregatorV3Interface.sol\";\n\ncontract MockChainlinkOracleFeed is AggregatorV3Interface {\n int256 price;\n uint8 numDecimals;\n\n constructor(int256 _price, uint8 _decimals) {\n price = _price;\n numDecimals = _decimals;\n }\n\n function decimals() external view override returns (uint8) {\n return numDecimals;\n }\n\n function description() external pure override returns (string memory) {\n return \"MockOracleEthFeed\";\n }\n\n function version() external pure override returns (uint256) {\n return 1;\n }\n\n function setPrice(int256 _price) public {\n price = _price;\n }\n\n function setDecimals(uint8 _decimals) public {\n numDecimals = _decimals;\n }\n\n // getRoundData and latestRoundData should both raise \"No data present\"\n // if they do not have data to report, instead of returning unset values\n // which could be misinterpreted as actual reported values.\n function getRoundData(uint80 _roundId)\n external\n view\n override\n returns (\n uint80 roundId,\n int256 answer,\n uint256 startedAt,\n uint256 updatedAt,\n uint80 answeredInRound\n )\n {\n roundId = _roundId;\n answer = price;\n startedAt = 0;\n updatedAt = 0;\n answeredInRound = 0;\n }\n\n function latestRoundData()\n external\n view\n override\n returns (\n uint80 roundId,\n int256 answer,\n uint256 startedAt,\n uint256 updatedAt,\n uint80 answeredInRound\n )\n {\n roundId = 0;\n answer = price;\n startedAt = 0;\n updatedAt = block.timestamp;\n answeredInRound = 0;\n }\n}\n" + }, + "contracts/mocks/MockCOMP.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./MintableERC20.sol\";\n\ncontract MockCOMP is MintableERC20 {\n constructor() ERC20(\"COMP\", \"COMP\") {}\n}\n" + }, + "contracts/mocks/MockComptroller.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ncontract MockComptroller {\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" + }, + "contracts/mocks/MockCToken.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { IERC20, ERC20 } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\nimport { ICERC20 } from \"../strategies/ICompound.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\n\ncontract MockCToken is ICERC20, ERC20 {\n using StableMath for uint256;\n\n IERC20 public underlyingToken;\n // underlying = cToken * exchangeRate\n // cToken = underlying / exchangeRate\n uint256 exchangeRate;\n address public override comptroller;\n\n constructor(ERC20 _underlyingToken, address _comptroller)\n ERC20(\"cMock\", \"cMK\")\n {\n uint8 underlyingDecimals = _underlyingToken.decimals();\n // if has 18 dp, exchange rate should be 1e26\n // if has 8 dp, exchange rate should be 1e18\n if (underlyingDecimals > 8) {\n exchangeRate = 10**uint256(18 + underlyingDecimals - 10);\n } else if (underlyingDecimals < 8) {\n // e.g. 18-8+6 = 16\n exchangeRate = 10**uint256(18 - 8 + underlyingDecimals);\n } else {\n exchangeRate = 1e18;\n }\n underlyingToken = _underlyingToken;\n comptroller = _comptroller;\n }\n\n function decimals() public pure override returns (uint8) {\n return 8;\n }\n\n function mint(uint256 mintAmount) public override returns (uint256) {\n // Credit them with cToken\n _mint(msg.sender, mintAmount.divPrecisely(exchangeRate));\n // Take their reserve\n underlyingToken.transferFrom(msg.sender, address(this), mintAmount);\n return 0;\n }\n\n function redeem(uint256 redeemAmount) external override returns (uint256) {\n uint256 tokenAmount = redeemAmount.mulTruncate(exchangeRate);\n // Burn the cToken\n _burn(msg.sender, redeemAmount);\n // Transfer underlying to caller\n underlyingToken.transfer(msg.sender, tokenAmount);\n return 0;\n }\n\n function redeemUnderlying(uint256 redeemAmount)\n external\n override\n returns (uint256)\n {\n uint256 cTokens = redeemAmount.divPrecisely(exchangeRate);\n // Burn the cToken\n _burn(msg.sender, cTokens);\n // Transfer underlying to caller\n underlyingToken.transfer(msg.sender, redeemAmount);\n return 0;\n }\n\n function balanceOfUnderlying(address owner)\n external\n view\n override\n returns (uint256)\n {\n uint256 cTokenBal = this.balanceOf(owner);\n return cTokenBal.mulTruncate(exchangeRate);\n }\n\n function balanceOf(address owner)\n public\n view\n override(ICERC20, ERC20)\n returns (uint256)\n {\n return ERC20.balanceOf(owner);\n }\n\n function updateExchangeRate()\n internal\n view\n returns (uint256 newExchangeRate)\n {\n uint256 factor = 100002 * (10**13); // 0.002%\n newExchangeRate = exchangeRate.mulTruncate(factor);\n }\n\n function exchangeRateStored() external view override returns (uint256) {\n return exchangeRate;\n }\n\n function supplyRatePerBlock() external pure override returns (uint256) {\n return 141 * (10**8);\n }\n}\n" + }, + "contracts/mocks/MockCVXLocker.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { ERC20 } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ncontract MockCVXLocker {\n address public immutable cvx;\n mapping(address => uint256) public lockedBalanceOf;\n\n constructor(address _cvx) {\n cvx = _cvx;\n }\n\n function lock(\n address _account,\n uint256 _amount,\n uint256\n ) external {\n lockedBalanceOf[_account] += _amount;\n ERC20(cvx).transferFrom(msg.sender, address(this), _amount);\n }\n\n function unlockAllTokens(address _account) external {\n lockedBalanceOf[_account] = 0;\n ERC20(cvx).transfer(_account, lockedBalanceOf[_account]);\n }\n}\n" + }, + "contracts/mocks/MockDAI.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./MintableERC20.sol\";\n\ncontract MockDAI is MintableERC20 {\n constructor() ERC20(\"DAI\", \"DAI\") {}\n}\n" + }, + "contracts/mocks/MockDepositContract.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { IDepositContract } from \"./../interfaces/IDepositContract.sol\";\n\ncontract MockDepositContract is IDepositContract {\n uint256 deposit_count;\n\n function deposit(\n bytes calldata pubkey,\n bytes calldata withdrawal_credentials,\n bytes calldata signature,\n bytes32 deposit_data_root\n ) external payable override {\n require(pubkey.length == 48, \"DepositContract: invalid pubkey length\");\n require(\n withdrawal_credentials.length == 32,\n \"DepositContract: invalid withdrawal_credentials length\"\n );\n require(\n signature.length == 96,\n \"DepositContract: invalid signature length\"\n );\n\n // Check deposit amount\n require(msg.value >= 1 ether, \"DepositContract: deposit value too low\");\n require(\n msg.value % 1 gwei == 0,\n \"DepositContract: deposit value not multiple of gwei\"\n );\n uint256 deposit_amount = msg.value / 1 gwei;\n require(\n deposit_amount <= type(uint64).max,\n \"DepositContract: deposit value too high\"\n );\n\n // Emit `DepositEvent` log\n bytes memory amount = to_little_endian_64(uint64(deposit_amount));\n emit DepositEvent(\n pubkey,\n withdrawal_credentials,\n amount,\n signature,\n to_little_endian_64(uint64(deposit_count))\n );\n require(\n deposit_data_root != 0,\n \"DepositContract: invalid deposit_data_root\"\n );\n }\n\n function get_deposit_root() external view override returns (bytes32) {\n // just return some bytes32\n return sha256(abi.encodePacked(deposit_count, bytes16(0)));\n }\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 override returns (bytes memory) {\n return to_little_endian_64(uint64(deposit_count));\n }\n\n function to_little_endian_64(uint64 value)\n internal\n pure\n returns (bytes memory ret)\n {\n ret = new bytes(8);\n bytes8 bytesValue = bytes8(value);\n // Byteswapping during copying to bytes.\n ret[0] = bytesValue[7];\n ret[1] = bytesValue[6];\n ret[2] = bytesValue[5];\n ret[3] = bytesValue[4];\n ret[4] = bytesValue[3];\n ret[5] = bytesValue[2];\n ret[6] = bytesValue[1];\n ret[7] = bytesValue[0];\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/MockfrxETH.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./MintableERC20.sol\";\n\ncontract MockfrxETH is MintableERC20 {\n constructor() ERC20(\"frxETH\", \"frxETH\") {}\n}\n" + }, + "contracts/mocks/MockFrxETHMinter.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./MintableERC20.sol\";\n\ncontract MockFrxETHMinter {\n address public immutable frxETH;\n address public immutable sfrxETH;\n\n constructor(address _frxETH, address _sfrxETH) {\n frxETH = _frxETH;\n sfrxETH = _sfrxETH;\n }\n\n function submitAndDeposit(address recipient)\n external\n payable\n returns (uint256 shares)\n {\n IMintableERC20(frxETH).mintTo(sfrxETH, msg.value);\n IMintableERC20(sfrxETH).mintTo(recipient, msg.value);\n shares = msg.value;\n }\n}\n" + }, + "contracts/mocks/MockLimitedWrappedOusd.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { WrappedOusd } from \"../token/WrappedOusd.sol\";\nimport { ERC20 } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ncontract MockLimitedWrappedOusd is WrappedOusd {\n constructor(\n ERC20 underlying_,\n string memory name_,\n string memory symbol_\n ) WrappedOusd(underlying_, name_, symbol_) {}\n\n function maxDeposit(address)\n public\n view\n virtual\n override\n returns (uint256)\n {\n return 1e18;\n }\n}\n" + }, + "contracts/mocks/MockMetadataToken.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n// IERC20Metadata is used in the resolveAsset function in contracts/utils/assets.js\n// We just need to import it here to make its ABI available to Hardhat\nimport { IERC20Metadata } from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\n" + }, + "contracts/mocks/MockMintableUniswapPair.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./MintableERC20.sol\";\nimport \"./MockUniswapPair.sol\";\n\ncontract MockMintableUniswapPair is MockUniswapPair, MintableERC20 {\n constructor(\n address _token0,\n address _token1,\n uint112 _reserve0,\n uint112 _reserve1\n )\n MockUniswapPair(_token0, _token1, _reserve0, _reserve1)\n ERC20(\"Uniswap V2\", \"UNI-v2\")\n {}\n\n function decimals() public pure override returns (uint8) {\n return 18;\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/MockNonStandardToken.sol": { + "content": "pragma solidity ^0.8.0;\n\nimport { SafeMath } from \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\n\nimport \"./MintableERC20.sol\";\n\n/**\n * Mock token contract to simulate tokens that don't\n * throw/revert when a transfer/transferFrom call fails\n */\ncontract MockNonStandardToken is MintableERC20 {\n using SafeMath for uint256;\n\n constructor() ERC20(\"NonStandardToken\", \"NonStandardToken\") {}\n\n function decimals() public pure override returns (uint8) {\n return 6;\n }\n\n function transfer(address recipient, uint256 amount)\n public\n override\n returns (bool)\n {\n if (balanceOf(msg.sender) < amount) {\n // Fail silently\n return false;\n }\n\n _transfer(_msgSender(), recipient, amount);\n return true;\n }\n\n function transferFrom(\n address sender,\n address recipient,\n uint256 amount\n ) public override returns (bool) {\n if (balanceOf(sender) < amount) {\n // Fail silently\n return false;\n }\n\n _transfer(sender, recipient, amount);\n _approve(\n sender,\n _msgSender(),\n allowance(sender, _msgSender()).sub(\n amount,\n \"ERC20: transfer amount exceeds allowance\"\n )\n );\n return true;\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/MockOGN.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./BurnableERC20.sol\";\nimport \"./MintableERC20.sol\";\n\n/**\n * @title Origin token (OGN).\n *\n * @dev Token that allows minting and burning.\n * @dev Important note:\n * @dev There is a known race condition in the ERC20 standard on the approve() method.\n * @dev See details: https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n * @dev The Origin token contract implements the increaseApproval() and decreaseApproval() methods.\n * @dev It is strongly recommended to use those methods rather than approve()\n * @dev when updating the token allowance.\n */\ncontract MockOGN is MintableERC20, BurnableERC20 {\n event SetWhitelistExpiration(uint256 expiration);\n event AllowedTransactorAdded(address sender);\n event AllowedTransactorRemoved(address sender);\n event AddCallSpenderWhitelist(address enabler, address spender);\n event RemoveCallSpenderWhitelist(address disabler, address spender);\n\n mapping(address => bool) public callSpenderWhitelist;\n address public owner = msg.sender;\n // UNIX timestamp (in seconds) after which this whitelist no longer applies\n uint256 public whitelistExpiration;\n // While the whitelist is active, either the sender or recipient must be\n // in allowedTransactors.\n mapping(address => bool) public allowedTransactors;\n\n // @dev Constructor that gives msg.sender all initial tokens.\n constructor(uint256 _initialSupply) ERC20(\"OriginToken\", \"OGN\") {\n owner = msg.sender;\n _mint(owner, _initialSupply);\n }\n\n //\n // approveAndCall methods\n //\n\n // @dev Add spender to whitelist of spenders for approveAndCall\n // @param _spender Address to add\n function addCallSpenderWhitelist(address _spender) public onlyOwner {\n callSpenderWhitelist[_spender] = true;\n emit AddCallSpenderWhitelist(msg.sender, _spender);\n }\n\n // @dev Remove spender from whitelist of spenders for approveAndCall\n // @param _spender Address to remove\n function removeCallSpenderWhitelist(address _spender) public onlyOwner {\n delete callSpenderWhitelist[_spender];\n emit RemoveCallSpenderWhitelist(msg.sender, _spender);\n }\n\n // @dev Approve transfer of tokens and make a contract call in a single\n // @dev transaction. This allows a DApp to avoid requiring two MetaMask\n // @dev approvals for a single logical action, such as creating a listing,\n // @dev which requires the seller to approve a token transfer and the\n // @dev marketplace contract to transfer tokens from the seller.\n //\n // @dev This is based on the ERC827 function approveAndCall and avoids\n // @dev security issues by only working with a whitelisted set of _spender\n // @dev addresses. The other difference is that the combination of this\n // @dev function ensures that the proxied function call receives the\n // @dev msg.sender for this function as its first parameter.\n //\n // @param _spender The address that will spend the funds.\n // @param _value The amount of tokens to be spent.\n // @param _selector Function selector for function to be called.\n // @param _callParams Packed, encoded parameters, omitting the first parameter which is always msg.sender\n function approveAndCallWithSender(\n address _spender,\n uint256 _value,\n bytes4 _selector,\n bytes memory _callParams\n ) public payable returns (bool) {\n require(_spender != address(this), \"token contract can't be approved\");\n require(callSpenderWhitelist[_spender], \"spender not in whitelist\");\n\n require(super.approve(_spender, _value), \"approve failed\");\n\n bytes memory callData = abi.encodePacked(\n _selector,\n uint256(uint160(msg.sender)),\n _callParams\n );\n // solium-disable-next-line security/no-call-value\n (bool success, ) = _spender.call{ value: msg.value }(callData);\n require(success, \"proxied call failed\");\n return true;\n }\n\n //\n // Functions for maintaining whitelist\n //\n\n modifier onlyOwner() {\n require(msg.sender == owner);\n _;\n }\n modifier allowedTransfer(address _from, address _to) {\n require(\n // solium-disable-next-line operator-whitespace\n !whitelistActive() ||\n allowedTransactors[_from] ||\n allowedTransactors[_to],\n \"neither sender nor recipient are allowed\"\n );\n _;\n }\n\n function whitelistActive() public view returns (bool) {\n return block.timestamp < whitelistExpiration;\n }\n\n function addAllowedTransactor(address _transactor) public onlyOwner {\n emit AllowedTransactorAdded(_transactor);\n allowedTransactors[_transactor] = true;\n }\n\n function removeAllowedTransactor(address _transactor) public onlyOwner {\n emit AllowedTransactorRemoved(_transactor);\n delete allowedTransactors[_transactor];\n }\n\n /**\n * @dev Set the whitelist expiration, after which the whitelist no longer\n * applies.\n */\n function setWhitelistExpiration(uint256 _expiration) public onlyOwner {\n // allow only if whitelist expiration hasn't yet been set, or if the\n // whitelist expiration hasn't passed yet\n require(\n whitelistExpiration == 0 || whitelistActive(),\n \"an expired whitelist cannot be extended\"\n );\n // prevent possible mistakes in calling this function\n require(\n _expiration >= block.timestamp + 1 days,\n \"whitelist expiration not far enough into the future\"\n );\n emit SetWhitelistExpiration(_expiration);\n whitelistExpiration = _expiration;\n }\n\n //\n // ERC20 transfer functions that have been overridden to enforce the\n // whitelist.\n //\n\n function transfer(address _to, uint256 _value)\n public\n override\n allowedTransfer(msg.sender, _to)\n returns (bool)\n {\n return super.transfer(_to, _value);\n }\n\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n ) public override allowedTransfer(_from, _to) returns (bool) {\n return super.transferFrom(_from, _to, _value);\n }\n}\n" + }, + "contracts/mocks/MockOGV.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./MintableERC20.sol\";\n\ncontract MockOGV is MintableERC20 {\n constructor() ERC20(\"OGV\", \"OGV\") {}\n}\n" + }, + "contracts/mocks/MockOracle.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../interfaces/IPriceOracle.sol\";\nimport \"../interfaces/IMinMaxOracle.sol\";\n\n/**\n * Mock of both price Oracle and min max oracles\n */\ncontract MockOracle is IPriceOracle, IMinMaxOracle {\n mapping(bytes32 => uint256) prices;\n mapping(bytes32 => uint256[]) pricesMinMax;\n uint256 ethMin;\n uint256 ethMax;\n\n /**\n * @dev returns the asset price in USD, 6 decimal digits.\n * Compatible with the Open Price Feed.\n */\n function price(string calldata symbol)\n external\n view\n override\n returns (uint256)\n {\n return prices[keccak256(abi.encodePacked(symbol))];\n }\n\n /**\n * @dev sets the price of the asset in USD, 6 decimal digits\n *\n */\n function setPrice(string calldata symbol, uint256 _price) external {\n prices[keccak256(abi.encodePacked(symbol))] = _price;\n }\n\n /**\n * @dev sets the min and max price of ETH in USD, 6 decimal digits\n *\n */\n function setEthPriceMinMax(uint256 _min, uint256 _max) external {\n ethMin = _min;\n ethMax = _max;\n }\n\n /**\n * @dev sets the prices Min Max for a specific symbol in ETH, 8 decimal digits\n *\n */\n function setTokPriceMinMax(\n string calldata symbol,\n uint256 _min,\n uint256 _max\n ) external {\n pricesMinMax[keccak256(abi.encodePacked(symbol))] = [_min, _max];\n }\n\n /**\n * @dev get the price of asset in ETH, 8 decimal digits.\n */\n function priceMin(string calldata symbol)\n external\n view\n override\n returns (uint256)\n {\n uint256[] storage pMinMax = pricesMinMax[\n keccak256(abi.encodePacked(symbol))\n ];\n return (pMinMax[0] * ethMin) / 1e6;\n }\n\n /**\n * @dev get the price of asset in USD, 8 decimal digits.\n * Not needed for now\n */\n function priceMax(string calldata symbol)\n external\n view\n override\n returns (uint256)\n {\n uint256[] storage pMinMax = pricesMinMax[\n keccak256(abi.encodePacked(symbol))\n ];\n return (pMinMax[1] * ethMax) / 1e6;\n }\n}\n" + }, + "contracts/mocks/MockOracleRouter.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../interfaces/chainlink/AggregatorV3Interface.sol\";\nimport { IOracle } from \"../interfaces/IOracle.sol\";\nimport { Helpers } from \"../utils/Helpers.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\nimport { SafeCast } from \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\nimport { OracleRouterBase } from \"../oracle/OracleRouterBase.sol\";\n\n// @notice Oracle Router required for testing environment\ncontract MockOracleRouter is OracleRouterBase {\n struct FeedMetadata {\n address feedAddress;\n uint256 maxStaleness;\n }\n\n mapping(address => FeedMetadata) public assetToFeedMetadata;\n\n /* @dev Override feed and maxStaleness information for a particular asset\n * @param _asset the asset to override feed for\n * @param _feed new feed\n * @param _maxStaleness new maximum time allowed for feed data to be stale\n */\n function setFeed(\n address _asset,\n address _feed,\n uint256 _maxStaleness\n ) external {\n assetToFeedMetadata[_asset] = FeedMetadata(_feed, _maxStaleness);\n }\n\n /*\n * The dev version of the Oracle doesn't need to gas optimize and cache the decimals\n */\n function getDecimals(address _feed) internal view override returns (uint8) {\n require(_feed != address(0), \"Asset not available\");\n require(_feed != FIXED_PRICE, \"Fixed price feeds not supported\");\n\n return AggregatorV3Interface(_feed).decimals();\n }\n\n /**\n * @dev The price feed contract to use for a particular asset along with\n * maximum data staleness\n * @param asset address of the asset\n * @return feedAddress address of the price feed for the asset\n * @return maxStaleness maximum acceptable data staleness duration\n */\n function feedMetadata(address asset)\n internal\n view\n override\n returns (address feedAddress, uint256 maxStaleness)\n {\n FeedMetadata storage fm = assetToFeedMetadata[asset];\n feedAddress = fm.feedAddress;\n maxStaleness = fm.maxStaleness;\n }\n}\n" + }, + "contracts/mocks/MockOracleRouterNoStale.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../interfaces/chainlink/AggregatorV3Interface.sol\";\nimport { IOracle } from \"../interfaces/IOracle.sol\";\nimport { Helpers } from \"../utils/Helpers.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\nimport { SafeCast } from \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\nimport { OracleRouter } from \"../oracle/OracleRouter.sol\";\nimport { OETHOracleRouter } from \"../oracle/OETHOracleRouter.sol\";\n\n// @notice Oracle Router used to bypass staleness\ncontract MockOracleRouterNoStale is OracleRouter {\n function feedMetadata(address asset)\n internal\n pure\n virtual\n override\n returns (address feedAddress, uint256 maxStaleness)\n {\n (feedAddress, ) = super.feedMetadata(asset);\n maxStaleness = 365 days;\n }\n}\n\n// @notice Oracle Router used to bypass staleness\ncontract MockOETHOracleRouterNoStale is OETHOracleRouter {\n constructor(address auraPriceFeed) OETHOracleRouter(auraPriceFeed) {}\n\n function feedMetadata(address asset)\n internal\n view\n virtual\n override\n returns (address feedAddress, uint256 maxStaleness)\n {\n (feedAddress, ) = super.feedMetadata(asset);\n maxStaleness = 365 days;\n }\n}\n" + }, + "contracts/mocks/MockOracleWeightedPool.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { Variable, OracleAverageQuery, IOracleWeightedPool } from \"../interfaces/balancer/IOracleWeightedPool.sol\";\n\ncontract MockOracleWeightedPool is IOracleWeightedPool {\n uint256[] public nextResults;\n\n constructor() {\n nextResults = [1 ether, 1 ether];\n }\n\n function getTimeWeightedAverage(OracleAverageQuery[] memory)\n external\n view\n override\n returns (uint256[] memory results)\n {\n return nextResults;\n }\n\n function setNextResults(uint256[] calldata results) external {\n nextResults = results;\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/MockRETH.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./MintableERC20.sol\";\nimport \"../interfaces/IGetExchangeRateToken.sol\";\n\ncontract MockRETH is MintableERC20, IGetExchangeRateToken {\n uint256 private exchangeRate = 12e17;\n\n constructor() ERC20(\"Rocket Pool ETH\", \"rETH\") {}\n\n function getExchangeRate() external view override returns (uint256) {\n return exchangeRate;\n }\n\n function setExchangeRate(uint256 _rate) external {\n exchangeRate = _rate;\n }\n}\n" + }, + "contracts/mocks/MocksfrxETH.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./MintableERC20.sol\";\n\ncontract MocksfrxETH is MintableERC20 {\n address public frxETH;\n\n constructor(address _frxETH) ERC20(\"sfrxETH\", \"sfrxETH\") {\n frxETH = _frxETH;\n }\n\n function setMockfrxETHAddress(address _frxETH) external {\n frxETH = _frxETH;\n }\n\n function deposit(uint256 assets, address receiver)\n external\n returns (uint256 shares)\n {\n ERC20(frxETH).transferFrom(msg.sender, address(this), assets);\n\n _mint(receiver, assets);\n\n return assets;\n }\n\n function maxWithdraw(address owner) external view returns (uint256) {\n return balanceOf(owner);\n }\n\n function setMaxWithdrawableBalance(address owner, uint256 balance)\n external\n {\n uint256 currentBalance = balanceOf(owner);\n if (currentBalance > balance) {\n _burn(owner, currentBalance - balance);\n } else if (balance > currentBalance) {\n _mint(owner, balance - currentBalance);\n }\n }\n\n function redeem(\n uint256 shares,\n address receiver,\n address owner\n ) external returns (uint256 assets) {\n _burn(owner, shares);\n\n ERC20(frxETH).transfer(receiver, shares);\n\n assets = shares;\n }\n\n function withdraw(\n uint256 assets,\n address receiver,\n address owner\n ) external returns (uint256 shares) {\n _burn(owner, assets);\n\n ERC20(frxETH).transfer(receiver, assets);\n\n shares = assets;\n }\n\n function submitAndDeposit(address recipient)\n external\n payable\n returns (uint256 shares)\n {\n _mint(recipient, msg.value);\n shares = msg.value;\n }\n}\n" + }, + "contracts/mocks/MockSSV.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./MintableERC20.sol\";\n\ncontract MockSSV is MintableERC20 {\n constructor() ERC20(\"SSV Token\", \"SSV\") {}\n}\n" + }, + "contracts/mocks/MockSSVNetwork.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { Cluster } from \"./../interfaces/ISSVNetwork.sol\";\n\ncontract MockSSVNetwork {\n function registerValidator(\n bytes calldata publicKey,\n uint64[] calldata operatorIds,\n bytes calldata sharesData,\n uint256 amount,\n Cluster memory cluster\n ) external {}\n\n function exitValidator(\n bytes calldata publicKey,\n uint64[] calldata operatorIds\n ) external {}\n\n function removeValidator(\n bytes calldata publicKey,\n uint64[] calldata operatorIds,\n Cluster memory cluster\n ) external {}\n\n function deposit(\n address clusterOwner,\n uint64[] calldata operatorIds,\n uint256 amount,\n Cluster memory cluster\n ) external {}\n}\n" + }, + "contracts/mocks/MockstETH.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./MintableERC20.sol\";\n\ncontract MockstETH is MintableERC20 {\n constructor() ERC20(\"stETH\", \"stETH\") {}\n}\n" + }, + "contracts/mocks/MockStkAave.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 \"./MintableERC20.sol\";\n\ncontract MockStkAave is MintableERC20 {\n uint256 public COOLDOWN_SECONDS = 864000;\n uint256 public UNSTAKE_WINDOW = 172800;\n address public STAKED_TOKEN;\n\n mapping(address => uint256) public stakerRewardsToClaim;\n mapping(address => uint256) public stakersCooldowns;\n\n using SafeERC20 for IERC20;\n\n constructor(address _stakedToken) ERC20(\"Staked Aave\", \"stkAAVE\") {\n STAKED_TOKEN = _stakedToken;\n }\n\n function decimals() public pure override returns (uint8) {\n return 18;\n }\n\n function setStakedToken(address _stakedToken) external {\n STAKED_TOKEN = _stakedToken;\n }\n\n /**\n * @dev Redeems staked tokens, and stop earning rewards\n * @param to Address to redeem to\n * @param amount Amount to redeem\n **/\n function redeem(address to, uint256 amount) external {\n uint256 cooldownStartTimestamp = stakersCooldowns[msg.sender];\n uint256 windowStart = cooldownStartTimestamp + COOLDOWN_SECONDS;\n require(amount != 0, \"INVALID_ZERO_AMOUNT\");\n require(block.timestamp > windowStart, \"INSUFFICIENT_COOLDOWN\");\n require(\n block.timestamp - windowStart <= UNSTAKE_WINDOW,\n \"UNSTAKE_WINDOW_FINISHED\"\n );\n uint256 balanceOfMessageSender = balanceOf(msg.sender);\n uint256 amountToRedeem = (amount > balanceOfMessageSender)\n ? balanceOfMessageSender\n : amount;\n\n stakersCooldowns[msg.sender] = 0;\n _burn(msg.sender, amountToRedeem);\n IERC20(STAKED_TOKEN).safeTransfer(to, amountToRedeem);\n }\n\n /**\n * @dev Activates the cooldown period to unstake\n * - It can't be called if the user is not staking\n **/\n function cooldown() external {\n require(balanceOf(msg.sender) != 0, \"INVALID_BALANCE_ON_COOLDOWN\");\n stakersCooldowns[msg.sender] = block.timestamp;\n }\n\n /**\n * @dev Test helper function to allow changing the cooldown\n **/\n function setCooldown(address account, uint256 _cooldown) external {\n stakersCooldowns[account] = _cooldown;\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 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 require(false, \"Not implemented\");\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" + }, + "contracts/mocks/MockSwapper.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { IMintableERC20 } from \"./MintableERC20.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\ncontract MockSwapper {\n uint256 public nextOutAmount;\n\n function swap(\n // solhint-disable-next-line no-unused-vars\n address _fromAsset,\n address _toAsset,\n // solhint-disable-next-line no-unused-vars\n uint256 _fromAssetAmount,\n uint256 _minToAssetAmount,\n // solhint-disable-next-line no-unused-vars\n bytes calldata _data\n ) external returns (uint256 toAssetAmount) {\n toAssetAmount = (nextOutAmount > 0) ? nextOutAmount : _minToAssetAmount;\n nextOutAmount = 0;\n IMintableERC20(_toAsset).mint(toAssetAmount);\n IERC20(_toAsset).transfer(msg.sender, toAssetAmount);\n }\n\n function setNextOutAmount(uint256 _nextOutAmount) public {\n nextOutAmount = _nextOutAmount;\n }\n}\n" + }, + "contracts/mocks/MockTUSD.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./MintableERC20.sol\";\n\ncontract MockTUSD is MintableERC20 {\n constructor() ERC20(\"TrueUSD\", \"TUSD\") {}\n\n function decimals() public pure override returns (uint8) {\n return 18;\n }\n}\n" + }, + "contracts/mocks/MockUniswapPair.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { IUniswapV2Pair } from \"../interfaces/uniswap/IUniswapV2Pair.sol\";\n\ncontract MockUniswapPair is IUniswapV2Pair {\n address tok0;\n address tok1;\n uint112 reserve0;\n uint112 reserve1;\n uint256 blockTimestampLast;\n\n bool public hasSynced = false;\n\n constructor(\n address _token0,\n address _token1,\n uint112 _reserve0,\n uint112 _reserve1\n ) {\n tok0 = _token0;\n tok1 = _token1;\n reserve0 = _reserve0;\n reserve1 = _reserve1;\n blockTimestampLast = block.timestamp;\n }\n\n function token0() external view override returns (address) {\n return tok0;\n }\n\n function token1() external view override returns (address) {\n return tok1;\n }\n\n function getReserves()\n external\n view\n override\n returns (\n uint112,\n uint112,\n uint32\n )\n {\n return (reserve0, reserve1, uint32(blockTimestampLast));\n }\n\n function setReserves(uint112 _reserve0, uint112 _reserve1) public {\n reserve0 = _reserve0;\n reserve1 = _reserve1;\n blockTimestampLast = block.timestamp;\n }\n\n // CAUTION This will not work if you setReserves multiple times over\n // multiple different blocks because then it wouldn't be a continuous\n // reserve factor over that blockTimestamp, this assumes an even reserve\n // ratio all the way through\n function price0CumulativeLast() external view override returns (uint256) {\n return\n uint256(FixedPoint.fraction(reserve1, reserve0)._x) *\n blockTimestampLast;\n }\n\n function price1CumulativeLast() external view override returns (uint256) {\n return\n uint256(FixedPoint.fraction(reserve0, reserve1)._x) *\n blockTimestampLast;\n }\n\n function sync() external override {\n hasSynced = true;\n }\n\n function checkHasSynced() external view {\n require(hasSynced, \"Not synced\");\n }\n}\n\n// a library for handling binary fixed point numbers (https://en.wikipedia.org/wiki/Q_(number_format))\nlibrary FixedPoint {\n // range: [0, 2**112 - 1]\n // resolution: 1 / 2**112\n struct uq112x112 {\n uint224 _x;\n }\n\n // returns a uq112x112 which represents the ratio of the numerator to the denominator\n // equivalent to encode(numerator).div(denominator)\n function fraction(uint112 numerator, uint112 denominator)\n internal\n pure\n returns (uq112x112 memory)\n {\n require(denominator > 0, \"FixedPoint: DIV_BY_ZERO\");\n return uq112x112((uint224(numerator) << 112) / denominator);\n }\n}\n" + }, + "contracts/mocks/MockUniswapRouter.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { MintableERC20 } from \"./MintableERC20.sol\";\nimport { IUniswapV2Router } from \"../interfaces/uniswap/IUniswapV2Router02.sol\";\nimport { Helpers } from \"../utils/Helpers.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\n\ncontract MockUniswapRouter is IUniswapV2Router {\n using StableMath for uint256;\n\n mapping(address => address) public pairMaps;\n uint256 public slippage = 1 ether;\n\n function initialize(\n address[] calldata _0tokens,\n address[] calldata _1tokens\n ) public {\n require(\n _0tokens.length == _1tokens.length,\n \"Mock token pairs should be of the same length\"\n );\n for (uint256 i = 0; i < _0tokens.length; i++) {\n pairMaps[_0tokens[i]] = _1tokens[i];\n }\n }\n\n function setSlippage(uint256 _slippage) external {\n slippage = _slippage;\n }\n\n function swapExactTokensForTokens(\n uint256 amountIn,\n uint256 amountOutMin,\n address[] calldata path,\n address to,\n // solhint-disable-next-line no-unused-vars\n uint256\n ) external override returns (uint256[] memory amountsOut) {\n address tok0 = path[0];\n address tok1 = path[path.length - 1];\n\n uint256 amountOut = (amountOutMin * slippage) / 1 ether;\n require(amountOut >= amountOutMin, \"Slippage error\");\n\n IERC20(tok0).transferFrom(msg.sender, address(this), amountIn);\n MintableERC20(tok1).mintTo(to, amountOut);\n\n amountsOut = new uint256[](path.length);\n amountsOut[path.length - 1] = amountOut;\n }\n\n struct ExactInputParams {\n bytes path;\n address recipient;\n uint256 deadline;\n uint256 amountIn;\n uint256 amountOutMinimum;\n }\n\n function exactInput(ExactInputParams calldata params)\n external\n payable\n returns (uint256 amountOut)\n {\n (address tok0, address tok1) = _getFirstAndLastToken(params.path);\n\n amountOut = (params.amountOutMinimum * slippage) / 1 ether;\n\n IERC20(tok0).transferFrom(msg.sender, address(this), params.amountIn);\n MintableERC20(tok1).mintTo(params.recipient, amountOut);\n\n require(\n amountOut >= params.amountOutMinimum,\n \"UniswapMock: amountOut less than amountOutMinimum\"\n );\n return amountOut;\n }\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 override\n returns (\n uint256 amountA,\n uint256 amountB,\n uint256 liquidity\n )\n {\n // this is needed to make this contract whole else it'd be just virtual\n }\n\n function WETH() external pure override returns (address) {\n return address(0);\n }\n\n // Universal router mock\n function execute(\n bytes calldata,\n bytes[] calldata inputs,\n uint256\n ) external payable {\n uint256 inLen = inputs.length;\n for (uint256 i = 0; i < inLen; ++i) {\n (\n address recipient,\n ,\n uint256 amountOutMinimum,\n bytes memory path,\n\n ) = abi.decode(inputs[i], (address, uint256, uint256, bytes, bool));\n\n (address token0, address token1) = _getFirstAndLastToken(path);\n\n amountOutMinimum = amountOutMinimum.scaleBy(\n Helpers.getDecimals(token0),\n Helpers.getDecimals(token1)\n );\n\n MintableERC20(token1).mintTo(recipient, amountOutMinimum);\n }\n }\n\n function _getFirstAndLastToken(bytes memory path)\n internal\n view\n returns (address token0, address token1)\n {\n bytes memory tok0Bytes = new bytes(20);\n for (uint256 j = 0; j < 20; ++j) {\n tok0Bytes[j] = path[j];\n }\n token0 = address(bytes20(tok0Bytes));\n\n if (pairMaps[token0] != address(0)) {\n token0 = pairMaps[token0];\n }\n\n bytes memory tok1Bytes = new bytes(20);\n uint256 tok1Offset = path.length - 20;\n for (uint256 j = 0; j < 20; ++j) {\n tok1Bytes[j] = path[j + tok1Offset];\n }\n token1 = address(bytes20(tok1Bytes));\n\n if (pairMaps[token1] != address(0)) {\n token1 = pairMaps[token1];\n }\n }\n}\n" + }, + "contracts/mocks/MockUSDC.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./MintableERC20.sol\";\n\ncontract MockUSDC is MintableERC20 {\n constructor() ERC20(\"USDC Coin\", \"USDC\") {}\n\n function decimals() public pure override returns (uint8) {\n return 6;\n }\n}\n" + }, + "contracts/mocks/MockUSDT.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./MintableERC20.sol\";\n\ncontract MockUSDT is MintableERC20 {\n constructor() ERC20(\"USDT Coin\", \"USDT\") {}\n\n function decimals() public pure override returns (uint8) {\n return 6;\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/mocks/MockWETH.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./MintableERC20.sol\";\n\ncontract MockWETH is MintableERC20 {\n constructor() ERC20(\"WETH\", \"WETH\") {}\n\n function deposit() external payable {\n _mint(msg.sender, msg.value);\n }\n\n function withdraw(uint256 wad) external {\n _burn(msg.sender, wad);\n payable(msg.sender).transfer(wad);\n }\n}\n" + }, + "contracts/oracle/AuraWETHPriceFeed.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { Variable, OracleAverageQuery, IOracleWeightedPool } from \"../interfaces/balancer/IOracleWeightedPool.sol\";\nimport { Strategizable } from \"../governance/Strategizable.sol\";\nimport { AggregatorV3Interface } from \"../interfaces/chainlink/AggregatorV3Interface.sol\";\nimport { SafeCast } from \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\n\ncontract AuraWETHPriceFeed is AggregatorV3Interface, Strategizable {\n using SafeCast for uint256;\n using SafeCast for int256;\n\n event PriceFeedPaused();\n event PriceFeedUnpaused();\n event ToleranceChanged(uint256 oldTolerance, uint256 newTolerance);\n\n error PriceFeedPausedError();\n error PriceFeedUnpausedError();\n error InvalidToleranceBps();\n error HighPriceVolatility(uint256 deviation);\n\n bool public paused;\n uint256 public tolerance = 0.02 ether; // 2% by default\n\n // Fields to make it compatible with `AggregatorV3Interface`\n uint8 public constant override decimals = 18;\n string public constant override description = \"\";\n uint256 public constant override version = 1;\n\n IOracleWeightedPool public immutable auraOracleWeightedPool;\n\n constructor(address _auraOracleWeightedPool, address _governor) {\n _setGovernor(_governor);\n auraOracleWeightedPool = IOracleWeightedPool(_auraOracleWeightedPool);\n }\n\n /**\n * @dev Queries the OracleWeightedPool for TWAP of two intervals\n * (1h data from 5m ago and the recent 5m data) and ensures that\n * the price hasn't deviated too much and returns the most recent\n * TWAP price.\n *\n * @return price The price scaled to 18 decimals\n **/\n function price() external view returns (int256) {\n return _price();\n }\n\n function _price() internal view returns (int256) {\n if (paused) {\n revert PriceFeedPausedError();\n }\n OracleAverageQuery[] memory queries = new OracleAverageQuery[](2);\n\n queries[0] = OracleAverageQuery({\n variable: Variable.PAIR_PRICE,\n secs: 3600, // Get 1h data\n ago: 300 // From 5min ago\n });\n queries[1] = OracleAverageQuery({\n variable: Variable.PAIR_PRICE,\n secs: 300, // Get 5min data\n ago: 0 // From now\n });\n\n uint256[] memory prices = auraOracleWeightedPool.getTimeWeightedAverage(\n queries\n );\n int256 price_1h = prices[0].toInt256();\n int256 price_5m = prices[1].toInt256();\n\n int256 diff = (1e18 * (price_1h - price_5m)) /\n ((price_1h + price_5m) / 2);\n uint256 absDiff = diff >= 0 ? diff.toUint256() : (-diff).toUint256();\n\n // Ensure the price hasn't moved too much (2% tolerance)\n // between now and the past hour\n if (absDiff > tolerance) {\n revert HighPriceVolatility(absDiff);\n }\n\n // Return the recent price\n return price_5m;\n }\n\n /**\n * Pauses the price feed. Callable by Strategist as well.\n **/\n function pause() external onlyGovernorOrStrategist {\n if (paused) {\n revert PriceFeedPausedError();\n }\n paused = true;\n emit PriceFeedPaused();\n }\n\n /**\n * Unpauses the price feed. Only Governor can call it\n **/\n function unpause() external onlyGovernor {\n if (!paused) {\n revert PriceFeedUnpausedError();\n }\n paused = false;\n emit PriceFeedUnpaused();\n }\n\n /**\n * Set the max amount of tolerance acceptable between\n * two different price points.\n *\n * @param _tolerance New tolerance value\n **/\n function setTolerance(uint256 _tolerance) external onlyGovernor {\n if (_tolerance > 0.1 ether) {\n revert InvalidToleranceBps();\n }\n emit ToleranceChanged(tolerance, _tolerance);\n tolerance = _tolerance;\n }\n\n /**\n * @dev This function exists to make the contract compatible\n * with AggregatorV3Interface (which OETHOracleRouter uses to\n * get the price).\n *\n * The `answer` returned by this is same as what `price()` would return.\n *\n * It doesn't return any data about rounds (since those doesn't exist).\n **/\n function latestRoundData()\n external\n view\n override\n returns (\n uint80,\n int256 answer,\n uint256,\n uint256 updatedAt,\n uint80\n )\n {\n answer = _price();\n updatedAt = block.timestamp;\n }\n\n /**\n * @dev This function exists to make the contract compatible\n * with AggregatorV3Interface.\n *\n * Always reverts since there're no round data in this contract.\n **/\n function getRoundData(uint80)\n external\n pure\n override\n returns (\n uint80,\n int256,\n uint256,\n uint256,\n uint80\n )\n {\n revert(\"No data present\");\n }\n}\n" + }, + "contracts/oracle/OETHFixedOracle.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { OETHOracleRouter } from \"./OETHOracleRouter.sol\";\n\n// @notice Oracle Router that returns 1e18 for all prices\n// used solely for deployment to testnets\ncontract OETHFixedOracle is OETHOracleRouter {\n constructor(address _auraPriceFeed) OETHOracleRouter(_auraPriceFeed) {}\n\n /**\n * @dev The price feed contract to use for a particular asset along with\n * maximum data staleness\n * @param asset address of the asset\n * @return feedAddress address of the price feed for the asset\n * @return maxStaleness maximum acceptable data staleness duration\n */\n // solhint-disable-next-line no-unused-vars\n function feedMetadata(address asset)\n internal\n view\n virtual\n override\n returns (address feedAddress, uint256 maxStaleness)\n {\n // fixes price for all of the assets\n feedAddress = FIXED_PRICE;\n maxStaleness = 0;\n }\n}\n" + }, + "contracts/oracle/OETHOracleRouter.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../interfaces/chainlink/AggregatorV3Interface.sol\";\nimport { OracleRouterBase } from \"./OracleRouterBase.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\n\n// @notice Oracle Router that denominates all prices in ETH\ncontract OETHOracleRouter is OracleRouterBase {\n using StableMath for uint256;\n\n address public immutable auraPriceFeed;\n\n constructor(address _auraPriceFeed) {\n auraPriceFeed = _auraPriceFeed;\n }\n\n /**\n * @notice Returns the total price in 18 digit units for a given asset.\n * This implementation does not (!) do range checks as the\n * parent OracleRouter does.\n * @param asset address of the asset\n * @return uint256 unit price for 1 asset unit, in 18 decimal fixed\n */\n function price(address asset)\n external\n view\n virtual\n override\n returns (uint256)\n {\n (address _feed, uint256 maxStaleness) = feedMetadata(asset);\n if (_feed == FIXED_PRICE) {\n return 1e18;\n }\n require(_feed != address(0), \"Asset not available\");\n\n // slither-disable-next-line unused-return\n (, int256 _iprice, , uint256 updatedAt, ) = AggregatorV3Interface(_feed)\n .latestRoundData();\n\n require(\n updatedAt + maxStaleness >= block.timestamp,\n \"Oracle price too old\"\n );\n\n uint8 decimals = getDecimals(_feed);\n uint256 _price = uint256(_iprice).scaleBy(18, decimals);\n return _price;\n }\n\n /**\n * @dev The price feed contract to use for a particular asset along with\n * maximum data staleness\n * @param asset address of the asset\n * @return feedAddress address of the price feed for the asset\n * @return maxStaleness maximum acceptable data staleness duration\n */\n function feedMetadata(address asset)\n internal\n view\n virtual\n override\n returns (address feedAddress, uint256 maxStaleness)\n {\n if (asset == 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2) {\n // FIXED_PRICE: WETH/ETH\n feedAddress = FIXED_PRICE;\n maxStaleness = 0;\n } else if (asset == 0x5E8422345238F34275888049021821E8E08CAa1f) {\n // frxETH/ETH\n feedAddress = 0xC58F3385FBc1C8AD2c0C9a061D7c13b141D7A5Df;\n maxStaleness = 18 hours + STALENESS_BUFFER;\n } else if (asset == 0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84) {\n // https://data.chain.link/ethereum/mainnet/crypto-eth/steth-eth\n // Chainlink: stETH/ETH\n feedAddress = 0x86392dC19c0b719886221c78AB11eb8Cf5c52812;\n maxStaleness = 1 days + STALENESS_BUFFER;\n } else if (asset == 0xae78736Cd615f374D3085123A210448E74Fc6393) {\n // https://data.chain.link/ethereum/mainnet/crypto-eth/reth-eth\n // Chainlink: rETH/ETH\n feedAddress = 0x536218f9E9Eb48863970252233c8F271f554C2d0;\n maxStaleness = 1 days + STALENESS_BUFFER;\n } else if (asset == 0xD533a949740bb3306d119CC777fa900bA034cd52) {\n // https://data.chain.link/ethereum/mainnet/crypto-eth/crv-eth\n // Chainlink: CRV/ETH\n feedAddress = 0x8a12Be339B0cD1829b91Adc01977caa5E9ac121e;\n maxStaleness = 1 days + STALENESS_BUFFER;\n } else if (asset == 0x4e3FBD56CD56c3e72c1403e103b45Db9da5B9D2B) {\n // https://data.chain.link/ethereum/mainnet/crypto-eth/cvx-eth\n // Chainlink: CVX/ETH\n feedAddress = 0xC9CbF687f43176B302F03f5e58470b77D07c61c6;\n maxStaleness = 1 days + STALENESS_BUFFER;\n } else if (asset == 0xBe9895146f7AF43049ca1c1AE358B0541Ea49704) {\n // https://data.chain.link/ethereum/mainnet/crypto-eth/cbeth-eth\n // Chainlink: cbETH/ETH\n feedAddress = 0xF017fcB346A1885194689bA23Eff2fE6fA5C483b;\n maxStaleness = 1 days + STALENESS_BUFFER;\n } else if (asset == 0xba100000625a3754423978a60c9317c58a424e3D) {\n // https://data.chain.link/ethereum/mainnet/crypto-eth/bal-eth\n // Chainlink: BAL/ETH\n feedAddress = 0xC1438AA3823A6Ba0C159CfA8D98dF5A994bA120b;\n maxStaleness = 1 days + STALENESS_BUFFER;\n } else if (asset == 0xC0c293ce456fF0ED870ADd98a0828Dd4d2903DBF) {\n // AURA/ETH\n feedAddress = auraPriceFeed;\n maxStaleness = 0;\n } else {\n revert(\"Asset not available\");\n }\n }\n}\n" + }, + "contracts/oracle/OracleRouter.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../interfaces/chainlink/AggregatorV3Interface.sol\";\nimport { OracleRouterBase } from \"./OracleRouterBase.sol\";\n\n// @notice Oracle Router that denominates all prices in USD\ncontract OracleRouter is OracleRouterBase {\n /**\n * @dev The price feed contract to use for a particular asset along with\n * maximum data staleness\n * @param asset address of the asset\n * @return feedAddress address of the price feed for the asset\n * @return maxStaleness maximum acceptable data staleness duration\n */\n function feedMetadata(address asset)\n internal\n pure\n virtual\n override\n returns (address feedAddress, uint256 maxStaleness)\n {\n /* + STALENESS_BUFFER is added in case Oracle for some reason doesn't\n * update on heartbeat and we add a generous buffer amount.\n */\n if (asset == 0x6B175474E89094C44Da98b954EedeAC495271d0F) {\n // https://data.chain.link/ethereum/mainnet/stablecoins/dai-usd\n // Chainlink: DAI/USD\n feedAddress = 0xAed0c38402a5d19df6E4c03F4E2DceD6e29c1ee9;\n maxStaleness = 1 hours + STALENESS_BUFFER;\n } else if (asset == 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48) {\n // https://data.chain.link/ethereum/mainnet/stablecoins/usdc-usd\n // Chainlink: USDC/USD\n feedAddress = 0x8fFfFfd4AfB6115b954Bd326cbe7B4BA576818f6;\n maxStaleness = 1 days + STALENESS_BUFFER;\n } else if (asset == 0xdAC17F958D2ee523a2206206994597C13D831ec7) {\n // https://data.chain.link/ethereum/mainnet/stablecoins/usdt-usd\n // Chainlink: USDT/USD\n feedAddress = 0x3E7d1eAB13ad0104d2750B8863b489D65364e32D;\n maxStaleness = 1 days + STALENESS_BUFFER;\n } else if (asset == 0xc00e94Cb662C3520282E6f5717214004A7f26888) {\n // https://data.chain.link/ethereum/mainnet/crypto-usd/comp-usd\n // Chainlink: COMP/USD\n feedAddress = 0xdbd020CAeF83eFd542f4De03e3cF0C28A4428bd5;\n maxStaleness = 1 hours + STALENESS_BUFFER;\n } else if (asset == 0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9) {\n // https://data.chain.link/ethereum/mainnet/crypto-usd/aave-usd\n // Chainlink: AAVE/USD\n feedAddress = 0x547a514d5e3769680Ce22B2361c10Ea13619e8a9;\n maxStaleness = 1 hours + STALENESS_BUFFER;\n } else if (asset == 0xD533a949740bb3306d119CC777fa900bA034cd52) {\n // https://data.chain.link/ethereum/mainnet/crypto-usd/crv-usd\n // Chainlink: CRV/USD\n feedAddress = 0xCd627aA160A6fA45Eb793D19Ef54f5062F20f33f;\n maxStaleness = 1 days + STALENESS_BUFFER;\n } else if (asset == 0x4e3FBD56CD56c3e72c1403e103b45Db9da5B9D2B) {\n // Chainlink: CVX/USD\n feedAddress = 0xd962fC30A72A84cE50161031391756Bf2876Af5D;\n maxStaleness = 1 days + STALENESS_BUFFER;\n } else {\n revert(\"Asset not available\");\n }\n }\n}\n" + }, + "contracts/oracle/OracleRouterBase.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../interfaces/chainlink/AggregatorV3Interface.sol\";\nimport { IOracle } from \"../interfaces/IOracle.sol\";\nimport { Helpers } from \"../utils/Helpers.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\nimport { SafeCast } from \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\n\n// @notice Abstract functionality that is shared between various Oracle Routers\nabstract contract OracleRouterBase is IOracle {\n using StableMath for uint256;\n using SafeCast for int256;\n\n uint256 internal constant MIN_DRIFT = 0.7e18;\n uint256 internal constant MAX_DRIFT = 1.3e18;\n address internal constant FIXED_PRICE =\n 0x0000000000000000000000000000000000000001;\n // Maximum allowed staleness buffer above normal Oracle maximum staleness\n uint256 internal constant STALENESS_BUFFER = 1 days;\n mapping(address => uint8) internal decimalsCache;\n\n /**\n * @dev The price feed contract to use for a particular asset along with\n * maximum data staleness\n * @param asset address of the asset\n * @return feedAddress address of the price feed for the asset\n * @return maxStaleness maximum acceptable data staleness duration\n */\n function feedMetadata(address asset)\n internal\n view\n virtual\n returns (address feedAddress, uint256 maxStaleness);\n\n /**\n * @notice Returns the total price in 18 digit unit for a given asset.\n * @param asset address of the asset\n * @return uint256 unit price for 1 asset unit, in 18 decimal fixed\n */\n function price(address asset)\n external\n view\n virtual\n override\n returns (uint256)\n {\n (address _feed, uint256 maxStaleness) = feedMetadata(asset);\n require(_feed != address(0), \"Asset not available\");\n require(_feed != FIXED_PRICE, \"Fixed price feeds not supported\");\n\n // slither-disable-next-line unused-return\n (, int256 _iprice, , uint256 updatedAt, ) = AggregatorV3Interface(_feed)\n .latestRoundData();\n\n require(\n updatedAt + maxStaleness >= block.timestamp,\n \"Oracle price too old\"\n );\n\n uint8 decimals = getDecimals(_feed);\n\n uint256 _price = _iprice.toUint256().scaleBy(18, decimals);\n if (shouldBePegged(asset)) {\n require(_price <= MAX_DRIFT, \"Oracle: Price exceeds max\");\n require(_price >= MIN_DRIFT, \"Oracle: Price under min\");\n }\n return _price;\n }\n\n function getDecimals(address _feed) internal view virtual returns (uint8) {\n uint8 decimals = decimalsCache[_feed];\n require(decimals > 0, \"Oracle: Decimals not cached\");\n return decimals;\n }\n\n /**\n * @notice Before an asset/feed price is fetches for the first time the\n * decimals need to be cached. This is a gas optimization\n * @param asset address of the asset\n * @return uint8 corresponding asset decimals\n */\n function cacheDecimals(address asset) external returns (uint8) {\n (address _feed, ) = feedMetadata(asset);\n require(_feed != address(0), \"Asset not available\");\n require(_feed != FIXED_PRICE, \"Fixed price feeds not supported\");\n\n uint8 decimals = AggregatorV3Interface(_feed).decimals();\n decimalsCache[_feed] = decimals;\n return decimals;\n }\n\n function shouldBePegged(address _asset) internal view returns (bool) {\n string memory symbol = Helpers.getSymbol(_asset);\n bytes32 symbolHash = keccak256(abi.encodePacked(symbol));\n return\n symbolHash == keccak256(abi.encodePacked(\"DAI\")) ||\n symbolHash == keccak256(abi.encodePacked(\"USDC\")) ||\n symbolHash == keccak256(abi.encodePacked(\"USDT\"));\n }\n}\n" + }, + "contracts/proxies/InitializeGovernedUpgradeabilityProxy.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { Address } from \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport { Governable } from \"../governance/Governable.sol\";\n\n/**\n * @title BaseGovernedUpgradeabilityProxy\n * @dev This contract combines an upgradeability proxy with our governor system.\n * It is based on an older version of OpenZeppelins BaseUpgradeabilityProxy\n * with Solidity ^0.8.0.\n * @author Origin Protocol Inc\n */\ncontract InitializeGovernedUpgradeabilityProxy is Governable {\n /**\n * @dev Emitted when the implementation is upgraded.\n * @param implementation Address of the new implementation.\n */\n event Upgraded(address indexed implementation);\n\n /**\n * @dev Contract initializer with Governor enforcement\n * @param _logic Address of the initial implementation.\n * @param _initGovernor Address of the initial Governor.\n * @param _data Data to send as msg.data to the implementation to initialize\n * the proxied contract.\n * It should include the signature and the parameters of the function to be\n * called, as described in\n * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.\n * This parameter is optional, if no data is given the initialization call\n * to proxied contract will be skipped.\n */\n function initialize(\n address _logic,\n address _initGovernor,\n bytes calldata _data\n ) public payable onlyGovernor {\n require(_implementation() == address(0));\n require(_logic != address(0), \"Implementation not set\");\n assert(\n IMPLEMENTATION_SLOT ==\n bytes32(uint256(keccak256(\"eip1967.proxy.implementation\")) - 1)\n );\n _setImplementation(_logic);\n if (_data.length > 0) {\n (bool success, ) = _logic.delegatecall(_data);\n require(success);\n }\n _changeGovernor(_initGovernor);\n }\n\n /**\n * @return The address of the proxy admin/it's also the governor.\n */\n function admin() external view returns (address) {\n return _governor();\n }\n\n /**\n * @return The address of the implementation.\n */\n function implementation() external view returns (address) {\n return _implementation();\n }\n\n /**\n * @dev Upgrade the backing implementation of the proxy.\n * Only the admin can call this function.\n * @param newImplementation Address of the new implementation.\n */\n function upgradeTo(address newImplementation) external onlyGovernor {\n _upgradeTo(newImplementation);\n }\n\n /**\n * @dev Upgrade the backing implementation of the proxy and call a function\n * on the new implementation.\n * This is useful to initialize the proxied contract.\n * @param newImplementation Address of the new implementation.\n * @param data Data to send as msg.data in the low level call.\n * It should include the signature and the parameters of the function to be called, as described in\n * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.\n */\n function upgradeToAndCall(address newImplementation, bytes calldata data)\n external\n payable\n onlyGovernor\n {\n _upgradeTo(newImplementation);\n (bool success, ) = newImplementation.delegatecall(data);\n require(success);\n }\n\n /**\n * @dev Fallback function.\n * Implemented entirely in `_fallback`.\n */\n fallback() external payable {\n _fallback();\n }\n\n /**\n * @dev Delegates execution to an implementation contract.\n * This is a low level function that doesn't return to its internal call site.\n * It will return to the external caller whatever the implementation returns.\n * @param _impl Address to delegate.\n */\n function _delegate(address _impl) internal {\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(gas(), _impl, 0, calldatasize(), 0, 0)\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 /**\n * @dev Function that is run as the first thing in the fallback function.\n * Can be redefined in derived contracts to add functionality.\n * Redefinitions must call super._willFallback().\n */\n function _willFallback() internal {}\n\n /**\n * @dev fallback implementation.\n * Extracted to enable manual triggering.\n */\n function _fallback() internal {\n _willFallback();\n _delegate(_implementation());\n }\n\n /**\n * @dev Storage slot with the address of the current implementation.\n * This is the keccak-256 hash of \"eip1967.proxy.implementation\" subtracted by 1, and is\n * validated in the constructor.\n */\n bytes32 internal constant IMPLEMENTATION_SLOT =\n 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\n\n /**\n * @dev Returns the current implementation.\n * @return impl Address of the current implementation\n */\n function _implementation() internal view returns (address impl) {\n bytes32 slot = IMPLEMENTATION_SLOT;\n // solhint-disable-next-line no-inline-assembly\n assembly {\n impl := sload(slot)\n }\n }\n\n /**\n * @dev Upgrades the proxy to a new implementation.\n * @param newImplementation Address of the new implementation.\n */\n function _upgradeTo(address newImplementation) internal {\n _setImplementation(newImplementation);\n emit Upgraded(newImplementation);\n }\n\n /**\n * @dev Sets the implementation address of the proxy.\n * @param newImplementation Address of the new implementation.\n */\n function _setImplementation(address newImplementation) internal {\n require(\n Address.isContract(newImplementation),\n \"Cannot set a proxy implementation to a non-contract address\"\n );\n\n bytes32 slot = IMPLEMENTATION_SLOT;\n\n // solhint-disable-next-line no-inline-assembly\n assembly {\n sstore(slot, newImplementation)\n }\n }\n}\n" + }, + "contracts/proxies/Proxies.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { InitializeGovernedUpgradeabilityProxy } from \"./InitializeGovernedUpgradeabilityProxy.sol\";\n\n/**\n * @notice OUSDProxy delegates calls to an OUSD implementation\n */\ncontract OUSDProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice WrappedOUSDProxy delegates calls to a WrappedOUSD implementation\n */\ncontract WrappedOUSDProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice VaultProxy delegates calls to a Vault implementation\n */\ncontract VaultProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice CompoundStrategyProxy delegates calls to a CompoundStrategy implementation\n */\ncontract CompoundStrategyProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice AaveStrategyProxy delegates calls to a AaveStrategy implementation\n */\ncontract AaveStrategyProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice ThreePoolStrategyProxy delegates calls to a ThreePoolStrategy implementation\n */\ncontract ThreePoolStrategyProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice ConvexStrategyProxy delegates calls to a ConvexStrategy implementation\n */\ncontract ConvexStrategyProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice HarvesterProxy delegates calls to a Harvester implementation\n */\ncontract HarvesterProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice DripperProxy delegates calls to a Dripper implementation\n */\ncontract DripperProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice MorphoCompoundStrategyProxy delegates calls to a MorphoCompoundStrategy implementation\n */\ncontract MorphoCompoundStrategyProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice ConvexOUSDMetaStrategyProxy delegates calls to a ConvexOUSDMetaStrategy implementation\n */\ncontract ConvexOUSDMetaStrategyProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice ConvexLUSDMetaStrategyProxy delegates calls to a ConvexalGeneralizedMetaStrategy implementation\n */\ncontract ConvexLUSDMetaStrategyProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice MorphoAaveStrategyProxy delegates calls to a MorphoCompoundStrategy implementation\n */\ncontract MorphoAaveStrategyProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice OETHProxy delegates calls to nowhere for now\n */\ncontract OETHProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice WOETHProxy delegates calls to nowhere for now\n */\ncontract WOETHProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice OETHVaultProxy delegates calls to a Vault implementation\n */\ncontract OETHVaultProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice OETHDripperProxy delegates calls to a OETHDripper implementation\n */\ncontract OETHDripperProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice OETHHarvesterProxy delegates calls to a Harvester implementation\n */\ncontract OETHHarvesterProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice FraxETHStrategyProxy delegates calls to a FraxETHStrategy implementation\n */\ncontract FraxETHStrategyProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice CurveEthStrategyProxy delegates calls to a CurveEthStrategy implementation\n */\ncontract ConvexEthMetaStrategyProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice BuybackProxy delegates calls to Buyback implementation\n */\ncontract BuybackProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice OETHMorphoAaveStrategyProxy delegates calls to a MorphoAaveStrategy implementation\n */\ncontract OETHMorphoAaveStrategyProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice OETHBalancerMetaPoolrEthStrategyProxy delegates calls to a BalancerMetaPoolStrategy implementation\n */\ncontract OETHBalancerMetaPoolrEthStrategyProxy is\n InitializeGovernedUpgradeabilityProxy\n{\n\n}\n\n/**\n * @notice OETHBalancerMetaPoolwstEthStrategyProxy delegates calls to a BalancerMetaPoolStrategy implementation\n */\ncontract OETHBalancerMetaPoolwstEthStrategyProxy is\n InitializeGovernedUpgradeabilityProxy\n{\n\n}\n\n/**\n * @notice FluxStrategyProxy delegates calls to a CompoundStrategy implementation\n */\ncontract FluxStrategyProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice MakerDsrStrategyProxy delegates calls to a Generalized4626Strategy implementation\n */\ncontract MakerDsrStrategyProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice FrxEthRedeemStrategyProxy delegates calls to a FrxEthRedeemStrategy implementation\n */\ncontract FrxEthRedeemStrategyProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice OETHBuybackProxy delegates calls to Buyback implementation\n */\ncontract OETHBuybackProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice BridgedWOETHProxy delegates calls to BridgedWOETH implementation\n */\ncontract BridgedWOETHProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice NativeStakingSSVStrategyProxy delegates calls to NativeStakingSSVStrategy implementation\n */\ncontract NativeStakingSSVStrategyProxy is\n InitializeGovernedUpgradeabilityProxy\n{\n\n}\n\n/**\n * @notice NativeStakingFeeAccumulatorProxy delegates calls to NativeStakingFeeCollector implementation\n */\ncontract NativeStakingFeeAccumulatorProxy is\n InitializeGovernedUpgradeabilityProxy\n{\n\n}\n" + }, + "contracts/staking/SingleAssetStaking.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeMath } from \"@openzeppelin/contracts/utils/math/SafeMath.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 { StableMath } from \"../utils/StableMath.sol\";\n\ncontract SingleAssetStaking is Initializable, Governable {\n using SafeMath for uint256;\n using StableMath for uint256;\n using SafeERC20 for IERC20;\n\n /* ========== STATE VARIABLES ========== */\n\n IERC20 public stakingToken; // this is both the staking and rewards\n\n struct Stake {\n uint256 amount; // amount to stake\n uint256 end; // when does the staking period end\n uint256 duration; // the duration of the stake\n uint240 rate; // rate to charge use 248 to reserve 8 bits for the bool\n bool paid;\n uint8 stakeType;\n }\n\n struct DropRoot {\n bytes32 hash;\n uint256 depth;\n }\n\n uint256[] public durations; // allowed durations\n uint256[] public rates; // rates that correspond with the allowed durations\n\n uint256 public totalOutstanding;\n bool public paused;\n\n mapping(address => Stake[]) public userStakes;\n\n mapping(uint8 => DropRoot) public dropRoots;\n\n // type 0 is reserved for stakes done by the user, all other types will be drop/preApproved stakes\n uint8 constant USER_STAKE_TYPE = 0;\n uint256 constant MAX_STAKES = 256;\n\n address public transferAgent;\n\n /* ========== Initialize ========== */\n\n /**\n * @dev Initialize the contracts, sets up durations, rates, and preApprover\n * for preApproved contracts can only be called once\n * @param _stakingToken Address of the token that we are staking\n * @param _durations Array of allowed durations in seconds\n * @param _rates Array of rates(0.3 is 30%) that correspond to the allowed\n * durations in 1e18 precision\n */\n function initialize(\n address _stakingToken,\n uint256[] calldata _durations,\n uint256[] calldata _rates\n ) external onlyGovernor initializer {\n stakingToken = IERC20(_stakingToken);\n _setDurationRates(_durations, _rates);\n }\n\n /* ========= Internal helper functions ======== */\n\n /**\n * @dev Validate and set the duration and corresponding rates, will emit\n * events NewRate and NewDurations\n */\n function _setDurationRates(\n uint256[] memory _durations,\n uint256[] memory _rates\n ) internal {\n require(\n _rates.length == _durations.length,\n \"Mismatch durations and rates\"\n );\n\n for (uint256 i = 0; i < _rates.length; i++) {\n require(_rates[i] < type(uint240).max, \"Max rate exceeded\");\n }\n\n rates = _rates;\n durations = _durations;\n\n emit NewRates(msg.sender, rates);\n emit NewDurations(msg.sender, durations);\n }\n\n function _totalExpectedRewards(Stake[] storage stakes)\n internal\n view\n returns (uint256 total)\n {\n for (uint256 i = 0; i < stakes.length; i++) {\n Stake storage stake = stakes[i];\n if (!stake.paid) {\n total = total.add(stake.amount.mulTruncate(stake.rate));\n }\n }\n }\n\n function _totalExpected(Stake storage _stake)\n internal\n view\n returns (uint256)\n {\n return _stake.amount.add(_stake.amount.mulTruncate(_stake.rate));\n }\n\n function _airDroppedStakeClaimed(address account, uint8 stakeType)\n internal\n view\n returns (bool)\n {\n Stake[] storage stakes = userStakes[account];\n for (uint256 i = 0; i < stakes.length; i++) {\n if (stakes[i].stakeType == stakeType) {\n return true;\n }\n }\n return false;\n }\n\n function _findDurationRate(uint256 duration)\n internal\n view\n returns (uint240)\n {\n for (uint256 i = 0; i < durations.length; i++) {\n if (duration == durations[i]) {\n return uint240(rates[i]);\n }\n }\n return 0;\n }\n\n /**\n * @dev Internal staking function\n * will insert the stake into the stakes array and verify we have\n * enough to pay off stake + reward\n * @param staker Address of the staker\n * @param stakeType Number that represent the type of the stake, 0 is user\n * initiated all else is currently preApproved\n * @param duration Number of seconds this stake will be held for\n * @param rate Rate(0.3 is 30%) of reward for this stake in 1e18, uint240 =\n * to fit the bool and type in struct Stake\n * @param amount Number of tokens to stake in 1e18\n */\n function _stake(\n address staker,\n uint8 stakeType,\n uint256 duration,\n uint240 rate,\n uint256 amount\n ) internal {\n require(!paused, \"Staking paused\");\n\n Stake[] storage stakes = userStakes[staker];\n\n uint256 end = block.timestamp.add(duration);\n\n uint256 i = stakes.length; // start at the end of the current array\n\n require(i < MAX_STAKES, \"Max stakes\");\n\n stakes.push(); // grow the array\n // find the spot where we can insert the current stake\n // this should make an increasing list sorted by end\n while (i != 0 && stakes[i - 1].end > end) {\n // shift it back one\n stakes[i] = stakes[i - 1];\n i -= 1;\n }\n\n // insert the stake\n Stake storage newStake = stakes[i];\n newStake.rate = rate;\n newStake.stakeType = stakeType;\n newStake.end = end;\n newStake.duration = duration;\n newStake.amount = amount;\n\n totalOutstanding = totalOutstanding.add(_totalExpected(newStake));\n\n emit Staked(staker, amount, duration, rate);\n }\n\n function _stakeWithChecks(\n address staker,\n uint256 amount,\n uint256 duration\n ) internal {\n require(amount > 0, \"Cannot stake 0\");\n\n uint240 rewardRate = _findDurationRate(duration);\n require(rewardRate > 0, \"Invalid duration\"); // we couldn't find the rate that correspond to the passed duration\n\n _stake(staker, USER_STAKE_TYPE, duration, rewardRate, amount);\n // transfer in the token so that we can stake the correct amount\n stakingToken.safeTransferFrom(staker, address(this), amount);\n }\n\n modifier requireLiquidity() {\n // we need to have enough balance to cover the rewards after the operation is complete\n _;\n require(\n stakingToken.balanceOf(address(this)) >= totalOutstanding,\n \"Insufficient rewards\"\n );\n }\n\n /* ========== VIEWS ========== */\n\n function getAllDurations() external view returns (uint256[] memory) {\n return durations;\n }\n\n function getAllRates() external view returns (uint256[] memory) {\n return rates;\n }\n\n /**\n * @dev Return all the stakes paid and unpaid for a given user\n * @param account Address of the account that we want to look up\n */\n function getAllStakes(address account)\n external\n view\n returns (Stake[] memory)\n {\n return userStakes[account];\n }\n\n /**\n * @dev Find the rate that corresponds to a given duration\n * @param _duration Number of seconds\n */\n function durationRewardRate(uint256 _duration)\n external\n view\n returns (uint256)\n {\n return _findDurationRate(_duration);\n }\n\n /**\n * @dev Has the airdropped stake already been claimed\n */\n function airDroppedStakeClaimed(address account, uint8 stakeType)\n external\n view\n returns (bool)\n {\n return _airDroppedStakeClaimed(account, stakeType);\n }\n\n /**\n * @dev Calculate all the staked value a user has put into the contract,\n * rewards not included\n * @param account Address of the account that we want to look up\n */\n function totalStaked(address account)\n external\n view\n returns (uint256 total)\n {\n Stake[] storage stakes = userStakes[account];\n\n for (uint256 i = 0; i < stakes.length; i++) {\n if (!stakes[i].paid) {\n total = total.add(stakes[i].amount);\n }\n }\n }\n\n /**\n * @dev Calculate all the rewards a user can expect to receive.\n * @param account Address of the account that we want to look up\n */\n function totalExpectedRewards(address account)\n external\n view\n returns (uint256)\n {\n return _totalExpectedRewards(userStakes[account]);\n }\n\n /**\n * @dev Calculate all current holdings of a user: staked value + prorated rewards\n * @param account Address of the account that we want to look up\n */\n function totalCurrentHoldings(address account)\n external\n view\n returns (uint256 total)\n {\n Stake[] storage stakes = userStakes[account];\n\n for (uint256 i = 0; i < stakes.length; i++) {\n Stake storage stake = stakes[i];\n if (stake.paid) {\n continue;\n } else if (stake.end < block.timestamp) {\n total = total.add(_totalExpected(stake));\n } else {\n //calcualte the precentage accrued in term of rewards\n total = total.add(\n stake.amount.add(\n stake.amount.mulTruncate(stake.rate).mulTruncate(\n stake\n .duration\n .sub(stake.end.sub(block.timestamp))\n .divPrecisely(stake.duration)\n )\n )\n );\n }\n }\n }\n\n /* ========== MUTATIVE FUNCTIONS ========== */\n\n /**\n * @dev Make a preapproved stake for the user, this is a presigned voucher that the user can redeem either from\n * an airdrop or a compensation program.\n * Only 1 of each type is allowed per user. The proof must match the root hash\n * @param index Number that is zero base index of the stake in the payout entry\n * @param stakeType Number that represent the type of the stake, must not be 0 which is user stake\n * @param duration Number of seconds this stake will be held for\n * @param rate Rate(0.3 is 30%) of reward for this stake in 1e18, uint240 to fit the bool and type in struct Stake\n * @param amount Number of tokens to stake in 1e18\n * @param merkleProof Array of proofs for that amount\n */\n function airDroppedStake(\n uint256 index,\n uint8 stakeType,\n uint256 duration,\n uint256 rate,\n uint256 amount,\n bytes32[] calldata merkleProof\n ) external requireLiquidity {\n require(stakeType != USER_STAKE_TYPE, \"Cannot be normal staking\");\n require(rate < type(uint240).max, \"Max rate exceeded\");\n require(index < 2**merkleProof.length, \"Invalid index\");\n DropRoot storage dropRoot = dropRoots[stakeType];\n require(merkleProof.length == dropRoot.depth, \"Invalid proof\");\n\n // Compute the merkle root\n bytes32 node = keccak256(\n abi.encodePacked(\n index,\n stakeType,\n address(this),\n msg.sender,\n duration,\n rate,\n amount\n )\n );\n uint256 path = index;\n for (uint16 i = 0; i < merkleProof.length; i++) {\n if ((path & 0x01) == 1) {\n node = keccak256(abi.encodePacked(merkleProof[i], node));\n } else {\n node = keccak256(abi.encodePacked(node, merkleProof[i]));\n }\n path /= 2;\n }\n\n // Check the merkle proof\n require(node == dropRoot.hash, \"Stake not approved\");\n\n // verify that we haven't already staked\n require(\n !_airDroppedStakeClaimed(msg.sender, stakeType),\n \"Already staked\"\n );\n\n _stake(msg.sender, stakeType, duration, uint240(rate), amount);\n }\n\n /**\n * @dev Stake an approved amount of staking token into the contract.\n * User must have already approved the contract for specified amount.\n * @param amount Number of tokens to stake in 1e18\n * @param duration Number of seconds this stake will be held for\n */\n function stake(uint256 amount, uint256 duration) external requireLiquidity {\n // no checks are performed in this function since those are already present in _stakeWithChecks\n _stakeWithChecks(msg.sender, amount, duration);\n }\n\n /**\n * @dev Stake an approved amount of staking token into the contract. This function\n * can only be called by OGN token contract.\n * @param staker Address of the account that is creating the stake\n * @param amount Number of tokens to stake in 1e18\n * @param duration Number of seconds this stake will be held for\n */\n function stakeWithSender(\n address staker,\n uint256 amount,\n uint256 duration\n ) external requireLiquidity returns (bool) {\n require(\n msg.sender == address(stakingToken),\n \"Only token contract can make this call\"\n );\n\n _stakeWithChecks(staker, amount, duration);\n return true;\n }\n\n /**\n * @dev Exit out of all possible stakes\n */\n function exit() external requireLiquidity {\n Stake[] storage stakes = userStakes[msg.sender];\n require(stakes.length > 0, \"Nothing staked\");\n\n uint256 totalWithdraw = 0;\n uint256 stakedAmount = 0;\n uint256 l = stakes.length;\n do {\n Stake storage exitStake = stakes[l - 1];\n // stop on the first ended stake that's already been paid\n if (exitStake.end < block.timestamp && exitStake.paid) {\n break;\n }\n //might not be ended\n if (exitStake.end < block.timestamp) {\n //we are paying out the stake\n exitStake.paid = true;\n totalWithdraw = totalWithdraw.add(_totalExpected(exitStake));\n stakedAmount = stakedAmount.add(exitStake.amount);\n }\n l--;\n } while (l > 0);\n require(totalWithdraw > 0, \"All stakes in lock-up\");\n\n totalOutstanding = totalOutstanding.sub(totalWithdraw);\n emit Withdrawn(msg.sender, totalWithdraw, stakedAmount);\n stakingToken.safeTransfer(msg.sender, totalWithdraw);\n }\n\n /**\n * @dev Use to transfer all the stakes of an account in the case that the account is compromised\n * Requires access to both the account itself and the transfer agent\n * @param _frmAccount the address to transfer from\n * @param _dstAccount the address to transfer to(must be a clean address with no stakes)\n * @param r r portion of the signature by the transfer agent\n * @param s s portion of the signature\n * @param v v portion of the signature\n */\n function transferStakes(\n address _frmAccount,\n address _dstAccount,\n bytes32 r,\n bytes32 s,\n uint8 v\n ) external {\n require(transferAgent == msg.sender, \"must be transfer agent\");\n Stake[] storage dstStakes = userStakes[_dstAccount];\n require(dstStakes.length == 0, \"Dest stakes must be empty\");\n require(_frmAccount != address(0), \"from account not set\");\n Stake[] storage stakes = userStakes[_frmAccount];\n require(stakes.length > 0, \"Nothing to transfer\");\n\n // matches ethers.signMsg(ethers.utils.solidityPack([string(4), address, adddress, address]))\n bytes32 hash = keccak256(\n abi.encodePacked(\n \"\\x19Ethereum Signed Message:\\n64\",\n abi.encodePacked(\n \"tran\",\n address(this),\n _frmAccount,\n _dstAccount\n )\n )\n );\n require(ecrecover(hash, v, r, s) == _frmAccount, \"Transfer not authed\");\n\n // copy the stakes into the dstAccount array and delete the old one\n userStakes[_dstAccount] = stakes;\n delete userStakes[_frmAccount];\n emit StakesTransfered(_frmAccount, _dstAccount, stakes.length);\n }\n\n /* ========== MODIFIERS ========== */\n\n function setPaused(bool _paused) external onlyGovernor {\n paused = _paused;\n emit Paused(msg.sender, paused);\n }\n\n /**\n * @dev Set new durations and rates will not effect existing stakes\n * @param _durations Array of durations in seconds\n * @param _rates Array of rates that corresponds to the durations (0.01 is 1%) in 1e18\n */\n function setDurationRates(\n uint256[] calldata _durations,\n uint256[] calldata _rates\n ) external onlyGovernor {\n _setDurationRates(_durations, _rates);\n }\n\n /**\n * @dev Set the agent that will authorize transfers\n * @param _agent Address of agent\n */\n function setTransferAgent(address _agent) external onlyGovernor {\n transferAgent = _agent;\n }\n\n /**\n * @dev Set air drop root for a specific stake type\n * @param _stakeType Type of staking must be greater than 0\n * @param _rootHash Root hash of the Merkle Tree\n * @param _proofDepth Depth of the Merklke Tree\n */\n function setAirDropRoot(\n uint8 _stakeType,\n bytes32 _rootHash,\n uint256 _proofDepth\n ) external onlyGovernor {\n require(_stakeType != USER_STAKE_TYPE, \"Cannot be normal staking\");\n dropRoots[_stakeType].hash = _rootHash;\n dropRoots[_stakeType].depth = _proofDepth;\n emit NewAirDropRootHash(_stakeType, _rootHash, _proofDepth);\n }\n\n /* ========== EVENTS ========== */\n\n event Staked(\n address indexed user,\n uint256 amount,\n uint256 duration,\n uint256 rate\n );\n event Withdrawn(address indexed user, uint256 amount, uint256 stakedAmount);\n event Paused(address indexed user, bool yes);\n event NewDurations(address indexed user, uint256[] durations);\n event NewRates(address indexed user, uint256[] rates);\n event NewAirDropRootHash(\n uint8 stakeType,\n bytes32 rootHash,\n uint256 proofDepth\n );\n event StakesTransfered(\n address indexed fromUser,\n address toUser,\n uint256 numStakes\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/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\nimport { Governable } from \"../../governance/Governable.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 is Governable {\n /// @notice The address of the Native Staking Strategy\n address public immutable STRATEGY;\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 }\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_ADDRESS;\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 _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 address _feeAccumulator,\n address _beaconChainDepositContract\n )\n InitializableAbstractStrategy(_baseConfig)\n ValidatorAccountant(\n _wethAddress,\n _baseConfig.vaultAddress,\n _beaconChainDepositContract,\n _ssvNetwork\n )\n {\n SSV_TOKEN_ADDRESS = _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 /// @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_TOKEN_ADDRESS).deposit{ value: ethRewards }();\n\n emit RewardTokenCollected(\n harvesterAddress,\n WETH_TOKEN_ADDRESS,\n ethRewards\n );\n IERC20(WETH_TOKEN_ADDRESS).safeTransfer(\n harvesterAddress,\n ethRewards\n );\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_TOKEN_ADDRESS, \"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_TOKEN_ADDRESS).balanceOf(\n address(this)\n );\n uint256 newWeth = wethBalance - depositedWethAccountedFor;\n\n if (newWeth > 0) {\n depositedWethAccountedFor = wethBalance;\n\n _deposit(WETH_TOKEN_ADDRESS, newWeth);\n }\n }\n\n /// @notice Withdraw WETH from this contract. Used only if some WETH for is lingering on the contract. That\n /// can happen when:\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 _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 emit Withdrawal(_asset, address(0), _amount);\n IERC20(_asset).safeTransfer(_recipient, _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_TOKEN_ADDRESS).balanceOf(\n address(this)\n );\n if (wethBalance > 0) {\n _withdraw(vaultAddress, WETH_TOKEN_ADDRESS, wethBalance);\n }\n }\n\n function _abstractSetPToken(address _asset, address) internal override {}\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_TOKEN_ADDRESS, \"Unsupported asset\");\n\n balance =\n // add the ETH that has been staked in validators\n activeDepositedValidators *\n 32 ether +\n // add the WETH in the strategy from deposits that are still to be staked\n IERC20(WETH_TOKEN_ADDRESS).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_TOKEN_ADDRESS;\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_ADDRESS).approve(\n SSV_NETWORK_ADDRESS,\n type(uint256).max\n );\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 ||\n msg.sender == WETH_TOKEN_ADDRESS,\n \"eth not from allowed contracts\"\n );\n }\n\n function _wethWithdrawnToVault(uint256 _amount) internal override {\n emit Withdrawal(WETH_TOKEN_ADDRESS, address(0), _amount);\n }\n\n function _wethWithdrawnAndStaked(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 direclty\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 /// @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 MAX_STAKE = 32 ether;\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 constructor(\n address _wethAddress,\n address _vaultAddress,\n address _beaconChainDepositContract,\n address _ssvNetwork\n )\n ValidatorRegistrator(\n _wethAddress,\n _vaultAddress,\n _beaconChainDepositContract,\n _ssvNetwork\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 emit FuseIntervalUpdated(_fuseIntervalStart, _fuseIntervalEnd);\n\n fuseIntervalStart = _fuseIntervalStart;\n fuseIntervalEnd = _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 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 >= MAX_STAKE) {\n uint256 fullyWithdrawnValidators;\n // safe since MAX_STAKE is hardcoded to 32ETH\n unchecked {\n // explicitly cast to uint256 as we want to round to a whole number of validators\n fullyWithdrawnValidators = uint256(newSweptETH / MAX_STAKE);\n }\n activeDepositedValidators -= fullyWithdrawnValidators;\n\n uint256 wethToVault = MAX_STAKE * fullyWithdrawnValidators;\n IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: wethToVault }();\n // slither-disable-next-line unchecked-transfer\n IWETH9(WETH_TOKEN_ADDRESS).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 < 32 ether, \"unexpected accounting\");\n\n // If no Beacon chain consensus rewards swept\n if (ethRemaining == 0) {\n // do nothing\n return accountingValid;\n }\n // Beacon chain consensus rewards swept (partial validator withdrawals)\n else if (ethRemaining < fuseIntervalStart) {\n // solhint-disable-next-line reentrancy\n consensusRewards += ethRemaining;\n emit AccountingConsensusRewards(ethRemaining);\n }\n // Beacon chain consensus rewards swept but also a slashed validator fully exited\n else if (ethRemaining > fuseIntervalEnd) {\n IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: ethRemaining }();\n // slither-disable-next-line unchecked-transfer\n IWETH9(WETH_TOKEN_ADDRESS).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 {\n require(\n lastFixAccountingBlockNumber + MIN_FIX_ACCOUNTING_CADENCE <\n block.number,\n \"manuallyFixAccounting 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 emit AccountingManuallyFixed(\n _validatorsDelta,\n _consensusRewardsDelta,\n _ethToVaultAmount\n );\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_TOKEN_ADDRESS).deposit{ value: _ethToVaultAmount }();\n // slither-disable-next-line unchecked-transfer\n IWETH9(WETH_TOKEN_ADDRESS).transfer(\n VAULT_ADDRESS,\n _ethToVaultAmount\n );\n _wethWithdrawnToVault(_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 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 address of the Wrapped ETH (WETH) token contract\n address public immutable WETH_TOKEN_ADDRESS;\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_ADDRESS;\n /// @notice Address of the OETH Vault proxy contract\n address public immutable VAULT_ADDRESS;\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 governor needs to approve further staking\n uint256 public stakeETHThreshold;\n /// @notice Amount of ETH that can has been staked since the last governor approval.\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(\n bytes32 indexed pubKeyHash,\n bytes pubKey,\n uint256 amount,\n bytes withdrawal_credentials\n );\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 constructor(\n address _wethAddress,\n address _vaultAddress,\n address _beaconChainDepositContract,\n address _ssvNetwork\n ) {\n WETH_TOKEN_ADDRESS = _wethAddress;\n BEACON_CHAIN_DEPOSIT_CONTRACT = _beaconChainDepositContract;\n SSV_NETWORK_ADDRESS = _ssvNetwork;\n VAULT_ADDRESS = _vaultAddress;\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 emit RegistratorChanged(_address);\n validatorRegistrator = _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 emit StakingMonitorChanged(_address);\n stakingMonitor = _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 emit StakeETHThresholdChanged(_amount);\n stakeETHThreshold = _amount;\n }\n\n /// @notice Reset the stakeETHTally\n function resetStakeETHTally() external onlyStakingMonitor {\n emit StakeETHTallyReset();\n stakeETHTally = 0;\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 {\n uint256 requiredETH = validators.length * 32 ether;\n\n // Check there is enough WETH from the deposits sitting in this strategy contract\n require(\n requiredETH <= IWETH9(WETH_TOKEN_ADDRESS).balanceOf(address(this)),\n \"insufficient WETH\"\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_TOKEN_ADDRESS).withdraw(requiredETH);\n _wethWithdrawnAndStaked(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 withdrawal_credentials = abi.encodePacked(\n bytes1(0x01),\n bytes11(0),\n address(this)\n );\n\n uint256 validatorsLength = validators.length;\n // For each validator\n for (uint256 i = 0; i < validatorsLength; ) {\n bytes32 pubKeyHash = keccak256(validators[i].pubkey);\n VALIDATOR_STATE currentState = validatorsStates[pubKeyHash];\n\n require(\n currentState == VALIDATOR_STATE.REGISTERED,\n \"Validator not registered\"\n );\n\n IDepositContract(BEACON_CHAIN_DEPOSIT_CONTRACT).deposit{\n value: 32 ether\n }(\n validators[i].pubkey,\n withdrawal_credentials,\n validators[i].signature,\n validators[i].depositDataRoot\n );\n\n emit ETHStaked(\n pubKeyHash,\n validators[i].pubkey,\n 32 ether,\n withdrawal_credentials\n );\n\n validatorsStates[pubKeyHash] = VALIDATOR_STATE.STAKED;\n\n unchecked {\n ++i;\n }\n }\n // save gas by changing this storage variable only once rather each time in the loop.\n activeDepositedValidators += validatorsLength;\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 // slither-disable-start reentrancy-no-eth\n function registerSsvValidator(\n bytes calldata publicKey,\n uint64[] calldata operatorIds,\n bytes calldata sharesData,\n uint256 amount,\n Cluster calldata cluster\n ) external onlyRegistrator whenNotPaused {\n bytes32 pubKeyHash = keccak256(publicKey);\n require(\n validatorsStates[pubKeyHash] == VALIDATOR_STATE.NON_REGISTERED,\n \"Validator already registered\"\n );\n ISSVNetwork(SSV_NETWORK_ADDRESS).registerValidator(\n publicKey,\n operatorIds,\n sharesData,\n amount,\n cluster\n );\n emit SSVValidatorRegistered(pubKeyHash, publicKey, operatorIds);\n\n validatorsStates[pubKeyHash] = VALIDATOR_STATE.REGISTERED;\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 // 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_ADDRESS).exitValidator(publicKey, operatorIds);\n emit SSVValidatorExitInitiated(pubKeyHash, publicKey, operatorIds);\n\n validatorsStates[pubKeyHash] = VALIDATOR_STATE.EXITING;\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 // 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_ADDRESS).removeValidator(\n publicKey,\n operatorIds,\n cluster\n );\n emit SSVValidatorExitCompleted(pubKeyHash, publicKey, operatorIds);\n\n validatorsStates[pubKeyHash] = VALIDATOR_STATE.EXIT_COMPLETE;\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 cluster The SSV cluster details that must be derived from emitted events from the SSVNetwork contract.\n function depositSSV(\n uint64[] memory operatorIds,\n uint256 amount,\n Cluster memory cluster\n ) external onlyStrategist {\n ISSVNetwork(SSV_NETWORK_ADDRESS).deposit(\n address(this),\n operatorIds,\n amount,\n cluster\n );\n }\n\n /***************************************\n Abstract\n ****************************************/\n\n /// @dev allows for NativeStakingSSVStrategy contract know how much WETH had been staked\n function _wethWithdrawnAndStaked(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/swapper/Swapper1InchV5.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @notice 1Inch Pathfinder V5 implementation of the general ISwapper interface.\n * @author Origin Protocol Inc\n * @dev It is possible that dust token amounts are left in this contract after a swap.\n * This can happen with some tokens that don't send the full transfer amount.\n * These dust amounts can build up over time and be used by anyone who calls the `swap` function.\n */\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nimport { IAggregationExecutor, IOneInchRouter, SwapDescription } from \"../interfaces/IOneInch.sol\";\nimport { ISwapper } from \"../interfaces/ISwapper.sol\";\n\ncontract Swapper1InchV5 is ISwapper {\n using SafeERC20 for IERC20;\n\n /// @notice 1Inch router contract to give allowance to perform swaps\n address public constant SWAP_ROUTER =\n 0x1111111254EEB25477B68fb85Ed929f73A960582;\n\n // swap(address,(address,address,address,address,uint256,uint256,uint256),bytes,bytes)\n bytes4 internal constant SWAP_SELECTOR = 0x12aa3caf;\n // unoswapTo(address,address,uint256,uint256,uint256[])\n bytes4 internal constant UNISWAP_SELECTOR = 0xf78dc253;\n // uniswapV3SwapTo(address,uint256,uint256,uint256[])\n bytes4 internal constant UNISWAPV3_SELECTOR = 0xbc80f1a8;\n\n /**\n * @notice Strategist swaps assets sitting in the contract of the `assetHolder`.\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 RLP encoded executer address and bytes data. This is re-encoded tx.data from 1Inch swap API\n */\n function swap(\n address _fromAsset,\n address _toAsset,\n uint256 _fromAssetAmount,\n uint256 _minToAssetAmount,\n bytes calldata _data\n ) external override returns (uint256 toAssetAmount) {\n // Decode the function selector from the RLP encoded _data param\n bytes4 swapSelector = bytes4(_data[:4]);\n\n if (swapSelector == SWAP_SELECTOR) {\n // Decode the executer address and data from the RLP encoded _data param\n (, address executer, bytes memory executerData) = abi.decode(\n _data,\n (bytes4, address, bytes)\n );\n SwapDescription memory swapDesc = SwapDescription({\n srcToken: IERC20(_fromAsset),\n dstToken: IERC20(_toAsset),\n srcReceiver: payable(executer),\n dstReceiver: payable(msg.sender),\n amount: _fromAssetAmount,\n minReturnAmount: _minToAssetAmount,\n flags: 4 // 1st bit _PARTIAL_FILL, 2nd bit _REQUIRES_EXTRA_ETH, 3rd bit _SHOULD_CLAIM\n });\n (toAssetAmount, ) = IOneInchRouter(SWAP_ROUTER).swap(\n IAggregationExecutor(executer),\n swapDesc,\n hex\"\",\n executerData\n );\n } else if (swapSelector == UNISWAP_SELECTOR) {\n // Need to get the Uniswap pools data from the _data param\n (, uint256[] memory pools) = abi.decode(_data, (bytes4, uint256[]));\n toAssetAmount = IOneInchRouter(SWAP_ROUTER).unoswapTo(\n payable(msg.sender),\n IERC20(_fromAsset),\n _fromAssetAmount,\n _minToAssetAmount,\n pools\n );\n } else if (swapSelector == UNISWAPV3_SELECTOR) {\n // Need to get the Uniswap pools data from the _data param\n // slither-disable-next-line uninitialized-storage\n (, uint256[] memory pools) = abi.decode(_data, (bytes4, uint256[]));\n toAssetAmount = IOneInchRouter(SWAP_ROUTER).uniswapV3SwapTo(\n payable(msg.sender),\n _fromAssetAmount,\n _minToAssetAmount,\n pools\n );\n } else {\n revert(\"Unsupported swap function\");\n }\n }\n\n /**\n * @notice Approve assets for swapping.\n * @param _assets Array of token addresses to approve.\n * @dev unlimited approval is used as no tokens sit in this contract outside a transaction.\n */\n function approveAssets(address[] memory _assets) external {\n for (uint256 i = 0; i < _assets.length; ++i) {\n // Give the 1Inch router approval to transfer unlimited assets\n IERC20(_assets[i]).safeApprove(SWAP_ROUTER, type(uint256).max);\n }\n }\n}\n" + }, + "contracts/timelock/Timelock.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @title OUSD Timelock Contract\n * @author Origin Protocol Inc\n */\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\n\ninterface CapitalPausable {\n function pauseCapital() external;\n\n function unpauseCapital() external;\n}\n\ncontract Timelock {\n using SafeMath for uint256;\n\n event NewAdmin(address indexed newAdmin);\n event NewPendingAdmin(address indexed newPendingAdmin);\n event NewDelay(uint256 indexed newDelay);\n event CancelTransaction(\n bytes32 indexed txHash,\n address indexed target,\n string signature,\n bytes data,\n uint256 eta\n );\n event ExecuteTransaction(\n bytes32 indexed txHash,\n address indexed target,\n string signature,\n bytes data,\n uint256 eta\n );\n event QueueTransaction(\n bytes32 indexed txHash,\n address indexed target,\n string signature,\n bytes data,\n uint256 eta\n );\n\n uint256 public constant GRACE_PERIOD = 3 days;\n uint256 public constant MINIMUM_DELAY = 1 minutes;\n uint256 public constant MAXIMUM_DELAY = 2 days;\n\n address public admin;\n address public pendingAdmin;\n uint256 public delay;\n\n mapping(bytes32 => bool) public queuedTransactions;\n\n /**\n * @dev Throws if called by any account other than the Admin.\n */\n modifier onlyAdmin() {\n require(msg.sender == admin, \"Caller is not the admin\");\n _;\n }\n\n constructor(address admin_, uint256 delay_) {\n require(\n delay_ >= MINIMUM_DELAY,\n \"Timelock::constructor: Delay must exceed minimum delay.\"\n );\n require(\n delay_ <= MAXIMUM_DELAY,\n \"Timelock::setDelay: Delay must not exceed maximum delay.\"\n );\n\n admin = admin_;\n delay = delay_;\n }\n\n function setDelay(uint256 delay_) public {\n require(\n msg.sender == address(this),\n \"Timelock::setDelay: Call must come from Timelock.\"\n );\n require(\n delay_ >= MINIMUM_DELAY,\n \"Timelock::setDelay: Delay must exceed minimum delay.\"\n );\n require(\n delay_ <= MAXIMUM_DELAY,\n \"Timelock::setDelay: Delay must not exceed maximum delay.\"\n );\n delay = delay_;\n\n emit NewDelay(delay);\n }\n\n function acceptAdmin() public {\n require(\n msg.sender == pendingAdmin,\n \"Timelock::acceptAdmin: Call must come from pendingAdmin.\"\n );\n admin = msg.sender;\n pendingAdmin = address(0);\n\n emit NewAdmin(admin);\n }\n\n function setPendingAdmin(address pendingAdmin_) public onlyAdmin {\n pendingAdmin = pendingAdmin_;\n\n emit NewPendingAdmin(pendingAdmin);\n }\n\n function queueTransaction(\n address target,\n string memory signature,\n bytes memory data,\n uint256 eta\n ) internal returns (bytes32) {\n require(\n msg.sender == admin,\n \"Timelock::queueTransaction: Call must come from admin.\"\n );\n require(\n eta >= getBlockTimestamp().add(delay),\n \"Timelock::queueTransaction: Estimated execution block must satisfy delay.\"\n );\n\n bytes32 txHash = keccak256(\n abi.encode(target, signature, keccak256(data), eta)\n );\n queuedTransactions[txHash] = true;\n\n emit QueueTransaction(txHash, target, signature, data, eta);\n return txHash;\n }\n\n function cancelTransaction(\n address target,\n string memory signature,\n bytes memory data,\n uint256 eta\n ) internal {\n require(\n msg.sender == admin,\n \"Timelock::cancelTransaction: Call must come from admin.\"\n );\n\n bytes32 txHash = keccak256(\n abi.encode(target, signature, keccak256(data), eta)\n );\n queuedTransactions[txHash] = false;\n\n emit CancelTransaction(txHash, target, signature, data, eta);\n }\n\n function _getRevertMsg(bytes memory _returnData)\n internal\n pure\n returns (string memory)\n {\n // If the _res length is less than 68, then the transaction failed\n // silently (without a revert message)\n if (_returnData.length < 68) return \"Transaction reverted silently\";\n\n // solhint-disable-next-line no-inline-assembly\n assembly {\n // Slice the sighash.\n _returnData := add(_returnData, 0x04)\n }\n return abi.decode(_returnData, (string));\n }\n\n function executeTransaction(\n address target,\n string memory signature,\n bytes memory data,\n uint256 eta\n ) internal returns (bytes memory) {\n require(\n msg.sender == admin,\n \"Timelock::executeTransaction: Call must come from admin.\"\n );\n\n bytes32 txHash = keccak256(\n abi.encode(target, signature, keccak256(data), eta)\n );\n require(\n queuedTransactions[txHash],\n \"Timelock::executeTransaction: Transaction hasn't been queued.\"\n );\n require(\n getBlockTimestamp() >= eta,\n \"Timelock::executeTransaction: Transaction hasn't surpassed time lock.\"\n );\n require(\n getBlockTimestamp() <= eta.add(GRACE_PERIOD),\n \"Timelock::executeTransaction: Transaction is stale.\"\n );\n\n queuedTransactions[txHash] = false;\n\n bytes memory callData;\n\n if (bytes(signature).length == 0) {\n callData = data;\n } else {\n callData = abi.encodePacked(\n bytes4(keccak256(bytes(signature))),\n data\n );\n }\n\n (bool success, bytes memory returnData) = target.call(callData);\n\n if (!success) {\n revert(_getRevertMsg(returnData));\n }\n\n emit ExecuteTransaction(txHash, target, signature, data, eta);\n\n return returnData;\n }\n\n function getBlockTimestamp() internal view returns (uint256) {\n // solium-disable-next-line security/no-block-members\n return block.timestamp;\n }\n\n function pauseCapital(address target) external {\n require(\n msg.sender == admin,\n \"Timelock::pauseCapital: Call must come from admin.\"\n );\n CapitalPausable(target).pauseCapital();\n }\n\n function unpauseCapital(address target) external {\n require(\n msg.sender == admin,\n \"Timelock::unpauseCapital: Call must come from admin.\"\n );\n CapitalPausable(target).unpauseCapital();\n }\n}\n" + }, + "contracts/token/BridgedWOETH.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { ERC20 } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport { AccessControlEnumerable } from \"@openzeppelin/contracts/access/AccessControlEnumerable.sol\";\nimport { Governable } from \"../governance/Governable.sol\";\nimport { Initializable } from \"../utils/Initializable.sol\";\n\ncontract BridgedWOETH is\n Governable,\n AccessControlEnumerable,\n Initializable,\n ERC20\n{\n bytes32 public constant MINTER_ROLE = keccak256(\"MINTER_ROLE\");\n bytes32 public constant BURNER_ROLE = keccak256(\"BURNER_ROLE\");\n\n constructor() ERC20(\"Wrapped OETH\", \"WOETH\") {\n // Nobody owns the implementation\n _setGovernor(address(0));\n }\n\n /**\n * @dev Initialize the proxy and set the Governor\n */\n function initialize() external initializer {\n // Governor can grant Minter/Burner roles\n _setupRole(DEFAULT_ADMIN_ROLE, _governor());\n }\n\n /**\n * @dev Mint tokens for `account`\n * @param account Address to mint tokens for\n * @param amount Amount of tokens to mint\n */\n function mint(address account, uint256 amount)\n external\n onlyRole(MINTER_ROLE)\n nonReentrant\n {\n _mint(account, amount);\n }\n\n /**\n * @dev Burns tokens from `account`\n * @param account Address to burn tokens from\n * @param amount Amount of tokens to burn\n */\n function burn(address account, uint256 amount)\n external\n onlyRole(BURNER_ROLE)\n nonReentrant\n {\n _burn(account, amount);\n }\n\n /**\n * @dev Burns tokens from `msg.sender`\n * @param amount Amount of tokens to burn\n */\n function burn(uint256 amount) external onlyRole(BURNER_ROLE) nonReentrant {\n _burn(msg.sender, amount);\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual override returns (string memory) {\n return \"Wrapped OETH\";\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 \"WOETH\";\n }\n\n /**\n * @dev Returns the decimals of the token\n */\n function decimals() public view virtual override returns (uint8) {\n return 18;\n }\n}\n" + }, + "contracts/token/OETH.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { OUSD } from \"./OUSD.sol\";\n\n/**\n * @title OETH Token Contract\n * @author Origin Protocol Inc\n */\ncontract OETH is 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/token/OUSDResolutionUpgrade.sol": { + "content": "pragma solidity ^0.8.0;\n\ncontract OUSDResolutionUpgrade {\n enum RebaseOptions {\n NotSet,\n OptOut,\n OptIn\n }\n\n // From Initializable\n bool private initialized;\n bool private initializing;\n uint256[50] private ______igap;\n\n // From InitializableERC20Detailed\n uint256[100] private _____ugap;\n string private _name;\n string private _symbol;\n uint8 private _decimals;\n\n // From OUSD\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 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 /**\n * @return High resolution rebasingCreditsPerToken\n */\n function rebasingCreditsPerToken() public view returns (uint256) {\n return _rebasingCreditsPerToken / RESOLUTION_INCREASE;\n }\n\n /**\n * @return High 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 function upgradeGlobals() external {\n require(isUpgraded[address(0)] == 0, \"Globals already upgraded\");\n require(_rebasingCredits > 0, \"Sanity _rebasingCredits\");\n require(\n _rebasingCreditsPerToken > 0,\n \"Sanity _rebasingCreditsPerToken\"\n );\n isUpgraded[address(0)] = 1;\n _rebasingCredits = _rebasingCredits * RESOLUTION_INCREASE;\n _rebasingCreditsPerToken =\n _rebasingCreditsPerToken *\n RESOLUTION_INCREASE;\n }\n\n function upgradeAccounts(address[] calldata accounts) external {\n for (uint256 i = 0; i < accounts.length; i++) {\n address account = accounts[i];\n require(account != address(0), \"Reserved\");\n require(isUpgraded[account] == 0, \"Account already upgraded\");\n isUpgraded[account] = 1;\n\n // Handle special for non-rebasing accounts\n uint256 nrc = nonRebasingCreditsPerToken[account];\n if (nrc > 0) {\n require(nrc < 1e18, \"Account already highres\");\n nonRebasingCreditsPerToken[account] = nrc * RESOLUTION_INCREASE;\n }\n // Upgrade balance\n uint256 balance = _creditBalances[account];\n require(balance > 0, \"Will not upgrade zero balance\");\n _creditBalances[account] = balance * RESOLUTION_INCREASE;\n }\n }\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 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" + }, + "contracts/token/WOETH.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { ERC4626 } from \"../../lib/openzeppelin/contracts/token/ERC20/extensions/ERC4626.sol\";\nimport { ERC20 } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nimport { Governable } from \"../governance/Governable.sol\";\nimport { Initializable } from \"../utils/Initializable.sol\";\nimport { OETH } from \"./OETH.sol\";\n\n/**\n * @title OETH Token Contract\n * @author Origin Protocol Inc\n */\n\ncontract WOETH is ERC4626, Governable, Initializable {\n using SafeERC20 for IERC20;\n\n constructor(\n ERC20 underlying_,\n string memory name_,\n string memory symbol_\n ) ERC20(name_, symbol_) ERC4626(underlying_) Governable() {}\n\n /**\n * @notice Enable OETH rebasing for this contract\n */\n function initialize() external onlyGovernor initializer {\n OETH(address(asset())).rebaseOptIn();\n }\n\n function name() public view override returns (string memory) {\n return \"Wrapped OETH\";\n }\n\n function symbol() public view override returns (string memory) {\n return \"WOETH\";\n }\n\n /**\n * @notice Transfer token to governor. Intended for recovering tokens stuck in\n * contract, i.e. mistaken sends. Cannot transfer OETH\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(asset_ != address(asset()), \"Cannot collect OETH\");\n IERC20(asset_).safeTransfer(governor(), amount_);\n }\n}\n" + }, + "contracts/token/WrappedOusd.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { ERC4626 } from \"../../lib/openzeppelin/contracts/token/ERC20/extensions/ERC4626.sol\";\nimport { ERC20 } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nimport { Governable } from \"../governance/Governable.sol\";\nimport { Initializable } from \"../utils/Initializable.sol\";\nimport { OUSD } from \"./OUSD.sol\";\n\ncontract WrappedOusd is ERC4626, Governable, Initializable {\n using SafeERC20 for IERC20;\n\n constructor(\n ERC20 underlying_,\n string memory name_,\n string memory symbol_\n ) ERC20(name_, symbol_) ERC4626(underlying_) Governable() {}\n\n /**\n * @notice Enable OUSD rebasing for this contract\n */\n function initialize() external onlyGovernor initializer {\n OUSD(address(asset())).rebaseOptIn();\n }\n\n function name() public view override returns (string memory) {\n return \"Wrapped OUSD\";\n }\n\n function symbol() public view override returns (string memory) {\n return \"WOUSD\";\n }\n\n /**\n * @notice Transfer token to governor. Intended for recovering tokens stuck in\n * contract, i.e. mistaken sends. Cannot transfer OUSD\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(asset_ != address(asset()), \"Cannot collect OUSD\");\n IERC20(asset_).safeTransfer(governor(), amount_);\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/DepositContractUtils.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ncontract DepositContractUtils {\n function calculateDepositDataRoot(\n bytes calldata pubkey,\n bytes calldata withdrawal_credentials,\n bytes calldata signature\n ) public pure returns (bytes32 node) {\n uint256 deposit_amount = 32 ether / 1 gwei;\n bytes memory amount = to_little_endian_64(uint64(deposit_amount));\n\n // Compute deposit data root (`DepositData` hash tree root)\n bytes32 pubkey_root = sha256(abi.encodePacked(pubkey, bytes16(0)));\n bytes32 signature_root = sha256(\n abi.encodePacked(\n sha256(abi.encodePacked(signature[:64])),\n sha256(abi.encodePacked(signature[64:], bytes32(0)))\n )\n );\n node = sha256(\n abi.encodePacked(\n sha256(abi.encodePacked(pubkey_root, withdrawal_credentials)),\n sha256(abi.encodePacked(amount, bytes24(0), signature_root))\n )\n );\n }\n\n function to_little_endian_64(uint64 value)\n internal\n pure\n returns (bytes memory ret)\n {\n ret = new bytes(8);\n bytes8 bytesValue = bytes8(value);\n // Byteswapping during copying to bytes.\n ret[0] = bytesValue[7];\n ret[1] = bytesValue[6];\n ret[2] = bytesValue[5];\n ret[3] = bytesValue[4];\n ret[4] = bytesValue[3];\n ret[5] = bytesValue[2];\n ret[6] = bytesValue[1];\n ret[7] = bytesValue[0];\n }\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 { VaultAdmin } from \"./VaultAdmin.sol\";\n\n/**\n * @title OETH VaultAdmin Contract\n * @author Origin Protocol Inc\n */\ncontract OETHVaultAdmin is VaultAdmin {\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\";\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" + }, + "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 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 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 {\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" + }, + "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" + }, + "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\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" + }, + "contracts/zapper/WOETHCCIPZapper.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { IRouterClient } from \"@chainlink/contracts-ccip/src/v0.8/ccip/interfaces/IRouterClient.sol\";\nimport { Client } from \"@chainlink/contracts-ccip/src/v0.8/ccip/libraries/Client.sol\";\n// solhint-disable-next-line max-line-length\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { IERC4626 } from \"./../../lib/openzeppelin/interfaces/IERC4626.sol\";\nimport { IOETHZapper } from \"./../interfaces/IOETHZapper.sol\";\n\n/**\n * @title WOETH CCIP Zapper Contract\n * @notice Helps to directly convert ETH on mainnet into WOETH on L2s.\n * @author Origin Protocol Inc\n */\n\ncontract WOETHCCIPZapper {\n /**\n * @dev Event emitted when a zap occurs\n * @param messageId Unique message identifier for each zap\n * @param sender Address initiating the zap\n * @param recipient Recipient address at destination chain\n * @param amount Amount of ETH zapped\n */\n event Zap(\n bytes32 indexed messageId,\n address sender,\n address recipient,\n uint256 amount\n );\n\n // @dev Thrown when Zap amount is less than fee.\n error AmountLessThanFee();\n\n /**\n * @dev The destination chain selector\n */\n uint64 public immutable destinationChainSelector;\n\n /**\n * @dev The WOETH source chain (Mainnet)\n */\n IERC4626 public immutable woethOnSourceChain;\n\n /**\n * @dev The WOETH destination chain (Arbitrum)\n */\n IERC20 public immutable woethOnDestinationChain;\n\n /**\n * @dev The OETH zapper contract address\n */\n IOETHZapper public immutable oethZapper;\n\n /**\n * @dev The CCIP router contract address\n */\n IRouterClient public immutable ccipRouter;\n\n /**\n * @dev The OETH token contract address\n */\n IERC20 public immutable oeth;\n\n constructor(\n address _ccipRouter,\n uint64 _destinationChainSelector,\n IERC4626 _woethOnSourceChain,\n IERC20 _woethOnDestinationChain,\n IOETHZapper _oethZapper,\n IERC20 _oeth\n ) {\n ccipRouter = IRouterClient(_ccipRouter);\n destinationChainSelector = _destinationChainSelector;\n woethOnSourceChain = _woethOnSourceChain;\n woethOnDestinationChain = _woethOnDestinationChain;\n oethZapper = _oethZapper;\n oeth = _oeth;\n\n // Max allowance for Router and WOETH contracts\n _oeth.approve(address(_woethOnSourceChain), type(uint256).max); // for wrapping\n _woethOnSourceChain.approve(address(_ccipRouter), type(uint256).max); // for zapping\n }\n\n /**\n * @notice Accepts ETH, zaps for OETH, wraps it for WOETH and sends it to the destination chain (arbitrum)\n * @param receiver The address of the EOA on the destination chain\n * @return messageId The ID of the message that was sent\n */\n function zap(address receiver)\n external\n payable\n returns (bytes32 messageId)\n {\n return _zap(receiver, msg.value);\n }\n\n /**\n * @notice Used to estimate fee for CCIP transaction\n * @param amount The amount of ETH to be zapped\n * @param receiver The address of the EOA on the destination chain\n * @return feeAmount The CCIP tx fee in ETH.\n */\n\n function getFee(uint256 amount, address receiver)\n public\n view\n returns (uint256 feeAmount)\n {\n Client.EVMTokenAmount[]\n memory tokenAmounts = new Client.EVMTokenAmount[](1);\n Client.EVMTokenAmount memory tokenAmount = Client.EVMTokenAmount({\n token: address(woethOnSourceChain),\n amount: amount\n });\n tokenAmounts[0] = tokenAmount;\n\n Client.EVM2AnyMessage memory message = Client.EVM2AnyMessage({\n receiver: abi.encode(receiver), // ABI-encoded receiver address\n data: abi.encode(\"\"),\n tokenAmounts: tokenAmounts,\n extraArgs: Client._argsToBytes(\n Client.EVMExtraArgsV1({ gasLimit: 0 })\n ),\n feeToken: address(0)\n });\n\n feeAmount = ccipRouter.getFee(destinationChainSelector, message);\n }\n\n /**\n * @dev Deposit ETH and receive WOETH in L2.\n * @dev Note that the WOETH will be sent to the msg.sender at destination chain as well.\n */\n receive() external payable {\n _zap(msg.sender, msg.value);\n }\n\n function _zap(address receiver, uint256 amount)\n internal\n returns (bytes32 messageId)\n {\n // Estimate fee for zapping.\n uint256 feeAmount = getFee(amount, receiver);\n if (amount < feeAmount) {\n revert AmountLessThanFee();\n }\n\n // Convert only the msg.value - fees amount to WOETH.\n amount -= feeAmount;\n\n // 1.) Zap for OETH\n uint256 oethReceived = oethZapper.deposit{ value: amount }();\n\n // 2.) Wrap the received woeth\n uint256 woethReceived = woethOnSourceChain.deposit(\n oethReceived,\n address(this)\n );\n\n // 3.) Setup params for CCIP transfer\n\n Client.EVMTokenAmount[]\n memory tokenAmounts = new Client.EVMTokenAmount[](1);\n Client.EVMTokenAmount memory tokenAmount = Client.EVMTokenAmount({\n token: address(woethOnSourceChain),\n amount: woethReceived\n });\n tokenAmounts[0] = tokenAmount;\n\n Client.EVM2AnyMessage memory message = Client.EVM2AnyMessage({\n receiver: abi.encode(receiver), // ABI-encoded receiver address\n data: abi.encode(\"\"),\n tokenAmounts: tokenAmounts,\n extraArgs: Client._argsToBytes(\n // See: https://docs.chain.link/ccip/best-practices#setting-gaslimit\n Client.EVMExtraArgsV1({ gasLimit: 0 })\n ),\n feeToken: address(0)\n });\n\n // ZAP ϟ\n //slither-disable-next-line arbitrary-send-eth\n messageId = ccipRouter.ccipSend{ value: feeAmount }(\n destinationChainSelector,\n message\n );\n\n // Emit Zap event with message details\n emit Zap(messageId, msg.sender, receiver, amount);\n\n // Return the message ID\n return messageId;\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/contracts/token/ERC20/extensions/ERC4626.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\nimport { IERC4626 } from \"../../../../interfaces/IERC4626.sol\";\nimport { ERC20 } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { IERC20Metadata } from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\n\n// From Open Zeppelin draft PR commit:\n// fac43034dca85ff539db3fc8aa2a7084b843d454\n// https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3171\n\nabstract contract ERC4626 is ERC20, IERC4626 {\n IERC20Metadata private immutable _asset;\n\n constructor(IERC20Metadata __asset) {\n _asset = __asset;\n }\n\n /** @dev See {IERC4262-asset} */\n function asset() public view virtual override returns (address) {\n return address(_asset);\n }\n\n /** @dev See {IERC4262-totalAssets} */\n function totalAssets() public view virtual override returns (uint256) {\n return _asset.balanceOf(address(this));\n }\n\n /**\n * @dev See {IERC4262-convertToShares}\n *\n * Will revert if asserts > 0, totalSupply > 0 and totalAssets = 0. That corresponds to a case where any asset\n * would represent an infinite amout of shares.\n */\n function convertToShares(uint256 assets) public view virtual override returns (uint256 shares) {\n uint256 supply = totalSupply();\n\n return\n (assets == 0 || supply == 0)\n ? (assets * 10**decimals()) / 10**_asset.decimals()\n : (assets * supply) / totalAssets();\n }\n\n /** @dev See {IERC4262-convertToAssets} */\n function convertToAssets(uint256 shares) public view virtual override returns (uint256 assets) {\n uint256 supply = totalSupply();\n\n return (supply == 0) ? (shares * 10**_asset.decimals()) / 10**decimals() : (shares * totalAssets()) / supply;\n }\n\n /** @dev See {IERC4262-maxDeposit} */\n function maxDeposit(address) public view virtual override returns (uint256) {\n return type(uint256).max;\n }\n\n /** @dev See {IERC4262-maxMint} */\n function maxMint(address) public view virtual override returns (uint256) {\n return type(uint256).max;\n }\n\n /** @dev See {IERC4262-maxWithdraw} */\n function maxWithdraw(address owner) public view virtual override returns (uint256) {\n return convertToAssets(balanceOf(owner));\n }\n\n /** @dev See {IERC4262-maxRedeem} */\n function maxRedeem(address owner) public view virtual override returns (uint256) {\n return balanceOf(owner);\n }\n\n /** @dev See {IERC4262-previewDeposit} */\n function previewDeposit(uint256 assets) public view virtual override returns (uint256) {\n return convertToShares(assets);\n }\n\n /** @dev See {IERC4262-previewMint} */\n function previewMint(uint256 shares) public view virtual override returns (uint256) {\n uint256 assets = convertToAssets(shares);\n return assets + (convertToShares(assets) < shares ? 1 : 0);\n }\n\n /** @dev See {IERC4262-previewWithdraw} */\n function previewWithdraw(uint256 assets) public view virtual override returns (uint256) {\n uint256 shares = convertToShares(assets);\n return shares + (convertToAssets(shares) < assets ? 1 : 0);\n }\n\n /** @dev See {IERC4262-previewRedeem} */\n function previewRedeem(uint256 shares) public view virtual override returns (uint256) {\n return convertToAssets(shares);\n }\n\n /** @dev See {IERC4262-deposit} */\n function deposit(uint256 assets, address receiver) public virtual override returns (uint256) {\n require(assets <= maxDeposit(receiver), \"ERC4626: deposit more then max\");\n\n address caller = _msgSender();\n uint256 shares = previewDeposit(assets);\n\n // if _asset is ERC777, transferFrom can call reenter BEFORE the transfer happens through\n // the tokensToSend hook, so we need to transfer before we mint to keep the invariants.\n SafeERC20.safeTransferFrom(_asset, caller, address(this), assets);\n _mint(receiver, shares);\n\n emit Deposit(caller, receiver, assets, shares);\n\n return shares;\n }\n\n /** @dev See {IERC4262-mint} */\n function mint(uint256 shares, address receiver) public virtual override returns (uint256) {\n require(shares <= maxMint(receiver), \"ERC4626: mint more then max\");\n\n address caller = _msgSender();\n uint256 assets = previewMint(shares);\n\n // if _asset is ERC777, transferFrom can call reenter BEFORE the transfer happens through\n // the tokensToSend hook, so we need to transfer before we mint to keep the invariants.\n SafeERC20.safeTransferFrom(_asset, caller, address(this), assets);\n _mint(receiver, shares);\n\n emit Deposit(caller, receiver, assets, shares);\n\n return assets;\n }\n\n /** @dev See {IERC4262-withdraw} */\n function withdraw(\n uint256 assets,\n address receiver,\n address owner\n ) public virtual override returns (uint256) {\n require(assets <= maxWithdraw(owner), \"ERC4626: withdraw more then max\");\n\n address caller = _msgSender();\n uint256 shares = previewWithdraw(assets);\n\n if (caller != owner) {\n _spendAllowance(owner, caller, shares);\n }\n\n // if _asset is ERC777, transfer can call reenter AFTER the transfer happens through\n // the tokensReceived hook, so we need to transfer after we burn to keep the invariants.\n _burn(owner, shares);\n SafeERC20.safeTransfer(_asset, receiver, assets);\n\n emit Withdraw(caller, receiver, owner, assets, shares);\n\n return shares;\n }\n\n /** @dev See {IERC4262-redeem} */\n function redeem(\n uint256 shares,\n address receiver,\n address owner\n ) public virtual override returns (uint256) {\n require(shares <= maxRedeem(owner), \"ERC4626: redeem more then max\");\n\n address caller = _msgSender();\n uint256 assets = previewRedeem(shares);\n\n if (caller != owner) {\n _spendAllowance(owner, caller, shares);\n }\n\n // if _asset is ERC777, transfer can call reenter AFTER the transfer happens through\n // the tokensReceived hook, so we need to transfer after we burn to keep the invariants.\n _burn(owner, shares);\n SafeERC20.safeTransfer(_asset, receiver, assets);\n\n emit Withdraw(caller, receiver, owner, assets, shares);\n\n return assets;\n }\n\n // Included here, since this method was not yet present in\n // the version of Open Zeppelin ERC20 code we use.\n function _spendAllowance(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n uint256 currentAllowance = allowance(owner, spender);\n if (currentAllowance != type(uint256).max) {\n require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n unchecked {\n _approve(owner, spender, currentAllowance - amount);\n }\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 From d398042a8b8e01a388b8a2db9b0c8d7d91b8c13e Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Sun, 2 Jun 2024 16:44:48 +1000 Subject: [PATCH 118/273] generated latest NativeStakingSSVStrategy docs --- contracts/docs/NativeStakingSSVStrategySquashed.svg | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/contracts/docs/NativeStakingSSVStrategySquashed.svg b/contracts/docs/NativeStakingSSVStrategySquashed.svg index 1efe2f1314..a210ef9d8b 100644 --- a/contracts/docs/NativeStakingSSVStrategySquashed.svg +++ b/contracts/docs/NativeStakingSSVStrategySquashed.svg @@ -119,10 +119,10 @@    <<event>> Unpaused(account: address) <<Pausable>>    <<event>> RegistratorChanged(newAddress: address) <<ValidatorRegistrator>>    <<event>> StakingMonitorChanged(newAddress: address) <<ValidatorRegistrator>> -    <<event>> ETHStaked(pubkey: bytes, amount: uint256, withdrawal_credentials: bytes) <<ValidatorRegistrator>> -    <<event>> SSVValidatorRegistered(pubkey: bytes, operatorIds: uint64[]) <<ValidatorRegistrator>> -    <<event>> SSVValidatorExitInitiated(pubkey: bytes, operatorIds: uint64[]) <<ValidatorRegistrator>> -    <<event>> SSVValidatorExitCompleted(pubkey: bytes, operatorIds: uint64[]) <<ValidatorRegistrator>> +    <<event>> ETHStaked(pubKeyHash: bytes32, pubKey: bytes, amount: uint256, withdrawal_credentials: bytes) <<ValidatorRegistrator>> +    <<event>> SSVValidatorRegistered(pubKeyHash: bytes32, pubKey: bytes, operatorIds: uint64[]) <<ValidatorRegistrator>> +    <<event>> SSVValidatorExitInitiated(pubKeyHash: bytes32, pubKey: bytes, operatorIds: uint64[]) <<ValidatorRegistrator>> +    <<event>> SSVValidatorExitCompleted(pubKeyHash: bytes32, pubKey: bytes, operatorIds: uint64[]) <<ValidatorRegistrator>>    <<event>> StakeETHThresholdChanged(amount: uint256) <<ValidatorRegistrator>>    <<event>> StakeETHTallyReset() <<ValidatorRegistrator>>    <<event>> FuseIntervalUpdated(start: uint256, end: uint256) <<ValidatorAccountant>> From b6c221930f2c8509d6048783ff573ec454280d1c Mon Sep 17 00:00:00 2001 From: Nick Addison Date: Sun, 2 Jun 2024 20:07:43 +1000 Subject: [PATCH 119/273] P2P API changes (#2084) * Updated Natspec * Updated native staking process diagrams * Fixed signer for Holesky * split operateValidators into registerValidators and stakeValidators * Fix vault mint HH task. It now waits for the approve tx to be mined * resolveAsset to handle local Holesky fork * upgrade signer to use new defender-relay-client package * added approve option to vault mint HH task * Added stakeValidators HH task * update git ignore file * Added depositWETH and withdrawWETH HH tasks * Added resetStakeETHTally and setStakeETHThreshold HH tasks * generated latest Native Staking Strategy docs --- .gitignore | 4 +- .../NativeStaking/ValidatorRegistrator.sol | 22 +- .../docs/NativeStakingSSVStrategySquashed.svg | 4 +- .../docs/plantuml/oethProcesses-register.png | Bin 167449 -> 159704 bytes contracts/docs/plantuml/oethProcesses.png | Bin 454951 -> 454018 bytes contracts/docs/plantuml/oethProcesses.puml | 17 +- ...ateValidators.js => registerValidators.js} | 4 +- .../defender-actions/rollup.config.cjs | 20 +- contracts/tasks/tasks.js | 204 +++---- contracts/tasks/validator.js | 508 +++++++++++++----- contracts/tasks/vault.js | 9 +- contracts/tasks/weth.js | 23 + contracts/utils/resolvers.js | 9 +- contracts/utils/signers.js | 39 +- 14 files changed, 600 insertions(+), 263 deletions(-) rename contracts/scripts/defender-actions/{operateValidators.js => registerValidators.js} (96%) create mode 100644 contracts/tasks/weth.js diff --git a/.gitignore b/.gitignore index e2ac4a3fba..7d28879380 100644 --- a/.gitignore +++ b/.gitignore @@ -60,8 +60,8 @@ contracts/coverage.json contracts/build/ contracts/dist/ contracts/.localKeyValueStorage -contracts/.localKeyValueStorageMainnet -contracts/.localKeyValueStorageHolesky +contracts/.localKeyValueStorage.mainnet +contracts/.localKeyValueStorage.holesky contracts/scripts/defender-actions/dist/ todo.txt diff --git a/contracts/contracts/strategies/NativeStaking/ValidatorRegistrator.sol b/contracts/contracts/strategies/NativeStaking/ValidatorRegistrator.sol index 9b6455e012..2dc590f69f 100644 --- a/contracts/contracts/strategies/NativeStaking/ValidatorRegistrator.sol +++ b/contracts/contracts/strategies/NativeStaking/ValidatorRegistrator.sol @@ -226,12 +226,17 @@ abstract contract ValidatorRegistrator is Governable, Pausable { /// @notice Registers a new validator in the SSV Cluster. /// Only the registrator can call this function. + /// @param publicKey The public key of the validator + /// @param operatorIds The operator IDs of the SSV Cluster + /// @param sharesData The validator shares data + /// @param ssvAmount The amount of SSV tokens to be deposited to the SSV cluster + /// @param cluster The SSV cluster details including the validator count and SSV balance // slither-disable-start reentrancy-no-eth function registerSsvValidator( bytes calldata publicKey, uint64[] calldata operatorIds, bytes calldata sharesData, - uint256 amount, + uint256 ssvAmount, Cluster calldata cluster ) external onlyRegistrator whenNotPaused { bytes32 pubKeyHash = keccak256(publicKey); @@ -243,7 +248,7 @@ abstract contract ValidatorRegistrator is Governable, Pausable { publicKey, operatorIds, sharesData, - amount, + ssvAmount, cluster ); emit SSVValidatorRegistered(pubKeyHash, publicKey, operatorIds); @@ -256,6 +261,8 @@ abstract contract ValidatorRegistrator is Governable, Pausable { /// @notice Exit a validator from the Beacon chain. /// The staked ETH will eventually swept to this native staking strategy. /// Only the registrator can call this function. + /// @param publicKey The public key of the validator + /// @param operatorIds The operator IDs of the SSV Cluster // slither-disable-start reentrancy-no-eth function exitSsvValidator( bytes calldata publicKey, @@ -277,6 +284,9 @@ abstract contract ValidatorRegistrator is Governable, Pausable { /// Make sure `exitSsvValidator` is called before and the validate has exited the Beacon chain. /// If removed before the validator has exited the beacon chain will result in the validator being slashed. /// Only the registrator can call this function. + /// @param publicKey The public key of the validator + /// @param operatorIds The operator IDs of the SSV Cluster + /// @param cluster The SSV cluster details including the validator count and SSV balance // slither-disable-start reentrancy-no-eth function removeSsvValidator( bytes calldata publicKey, @@ -306,16 +316,18 @@ abstract contract ValidatorRegistrator is Governable, Pausable { /// @dev A SSV cluster is defined by the SSVOwnerAddress and the set of operatorIds. /// uses "onlyStrategist" modifier so continuous front-running can't DOS our maintenance service /// that tries to top up SSV tokens. - /// @param cluster The SSV cluster details that must be derived from emitted events from the SSVNetwork contract. + /// @param operatorIds The operator IDs of the SSV Cluster + /// @param ssvAmount The amount of SSV tokens to be deposited to the SSV cluster + /// @param cluster The SSV cluster details including the validator count and SSV balance function depositSSV( uint64[] memory operatorIds, - uint256 amount, + uint256 ssvAmount, Cluster memory cluster ) external onlyStrategist { ISSVNetwork(SSV_NETWORK_ADDRESS).deposit( address(this), operatorIds, - amount, + ssvAmount, cluster ); } diff --git a/contracts/docs/NativeStakingSSVStrategySquashed.svg b/contracts/docs/NativeStakingSSVStrategySquashed.svg index a210ef9d8b..2c31395017 100644 --- a/contracts/docs/NativeStakingSSVStrategySquashed.svg +++ b/contracts/docs/NativeStakingSSVStrategySquashed.svg @@ -91,10 +91,10 @@    setStakeETHThreshold(_amount: uint256) <<onlyGovernor>> <<ValidatorRegistrator>>    resetStakeETHTally() <<onlyStakingMonitor>> <<ValidatorRegistrator>>    stakeEth(validators: ValidatorStakeData[]) <<onlyRegistrator, whenNotPaused>> <<ValidatorRegistrator>> -    registerSsvValidator(publicKey: bytes, operatorIds: uint64[], sharesData: bytes, amount: uint256, cluster: Cluster) <<onlyRegistrator, whenNotPaused>> <<ValidatorRegistrator>> +    registerSsvValidator(publicKey: bytes, operatorIds: uint64[], sharesData: bytes, ssvAmount: uint256, cluster: Cluster) <<onlyRegistrator, whenNotPaused>> <<ValidatorRegistrator>>    exitSsvValidator(publicKey: bytes, operatorIds: uint64[]) <<onlyRegistrator, whenNotPaused>> <<ValidatorRegistrator>>    removeSsvValidator(publicKey: bytes, operatorIds: uint64[], cluster: Cluster) <<onlyRegistrator, whenNotPaused>> <<ValidatorRegistrator>> -    depositSSV(operatorIds: uint64[], amount: uint256, cluster: Cluster) <<onlyStrategist>> <<ValidatorRegistrator>> +    depositSSV(operatorIds: uint64[], ssvAmount: uint256, cluster: Cluster) <<onlyStrategist>> <<ValidatorRegistrator>>    setFuseInterval(_fuseIntervalStart: uint256, _fuseIntervalEnd: uint256) <<onlyGovernor>> <<ValidatorAccountant>>    doAccounting(): (accountingValid: bool) <<onlyRegistrator, whenNotPaused>> <<ValidatorAccountant>>    manuallyFixAccounting(_validatorsDelta: int256, _consensusRewardsDelta: int256, _ethToVaultAmount: uint256) <<onlyStrategist, whenPaused>> <<ValidatorAccountant>> diff --git a/contracts/docs/plantuml/oethProcesses-register.png b/contracts/docs/plantuml/oethProcesses-register.png index a1f1021dba4a1a0113fd4b47e6006a50de698850..03ac1f8f611aa6d81472e8bbd0595b751906c2c9 100644 GIT binary patch literal 159704 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 z z^o6{dcqez7yU`iKsQZP9^Cao0@_;~h#Y;Blk3D098NtOSfjJU()s}~+E~hT8zMpRx^V zb+>_Dra!G6;r{i@j@n)3zGMfS1*8yo1hk^9tNrC~$!dfT&&^$^P`RsROq^$4n7+F^zq2rW? zr^Z6coV-u0HYGlU*l=O8oevH2-~azCBZ=ss{%Ph!Um)}M_Lr(%EO3C|%)>yA^{#(1 zC?m?=8RYa=RV)~W1(WAt-K4F^cUDH9P2;cw@i6EZFkNhb9VMF+@Gt#Q)Xx5GcDY#U zmXw^_a@7Z+1kl5g$Maxl{l>UH`S``z_de3TVJ!=>T?K3DI!)G@28rSbXy0iMp z{P^*m8hj+u*}0{zTDvYBUVFE-)pLMGJ$1z1+WNt}@0!vN!?2>btLs4l;OUYMDVp{L zms|YN8#is*kbNwKeOomf#k|362ZkRwpPY^Z=P+}{_B2K&CJ>TO3W4+q+l0c47q_MR z@7*hQe`RlPFL*XcfzmZUFByxtcx?5|x^&6<0!&qrgM+6gzfb%|oi4N31P*17A77lr znu<%@`4>(b)L}11XJ=wiM|-<^^%b}a56f{TnnhxBF6!sFFrLRvOINHYWyLgJ?Z*qB zH8hZ>6!C-GVT}2)Qgr?L%%URwLFN2l*aM$u27%{qO^eYYO4Nd*%J%Tld;9=0M94N+ zn2`NhxIxg)Q}^*HMKy#+N4pjqieHd|AbQ=+0>??%P~HIZ z7^`^rmoz=RC;X_Z>xR=^=D`^l_+5&L+5~#6#-VK!U0q$!gTM#x$Pr>KnqED7^5vV4 z1>Hvg)xU&6%E5)3oSF<9gmo5PtO(l*%iJ&+QmO`SZr$aP-oZ3Rjf-Qv%rIw*ML$`z zCt*BaM8~mmV)Cg_j2c|fL`6>$ZE3<~eRXxlLIMA0Ng`_BCIW|lv9f9^t*AbsxA(pC zlJ#81u&LLyfJo$4>e$LL9`oeO2`L{H|Iq#%YQZSc0 zWG7Z0=^z-GgU-#jc@h2ok|NmU9ZE5rt1A= z*8Ss4-?AL3a%{KXClW?!1ZGJLFM&vmsPSG<*~q_?4NF0~k%-|2v}>1sKfESkYy-^( zCSZJ)d=*^#o}(d2P?rjZKsKW-L+OZAq0H_^c0`Nidu=S=gYNlyqss%%$>|IQ&sE|& z1_n8;Wo2^57lHc>(h;*F=r%+J+gVal^5I)1D;YG+lOF`#of(gXs!EE8Wb$yohxgL8 zSXbwf?DE@KUvog@jozKvZOH)Jh})ZgC;GyL3wbg2=H`7LKkB@y)|7y2!jOCd3_GzU z`>?mS|3rT>cv*%=*FUX*rebAiDhy=-w3?fnAF$d@qtRGaca3op_cfGodoJ*NRdXRr z0`xVp$DN&L&YpeR-j46by-z&#)os7h++5+#4I*!)gqj95J>nW<(6O|YHNhq_Kt{_W z9gKTiG5ogw{-Pi2qRl&>Jp*@4Z_2F?n0q8g@}vm>RQaXif~Q2VH#62a+h@Z0aihqS zM~~Jk#-XYv0Et=AXajZR4qnVx{c3wNUdPKo#5 zU0?9_VyS0augGIIqr$oOJdad|_e|${mSsU%OYHcBiz~=D51X5h?_k+xd^MbB+4l}E z=-TKhi~dLdjy%=Ol(Xwp#Kumpu<1v+Fx$it`7MiEMu11hrX;Ylz(T^5DnZ1%)8
    r`{2%`4}>o^l={ScffcNez#aY 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

    ;hVa?MkrX$ansq$8N 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�rZpZ@xuuQwu!5Vh%SNEdM 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 literal 167449 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 z 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 V%Y_8*Ipojfq?9C+FJ5*1zX0rvt>yp# diff --git a/contracts/docs/plantuml/oethProcesses.png b/contracts/docs/plantuml/oethProcesses.png index 18f51ef248cba6bf42372ff7eb43409f5c172b50..4bb4928a1503dc7736b9cab2abb9116971fdaff6 100644 GIT binary patch literal 454018 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

    ?0{mlKsFS43qcNhM~#U7n_+Y8CsY6 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
    #$ zggfLYT%bB%Qs^Azgwi&jM^CAQzRuTI%GnHKEku5rEE5Q(o58+Ce?%}*>-xi@pu!=f zBzeSdLqH_T(91W)Md+wS>xu{0)|SqefvPVtxvhD!IiFyTcwN0(MYW#E1NofMz9qnP z=MTTOTHbzG>Bt>v*nM#Dk^v9pM16QIj0xFhM1!*yTACuyfV7LR_jvYAw32?hpEg>RwKNwH+ zzX(NnEcW0k8CJj3fD3)#dngtv@^yweD=V9!V#@)$PaJ46jH5RqxZDBwHl1Sarv>KNDBueI_OUAAt}# zEgfAkaJqnon{*fQRP)-~&@6rWlnT+?YI#{F6~(^x1qi_dmqZ;`&hDbx^lQ91r>@#k z$mTMy?elUj3#M6`m^`-7idD|Ac%wvU@o@0HO5&-p$ZL0;--T7V?kevRALEbPL+_73=aEXg@# za6tUH7puNWP6VC07opgeqhI6LbClv8!Z2jLCyotgqCxP4r)%OG(h*lv;Xl39rb zr_TH2Xm@VziQ$s*Ozkp|X06ElY>KYB29hU`oP_&S8A1jHq!@QGr z>9*rTt4r@Ij!P7)_V!XqqCOQCn)U@^*bDn*2!8$`I-t+mI+CPySEU2h3F$kswYB^d z?7}FoUbQ{c8)kiGU?P~~RkB{cZlo?$0@@|`?xI%UAIhL0;MBFboABv?ZwqLwn zHd>bV-uteK-|}2fGQEzJ`M6764{K3F0I4rX>M=5QOtZ1mO*cMvw+$q}pmTT`b$N~` z{qfBry(^ISRz}6hTv53Qq;FHx@FG*@?Uh4%l-=4i;|wt(izunj`1lDFwS#YIyMnH| zO%$73jTn@+w2zI2<-F~eHLP|Bc?z*{8qP`0=}d^;s6#D1z2?uKwH%)I0?nv27vZ)i z?B6;*Qhc(F>e2oJ-i#13AGMj)e7DWpJ1+kn;RfzX%+|xj`){a6>{J$rtqw57hlUmu zvCxA23T%2{TUS?9_`1@b$I2F9iLU_zEU3AlU@IyvUH}9Ms797S3Y@QccISIgk-rx0PG2wl!z!rr;V& zPk9n|47zn^vaQwCYL8OHJlWSXD>f(5{r~r!2UQ%cKXItc>{P5VAm^^3+8tkpn z!>3QwdGIx7n@Y4!(zK2zEjhV&xMXnHQ|D_}NhEuVBjjcrZ+lo(_>#WtuB1D>-m4-N z|MTFr%F~8#@fgO%X_=|iRy(TC)1AhCnTCs+&I0O&`eBVd`#TbZIj_k9_Uh(E<5lpb z!H}Tg#BaSwL(a>vhQh;NKkpR2LO=Y4D9Rj8zJ9>my)E^-P#|_{TqX&ZuZQ$A3%Tg_ zB}Y4eTvYW#M=sBur_exxo}rr5^4Rb@N(PoSF_80D3rl1O|H8_qMfOQ|>H>?#e2^TN zOxAabj*A?bo(ZNcQy*uPvPsGZ_;01s3Ehk`qp84E*K};ai)p3XJAirG7Dmz9qEJbXZDx`xy&+Mgi_heANio5h02YV?v`5 zis!4mN2HHn8$|3`N{}3ur38buFVQw-sQcHUp&{Vt(%*Q7bEx}rUPHcDjx{~8aE#Ys zi6K8+UG?|q-X>99-H$5!brU72xbY-+?8CN{av%FraX{UOz1X&P7UA24rvmLYy%MHeC?5Jx57#)o;q7G&!?s+O zj7lip?&Q=V=CJiWEl{qd6nDS(UN1JJiv2>GRK2Xv+$=tl_TDGPHy@0^#ce&H^mu*Y z%GZh_%gQnugbVqbw*SLf`EP3k<0V>Jj?!_3Zx1Djr z>1i{?elEs3_mOx9XH`Xd^RY#M5sx+x2R$XN`93y5qd)*i?VN?EhNRq5S5*nN)JpT8z)$`U;vvE`m0FOXPjH5iHr z|Iw_XQ|FpjIDg^%efh)Z3#DJa4ju27IQsWO7m;$PvA)`@J<6cJY6yEu)EDQg&wTD{ z_Z{x~)WQ5bx#TD*Bwi_rj$PY|=Cl^kPZ1oPyyW`NjR%r$_g2#F$cRwbgAd6SMMXVU z%Xj=pwc_U^imu$a)UtA9p&mfKGCQl3Esm6bGKxKut9PBa*pHyKJtw4ek(mU=dv7#- zraACRw`9f#DaGkmkH2=5*-VHVx!z2cx%5jRI{%CAg9k#8bk3u7y?pQaWo2E-voaN?>zJHm0vH=RC%q{Q9rlaS-PBFb;W;X7l?Z(hh`JR4Acr|q*s{g8}vcd@|n)o5y?5uY6$g3++e?7*wJ6NFA2oOhLE5B{D%JZ=OOBw(tz zdpC;x3S{m1M)e{jTp%OK)%1s4pu8N6zdVd)7oa}?DCA+YPz_X_4nO;(#AQaH#dC{? z=kX!;6umx5@VT_Mb~K5ikmE|}`}b*!5x^2K2wE4R0c#h8q6? z_TK=$Vw|mi%=j2>fB$Z*prGLJ7Pt`s{{F;9?~EMx903T`Potx!XIzmuTFfsfFj631 ziu*A$GXQ!=HcQJ$K~2Vdz1G|3we|U=piQUEiXG1Eao2!{|8V1r(;hbZ+xrH;uH4*Q zpxhR!hpaa|{Vk>&2kSpmPmY!jh(()xlS2yrty6vjTb%P0p zx}o63XL~!Y(n`VhnaE`Pmc}} zusQWUo-Ig7810X@bFltMJ)}z}nelrwc1rOhX(fRIN2;HEMFtNzS{a<`Wo;)ndvcbQ zReN3q&gskJS@9KxjH{9vvZLfI;5B!}Emgw*@uNp(v1ky&fCsDdl9lfo<1-=>!Q{FF zJL0@Y78Z4OGtPUDY<{&|J*a#h%}#hzOJcZxP~g$m4rMXz){^;%w6Apb5vzK4ZKar9 z`lD;rqTZ{V_O99pJ)Sl3RrbmruhLW$y_ZRg5QZmkZ}f8jSB`70{_tOGnul^3nrYDL z!rLE$CJuCEpG?%b!E;o+J3T$!pF8imHjPWw3YkMhagcwbDCC42?e3q8JqYW|dnYC) z+S>y<>zy~-dU~EUyu!u!w*&BFIS$=lKaOKS)L|hYaRmwRWM7&BfA{NPp>ikRk zJl&s=0@ypqM$#%Ob|5?foLOqS>Q%ODpJDK2@GgicK@AGkxYD@<;PLs|i$44QVLMGR z;dZEl62-MGuq*c9;4{aEzA}9xx+Kh&Fu&rlf0xrb_RsA0TDJtHjgk<&;ld04bcmme zYBDkzpvnTZ6PRRvg`EuL{K8(XyS$-0KJYopD8cKS;l;p~D`8(9Q zxl;I!3+pklIz7T3Jp=BCu9>g)EE~Ef*<$B8*7p?0E%6kNkGwBkKd}9hz6^r6K0KMg z9W>m0latkl2M3^aWurlu55HXMOwtqJhFt?;3gIps8l?a6bJ)=fw7Tvn`J?r*PYp}Q zc~WQXLs<}(y6@Q{NKn`p4H;-iZfY`eaTj=`r<)LT4 z@dPf1a=a(cO5r#OY?f$lE5wTx&88(uXc}_Vi^s(a_yvo!DaFS6WOE>Nc(+#WY>Ye7 z_A6%^f_k1}$8D{f(!lDATwFqe5 zdgZ~LkYcZq)dU4~Y8$yR7Q0GFw6Y5Ww~*Tf53n}r9E|5fLx3g^H=X@l2}o-Djs-=T zRUN?#C_hi+#c$83L|)4y5hU^N7q~1CL#_r+83A~fgB?wUjsr#e zF+*QchzBFftbDuLwm+3W8BWW|X@3<^RD^5)u5!EDFI8F?r*FhBP%uqo60=+I@i&FR z-dFso>DCg?*k{M(J@F}$;Wkc0dyR-ut#g5qD7C}&pY!uO`yT9hZ>u7d;zuHmm|x+z z?D4TY3fdWNd`~yj|G*gP4u9VZ5-l}jFthXAxzVwZEVU0t#G$F@$rrX-@W5m}o zoDt#pp?$*2-dhZYqFHk5zY-pgmYv>aDJnh7P5gFokQ&UOD=R8iDGvlDIwnIp=v^9j z7~}b$X1q_Osz31U+FXqF+>bS4G0oexkC@T(_EYY1V2zqjy%kU!9qyKJ)Aagrg84*E$dilVT-!@n{6sTjrv+oIS-Fp65dC8WA~s&YvbO=1ciZ>_;Yu-0-hXdm zz5vW7)^UeTe2H45x9|bIZmu%bp=OQ*s6#6sa%azBLhuk8T#!SFF^XKMwH`li^Js<= z;D>bZH8~Xc1PSc1XNZG7Lds3px(K?=LV|)&M$|d2zm6&@ECg;G7;wx0)~-LB?hBb1 z;H+{Q_W>#gkRELG^BQ0Raq^&^9##JVFdWXD280vI&>T#qUdPWye9R*?2fhABUZCeL3IP+EwByj*iL)O2 z%jM8838>dv1Li6*V^XPWoz)k^Jz|k-+AV)nTI3t5uQ)^3I^Shm-hi;*< zI5ZF-(*X~Au$yBmUI}AVm}mQF?VK0(Ts>*(V9~SGSx#}LUSUE)Ogz2dsjfLN<8q(< z{{9jE-j5a8G+Ddr`eq@0T>8|SNUimaP|1gIntt90c9U#_!3f|LwA1?y%zN|lIA?t0 zR^c+_8uM(5f7RH}ty}8bb^h^CL;0-1wezAaej`lI5``bv->NFfo z@U~vpxCVn8LLn34=y&yiO>Z`)E5`Bw zWw!5_Q!!-?fcD=8WcKJxdYM~r6A$+ET)t(YXl9lgA5VEGUGr@6u=j2-pP7 zFg5=NM9l0PVz3?2Pm8~yd@%`x+#3R_%$2dcr+vY%Y{ZxpV{U*n3V14RU_q!60NLmH zGm^&M2m}IpdPrkGKfk5ftDyIi_X^`vUER6WD@O}M76xE5Hfn>9P<&)0*>M^DLiiUp z$l}n3wT;zjzR-|}6cHRSnkJX<+pT)BiVg`;`RO6}`WSR7*s6hCj!v=tA%EnEA)G@_0=S=&tnBxKc7m|s?relWnx_6Vf+o+9SiLph0;vXbP0V1G zH7N2?7cSrM>^$BYwJAM-D~ECA-iQxAx!31X> z#LId=KZJUj^BadU(cawbe>*ll4uC1^FX+v3ueWQP#S_N|)%Yn(CD0(qtoCN(1;Gaj zFr0yCBV}IRC&t#_re`~w4}{Dmzj>eS&1zGhndtSC^ODRUX6IL2i^b7-mz+OK<0{;n z#e4BITK${U9Q5WkHaD{zCD;48O;8^0q6vG-a0`)ig8xDNMo}nD93*;dgAZNyHnPgf zwg8CCl2M}KU%8$?HD$73wY#%(-UeD$=SsfaMTJ8@eh`Nm-sE`bJ~#31ImyWodc&uhH^?lV?9sWgjqd*}i1h zO31{-L{cl6iNVf;&c3BG11t4n%lg6YI;5M?--Zp}R7+{=)*T&o{}^4`Olk-!Y;Ynf z5IT3*mGVVg|E6!h8<6@ytB?Fz+yIDfe8qDZBIT-8C@h+@Ag2}c5oYo zVxkHLQORaP2s{}Y0r3EH1~|N22lI>C7pwIGO$kDdl`f9IYF#dgBTZh;zdHFk7}D8+ z2OiF}D~^;vzRV^?f%}B%w!=)ML@f_w=y0n2@qMA=`6UdT94x3YGnL?fa3g^;+r7JY zy`8O>h<1RR^qexo`tn1P)TayZ$kGa2Y{t+L(8q<=n)U-vQ1>fLTp(_zKw*3;crA&S zb0BRVyXB27(;&Kov1mY)13X|4-X! zIVs)oXbv58etsQ{hY7V?ty1>|N0ec9DX0;_E~cZSgS2X;*jL$FL`W!}T;$nzto`}L zMJsD-t{+)!&jd|!0x}iLxO~ci#{;Z<5+^U|nQlxjrq6Aem0B>=w;dh(bg0nl*7pXq z`g9w;`{c{{2p{OGsTm7A9br)GvJR_tKdgFD`cvVJ@&WXkqZf0;br*Kg>Ra4KUKXc& zaeK2Kqf0)!bYY&MFGIcpA*$u2>)BIi614iH)I)HrI93USR4jrO0c5x#RknT=;8FF| zA73H$5iJaP^XA<4wfs^g=$-pxOc?4msT-U7^Dh9?4!x{S{f-+koU+(2lO}5WRO7pB zg}2B4)>AlDV9b8|`K;nruvGpi>vcjM{+2f;P2=7vyuQte-B5W*NfV2@Y=Ni9EVakM z$4HpR)i5v+S;7xPlOmb+F9SC(g|o0+1#dcld;b;X1D|!eq7}%Wfs#Q|Po!uver&L} zaEA?JP;z{*uJX7XkOhsgD(%Smh?x%Jifcs!Q0D2`_FBT&8xZW6m`F4my`M|xfcm2L zjN0z6KCkht2ZdzpG>9f{eL__6GkDkjqtmV7Qf;tJbHE4#;E4d4c=B{juv%u?*Y+0s z$CBd0vijk|5|a2|jJA@!_dTqU9uwb(91Imt0`n)TIBXF6i zc4?hA2FgIf$j(#%_YgKv`M?*D<+(b1WZ1B0*)0KU1F&`t}Jvs zM~4q{JuaoAe;r_KW78cNBUZOltU{w6*&6U-90n#?${c(&+wmPVIQXc!D%3)nwxY>` zFc&O2!zDv{Q5Q9lxwF`(3~Rpl{ktj*RrC3;$c5Zy-^Ay2#kI`XS+`9DG?#>w`C($%Ks#-&rc@&cu+YT{H`etZw=_FuCq4B#EGz18?z0>YsTGkg=I=SNQpMc|_OAsRG#*=tXkWmNE@g z!j!TPryBj>rusFIL(vHXg*0hs%&p(jv$HEqf0IrVXE*|;75G~4;3Vw*hADS+k3-ae zmB!}YieXQFcR4!Pg=7}yl4MDao#{*zO*GlrSv7TdbM^hxN!L~LM6qWTHg3A1Ob@>afh|{4v00)O(WS2aK zOlb>LJH%(r(3{5TFR0Q09YYInQ{Ri6%< z9=iwL1;C=-+xxVOjqXgyH1Gp`4PCbK=OcVhu!MdOmpJY+r-2~ zn230ZYEGJT>KIOOR~Pwkx>#MCqFdy&)aNqhycJjmNYJql*$ea0 zgS8DUcD;lZ*MKrw+`+CHln_t6$jBK9c{;K7@iCX%Ejh-5X`YGRT?0eIP}d`bAacH< zl;VswEyPdQ-Y#2;sR`AQVZ;nYxUD;R%+JWxqjtSB+K*<~^M*Al=MzLdLdW<+vQg-i zALQJIxpC-QERURK&ar6M`RN|L#KE88x5|EQt@UX*$hd9NUhQ7Kg1I5fGcPIf#|-Dq z{gufAaV0adeU%-wWg{otc31D0J-M=pHFJvw`Gl!b$b|9{H_M)<<^N(Ual34AkK=dtj{nwYvZ@nTtU4d3f`JNytRbc?n{Az zW1)$O9(Of|YxnmnpHr~8q1$h{QCzOz<>XYdR!^s!v)D`+KcDVu$V@g_#qh-ko8rD% z@}9S9`n<-+7%^nF|2zi^%RJaTKuz0t%&>MHk@jXln}$YA`dgiw-Zx6G$n@nbyYZYY zMajIJ1^HkGE#keO&4&Ky#}6h0x~|d!&*QAB=3BSaOEfX(S+RXCYZ2>6X84!0`zoiA zp|D;19nr~kSe0VqM5oO2_~MF)U!{GP%4n-&C!yJwr53wEq;>}HCUn$TZIlO0Ozfn=LRk2m2oh;@RTHTRnnhV^HnZ=>Z^<_!YU5gICX}ERw{|` zF6L&1KWkMrn#Q)5IiqT&aqfZF{F(V{*r}I3o;i7Y5|Cg@AfqS;t_7Z_p~w`X^VCg2 zoX0;)kKH07wnwP=iqs3+pYrYn>642F8iQCg+~|{`oLDU3^AX*Ir+iQ5or?V(Yk~QN zSiL8M)&6_~3;ql9h54(0zk&7V0JWdO{1%*r;PXjeGlL($#_=XPWkyZocAiPXU+h#< z5bardOhOzXCM)YJKO;7<5b$>;7HBx^*b%3(v3q3HbpCCr*%Id?${lbp=>->y7?-M} zB-VRrVp>FR)4zR~lm6y^ud5{U2tO?1eXL=bJ*=00Z|PKhY2hM;uPU=lZac3kdhATT zZ0|z&d`N;*eQ%7hVMQb^U;+RwqW$9k*C#lGm3a;3n1Fo~$gP%0v9NZGgoTBr+h5n$ zAD5r3OOkYQ7b+n@*$ESFNU)NgY%B~c9-n**{*UE0RNj9o19&N3471Y)!!F}Khvm5j zJfQPcufY@4nfB!8GigEK{AYnrVSS&#_($0^0{$Y313&y6DBxAEC8eY$-|%35T1;sb zE|))hpzRFi!}!<@Qo%c*DMyohqRHfG5$QX3vI!(EM5-W7ZqWI5#W6E5NT%5(J>Hap zC5DIWIpz=aS*(pv4RSN;pQleAAMNWlX2eXMfjDM+-8eOkjb5(@uJk6r`QSjx&c>!D zDP97F6JS-}AVxL>v=)P|SbAe+d>fWS5_Hw~JjK=7|#YgT<< znb|?~_w@bOx&E_g68y<^u!Rk8p})YCIIS%0f_DW4zmo61fogVsk(Px;cJfRogtink zx~=9oxIU)5yu7aN2xAXAfo+u8TG8xJYxhKx4gm_)3QoAxU=T)yezPj$W>82-27U66 zxj_*r+`#kcd@pW~;2Bx!m$-zOi1BB4}9aCzI+)Bq;$z+U5AWd z(yEU@7bibt-2h``S65cGs6emU}&lT zit+3;40Hl?;|Zi=hpkObQmI^1&7Ze0T=mtfa-%*K)F+cl7aAx~#O&;ZiFmwN!BDf@ z2m)6RTGa`jA4dB67zkfo!8oL-Jq9zo6H;j{6_pUJgN2-eM>lOVxPK7&mrGyy#KI}r z7rgvMMKo;}V9~N6$kb%1A;UNhm1On_2;QQv)xQ3p_dP_px7@vzPe=K6zcn;SOc{YW zW&8E-R8a1LA_mN@q38vLZ8N~4s>!vrck}{}QnRvjR8^nB+*YU<0Bgd*Cx7AMQu529 zE)gW^kHBG%vpW)aYv6#EVp!|E#Khx;k{|Q^eRpPxa*i9!c8Xv&;g^F!Bacp)l7n9g z))miLMSwr6@d758ddUpJ*bIt;OP~tZz^Iz=W$`i1G-%dHQhUFADRK8MvvLB98ii#u zlOerVOu(58SbqWng3=EF21rR}G`8V2W?*0ROv%jjjY<}^w6gl*Pm1u{XS;O-No`6j zz{zdz+(sx|r0zn?5Yvaw$Y_>I!Iok9cGVm=rIZl&nx3re`OfG3HNZ#he{o&-#qXOO z%mHi$(mmlP186hFNu`i&lz%8CniMFQ{+2c~K0aO<2CM|I!JUT9#@p>01!}+j@PY#F z^$mWCd*t(Ad{SZ`8nJ_$5HOdj$1=WW9RRL>o10wVC z6m~y|$rG~ZxP0`~+m+#Z{EMJ7CS1hVKwl!Clb&vYAu59`jM{*rAh&c!Bk9!d*7o-G zjSVx$7$AUP=1%`oxP1fyEDd$__?xEEmBroG127#(gwn?n(s^R3j6fNdJU+ZP_jG;F z1OtUx58U}SRxt{T_nA{;Q90!P#2kNyv}3LuPcZ9e$)3l|Rp!KWv#haJAV8|gLAf%l zUe5b#W~S)~y5zcD{yZKSCsrT;eCYsFi^`ed9nK3YhWBilTeu&*_8DgJLgCeCsKvdU zw$YdF-G%jppDGDisx;M+oP$j@>~bSKEUaP5@o2^hd# zHyF->Xcv}PU24B9ZAnWk!tZ~}4RZ*k122nTT!ID!^-n`(QBlzYk&}7po^ZjR!4Qso zNKr87T(Rw0moGO0=yjIg`uf5SE!U=7H;O>i!*bb!1HOtyLQ)!((^++$s>9?%yIYwo}`e$oO1f7 z(L)Yk8IL6=DX!tN1sVnBI7}Id;}u*8(>MWV`hLDiFD39n1UcQLX+S_gN(f-S$TIi! zPJtIDR3}$7nnVnfb9sLB#j;BtvoH9NxwvF$1pxx8DJdD5l7|+t^BvvY0=&Ft+fF{< zV>&3mGFl#z2Xiy5X4~f%Uq$w4 zu`nZ`&nk8cuoK=17+JcNFYV_7BVS$y2NQGx*y6G-3iXn#t{Aw*{#ab3Bqw*6YQ%+D zZLuPmO}{)O`Iv$5xgR<_h|0{^m`6N12BXQrOEiPO+vf5NLc$VV(s4r`KlFDI83jejQ;W5t}U0M370DT3ExXW{0sP*5!jp-}FWg0q5agimx20OuFMs!nj zY0Da}^sYM|WJ9-)RUoQ4z=*^U2M31(QGgHufzskNf>rhK@Ys6Y2=|-9X!|9wlJPLP z(aLy}rqm7WHke8t(Sv9l8XtbL_Ni15G*X-N8E!*0KPU3~&6_U`5RsRRQ#Jpt*HC8+ zha}X*iEdk0DEU$K+&WXo^S$&Iy18w!&L<_3SwOa z4_fCH1g|0|XKlfCB< zLsjz@e1PEB{PlZ(b&ngb3}bAH{8?JmIUJp?nC_FOQ<3Z73D_ zGM@l*qCJIESfIsn63nnzC?Q;=*fc^=rGZ?Z2;3w*6YEb7{@>c;qz=NwddxqVKRaPu zLW%UxKhwndn~)obNM$^>Flv1q)Sh)xFEW3-nBDg8^`c0x-$!2>gw;E6&WvpH${wJA z3Ufvs`Bh^J9}myp-=D1>C8}_5l|SU~D?Ahv!`hQ&!~f^0Tl<=isT_K7a9VIAA1X;3 z!_I_$YQrKPhx+US>~G*yXD{uC$%5T5B(jN#Mo*q_V6H7m3jBY2JAaZ<$>sB?WVmc*)5U8!RKYAgvz z;ar{nBX>yo!8?qHpWngW{tm!aEj-{&4L3DRIfK9e)`w&|D2tJ@rwaI`fRF*kHiZt? zgG;s9;kX^5UKY4kj~W^pLP`MBg~!wvHU^>KD%ovp1n%Z0Oq|NJh;N?Jz-@R55x@A- zTalCU+*6{F(3=QTAYo&99{4L;{+43s1lkOy^aD=;j83m7*}H`YupcD!w1Ha%Ga4Zv zNog5D$I`7GiWD%4_!+Ju5?bNLe++M7!(#`ua;*AbdjPU4M|*ostl!g3lo!u zEm@DW9}n~Z=RD;$1{1~OuBfU$*8f|#n-inf&SG*9EG)Eouq04CQO8I7HgVv{SQ#7~ zyu(8mk{=)%i*d68_Y0V`g72#w4CAdqmD(LI5HbtR1y*aY^^;Xr#AkSXYDpM;jgD%a<>}dj%N3%did9 zBTBX@_NZeFx&k?{2I%6=%kVhmWZv7&$n)O%C#(ROC%Qxp4W(}HR8EN=H>kOf4G^~# zW6|Mt*pM9e16dN*w2;_A24hsS^Tu&|#ehv1(_7jp@Hh+*k(QB3iTw*}{6#Nx){Sq_ zdFrz`j+0s4K*PI*(?2{ifno(#j~=k;7n|XZHb7hj4hc9FWXC5`C2rN6lZa7hfz*?$--eeO%)zAqXuW3E}3C%f3 z6*K&y_5%@QZxs{)ePtd8JFCb0Mnm7FpdGc)mxk{KNo?O&pDh%?iPVnDQRJ=w- z70+wQ;|fVJrEsX*#`39u$A=ycc>m4cv~xfDzI6m>?H+5d-vh#k0efPQ#}vJPPge1f zWLW#r-}Co)?>iakGbV&5uup12UrtgzWbRISQ7&QV!r&| zu{qDeRR&@0aS)(}C%3})X(>QiJ;hEUZyE(A)uf?lGjO~h{R#tp28{VDU+~6&mRU)E ze)J697+f0uJ#aT_-h*%%LAgr`3Bw7_d4g-Q#Dc5|v$&_=Hb40W4g4$SUrv7J>A21dH(Xe8f-@d6^BX$)%zvR%=)wOZAIP@Yip>35k-#Q?A0j`Da!tBRfcd1p zm`_TENF_wYOg}__-C5IId6;-nPC-GP0FdZG-V+#E{FL3PUcaT3ud;N2j&8$d!~88; z#LWlU1if;{N1IGGzrTAyw)ppGWuY<9*nb}_&-vUd(0-u}!+MEn0IM@fF)MK!%@AB0 zGWuZuCqYDK`0vpH3Js{N@E_0>n6*+85-))^CP^&z=a<#Yr~V9yu7?Y6AJoHtepw_o zfXCAkm5ae2eNSNSP`zG1+S@>#(ME#osprkP$|;-JNYVd9z=yI`dP zz*<30PJB#^ER`%bcR^JephVz*(!&EILP{@`8|lWl2?MMKS2A1>Z~{Mlg32c^FAw+! zL8aJ9yy)jmZGy@1;PZiMy{D%KF3_*}24IXRQvtAFXLB<%56>F35CPZ&oC>@iU|I+77w9X$e2Fb8 zS`SmMK*j{Qx>CE0jEs6E*nR=F0n`t6h1TU-Etf%?B2;gL5VR@^6v+nlwzi5W_}1TgR`@9!u-bS>VtJa&5~@Y z0LMEY{rvPfcwWA30H;-O5xNBi1PB4~A};Q#o2l9)B!J){WD`+m6?nAp>z4#Df|C{FP{kXZ%fpzK7k6H_&6zCJcKtaRJ6&1Jl zDgXzLgWavxe9CmbA{l$d$$MW*- za=Cg1=OyZIiEcIa`w7w751&5eWM^OhR5VF~FrXLAgl~*M zBT_xH*x9+NR7r=9=_Uo;wCk=^xWgrzrESc{pM@VL*oa% zFPghF&7;<>Y_|=ILqfD6Gqb$P)3|T6t=<+tVY(WM5-R`Np9`(n1jj=Sr}wNLXP*CQ zhyAZiOrvv&T_?|0Q1fMBf5rUtvFkZP6!D`n?u}#YS3IdOAPweyFHWATM7DhLP9N>mh7l7JvtUm?nSxZ6_i{AA&62 z-b(jRXcf_Ab(o|x9dVhcx6;+;_+w0G{VWr5VS2Tdc{wKJxoy#}FBywI8$%P<)7PJx z8YdaS2Rn9l3z{vMi>^8MW2ti9@fW_n0hPRQQ1EAxKWWyU;zxLl4iTFZkhV*w47Q_tYY7N#@oQ zg5a~}zA?lf>K#FTMSlJj?kD%#gb;1?Mp}M(Ov5>RzjGMEj>HNM<}b1(dSm*@G94Tk zkVD0D(b=YEX18spe#e)0y%T=FJ-p7LNr+l=Q1XU5Qj&s{h5{&CB7eH4E|;dIkQjib z{60*EKq5Z>tnE(TVi&0 z*azx_!?Bl!H42^fQbsKwjn^mT3kx??o;-1}dp0EQhvEs*U+=HpA3JmIe6DxS8ryCM zemhdK$>&VV_&490S!E+X*QZxzateia%keNm^-Nug`=r~H>Zy9W--mU;MzKs~pHj)HqTWA+|A7|33s)q6kk43s};vV7Bj@j~E& zlI8n6an5>{Q$x(Fb(-qy1Ldg=56Y2rm$~O$y7a1iS?4HuxYg<2rCrIU@+F^>rwjVH zB420viRIWgrJW=t7M;!_scDglY|gL_tmNT0*sz4v>Ilx3t<{BNJK#P%Wl?`}@V(zg z#{TFTSKT2|zhyK}3$#k_+!cN>a{K;RXgO^lSI(Z8eF&1hu3GjooO5CQce`1V#5xeY z_TA!&m1=6F{cz2#zpxtKB4;Jb6NL`|%efEO{wmYbqTTn=`^t=om`;2sc^EGl0O6$%cq{*b#yk*Z(`tREf{stA7Z{e5Lkk# z9%t8aCkfA_TIlk6H=j@#A9y$Q`nd3h&p+D=cOn&yfAU1WxPVt^U{hqJb$=tnyVs7Y z;-pnu9~6ulc|Q1XWyRLAdrx#tTw6bU^$(#?o3K)|t;Z)%eBqx}w#%&8VSiw_h~`k3 zUz3wYk}qc0W_8|pUHeFHJo4M@S8)!3D92$oA`zD$X;A;SMEos8c~83NZ_RRKaJRE~ z!tE~R{6Xva#25O7C;6LD(JKvI`=V0ecqkR06yd?ROxmGGZD_5}rX2mpL&{H<*MHU# zaS7bhUp+JR{o?D(y9eHG79LgYPdzFq$Sy4Woo;33%w-oIey*^lO@;DNWzH}%a z$j8r}JG}Q^U-5>0CX4RbAF*s{e;CXdl&urtdud`R>$k28w%tSfim>t5)l9f5KeIZl zNh9>^sXWgGQv~qxuPLUT7KVm}r%U!2y6R5{XWBIk!G-n$AL+-`pg;P%#C8EEAOQFw ziU){zJW4@8gR1Y;s15#Hm6T|Fx1QdX2Bi`8MpTQ$b|cMp{B-5Z_6eIfAq^E=li z`R$#aL`DYRyeX7gy9Xr_px4Z_ebKI1IM?`A=~vySVIVN-v*BlTn5naMk6 zK%bc~?fcARVWH4?%4cqiSk&?9Pk)Z_lexb9=O?O`DaqEd7rHrjYuj%!O!OvYGc)s6 zMY*Bjpe7=6>Rv$s&PzkkzWL+Q;wtREQPicwX>dfg!Em_4o<~;*gXjaZoutAmi%hgV z+gW8le)Mv%pDA-vz#Wy8=o`e9Qx;~dt*cuuv+7J)82N*xlsZ9^A?m5QjGd^x3NrCl zt~_HP8!6<7oSdCB7cI&9HN8skOWEW)cZYtq*DgVPllB)**$+SZCDo7~=y3la$4oE3 z8{Y=sh!and+kkDE^^RI2!DHo8skTdOCpVwBY)RHTY~XMq+ev?WqN+*zhNxS<`-Y^teyMa+qQcH&tGgP;{4nJbod^lcJQ<5G%dQ(}Mi2gA^ zcC_#>z*jT*9as$L;TWAiZ}S}&QE2ueB#U`1XZ+aYqpd(fcJ4f6T)Oq@PBFbzQtS$+ zm#Ugbtb#;AnQcCM(x#R8zuI^y z^Xa$r!2+qM^mIoBg*yi-3J(^1?eB+T?~I26QRr3PP_vUVc74le@*>B7HU^(MR9{h? z#2E^nkSP;!kO=k^5a&^4(_OR_x+W)(n}#759pO0$n&N&MPt-RV>FL&K*O<0!@osrm zA0g`pB}zpPdNQ<|$f(G^H>M|{!-glgbm>r1B#u7{35Z-xYvW8H2|(ve_Z8fzl4TA; z4TfUK`pHP}qa%ZOLiz~9mn#pi2P_fb!gw*c(~L*b zoW|BdzVq;X;0dnAm;0>bet{bq#7!QQGoa5o_xA!&O~7=&v?E>QhdoDFJ)YMLh|w?f zUr7Hhu#MJ}Z=kw%xd-}wABX|(+>upM-i5o(1b4s?ZZ5}cJ7-;yexZT_5^TAC{WrT% zf+S}}B7vbm$i|&rTrmFklMiKdbQFpkAE@RP6Zu#X6vsr|tC)_p_YHDjQPjLIq_8-rn*UNCeo%8m5$q5T)v3oDQ2exX) zh3c_!-o!?Gd6x-^0w$|2m?94RqnKh z^$w9hmvc7q24}ze+)q3A!?Gt-#3?H&DZXI&U)3dSF(^Mir#Y~|TKcDVsc(Y*V9es| z4fFLpCF$C4{Q4hfJBpj)H(1P<1Nb^RCI(E((~qn$O(8EY4=qA8u3?H-DaBr5_Bq)z zn+1J@JkL@Tkt&|9smj~|~!#oF+WC^p}r zhct4}o+Q~D89GAr>_+MWxHLHp7A|rX>xy81y&;L)kJ^)pxg%oag6@x6vNhlTI#+ZyXSkFW$0ntw1_lI-fBj^|IXK4hA~F)UDL5OijR!(dj99E*bB=~6 zHb)CO48O4o*$tg3tDgLIspf@#(9<1~S+jOx?mXo=Zez&I$~jRj3RfG?>68zKY`Z$N=P%JPl-_Dku(36?E}|t1Gy9-MRCW zC+_s?5FSR%SY}D5Zj+YkMD7g4Nxs3;%S&RI>XFdBUw0HN2kvh&fF%e|&X?O(U+<82 zTNb{$+-DpzJASTEcYlAg+{R7h?}FSDBURXEyP`gTV4FF%3`v8?Wzxr2m(G1Ypif7) zlQYYjzalp`8;qb$m4(Yz^mA0uE zb^lnX3z3-T%--9XkZ5*x&6=O5Umr1C>z-ort%!4SMsi0VdB*?8Fu=C4lnY;}fNuWP znH?PQP_a zMnYn7e1Ctxg^7u*`vz%tmydJ&q3WtCL*FzyfPh=}pIf0rLsi2k)bg57YoZC&zj?@L zzb=>3ul(XrAv+T8nB&6;{7o4tn_8IY$m>{)HZw8`9j?!E^~?7x^{=j+Rn`6)?(h8L z))Fjd!AGx6jyI+zqp^TT_GBm9YOaX?6s>$+{$WtLYxiD-u+I-eG=>6i|M1wJYV|1) zUln2eVc*rRzP>^?5~g094R@}5E=_Z*lP|H@nRMz*@zkwy+_y-KN=2&6`b31eC8rz>bX^lAEp;ZM7skz=Z7MmZcLbCzZ#}Tn<{@mN9XHpN@K+)&r=|uU zqjD2c&zpXJs^Ik|OWX#l2I*5*vf1t@%pFdCI3p@d09R{jwp{0G> zKXQPdAM?)U8lY3%QQ;S^LVuT_u7kELOl+p6oJaSGiZ<8Q1~y&A1no;xzpOPZAm7*oEf@c?{K&JSrkx?;GQmB-sDSq;Em7jms`fsTG7Q5@a9>$OSHSXPu*Pk}9 zB9LvaxWudCMsZ0;o_r$LY+aEYMVn(xxZ<`TKl(9b!hyAV@6@`iD7;P*9DoZ0rnW#5`J6Lv1!7@`P0L&2uaj#wuK`T`Vr|sSt8s^@N2)V}^OU z_}SKae7M_N4=c&YOy&+~E|p@J4|i)$vo~LZ)O}_fnYF?A-M!46_n(%Mb=NUf`=y2l zxHz|reFwe>>{`^i)oP-u-WI#>(`#b^U7N`}_;yz73cNi^3;kr)Zu|T&by&{8ANg6I z=9%Kw>on6=+xrq9*J{0EX)G%dy> zK`y_mKDmXe@8!c|cy$L3RM*RKzG%b7HLQ)ZHVXiQ5yquo`Z96S__>?AXo77c=FZ79ah!v}dfJ>*gqFYTj}>90RbA=j5W1F%~!~5Fz}z39F=&yoW=6jV=0B*9Wyi*|r$RlM9_LG?B{}5nZdHI}2S#)#ruilyVYC1$t^9 zkU0e%ce=|$H)Ao~DfvXLFmH zT+p9r%t!nK-FV5$WgtlmsiHJuyw&w~PTN5gfdn0i_-Bt`B80LMPAj+;!4^OFrM6o24RS!1Dq~hTDp9BqGQiK zlu>~V9fB>+{GhiZ@WKiJ`h}oXP!K9+)>c&^pF5p&eoX-C*_hbasL042QG~oC>!01L zc&qn$Z+N~IOVyrAB<1mWDsO&6J^xMti7Z_1Qc-uiM&OW@A+BIt*jkT)H^NmK zZm$S}L=}f287UVk3_#UF#Udam7`1F@co;Y?J{Jb3yn7FX8DP`0Wy?mQj`=W+kB=wx z!8Rch*UgkUD!iNS?&%pBm|lE;6?h4KeSIe2r6zz0p?06(M8p9%mR4A##8ffVE=WmJhsbxpWc+}zjfljTrO-`Jg|kwEy07t(0N3rcSZ)M&u{@qIf*P#hrC88fb4$jO}ReAYgvhEoLpv zaFKc&KuC2aQXAS^bP%mX8 zV1>t$oV-GaoPkqy1w-{l8!N%^0ao1fO7|!-7nFeS_20C(Wd#O41>{a9{|tL=`f2A6 zQPI;7$VZwKtRHY|QlzCNk9n(@Jd_J8J=30M5k5TB14Q4*$jJ53!B7TR1&LS<3MQTR z0oaGB^p}RJPnTBO_c!XOCZz@kTQ~nyy?cE<`PI_}Ea;B_HATOCh(ieSk1k!aTrY+L zVwTNE>ZOfIqyr`8G8)W8x?XS2=7Z^E7_Xu|4%&?oEg6+?;|^Fwmp_FZWCa21q8EAq z*Gpwg(+mByscWdxh3%hH-o@6rJ{=EN?2mzPy2+_$3SE*B#wwCRh0IKqY_cgG^Y}|Isu_6+dxtHP1_DcQ=)xw=8RK zR63v6IHC(OSFPntw!-kyV&keE3Hc4bb6^8sDA(r+5grOx^u$T5lhFeAS5$b0zY}Mc zHU>O~GuP!!_*LReRaR6$2f!H6(9l5Rtw6Mf(^68Vb5uYr!qm&sKu-@3%n7_25~70^ ztjW&Mt~N`*%lDJ{4zkeE8AAIBV+4a-FYw23?*d%g$huOV>22I{%rNST;@(2tYv`?T zkb!=t_3KxOx?89_Y3Na)Dygb|L;C)`x}qt2r7Eb`iqa~eo!hB*2w9_{re;TECI9u} zg2M9{!Xirk61{Yr-NM3|dXpsu1+Pfm_m6+YIm@M4#=*^v43%QIV&%$iu+4-wt1oBg zyQXc9m|yV|u3tK%;_5&tX8c1{Y$V%j%~2WCmGwvY?vzw^2PT zrTu_*iKs=3@(|ma&)aQ-{MdcB3MC7gcLsgnATn0!?c0UwUC3fvSJYHhkp(R`v~8DS zCo+g%_I|H1p2MY7>0 zc*LY~MZwYEOe2EDMO<>Yr|+s_Q$WRXa+4SCU@aY;J6jJY?sxF<^e*iazLt`Fpj*&( z9<3L4a6it~_B67kBtk5grG>XIRY^{cA4RkIJ+3ap^BP%6!*0zHUwe8U1h|CqbhH|X znd^9FI*<3%DUgpa9f;1qDW5af5imD73kN!=^YXTNe&IV=mGP4X49yE2=(w7i(&*e? zn_^t1Aib`V*eyuP=IKpyMGF2?e32geSwllZ42%YuZntR0%;>3^lq^4B@&Vc$-$qci z#~;`Ia$-J9yWgvOX@+$Y%@J-nfb4}nMmKQk{)Y5dza)@;FIu3(9s9BSPR`w$SMPf$ z{Eu6+&0FEd@vB6tSPM?wojZ4s+z{p|4y3^EtCkRk6smS}`{VyZW1GjNX<3&oCU&oC zU==u$MMXWBVDAf2LRs01PYlZ`baYZtJ$hBdMLtiaW>56h+3AVwwRs7`hTo>Q{+nJY z*NvxHX>`p0a1c|(Negtz-@LcipbtBwhNcdpDF57 z1Hufp$)RQU?%nEr4Cnjxa*U2HdT_op^v3oA$JOu>oKG?4^{a&B^B={P1c{S_U>oS2 zEguyZ$p0HpdG6TUymFI@>dUGnSMGcM7OgInqf|_wGjpv*B8i8eul(oQ8GrmSkz+1= zb@_TUI~KlrJ-L1Pe_?T*UH@puqaF10MC$!~?**qX%a`v|xdE9k5@P;8rKtbPHZbI= zYv)nPg6JK*`q^7IZag;2dVh!tDFa@%`8qY*)eKOl>1Gll<9{#(yqC2dm&E8-Az|UF z#mdUcD|SvKtYAZMv}iM{j9AGXwe=b{89rCT62ZNj@3AIxc_^q8ti|?Y zqF|q5VZ_WLSvN;;ThT7}xo)+fkOAjcl!e>25#q~z8Qo!z|}afau28dl~A>=%RJl}T**N6pTxy72IPYRPrl zJrX#jYSI;jm+^xBQn#oq{j`k?rXe1h(?%xhev0EfEaED|u6jmX;OOW*(JNLp`Aw2=O{X8>1v zR~v*7_SV*D5W!(@^>18&EJ?UG5PRvjIfM4w1w9Ig{M`JDak|j<;^X9$ATS4M&pGb3 z(ce7|KAe#v-t{8_4}fnbBi&zF8}y5XfFQ(2Z(K)6DE(_h<=Ih0DPC1#TH+wnopESynb*>>HWjY0&DWO zs;JRZGi{SttX#g-+h!HRGCF}hMTi%AYeG$=}5CvDE-6Y#B~wAXEvxTUgn`7#lAVE>)d|U?VCD8?Admz zv||)4_JK)d1Y(#idQDe#A$mlM!Mb#Kn@>UVbo$6n9P`x()O#+shV zqNr}V#r&gd6rOxNP}%wi1~O&CM8XrpLV%7R4tg^cZ9TvE9lL~l)=05qH>@WM$O7uc zFyHB}Q8Cx4OOWZN6eT9^7kT)REL_*r^g1HqhV9DVCsm3BAPxVhoge*YI0H~qQ=>DD zKCov9oD>ytZefsvo-WXj))#7L&OEvRooFVU+R_6q@B<&hg$2zn{q7N5kTrYByF61knQT5apwG6G*y3xX zMRQCJYhkj&GDAUyiWsiNFz(sEUnM=`T;T>Nh1l7nP(MU_DHv_pr?p2YGJgbqRE7h1 zHP+S%PrIP_pnu_YDrJ&pP*dCdmWhc8r35Bf#fQsuKXJcT`9|Rv5(=TQ@pkX^6W#tm zfI&ryU3!mDZjQqMIdp&IwJ|%5&dEA8si*{(r#pz#bZv3EIH~q!7rZ05ghxw*^ zW0qdUc>eWCA*iyztTe?kEU&LMGW6!Sb^b~5;((C+mi|k8<*5)yEp+ORZ;?=Py-pG zoo6W#W%aYO9zFVkpMuK{eiCuOCSW-MdEx7hK0zD!nDajQ5Je`Mdgz&hWUvR!L(BeOAL!%U1HCyXb$e5Rw4HBLGTY9HZ*S+| zOf;M8CVC)&1OCds5$^bo-}2T>%cP^DnQp$6BCo7`FKjt(trxFHnL3YHo*ky4@uOW- zPhBaqmuGK;z;2;|ps)!cyZ3_K4=r29-|jl{rBHQpmG^!g84~BIsIRtk`xx&Hx?#0> zAf&kBXc$VVYWvbJy;p8tX{aV9z$(Ny<6MxNn=Xsl8^-yTm4afu9m_iTJ3f*>CmGlM z_;HklH#joZ=Bt}wpzDZbig^q9XI@>*7S3{GOUoC4pu9Jb;pn!a!sNzwy!N@`g1GOl z7n8BFMWR&x^HKqz4=4^ z=iAgR9{NqjyxMqZsPFlz)wTPjjg30kh=YS~3> z*JJ0;oN=nit4sT-nORp9FZJ+2@NDRTZWaXv#b4to z^{`00F)*B9?WaB&m!jft(X?1vGa&8SL6g=4PNljN)VfxphUJg$E??8* zx&PepPwwxQz$o)2hidO|leT5S;tQBy?l_?b#B#KxtqTuiG0Pls_Qdf#aL07u*3cVQ^S$m-M{Ep zNniT)=+quA*G%#zL8qd?h;=z-llwWMCCB>70n9Hocw)=Tqx@2NyQ>RdnAXj*a}G3# zb$5N*%W9xC6Fi+c7ME!+BBK_@b)4nMq3ZYV<$GtR+?R~WDUOe)bk}^3>3uIup}ZrL zw*?5Ri9}yq_x@ejM*Z%|pWm&Aszs**Vl{I3INg2?awSaF^r!fWjB33dUoCQ-VcY1K zWy4b+nW51ec!QqqSEwwnz*6nn$}TBHPBksf6|PWL>S;%U)497#lVTK+SF9%N13v8QFw@U$@awC+k_kI z(o*z9?*{M64$m(MyC0TdRMjDEFn&S7>-lxgfs)Xl%@14GQ{r@IuZEqdC={~meX8KI zzWD3c>+nIQxV;RfPV-vp?7yB%Gl<(oG48yPWze+a&zeo}=i$EWI(^I{oh*2S>HJQi z*x_kYPCT(_70gl&p`*j?%EnV~Xv?eCy0BKXgy{G~(eko`=M`y-ei4<=g8Yt6kra+tb10ZR8dg&$20& zOQTfT!t{7&u@5jBoIoj(jcnfB-RM@qxMhp(i_;>erlx#+eD#k&+Jo1`mV;&wUcYv6 zb)A9gnHmkvFN-8^uHFNai!EN~5hfv5#gtrSv>Tw=%e@4fBRJK}6tag~m16y_buDdM ziz{08crgR{$+0z+oI*JYP1~~-`1JSba^v{fr=u<@d}T7siUXb2!W{ekPN`AxH_pAq zj(LlC8lI^??Qh}Gz?9|f8KiF=`=+lqg$Hslz0ej`eEwWdKr_y3ThYwzErJGJ<;Jrtiz|BWoQE?10wWiv>;l9`g{V2aQ_FhG~)vJ28XWO4}idOHNwimXn zA9`iG4AbP+37Yp{V3d`7h2vOrA;f%G^4Zp6-vR%rO9$Acn{UU+k@}m)3T0L%j2n;6 zUjCjb*t{7CqRT{-T71BX1dPMuujt&Q-y5a=HD;{_>5(*z=Dz0x!`bvA-Hr7vINNHR zld40LgD+o3ZQI)0KHPhgl-+oNxH6EXckaAV=y65w!PqBx)BO}EKOptz)O`K=HEev_ zhG24?D-Ov=8)VUPxfkv2Q_X78HA5nuFjd6$0%W;Hcsz1LIiixB?lO6>^T_)h+5zhg3D-HP+_?rO1J9}nGa>!?lE;Nf!Ye2PdG9c>jE1k0n?Um8#`kP(OzlakDv zG9q;zj?zl`clqHE+51 zC{?m1(WXW(L9pW2V7_UJWsCjK{J{*)0HazbORpdm(Ni(sQ#}0a_xE>*L1~1(1?sh3sQuSqXSt%2>d&6nPtx zS}5I7X|=btk+5mee^NuiH&^+1D8O0q_jld|4%YDSuGn63d2+m) zGp)T8ia%xt`-J$a@~@Ed@m4U*)P!{*k>s!3QN#J~#7W4-9`V<#v8^+FVDcmXRl~fg zQ{0{5^}gx{l<^J+^i^red84>%5a?E}LUt@W$|xX<-z+4s$=ns`7k^IL^?YjL6Zv_( zseYZ9YkPmc%8M{bHML7qSq`UNe&(`=n`I$F#j*YlnUO_A$dn=7CqC`(81Q(N6e!s{ zafFytglX2eWLPu_wYbc>Cq7N?9YJNnl`5FPBSfS<3zc=SA5nQ5SI=DwS7~;j2&StT z7i(`x@aw6ueVOXoSR6Y(IcVvPV$@0D;lZwXx0;R%58SSL zR+G%k%H7-DUB%AP;4xEB!*5&#s(@)-s{Fehix? zIh6^CP**l?o%;aSV!RZ7S9&>x9tFZU|F{7EcK%gKf2A3HN*Y7sG;UsEmX>_(612>s z7c`5!9_BC)|2u8Cn|a~9k&%Fz)@+%mep8}R(#{HMav?--m);J_+Te4^tkIxP3@}Ow959NKBeYUD7 zuD8#?Za6UaVhJnjO$0~{Ubn3CVNc<(=I}cDP>hB%+`jyR1aQLxQ6bJGZ>DLz=2RkJV z)O+Q<6hv;la_PK!(d7bKEG_cn4X6#^*y8LMk3gj{P$pcidM;mG!4B6 zr4v?THg@Ps8wg<1z+CQq@b9^IikE_9QDkdxvF07M=0^d6WKpO7huGIe!QPzC9^VCR zXuS8E+H-H@{jX`Tk2HymZDyQK0_N}cV!^F9u!A_Fjr?`}Mk)5~4p&BKPe!{|$P(M? zKS;tlb|D!brrkm4S4fpXP{XAO%YfY)>$V;eZ)RM3_9$tw4K+{*pk&Jy!fLuodr>H| zZXcmPKoBk7J$pj^jYx{C7o*}&-#d`- zu>73VHTZJAN>7KemnrBg1_A(#K$voy*2vJu6b9luG-PR=aJjPrHKrYxSMIj3}<_W4{!hVaYMp50fwBEK^C;8IT zizQjJQUjBhuYYw~--j$x?diII0t80CZZP2|(DOyTzVmp(Gm%h{P9Bkm(c9W%q82w_{+_bx;j78Ws3S)j zbG)xietOZO=9|9KL0xg@f;d|eiaPP02ymC^hRkIhXVNK2a+_u=o=|IwlQJ?h zr!IdNULtM0><;S*lX{c*pP4Ee9&5J(7cf0vpiJ^C<=hj{{a^=e6~lV0H`e$+u!Z!$ zEB!XVy6el`4_r`E^xq-*j+dUfoKq_OWQ+(}{ zk%1P~19UWJ&nm)P;b?m2+4mF0|GL(6sEMlnNq(Mut=PtruxPK+ca)QZJ()?(cYhY~ z7PkKjJBXXzBSwToGjme_sY5KYmyT{dUUG!#)4qgRcn5gA{oK&t>B6*OU;Ltq&ny*Y zy`R1oJ;@m=8lIi%lp|i3){Vcg@T!p81<|kOl4YPuYyU)*;L#p6rN$Dj;WBZ=mV;}& zQ%-xVKYZk$m*W7|=zw(RHTT(x$(G3@qn`{Jsqa@y8ROE>y)QZ?I#B%R(OO`uwMV?3 zncwyd{`BbRYs5pZb~^SkgobGo&sGnFoXbBib58!agJj&;SVo?4)5g){U(Z@z==(yv zVY1D;HjHDP%k;75hopR&Pn~cTd+rz&rS)9BnDf9$cSO7##3bK8|D5$aK^uyT0krsg zL)}Hdu)M`R*IsBgFgc$8VJ7$Z`}fp+C$t9}`m$_xJ{8!WF~L9FR2Lu5lA{*N^Ep&x z%m+AR>8ax2+XaioP%H;>2*K)~hm$(+Akl5`Q6+^)jlzcF0ZcCmsP#4hwf+qWD0U%< z5SQ@u_}?yJjS9z@Lk$%PXB$$PcjvIwIg_UAbX#5zmmZ>~c8XtTz!h%*7-W^Z!TUUS z1IM8@&4!d=dK&8eejlvAomZ4C`;>@8FTol0*Kpllpi58V&CQi-<7dUozBOMIp}plg zU-tKYZ(ki3WUDN&GlN-{7iOHA@ z&)O?pJ&Hg}P*whN9Pl`iASsykG~`*v5G6^dCFd!tkWU}~8U&xV4fF-eC{>gsx2{Dt zhk1D7Ar}H+zcsXz=XO`y5c7OCe3)Wu*y@%$)=325n%}p)j&zjPdOpwPvlE*B&$|8w zE~MyH>^V^ucFO7J4!20y>Xe# z6G!@ZeBjhnSG`_0sOvIZGga-zua8$ncKKgdUoI2Wbs)mnRC_TCFY4N6qZ;tK_Yb`$M-w_A&sEJ5EFx<6QW z^KhZD0=^pm*>^WUl}&*|vaqo3>in9T6fkJRorgTlY%%Wx8XAF15C%!EqMxf!qbFs3;g6P7b+sBc4=6i-hrACM{sBEO z6g!-7HLG|hz!Cj^%uyee?*bMubLA;-g|_p!70SI2X%>5g(ssM;3Y-Th=qG7g*ex56 zJhi76sB%Dp3cebHt`Fm|gSPG8po!cHX~i~|dqs&3E$l42KXioG&wh^|Xuf24+sEf8 zu-}?HlvwtmavZ#MG)|x2zCAsD#uWgM|C=|Xz+*vh{5s$^0Gc9M;<1wV?H$`x8*=7u zgj3V$4zuT~o+=omQD$gMGVTy}m>=!F)7v-Ih}a`=Ucgin^!{M5dGzQ}M7W@U=H}+s z%u?7Ii(-Tiit>X1XwW-CYqGa0$~QAJ^McjvjLW}(9dr@Bg2J4K3LiY!oX#@X{-&lz zJ-rN#3b@Pymrj8{5pH*efcb`-L7KL8(m-%sVG_38Xb<_yroDa^fyGfYgmB&iB2rVb?EUj4^rzcRCm#338 z@#|a4=QPXMtXSor92u7>M@HgXve&KZDM#K8j62#+*3NO}8l!=3d$L5CSWB8DbvR74 z9rJDk>@n#GUOq}?nlcwJD(}CQ#}v_p!3rfd})Vf z$NaZ%kM7wG99UCBgDp_su^ohsARv8S?GQ40J#K;y1zDuq%yLJGYi2p5Zk2=(GC5wK z5InWKcGBd|&&`EhVA16inYv|YsDdgUdi+cvJYvv?k9JM=QcylotPsw1JO}k$Vuy)k6oblgrm_2oi9q-J&@&)%34azLgb?M-^5gRI)3zP?3|uppen{TB z>0JtEy96j-b+mIZAt>Q8nrCPsI?!v2VX}dwRA;pE6aP~g@GbtNZeYN=(1As^sw_Hd zVE6H(+s#|+E`N`&Lu#|x+zq9}bX^YR`OFXx&$_52v6_g!oqGSxo_RN6-{p*<~q?m*D;1*LG=KyCJFc#oH&Mo3)$GA zy$olooT(w2|2#_Z9wO8~c=lJaLl<(p3ynNX26O(grOghoC0w(RT=MiRv;!$sEiL-; zB(HWf7;(c*|GYlv3ch|~35@MQ>x@(4K-+(}Jp}~%Nxhe6t{w{1gRSP3hYxkp*Vc&B zQr6JexOMAP-WE$Mf=5vI7muLo0R|a8`o)PMis~suWB9@C0viI5|96hjU1L4RLdo2oUlkpT5&8=i0GP;mZAf zIi}g5kGaJ{v1rX6il2)5f4$rNdS}<+Dhwzqwf$Q&HEs`5ah^_U_?mxxJ=Q#lHZbiR z+D6nQZ6^Y_Y;CS~?V7wDGFLNM?O2LFLI^V^50mWeM@L4SJA#cv1T973Of4dKDR4_= zoqqTsm&*r?;6uIisABLTYXZN*j+pOD6pB*(6fyZDXiR(#r;}+FT81_-EZQHU>-v1l zk(GNo!?g3(<7Z2em{3E`RYYjgkmh{LqnBbG?$dzm$C0-0gaRGgyZ!Nhk~iq6ZeL}} zc>-YcjW~djmShvv$X6r>2g`=k_+OH216}k26SLlAs%tTZM8|}{?C0u=IS9cpITXfc zm`>@^pWeBFjt(Z*F=jwF|5-UG4}ZPIQj~c}-SVp%X4Mgw^q=46n-TOCrKP2qUv)9f zioh%8vA2}>=cL4WKRWdy!13@;ovG-wp^!Oox>xAjm?K^imm!CUqF*4-4s?UoZc~`yTUr8-Sbmt_n@x>QmFcq~kpSzV$?n&aP4y@7E*8@~UkR5NYRUWS)o5em0msrM!T z9+1Wld;TY!+Sx)cj|Kv2Kqt_9UcK^ghu4_bheZo`F;F4md8pnjm5LhLh;C;YY>+(p z9${5@bdulL{Kl34`nm&Bow!ayQwD2wEpzkpy_X$+LQ~A0G!-4xzAn$(P5XSXQK0tu zdQuR%cu5o3#Hg~o{t7%#$hR@mTn>~~&>S>f7r|rc=g`ppZ^A&UJsi>!-eT!TuL5n5 zIPvJsE`#4oTF@ZGO)a;D=oevAsPEi9vr%;TBfp~Pcm!BWcm<4^3jD&IzZcnm?AsM1 z3F6!k-^b(eINpcw3j(rQX!@}&z9@Jpq&@DtheC7Hf7bDazc{Vr-0BqWX8g8$)9t2@ z(oy%}1qyu_sJ562>PtW`Xq)k_B_48n#8R)#^WCiHYK+9wvF#DsO)N~hjghi4?E-+I zw{>y%&IjUPZ7m?wOiO>C*S>R7SnRt-QtVaR7a)pV#5WBICtexqd2u_B(yL3TOR1@T z?=lj91)gD4 z)Xur)67gG}>R*;~|44i{5A)npO^FdyFPc1srJDubCw%-XV9yc1nigV5jQg)&m%NLv zM*0Nl?X_op6AhSWpH2niwrwQ>_jCW}8=w19Syqal9QQmqX2)(Nkd;C2@{?2AzUel3 z#de{?X(%=f7S*%6i0@sw=PK*Xxqay;x1Z=d2-BWfz~Q|m2{35IUtci%_$)zY!?)Ob z@up$$S>ktd{2Tm;Ga38lULw)|p?af*w~1d5{JIX5uE&H-{P*99W`F*kh*N+6JV><42{996t*p#_oBQZSN3g`K7OCe&dF8d6@?^=;sZk~R0 zBl#k&{v^u@s(p;g?Rd^_V%U=Zxc1mlro$^L4!*gI8=&a|fIlyw}f1@%N z@7Q+4bADhUVT1cYjXY{t1k z8#Phi0grGu{DETVA?2&)K|H!_shDD1?%e%sxek|reobTH&TSF_1KM?LmkoY)Nky5s zB-Xs@I>)qhfqQWy`MflHXBcCs*~w#|E`!CBtGuYfvArk&Y$Z%6dNz~ch!{%iukP;W z=eNQHfa0=LFj^8njg|s{EV|!8p@7<>kvC6>AmuIL)Mf}5wKwZ%@1=fh*pd+A zZ?(B?M_iTjF*#b=7_>Wy$Lk*wch56}5UOkS6 zwhrL=n6O!}Z4?A5>;nV8eTI1);nxN#BfT#qVQ@P-+2B~|YbU{w8{|ArBF|z#h<-qG-Rlosbdx69?k9LBwS%K?NY!$0GpYeh_Q;Ki)b&!(+4 zFw7Qt*tLNiBI&o~xo(;Qzjlahg#d5-(b^>AQ&Cr+bsgBNLA(W=!ue(>nhjTiy$R1r z?@`=MI{G}Y__4O8U9)`c)gWT`ORBaCmGH{(rd_F(=}r>y;zA2c)Aq%1OKB`1fSwMRFA| zh^~=3vc^|kec#1u4r`B(A5YG`2;A6nDN^l`h2u5zl46T7K9tv(qM6tMPAkT@eZo8$ ztw4#Y!a~_>dU%}WR>5IE(hrs?ikS8yeH|?skL4_`zaB@AjEn zvN7+LA_{L#y9jV@flgUw4c?r|j@M2)#$6YyIRLj^71r;Y$dGBTVR?C>f)yQ`Uv+(p zDtBFUA)PY6ka0gUnEuqaN{08V!k2@udo%ypiS=ZE6M-hhg9y0`++}YDa;VdJtHgbC z1mwTnL!-AC$XFSMK3MHVgkE-ntrevsCMxW{?_TeAh&a_NcE(4OR4^AhAkhT9g`&~L zx%wOf3^h}yq-&VQzk5|$bsvtNX|dJIah;}9JhDT0FBp>WRu-97rgIEw2+XvV*A>D_ z)Ju*xriFCH0U~*}zPd(mFil$x74(*0Tgbkx6?Ug6s&l)T&NhBu+((l$m*Sp%u&I5f zE>~g`(#Wps<6YX-b>aCv?v06x6Iae`sDype+(%-3{5$)U+Pf(IC8=T@$|zZ`D0-`B z6kGH~4C>+2oPEHe@le9&7y4oep>S3VKV;F8{Tk(9Pm?oFLs58CHUHJyyze7BAGIs! zsVXV$wQSB>zJ|%;JcJX~RV;gkP{l=>HrO~kPleN4XOVFc?HFo!_xq}_M8 zJNL6U+bW4rhH-ikV&ww4$1zxWYI-_Si}*mf zVNU(&WulWOzt8VP6%sz7IyZVjp6zemyuk?jSo=xb#X%c>U<5|Sg#G*&R%I3@CLtKG zF`gBnsGjS4opW4HE|#+*Mkx8#1~PH@ZU!7)v)WhP=+f-;nBD*VS&!`!0uws}-gbw_ zZ-1z*wFe1ls0R2~nn~5MT0~Z*nLvtEv#qhAq3y(oiIEXFzEIz`o$QB>3Pf4|pNL8q z@2I34D{gTXe`%7!=H(+#> z+kTrO|2?eS29Eg4XH6h12HL;ENxeKlc*9|kp`IEzBN)7>!yR3c6~VMd{X_6mXLXW_ zjzo!k8&Bjjit4bkOU>hM#lZ6_$#>*5S93WsZQdL!bM7!QG4I6-nHa^-kHEd9NVU6u zU+Rl0V%l&ez`bc2lw<##x)`ac5>R|t*0j`MGeHP!KR(o6bm-|Vk?5>#DkCjFW^gZU zWMJrSNo^#@_P4%%6?Mwr*N)T@|u6X|5cve zpsy%|e1zb&{8gS75|j`Rg_l3P-@m;cj$w{Zl{o0-cwr+~3S*GD6OHS)^F2|J{ks;& zPB`|^#oAqeG+&V(?V7^f2kncJyI*W+MIBdQkW+|Sf)mH6jM&2gq=A1iSPEU@&s$Fhl3$WLjZCwW8cuw9QDNZ^cPoo5}QW2gCm zbipbswzkogDhg9JsX(?;;_y`03v8+o2E6ldh&YflL;WAbt!+TG zX`8_$TYfMMP|Z08(dm&Y3@a@B%)!aI!3TjbqA@ihLaMr$#i}}~M)GG=5p{Hw3)nb^ z?iCdkwOvHVT1)E_u3qGtjzK#J3Kw3;P?wZ(`f~yp+C@*i#@TlZudzdjvEngxK|6+@ ztXt;`-34TIt2gi6jsd<&@&T9L04hhJzHZVRE_T@?m2x)PAZDq`j8`INOMSy!KJD~A z!2i;$Adu|}{Ap&ifszyv@u8~97SmF|(@rt16SeE1XSu*OLF~CR$&e1IaL{{wW`E3F z2M*1~N%@nY5`3FoAC%)8wY{LlR)%Bo^Ed#$eyJP31{hF?)hH5rX|8M+ohA5a`9lU4eO(E*=SP>ikGLt%&LcP1sQkJ zlk@CP|Dn$~w-jQUYuB$MCxr&+GN!_5JE8-DQWpp)dJDzWkx?guk&1u&^5si=dkQ)S zw{NfBmj^LV&8e7_do5Jx4@pO25Gr!ynyk~upS`In%yDo&j z>dtxQb+kIl*lf=j$2^4~k4^qrjwXX>E4Zeuz6vJw-9^1WTFY)B2t7PtZG+KpY%WRl zGIq^w6m*O>N4<>woXyxd`Tr<;4|uHG_kEm}(Lkh9ND5h%Ro$}6sASJjNg*rIjSz|k zqD59@mAxgAQ9_|)&(I*ZQKankKi<^yJfH9L{rtYK|Ht$CJdZN&`+Z&4d7bBR9>;Me zyU53<pJMJkq0|W41Yp) zZfj`UtS}^#jSa0e-ORkb;aMl5)nT>? zh1Li3D6F(vZORYN5TBqvCy;Jy2Vrd$w;a}i-pPV5&_oI z&NFLwo+#kcg*50rdL#%w<=hM83g4z+_;!5#{#^vRgkuucMiX_)2fMQp(zRZzPS&+v z=<+V#S-f96k03dHW*#cOX;LZm`Jm4RsX}qH?dFGat#rw02D3$nD6@51I-ANXyQl6d zjxG{2#J{jOCb=cg(4Cy!?eR!KjfU*D)>8Tv(H~n2+aKaZfYWF}X5teNuv$=2T^`{g z%fUEqw|w-J34om%IK;ZquUCS~-kijx!<$hY(vyHf8Tev+Ge+uy%uq2GO# zjU~cTF=dfTGO#ux>APl*x5|F0j#05DZc^i|3H7atYPQK*WJ`mxN~h-~N+}@}Z7XQ| z4%HT!WY*Q^-l%jKRcf42?opda@|V>qq+b0#=ToE}Avoc@Zcqhs2TH?s43}EqJrmC? zam^ooPtzHB2+a^;M>^kPT9rmXNC=;7<(d?%sA~ zBiOivhnIG0E5yUWXm2U1kNZLn>`%fxVzs(eLE#^8a8MI<$#>)%N8QVG3~DqX-CXO| zn6?xA4XE05RmgFVA6K}9%4=|s?L!+$y8h^o0RIZ_7iY86b;!`uFm3)&+cxzhP9@@2 zWDB>z`*4+&baZLQ+mX1L8jdK%m{kVq*;uE5(_L5)mVSIZ(vmSEObNvn`X;514$q&r zcPV+F{_eZfz?rIJLxmeRw44wd8?~7QXRK#z3~~>21e8axb366s|q?47&Y<)ojS*8#X_@K)a8I<=mjf$t!$ysKd6 zz!7FPFfvJo?RsziR4o6Bt!)D`oTXHzcTnF>-u5WivgXmoZkb&Ff0J5$&hD}Oophl$iU2CYEA?Sv``wCjTi z_h?x`@7Om}sFl1MF%_@VD((>2%~Y=xdJCs{+1WQK%CD-D$@Un3=+KUtpH&Fv<_3e^6lT zyg8)u183Zg^qSDYou1BJ_YKV4cMl5(K+VE&Ua{trk=)eBm(d&?=VD;0xtTGRaoV=N zoZH#8`jx!2xrC&S-h>>z&rx8g0B+gZ zQ-2@VI4gDSx-;NGU<-MSO00KaslCxzwwA=E0OMC{ zAR7B3)vhT(9rgCW<+%%SNz&;YIh19hFOc`zU5C>E67UpiqTszWIRa;5_$*`hAHmt?vAj(6_)y)xwa<{94LW{C(?jXG$dPETD)Z}EN$)u1So7K zE|;JnRu-0RMK9sVrqwsr9*<5rW7>1&?IRi9*auSErA}AHy}MaDQX3vj{bw#)ZW&lYcoS|J)F(My}SzNX!Lq0JZkPb1F{W{G4tM) z5)k*?s{-A_jLsu^bZ3jhs3vwTZ0)wU`<5%ph=e$FnfQidH+8Xe!5)w`5I6~$cgPKQ8TRTvH;#+PPHWiz= z<+fgdW|tbI;BzX=K}`Xygz(U`lXQQUNl-sS_Lo-n39E6kf?D&MMG*!s&F9|U;0F(q zTiwygMAjE`WkVI_Wd+7ufNMA`e2@#SO9n3*h}a5SB!2pWK*3o&&Z5JQ4IUWw0tx~z zP71{?aj#*6_0gFjFX(A){^-csZOQJCn`xF_dUhr#c_08B9dBvS0(vNpk5kl>oAa5E zD>aN(U5A+Y5`qEdQbq|}pW;q$wK-mx_0)alJug4xWSfH9m>!Ss8~G;u$|E-W0~fT^ ztzU=lM%aTCKOL#YYke%`soKGqQ-{)$Ws<^Tw6gU~3Xmnfnb>vqH5rj zdnLMX^dn$=KcdD^<>q1GpPhEKzwdV18cLGecT&B_+Y`E^`}vL|88M>c zE#@XN%0Wf(3lFi$Myimwuxp~<`_6ewB#q}JvTKa-S`4hs%Rl?$tv$O@-a++spwiFH z*!BNKrPpCPl>@%%>Vx*jXEns-$)Li3+1beXTEOFBmI;XS#{EnYmAl!V2^>Uje*Pa1 zvBIH;Xa_BBe}TUk&d7keJFbT8I#q(MY0plo%RXkI72Z)vhYlS&?=B1SPnq*5_OGtU zG)Sts?aoy}uOkEw?JTDY>%IdJm)}M606yNZ z8YuMQ;)iCXGKN%t$W%VQjVZ@Bgb<0o`%4{Xj8UnPv`vkMyGbXzaC&Z8HB~>K_!-SE z8Qd}T&GoqCZguigi!XNF?Z>xXhbmM40m{7NyBj#2bIuJ6=~N88hD;SQ;o#d;10<7d zGnLY(5K-uQY=-+oeAUa1(#v#eck~-RIlpdtUV2EmHtK@82Lr>NeR%~S_et$Wf>JzRs1`wTq`!8cSg`?2&Q)N~C6W}EI+=P?8rXypR_^0Asl8yH zX_l7U|I@d^+m90pvN`nlEqr1`;lUhZZ)~y9;oYkcZ)(={R`K2I#En-Umn+2gE3k!- zu;<{vh5qsx)Piua0ev!lUQ@|qOkANCb;7#`&!s1>tQqJm^zs$v2pok1&}o2mqFK$k zp}mM(u5)GIqOPvTRyrxaYJQq~n+>NfS=eB|)<8#alG3jQI++Z|8IZsr-qXAQX~*cx z+X)SmPJ`PtT2TYd7Q({tBreXZWRc7e#FKW$M>e^Xs!0fDxDabO9UD5JH0ykg zBHvFS4&JJ1+Ib?p>%mWZi9WiZ4|;2X?V#NNW#ZTRH><2QIz%1K(NUu4mgmi)t3A93 z*MT)KQhZ*CS9_8@0!VG00cti_tyjH&ZwnvWkz1-7iSsfqfE`uF3P*ZmlFYu!fTLYF z+GK^JLQ9LsX+-?Mkm$dd6g=D}L`!@_D$yFveiDv$7KT@D0_c#i&w1og7IjR(flKx& zB|tB!4$I4FN2~iCA&=;_tSb5!IOn-9I^5y-D66XY0(fPj4XBffKwUO2j9x`fjudPK zL7>_tY_HP9aTJ&$-60l ziC7Z@Z`f2OZ2rqM#3HnHPqxNSJIfWs=-{IMc!8wM7EEaQ zKu~)K*m{w0ML0$9aFYP~Ktxc?qY~zwYy@Ex0K`k9je6VGU~vdm7y7He*K-%}{eo*m ze|SW=8Uq(Wcn~B+v;|T*V+*M{9j?GtMIgkG?7kp?kTR2WuO4Wf9~?iM;?zzDZ`Udij^!l<5jQ zM1+rJl{PoS9_aXq&rdPt#k4BO?2=M^XvEJ;;bE8*J9A4l@x=>~KOBc+AWNCA;C;a4 z`=6|zWXUDyy6!CebuT&DDw`%Gb3mRv@*Qp|KFb%hLEHXbzd!UJYlV1uXRr8;@4%}{wBdQ){fe!QmB_kXj5{@NFR+f0PVWPhMFDs*uGZ$Uvp zp_@=ziT;D}^*8$e`@v9U?DZpfKE!dN!n~P(_BeL!sojT``o$;VN6&CQH&-#D5UHMSOnk^{9{w7xaw!>mrO+ZKZ5tlVYH&^}5 z11Ek(y+7At{2<;c+LQ#r=S8^u?+SBaYZHI7_)72}*y?{iCl1qpd_Kwe|BEc8cOOv^ zV|hTuIJ#>MiVYrp{-FJi0k>q0j6Td9A==H8W>-U3zZQ8_hf1+e+;<{bj9qXY8pSU} zymkm5=E!OGzI99S1ry&&pXk5$wS4?O?jnWR)x_(hin<}<^e(UP|WX$s=PP>tBD*RH*zTHq>WJTdl_ zA$hBAWB>hJy=BS`O^=4`lDm}aee>q@aw?8{@PhHpeGl6DyIuy)_^&KMZ1esgL_XWQ ztd1s#`E6f4*k=32y}1^G%BAjwh7eVf6462Pz)UC0U8_A8BJQn$VaI1PU#FSd=LWKRx<5ve73koXwLqu0?{2 zOYZ06WVW-Z4VQE-@G8Pcmk3$Lnc5F1%Q80msgv2vy@_a7J%0+9F0SE`8?V;UmxYO2 zt?Ft5U&8u+K)`9^!pu|rvtsu{j)DPUJ^l58ZGT%TKky=qo-bVr)db{k?mPlVU`-Z&!HY1g$=(gWwyL(#R9;SPUyyUO0cgCEHxB>`_Qd zJ6Z}HV{%U}$*L1u}r(6E24vz$Gj1>gqzjxwh60NHl!> zEHwu)-gRfe@B#3jdbr<1Bl}}`_)S%nmauKxlSJ4`t==TD8MYZH)B@jE(X3bjHQmkC zgt(wqP(ngCJHVa+6edPDI7GknX5uc@K=)oC2n;q@M+-k-U!*EAAOD-Fq`jxPjoMU3 z{6>n0E!3sVZdl{urnID@Fv!iGJK5IiWC}1TKAxFHpMS-w4K*NV{kR8D>Xe2y{cKx< zTpfjMxtU%Ab3ph=~eqHUlo4j4@Qhb3zHhbl>O!~oTsv*u=IBZrqPu$32{ zR4ttccHkFrq1t2G+TDYLf)a_xpO3+3zdBN8CqE{mj&=vA`Bwh;@*3-_(eSIk(W<{8 z5kS-UA5Kqz$zPnFug9<0x0aVH4$4a>2@W+gzqTinS(33O+-66c;k7?1nFZ1jqN?|- zcMsMW9FeMr?;|Ajo`98khv6dxvg)hA7toDXCzx?Aq^LHv9IoK!gd>;3V2ehhn|i4K`_u#OF`(RCBf# z0W1MMiTO%hWa*nXZ}J!zZ8euF^kR*8WMm(<6V1_RpNN~by_e>O?JUjy;!MVYCtIzy z#B|?p+N9P>;Hs?mmnv_vMP>LAU3)c|*(chE&;x|%dn!QUXoca2k&eW-5&W^9?jv=_+2?d>W zpES)ZfHuY1Dycu!8M@wvdg>haq&0aT3WWf_yuZ*@sRyIGgPHx`zD0zF=Gpfg$=nPg z#PLVg`_QuNDSVR8mOQF5@YFI!%gU>=TU)OSO+D_QfyQJf%&j_jkMi+j%`i3iTq5dZ zUylxssG04pN?at+=nS?8)z3(K2u^-!urB#+8)vm`!8Q)DQ1=0)duE$@5c9!*wj#HZ zax%~^<9&GXz?^DK+%d3^0-vak{4f{ap^Gu<;^Xln(VCrCc5ERwbPKzrg=A|0!c_NW;RMlbh+o^!F;kVPOT=yv~o0$3Z1>OGbtP6}x zf;LV=WGPVjrB~ckeF-nQ9`4Q~JDyrK3uh8D+b69@5UI;}!{S&T$aoZiX}F1>_l<-+ z*&TdCd-ref3}IQn9^=AdMgHa@ofG-ZMJfhFX8#7S73xLXtEl93=9a|qo5%zGvVv{= z*=#r#O8M(d$2ov_bfO}>zrP*mn!Fomcs>1y=_;yZ-9~1Ru;(hbEcjFs#Hg)*UmHZC z-SmiJ1gCmzUSzC+(1ii3eR^Mua_IEvhYRm*f?Z3NaG9dVW@{k(!Q;E3r%`0ui{ffl2B6N6bG2W=*#`Wt^QR@31l8U(i zn0jbd0n{H5!1!}fJpKJC&}g63BpyP2 zqfVn9#Qh{PWee=%ZG>XB@hcnxKk0G%x(Aq#_@?U_BC{wvo}Z7hL?&9OS$Gc1H;JozTz@tC{xqr(J4T_8;Pou=>h{zsbrq7GvYVgh~!$R1N&<&QM!PqOYy z*|x~6|8HWLtt1%j@Zz4Wwt-Yhe~}a@&x`f@+nyGma{Zz2zbx6gW_sKM*6*=96b;M$ zHp(&5#tA~wNlYUmZ|(b?E{d_Dx&(Bx$oofDjFSN>3sM2$=`XzC8_o0-dZ=;i{;Y7& z2%^Z)rrup4@~hx?MASPs%UcMxtUknxvf#eNohW@i+GOkeUPh)H8c0PX{(>}rfg6A2 zQ1sU{izqDfos+W@A73to?-k1Ch58PRB8w#$beEKn@a8JX!uW=*%;gzE6hmMok4qq* zH7xE~y`kphZIqJ>Yf9_~^L2!#7|a;(QbhOfzf^H=`*m9kv18x3(Zcu(ESHb!eyUfK z@xOKJVTylD%+}hAh>4XpXkf_~&VDRRZL=?(Q?4TNV?{YX=fD zC@ei_#EpNO9*jPCoC!b{Q9NM{+y#W@u^PU zX%D{IeYm!qoW}3nTbl_D*hlK6D~46iG;FJ_`^Uwt;4$WZ5&=FZJ%cac`$p$<{!69F z#h0c##!qh0`Styu7NOCKq$mNNup!+(68IP(501RP_V06$GHC=0i<3sKNO|9Oc1p|0 z5CjgWaL`tEbaK*@J_RcN+Rd90B|E?sLZR~J$h#n|xT7GD+rd(IWCZHUh>4=@TN&4{ zk9XOdBQY{058YA%M$~l_y5@%MfjDAqdUcq%aw86o6rc zOqu6~bP*Oz-vyB!g6D4H*)M2nWXWur1%-uMxnBund>Y(mtMYIrDeKXtd=ZjMfu(;I z3#+MbxzB^So9uhu%4UtYX;3V9B)BTQL-#1Kl&2yBq zKbYscKUX-%BlyhZl|cGB%OxZoy60_j=DFvD5lvjC%g(jUY>(JfwtY|XU9I4i(_thB4e zor-+;K^-H*5tjb(cp3$35=p+Acmv5lLF&+s-%mgLm@Z6Sn||=#$+I&OHiFwp%9pF{ zukpHBJ6x$A(NxeWasRSWfS#?IX6wt!9!@;g9TDH+Sr^N@#lL2I+FRCv=~h~^Bt1G zD-j9x`_>;@V@{YMfBnkC!z0EP$<L~U?!)yHFm&6j=m^1z$hy- z6Hc6BA|eL)n?rBJjot>4D*zNqfwsvgzZmP)z9cqfURKfPh_x&GQ zeMpjfTQ-wsygp{m*!SKRz0kFyoz*j~Rml&G(#);eU0O26mq&9%TucFx ztP$;a+3alTV@_*n7`}HTXe{MFc*AAhZhV#b%H=#ZcUwY?j^)2CmRowzK-z88l(N6C z?^)NI=R<9F@$@+tFOtnhLt4)7$z8M7xqH4+`-gn~@Ld`S?xbTLH=@}-aY=A5!D?O= zGw5GIDl6qB4+d3ud(-xud;It@RHoQjC`JOXk*t~_g5~FQ$1sXCnPP_Ljk`re?sbHg znR`RK!wwr&BjI@Ix=;7%NZU!tOGw*2S(Zfr7>S(=;8lY_N!XPMQY_Y-J6BR(A=8xO z1ZHq8l5UwrU=lm|fO?*6Jf8PJaQmuTYTh%+AAMtEQ-k$#FYK^$cQ1;IQ*4M%*!%8H z!jJ9>?s`#G4(TlMc@6&d5{10pp+4ThZ|!5>raN1^Lu4-8Th5^U!f<9zaD$Casp5=vG^2GFzcqVh+I>0`_;JfxQT{U-$YcX}+$K(Ix3~^D zG}R_fcc%-OhVg`8Wy@m1q&voIzbK0-zzt*NNu%}3T8I0D%zGUh=08Rc-QL{s^`mj@ zs!_gsP?J5eY3DyRUmmHZq~XzYqb>2ARXd4C;*#xKCvAANpS~UX({{(YCx@($&J~0n zi@&i7VvL;SLSxmO=8xjPxN~z$Q(nhiyyG-?GX1{e&kb&yNevG)w|v^L=fKPQWK)-z zhf&O)VoH{@q{jNKv{B4UDBA052n+`qk&O*8GZHca%sqJf_ALy|;rt1=H~35<>b#SJzE!Y+&`OnjpL-BiD+Xj|D)hD@X}kquE*xPNInK8YnOK?x9sEf(}Gi z=F-HjydT4#4$d6if>-O=u#xQI>SR7Ddbl=SV#BIXHZH-gf#UWwpnl8!5M48vG zf1X{j`-6t3)H;q!tot+Gn!oDkkSx0B?A2ct1g5yl+6y}}l*4Ya9x(kyxnk;B%_xVeT6MW;d!L_Rt> zrhZL2YizX3U6nK7eHp)(s_D(ra&7(Qz#Xw?=~9HH*vB`u7M)%_t5!oWB#5ndGN-M5?@@(cj?diEyF+U~Rgn}t#!xRr=%wo}7P3aD)tv=pW z;O^?@3|^joD|_Ls-GWvFLFp&Y)rfQ~y>#Hwf#)B$n27qC4x4HiM35X<1w-O|Ej(K_XblDV*(37P zA9}SuJ8IzU${{ z?T{;1=D@bw=HmFR|82){zKc<054p43nRM1+X z=kodqe-p33_2d)zGbh>1XLBQyO~Q;FCr&BLi#zmFPQB`kznE~lwBprgpU&)uZmSHR zAKKX8@lN$##hC}WSMAdkP2E%Zbubzb+NNd2*8)@P~4e&$mP}cB=b^;$K8HU8h#dckKJdt zO9U@@jtDtD{);)~eEXY%?G)|p1%}$sr2)e8z5Z z@u|5R_s8ek}&o>~(p?UWr*DW)PQIg{}?mj9AnNBi^V z(b3edMTXYp2sX8u@yt%Poog+Pqju7clAIhxb~~HD^t5<&V?0$)?Icft2KVZ^r2G5W zT}RvG*ix0(_co;pwUn!vdj9oj>5lEb(eeCz%hW8?$On5})KXva(Ke ztf?rbx^9{O+q?woUyOzUxOfYQ)|93aY1%WYzOyJbvTL3z!bv+Gf>mS@8= zN{K>-Va4uw{;KIG&b5xaGYwRn(|eM!tG=np*LxL{r23~Z#kArByKuWUGzTlcef&ar zetcHqTjfg9t0rNW?BNrvkDXoei`++53LjU^B-WOfADPs5Km6P|<+KtFt7Wzs51zJw zgm(xReN;BWtfHcSMfi%GK%AQjv^j2k$fQ$x>$NcS9r6Z3s?U=_tuE{YYrW@(Zp+lsU9`r>Q}e!QLjpBY^AJfV``5RKWZj1P z(e=|wYSffvkGyUy9$qRB{hi+_rOvc88J2=HPe0yLP55d793I@6tel*l7E|;F(61T8 zu*CY@Um8>MbIU058uKIdSKht6Dg9%VeZP72qk5m`jgChztIo(>*Px2nn@&X%Ur#n6 zYKiV8RyUUFiwDJqJ~bBInozQXm}b23GuhtWAkzd0Fk3Tq6!UV0r7I=4HO*fp7<~MX znDD#mv#eEH&!Q}@@) zlf~pF(IDZK@^W&CeWpO?@LTW`@Nw*MiJ3fA#GB{0O#V)rr|O}1*En~+ zy|fgyRJiM~I`R!dySY)VgD+U_`daF1&%6?Q9-F}@peKPkK5#U=kF>a zJz{O#^6B+T(Z-GB&ofsw!oEbad8#@{;)$Y0rlUucHU4&<>QBjxH$L&B1P?ykm2u&v z*Z3%_|9Xt|wIDnU!^A8~Es_dBeJ*ei1? z@askIcizMcEk^ajSumoD{Es z*S@Ugm{es|RXg<1fCf}fLcD(b4I7qg;k7ON>-TNLsC`1QNeM!lZKxUj7B6YsHkdtn?tcs875xNIV)MVY@ zrnKW#Z_Kdsk2;5mnya2Y%cs-wwJaw~wf9u&N$&m}=^cJ?=F?h#Ucwjo)rgo9_7R)idHwc3Wq`#2WP!(~CecjHp^@E2b& zB1;+;Rz1S@acYt0Y;2AX3{e`of2s$tCzvLeTNtghP8^dYZKU-Q(|RLaM`IBdsgC$}A}Moo3lf4)pBWEK8S}{U3SQIr{VTGq7chmK zcM2y?bfW6QNCG>K5`@^QD?&MI$tIhYsjz0<{v{V?#v{R9l1IZJj+a104%#{+oN~rx z7JG>`LcN1`&UNU*qw7&xQbNerqT5!HFx}$`8xj0;)4yX33xWXSG94e6@$akuN=_KH zUn0H3mk|FX7+|CSwU2f~tva>v?Q`R9=P;E*%^z7(ozj~Zrd zWV$+d@DS(QtB-flC*}RMsDB;qKkX;2G51OkOS0t*XP=ib&)*N1 zK(2QFd39HW5SxV8a6Mu$JCMPm`10W5p0;24fJyGpt6GdwfB&Y0uP%Si?7|ajSiTTS z@gQ>O{+vuaQzEt!&z3lczYpZ%L0kB<#dt`p75-URGyHq8ya_sptnYwuhU4DLI;Z!A zSs=`N-f^St^9sc)loM}0NQ4-=njKMK0?~8+#G`kc`V|Ulx7cXFg9q(mw0SjyIT-qN z$-x2LQ@LbuwH)ilu+UNiGiBHecqZxmDrWWEqOy+IK?{%W;zW=O`dxh7kFR; zo1!s%HStb1F(YTFczzD5>usvMmXD;-=q0wn;$^$ACl)h^`I7+tJ_PCbvx$dEySeD< zHf^fkEMZ`2$*+HEbt5<#u=uO4rU^Yd22uJ-2`FBD`cY4Ib53`<4r%1(uDa|&?-QYl z$-fQKR!xF<)L(zB+8kdAQRG>w>-?ajEz}3R?eOY%Ew0Si( z!*A|#_pnd;Go&m@ykOm&l|+mn9ZUw=f=P+u zmJQxhV1ZrvqJjrF2-y>^gMff~B~G^n^qEnAXQt;nemlaMe*C%OC~r=vdq6WI7I^zMLr#r6cu7$5q6mjWzhCSQPFO0Gp|PWGj4r_t ztR~20F&V14%a_1W@@YEc^`>V81AzwHbJd0!Gp{9YcmQAT>wJgKUs|4d)&uQl+>@|N zxd?wO!2D|`V*;*BDap&L&z4+UsSQGp@hoU0uRu$=EHeSs%!VQ`A;QUDz-R*@O6eQ; zWu`(v4P$RZ;oZxy*Ktrk?C#vu`MLVnup;#-8$tR)Cb>`st_ss4K zUkJp|29v=`v)A5v-!Z+cy8P6ifWLTL^{4-l9wjkQ_FtM9hOl7us#Q;Na?os0{RXuw zAr&_;An*Q)=7bwOo!-y}-@VJ^HrSlr6(8w-i795OJMt%D%XflPk(c(Yfpc|3lDej%h&z-1r%{d}KaDQV7sq+3*l ziG@YmaDF7A*b-Hss87z@AWNDE?7(M=b^2V>hd7ssp4#E(c_W8`h$PF2to2<~z+q)& z0Tl8%U=7|f7#tjgZdl^nheHlTi({?`QqoKtb9l;>$?_({+xM0SZ&YES)R&~0Ijg1= z4ex$Xo8eKy<+g6~=9EiYUYU~xBcH8i6FX!gTj$i}rgX9~{bc0x<(j)z{N9Ep*ZGv4 zFZG;-JY673ElkX(f6&4%)7c^u9B|QHyCzUsJSX=Z*kN`98!}_ls&(Z6u5gEUv`*Gw zD+1KaEXS~py4N6(85La${nP-wir>$1s8dSuG$`Dlg}c$a!*#Ci=DKAO_*6=VP3$aC z(4{@uX(QF4^tG71(Rjmt$zQ3>zwXiOAg}77qUq}L^6MS8Z`xppRAnRm>dd)w)g9|7 z-@gk_Je8MzOwbl3hYDV;*eG_Ev0c)Tk!=6`9ZX!X-a+D7y|xAp>R1(U^x=nmOLIp;dJ2-{SXnB2pl*O2S6|LE^+ZHOYM6hrQ00X>TX1Q_i zdE;c=)Y58S#Dr{hq^#T72p3#Vi+-51Y}&8^N13zo;BGcaM4}Y}tpiK8u?o)K?}lJRsu0D!gI6h=kJ?zDD!3OPiDLhu_?9n!_cCC-Ye9~I$7)vqNaYH z{q`>=aOgOT0qi-Lmyi$eZcyXwxpbRb8%@p35P%6I2yku@jT;W}ZoQEJ-oOhFshA}c zbUq*Z;(a$Fvb;S(Um>##6ac#~<-hDuCBk7)uo^!LPvd(6>?FX>y(a7fI5+8%cT0(m zpUU9*-3M7@K_Dd1Hs`~rc24hc&CkorOm%H}Jv%)vuxbvsCB7j{up`H6y+a&PDR}y) zc)+hTElqfn|8{M4#IiGPl%2;ziG7drQs3Mh?*eko^;H{76u)>?A0e4ra`wz@dcbsw z$mx5n{#)#ga9LVYF&26%N|c-1i#iIF?3&kzG!C#4;0egQ;R%w^n>CZzc&RBV{mtnz zXWlT5>B^r|+q7`YuQs)?sMy6PuKI9)XyNf6pg5s-7^{e(eC{5Od)a$Fe=g}Phn1l9 zidq=(C13i8jf}zf8;31FJlpMR{&?gveN1diebXSvE94sV99y5AZ#>N`X;j0gy7r4e zukuFnk?xykFm|*s*cjk}HZgnm+_|)pkH21fvR8kv-@MyoS;PiU{|{VnQ8Yhq^m+4X zC#^bPET+y^lgX9c&1mQLH>E0bf`;0<=BxFWs7h&b%Z)w1D?cL9NJ3UFB}82JDJyD@ z#eIjp*5rt(G>ar|Bak)}??Z7Ra_AS4zi_ysR6s7mmkStf2ht_$a_|tdd(-j9(*xZdl;b1+S7kKxs++Bh5iaM+((pr`=tQVEP|D$W~$)2?e7xCjEsDIiTDF3BBx!~sG zT@!ve{O?2A3a1ycs)aOqG1Er29iPz>(2Oi#@ar=~i2HP_xegtCbp1KQzf$cc?V5d- z4GC`d6A^waN4hJJ!1lH04uR%uVq!8T$N0pS(>0D`+#Y4lpCrA8?k1p`m1NycR5{CZ zf*T_3QF|>Ej5F-*Th2ZurkHyYx%$gjZ8RhTku)C_5EFY+@*0tN-*#90ir0;5;B@R; z!?ixgViWkgbjcXI@(0nd^2o9?y|oBwECLaK z#Vo~_%YG++D3xgQUbKCp()F+3uvjSlmF?3mKrwU#?18UwrmgYm*;0jqxU{5<>+hOi z@vDw~O7gQ|ZrIn_BDM7Q&+B=?Do!2IvO+H4pLw@*jSqoiSjFG5CN{^PY|vATo+yco zPf|sMg$zRUwydBDcOk)C*3>L%!$dlmCy79}04w0S<)<7SC7j+Me}Wg_O0;86p6o*6 zrlo9bY<&67gwjH>gi>nZ-@gl}nq$YHf`)9naeAn@3rGmPJGOd5NKjBymZ`FqRy{aU zn2@JIgCLDtaViP96?luVHiw=XsU_LYF1j3a?c0}xl$EQ%HSwQOLiY45{5opif2Gt( zR1s*}?&b~wm)Zh`+l?3rfv7n9>leAH7t9ni^l>GggMkv#=+wJ%YHM?bmC)ATyxLRw zEb(0al-0kptxk4!;J~y#v*T`r z4eQGxM-)buMljy*O6RnX@A8|;!TrCYhVFTPk?&NTnPI;{MUp#=+L)@w=fbA{_Vc8o0$i1Nwa_z< zj*d=F7AW2gV=P0%Y5bg-ay*k77w)ZF|IZ(EObS4TNmRfSFvL-b;S%4E_yA`*u#fWd z^D**+&J8^K%;Di-KR-XnabOOiDLH$Uij+M2;nl+7>v<8xwv3dy+LLGHf8ZI+1ZLKx z+E{u9WDQMy{Sds)Caa2`k?qPsAWCaZBZHzgemg&lQKBCI|dkZaAr&rvl z$y;0JW08+ypTP?;f=gBP*Il;ktgQ2is}?W?0;2gx>ACRPzY5a-_*48XRRr4_B6cl; zDcBZb^{m)nT+@toGz}&zalBCebPanGKOD=+3 znqIQz#>QLH?uzLWfZWTY`t-3MPkmb&(eHR-5%M^K2^r@Q7uT}G*bW?`PLTtd$1v6b z6~T0nm)@bP>%`6Of4W?$FHXyZpJ~Uol>B+^%70)9i|8vg$?C1k`=X%!DA*5IqxMc> z&=;<01&<6-prB`@$}fZeb;|GswYQy>`Z@h{%eg$40*zjP?*5hEGDl@6H5(cjRL-{` zcSe$uNK1lW!;>dZ;9DxNyQt)H&yon+ojO}n{C2N1a?8G;W_?HGo7)$i;varVn`sZA zyZ3ioJu3SL%=*n5GRDb|Lz0RV#1LNTb#)>UCJG+1?56310V6AG`BVyKqGH&npg4b$AgFkEepB(5Q}MIXskGtdL69P3VnEW6vIZ`f zrU;52cv%k9H`H~zx8N?}38+9Kv3)PkN_nA<;%(qNHv7mSN;PTo_Ev>yDFNSUshnmZ3nAx?mj>iqfh7iT7RdpJr{v~OMY zjDG_(>%|m2(|*du^E1&)fKBn{OcrinO{pzgq98>wNjAIU?CPrgEbQLB1NTv7^lVu! z7yoffQhPEZ*Cv16=sTVwuUM5?Jrw(v{`0N;0ili{OMlMy5obAPUa1xUqcRw6O>bx- zWM+Q_gobXMAFF_-8F??;Q`Drmj@ECpLvFYS|J%JgI&m^eOG)X*8kAqLOZ>igsrDQ~ z39F)Hr>;g#PTCM{92*}W9~`WQ(g7TeBEVEWIzN{(lkYRVfCm%$(`A~mzJ--cS+#I1 z3zUl|x0qCXe$VH)1rhOIiG+g5_-7D*_@020MTGUF%hk{>V|x4HPs6xM;bpgUsTYi7 zb}(FoRp9r|@|qfTX$t6g{g_X5_ELW=iSo9(I;i3d#z>#~25Rb8FV%J2EY=^2+$8-8 zL6V!B+gSLsmXMhj%Z|f>NJRX5YxWH{c$^4vl0h)b8Uua#=MY6(RV8$cUhyIrW^De# zgJ2bW^jmn@O#J_P*~j{DMS0Bs>__P^0NfR46Tpv|nb|)GOD7j-lnR$F?H~Vv9uO`s zfHoMyg0Dgndg|K@HK^Th9>dQF^$Y$S*^89($khiuFnsRp?1Z)owY?S-`5wvXyS0hQ zf%R#q8PfIAA0Fiq(7S4KO2%WZ;MA+@EZ?ruF;5ij@JnP22}vfiqz11A(sIVw_{EiK zRG`oE^EGpiWt(YmFOBf@N-#+`zA6^x<>i%_*v9}EtvAvGg6AQKh?1@f1qsginGB?6 zbsc}V77Y%2fMC^KxJ1qVmrGQ)_`tz~;{2^91Ml9v!A%^MVJdPgR?#2Sla|$&@jTFU z8Pt__b#;}Ik!kY4z!4OvDeirB+w+X(K&n6Y1cx`ry7k_5piv+UHN)lSnIwH4^-W*j z{ZdjEGDb3A9ujmB<*`krq`NBiUtOF?|5QSjPTvtzF}|Cq1B zMZ)ZdU2<+92TIa0JdmWdPxZ4{%vg+U@6Ud>3=*rqV(`>5ygcW{{{>hj=0yecA*qFg zb0%nki6i)QPi{z%@bP|JuOA*pM!xS-IduL7KmzcdlJ+}~$mjiRPXJ(vCb}&nj#YoM zZdoIeu@8l=!S>O^TWf=Np8VR=leqU#=-3hY5P%;NcT4>|D>S7K1~M%BKd#XgDNd!{ zOju+uQp!0XMsibA!DYsm$P>?O{4a@}kHAlR3XlbK z8AnD(BSg(_O%?OrvcG%p-UuAqsjt0Q?2-MiJ)PWjL?2~k3i}$AS+~sEJl}ca&L>)L z=nbjA8)YO?GC=)z#rCx_z_Z$AlwWw1fYcY$F3&B8VrAo943>>8ukkq(oQhzMX|?>h zdi~103&8t-ruL|c4YHwKYpaDIp*KXLGEz&`qM{NZZpFI% zJ+(@v;~Mfkc)NZ2`c;wJwl%Bl#f!^JBhZ#WsYz3lQn^^nIXDQ>fXeZh$5Zu|gYK+b zM9Z>R#g)H1eZ{9mW5UiOL$=&XkH6I zE6=6U6Q-KS68yosqpbu7e(%L{kRrh~^2`o|I>PjjEoaD+)0S&Ui7X4-RXt;&N?X{c z(@BX@sPuk!lKXQ{RvSv^cP?rX8a9(bZ>p_LR8|mfb`9~!G?6nm6;pA}07Fx9c4Cs}+a4qnQ*q&Kl>*4cK)oXStrdw$?dY9X6|9(=o%TeoR4-9FN zFrP zwHW|^vbTn7b&l~%v9Piivh!dVidpwotBS>WdA*B%C6ln$Z-lE-Oo-fbsXqfE0I{9( z(YBch+I|vW#u7UVJ4Szzg@hgq`A^@d*>cl`FR_=dP`84P9;PU(6R#}XhRxO?IugpFa|Mi^XTDRvH zD~_7dBybc^n0vCl_nSLIQHA-63}?44A4xDVHht(&d4ra1>jnmg2O_2{d#05*{U^Eu ze&}46Te@^<^2d@`OS3BrJ!7s7Iya@X57s1}>s<$|kyqBdHQ)KC8T_}%kvAAP(cfIh z$DFVdSWVa}Vy^Ya{wZM{Fly(UtsZymSLD30X7r(0-$Ci*DXH13g>LOdZe5ZOHvcqN z6`4L_Xqc=P`MuV)$*I5lP5F);g*}5GZWWO(Ql`0;a`)|RIZwI6h6s>8^l{?q8_+$4 z7(xprT{;@AXgWTS0RAi7Hx6XbSP=nRg;*s9L4H-M&JPV0iR?~J4~@0?6{q!Hu2WJn z#9H-geui91Ma4g1smiG{4Hrkc@AhrvW#DWLo9EL>(HN9g(jgfh%hCTiYEJMokr;js zJ-ZwfVQ=HG7BVQo5JC?Z4DU(mIwW}{S<=~3&#pqH=kX2}+oA7gl;`K9j**s`-#zp$ z_I2=C--lAqS&N>fg^Rq*_71n`DpG+CdF`0(%p{qm=g_dKq0SP4pD9{<s+k7N`XrIHbn zM7WTVy|S|^qsYh>qDU^g?CpEM=$!XC@6YG+yWM`L+xh35(sezbuh;YWc-$ZN;k$-( z|2pF~UKTQF@SBPyVYnf+Wfd_9dy$C##^jiR8NQ`StJ-kN1TE zO1xIx4@DhptgffoPs}{|$~x?7NSUw6>sWH4Uu|pLZuRGe#CI&NZti9Nw(Nd2t)BwM z*q#E@YU8mOjcXFG-ow@ZFB&^{Pk%1}@E>QOCKG{!YabA@!UYrVviMa*}0kn9k zDOy61YXO{+k(O48Fs9jilzdZuiWiC)m+Z91Fb9n1oeU%z1`&No2G(u7HQX`j?Wfoi z*_{c(`gD_8;=R3*dS;}B2e%|`J`_*hzzP22$NBSeoyJX-p)9c{?kS2%U1@~@O`Q#N zY#3NY7}lmJ8!GJal8({Kq+XZR5RI|$m1{RA2ph|ik~Lq2Z2fHRr01W=6%r;x;4)`5XP*B734w5vCv%j@;tv|*M|P?`?G3ppfcGUcaGZ z#XBfJZkYZ#%fngqM#81DfTP}9k97Vu?wdo}r=&rtXMIQpU^L?A}MWA`?>vJ4*= z_Xw8VzeZE zZr~5iO-(>l1RZD6PLL+ZEPgiumzwe5RX28{ux8FxKm)#o|mF!a~<4G-&|dNl#A<8Q%jOY z&$n-H&*vat$i>A4Wt6P!d$<5^mf0q`i_PX<>>AQ`G70@%c{W$7QY?j&$PJs2uZvI2 z+thDpKHqkLlk?~$K5Og2>(J+5Q8sRzb0uAegsG8v&bG3rAYHtIOJxv-I=$Ko)|BkCZp5rfy zzT{Y*I*lZIKn;;7C)cTwcDe26H>bg-hQNxeTWjKW2YDJYF7M(wRoczLDIe8Qm)59L zcKcNi6Ehi&PN2Mqt1xU28HWb)kA@!pCCcjRA3m{Y>yxF50}wX@_W=xKjdiJudU%5L zeE8ppW8xd3M{VgSyXcJ7X%Ps zMsG9FSb;ofp-Z0_HoGcsA_k@|NV!BUEQ%Yz*}>-cNsD((G_iV?UCp(%f%%p-@7~G5 z0qG0X`(=~K;0JSaH%1D>Z{#s~8((X3bs42EUj7)#heKvA0R)V5fwK+ixP0s1x--7p zG5GZ|uk*r%2R8+SLjn;0kdMOYoXbzF(=K}2u;s&9*Unkbp~z}T45ZHw zQAksKah)}>{&}QcZBWMULPOEAv~I7w-EOC&Jt`r@?BBJdDH#x0zVmX=OYXxWbJ-T! z=IpU{9opUt8kKVAAk_~a=b^7gOEzipAZWW_eR)G(lO+`AA{1P^;Uk@T)*s?jS-oOmO z>2y%S5EAV~fd|quuk3ndTWB_Z6W_k{k-NB{&3(T}sM7*CIl9AERwE4bUG425Sq($0wpL@?7HN>w$#S`D4j~SLKz>Cp`mh z*s9j;qG@0&@1+F6A|@e+bq=f?g#U z>i-;+@QZzhLlIhTV5~p^XJO%`-UBqK8ZlaOa&Uk-xPyRMg;51s>kAtJYW=MH2C!4d zT-^$2EGE`MbGh&nDGun|6#VolRECQVh8|>yGxiy%IYkbev}`iRJlWg=)(|^vo=TBn zhJ@YdV3p7B<2R8&2>Fj1Vn=$^J-I`WY^jR&OPPv(W+lhcF7HF$;9MXLse(CBdyjVx79GI1*kaXTLpU zZha5RSKWII#ukod{-X5WM?-V%@?}JSiOi9qp1_aD-wRM<<1qsqn%Ck00N@hMrwZxB zAOF0>&}s6=EZAJO{u!y@=(MT!Id8vBw?&pWJ9JRBV&gr<`}Uv}8ej$0mQ4R#^r?0? zc?W(~yhjB2gGN0$n%xPa902K`lgGAFsh^XR+wO#pSJZakX-G&22D+eImP)Y41MhG2 zPFX5l>T_FiAI(Sp0XJ5*^M z9a_A+8SuVIo09g@8U8*vI2Z!vK_YIO>k<-gP(L1Y8}2O3$Ka43P6}Q=N2zSaq7Kf^ z&trU`BU)P+Y(1(;>IyzuZ38XBr7J*q4j;~Xsl0J-I)={HhwansHwF!fg{WMo8+ z4~autLvF7#Ku%0-Y~P^wh5-PJau{-hLPhT7k(;8_*y7{y@SMqHi)ve1;wkGEVg%Rm>IgB0O@JQ zLsFTWx0e_1$&)W%AY{eJk-}yyRx`t3hxEsRt##mBg#-nynImf?B9v%8X=vRTpYdQ6 z5BG7HT2R~ZP!<)1R-S{zq}|i4+`s`m3K^(2L{R+(&Q{3HoM4Ftw z%H9Uw3PS)1<`rD$*%rd+qJ6f#b%Q~*oZNYDXEDYYf*~0k*njyz0F7={p~LW3`p3Zm ziGS$pm2?&P4)ne&yR~&j&%{;z;pn?SEBe&LdY$wbEwA1M!-J3+S00ZZ@PgEOqQB^C z5D>Z*P-lJADyXxT0LbLeN;)1rDJ?CA6|Ok+gpz$Pt96?bV|BG|WE6w~D3DH6{n6R^ z1>*|Yn| ztGBA^QB3jHC5Uh@R5vz~3a1HyLVrG>rjZ?KYqIaiWm$MOpT|KU*v3NwymOozlH(+^ zjhvea%ZsB|5;jG3#Cfs+3JT!WJQ@@E?pBW#nXLaCAN*StpLBrbGeD!@L)Sj#**tea zL5UxjoUG}*kKlXhghlwkmv(Ihg_inPvzH=?NC~PkFH&*z0O7#i5gzn>s4EIyi z*VbkX9<={v*+}Z?$@@O8k+iM}x6#t5%TCkQw4yxwhVvoC-`n!UTv?SKew7ZNnRhYM z8}o^Z8ve$r8E-W;^6FUtU-2##iX-ec;= z&A*>!Ubk)$Lb%N`G~v7YM>_o;@$>TLIrq3ru@?WN)if}K=G|eAZ9Aphv&&H-nh!1C zK|2e@-o#JRg3FmLVQ>j=J#?N9MrVXst)bvl@uin81J}14;PK&P4|-=)>9?)s$gRi(niYx0{x~puCNnn=Z3A3J z=A3lyu`w_pGM$K47;N5S=&wJrVD%EJxBv11FiSkpi&gF{uyyQBkeJ(aZTNMW9#MBs zjF3>4DRzCbU~2F!M2eB!d>f*rCo!Xv3!eA}#rSApi-v6Mh<|a)&w2L;l8j&sWA4sW zXy_Cx?~{@;da>tkBLSx5!P?NP%?;({CQyv?*^d8sNxk!CcvOb9Fx~gR<@+UfUaAX+ zC?4{koul~eS#U#{?*V$g3V+#`hM^*kS523ql+$I>L-wik%Pln|_%gN2_u^{c@hWws z;*~nCp|{Vhtx-_$)<)suhmC?EaJFCpbs6p7!gOpkH9KQ#deo_oq8(2uVQ!M-TbkaX zk&d={gk-Ch%4lOf_$f-3wzuly-lvB&+nXU@y{%sq1s^lU+dHxH3gOy4sz-D8^jj$l zy`_Gsu4-iHmz%PsqM6!bt-)qLGcgl;QI~Hx9qM8p&e%) zesYOtVi37E0PH1BemTZL>Zca|1+FH&4L>2x0>%R z7?yxUD;=XL5IFWyp=#ILs~*=b{GmEE+U5UwvQCyYSU|vO;roduR)LfVtG#y08*E;U zq12xpkENrdJ8XEeKTwo!|22#mmxuc%cxJVd{tT|v@|qA#2)*pu@Qamp{6aOe_CvDJ zhfL-m|H^n}GnI9R6aR^Gi_J*Kc;&zb?~&pBUx@4~v`ON?ygFF@^-dWchx*QD_dprDJyJ@Uhk7V9{v@#N&c zd!(mGJmZ<2ZE;3-aS}n4?dGrx!eoWi@bK}9LM5U zS`pR&4jL`=#wg0THxo22bM#H8`&RVn_3Jl|WbGcEd#Zlu(<3^b#pj$P?mvlN04WR`>pIp!{t zJ1YTOloHs(?3+HkiQ$YGukT&HxC}dk6u3v<*t?s-Ghdo-^xFne(JzWo8y$c3il~B~ zVD{-v+Sh)SlWG%TlSziHZPMF~JhP7UoPHbEs{I^*(7wH-+7JQh*NWSpow=#Hk(dyx z@NQ*y(~OmR-n>~(nQ0jtB?Bp^lxASv`;o!gko)37tf|Q&E#2=I3 zZ$*owC|@y11cCm}AW!mV*YeU$(2`N`3Rrel5irOOp{Q$U$jHomfJe_~gKpEJrAKY!Ogdjx83BhcZ?@>%eRdL}^1M7-L1J!* z7~NiywS-cV_O~BOy>Ve;`PnRb_6E(ym%N@o-;%F%F->v1O+vlKKAVIvu`Mgl)7z0R z!g;TY&gs_#Pf{}K9Q&m4Bb|J3Oa-<6^pCYuJOG|g>-gwGRlVn>tP`=8sXD@^Pucc& zcffR{UF-CAo2@C*Wmcu~#~)a@`gz&M9ruBHvqRw0U&FQiwm<(NHl*81XlQ6ai3cZ` z5KLYD{WIY5!N^Dif3QIf$c7CKB{Q>vt*~%@OS^^~BEB6)3#a31(c`LIya?(Kskb-a z$rHrH7@C-Db=}hVV1-Yo3eom3$>^h#T&-aLx4P#`cR`VZq{!WS8?EX0do^&=2sz1b z@ujW1Kf~0O*kHjl*jjhD@Kc5cum5eAuo#)!^V!bM%bN&YPC13Rq6rBw&lyoY>&*Pt zZ-6ur6V9pw9#b;mWcj{9ztV*@gN z)@e^HLEm8|5;sT~K7S7wWPHLVW(o99&DT}oCrtJAV;*bF-QwYY;WU4e>o~!mtX=n! ze6cx2I$(7h^l+~x9;f&VmwOAk-0CmyHAI)?(WpW2*z4-+FM+<^gg(Ra$`wVx2@-wq zM$-rfSGk@JT&$3%Po)A701190_#O$dFJJzl_lGT+85yCJB;w%c@#TVsfqtG$Zg|Mp z{?UR`F%c{UZ-#sZW8p{sSC`SRs{AlYqAto^djEwtAt!Nn6B<$^(wt9IOnRDVUG`Fe zOQX`8Tc>l^N8{(x0s6~TXPh-AIPdv}YyIfBP-6z%J8x$tt=rc>KJxoaY&oLYN4R;g~L>?AgvmuMYcrlo!Q@WBY<)+Bg_l38>~I?Bou4#Hj=07E(y(ws`1 zT0Tr5(Cu2CN~|FcD3vnt$w)#Je*d=$Zk0@{kx14Rbwl@?a|kfKQ|5iNLM_Rf(}2<{ zBgRpiH-1Bk+O?ZD&;YH`N+`*DNEZITe*G+}Cc+vO$d-8lSDhCTWP#nv4AWIHtKzp> zQA0Yxqk;)(eW0%)5cBhUc;4{x@?I)~(Pf^P9i}JQ+32G`R98<luN0DeDbj3fjEO%;a$)#>s1bi#val zrZr+Xj~=bAtmHg)%zznj^^Mu)n$DZ1NDgPtY$>LX1$7nES8HYvoWK6~v2kiGct(ci zNB`482^>KS6<`|6O1(-e08yH}rG7)pis0wNJL&;uax}7g!OzdnTG3mNdy_#8ufQsZ z;9xp84Tl%ifH#AGk4j4kj&bJS&fM`iJ25(4w_1s=-v3I&_p9C4+v0Jm6`LP|>|miBJci+} zV%;(ikO0<-B`mFSTeY=6#&7>*&pK@M@!1bpQ^7rM>(=1rgn&HEQ(#4;QsN*s6T!Tw zdD5V2|Kxh&m)CiZk8;{&zcP_zVHC`Lps;gg!1_Hf<92+(XPe5H-0ub`d4Zl`ytI*G z;)Yc^RcMS>#Q4!u4)brK8P}1xl>YzBHkCJ$h7fp&`pH>A{H@rJ4sk<^&WSHK+lxg{ zaarI0-@2lW1oUU*Igs?H-;Qydm8~=PPj9_*uTe`t#ei}hk>=uG)7O^$pFHMeOf!GK zLeUgV2`nV#obj!zMN|idf`^uyLR}q@gNg?Ch^=vpFGKlXXF{RkF^kj8y1Ciei#?byX=`^a9^wib z9K~thgiaS@zYAsW-}Bz8V_#Zg4hbsgAsOAC`Jmd&^54@`{)>HZgsT$-B>gDSEhRKH zF)@QYeq~&KG1~rI{IaE@dXx3Kttu8ran>4?E zx!|==XL@W#hNK2H+#Lv>0Zl?&VLlxWipg8?~6UJ?*t)|LkKXpX{ zGvMfQ$ysWz{XN3X68Rtu)a7ix{Ub37#sN{FhL3!VO-(2J8$=yy=j4eD8hzbQLVSF( zb#%VK2WxhAHaM8h>ah2r$w@}J9&sl-?@Rc!ur)kgchb^g;CrJ_zHsg5JVslwzsI}B z(YK}?AJg5S_S8`A%fa+{hLw4@UUf_O4(84rP*6P#BWWc1#vXspk805_wEG0>7x*OZ z_07n!1bgl_`o*QHGd~pAgSdF~XUp32g+JF9yC^*4c&qW0_1jD5iJ9H!>oN>m$aBWg z32He3p$61+IKmDNbV$Hr`Z@2zCa|yP?$tmO`*pItw;UEBx8CB0xFkWgds*#o zW-Obi%}}s#_*d8sEd&psj{=}|D&T|n5t3!yFRJB?D>ckFYcKS4ALK=O5ru)t{?P>t zQ|#=T%gfISKRT^ABB$Y#$o`+bEEx*yBTGD-j|R+ASq6rNzYs%u zODl*&MT+HUo_b*&_+OtfxXS!cw z3jDouVO9xf_j=~iA1|roo&}|EwJgyZo8>yYJ|MZh=*g`PO_trkh>qR~$L#K}m&ZxJ z4!)Ib+t5%w(!9MZO>QpWkAE)b)h}nF{e?h%Fo|A!l&k76S#sVob)3o-#t2MgYqLLW ziagTxDcU#vrko3rs;aA-?2qPYfwZTa9+45b2fQ^t4HzCx9hLoAM>d3OZa(^X_{NYM zf4asFXucOp917Sq|W8qC$r+lw5&N~C`Mx(~^WOvm4t_N7=p zdPGM{6U%WSEmd_B&zLkL>8EOP6}G0N60LTnEpYDFUiIp^JdPodJweEwco(&yil=1z|GjRoBnzlcmKN3 zjW_7SMZ#TiT>{ymVSxL80h6gJ4&}Xm?e^e7`W&R~P>HIGBCN5x+M5$3$};u})QfWZ z1VKRtF-P^^j0>pSqA5ZIEMMAV()BTGWm=tM*#&lE4u%LApaadO=Vf7ei}WFk6sxL+ z;Onv58~!c>^D67g>|*~jk=^axo}CIBF@T1cRBpqay5d#EPz1aQll*a3;*Avi97A$^ zl)ii^?1_*p{C=ab@!Wj>^?{+D9^`eM-ZEA;lF^O^_7A!rq6HDLvBK!Oxr;*Ip9Q|N zgKjT4bq@VwF8x1AqJtW>X<1%-<93^>mHWApH?MS$XgyKrQ-z&>s-{|q!--G!3#Akz zc8%Pp`hKN<0no7_R!RO@Y5mi4-OrZ?tHPzZ@a+Gd2A}!f^-c2-sUUqm}UEM-KHF%y2Id&??RkORclL zaz@!}PjyEJAymHOJTq*)gf1Lxu3^@=K6N9HZ8P~O+eB=vZq3~y{XwD+m~7nd@$)5D zj8S^n13#N5lPA`~HRH6Ap|~pYZcMaJ;mV6K429`vWz}=4!@fDr;xCSSsk504;I=3% z%!h*|Tez1BC7|7o&lRQLi6|$?w~~&i6M;w_s(A4DgI_9Ea#bMlczQM*zRAaxWm=Om z_*+=Cdbp{2!fQ&BmJ=R{Ajt#7#!Ny7GG$50yIRK#ZyJs9M6OV8MlcABof7Xq3)*nBO-6rJvi>{@ydsXr9fXg6YR5e4q3Ke)pl0KM4y%d*#WxB z)MJlM{lk{{>=!Vre{^?02@S0(JJh;a^6|^NHLE^uAFrO!)+Xu{cCxBm^&| z9WF2$3rV|t>eRaAmM0%4_i#V22$PGwF(@V?FqRNSbNo{%N>rQ^>ELhnxi^bsYs9?X6DpKK#@h87;^oWZ5uv zVVA3KKYtwDt(NNth*UA%uu6mMJ*cPtt4z!7yNIZEzdp*?XUE3bqi_JW4twv}W6;)i zX{cHH!Gpu>=RT>Ym~~8Scp%%=oSZmJE-VuL#IbW7jo^K}&a*YD|Gu1l^U!rg?VHQT zT;E7oc}QPy-MsbBt4dKa4{~3y$oL2C)tuhTYP7*z*^!1vs;8~4T)=|ID9bAT;Nggw z<^awebajVwGZmvYb8g(?C9|dS$uh@u^(=S!SIuu5MWlu^;mw)6G<+iprI+aCH+KfQjtNM= zkDFjf-g|2DqY@L*1q=nr-4Ph{HWkxbkU-_VcH~k9)taiaHfNLLW~oZ*1^?r9&iEXuAf24-h^RT@7xaoX?TAkn%2Vo5AMlX^%})S3UYSOPPyYxl%mX zSW&WziyUB%xI+(QozbO}uJRo4z@shD<*4-H0*q;gThmM4zP-|#b_Jw2ettdJ`rtN+ z)wBr{chO->yFG0Y55`dzUDG#oyx-M00?x*m9ktyq)6Ozx3|Rxr<#7Tc3>~s_S)6;! zVvcd<$__rN4pF?vj-?nlJUN<`lM^m{Gi9X4t!VnuhCQr$JO>&=d`{M#iQ?Cz7oD4I z(HUIUU8cd1wD`dT>4iYk9o8Z@x78e`&UTq&D^HSQ_qx27|EceBkEan|>AWcSl{h^h z@yXW3D|1#Sw6^^q2N3n!mW3wIMzI1i8F1pC2*IOaWwM~@yI?J7>aeY}mrPvM9jt^Q$7&L^?Yo;*1~L0R&Nhto+$ zQ%8qs?_Pjrwy?B-J{YdPK;1Be%+1Zk^p{5-wjKRVirz$5C{haNNAh<#jP9$=x2z1W zrXQDkQ)-ZWl2MAidQE%RPBV{1qw<+wC4E&}<~bM7-D6ZRXkOYW{z!STI_<}Pg1u#9 z+zZG1XQJ0{aC`h>t*88{e8lg%%a79#$&C9YZOe>kUp!J|m~}$M>Mp9dt5>5louDAX zbQ50Z{aI(5n3Hu1+mQFt26OY+KVQTxIhiv?Mn+z>jeG54Z$AscL!wKqS_Y(i?)o_Y zYLCU!jF6u4A``wMSzEUgD?&j+0=!BUl;3loU(l`YAxWt7E@XT6$ zgcb8|@K1WUgv7?5JRxZ_c4x=xqp|vcA0SZf_)&u^6<2%whG}xrn+CUeZvv?_+Ixo+ zr><_QyZf&o?*I7*>F$!>j9Uh$bsxs=>3ArfvDc47UN(xfFxSXbNB5x&dOqkc(j3GC z+JXkp4e%RLPc}_3u&w<3w9Rgcr)D?%pWd=HC4H|SPluYjyfrnEntsiiFedNF45UR; z9V(dQdl&O+Am1?QR%5xA?!{DjMUi=p7URdSd5x3aHawCihaukS_mD4nw0ZggDY|vd znxC1GyqqSlyuGuKpB@-EPus4#15=-Cl}59%{)fCnd3vn5>}6{WwKsJhLshT*K>InKNJ1kG&S11fCn;O?`Z7J^a0R zmzAe1jr%Z8@-Rkjn}^&)t=6(+W#qVBXGNIkI@)7%6765JXoz@%aA2*3mU@uP)H#nF z@nsaALMr^?M1z9CF)l#b$8-wfT*TK%oUgMVp5qZOmOte-Aspa0gX2G=NajRwO?Dv zRqeE+=f4A+gpCPRFAVH`vxTRXd@fyC4a@$0i= zy%~ub>3U^IHVOM$4~v_#XU{s!IZeP{(^~Hh#s+P6tx!hBMYN?hHrDN2b74@e#oF>E zM9Z9NHB{}Wplz+K{i-5TQ(JPaN@ARjX^HG#dh)r@u*AcEi=KY}tGLwq;swnGx^$;w zywV}0q@=kNbIn+MZ-r}YCYdLN?NasxF1`2}a#S;*I}YOcWbK@v?>Es>Z`JG{KHW5` z*Rn9+aQ*tUtS`6M@WFG2UZ+aSD^hQIu{dR0d1Thk?O^uu-52Yh=^>xh@N8*<8!Lb4 z(6PC!>PtO)qlu`>wRoR>`V<(x-&%AN2cww%*y!A}OGQ^#{&$^cjqz4L+crv^TFDz- z34b)(rT*x&9{jqCmnKtjat=DYgX|9G-}l|z5Q8jNHOK8TdrrId6KHs(W5z|GvB=h z{?yZth56IMWXq}2gQds6=j^w2m!FlzjVSZvQT@*v#|*WBT0tV4Sh-7{szROpc(Vts z?u3%Lp2BPI8&0oDiHe7*k>WUcgfPh0<(51BsPBuwI5A&{{jy$$D*4LiC>A<= zX{@uhtc&H_x2WKgS(W+Yw&(kw*)F-1QVa?>auqVo*mqo93@nXLnj5kFWjZuG4CdNJ z>pmP>mPJCRU!+x6wG}(PXQ!Z;!ZeYZHQt^xi^ufoqxTJVi+#(V=k#J4i)U+(l)j&! z+VX_-$Y-grQQV-4J|R+RGLtSOTf>y$UT$cs#_p#Cy*hF7qq5vtPsyr7!#evuo%niF zs?{1ksn|Qy5Noe4&E?Je=psmbne$t5`|v5%C*oFwMR`{B! zskOk5{KMjy7+o!w-3+Ft2Gzm6-@jAu+I1Zo{W|dH4j%jd_3QqWEc5o0#ceqQ^^7oJoKc8skbsShf}i3eE3sIvpBaKtV$q_*DNhD@wfGkf(U*K1;w7XuXA(Z z8l#b{boJQH0|lq=XoN(Q7=)+JE7VR&m-R*a_R^?nX@!>RvW^z;N;L(~&e$yc7%Ix& zU|8@sG3I+|y_#mz1YQt)FuU+*pdQCW&$tPS|(Uhjyfv?kk;DQ7iUq zf7NRpJ-wqWyEPd-cXy9pRJ*CC_{vV{o$gk~{i0J~bK%i&OyFyqA=07b4HIJ@Md3Nd zNk9}2+c6d|yyYflZ3f9!+w}}xTrA-}RP2~ORx=&@WZHS@>$kGtNTubfNrq@gk5{r? zZf-?GUoUez8S1uw<)^sgM*6-s#PIfhxdR6epI8n3a<6d#vs%{k}?Po}8Wzy#F%W zx!<#CQ2UX>nKSl3ze-jsdYls^5D+Sg`4F?v4Rp0q$x3oc15&sA)?}PiseA5x;B9qv zS!Lx3i-r@k?H%2zeo^tl%E=lnDMUuba4MG=KFg8EX}1d-T}0<^;nFXwi7dYM@yD48 z`X>32z7~!XW8yNYxoizzzNict=2|q8BAgjun5g``qeF+z6?(=<>|VU+tW`W2@5*PvZ?x*b2M8Y*zC?qO@SAr7Q=z1 zBiUe!FOLiVs0pQP?=D`RH8%}8c_zO?SFxp;TN~Ln%CdTTIWT-c?CVih)>BM(OxSg` z5hrZwPfM&9sI*meI~F(Va9O%nrRmFe)f?RB96qNtt13In>+J302x$wl z&0NTj-R3+alRRG6^HH4Id7Lk{$)&k|TLK+7dk*1R%JTk6X2R^G*e z@&kKiD0*4RZ)0w`o>cjDT^2&MqRmA!^JZa@EEK(K&PYirTiTSDmBo)lq>md0bk*en zN>0BQl%Gw67m#A%^-@PsX%voqWlM04i<^}(tiD3pMI1X4iS`|bFF4RkJ=_qjMZr@6 zg6pR#S!i61YjH-NB_D}xG+Ewf9UkzCiNS=x8UA0dh1b6Mp!+jP8w9!G<)0-V-bH34 z5D^n1_qljqR-;669dC=^8oHIvS?;0@oq<#?w^VGNmwbPqF&2VR+k8YhROuyJ`j=}q4r#1 zr)KUr6@pXPE(z`vnXg~Rxs$ljff^#Z?Eq&MTGsS0;DJX(M8Fp6S6yeP&Ys}5xh5U4 zWTAxrw4mrf|J{Pd9az(_hsZ~_V zq+$b&cs6*?z&Fqq)7>m`m^4AX>!KkTIXvCv!c735_y8;GwYtw)rfR^P2R0lC{+N0( zVI=BTRf2HRYRl>D-3UaqveE?nX-w8lPNc8)lcDF$MmzEVH@G)=?!$&vkhf%jhTjKx z9J!}-u-_E|*Uv9V;~ILIuJkG994$LLyE5gPNPn3qmX%QSmDcY7VK5wvd4^lLxlJRM z7q%(Xd-j-g=sKK7TMl7{+9m%&dBf(@=rxlK{cquMz@Ybj{#s>q_Z_hI|U3$bIbkTvoX?veVSlV8{{_~rFRj?2S z*Z+S35j%Lg9InE63oIOgkm=$jm!r|CB_R#}!T|tt8XO7OW~`{#@W?0=#^xFYY_BOb zqjuhTnSMT8Y;hmL13TmX>Ls_coLWasbhE?jLPoM8_EZtq2k}eu1*)T)s6h`IsFNckQHBpeAyNMxF2iuhvO^wrKcil<;o-xF(^6z! zTmZqMC6&aN!|%FgO_iq%En?LXtbR7K;W+C%C!8?ptvK;u%m&g2oG9Qq(cHWbG&L$J zR%Vz6AO7_VS3K3Y(_nIrvI5X}4gv`Io%p->O`AW=PY<`NwaK47i>h`vJqpeF|E|l7 zAHpJQJCjIjb8|LSM#yWr7~85L66iVJ+TMOn#}=7#@Pz{~O&O?}ZgU@%9u}b8u{>JDI5a{oEdTzx_1_u(j!$OYq^yyQhLC6=( zkuk5K@wv81S1l(k?ew{G08+w(MuFEgRmGD!FkZq5h&SY@!`5xvTvVz-6)1ZTe>Pz- zUd-S%gv_Br1UKSKjzBz>X^mnY)9urzKfr7ZZ#PUCVj4V&Wzt}taM$Rf^K(FiBe^({ znMZMgwDq(3c(=gkkREb`-z!etIo!Z22kdk3@Gp!H%*CR0N7yL-kyyE?-D_kb5)u;7 zi{jl-T1*b66NZ%(^l?jbEybS0n7M#TrD0~)S)frh4f<3C=C<^#0gQ=H>NSj(*3&uN3c$V94C00B8yb3gddjjhn;*9d z;gT*QN2te4%N*QtB)c|Lh&8*+rECha)95eXQ{zm3??U*0?Shyo8bsCGxGeQrPd%i7 zkxPnC&E0jI-0t6h8W50W(lmgmR2tFcnfKzQVz6pa7JU&-jWbmT+6rT1Twgu{owry| zp0q=UkXpPnheMo!k?{y8CtJy0N=g=4b`SaVdx9M$B~jztY;0_C!(4lD2eg{Q(ge%O zbo}z2*02-TJV}8=-?2tb#=6q=NDjn}6(RigjEq zkc=E6{ma~U5xspc#`7iW4F;utUkk1v#Egki)=-1socE&T&d$j2FN)U&Ll}*PQ?Hf* zt|hp$b~#NGTM-KGj7tp3nX0PK1hs}>xt#{DKVt>&NF|5Z6Nvvcf1DspOGERytqtm( zIp1QCrhU;9A!qC-I*;z3fGE%1#urxIO}?vYl7{hEG^$UBrC+YG7U)|qXV%0+U*cV>_pGn0&_au7`u3)Skn4pnwxR}!b9K)UG$f_MZ zSCAUR9No|kT~b$1Qcv#&y-079RfM;9H5@mi!;eA!m-lI_IdCQ28d4gO?fta($i}5+IY=YNNh2z%?UX?N($oKSy=lgl z!a2NbeUtN%Ui=&e1_my2&kPHiCq>VXA&|+n)dl(R_3z2EUW+f6mg0Y7yoI=rg@uKU z@ozp%%(^9b+z>2uh@CxgcxZGq^$?Ocj$jfU^WY0!Ck{6jic$0r%F0i<__8Jw!!&xD z2A^Jpmjw=?G&Wo#yNJsB>MB_GTyUz~^p9eas%|!^Pg6_F5xO5ILYAV2hCOg27_h27 z3sUgSbwGlIKjS>k7@RwUU8%KAlXCq4lqDr4)p!4pN8~b|$M2Ne;>3E_y<@xRdf?Ow zhBy1@GS2~{%`!d=9EGlDj|K^E2^vVs^FF_S&mPu4{<_27+~NhEg5N*BPcmI{jv(^a zq4-8lD)x%Z{rNvpFyd5Mfx1>^J1EH5%T69$1p`l0{PWnc(sh^rRF$BT2q(j^p;q|J z*QOXCYZ|wITvC!*gctPGiaMcAI8I?@=|EuyXB|BpHr{`(``1x?l8Z}b;t_zKg>;2* zF|v~Vl@d&O-lOh*u6)Ngupfq>%O< zK~RN<)c*sk>q6C~ZA^3SS_o@RyWi30f5hysd{W7qH>L8v|X6S&|Z`uS@0R8EeX9(R+!b8k#)swLn$gg3%D za(;5q5HiaiUvW?74gWw1E~?(rGu*b#3+o;m9sTs#vtydsTr4c#&_3clfFO-l7|xkr zYHKY&JZ6FD72K_Q7VJ=#&%dw$GT4#KNk~jckPj8CgHaMzpsFSv2Gut18|t=*F#LfgZ2#Y{r3a~zzYAB>rR}#MUZ{T$?|gS(z@5*u zI-#hIUcxouxdc*csEGZ=xnp+!>8_vJQS8{EB0LL=IGp-G=Jq=&&kwvFVzBjP5fnst z-+R5=pnPt9@aL2VNVoOeZ--C~LZKJ7E^#sv6(S`)h`UebvYc$S-@j>;>ceclY~S}5 z=@@mGd+#s10jwGRxn!Wr+%EufO*TzDLq~oD`1#%azrT*gHZB=9xN8RP{fXHo3}~F@ zGH1xa;RysuNpJ+Pv8DPiGK&$q+oy|M1Iws)(*MzHgMUVZ7E*Ly2OQ=CP055!6q&z=cb0n^QfpE;0-Y~ ztF5xfIj``uqql>%Cv~H=3SUQ5`Q)7#N!r$0IgeeRU8R3Gf{KEYlSz3G7awb9PPNO3sb<59yc;pa<3 z>+S2Cvof7M_Q!@bZ%S7W*PtgPzAE?YI72gz*x`#|#V%YxQx-i&BC@iZso-|p|jXU zcY@pxK>U%Lt6ohrz;rJxQYrjyzkMBwe2=Axi3xD2Fd%ACu_;0vLrbbIEqO{28=m+BkN86$pCgs7g2c+B0nWljZLv6}y1nNh0S48naSCnVvzu$~xJfK%r#sEt{fd2Zc-KlJ zwK}}@*0g!G*UzG{Xky0>WiOOr5B_8sVc-oFZZd54mNzj;$jGpUFaWml=P0WOIt_RZ z{M{fv5;#Tf<_-|}BUT3Ww!~2s@Q|9-M%_NuasVTjlAYoRm_JdHr{rW{z8Oga1hoeA zeVC%t?Adcs$~rfPUfV`SR(AZ+)$IQiDlgdyJBBf;Aftd1E5$^A61j83pTzZr`X~pF zH+-~T>;C+HQf8(5{j0+yPlL%Uh_TIES0Isw>)M7WiHRhIATzTofHESlw z{NxbH zT?ptTH71|HK>U_v#$L(`P7$lK{_+qOFG}(b*KYRQvF5VP>1V)Q3-J|@FF?kR$U<=) zos`&0@Hbe!kFB(dZ=U|MDjL^AeP8btnvi1k8GGo=paS%5(vSDY#9&!u95jf z>x_-2X;yY){py;r;xm&Mb<@A81HVy^UBr&||8;ldnI!AhuD~LZ{y1UpK0Jjr-SQux zcyPNH<=U(j{DPABL*v^2RdB9dBezp3w!e} zk&DC~Pw>9O#ZvM7>Y@3MwUjcv=UxL#$AbqC@=tI%Iyu1~JnqoyPsa0C>hwHqKuIRp2egW**AHd+}0z4@>AjJ<`|=v$%-MP%BE zdU&(GJ#Mm!>AdCN!+OFE<0)gGNTrqfkzTK8^~ESj+A*Fuh}I$a_!ZYnhAJve{vPs- zn+CLdNeSVpbw;%>F{hlu(AT@smi(UGH!JwPsi!`CS|k0t69au{WkU_LYa^{e6WRvR zh@h1odKM5YVVrPax;9+g1$`_0R>(&+bIdZ!?%zPmF}ufNp5bUNA^a@|%?$#bNOn%n zvyL`E-N(itMhzk5{a0xjcghCq>XC8uQs(J_RQre-L6my4Z&pjab#-TW;|`7FY>Ej4 z>H*TGF%t#3jNZi|$wH`Dzw&zjvAW^(sy1+EJ!xFe2EmV*SP@<*KtbY5Gf|DuYwPIZRpYDGYPamfdh!-oD6@tI5%zx%Mv{brAj87#fPa?pSqT&c2slFR zSQ&7njH25UcN)f&?()GPAJs)q6TCnEkIz>#_pr?U&ZXlwcVBMaag@-j>!pFVF#3!? z(D`Mpo|bC~&J4)VL4}3(8Z-m3#R;W&YaA^pDJiH1nV6X9r27C4lopG1$FA_@Ui`S6 zl$=~serMRCwmZL(;~jK6er5$SL6A+q6g*C3gcqO_anwvTdTTiu!TwQC~8 zq+@-3Yk|+e7zi`c)C-5l#>Q;CYJOuB-QiEBJ8vrtz;>IO+5gEC;2FUFG2#c~jC&3r z2+orlT3QR%lY^1SjKU#LR;L{~@(~oXii$cTZDvsiYC1X?q+Z8^&bSG8J@63s!J_dR zVTYIZNy_G!qG2i)uG3)*8$`~4j#iLVCv%CkJk2i9-UeC?Vyo23jfAYx=>1n`D5 zxFRyEuWPlw={!H&L&hY;529JAe~&K!l*=;=L+GO#uSzlNZ*SL}fCtRG6=?sg!)M-A z2mkSO?(+JfH$WXm(Y74NA4f`R`1nZS=MVi<9qmJMw+8!b z8zd~b(F5@NbX~us-P1%oqdoZQ@>?6LkH%)(XsgM7(`Z<>PrbbdTE%bf!2h6C47mky zul$8Sjt{c$ftDe;z1XFgM_%afYRKU%nb4H}__5g52gx}%A5M2ICkF=Rf6sVj84d22 znW{_?aAXp`G&D{c? ze;1mCrKQe?6fP`w?w-M1Vg$ifFE8hG^MLH}xa?qdMe`RgxZjt``HOp=JIBn=6vH`L zdZA3Le#$%4`+%VI`{!Kp3Yig7*~3r25U-94ye z0oqnIWmSjgEGYJ{jBTC_@1ZI^Vt7M%G+MCzoiwviVk-GCHzFVAGBrWJEQowYD8X68 z8R%wy-uVrNIJ;pB|6So7A9UD5G*G=}Tc@F86=Q8!D^C=;IAyuir}j(xb-{l7LeOdP z{aIL?d|;}4IWV^8cZuC4uK$JC@c&X#cWq@BaZXVos8^Es_Wj=gcY zbH6gR+k7t45XZ8E@;6I5irgY`%lcSMPftISHcalJz2d3w3&H3-FKG%CF84eLe)xg4(Zxq$SE^0GliM2P+ruG1bWT;%N&M2x zCZ0x2h7aghYzSQPKn zebu#9{WaIwp`ST3{Ce|R2A*v1T<_(JJ2+~XacdAXU!>8{6VS~&X$*Uci{-+kNqN(z z`QWbPX1lQ9^TTX6^23}u-o4Z7(_PjyLsCMXwV?u|tT8n)wwBFnu-yF8%i+X9Lb=P> z;1@kZEB6VjMK|B&485j)Hgm-fflLAxxtUJiy4PBL7!jp6VLITOCU2c&TF}ku&%T_3 z^IOH!lt z!i^vh&Prwd(nh+R;^(5?_o~4Q?F3%0;D>R}*fU#iHLbF?*YU094L^Es#AdGpYV&pY zi{$o_x?g#|w6#ftqdTQ-$f(PK4X&#livc@>1c_=ofDXO!Eg7{lH7p>}&oBu3`4 zDUm<7Ve{-Vr7-)D4)>W4cQxs2WkR;hK?T#+b<9j+3C2o^1;V-^L8Pmc+oRl8UrjB2o&);1 zU?l%IOyD?4#%Jl}Z9JPZ3?uv-EXf?V8sSsUi>AUry!)Hpy?H|mZre_Vjya{z#kJR7 zc6^wPJy{oDTZ6-kYIz24he%lVk;5cuKs~pofpetmcTG%~>4FvU-v0Z`VYYSXQwY`q*14Le?`7+YFmh~iYvT|V^f8>h3wuX;(InLwR^`t+!f ziI05vhRoqUU7=rY=6tOJ=UO^CXIy?@4{@$GUH(_48prL4|Hs;U$78+!f51(ZnH`c< zMuQOLl9}wS(h!Nr4wpSsc6NohjF3^1Y#EiEy*FiEcJ}6eeJ;)OJ->6`f839HobNg3 zd&2ekyvOVHd_9NBeQY(*$eNa?v*@pDn!}7(Mnk8hVGxQP4>rL5?rNJ7pidKMf*>`x>D%4eCmoBI>^==pMW%`KAe2%>RM=6g?AqhRp$2;HbMk*q=&gi&>%il9 zb#2XuUR6zv?w+xiBJIl%Tx%*5FRF}#9uOenN9!vRi-iUSk~>W9+=;Q|131O-O*#|G z02*FgYZJ5wTAQ85;8!Q6-)INsIM6tOIuY!o6c?bghfu2|(h3i3JQKw_-FtS5 zA4;f8&KLgU3~2F%dxyP&{H)8C<1rPa=zKzfkQRQ|$aOC>-o5({8KX16E&|Ny;>C-{ zx4}7d4Z>Y93x9%5$hx?5^rc##B80PgdBL`r=*i=KOO9KnFjU43lVF`na-dEOQD00@ z2kB&w4A7vEZ@aT5hz|bh_vysZDT)9`Do+N!cp>|Y6qE9f&`scf;8*>@I2=4h#I1#E z$ZNFQlun~g!2BF+Y9d2JrQlEUfamB%mhdxwQ5Ak@GbGq{D#&~>3AU^M4mUB=HvAVx zL5exZir%$zAt2Mluip;iI{U*EIDq7w$sh2GM55ibaA?2A_wKCTvwehcoxoahlvIZ4 zSo7XS1N(FNIMDF#Rt4z=kp2b7s{bJ`@KO~0jRWmqLNCexd?6FNemzYhDKrwc%*CZt zkCBs;o3QuF4hhr${|E#vLI+n=R0Knirlp;sT;`M=G}h3|W?hPMg`5^PR@N8#&;CEb zeP@j>kwR&|0F(v)Os5oDyBz4lA@vIK0529|<>lluva$g3ND&q+UTk}iVBzl1Z`fjH zHFHOKDmAAMyoO9m`5jm208hC&c&!+wR`7dRAY9+!^YMLu@I@6D@S8l5dV}A*FjLTtwW^(J@olgKQ--4`%@$q~Z=>g4k zl4VmV1Po;8=;#g{H~=U+%pJUsrKdv(P}U`A*C2r^4;+S*w*e4=kxX`0mPvn6;leO_ z)*LLz=0385@Ij}XFx`BzgB$Kz*fhX>%GB>HWk?zbCMfYN4v&heYv!q6`U^PQ{R_@K zABlaFl=J|N24|D{x;kO-RhE(QHfDpVIvKDD7#RA~v_wGv47pt@3g|BgT)#X&PsgJx z4XK$h^;u!xdItR0oN-eilo1>}c;xJzk3blZ(7$&tVdV%JnFT~BKo*pNEwCsksPlnn z(E*0N=^)zxa!W^%<*5IKZ-DHQV$OB(Qeg&)mt8i1jo!XO{K5PaEh|nf^-nN>hz%L6 zA$h?tEdWcFR)nYvr=?6c#L!S|8-jbMR0MWob=%o$6F4V#w}H!Nm-81gqB;uySSAb# z0XaC00s^SJK_UT10?0`;@+=ZMwEGI|cF>ZhEdajco}U(j3!+{V?Q`uqTDu`e434^i zaDa|KCSCqxex1b7$RPk)V6NGj&oH4+$l+)`uD3Itf(j}v5m~_G`hpHiZwex^va+z9 z1$G&ZjWDb5J_e+!x?->sVq7ab0<;`hgD~rZ&vUx_y1RHfh~OmH{My)Gs##+S+ToP^ zjsD)reW}Ld4bx8eIbjBp%E1kQ9oJSXV0n*BVT!aH$sb;#W_xM_g~vFAY*64M?l!s~ zPA+--`l``Y0Z??=1+)=B>l@bkVh3c`#yp@$Am8u$OEnA3C65Ao04Soq!1;pXh2a#3 zgoL}s zB9Q-0LLZhnn0$j{FK|j?#2yWWvP0??+|Ljh&+gn(U}tG}4*?}AD=S}gvnfWxg#}58 zFrN-tIl{oe{B=EUobpHaAR}nvx+KRsxK;QWnxv zQclA7^bv`01KZ<7YB(`9Nl6D2rk=fiNgl$_pNV{sXcG-)9z+_^NjNyxo#Fkqh&8GH z{>0OIpxZ-7{5+fCxu%c*mJ>)UCeC$1w_dHj(f;vaA<(3XOgCS8BsBs8Y+wRh)&8n4 zUj{mB0=0?A5g6ai=(MCRAz<>&M=vMhm_z4F9Umen-&xNaBDL!6zP`T0_uOUIA_0od$Da zR-3>)PjWu9c|-E1vT}?vdug$nMZE_R9VGRoEmOwPVGD~j3-jf}zF*TRl)dp9>$vu9 z?3m=G0{N~7L2al{Y`N%KN3<@pZymf0;6MP(@K!Ah6gJ)#(O;ymbZ?Jc*1tWG3vke^ zzN`*#1v`NfSZFbfuhjT|-T-30bvs^2+nx14reQ6k?dIcLsO1D>eBxO4>P)|Xpq7q_a{D%JMWMM&1aYwdnx4qe|q1={Y$ctT)3XgKQ8iXB)5_>CMjbO?V{4aNQX6Z>=I4w`0hK(>V9=hcq#3 z-xW6IY#oso+(vEdii*XD4t^JK)V+l%e`5`Ln6c(penzb+WdvO4nhTiBwPF#9VM`mE z-l9QrgXowTYLVOIr%YVl+lzrZp_TRee3M~Z>SB3PxVK~@hn^w8A&Xq6hMk2i%|q>YQOR&$z`lF`JgWtW1Ok&K}!qxOK+ zRV!Ma`2OT4r8D!qnHV+G^z>#RdTv3VTedWON(%P9f8rEbw_NCDr|@^v0|}2n?y@wq zt*Y>d)lB`GQ+q-+!NB0BOD+Ny=nuukIj2!ZQSl?+OVfpg>0zf&%WTLSqbEjgLHC3z zK7#bFup;cQ+b6%mp3V!UJp7gSj%XUFUS#`YsTeN(DPBZ7XMQJP<{bOb0lFNB-UG}i z(tnwuEc-8YB4|-ko5NZaPjQ|%Y8coFwGJyqz{j;`K(eeFysaf+67yGRYF?k<-B^zmTWFlBtfh&6ez zDA;Io@DTwY*X;=tV1#uZL$>CRSD?QM4B(w<;sl`8esVhAb$|tTWm}B{P`1VV?#)9e zWH?QNs*HIxFDeT5m1FgP!aR0V&;;&9MLy&YFnxt)D(= zdSWj+vECr$0MUzy)@^k`@A2=7&V{!oPZI|TzwQ5?z7l4Rl0msZ+uv360%8gOR0!Gu zR(8SqZx!Q-KX9odj{ujFWJyLPgAy&^m=;yH-1E9??8X!4^s<_PtRwnGyD2^hx*SJP z>ZcbP%v+=v$D0~aV)%;l-}2w=J?~L2Z|GB}SL=Mn`8X@HO&f>&Y(KJnZ+K^$tVg5S zlBeLQrOq~G^}!%I&Vx_>U-iV}m(jG79kf@_vd=53t8d$jC~A^RwwefW7DG}sj9?PS zI8a#_wJf5e9fHT>>y_?po5Ch@aak+wkJrp`4ti}w$ClU+Kp7w*!G3EX?}7?*Q09u~ zG9pmK)Pt;W4S7nAPqr;mr?uwTopnumuT18_=gCt;JDMC4`>7ht@~KN!t9Wu`Hbq?f)Z3S9 ztY1gXb&!*N(5!xCOIWDJTIp^4x zUxVllW>Z7%T8>VIj*cj2OY3MXsFHHUwH@FDCLZOpo{Wf!n)3CjAG?rfcxrP@3$jAU zx4Vj#`vg_%qe|;bD?r8#qR9RG3xSW!;WTx#n-Z+3PFaKTKs88k!8{`v+hR@D`fU?L z*(4^#b>YNU@1gS{>I7L%K^eVMCkabx_a~Dr_=$$0pq6E z?jRa0EiIGov(uMOHF|19j;Kd6Ey|PdEkH-ge+@QjAr6e!0IGGZfgtt&& zUOGibGYMy#OrYo64hfa?Y>ZM4w2=uZMBLnuSM=`QYgMV>wH|faiZ`Qh%)*A*0YMfI z{c77uF#u*H;FM-}q!v#U!JtGSPwSbwMx)dOz<7!ImbI4S%|-R~wi;W}ygeUWirPx5 zk2yKOU`I&lCI7|7IUJl9!FEeuGS&OFG#CGuGe2;=VFSARHE<9jlJ0!X{I};NYvsqe z<;}-jTpX@HiFKZN{UX%)efN<@gOzt4hY*Fwe=-$FF(`?|>6vTI<6YBKkt*!Q+Y2&J z#uTPH`;U~~<=A9p(X&Anfmu2<)?^j&n0n1x+@ zIB%@<7Z221Q)~@4#r9xF0c1^1Mg}OK1T=ByB-s8bH}t}bCqWPz6V;dVFf0Y~D5)S& zYWTl&90rxuOY-k5@WcIp_L@(FW64j}37}B0LY=o(M?r~F*J=!%d3rfubd85G%EkZk zTo7`JDAdaUAOf*94wMH#riV00D|7SCViy+{e%+O)STTBj+?WyGf;u* zMYbI;-Kx{)KvADwd8A6C!(-A|k)i&^>s2FR255~i6}&&Y9t0V3g#o)C!G8NaIBC(w ze)#{8#e@*4VY=>$-4GFhn^z;-I2`zb&1$~SJH0eDGsJs#Q7>d7dxx}nYGn20g9$IDi?9FUcANd+b_=tx z^Mk#|L+m*r+S@qT&6VS)*T=buyVO)v5CrbEJ-3Sx*SY`VX8|rptCg;VK~Ww#a-Vf# z500RYLqvZz_^ekaffWqzy8w`^y4K0AEMFIVpI~9_f;l(%@fJd8 z2w<{Y{O|%xEz?x`9e%Q?=z_4iH2W+){$y(b|I4ecTnfi7DsvoGzW_9JxJ=lN)$Oc; zcaf|QX1EbX2uJ{oCH{-?Ww2Hj#c%Q=gB4I8mY0X=R2hv$9+?~(soNCo^}E-d$Nw(! zUzuKY`lx;|i~*nsG!?7gHb7K8J2yArr?>;1Dv@G*|e`ffQu{Oz#U|R{rQ$(H~^yr-WKxCe!g1V-~NJa8L<4#nGVdcw~(5^FO=}Kh6I;lk%*QkJpZV z;|C24SDfJ3fC#0^6+6`T?+EwYL7yFwAV?b+|C5Cm?r&EPeCXfWhd=g*HHIBR|0*&N zc7B0vdY=-(u3fLB;JiQ{$=MUXYQgnRBo7#p+So2UXid2a)@*$1=S_RqKc}UnybyM> zzk8SY&|ZYyi2OOgy-N`_U|~mMirt!1rV6lT$HwyRmie$<$leikG%}%@o0`DL3Q*oJ zA-{wtKj?nVZ+v@!>UW5o6-+?7uKxmn$IWZrV=21L3K!czMEU6-e=c;)7sQOgfRuvs z0tl3?&CT;1SKnj3eSF@hrYMPqnKrrXAI{L88tA++#wooAPvGcok7|bvJ zkXOOg#Dt<_z%7!t3;q8qH1w+b2hUAw;WQ)*ZNwG=;H<2y3~o()(|`muVL*NeO74Tcja2f?VV3uqcJeh{M9HSlRhr|=7XMGs+ z1Gj8mxSaTPs44`I#$UQWN$ ztLW%|e*M!DiSheEp17mQJ0(|xgQc4Y!kT64lZ9w5oi6w<3X(ka(=(Z$sC z?S)uuqf<<_^9>xwZSmB12%LC!c@)6y(j}nM{TMI7Atk}~{lP&*6ijgt@hbtPZ!SVL z6@yz?Lqh}bYG614Q~oK3T0G3#D?rmhMNREH1*zEF$)KSDa2veMVMqWX=GRj!wyRLZ zFHeIU7%Xt)(~E~rWMM?ko<&HFDB_kzF7P=4G_*9Zv;|67Lo+ij-#WPKyE{54C@E=1 zq7MKuRsZ@EuQBC&5~F-@>6`t}rGHN0$=eR#$%1$oSIF~2G-z-rhlu&WW6*s(d)5l; z>`Qeu=(gBLz<2_2EdxoFor44Xbi$y1Lo{-cCqX|6ME$wot~v$=h8Zjt$n8l}qV$_k z2@S+$0*6l#XzS%|zz~NqiVPax?a?EVm9KjX;E*`->L0^0gI8ss7A~@xi9!go;8_Ob zGxr7VKe%UoH%y`dPnDZijh?T7v@Lh{F=6Ff#V3JXpAXVi!+H?AXgMujwY#!w7j0E_ zHH7khSgH2=i&syIp;%A8AESlM254`rdU4mTd>I7=aBDJcf7?r~6|4S2mk`bPNhfTiR3@Ng4c|5xtzxzgoV zM0p)V3qt0&F{u2Vw&00{#YL;F{q$V67IYCG3w!^Q$qo0qHE^X1XTh+9AI3H66Lr^N zVjFN>^w&=Q$yo}B!R|sxclon2($e<<2L!c}r)S0Mw4yH1*}$05X>BYKQ1_;7mH72- z$$>P!|Nc5%jHeTK991p~3H7^dZ-Si%kgG355?>Nb2xIXM~lkgy~S(;hIR6r%n|a}I0<*Sx^c&>W~Y zdU|?pE+b|oKb76cH3U>ltl0njyIqZke!p(;HuT1 z1vb&S!jtFo!Scv|gr>?kcI_$24(g_$gr@BR%S7a7!6EucmA3Ole+UqNIA#7MdP}e^ z^Y3W=e}0J{*lCEA^8XI1f78+GP`{8pqyOIq)#n24MyHI7E$>FkrJXDN$5EZph~4p? zigISyVRZg{(h_LlGp8lvN&cb#rxF4!4rmmA%M!ON#yT?+u?x$~pk01f?gZ>yP~Wm( zEJ3yb2!5-zv!(0KZ3^ns|ML+0(YdT20?1b78y0)y*s&-K#%ZWB2o%7Lc3{B-rw7v| z4_#f|q0v#_D46_si!^~67t965`-_XqonU4}PDghN!_UfE4*rYXtF;foJqy=#0IPtX z`M+*Okd6Kp*jHCpDo?eqWGw)Z7(mhbPoKmFg@M$TJs-Ez!{A5?JGb6n?79idBA|>WH zn5BC2CM^ufVdkW){B>Y}2lN2RE|VSUV1^B(t-FHY=P54$FB?!rcJ@jrgn+JZxPDO6 zc@^Q~>+9)(yjN|K%UjW8GjY7!b%Kp>e}K5ltPMee?g*@+dZ!mipX=%$(_I zQy>`Y=?uFVOK4fT1d&anny{e7VN_gP z9O==;{X4cH&_@5{;*2&AOia*$y@E;F&8(9g9LXcXblVIL`g^Wj&Dz@bJ={!6Nkk%E zd0Z+`M&j}}Mw+B}i|TXE-&`*VBwP_8wJf-vd>vam@g!L11rt7d-znKw?2M1_S)aXN zWM{wND&Zx+8TzJsYo@<*uO|!RgQ9+YAt9r*jHM5K%eRdzFGer*onm$yO6-i52W#-D z&v;HyK7r~Zg@$x4kEV=pH>AFJC+$Y5KoPBc^8i}4ZB=A@UJ=&z%0baXs`yMQKO+!! zVHEH%Ad~=!jp}anE54-UOCW8&b>jw1&%qqby`%qwO&b0d!RiKc5l7_be|%*k;_ zQ{2qN6CrN_&1~qZ7;7;&68`z+m04i~?HlWoQ6{wF{PHG*iax3J=zXpPtG8cR{hFvo zk~*84;$w1M{5U4$6&3Lqc2kJT2C*OCy%S-w*GgehU&ZxZJ z!jN4Ldbm3irb44Nt7VjHy#niN zuiw=6%APsvfXTd1N{c))qk9V1E0^2g@N*!Y@AlxGD(& z0ZaP>klbo;f(i2lYBbN{+L}H1W?0w)R}j>upQ@_7cVjeIK;s9&G^eJX z813rpECU%-X=$L(>(@pQubHJ3d5DnkNkBl_n>X<>^WY9}3sQvB!6lBW$#Vg1ZM`%* zTUAp-h>!pBxLXHUWXym9!ke58xErFAyjy35Lxh3;1NB^8bu}n}LDe$2R=yb9_<+LW z@F9?Q8-ZX<%Ks=h9=-eUVLkfrzT{J&l6`PH^Zs-E$**_2R8(J}GPA7APMzY_>emLq zm33)(@^+%zwzzPyml=NIIh2GE)xFOKRGyT0d$7isyg@3Ue$nvuO?AYmWz{5&JWxxE zp+10FD5|63Wi389@fb1)yAGBasl{ZNyuw9fhHSb#4Gm3o|>zGO$ey;gy35Slfyp#)f1K_$Q~GVE_}59PiKRslK1 znTD+=4MhL~ItpC@cmzsaz8qu^M6l$LFHnx>ZoT{V28@E>0V9REru%3ErQ`i`N0$x{ z#M;^0UsG2PSp!oLkUxJ6W0W=#OZ+l<2df;Ktk$ox8}0o4({|vO<`gZk0n&8o^@Dv% zdX&;p?M!4FN9st#XVHO)cpCEv!94(OZn<$^Rr%C4 zM~N-Q`R80k*AY8wSUMYo5EHrw3mM((d$3p1s(>K`?=?9kWxO%20>-cggK&W%Nm;7N zpbNWzjek4~VttKwl}3*h@JImrMQP=uy^rbX>IRlT>$hEH$B+cHrQ%`{nzDw52Q^{b zlg-}d>%|oG^a_gl-9!5^6v1C~dFC2{btNY&Tbi68t@v0`h3DM+$XzI=q`j_+@Up?J zLx*_po(=4`QLWPtEGIzqJvF53Fuou>U2iKQV%Fr@W;PnVJUiRa+?7`) zoDtzN#6*P0dBTT_HYa4{K4FH;2PJ7~txw$Bu)5a%M3cYEtn3r^5|=uO;;Xi^xKX;oq89j z)1#42V8i%c5e!XBvq}VSOo|@`IB9EPj2wi~clFwg+Naa*f6x$qF!)OO=C*waJ{Q+{ zJu%1>JeDJpp-kYbDpMKlv{ful99V+*RT39$7j0KCD3L!@V^;e(Az)T{^3ACeT;%*% ziu{vh`f9qE?{A4>RcLS5Op36I&%ds@oFebhS$9yNCM)hUB@FKyFZxm!#FG37>x9r) zHF~ynuyX+S?OJ%pv3cd7ca;B552&2%yis^v(qCZ5yWdw_(gV4>}UrX=ou|(~7WxhITC|R$JZY*xUYvGlabBoNKU{AXG%sea0r>`E2KNbKRWujBlqCl z)MUK8A`ad}4Z(uEyVQNhA548$q+0gKg@C5o7mIyxPr!CpxV8RluHS`u3Ye|O37#$8 zC~}Mnzri)TbuQ^WTc>X6`Mx7J7bn%34qS6yIwbHq_xK~`vk-BoQ(=Rj&Nj>O)t;Hc zLaqJTT_DEGHtB$3teVD!pR7qwOmK0$zu^RqnZXEkTnJrp!O?WU5f_j_-+??#f` zaFKGYw8-6aZvi~e0eK6G(W?m)y9L)`rM9uLv8rmY1}9tbb%1HyMcGuqi9qH&&l+e| zkCPoj)(ERol(CME+RdA5`XyB3K#Lt}2K*9|)1f1RFX&lx_R2vt8RVe@6BZ7WWVnu9 zwzqh~!Bgd72DhG>qIFY{x>t!bQ#!td@O2O*iHUsz2oM7OMr*<^ z3BGeu`!0qoBv@$I!W%kbcp(cI+AI36X1n=WKI=(9K6Ta1gSo_!uQuDvi|z#a;4|?~ zWV3J}@r2w6?Gb4S=O%sKa-nUJ^Fi9;N{>z+(H0?kVLy9tOkOe8^Hz?N7;!W2-DD>? zrY5D@!`odQ(+ziLMF-O=5Vt>e*N_(8aB5*yEe@ts8n5p!PS@dUXW)6`xSy zCE`}Q1b1M^B`?pBF#+t2MJrV;i1~<$di(kCIZht>Nl8k=IbqvV!mu2~^T_Jy+KFd$ z&BaEaatz+zOf+JP-mb5V>n;^zGjnMIKOzS>bImQ@pK%DTtxIv+yWb|bs{QUt{)za# zGQN3v9Q(ZrE<57qMjdqTX|YP!xc3=~x!0=UofJ3OdIU@sx~Ol~d~sF0$JxYs?|P{= zli*1Wu>lwDo4e6>Nka4}g1w(It5j-B?Ll(GW9ElX!6A^!dTZDgUcmZB^twyoyZ5hN zm3MbXWTMBK?m^28+)jYH<9iz$x!KvhmbBYJkerm5D76N~E3b_*J`F(i+~?0D*gQ=SrMp0Nc6#ZA2m^isw5C`;(>?!?08X8oKd*1StM$>%go|)d|{xdDbor@;~G^hcLJwwg^WC%IC5ScKSqt+>Y-;MmZv|&3EH%=xhPUPZpHEFSJd&X?x&VLrVFB*@TvP9MI0+J@)su6o)Y>|ql0rJ zBaQw1{FbI~*~~cKgoj7zqM`PQu{-Bg9fyt-yZR(^@cDB823?Nt9D*N&Lpd4PboS%< zv#?Q7B?K=4R1UW&W8&%S--W&1h){OxY6nuHHpeFfYd(sKN6%4N#JpO<^Y#rp@!Ea% zI54SU;(IEWO?bbC(ql>E@qE=S9&IzpQirSjsE99b$d_mb=@S~u-rNb?x&Er&iGQ=Y zUg`fuJ&;G82=>4~dUAR#K*)gmfA7wnuP-nAYPLD-y&6W4uS4ca&EuNX&4E3B59CNg z1a5YiqpO`WQ&WB4zxdX@zII?@VxqI_W{9;^MUj};_NGkzTZRj{VoFLm@YV{$1=-!7 z98Z*haR;zkn;hca>XvnPcW*4dCH(Mak{ov|ev6ZXV{x*%Vk6*7WKV&mrlzS&Azr+Z zvBtjM%ccD;H6I`PM?3O3mHDiac^A3WHoZR$y^u${>-~TuO#0Jd;ZoYE1aw#?0@=FKlmuH`EJBZ8NS%(4@KgROoE(eyl z>G(_SZ}Dm{Ht{e$7m|((2sn^lgNK33=i8G0(WI5Z7aGFvqykLQ-9}6Yo^wS@(Yjo) zbe%0NONhR*cJjPxEXU!wNE->twr9bi-p`(OuFtIdYW&z2LWu=&>=|L5cy^=eRlb>x zgr_K&kP^gkKZj*2KoCzE6AqK@#|7plYsQd6P+u59sXv_G*Y;uxhMmn(t0qb(mA<6$ z2<9JrmZD$WcSc^NN&5Dt8LUF=NOdMfsP08uTbZoeg3?US$5I`8n!ZyVKF}8cOaEJW z*`k8`gO1_L;-~BaSHCwVP;)1Jg`*&|QG+A;{0TPSzQgLbY(k92;hr`&iWb{@| zcd-m{&5K3N{-SG>&$lCc&V-Usy#I*VLt0;U$+WRr0-Iut=8qWeQrF}5txubyHi)CS z)};LwL!IYFTg%JOVmK(y6Qp_^Utm%i`8d1L*7C_!x=>N8VN*jP;EZ1B%mGxlS@?z7 z8BpzPFEn>P!V@sKf4{-xmU5Rfsog;Cux!;Mc`&A2Yf}dY^nh=D54zeeN{xNozicUX zcwd%LmRLh4zuLZ~{SDq#*JJ_h1{*Om$wx3VyxkE4)|o-}s;Xok@%M@C!kFZ3j1EmV zJYzV3=MSQzHus?tSJtTnD*P{zzzk}Hxi06Mu%4jknaLMn(XWlJB|GPVdQdQT~BzZ=$>i?wjW?P zr#R8t+FE)+M(6tVFfVtQ(n0AXCzF8~0Puwd@F5vGacyl7ztYj60nk*f!C*&y5z{jV3#zSrDc>2NhC*o~5NFSb4xq z4-*xosiATD96I8v+?&EBW-I^O7~Y1yI6T}Bx*Hq+IW?x1{Wv+t<(Gja{`*kfUHQ0X zA3LPtcfs!rFgJO9EiJ8^O2DS7j|Z!~ zpO^+079^`@R>43`x$-n5qT@U5ayl#sC*dsy^xNyR2DU4Pe5WB%(M+nZE{uCMqyBkO zDUVKheCWh3d_Aq&YVd;Ghl3}XRd8zp)-!QPS!3jq##P?lb0nG>Wbb^^)|HNbf?U+=LFoaC3s$*RD+@3QD9c)7?-f|(EcG}54AVO=GD zJ`9y9^qYud03Yg2Y z=x8OeQGhw&rOQ-9t7Bqp4Cxh!58PerxuL4~TLuQn($V~;hQinMH8j zg4_w88}cb+R^Y?m0R5*yW>(f!tUSPGqr=0O^GP!RhJ=(Z3iMX07(l6rzzj@MSH3fq zNZQrDijNPAh=73D%aW4#iw|+lWEbm?d~i1u8P+(0V-JEmHCKWEp{2PwQ*kT!GnZ@v z4PgP)cd{=a82xQ>GSf4N2@A@ogq3&si$kSRHfTw~lL=Z4nM;?DWOZ@e*@8P>b`B@5mMx~Nuf4?WbofUbRk8Q4Hp&6ygHMgYH?KP^0XdSd1mY_k98XnF6ra3K61Kdg zdfrq%Ci2WeYS%-tQLq-BrIRuF$NS9AvO?~~&RMpI(ul~&$}z2I#J+y*^(z`#H%hP<0GDdX&VnD9Z^J3;J2?*<>jw%OOv$=&*vZ50JhPV=5!)nI4*pi{reNl8)UZDb0?XijvZM*$&t&V4`@l^5K^+vNd~lUg&Q0%a}~9hSf+b zDy>B@@|BY-Vc_0*@mNO#I0(7k!uT5aIs9q0FtT-oSsWO5g3A`j5>1-&z`VZ)csb&O zqtPzTkonoSwNoci2b^GLcB?UflP{zGG7MAF($exb&wS+Mg!S<4&hy-a_*zIW*{r>-?P;*Gi@$X9(bMzS zA?_(r3E<^!;4kL%*;lu=X31D;c z#+)1&o4|}P<}ftyEJx$_!$J+X1mW?15&HPPs#=^_I~epTwJYwijopRj8U8jH-ETjU zIyq_Vn76Bm=~uQp7n>#oAkR5)K?n(R(9p<8-#>?RBnAM;G(s(sm9_cx5s5Aj&3>05 zjgbNGfPm$N1%Mp*`S=Q*H&F&K5d>ET2+?NT1UoyWo3?%#^j`k{tcNr*^oXckPaaub zT)bW6DA4>cQjrAAQDK;VUk6foy}hd-5p+yTv`KNp+`WZ zeTdA+dX4~7k=L~6LJ6K9gGkZ4cY$;x!6)RTT};D7ncz^BydX^g2S`KmaowGP;EIJ< z{gPMfP_&HIV(~*e+++9@7ij~^?!G9#e+$(afwLSd!oZtdaZRQ(2k&ZWluK<4$n#Bk>$SZVC&#e(jp%Y!Vpa zf*pHvb2D)AC&tHf%PA3ub0BV=SOR}J2XIpEdf0Az|9(V?nEN^k^MDGD7tA_y1Lrj=CwnQWR(54laS~aPxZ!3HbNP7ih5HbCao8 z0iJH14nHn8cl-ccgL~8u@*Y3_xZ@(s2b2%)tj|3ShrU&4pL$g1Yak_KK;O{$L?<>T zGwc1`GN~cA;WM$PEulPs|2Yk=S(-@3^I(snTJDXv*ig`3{ctKnrJ+iY3f~9y zG}P_l_hC1QWF_Ksm>{`55%mC-y4z0|xhkT$W+p(q-qzy6xujEhz*KEN;u4t@`jUN9Sux+iEUxLpts;0d@l z=63WU@;+VB(VbbJ(i1^}&L~u2fX!)B235C5B4HO-O&)OLdcZEeUlpTGgN#`|6z6Oo zEhU%;*n# zd|556XyJNAtLYvAivbW%!rT>R7&6t+0)$7L0~7T!u~7(6>8yX&{DG?qD=yi=t?HI% z)-PR*4~5dFV=!Wx-C`f#k{4sv4(`g6w&^M z&e!Vo4GjVJomS`U^z;g)-O;@Nm>fwDruJm``#VVmI18N-8gVwaH|bT-*B4}92zXMH z8xtd{qr);{-RPk{{Y3B>!>ZIh;`MSR>QLvQ=HJ7w-58_K;>1#BdCx-_LrIPbJ07$- z-6tF`LEm?Dwf5$Z=lHXZi=aWbwX`hE^lPz(oH%|QE*V&jjdUk_dwSwkIaY5Vd&hdZ zCw!ws{aX+4h%kaS;Nt)hMIT#Q&_JomECHf4v?H=|a+jZE&|d(KFgP{>a~ev@?X8(@ zut^A@AH8M0*-Sve4 z0cqmPl;Cb=LosMU$8OiHxNw7=@?(0`le=b%H+Pl z(Zb6^`(r3PG?5_)D#v&;^2w=ZMY3-WJ%m1c2h`c=r1&4bqY3hgf~&rD&1rdx#A z_+=|+hAbK8Mj&et?`24or>Q7{@S8e5*=h7sWW3-4FkXPh)pm)|GI3P>n{Q`K z2#s742|m6kTaiW}^dZ1TKx+QgIZ9k9x5+#UQ4Qw6X#jiIG4KO9ckUc^8r9%ie_8JI z=Or>hJqDHF2+UEQEs`fP+@59;SR3P8H819usf$Gm|R*a87YU75N>U0aa47_s(m_Ec<8$b zo6RF%s7VH@_XA?p4F{>w#12TICjS?z{ooWi`=Ps1c)L)uHiSqE5(7AEd{3^OUIQcB z+TEk%1N6eE;n@Hcmqfno`j?0MQN7(n1p*bon*{@*GFh*$)t#0)@lGwnS+rFfg0~IXu5FS)0K>k6wNK z2o4IEZ&8+$jq{oh^oN@as3^lv1y||sdUE9+@sDQpK_Hc@Vp55l;!PMm2s@%>u+93d z?RFwg8ukg3GTGufKM>*RsmwrO_shw$WRW{y@we=LF2%IBcBaUzL{Hg0-F6+>@H-D` zr{CR;(o!q{>z^T~l2^)t`()jqN8EvYobQTp5hH}Yzke_{Xg^Y_K7G>O+E^W!0y#~9 zpC2Xnd+Vv2dU6ZU!^}~C1OCgnrBKrR;I{1|45t6Ftbri-^DCM#`~Yq^tip`%i6#P3 z9)=GRPp-pAl^%(Z1+W5W#&`BW-z%*EB`MMvAqQ4V(C^0VgPo{;++ER8=#%{DvDBbyb_U*g1&pA`S%A54oGSnZt=)#mTH&%aUbO_L2mwfB@z1mqL zwJs4iZz6EZPyB>m4Ctw+uDuBZ;T5Pcz`59Zrca@J*kTn3zxSQM(+VyG!iGpbBdQz` zIy6~C&1I|Q>Dw-#Wo2Oj6f<1@+SRLNu5}W*{(nQaV=r)-=*zc*Lqi=h)g1#F~nDU2)z=7mTRSV=$O?g3C*^C41Ljl32nWPP! z;#D}>1`bfjFb7BjPgXIU$Gr{WKqNOrAW`N5c4(@e0Hvm;CgTas-bq436O&#DT%2nJ zT~(N5m%!=MPjYF0RNMetHny~AmrR6-(DVLmu?(E>I-|yVcj+DmkHDz+6_wh~7nQdLg!xU5*YRD#v}!0D2RWWs|9w$+(J%zj>*SgVs`^A%%q4z*5S?MkdbMY6Y1gOqUJ28C-OB@rGN!o*C z_okW80%zHqe$p0O<A?bCX5op;BKLcgi?gN0J{X`V@VB^n0DQVe~ zq}?c$O?+$;u1MGEj=@Re(ZRu>AR3??+&4BZbtpczETIZ45nzasrgCWs*VnwEZq`y$ z<7NCf)4$yb%lQM?o5RqojJ})Oeqn-&DvjHTw$F6oZ!Q&?g$KH=q2VCmQJagxa{*tD zmZ!hyqT}S;oSa;PJM^eur{c-CZ;4B#oj-*a7HXn+wfK3+_=k zLRM@_iVq3l$4r5xAs}Dxbz%`%kx*}0C{@)80;|{j`v(_<)yq3I zWzrG7r8(Oie8Lj=q0sEJ@J_F88wC)O+oNxPI=DV&OzPRmO=iT(stU}&%!MQOqNu1} zFwRP~U%gJ4xwk69i?`slI6HH;x&p?@6$j@0z*eE1pLeZ;yoVz+G(j#bNJc3P_%emy z7JyNCd}Bog8!(}WP~c2gHwDVX%E{BEZ(-JJ2?l{KMu7lELA?)!XHsr%*wNqsnCe9A zj8^Q)2BE1aJGm5rB*3zOFWn_F-^6Vn7DXyY z97k+MwHp&}>+oTH#TM$!1eoY=cdhh$zCp_V6)q_IC4o@=^wVuzFJR~Q?nabX2|o9$ zc*$zr=R?i#3fVcU?o*)W6a#~2uveV98;C0gSt9UJ?#u(MQmdT@u%)2{z%tr{8@&_- z0-t^_=V*Pj7G!WKD~skx=wG>gdlTEp;=ToqC}^{Xr?_5%km-TKp)nW-EpVzxX6V(9 zcjs_@7>3T%BCi0WNz(B|8slE;b(mO>CT5-rrY>e#4SEuU-7j+*r#kW^t5WqS5RjCi zX)RvHESV6Mk+v0)Y1X^s9>^=6Gy$BV^Vu`KIsV6-GbZFL!XnAe5TlBPzGnfXK>eBu zJ2BCypX74UAuvy7{`L2=ftV0`Iw##zCjFUqC-!3y0<4wx^leJ>Fglj>Rbc*kOSsGq z2-NOD(IAIwX{$%OJdV2c+U@*bt4I3-9&Q|zp_2k&(0b5(b~1cW?ATaP&wIMf&CT$2 zA!MMDNfr4}D5NfB3aE*i*f^{M@PD5I3X2yi& z*xYRJf$)b92fb>62*srTSebfE=iWWmP?Cb@A)+V}nt`Uo00F1%R|m0g9M>#!OmBO! z@#+=G-9nhLp4{oAqrt?aMzFaTZa6T7b$rM-l^v+J$O0e-A-276YZ;*^}BJEfCq74S=F3gAS-OvzO>`6P?E` zG-x3865-?PW|u(qs-t;pY zpyPW1KVy-s^qsyv~={a!YEFj;agt5kk91g+%4`p8-Pvzcz-8^U%5hZ1gq9|$$C1i?7ltcrGGH;1O zvni1wp-pWh36*(nP^b)BW>JZ3b7mRebsIX>IluS!zR&sN>2p3E_P+1$a9wMyYptV) z{HjaiLk=1^57K=YUi;rMIw(CF*x{{a*Wtuy?5-lZc4tQK6}A+Ed-_LvKKb%D>bT9W zr$mR0IwWtFSKJa1__OYTisZIEtM1ASMypIsvkkKdT5SsD zh*EHvBwf7cPnM+<(g&in{6~jj$_kTY4|n(aq`h)--df2Y=T|;syG>dY%(#9H`0%Dp zXRqF`)3g`knvif12zcJ{;JJUWpy|BzWzQ^=h*mr_d zW3n516rV#Zn7Lpbz)mq+SFZhy(%9$AaLoz?FA(av1V6S|wsgV#_{GI;p@#;oDmUKm zd0QYB)6?>Lub0R;x!v%6Ra{Iup*L(2k;4;A-S-ULe!gDUE z?IKNca`7BF7oaS_ls=pIX*?51T@r|JN1!{X@jA<6f&&Aq0P2_w|E(z@^U1K!o)Vl0 zr&2*ckjZ37pVdO8_mSX9;=O0~?Ad{;NzUU=T~<{OAyxj@;1kAg{$M>UXP`A-zU|d+ z-5I0@OK1P9`!VpZjjo6>U}swW;No~YV|24Z!={&4J8IQ0v~N4f#1!@H8SUpH4Kw$H z8+^Y8v}V6MbHA@iH?Qnr>|1TcS-bexaZJDeD*fFEzl;H?K%pFkNI_L~aTKCJ%gf4c zd;L!h66dcb2bvWW6$d24K`Kqr95~Q1m5>Yd)#jJ2j$psnYEanRVc1nac16qChw&?CYjd>T2T&;yF5#=;{TZdVptQY8Yo*sv{=;u z*4iY9BuE152_{nqM|-Y zVqURKfp_oXAwP_aOb%$B8O#_Jj~nvU%Z;yaIPEKs#3yyb8E|b3thRLjI$_$;W}Ua?xc5W z8ol4QZz(iXzS*z$r{}FFG)-uFc@xv~rOEW=R)dfl^ls+nzPbjg-n+AMk?HiYA72QH ztlOd26SAR488zTyjh8j1!h9kqFiHCZ#(0ogxuiCyjB$nWt7{T$gKxHl_&dHTFL$UN8h6MVuW?RG>AmpdhtI3~5WweRXz6sN zzhBok$4-`q-fsaUrJvhYT<#>#7e69+aZ81|{^u0wYu7%M(rDtFy_ZW4_s7}UaXv+Z z*S==?7sy%^T5$uUIUdY$zsHrJ zR~7w?cJEVaaDAuD+q_4TThunn#0<%=UuftQ7)8weoN7tE62F<+&nca+05apcOP&J3}~>YP0o(UG(}km4lBwvMfW_N z&j$yKoDTlj|I%6i^ZC_o%M=u9jfFZIu%G zj%AjR1Y-yV{&43*-wNO@ptc8s_WGp1p9O`K&&-tj(rwzhuQ(Z#a)O74k`5Q?QX8HAu01 znCF100NFdM_bs(kB5=?N4Gj9UBRYt)&&-q>b)K3yNr39{_=`(3F{TO%2Nvr_<`Ey> zzXz?uMNvwB@Zh+f-Wn6!Sj31chpDM4JlB<6U}*G2KT{WW^5x}s5)c4A#p47^U4Ls7 z%=P^FbBFQK0h3V#;G*#k&rVFVRa9IsmxB8bX6QL=92^t~Mn0w6d7XnL)NSR6!7a-s z!Ay=-WYLSn97ALS9n{Qf{jG+lrshb9w{h)Ch)RH$&Ar z^C~H#`*qQ9k&s{@`7iTc60=r1Ej%iU7_<27@ScBbZ`g(dZ%0Qvr5ohH>|z*B?w-b% z8x8w0RMu1^=oqhkTEB9vXNa%CQrR?tm{sYHkU&Y9^O{xkRY$y0YZC~|@Dd#*3H{>y zGjgY6@lILgP zt{D7@oyM`QV=*gni<#gqa-#qz*Xq8dHutmKscYfA05y0_JXnhuml@F&>i zgD1r4h9$2i9$bl#&#v2S8uQ5RP1hFho~N61He@?pFRgcvZs^wLP4mdzy5?JVv@e~2 zbTmW%!bK&v>0jTQS3|)JRCDb^)93xw9;G|Z*%t1a@4@~)Wp;RD#5D6XN(??r-2j1~ ze@zOgUaHSZXUXx42X^ysz${2!<7^Qg&bmx~JuX`050$+07-RLknf7^;>JCfG*~1S` zJ@hWr);^W<1$dTqx%YZu$Dz9)DTYC4|<+bUdEOux2zTvE3-neYFcxA2Q zj4socR|b^UF_Re%YxC`BUo`#nlAwd1o@R=q!jF|`F#FTL-*t4qGU3CmQ+pFBBrx1o4qkYr|vCpg+86H;hGqB;&Tnz~^e=T&?!R6Wq!!N8AgI>nV za9g4)-=jW44~s&__raz>70(*>A3YUkJldW=S1;~|Na6OLI`3fSW7f(E7|QFqR#$eu zFLK;_>C2a##Rujsv2Lk~pI@7bi$}VKyA%9vt@SKq~hCSFs z{mFWhBuB{@T?8zU#@vJyqKutr8cVVf7tpj;wPpOyShS7b3|u@rmQ?eIK81xlCS zZG1qb%D3$mwUqVQ{=T*f%u^Sf$w=Y(_VTsLCgx+4^xCSRs-QvvUrzIHfCpqRtcenj z!9^Z@Cd6etd_?eMU@%K8Vq@F zw$%SPHU7IX1s?NS^<3*EH4LM|R{|`Ry1F_@4WBf`&45^NyXRBBZpK^!nmKw^4Xlye zZlWoE#C^FiDUj=_$R#z^bMcqejQVFiPf7}rb|l3B+wx^p>W4$8oEjUPb>P6+#WaOz z%ph5O+8I{;e$GMZXQ}U|ShlhoXC&QLEX+vi_>Kh@lD+)k&)%khRn|3nn}6rs1f#)) z;KLz}0Ge@djAHj~fU!f!uNhSeAIdFTZYTMwyeTNyw|8%Dett7XZ4+okMP4H(7B5)f zt;hot2nfv9?y$x+8+-k_ysGNWJOK=SY3b-R(dhu%H*VF&&9!6e=FQ&uhVX-9?VgV! z5dg)1H=d*S4@zr1dNM(>$^IOx;nwakZ?Bb&Xy;KD_<;!{{R;(^IdZ0F&yvSvOH~%9 z+IG(%q}bE9v&W;Pr1HGH)39|%8Va;sxG)#fOG`@Fx0#mS=H5GR+1j>_4z-%suU=8Z z!fdRq8?1jKOgOL*S2sXzOoX74!X&A*v@~*BpkMdXW$>iVAi1%K=&P<61gKc|%=)jf ziH2na{R#Ov$2_uHu(I#`Ay~K4k$)s2QE5-vXrW7%-3^}Z=HhEO)~tawS#)%?l4C*8 zHWUVJ>c6_d7bt`JBKn|q8yeifCM+oEUWycvYYJbl6hidsa{wUA^|$qo0R{3t^_NaFIof@RY}hf%_t$q;{jzUkUlU^*KSB%ky54amWZbr<&cwT~IVovoQ zLW2&uq>AJ$O3KH*6ev~q&85H)fMMy_EJ=Q>-5_P>%n(IgS=m!QNQ_w#_`&+~SRcc@(UA-{j)!a0x=+UHpzjBe z4NMiSN8skK`)&+aWfr`XK7Qs*runGzfoH!rj{neLYq<5L(2NPJIhT=PjFVWxoFRfE ztM2Km_wV-w%30aG3budnBJlYnTgOwAQwZhAe|Sx(n*YK09s1%x?XLb(uuO89Y^vs| zf*-epnPJK^sWWlJ;gJ+eAb(}70gE;oVnC0#LhvjN? zl&y;$X=6eIB1&Sbc(Lob)QQAbuDGm*20AO?5&932_38T(m-dii%$4*lUNY)>PJhzW zz-UE;H&flAYqN}VeGDwWQtTA^nop{=p?`G!y&PquX+?PbHDzkm^!w1h+eSrQ5?^u@Pt(_ot>|2Al+ zy=b$xuC8DS|D^Z8i<#5Y4!A2wI{|mC>BWT?6{jD+UtK*wOH(r}U&g!q5Bq@6bl*I* zs|k}0kCDwUYKoWhC{)CHaT9{I>>qiXuk)u|&*0_sYO>b3G_yS`5KG8=|lRz zRQEGdrLwZ5uiu4QjpxN=zZA3;yu2Wp5Bf@?y{dIRjG_LNl`qK* zaA2R0vH@@8<`H4uZMuB%XU{hmuYSYJhOJvjua7XOW^PA5?Pb#~l{Eh`w)l>GO$BQ5?#<26}LK%^3cZg14{2UCmwg-?Eg*hLgdkr6H;q>1j zc`i0zBxQg1x{sw=B;!Ikhw_Ge3#R!P--RiXPYLKLwtCs_ueBFm@vd-uH+(H)$%N(;U1DnVf9{TGQJ9Ag!x`zG2s+H`!s!chUgHa zcub4*AU4HDd2s0bY}T2S20fTSSieIbbiy!id4ROzht%L%8w{zNJD#O| zzmc4L;kCylQk*V_>c+}y-GDnrhjoLtWsnsw4J9uLUZ#} ziIdNzH0;fOe4qH<%CT&9H2Eu_sMbwWB}_zpH~}(UDSUVbzBJI;z3a`GprkI^w1bn% zKb+8I)x7dyp_BLyaE7&RN3Ls5_7WoW7}*VzL)Z$hO?sa|yth)i<2d@-j z^7542{$PU2Cx(kBnW+nN{${4GPmE0MfBop$P03xl`XqV|MY?5U7iesv=%1vrllK18 zVm7H9(7pOcWBD}~6Ij3Wq{}BnSxooiImYKe{7-ZOmw#_Vzve#Zo}{a?!`@Fz?$$@L z<{wBuv$6R|qfJe+nDzGbELyUJB4MEqA_8i^fZMls zUlA1(gG0(r%P%w95fAYvm334&z@j?Atz6=4<(J0BH24}PD*iTu66uM-EHDr=XU-h| zS>%lS0%AL9NK-J}>A6;_`qir|WZ+52$9NVW?}2L=mpJ^LDqy(NtpSk|^utk<#`giB z>9#=Ym!ROuZVOvLXk!rV=ld3ZfqVDvJs~b7m6?)qXkYC7sWI9K4$*!QMiY~@DsSdh zrzL|=nmN-cVa-T~LBX4(NjfQloqo0@H9-#|Jok4?6K2iV`tdY%)rm!cj=Rq==qL6L znY{Oy6U_J(lUP~PgJDOM+U=hIQ~mGChb9Viw(rnzXZCpYnK*wSy+as=+cOIuNg0^2 zi-M@Wcnsh^w+nP__4hIC^V_8M-kP!>G+V5E#e&`ZbGEG{gI;{F=~GVbJj!GL2YZe_ zRCA2U2a=M9~tqO z3$GAcasp+74B5LH^B9lxEwF_kB;s3`c}`%=j5)~p%1tTpsFKE4)W zsD#mTWA>)Gg|S7~7Fys!cI<%uYHaM}&6{aVoO!!|Y<=w$ZoA#erw_dDj5OfURYETVQQu9sDWS=k<9PM-9iqqN0pnQBNrGF(u zr(oj^?&pdZ9bGmVNPBHTu%nA7-x8ckL_PnK&^8!72R^T|=GM)dBk^DROy6BCB-|RS zk}WvRK127vLsd!X!F}J0aUc8P>%Cz%31s3GgW9P_xbSkJM%ax}%kMKbKNMjoJe5H`r_nwna`*S@#?%u46_;2u^gFwU+zw|sHg7Tgtv_vze6U^j5ij&oP1 z4|kJ~*9x`veIs9w@be#eyVSUq}xo>N)B%ztOVxj*G~uUWUgXMUg+|FQDVQJB;0 z03QLYdI#H~6C8tiNvzJkCGJwfagNtt9bK03)pg^F6#?*qdv`7lUU27ag`4+>Db1eH zB3x1nfZ?#Az$VJu02fx!F?((-#;n^i6COt-KYjB>(mP<&c9SBe3UfMen#FM>eS+o@BS&vqYU8pHL_`s zq_&5Qb?gf^tP!c`EVY*CijAcoKl1wD{IK1+zA$fdEXVgxex;{NCQ9;8ultop7MknN z_gmP2E4+d8*)q6xp_xq;M+g5IK9U^(+j9U7Go-P;7nVwXMb9oo4LK+@g zdZ3$T+gKnfFHq)rMa^dmc>U<;J-QAzy>$fVytyf4XmC+#!FBEgMeCkI!Z*aO)F&RZ z9DYiKvmPPazTz0Qh_I}XLu-Q~J*VkUQbUqNB1|Xle|+;s9wiq1D<^1^&)+AFx)Ri3 z3xyS(pDl~=MOQ{BZOqJJv2|0v6N~k z&`L^6NBUn>SY$Rbu@BK;kv2AF$64=xTf?qniPue|7V)lvsg@u|>TIvxZ9AhZ*TWAN zM5JjHD_y>?dP+%+Q?j2Jc!?z*+?Z=c)}X_3hP^yGkp4hbi_@i<7FLrjenZfAEAWx^ z8XTf7sLOGU`|h2z`rzt9d;+{1yp`brjp@4}L%<~s@QPsYgry0tV9h#3OcDc*GBev0 z6^h{);Q+g~)(5=hYo~=A)r`}1h0e^$VU&-JfD|^!3T{*`D=x0Y!m!^PZhBvAxFtK^ z4Z_%x{(ZqZ*1L_Z-}M}6xw9!aH|ay`N~1#u9^O1qH_U}$=0{#5XNs6C;_!L<0(C0BkS80_Sv4KVY|ee>oIIVfBn z=8@MzQ#&@w_Lo6bNyqnc13^dIs^|8dS(0fs#*T2bwc7v2qfW88w&vR1Oz(^52SO~} z`39TLJ%ecl;-oA*`t-}_ zjbufs`4nfZ?`{7G+%Wa#Mm!expNe_X2hLYq-M^hH_3@O7E(&dxQFgKxj|ncoDa#^w z4HW+rJ!oLC?DshpIN7Y3)UpkU821trFH9Q$OuRH}i{Xl!x0F26;M**u{UJcHH}wu1 zH$xv`-E{7*#4*suD~5BH^e^#m8=J1~X?a9-KQ?}{^XwPuURY#UnA>KB;>53W!Sc27Hd>hLA^jwG(Pt8SP)dvgE&Ei*r_%iVmi3~ach z-LIdXX_n|;)+1w`Z2w(GY_THO?4D7l4r7^tkR1b`dWI<%e1>Z!Z3+|1qD!9dT(+zt z%dxTKy(35SuD!FOECyXt%F}G$hwq^UuHQ3HskN%T ztZ!b#=%bi^+m$i2;g_ek^I7vI9gJr2c$X$KuiCt1Ib|1hI)IwC@aEiSzB8$(mJ`WP zmk+xZ-a5`fxAuABXYQKTwx@TButOwWWV*O> z$!qz@TjRA#S9jf6mc(bP zG>YIh(CfNpGW5ybm%i;P$EsB+ki`dEJ{TMvgot1c;t&q`(dVQrr1o%%7@66(J-B=K z(UR470{p)B>m4sWGwb*s@~mAVER^qoT%TB}zAwijs6Bc@9C6Nw&4Kjb`}b2JY4{7eSj&$|7;@%-yqO*{?Ag*3Zq*u*J5vE0%NSiH{ zQ9ggPcC)XvN4pDWu)(Hx(nqWZgU2(RK9bH#e~n*HnmHA+6mPe*KfN<6{n*P{uowdQ z!pRwmAFr)W#>m|ks4J_TTcRQ#ss?hkN0+srPQrDbnwF-YabCj@=`XGd^A@jKSG|Kw z_ZF~kjY)>#zX{w%nwz6W-5m@K!_U7$Dn?R#d^%FnF)yqqJdXL1^FNSRBFDduw1k|0 z6;=`K=AD@aYgf_Z9c)$knLqg3DJPqK-tIVb4Nt8%^GJ>0NNdL?b>p2;b{*f2a5^Ol z97%3SOQSVQf39r5x~wQQbqR;~2YdSd$ar2C3tg82o{Qpg{79i9-u!jq&Ck(^)8`O7 zb@S@g*Wjo0ok#o7!w_Tj$gz9#2B{F6O2)Xoc2W^fee2QphK2-$RG|?d0tYc!lq!&M z@n`oVjj)ca;SMN0yrhTdxtz{xq#Sy0vWXRj%4DA^2m&6j?CJW}Nc1rH9Nn0)@4*(* zNV>V50Go?C>+iEY7!QkXRFK<#QEt3(yU~fP8)3fq9FFZ2XO1Qo&EJAB(cJkzCv+=fSn=`Fy?lLuxMefm?sXbLs zIJg42OkaBm7ILf%PIXhu)PJ^~^fULm+~M;}iJ&w$`c_%+3i3;mXy@Mp26KVydYn#O zEPVtPhp5Of$ex1XxLPLL>@?wRAwE7_Ax=b7(U0X2@s^v5i(CX-bht)8zxT6v<-l5E zbMvh!DY+`gZ!vU8^x@vmIXV@c=@zlc$;P=cRbDcQt2W6zC}ei_r$m3Kh&h$;v{Cc6 zD&I%PD4Wrt%G=zT&Tbj4474ikaK5DZoO)aiCwjwbES9lEja^sD`uerC@A1dW@qOmB zd>LV$ch=UYZ%{ve>JUOC+DBP=W5^ikPjzFm^l2OHRgpSmH6(>&u`8EzwYyqW7b*a+ zkw8obk8c~CS&VVfDCcpagWEHIxg^^<(^u;^xvK3V>j%*F5>2~sP~M}!&8y$Jv2=aZ zNI`PphkHBn-@dK>__6)8(+zz|-iXwCk%aJuzIGOOvv+<^pFZ7Et+U%@iH%xS(#!pI zn+&or8P~Loo$Mj|wfk)O(x{8AOlRJtmX~Yq-t8okZCza4%NDboZHMFglgrrV^%bTY zEn@j#ZEd~0&+($)_|K%MTE&RYZ+qnnGWyCdp9q!^sjnS)C->D?sde7cHOGv~)Dz;l zZGFv0uU$Jt8@n{~Tz%M8mvgqHd^6ia5+iO*d(K6g-R>XnEjo`yQCZnf zPmjo({qN{y@-1V%ktuY#qNF4eu|4*Cx~i?yAOdKxGfb?g@lT$pk`L|d3}m64c&j`N zYPXxtw$1$})WZ;+Z*W^IU^06&F#N zmQyNtNyGjApY59(GPo~Tq?`3#TX>R}V~0b+_)WI22b;WN4l{|7ANd|Xz{u!(WIVgY zBpLm$CW5n}&6P)H~CVs}12NMZcRPY`)&IW;xI@kP?ZpF^Ezl;-9}K7INFb`&c& zWsLUM+@SU#i1Arc(io4i%bl4XBivJJve(_Wny2g*=q)~xrt7WPdeP%6?FBjw3oz{UWKTpuU(_qWHa8Ztarx%M4SPKUFYV{g zrcfb&WsTEF0%$cD*G)g=aQJYbi_2aFQDEZs&DUUytQ{~*r#*i}Tv6^1d)dcv@bT>n z>ctgsr1avkEnF%$-ncGs(NG}kpJ2PDzZ>2#gRkSBKkt5f%PG=1tf$D?Ue4Om`F&OG zP|a?4oL~`~Bt&XYUoF@acjMa470%(Aef@`-t`B^camKeR%6=4|oLoEJcJ5=gKA z2z_ZnN86Nycv z))oV1{{iXIoM`!~3a3{BV)D!#inWIHEj2OsSNoOn=7+XqZZqL3sTZqo5*bUqDjD&5 zw8)&*g&K8EKC*vqnHoP9#1eVq6ZKb1vJ~UA$;zF!*!DpbO8dioLQ5``m6s9OS2Nzf zTr3}H|8T*;b-LkG3vqRs(cS<9C#AJSz~n+H#x9-D#oF-J;SUi&{zY*+^}vv=A}42~ z%JunUJ!S{?#pn)P-}h{^sF_t%ODW*<#<2mNCCg++E}*o%qav@cD6zyWXMtT8f5)rq z0||*fDcRXNeb<>dovo$$_>{@tG6&v!eK&SJ(7j0Ojj=VK+G03H`tX$Xr`9q!?4CRK z=Ms*V-cK(noEOh`RCYNUIF9P3-*$iX_4P_>R|Wf`H<90R=i?$*^q3X6oT75)1Ec*| zZ+wt}k6{=``5CkBh8jNARYHYF)B7*uEJ@=dWsg0y`Ye`jVX%QQ9}}D`qg&e!9?{uL z#Fj0m5YeQfmH6JSU;=&p{kNU1+>B5}n4%%D1@U|%KCCO7V;2bx0?$E(_LKh=N4)buSjCU4tyi7~S6Nquf-WJ+VDQ?obG>~lH3 zQSPnDX~Z4mZD$zA^X;K}=(@tRMwVfI-*UICpFcf|+ilWU_FgI38oG4JlA)g!ckamy z{?Nl$k9nvqWgVVOE~nGR5^eb-x``Iyb&~#D1dJe=PB_!7I+Z86?09W?&IW)&=A-tH zEHwn&3X7!U4hpV}ky&Qc*J_}Car`PnSf;3hZSC7CB<;DXXM zH*Mbh^rOi6AlyLdj$`t*7diu0kJ4L~1wE9|NB5wVex0LAdN`vWWv_6|DdCt+v9;18 zkGhAWE0nVapX>ML{`hoGh;D|LJr+9txZ`|yNk1+3VCYDE+Be40!2=%0H&z52GI5lf ze|B`H(IZ2hv`^kepOJXMcDlSAe!h-oV&cKLgh*|^6nq6ftO>rDN-=K~UO@pSwozdY z&*S9p-fvuqYMUFm)w-p}?Bp|E96~kn^u?o8&kMVC(?&hj>Ux`vkXg0ZLViU6h7FY? zy3wZ~RCPtD`-+d_I$No}o=YamA@?=?WSWWjz{-icX3pCymH9I?#9WE6z5Bj*KE8gv zNAn&+_=uPyg)o}-F7oqa(GuLgZ6(${?_keZ3hQ|7}>tR}69brHNM zkC#W4EY)H6RJEF+w0UZst4&1E(%lg5eBie=faU=YoOlHPtc!pC9X>h{?@N>>#A})O zCULV_xMxj1Ev8#W53j#*#qpu4@1vxw#N7L7s+lvn1}%^Wdt0n4>#9X3_-C`M+Lml3 zqNtMWL6{_j+{Q~R3|ZhCVCbW{V(xeEJz~t1@8@u15l?pFJ1^gMbt1-hIpswIZ(z8e z+{~$x0QrB<)}0gmmE-HG7Sev1_%ZUoUJH@%_s?rV$lFG_6u)&O=MAv^6-KmWEQ}S2ry{14+a1fqw?9Fgz@h8A|75#*Y2#u;)Cn$vrunuZx|@UVs6C>QKymf_;R(Z zj!YD0mm;E>E0TedCbIqMac&0+^JQ0?%!~{z!Gj74H!2Z~#Vl3P8hLtmLaJS-KA#Bn znjcX&P6wQBW|?SAcFU2wUFUx1A|(p7G&DB4$%rzoSOF0ta$$0^bYobCPw>O{>T%fc zKFg!Y^tQG&t5)3&4UMZw=}3O%DIQxfbN8M-S7Tz@-B$|bIB98>!qzUf=KdfVnb+{% zlxcVcpZro>_NLt!CHBg%ZkZZ2iT4c-F(gn6Ib z-DY^{5t|$l0(wlCdZ3lTuCs2_Se}*ubDfNDNJy4((OQl3BZF2<)C1jjv4SpcHLFg5 z|KlE)(+OQFZ=H;7;B12(h!Yqtyfw)d0SxedX{oQTr_%*=H*X^GdOSXwt(g2;VfB`_ zaPdkE4p|9^-nWancW(`o3eOgMM&5AdsZOOWk-$bS5eL(*(rYIJO_0e*x1t_!XcpbE z<8ZPpC_Gg@m3{mCmqLf@>0YQ3(`oxKBBH9gI#w@LvvoPVtyH&~Ymvv=Eu5LQVd@_6 z!~p{X=jJ8}frx;u5@ywgy5y|EdXKcvLe6c^a>JJWsYE2|QseDj9Yav?I?_z@6uO_&1I;L{wc9Q4M@1>cXd@j- z+s}(l>@A!q5l{lZw4}sD|9nG-CU}}5o;bkI@1Bfv9TJOaRC&$o5ICK8aDeC9-P51; zlamq>Qqt2sWb8Uqo7P70aC7fj^H}TgWVUyzp76r`VblYgQC(?ll8}(tw(TJK&)!82`qY#11o8Ol;SbBuq=K3E=k=gW(5V^63ImRLb#pETZL4 zJ@GUHGJ6D(CzA1rz88Uiixw~5I;630pXYXsxTmld3lEnIqmjd{J}O32Jt!b1UN36y zdb`@f&)?scIF_K;P88aLv~5;ly}Zo%6Sr`E)^f^X@rj%Hg{pky+JU+Yog8+bo&juw zd@WFwZ&Tsy0A1%+UmoJ66Bo#$6%>?ElV~#En)j-UJQ#P!F;W0QE|corkBtei0DWS< z_{5#OPUDXE9u{umH1PBe3NqEWTD!7q7O~}C%nJK1-Z9st`5X8la|TAQ<*%miq8mry3m;k`UH&YiRFQlA9i!}FL-*o zAUGvNs*x8WF)=a0Z5!(1hr=c+DvM?_%$RZNMArvpa*(mRrGcy3yw!L=w1vl5s5V2r z&9J)*k#Qc|l>7+?%=44EOQUx3@EA_Or7-1$B0NFX29e}9`fTMRPul>{C~?BIhO}@@ zDue#@Q#Qgiu1#J`g0d_Cwypub1hn+R<@^z@5e_Atk5 zR18xX)k1s}0<9Z!2CNPhy)k|j)+`2mM~C`g*}uFIEd=ao16p$4yh(+RM{JxBDRG$H zlW*O+W3c(av&PK0pue)8BGm@_jH)-lTMTIZ*EQ#64ai$#&_!lsx1Q|KiDCFp!aYl@ zXy8L=}U#Wwmp2L_iK_Ao|b*6PigvmIf^_Ab?*m=k42;qouXAwRLs+ z7sH2p1rDkyD&}DZ0BQBZrip0@30lGd<6U0P%qz8HbQ@b*sy}`D@awm59?h{36KifvnDU>i7sfJ={&}X?GZpn1~SR2 zJ_mXi+$`vx2*u`4v*cRwb8Uwbbw^*!Ugny;6Dy52WHzdR-0@IEOhEEpM3KZV%Bs-6 z(C$8s%f=zgfm*vW>6vFiefE6s zI=gJL9Q@VwT%rEf^{gX}3-KbfqWR00b-wxFJD#HSh|-JDT(WlOA?6$Kh0DpIyBBtS z%UxX#@8dFewc1fQ6wIGHcl7Z}W8)?eG|ld6yN!$@wli~Lj(a65tIPH4Zb8&8d@j@M zvbC(N{0s)?zs@yFhHJqZ4i5XI`4f%F4k9?5I7im*{uALFUl{=Z&VqshBsG-y&~=6N zGY%a+8l#h)l+@o>VIZOVc@ErNB+fqG)Y8%to-CKR5oX3HbV66Qvt~B&LfqF( z{P@CP1`o!WlcmYRT+xrOPRJEsm5bcra&BzI9&FU!wf1t!me@em15y__rH?oLTn9hPrcQbv)jAJH$_j2*SwP}o# z9orl^;{lk0EbR(1P?nGm=$tA3I2R2h;E2;AEoh^6&{Rz*M=ErCT>)*ZQIJI^U{Ut z=Mp{QrMU_PW}g<7l(bXDFwJAkBWKL&R;ae>E!>t+yKs@Fj#>JK9b5PO58e2Sn{vh` zCe5%9nxC|Skx@fio6jG{I*w?35DJssc;^Vj9Ov39*ZYV5)kjpnBUIP7Z==40eH5}| z2<8gQ20<#&&dFb|tUP3eVdh9JK}0?p4W*^+Yj!V0XMlx>8Rhf#_O-SZM|EkK7GYy& zuZ}a2!4kxn;J+97AFchNJM_}iTcP!Xy@Q~?AWr5s%t?z&NO*WbY=XNW9xnv(5a2+7 z93ex@)e934@an}~!otM#t)YP@kz4TnbT@&+2}T>Rmq1U5Vjp|Mg8|3 zw%zJ@wDw^FH9jIj{vMaKV@GOJi1U~|T*{GB{ty=krj6i&fw&Q^BS+rHOHH;j>!(iT zZo^wkC+pTdy2~lY4pV#J{!}0L4g#VSVx;ieNepvnjg_c~xOD@(A&H2nw}G*Q z_c@AKH^)TXO$S4E+CSI-h7$v+n*cz4mx2H@C!VN@{6vXQ@$+Mj(i<+by^J(sxQ079 zNf-6+nk-T$E~)r4sF|l)|F4Hm>EamwU_geM)RB>cFwX~|3-{nP9WcjPaSJ_0!Q3LUY&(Mx2kpqIkVm){pgjlWt^wvytbBV|>8Erjl8ZX2PwVJVbR zD5=U8Dfs^TET6cvUx=c(S?F4LZh|2jj3%ZmO1>f)^v#3biJt12xG-!C95D+~E(8HRH#pTdDw!0%dEKtKgji9wG-b8m#sKwn>YH0hyc z6y&g%9`UK|xX}M3gz_OTZ@F{SMD@Lf_FPXGrvI#s7-j0}?R^pzWipVaARl=Q25R+w zaB;z%g@7L=@~;x#)rll2DFTcC#~G6+xz)*u@)C^aGzR35O=o^oW@=&4X^>do+3DQf zpcM5fH`f?SR208RwZaXlz14 z(RdEXHdgeXJl<2c5H%L@5rOLxe_Y72p2UmT`Nz@GwkqKgLI_X-*^1P6{ZY6+VityJ ziLy%cM47E|Sn#Zg3GGb5kF2eLHbTVw>1=|7&eJ zc+D`^K*7~6Q5kVnuhwd$u&94Chq~8yP8dU+@uoZk7is7@Dr-^ zS*VYv$~!lDL;k&~=9AdO#qsh)DZOue4*x_UJ$J=*dc%K~3hDHW9WuqK$6w#5)P^Uh za6hIJSM8lDGA4d^SpNJGQJoT!lniS&A4Kq#F@ zMn-^_2&{yr7?yUJLMtgRPkQu-j{C%yZy!cn&)L|#&&%6vwel!!!)bGKOfuS9Tbs7( zA{d~)xUf(yN~@zfF*;@ptAXgHh-W_W$CuCLA{D}{EG=Dc-NFxs_so9uo7&`ejorZR zIx$DpOQ!(>@_z@&1mz@Varel|zV+gai`nR#591O*S*zLEe?R-V55G@}rSg;J;+SA| zZbX{)>P&3_adB~-_?|sIJ@5&wX#v3aXGy(Lg=oYPw>5v>yzfm-t#^h82d~|@K`2Yw z0AbZZZ8q=`kL+NyHjpwCAtYfQu12XGA<(i&w4RB!o5Bo^ zRz#zEpKQX?8U98LUyR5{l0yajmAjG~Q7B{6C3I*GucmnI>~_^A!*#I?t_U=m#)JKI zcQvy{JP(hDIgu0KOkMfG#qtDfilM1}dMfH<_Lz^0h$iy?x0pz$_Gq?Vp!_;px2`84 ziQ-M@eIQCFoN*xI(Cbw&2GPEkc&_OE5swZpZlii#Oc`rvXp}e|v2~a^Rf*l*v$SA8 zIjF|*`oxJcv1@mgF6N^8?%lYVl?E8#?!9|@nwr+A=1>Zt+X5Ly=-Jix`z!nV`rT`zcvV6WMMW^r$L859-dtVSNfj|)h zpSuXeS?+utXhqzSWHshntG39-J-?5kwT&B9wU`Q)PJkzgwkz%I1`HBQP~hNj$G1{? zzdSHS8`-rJSc$rll1a200L!p2?mzEr&=$TsNS6rWglVbCZt|4~S2Z`Z2RLe%>OXq^ z98H%ifoL!pyLq7nk#tu-^i$=WIjH=?wi->Tb*h42`d%6r_c8H z|MS`IS~$*)flCa*-&{Avj!d2L`P>3ia0zrzSda7!BD?NC&NyjlCuBHXowuaByIW8| z;CwG_FDfEthUqeEnuMC*at!7%u*;Pi(ZU=_I(xexeoAXtSRR`7JaAbHM~}d; zu(0gxaY(V`kdOT&C4oYrXhs2nXZ@D1^xv}M-}Jh z?iCK$tDu0u5${mPNMalwJz0Gi^0jkv zb5+_WVF`ND4*Tu~_-o&SEj7~hs81g~%B!f**%}-gY5=RE?SDc(y8niJq-4p;FnWKY zoA?eVyAUsm!Sa$4u70BIP$Md)VJMuKoUfz$fUSUB8xJq9NvKWE@!h*Go6yh%IN+Xo zmhCj^03~76y|`GhNsQ@O$PU9TTv#(bd@rYgR@aG1b5uikl(G+sS5i>5mN>zS2VXQH z8@R2~M0MM?M#f1`P((mrxeFxDTQ-pr&7`~YxWU)Y*lhCwr_mp1Qt>ENOi~ghaUi5+ z{lJAwt!RP1zTD?>9%yAb4xh6U$UG%#nCCs8^WuI%AiL-G!jM#pnR~%xSBHCa5(>Jc z=3a;dl`fqKJn;N{G=ZSwOLR(WR#GtZj6>y~=AlE6w4*UeAhmO++=E9pHD<}49Fp41 z(m!6zrdp>{ZNQb__yX@#@)fC+0I_l}0pKB;3NVS&P!GpS3cKg2SJxKSFH^yEtZi#~ zU*~6Mr1VigRa8_Y(3yeg{K8TRZTaIc%_#UJ;DUVh`n5c_F1Q*ZwdPG?_-IDPP8d-D zRn9yl7~2RR+F!p94Rjrw$i(*8xY^YFo4z-2pIJSuloe?9*gX~65cXVAR(7<)7SJ9_ z!#)NP{fyIxPG14#1K;_mWs|);i*(R`wB*Qg|1YZf*Y0j}rEe8NYaXE)wejNCY1q(Z zP0$1S)@1a=69x3|Y{ez|S>HQ%Sf=}rSyL@}10yqVtG(nEOQ$zdy!>SO_74ua^9ljN z5+}mc-?2YA0h&UJXd#;%Ve5Hm>WrEAnN?y0CHEH`VIv>u<>htmdarOJG?*xSjtx## zuA5)~8|oAwc_o!}4Po{K5VQ!7?1{Z{&KbD&V6{$NjyUHAh4EeGilt|0df9@Bz?f|yoB`3S;c#AvulW;}2=?iAvk3>bC%n0!f&0nk&6^RFG$27LGh&IF1ygX#-C zS-0zTdRv19dFba)tjG3GsXZX7L493lPps(GYxoo1l-bSuU-g=jKOE(tsXlz*fK77~ z=Zu4b{)kdKZECt=(>0++``voj#%&&7)2ANe*C&uYoojWIO z*Ktn(sbytpivG&m&i^SqC;U7_6K|JN!qFDA%36=j#IE_ z;@DvXPVgBC{NnhHfyYmuS|YLdQ>d!pw4CVQdZ^Uds&yfvthbU%Y%{B$opgzbF$1@n zt8N9*#Ky*BgsrRB?qqr?Xr<=nRI6_a9qN3dJKA;=H^XvDCesviNQ|Ip*sPyy2hfT` zmxq*mW1c+0-RY;?h)pS% z4p41_ds8>cc9H+@hjRSU#2x6?$MO>OuKPAL|DbU_2;f1KK%(EY<07EaD=a&yV+69HJBD~gGOT{dDb65AEcXg;;ioO z?iU>$kpvnv(E)5w2EuMAdRR+K3m_4+764P>R0W)MdRENMlF zIe*R^a0XFYk5O4aV_LOJz)@1a|YOIm8G(s~bmWm-?{sw<_X zIiX_%D}t-c)%kcg8jMNmO;R+|uqzJJOiN+9qit<&Zmy+&$Uitv>z^3Ucg@yh8u~OC z9RMk^EjpTT`ZlP&gix@mA>UX0F53~$AU=C$=I9SX@oQZ9jC=1bR~xwUCZz3N!@|t0 zScc#uKF4iNFR#qyYC#A8EE^$`8j*;~MEB8lZ>RkVn#twhRrf96jM&|njk3Bvd)35N z?MeF=R!V62+Eb}we0&NQQfynb@tm=;uFF0E$85XSzJXDRto#}z%$uHS;7AEvN;(sr z(M7?a?y*2byT0~dA8ko9=ZK;}kEuckgX%58KRT3w*8mP2J_@^FWvUoI|K2uan^A>2 z)a4?7dZ=|}e>Nz)JAMJe2g9-PUBCu3$p5!up1RXpazd4ue1vG4{4_!ZGDq%C_gS&@ zjM5=}W6YyN&GgP+Xvq|?^n9UP6(em!K9MY_>;f4PtBcPZ6CE;EkShl*KQ={%k%F$% zeV;?z$9qSOlgD!>4z|(Rm;b_;m~>_l;6hM^-d#93MMfG!BJx0;K=qdyfJOqp&ch=o z9H3$_TSAb8_7mI#pzZ&|*muX}+`jMI9y5iKBns`K65XYYhKAA>4WpqY+B@Sx%S($7~BNY#VafeTmSq zv^g~kpk$&B=>ZRwQ1i)at}tJYbEnIr*`S$MSZHBog)aF=e}A-}PAa~joZkh~OkmdU zteJ|cbh|hF} zaZ~(!e7=79a$HO6R(rfI#qeu1p+zI`{@L7cVjV@A5Q42&zgl|;f9SWW@&Fyg+hE56 z^rt8QFAcfV(b-v}dKi@|BSn%d50x`7RSN3B^_fcR5R1@^(`F&LjJ_JHAa_CbmNiz| zdEoGVqelu^BhGf{#71=rWGA@IT{Y-)mi&(9&-O*H#3dWvkEig?qNyTuyndnLM^>=={dE+wM`FEp>4k!qA)GJET~| zT($pI?*_q6qH40;pb-N@r-E1nCGgZK8zm8cb)Eebx6{Qkmcy>ZSJU^O6Hm@#V#M9< z!whZYfzix~uhs$S4t;NSUb!M_e_d?4{Np_fg%|v}gF`6=j&*UKw27J=kani>T1D$H z37bE&X}h|YnQwlEba8QYli_5S~IS(mV_S<)^q&X?raguC#)xhT?ou9aI z8ErXGJ>#u>GhW;L~jSDw1TF{)#;K zv6ZYC?AV*>(2-Iw38B=3EkSa-Jlx#o#82;99{gRK{vCP;R{7N_&A0ncQhiQ}nJf`z zZDXu*s4)#@g~(xL%=8mj<@~OrBKLK3?zCvD$25`c)h=yyu}sb;FqUz7=h+uN`2JI* z8$GF9y5>obgq6c4>OC4FXB#X^1&$3GmR&E^?_PI3W?u%^u#R)$7Kd>^NjnxitajEEgFBXkGAb-l>8`Sh82RU9>^&&tdA~lZXv)n`^qP zcEIRp9-E)s@TVGsV;i6~nmm*J7<%uL`g-e`xSC_jIjz3_s&ir)dS4J8w7;k}>zKm@ zDN@4)LHk?nUBe|02^h*{+g$kir;peqGg}`FK3XN~!v*Kj?G9QT7{zgmkAnn>Gwq$E zQr+jSQ;cE$V0?e{_jD0^tdCg-hGhkb_3gDIa^|dRLcHAk=F!?`6#E-;8k=(CBzz$S zskeLyb&q&!+uEK7Ye&S=w6?e}3z-JoYCAodCN9jpg0a^zt?C~Jpu*So1&{}TtMzOt zdhYUHgg()YDTZac6#1OSzr%bkFYhQ`Fgj;&qyznJtqJDblcBvN zDXMtfxucV6NlY|_Vs+)pm0O*@D%oXod_g)H_O)}}Yc=$+?^zJA3_727Xj4T2Tr z;UT_zYG?vxEXJ>|R{aQB(9D!-b~e>aeRXv>}$vHgP{$!lU=$O-0w3yq?C7@|(6L>ioU<)F{KC2ED z@NvaM>t*j@3Zv6RLCC&+Qnv=Q;&w@P?gY%YE%2gQO73+2Gf<dn zg025C_FK1gW}V4=>(zknKhTn{TQ=xr#frzOoL`!8C7+<-O zps=r}PGhyN`2LQQ?9feXeUX3laPXZ7(J=$7_ov!z+k_vkp=Ie{{C7FmPNHBY0!w#q zy_4yshx5s7C9N0Iv^&}f?d|Po85+8v^__9TGEw#v*(*xQBwg{s*FSk)kd#oZ3lI__ zel^7+)H2y=A|Y4znQ!>~{_)z-_zyuC=llb|xB=*+hoAnnVg)-Fmr6thz*?fVnd`ZM zJ3*v)|L9#16@VWNkBn4qg&4tT&GUm%Y7P!FHhbt5yWx0$qhehEL>#zcU?4DIlHZ6b zAhpUU)5XdDX=8%#1rvYBk{Krxj?Ezk6CDfxjd>CrhNOMP*O7;HbQtl~rsTScj`ltF zulay52U!&9lzFnp4y}U3HHHpb%ebpjIQzdxR56-uKjOV3Fag@v+?<`CV(x6Lxv{1& z*SX*Cv31Sr)!#KTNXsZy>u1j80pXDs52aR8R^~Q(nf7lXl^y%ylxyu>PYER9z&Nq^ zP*I;TGn>f1Q>?}DP15rsok9Wc#;qT`J=tpnYY$S`c^bccOFaE1QrhbYv6*#rf=>;xoomxekvDT)d0Jd||1o*k0?zmJ;Qq)iQfndtHNn9Y6v&1AeQ zd>Kjl>tfmfg-+jky( zRqRjK-{YY7(T!Z~!`*-Bk}QULY*_b2RYSF}T!%@OP4j_F?jY}E?u+)-R7|W}eVUtl zA=NU~YK=-NEqO>?pOtkhE30yH%my?sf3pBTA&dLBZY6|<)*xv(LSdikYk#4bi5yt^ zrlbM|+96KY)khio1{q$NRGCTmJX>qxbk_95=S?8%KiQV$t0TlFLql^mw-Ew;a><(` zX>vpO~gXSA5M zZ28jL>#g&I^eAY%H3;|*GFy1UG1mkwB)XY3kD^j;jwpE8hL>rrz4n6bIc;S1X1#<#BH5~@Z1 zA?*gmDd$@{zsbJfg2byI3;QY?1m?N&ZELRm33(puS>WZHa{9_hC?zI3Ml*$tEl**j zrWV!!AyWhHEKU7_I4g`jPU9;sozPI-rkd6kXn23f;mZ}6*&WG(Y_rRtr(sverg34U zb>A<6zi{N><;tXnjHes1!XX`#dtMF7>ATmfR~8lwKI?r3%N0Ua{5d8}735{IQ~x)l z!wK_WZ#eh1k&e=-hJYE!f?Xz?!xt{@S`7*y$*OvF+$KdxrwD;{SHQd+aY4)4*S8+6 zk~+2BVc*}#l)95rW_;pKiPQ(ii1IM1scm%4&Q5Xo9v*dq`hdRN<#?AbDFM60LqAi8 zdaS%7nkoqjeyaP9EfKtrKMZ;*O+hBiB4sao>VkHvB88qI?L&RNn!}20<#@$SQQNFk zYxZbS{C*0?<@a!qgde5`a*~R3n*6-m1xo)2m#2Atpl-S`fCBpcw)ERhK%4xraoQls z<48AMsW2-kcetjZq@yw>2Hd|Lcp4e4DUY+Py?NSUBBrJ1Qq3%T9ClUp(WH_GyyzK$BgH(ys{xl%|rEGfbk$I$8->+G#VsiJPlqqW&eE9}TD z(oJA00K*C8!-~_?7TY1lL+9xSD@pbN2I>4NTHBG>Dc|NzG;`~m96GOLOzP&bIMUc(w7W+qq0U)_>y zo+?JA<;a6DYGJ{jGPRRzQ4yXSEHzXZ6qH2f@QP0X0+ESlB`hyq zoFEUzq$QoF8ob@Lu_Dp5;ruuUudY}H!WG+wP-C4J8(N`Y59He^x849Du1NEIed+9jtd)%>rWokv=#JiLqN88j0wXx~+NY%T9>sCN}Y|UA1y$p6T*l z1#nkcYET<|lgZ|(_S9~z>8-aN$>0kfLIuzRDSb>QO?Ti~@?qOiv|$z{z|{e!P^z~+ zk0D#RB==bTFK&x-3qIZQNkrv8g=TFdgEO2#?{+K7qjMZ6eZ>5B)7 z=I)Dymd?E9%|u)ox$JC`ghx-n-p<>%7}Wp1u`FMg&v5V4p6a5GEU~(JdP2uLOtoaT zApAvAt+`?w=}Nw_^_=jdG(RQrbs_WyA=%wEG2DG`jT2oR{ipf zoiwD`*30Ixo>l2XpolTpLN)4hv$r>Cc(JKXVVb`8BA6X|E=zuFwL%XrA*=?@v#d0FH$ zAQ(u08>$a-m0$1weC+!WkEw1xkpLCVF#SacMt&g~=P`=2?xuUVYF`k;PEt&|a;oXX zJE&A3kq+stt5$2&u`#nFHA`n$Fg1+#!5$)YCz6q8-F9+Gx^2-pWik2VC}B3B<~dj?^xUN8G?}Wh#$Z07`{^KnFuuUzsjo)~JclxSGgBBVO=BK|LABe>ZhUJjuQx#E=;-boOrt+tK}(>>Vea z;PmpRGtrqKU@B?CrXDIFk1A;@R+sV~KlXUjS!Qxx-Zz(V<;VMTOG<`6wlYVxJN8bQ zQ`+7qiF(fFV3%|b$o-pOl*f2_fRB#!#%ZJuzQq)aUWFqRJLFtQgKQcO3~B03-(*tN zo;tMt&!l7$Ym*Vj%)HCveZ51E-*Y&RrS`#(irhE!+&6c+FlI|vS!gLzw>1)N$}Udd z_hqG=ay)s`CzO+viz&y$L3>!zJ0@T4H9m`ZzI{ zYFvQ&Ub6cykdx#bq?6n<59zqdTTI{CP6)ZF10;|BH~w-<$m*80i{AlD*hWf8g0_=}fKwWmm0pKF{x)>H$PeZ^c}k5$r?0sg zBQ{9qKWyXWjY0V@#pF~D>HX8=uB?1ve>CTIdEfl|Z_xiGs)_O5kk}>`-`r|{zA9Gl z_U+pUh_JPxxlYicKSH}L6Jm}LMdTg040(LjRaCz3g2|QPgLoasT~Z>YqBa*%m%<^X z>G(J)g>uYs2S*nYBJrPa(Zom+aalo~ZIU(B9SN!rTCN?Ll(5Q7?VwyiL#6h|LRqxk zm7f9}r>|$N-gKG{=3lw)=gX*p$pCRE4RY~4-&R33`B@(P<_tmLTW;-tGYHY4@%1bD zns*~1)o&fh%gc+527_j5jm6u3 z;!l!YGpHJ|5s>t!e>!nOIb!QPBGmC|Ca8>8_r-mlER9JxNNsf<9f7|Lx39Y=tr4A^ z?2keMTo?HNhpQsA1o)Z1faD zsir=ZDrO`!h}hR=P4(Pzb2pmHkPXnc7`uHHpVWZlkLXu4K0_J<&g;nrwnl=XHGh>NRUJZ2QTdb+Vi@ z;ApNAJp%0yT4%ua?3<vTNOqwat%4uT zE*V|Es;H#3T>GE%by+xNi-}*i>hzHgMXs`jo^P~+YV)_3QLZp6(~A2#BOW^3_Yc&B zzQOf&fts03KMW~ zn9}c4jQe&=J%_!Uw*Eyo;#IvvR;^{wF|+3^9n=tn`=|VeT7}kPJ9-S&Ne`8ka;DL> zCGn6f%%i9Hg7-ftNHWVBF7*63q4ulr)JB}(UKysTKu7neI>W&RwVBCWraJ2k^~3e# zGSA~x1h>5(%rL}bXwU$Ze&g%_@&iIUfK~b5prqsFDcy-R?`|`4u4Jvt`)sT zyvEP!5f%0IGgEq!;3NRxld)3asKCd-)b;|kA8Me)3q6^8gqf!U~0Y;>!!c=(Re3x_T zTz7pCyg|jLZJBF&U9yr{t%XHJ17|k<=d5_{60}e3+yJ(TxTGX806B_IBt^_G&s83h z=QjBBihLm_m(94iDqY)qLwo5GhO=~vTrVEx?C`O*4yNOJwd3CDqQJm+;uI5i)>rF> z&I-RhvoQGU_a-~q4QCIPZ#u{8d$%m-#QjYhTc;HsTTD+}t6Qpa+NN#Fxwx>hYqzj) zX`7$M!=$(g30!Pfw2up~IKKCoxTU$<(mcj5Em4ye3uUA+7w>@|7%>l$`Ic{GMFSYi zS?=DhyPNq5UAg=sm19EHp4Z2u$PL^y#&AQ z*Je|ljZ2Du_CEL1ZH;P$-V(Gg2!Bvqgg3tIeYUbXXOTpxo+RO&^l^^$y1;z-Ws9c+ zP|hl51t@1+_fna)g8iqqtzGy<^W|n>kls|`bSeMk@7F?{0xS*`9WJG%bDfb8Jo)9h z@7;QypLQ7wC{Gs$%z5r|u=1TSyRmxKs&4b4m`daDs#Znb537t=7p_q&K4Y@@l}c)R z`8P{VmZ#f4to!sAD{tGPFmvW>J9W=rA(wr;O*nsot@izDwe;n1L+Dy$xegv#F#l6? z2ERmWefFJiBMBu^2WXyMxcREF16z>A_I>+oKnIbO+RCb0e`fzZ>HyuVa}ForA?lHwJ%NZTA-?YTkzbO-OR+l zAJZDN3bXw1BBM?w3?xgLoAc2Rtj%_ly8(*^dK9jP{vYOF`Q}Am&XipD^z?*1Dfl)5 zCZ9im{5&_yeo3D2>dQMlgOug4&_r)?;KcC*)PqOUM0;k1G$*C7LzV zhbl1PKh=*1;Oq%ly%r4n*=QQ4`>(HRxrjApXV5B`0$an-w}}L0z@>mKK}#fV`0&nt zPmQtmA^T%{(?mL!+8^rP@#Iaokf-T39~ruUg5^{T0a(YA_SG~$>*^LMXwdhVX4GS$S1|&W7f$@Pfyy7Cd36 z82V8Yy$XSOvy4OLtaICJfL9t_uRp|{pIB`G2W{SWq3CGY>y#hLv>!_MPA}oPO@xlv z){zgLL%M$vDvH@Hud!&g;5Ai?O*IF(ym?4gB*x04 zd5o$(FOn__8kN6*!~ydNV%HU_D71*;5f?~{A5t;&yEwp1!pmRDwf)Gd4FNvZnsb-n ze6U(i9JE6_^BAvx`Er_SF+3->zjrHQlUg-M%NKKSEtQDb)_R`N*2Bkje=tKeAvu2$ zu;j%fb5}G@)woCm!O)X_{e}(T6o$12UcP+!_3PIgIo0lNtsMS)g}BUr`_)g|Nfmp2 zxlciP9^5Vu&A2A(@4q0s>KgUJxs6po(dWW@^kFA$EN2k$P7?+PDgT4{mzJG!%sbik z7oQgYbP-=HfsJGcbDGP7VU|Qsm!GVxhZ3TI&IWyS8W#M;zs{(~x`35fyB`}52X{WJ zpCg-|i1L+-RfxL`JH8c8NELlcs`7gKN&o4K3TYO?A?cKlWp8YBVTU%Q&G`$&w zz>0hMSny((B5`%LuJhRFCV%4)@zYTo02C|BpMQ0Qs-pGY$rUW99)PY%6#k;{8WzS)SCN z?X=z6Hvxqz^349BA=R0e)9^51+Pt}d5iS%@*g2+d;~+wkhbJKN7^!UV>mfS}OD+Kl z*i5YCtS)ITaKchKs+eas!Xa49;>2^II&{cQe$84*-3}?(V63L18tLo%oM_6Ro~360 z`#1f-XBjlS@C*(6p?goe-Q<_S$Vg4JAbCl(p|#r(CN$bXAcp~nf9?S9H%15jKR8t{ z|6BSQVsauYiMu;_&S2#r@9bflTe(!K_&dAZ9z6M>QlJi){p)oBTVQ0w^XhU>ndmm+ zK=A!A9pQoL$XrsA1D{BqwO59zcdf(2&GC@A`2UPeADo^z5znynlmDOj3Etx6=i-0l zA^1aL6A^9#^Jxt6wr6vqA1qSh4`#c=2K1+QlW(@5jf*$1G4Tzo{Mb6TK^MZM>uS@UI{H^ZJ@* z%1nOGvLOJ*9;^QPYtzLb1<|o*qY)1=bJTwyq|;xE{DLFB9zXV+J9+p(oS{p9VKJ^8 zU9plPy=(s7txhx*hFIk$bpT9@B*fc5z$(si4_i|L0@$`~Umz!Ql~?&|_GI8LOWwbv zTI%7!XY)51k)|{c!N&cS)5I{uxd`S25WW+_8Gsl`Sf=htT|gpCelIr~^yLlK3+1y&}(1UT|I1he+5=>Yz8?}BTfnK6-JB^22}vWYm7)x)v(3;zygSk zwRmBc6;W(+Nz2Hbgt!Xn3sMURm2}xiFO!3k5@AyJyaUEA;CfGVtJs_N@+I=I2si=Zk@jj{_#TWI6_bMuX6cPE3n9HnNkMoU z8h&g+W?k?Wx(DfPXnjQ6BJI)>g|7&8z`)^4Bbx-y-=(PETZ8;+8hjN#G2>5MVDkG_ zWjdvqw7?5IaR-9N!REQ(U?NRKA?*H8T7U4L88>g{NW(A-1rUPrUtHA$Tmh~JtR#*f zzx%Wu&7r%j7#5_W#gCB;K6yrKdhx~{&G<|SlXgl=SVDTMEcnnLjdt8Uv%R<3vqfAC zLh$9lb82a60r`pK$b&eQZLr{gHyBi7y%{m5(fl~~&huMMQVcZck-bTx0sd#UR|<9 z+wFnArd$u;d3>0UFx13JC-o`6w3PQ!0&~n+cf+#hx3&l=Q3pWo3KObV9fMCrZXZDH zgp~E{D`rYq*|%iLk6gdq9kRmFMA$s$AGpxuzwr_D16-Mz z93)_$2r~zu{nQ&n$N|`g86X?ht-E{g-geoR#&$|@1>P)9PGz@lg5D=FQS^zdh7^N&t@Y&DHeeBA2mN-`E+PLVjM-t!Umt z!0m)U^qI65?55Z`bqx#(SE8;(*p8YQb{q?fTf*w|h) zI^jlPDa5pnZ?Kp0-)9Ctq!D>D&45v!U0z#x(&no|b4AB>5XyZcr zU*p=;NIiGZF@Hh0OVvSYj$}a37>nlHYSUBOKRoPHEQ%|pBM^>M>3wfko!rl~$@6F- zO1#z&dg5({Hx7Le{Ow2+>0tG)PoKLmMsu(6r${)Jpq+uc^+cL=RIDT727$tHdEUCk zDCV60w7m=azkdjM5?4fi5pUKc4eWZMI0DXFm<_YAcR4vnxniAxTL4VX;wSD9WY5jYzhWMH(*V(DrFc5*e@4eN$i``;`4d0c|1K) z1=cM`rbJXm8T6?3k)0SWnGM9gQW>*9C~#u$%~xx3l)jObL(4ARdZy7X+P#=4H<*vq ztp8c`mds?sXVcfuFW*X-bon17>d6E)jTbVxc@|@td#7n-bRCY;*2V~zOH|?ue3l&f zyZzagR2WUrU?TJ3C-WJ|kD^%3aRqX}8n_u9_-tWnb{El-&o!L=CJzfKMY3u3RMGr% ztV*PoU880<`6JU)r-f0A@&Qh;YSu$D0Y_t6+F?|FxKug5Dt_`4b+U&?5wZz!@f;j3 z@1a(=s8dPSmX;S%Rq+$rrE(o(zkO30z zK|ZkhmG>7srr`ns2VnS)PBiJ(VDK+~40)XeVyuZt7p89_Mec2Eyds6oUNdV#xZt$x zkLze}W!KxchtYjRLIPK$%8Mx+B*LqCqZ4$w1%w3p2nC7V1UhhqlW;tRo7$SBK3G?0 z!3GxzcR@BYlh!^K5;Ths#*i`EMZub`>Ly48e(*4AZrVarHpI1cLS!B_5IBqjeg6E5 zu3=mdPAK-6$reaf27(taU%P2zKmkdnF}(fPyzs+fS9vRc1kr($vG;C_z}0FEUE7bt z^SWuiVG(-i*91^gd_TOFYO1QZPbJD}1U`ItUfU9fSWE3htZu$b?;5!?Y{V6DmJP^4 z0G}8duxR?E1Y01@)4cmfVJnS@1tQNoPVaVN0NZLG7JlH~2i#5k^KDfp_mBZ1SEM8hd?O{N#-{u584CQQ%*FHSy_0JQZ;y z-B+6`5C9)JZh%7IV2Koaj3xeeo>-4B0fR!$K_V~2Xe^-g+IFqpValPf1ftb3z{5i7 z=^oJaF~sBV;|O$M@fW;(`EvI!879X*hiILwX*bruyOn4hdf$3MF1zUe7KP8bvuAaU zWAzbfTQp*K&xY5!@Y4VLmCZrg2)k`_!d%znnO2%LE)ryhU^+wbm{){+x`LaImR1`R zPEl_aWMe<-WICn@@N%5OXkT@v3-#&Xh;06k7d6>SZoazSgn2N^3I~S9J7bbesy<@= z6Ly~WsiQEBd2mYjf9H)pK6oU;+7j0z;Z62;%xUEthY$a!yZd_kj`i5>gZusjnSVyn z$bCnMn~s^p`IoWTFw(ZsR$m?S6z$EKn0dr9!p6mweyMrcm04~f4$ndVALlipz6)ov zYGz>CWOOc28-ACo@ebjljb!i2 zexkS`Tws2{5JpEW6OAh`z~;YTl5XUKi&bKKmc@%f+i22 z-rFMTn9Sz_(Jc;F{xsZtyq#A)7jN_6&1B<;<W(vgUG}<3in;8{S0Vi`SRs(+d>u*!JsIg0?HROv8dzFaYwyJOC9hQ z1|3K`AlG~<^1vYBLfy$gygaW`v6#bXLSuQisPODb18LNdU z>A~*t+qZ9w!q%vyM=|^fXPSj!1r=2(JR0)y?)qT~3u$%ja4BKTloc*hT#wor_NsMx z2oAcyEckCR>~qG5rIDUG2L!_=vhqWihjx9$fO9=jfC2Twuy@)F)8jB@*5FfYnYTGe z3IU`cSe)m7`dS*qyQ;V=kQpW*@X787<7uzejHu9qR}$ z-GPh9)nXa{xzYM0R4HRRaZFn34-YsbnjFihR2l^+)L`4Z1~QxAQ@c}dn+)5G*iCdN zd7n}{)}0vEIUmC=AdYQFV89;jARU zzART!aIW%+eTgclBkBq2FSw?tWG>-nW^Te4kL|-spbruIJUI9q*0zE=AKzF6)w7;6 zJ`Rlum`SQ$$X3acD|_?ikl=p%@9j*^qlYwzBm?NsKrnv4^sx|zg6`zvip;|rB4VK> z()H~d{gy3`&F|I(rQ-;rkgz(Qm+X$&2w! zM^Fy=V77>;%7u67fEVYtmToKlxiD=dB-@;^)ci4+g>v4~SQ3_?XW`mbq?zTcRcCUK zdz04t)si+f<>o^PC4mRhV7M+}$#W_(5wY%%N&wl z3+($hI>#5q?Jh&?`^-1jztvbG9?Jb@u2c8x3z_9+n4$z-Z*mRf17JNEq{Ezaan>L> zeiwK2GPg55B%!4=bNRQ z{NA~dL?imYH;xHd`9Jm>(YKic5&voC|JGl0m7o2GUFC0^5-=jhVO4LP%hczu4KG|38~f+epP_5$bn@EG*@6Lp9>GS(ljJsLF6?13sfMnzklO^Di0U z`LbW*&^#UEa)Jj&4+?BTbvKE0%c0#}#1|G~pRw(8~fZAQ*qY0`f1 z1bz-#S+nUH;uH|mm~jO0_K0;~@0H*#KQ?0h#w|y@r*jE$qAp>c2C+|J91PFV9Nl8F z@~+lQdCmFJ#PR$8%z|ICQ8ZGvk^CMO>>zPhSq&6ke-iIC-%I=dt%$0nT2JP7;&(Yn z+@I!u_bI;5JQgg@I?r=(Bf5PHC}V$#x4C)MWEPhSW|g!uS=@0@>4%g%{R_fJrO#YBx4s|GgLdJ(xzQXSrc8WpAsru(;}nBGTx!0-G1!|K zT9_xto>@YE;5T3}Soc=hn`hygkwiJKFq-@N3ijOzwpP{2hGFs}_Zw-f#s$SrsmV{& zh#axmRTyU-;~c+N^ld!T{%G^+lEr2p%EzC_^4Tk$sQxTIX}%q!l+gbD2}d8S5Ww(= zowVCXg)kE~u5|qP>>kyVdh^T^tYt?EVm_L*-18{0ADUdW$Z^@~_At4ypvkf8bmMG; zv6HXfYnC$w2xrNvZ52(A8L#D3AJp|9ydSD@yPfNPOvZK2*Y9bw0`T# z^#LIYu}5!EZBh4299-bUYeo^W>R2Mg>nYE#zau9nhp>V9*kDR9CaUxQW`A#ch=b~tGLuBC{w6eRWF62E}(jNscT7lJ8j1R)mQmjZiZ32L`=sESFGSoO%sDf z@buUx@2@r$=e1(*iA`UMjK^%D*6)7Z9Uio$$D20u>mTp;gI@i!aUASNSQrZ%|V<}b{v`#tcj3y_d#i#J@4e4xLx_#B_h zWR4ip1M4n1uQ3g2w}{H3nSpj6JYN7Qfj#WZP-Yf}yln276PZIn5sw5`C|fD@ z-+C+>mvO0iTtT#|-y?&5CM9{Kq|S?)y7ASk?%{47pzX)0?xads$9ySqOSLk-vw82A zqAJE9GcCJTBklfM4;yMCD%a-AqU$#NH7Z8$DPD~7VQL%tjTI*OAFKF6oCn%yBn%?d zsF{ia!sTLbqIVVAw*KQ%J?DZ4uQD?OJEqm6i~yhC+-ppi_q-*fxGOwthu*Po-#$Fe z5H!&oD7+O+ys{7Nh2Ec^C|$tYn*2U^ugQOJwXrh81Mi(Tv96v)53J}tbf4P|O2#II zi148;MueeX$X<8kEWdvJ%5&o7!RaVXirv?)wMefeYBGjTI%eP4enV{PTN{g6`kr^i z#TB0IwMi}+lL6_r()Yut{-UdLZDb7?(T%z1ZLo8vez*2i(sx}yv4=^o@}>(rb}; ze$TDFb-xY zD$(F9y+7b>Ma$(VyS1mzSK~PgZam_?BcwO8@l~Al^$|Dt!g^v7D!~^^_}JV2AWYWx z#pln~S@j}nm^UF-IuYdNpLP01OiXCnMDw9Tndn6@hp%n9z!vT0c_HV6htqvQ1vQ@_ zL6c2nIcy`|SOE{)Imw;`x1n!KJ?XnWvPUQa%d25U62~tu5ETHC$bEyIZU;EEXmza&`|h$Fr5T z`r+XT8-R44U%%*l`HOq+58U_iDzs{l;U%e04J{THPD`o}Y;S6c zbkrWzsZp*t)mTqa09sGQI4!599cO(dR%9$26KD7m?j@SC++6)l&(@$p%EQ2Wzix5E zM=x}OcPVVua%9mTwk~>j2ubWkYwP<~Md{=)8V)(j4ohD4!E4J77;9TTs#aB&enb~w zbmO^pw7?pUVrzGtVUb#oIb zIVFW7$XIa5T~d~fhcxlsP1s34jV~;?LF8F`*N3O7Dk}U{UT*7Wwsk(F3wUl_p`xWP z9(sm&RXNMN&4nd=80sR!v>EE2h;Xvyshf`uwA0$z`wQNC^Jcn0z1YWA_hfK;i|?vK zhOGaCT<0o3L`(47?o6QL=9|>Y7192{5UVzj6g^(&if?E6jb^88xVlSMx8DlPi8^y; zNY}3U-O&3xGeL*>9?uweXyTA*WN9DB%E_@+&7iN#>p5UNIh7HimZ0AAM#REeN>0vL zqqw9bS}kg`U#IeFo34V2^w$S<#_r*2sf?zKHMFu7uGy#5R6jjg=u4q+LvRwdy2bSS z##=teH7%!0F6ZSf)7u!3&m_;gHM8sWdWG_P0dBWUS%o9r<+J}5dnl~h!RM72mb!YM zk}k)`zm$0mG7p6`$lp7_o~fanA(-&y8iouBu2!@Mdo0lAyfXV8IdRteYv=nZ^Tgi; zl>Aq>2!dzJH$QL0_1aklW5VzZVDjbVdyu`7F! zoqI7k`3IRAHDfcJa9r+g@=VUb`1{6V-p3b~Mb*4_Np^hlz0WN z)J9UY{rz~ft4F4&mT%<(`S{<@B8|>3sE>xd?Q*D)K$byo{;$7|PX^z)Q;J?6hjCEh z4y0la*99CU&GV_ess3d9(e5Ozq4K2Dwta(MKdMc0Eh5)+d*f=d>1ynic>-YMw)1ln z^S-$@XK` zh#EVofBm9Fx;cA;hsi1fyacxF~!a1P1qt{7X~^|4L+;_I=KcvVIea7JauGG{rR)w||tQ_b4u4=$7x7aUcO{A2qX)feRhm3z|B=xcR*A$^P@yt_Ipv-P}{k!eEDkUR#u7I88@E- z-1@kyeh()2><`$V(p@vzD~0C|v&UP!~}5U0n+fbh=9oLBSS zhd6%(kT53pXs_{eQd%IOZZswQi18p4^7SHky6QFMxbdxLV(P_ow~h|92S)+gvoA7+ z^(mOmP0e@2U^*0CubcvI47$*8@m{)oId<`pjVEHm@O=v+VDe>x9;#psI0{wz5OQN~ zuuL5Pz{eOQ+xKVyXDi#e*)%v+zBtPt9$#?8awR?l&1-blCB@X)TC*kx3Uiz9e=LtW z7C=&sI{7JR_nEhMw;wV36v-|POW5ge3N8bX_6!Yq8!t?Fjm~vp57AuI>~X-r;gMdLsA^`$TikSPF_(-b zZLQF~hnup_89V}aEyO7%gEq^dbaQJXl`mCZHdba=ao`UAj`&MuN&!7Pvv+oUH+4>o zd_0_F*C7iaTz{ zbT1B-q~yE$3}YFa zo|Uicg(6GUQK%Quu$r2h3TY0PR^g0N48CD*+$}aU zrch-9aaj>vuOT%hti)eP-rek3-YWy6n;zx17!(PfE7hjmr}2nj4Hp#_Dm%ree_|Qq zP`xbWAQif$^4fB-(4rac0~%|~eYH17if9g1Qf+lf{}hnM+F3EU>aRZf-A_Vi3t>9# z_TZwzf%jW26kRNPCV4dMM*A{5hGR6Rx@Qc(?o^0#q>TCAX}EXtS^e^QbD^br9ip`| zTl@*}L*$Zw0c4I8A)6jebPU0XXdfC!+Y!yn^s%r0U`E1TQt5(_K)gz>SZY18FoNnd zX&jTWOW~d$c0yrL7$|K8q#I1qK11G@{$72r5{QInM1--MF!nZwKccPIcrAzkg=_bd zNQki;#^j4YU`8R9?{iD7yREIQr>DMgYpLjji5s~Lgy9J%l1&fdSPyDiEF$3G(TRo` zOvI+WQ~03$ftUIx-%2GiI4wbzedw_Ai8&0LR4vR^DIlTAp%j>AH>j_Xd9m@ZU3Afo zUAw?xB?*n~Q;&tWw({62L>q6bXUZKrBSg@nd@u%k+#A=gZ*(buv=N?^8>F`2w8M8Q zJQVPPUvo~o&un)eK+q(`9p|K zhc+8nKH9@_$eBJrWd+j`S= zHVu2xj3dz~dUL4iuDbs)a$DGqS_2&F&|@y@&ts=C88UqK1;dSI^eH`sU0gx}kA=DQ z=RmVlDPyZwRwkDfT{>&Ya^roVA0v-aGma@*BCVmI6sTn#QqY!o8zf*zW43wHJgoMK zyGKbvCv8EaeOG6xUZ!E$GG}M)0Uz7$@kU@#wRKE7nN4-(8v|IRhJC%!%@yeOgJ>?G{ekyP*4b++*egA6lvhS8wRzj#dMIH-Iwf_A#ot_vA^INfoR3(k> zu9N_GXYey13e0Xj1-Agb3 z-+0@mx?3QxeGPRN+RN3AM3Z1|{-PYAU5c4qhcWXRSw%-n3%ss(jj@zfR3xB*)v-xb zLOj%d<_WvSNR>elz4L2gQmCXvsJX*)^CJ!5I;aNe=^LO?(ZUXKUasu<`t%fg<;ELp z7%=^`=!85}WxN^R@AJ)c#g&S_Y*)GOyGp+Gb_u9VepL&PY`7Nb{LTfOwt?d*=kh$; zAM|{#s=~}LN>!D{m`ZY3;O311&u_0+X4oS#T-0^3f3u$dfVj{ONrHtA=1r;D%5(K1 z^#Y@Xw+OwybtDxqO0&kl|@w=vMw zU990!DCT1})fT?%*jsEK6t4CoJzKYQ%>ZF@afu84QnJEM#@6JC;`E zZVBt)qus648)omrpKX_dLzd>;D`~k&tj8Wbt6jiG|E+&Z=1QV2-9w=(A_fLPGKj0I(Fa#TNI=H)W#wGjK`0+ zR1F}m>h7($nomM&Keno3t59pBzUV&PRJ|z?%SLdU=((hJ*n| zWnjs7a7rIc^n>%5<8{5$r=RSw==!{;Y5@JwB3F40sYSj#go%gRZBNhdBO~gWE@htW zlN}K;;p#Cw4g-^erT)EPNFY1*?@6G}K37__mf?a9GmavzIG-*2m~*e>5$l-iz7gsd zMC^3KzQWv(;-PYQl&+ej_XaLA$?)3;0t9OJ{;6Vh{Std_zSt|_Etqf*uqRL8{D-)m z1^=_sxm43s3DR?82uBiXS0~g=CZODu| z+nZU`l&1J>7?a56%kz27cq1`w3%R;ofe9Y;mG&*0GDrhC!Ar(#5O>cykWogRX*&<@TFnaY{wR-YkLS+*ZvJD0^PrII!=z*6=>YzCT=(B)4Sg*bksr-LvgV?V1os zm92-FMpf*RZ5qrP)b3@D9~p$Buv8_{Fg5@CPk1(BU4UK_>P$@F+POBd56ove`p_D- zg1@TyERa1ZtyL4o;8?x=wpHux+z5uk>pZH~Vx$%u9Zr4nLQ&Qm5tFGTd6YNsn)pdw z&s~GqqA__FL>B0EgoP1TxjU0XNLAytm_If;}nyuN4-+tICAy_!q8 zTaVH6=<{PiQxehNkt>W%FIVnyi}T&W$QZ7c(2&{eg?`h`wG9*cZr9D&$;!irG(@q* z^=JYhZ)D;Q)Ehlq@UAja>xqcm^hJ9&vc>xnY|F!A?n-_>)2&Hn5uY;*Zs|+RDpyR` z&m$Z!Y$=8-})ZL}c_}&kZ22Or&_@5Jkn}wO>si z@9(D?$y9%~8cz))a+y7aI7BdzLS=eO%A93#;mvj674;z;~5@{$!Mp8%D(GD=HDX=-R|qoJKsTZ^d9w)U>y^L-YVYka@I`;Yr^-~Rc09xig8$NPO8 z$LsZcJ;yqK`mrpR-~122l6&i`nsnI{`UwOU;FE*100+^jy`$Ak8~yhs88fTl&fHg9 z=K0DBSB9cke$4KJIi^jgveOfWW_W{bEo>Q?8jleRpZHBhm-zY-Ba~7XA63F z?97KbCG;mQPRmu;SWD__Uw@s&(|Fpx`SS&mpi8AT>)|;%?{833?Srl}COxY`f~TQz z_`)o5(z)z}PmE@1dViOSWp99p!`4^0J95|>)9j`ki}1yL*PE?(?or!%LjMfN@A)T!Eg*6YvX6PUiugPidBB0VY}A(ivnK!YU{1B1 zv;zbX1e77mgwCv^r)Tr}_4}|1aGUSTq}hg=BH3&aJE5{3w$2Ro)nXl{QUyMqt76F) zSSK6eDsSARM$C0SFQ7t9^j8jgy2sd9S($g&nn7ZK;`+wxQNmWWLg0S^vLX&Vdi*%3 zAc2~c-~NJ;4>1QlA#gAD$B<_w9yxyUq^G4K8(SciZGmLexj+8bbh{=9 zSRWOr>)OJ>(H@=B1gk3R#J-&QpKBQX@A1t%VmTmYG-M}a_UR6jX@_@-!V~S-?;iR0 zZ4_f2WM}r279r;Ju=Jf|1fi)l5==or@l>=7P4CLa$$xL|Iv z|2A0lw7Nw!gWtYY42lhm5-LRxE4AL1mY|tS;GD%@1JAOm9n8GKz$k-(x4sxe5FS9ul(051%ov&2nw+W!tl8MpV+CG-J1Rp zlz?J7p>L~$EzZMj?ChaU9DIBrO%NO;tb9;~HH`q(+X0)Cc&&c(c5wakfU`Wj#@3GB z7^yRmrSpfjzp<|ZT24uh`A0jy2dDx)g83ss8nAGod{?LAK0+EGn`7Jj!A|(${FlU# zK+36G{ns`Pi$=`Gwng*)9>JxmIBSfKg7=VToQ?k4X5HMMzjKpPS@16Z93kO1SaNvY z+hil+Pz)qcWPktzT9>>fu~ooR(uIf2yuxtqczgRN&ufs`i15_e$J>bm?{6FDoE<|g zSfz+kf3y)DrZeqNh7TU$Tny>!&{f@l(g6J}UAD}oVcWrjKC2gE%gw##|JFhlXS~%; zx~vQ^MO0K&{{=FiBqZJfB3%A4i0bzsMS5?zbX)wr4eQ7eQm~RElt`?7j={rc_jufAhJ{OnnN)M9`GCazyGDDgjLYro;kM?X?M8bjom305WhRF-m`3O zPV&3`!xQ4@yYvJeGdC#&&xY3r8X|5kIK}?|?bT5ntWDiRo1%PkYM1K5O@yk@B{U7u zv~yo%k!-<7*fND|{!c2^{8Z>?!s>i;_lqYi38#}e3Hwhnv*w>czqzX5n)n+N(!l4R ze8m6Y`%#^w3J@XLlsV}{yDk4S56Ys61yMfe&g2({@48$QGtFC3px}&1-sf^ih(9_L z^u%EeLy`XSwVUvU5cik6Ho$MnNCt**^W1)HC;|w-(NdFll#VylTJ3i7=)5 z?@RB;G0Aoinr((CW>aHkesuoMqYuUHF3bQGMG82oa)QCn6}lOkh=(c)Cr{elsps6a zs}{ZSqir%SEcNI=U~NYSw$&)Ydi?O%Z>l_1R@`}IHGI3mZpVER?NcC=E8dj0968`dn$C#R>T&}u| z{<}yx^l1u`*pLZ`p~9m_kANKj5GR1Uapy7&;R<6A(;|M80^Q3Ez;yU3^o)!|=9*eO zYGo)rmMwDx)C;La@nc}~MGCV&9K{i?eZaISqoDew+;~Jn!gUNOW?)-cFjH_D^BTBb zKy!lZ7jBdbkyplo}{h5^pqJ9j+duSz1m{niy5+;hLI zQ+^qtsrpjg6JX)SP9)huA_%gY7~Tk_;;QzvH*bjd9BZ*p{BmXZwfJX6fv0#gejMqj z*h}ZH<1lTG=LoGdNb#`AC(NuPf`CTjIowA_UuDr<`(jM;JWx(HyP-#4LwU3_(9=|5 zHYEFXAlD0T93DWCpdM)B8UgV@R$!xh=-|OB#M5lsriUMm>qtpZ2qIl<@!heyZ|Vq* zJUt<^+BXX~2iTM~WZI;RJw0hhnx5>-jy)Z60^-p_eHj%YvJ6rrdWVU^Cmi~rKzpzj zA>0kgQXDy3h&%o4N@{U%_#O39gUJ^zHNt?5`y>f&2d6H6e-Uqsd96#s{v=I16VU!k z9H6V&$F^?WDb}agG2e(c8|R9YGo%}*q&YguNJ`$>7hBQsU8ZQ-ttfzF=g!?(eGy>+ zyR#yoMksO*fM|ThhMhtO4<;E_NYk^5+&E?5ag1&t7;?+jnujm8Dht#G%h33E)jS@@ zXJs-O!P-PBgYV4;!6=<2`3u7 zJO1J#o(ZMcP7l}UhvI1z4U9HB=&-^%&R1RgyIvp0^{0DRdg%1Dn(>0GSW)DAkBNNH z@YD8jMPlLt$gf}u-T&n_t^*q@h|#pwDA9}#M4`ah-Fa%CN^&ZOlI%fBbwl%Xq2ZIxm(q(CsJ^1e z$;&@wLUf(}xHq4khYjP&J-qC~6`wv`XsWAA72!5e>ucp!B*Aw>%DxinSr}A~bXLi> z;b6NYO)`N|s(mF+HOO%>rM8{u2!q@qlDiP&i0sY_7i(XiFA`|oVF6Wa7qYTq_6J>` zotbvo(p#4h7XK1&j&m7)W|1w%3}Uc*dHYs^cx}?65ck#E(_;q>5rl(Yq0}uzohTD! zBtcUF10?`lSPZ%LiJyOe2j>t+z>Ooc*F&GaD)0IDBInN~t2PN3h1(Ve-&HMZ34*gi z0u-X13b1m;9@}{E)zltc`-elQ<%ucj+1Dv4eU%YUwu9E%)7dF(KQ)E}wRiyYArzJM zuoZ4YVUq^6-X|yd!y_l`6VK-?Z9U(=2a37!aEiyG5Y7P?2<=a0ojwP-hP0&-v_XWX zwZs9}KnN!bK>)|P&xt7h+Wbxwk1pHcm=c^r5JYIEzI%-?1RH^@_y-ZKE)=&14*<43 z0ZYgm@SW$YR&J#Y8_8HF1;U0(Fzr3Y3m~_-y4^9cza2jVJ(`E(KrTEIj{B(iKj)qr zsW*ihh&9w*I>pEZGp4@JNw0FlAh#_SpZamsa3#8sN&NqEc-m3^kiAXq9sXx;xG#^K z%32EgF6!t0Snu`9@-|+^k)dtVm*tg$X*`ph^?J__iJf?0tOV`u?$n6n%KSN-iT~?u zM!#K{?TcRDMuCZS5ZMz}Q$HCehY_=eyYN@3>2ZRzmPP1C#me(Q&|vg4i~A}UmvXeL^exQXSSCsg)u5!9?-Om)(lGpkDEo<}VttoFi` z$BKgmZ+Ld^;8#bsnc~QTvNEuedi4C}oj3n3g`k#3U;NiWtxbK*C!HY?aN-i9x>o)6 z`#>h1%>S+=M<03=XaGQ{n&SiU^etR)gM;`Tsz#Gq(-59kb3%-bgICJ)BdN?NqT|sZ zcHSP)JmnM)S`Y2=Zy`uMJ9fQ(`gc>fpM_?K6-Q#+FUv)0mo905ixoE}+!CJJPtQ?d zZpoX?Ik&0G{+ntAFGDJkUNw!PY3VMrOBmkJ^y}9BfF8JlbG~S$;y=H2dW#6*U-%X> zz+8d@0#E|}68mh&@OLK1##jznxc&SW=hlGu`*XZ4G+dgx?}8cp;Xz~wlRey9b1Z}1 zvMt}fZDwJC&j9jZn{E0;)%KaSDCp|;Bp>Vld}8|H4Hxi>7))r{4v|AoGQ%Jrml#Izux_x& zT@e2R)2@Nn0LQTxy#j%RtJFQu(BoBoeN*7)!Yj_3pq~BQD!Sli_1w!t!%GN7TQOP= zR}2P~FsD^oJk1_@RX)A^H)&~+K?&e9Aed*xs#S+bl!w*}cbb;L)(drzJP!A9$WmcY zSX6>Fx&-G*Ra%s^xTs>rsP>dMEsx-xJCj8@Q+WX+myBSG-Uch24AN5Ve;cnJC98pf zZ`A_hqpAb#rG6Z;7m^-MmIR86!)}V+r1teK0i4j-u!S4hf{5PhhdgX5Z(hSQ?`y2_ zdG@TkrDdP>&?RLOaew%z^nL&_^6@w-1ZI~qc$E)R$T@|D$Ey{SBBDgF19N%|^z{pm zSgrVsdYu3fRBWB(fo;A$v=uEUYbHem$~?F#U~)Lp*WB0Ji&=$){`mEBQHFKvt|DN~ zM+Z5<8O@>8aaGbK@_SebV8kBQ=OEJ#ACkrwN0+In)L?L4F`6}$fKLEbAf^d$;HgFD zVcGL}N3s4_uGowtemJ>tfP8l;Pb0u?DlIVFTgPU#bS?;|+>3~s2G9qpaX3l9paJ70 zFn3V$biVtBm_}36Ko1WR7)0UWyR3@sy5l~~6?(9?;OMH1)zM)xpN1OO2$T#|!k&lg zF+e0kQ=q0Jpn;(aMk;FF&z@;wwu-Lkg~sD2M6K2IsMtWJ-<0c{^~M6 zQ3XBc)PfS;L*Tsc=ixJVxe-r_$_FH>UT9Xk=wa9T-wH4EtIkWD(CXi!nqbX~T6fQz z20qud@8M&lg?Kn&`Rdy@Dcm&VRLI}ib+QcY56(MGsv7>+cJX8vK6>=1=eugzR9I-d zJrO5CxUrh$IZ_+Vj19yA`&0gQZSHp=Gov2g)$oV#7nXAW`NV0cWhv`-|JRm%0oK!g za&n$Rm@ZHB_z3R|T^69L8w8lBSc7CS?$DjNO7o2Q%q-g$%Z-xj4lB}1zU5kZKFHha z#I}?1auKiPGVXX~T=cf$B)@mtc$iO4Y1;-mTB8G{5~nh*DsBI+Yur<9VqBe^RBx9( z>uzsR?qJVvaPRPvrETN3&t%+lzFsdIx7F_BzujKvGw#MJ3Pu;`2nfg4tKr};!IR+7e16M0;(mKmbU|{@ z*R&%f-(ZT|v15B*=?doGxTU_=V*TDW|5H~go#g51pFYiU8jXXppPXo@m@iUe#TCTA zZ{O({koV7Iz-=I{3M2w!-oPQ2eHWavv$NR^@}|8ny+%O|x+FS+xBx#tn~5PqF0NN_ zz0ux}&}w;r5|^)BNe!&o&cpLy9U(_t=_`74106X1TJwIl^ltuttn=r_uY4Ez{^mf3 z2v`ApKowbYBS>l7q!ecHva-dswW>KmN=ccuCdS5lntTL}YM-;%LS(Az>gA;pJNxL_ zGwx()iHbga2#bs?%FENoq0mtBO@{hU{=^{3D=PntBgQ58$D%b!E>dDOhPCER^yG1{ z5}i}dS`i*~VX!!rHgWjzZke)F*hQPT>9`N9p!T5n)v~ruYun(DY*clQM)(faBKE!# z>hEWwHc$Pmrj`>$(QkzpR+p$-@YIK0h9e_QNmo>ql|6;j zA!lyDbe?Ce&Fu6jm#7b}H4L-g#C>q5T6E6U1{E9q<)r_>H-92gF;%Cxj~$O1_P`-s zw%u`s69HWr8_9LBtOmPv)hbt%(IGEi7W70!MBs*|W6pX19+~O~q}oB5B-MlOrXkj0 zg^>|li46?eVbJBo2AV8Rjl4t2m-;XtU&~bwGO){iSXw84BKi^)6%~{2*nN&Gh~>Fu zc%k3|6AvynH`D33O1DTniuS)>Qeb za_i<6nVKtCt^l)v|N4FhWhiYau3RN0A`@(Sirw-kjT{?;sRs=j0Cy{mHuP%P_PR zvM?H(8n2MwnDOc|OSP$L@`dAW@lHqc@S#pDC&%&`Tk9OI z^82i!`-O$~9n_ERKQz+QC1`0v(j#@yAFB2!?%8CNz+H5ueK^I(HYkq3rENr~$_tn<#d+Ns+`erI4GqX31tKf6meNWG-4}sqWV<{f7t%Xmv-J_xDXsA1x zv0qm=6v2zidVwklPSW||eTAfhg5*3`22)pxCNNCU_8C|uQZFxAj^shZ)%615@c zvikUj6Cd1;%js+>O=7HLTbz^ad?B}0P%l4NxAllw^0CR(_KOEh#e8{@ToXaBQZsD$ zu7=mR=sgqDw<6EMJPn`DcxhYOv!p9M8|}-+JSq9%LD{WaS?#u?{AE?qq%5Y(JAq@W3}0cdB5y_!Oj4w6b|2@!9iY^TvP1A@H<=5hngkM z@~URsxR;*Zb#vjuqJ%W|96r7G-90^1({>k2Zk%~`O!gd89ba@B;}h@8TOy}vOD~o` zI9)a~RPls?`^IT5iPCp%-$U21v9j~{@n|)~o(Vjal#;gQ%w({yU$5%w?ZJKPl{fn1 z&3^mo(`oIX$Z5sQ1xVxOf5IUHftpiKOU3|M_9*X~B(8UFiwE(V!$hw!HNo%e^RqF} zxJIs7nDA;}GVQfh9&cJ)WfJ~Wf-~sW9p=PKrRgpdqmz5*j=XouJGWh4QL{0qfx^!7%G?KBh67yWx>m+8bVNk)xw8qV@W+LlkaKjFFgyNvA$P zSfhK~p`B*f1&nl-AJ#1=QgdTcH7+(kDc5gd@cCSwo_O zy#sLby<6T2cAe^c7iFxgk3BbVv^U5Hd#W-~dln0yMoxZKw;(~DgDzOLgNT*dZ0*eN`c!drgjbH4Jc zHcQHv?fOdQrOSd+a7a08uVGxb_o7_w-Ii{v!Jv%>FH_w%GxHp|@#U7{fh3NNU18?* zjRCvDW>UO|yn^w&O;MuCcM6jLT1CSX?Z7Hqbls zGQDr@#^H(f(Tx*nFJh%n(5~6u5HHz|1}&+L;ZsOrA_fb=_pM#^Wi}M`1zq;Xd<=174%JnXsKjXQx=~*er*KNNk4$G`Rtj zoy!bL&=4$lWKC1xp%K}8qFJWKp!`8+bF)r`f%CWG;h=%2Q(W^b2KMEvD?@j zitDaRFMPY~Mv^tV{N@e(aEaQ=9`0aksW`l?M_0>ZxLqeQZz64MM+;q1g>OXtEc5eY zr@^YL;47Wm&Jz=Zb%6>RV1XIgY8%ll>u$<)jo~`8l@VsB+FifFqy zB~!CTGf3SFDL;-kqzVjNkOp1!V@WVmlo4ml{?f&p>6+^1){R+1FN{pOoWlusgm#e&iG7t8Cop`0m{_irSeW z!&|*-XKdKP9N+OEFj?=mnDNWhtd3!ZmrajvD=(_#5XJ_o9=%iThXZrz#NgY-!8l7L zUz(Wk@MdNd{9y15;4DH{@>JnPQM*JEedE%Jl`nn$`hzOo?udjdmeP_wbu~57iA#5~ zW++R!G;q8cvVJV^y4U8kI{T@fZfK%$*SQO)vZvJb3=LCtrJ`<`gja{(bs>C^;QgZ% z! zTy4{ynZ9<4WyZM6nBw@C@lu2;i{O(anKScga|(->$TFm7JWAG%A}&0odQSJ(hW=)K z^|2bNsu@EA?4T2j$7znUG>izg+>hheU4BBZG=b9PEHwP=pu6bQ4tux{~mp;(4illhC=f+DX3j>lJ7DR+XhZippfpr_LMtXblv5+%Lb5-^Fz{_j2<7fsperDN~a* zgdv2#$iepo&v~@16%vovO+1EgQ1vlcQm1UKhjqWhpdgfLPGROLk?0$ zPn~-HL@6E1xKhEuDWqjUQTgCL!%wxZ*xC!Fu7C2BUhgkHbEYaGtmgIkcR1`lJ=@nZ zt^eLtuVsI*E!wFpc1F7a_T6MTm$KVx^|{v7FV67Un(=UPagB41eP9dRwRE^NML%sb z;URzUPzr<1$-o(>0XIL&?ZCj4>W^1F-ndUBDI6LF$a(7i&{pZh> zTBQ}ju2}&EO0z?Qo^g6P^-0&yh%ss5y_da2k+8I^*~q2KX7zn0*?2Qv@x;e`p?c~c z1b6b;-J*1r$7WZNI$C(vawRhdSZmW+PBQl+Rd`qDE(`Lrykk6(YlenpbWGH9YBcvd z=zm#Xl{U3g;lWsV=d@eN1(lk$sArTXgEvK8;?&;ae<(dO$>y8RtOd{Hj}f*R^E$lO z3(1^1#k$QY6&v!d;$-~p^?lRw-CN$KyxcGIa(9zp?s>%T9-|%~38v~RaD9I(&H7jJBdyq~uaB%SA;_e?IG2)O6C zt=;#Stn8{4E8>!qEi5g?&078_`qp;t2qQ6hHG+vkA?*CyuG!EmIA>BhDIdOD7{r#{ zBbS@Aj8Q@2FpaQ%S^55b%i1*_hF256J6-ex3USY+?B$+U<}|Q{)LXptk6q#j?z3si zn4Nu>89&ef=5ryx%f(g(cZz@?>g`WVI0WtUHFu;qhM#jdurqR*$ zxW&Uos=}@4?L-yjr*pD-Xqf36;(`;N<*O&i`gX-~#L!Lde$p-%z(UK?&f)TOC+g(=FOPd_a*+hb*8;9#qW2PqCpMN0a#X;heu;&SL+noO-`)YRQaK_RLY2S?J|e<;icLyCQdxB6O3ledk6pUT5hV= z4G_V4t{ppeT-$=c0XlK?ITrBY_1(k=>p{@npo6poND1tyH5P+KAO}b=Ub>obi@TDF z3IikKF8kqX4bvW2?xIBKzpWeWv;*-;d-g=f$6o_i57c!`u2-#H%L;^t&!5~FqD@v) zQrb50t-G7MW&I(5;VygB{UgG|m*dx}RmEjx^o|f8^Y4B5`LlXs{=}zKYfg4VfBouY zj|sdSVjaZA9WV#POmY_u?9;*wsbOiSjTYQ&qxH|84eR9%4CLf29dE7i)tLHtNr^|t z-u$pq?*9A%6qm(vS(EKM^xw15)`SIaoSD#A9KU|@^2z>}2bphFd46lTnI=URalNcy zQoNpC;07uJ!Nxd0*%FB@>eD_4ub=2^61~q-EZF>%X|0UT;>FW^_G4+;X&tg>Qp6{C zZsI_j8cuq=)5h?Uxty3A0YF6hgj)nRZEDQzdc`Mc0EE)hQyHo@l&pv z!BrX)1wi$09xeUlB!`u3SElFJ2@2XNDd}e0o2s^T>on>zQhOoaqZ!-bQC%CG^pmmK z5`}Wt$rBIGY)~_CrEqg{#>L04?+b@}yN|eoJ>tex;U1oVg8~ZWh2)5-6AhEclQ&MQ`@)s|Lri>1&MZ-qW{OkKACSe4BZ|;^y174_`Rm|qztC?hdm_+&>ug?zz z#oNfCh?mu>KhLTri!J1uSO_FZr$rm9rF*9G0AQcG! zz4Ki&v_>*1?mRhSlkcM(S_6zzu3fzfqfUX8il2@GU^Lzic5W)_E#?=dr+y=hIxm{QL*Y2YOzeSPzePdjq_$tkj#&E$^0zP`4$WZ2PS;%3~OH4VwEx=mqU|1Y3V z89WvseOb3CSE6{=*u7w4#TsAK*VhLf{QUVB1@9p5-o5(->-l`-$?QDYQvLac_quz8 zU7yAi%7uN1=o#ELbN<5FJQKJ6MM>wnx1TFH^rAZ4G@TL^A*$Br#jHIUdd56|WM^;w zN#2tmXY-k*f_Li0yIMW)Z3V(aL_M|iknqC?K7ay)A&a8@8O@LBmZqf~Z0V#9U48u> zfk!K+Jl}LBq@;LtVSt8NPK!5mwXV+2ijn|P&8A))jV%|g!aNTkjjNrVt?g<{JQrU_ z@)`gg60t_Ux~^NGw3-j4dG*3+^L_Ol9FtEOY#)>kv3^brT4-Vdjs=a9<+%!`*rIzn0X7kLF_*i&8 zL5GLUz-{0+D66zdgrcMPs8$+kmOR&d(wChUkLVZ}ygWP@O}4F7J#*&5cL@@6v*e|T zd%<)mQBiVNyys9%X@@O-e}yNo3zNCRc~J6QoR%~=_q^|$yMjkoUvIWpaV|vLJPr+$ zBV92uo9!nv1-OlVV2`!tC$z71Swc1}!J&51ZOtZpp-n;^Cpo~gKIt|=iPQ3RRL?$N zXUr1&RZ8DfHZKr{7=`U!U|90jyb-pF}BTU$><35 z-UCdhB?M@H#aBs^f>cgvVegcvkjng-dpbIJYT8R(>CE8PJc_6x{dj%vAp^Y8g}3Ns9kCj)`qNQrsqCOvgF&6{2Tl< z5>$?wJfz-HVTOd@U&s2ox)BO__*}I>&a{d#_u4m?hZjY!BPE>HHKOd=Z&^}!l37e7 zH$Oj3mSL2uiX%~dlg^f^TbG>6UcY{)`(?0Q0fT_FX~DfssIhf!Y(0B0{+Ra6r8hKp z!}xRSYVvsbL?m*K+s{Zn8td^*T4ny^Oti0R?vAapIG^}|S++>3w~-4TRM|vy^#*Nn zy6hmCP?r$wk$}{X?@Lw%NSd(=YlxPdKSIPoT=gt;Qh#rb>|`18@wkNxd|UlbsgQ8Y zRDSvd$h${8D}C45?-j0q4Yf}D>YYE|kIJZ`Qd&j43={rQc!Agf(Q3{T;dQ7AyBRl)gC7 zTBMhAZ;3n0LCO72F1}l628NT?AC#3o*>k-A+sos6@G57=nv=tpJB%k?{PI=;SlBPb zrxSg}rQxrWY`d4PUe3tBv-^nINQM;|Edmo|)-=1OQ=ppR&&y{|aNK9R+h##_5ES%M zO9-`}IzH3C!6pm%_*vO)t6rLJQ4iwpr{NVFD41@Ee5g|&$ti3;X?iXLD$c%-?~bdt zb^6jsjsY}ds&K?pks2UC9PP!C27C`+zIpiN9N8 z0-<`t+MVj@;Y)*J#b4EkT+!2;288p{BPBjw_}So67b>m(TtHC8ergU7r@#UUekb|3 z)tf5YzdC-%9R1+G`H=AJn35;xlbr|3V_bFC)6s>$awLf}iQ3*MD9=9QY98mBndz^Z zdg|Gpw0`N&){XA=t|NLM?p-neg5?Qtu$ND_c%VDoGbD+@AAqs$2G1><;96%UJFtl? z!J=l>CVz#&&gBQ7BB8#=JNVL?PIcTi+JI*S^mlw?h<(%T;{$xMLIHHO=`lb#? zxn6_cS#g2b)QC+Fv3tc_^~;-1E*0yI_PZcg;_+yk<4|AUta~3% zA;X;y=PcHsEZ2F|i7h9mFQYH(YQIig9wQ2>%N1R`$27JdICI5Wyh> z{@3G?_O2^CAg~3nKK*XlhbZ*}vl!8E$T1F~?^O@u z+!v65@9;wJYKJ2riuaEkH74HxFz;2J6Ng155O5k(lv}a!))?jEkfHpim!o zSm$wMVZl3kFBXBeF8wu@QBAU1R~V`!Ru9Q&E|{4SV?W*h=|)GZ)L3aKtv{&S0kF3= z&Y%^(vDjq!U&9u>bZ>iT{bibLl)776S~7q}nOyqQfH+qZ$8!=HtmF4Su?K$1h|Ej6E1(;MM`lE$VeA2B$LmN57dG6)3m6A z*(nmhTClscszwT}fk%*%4%SD#l8h!c#EapeP;Ie719Qc)=+i~{zSxf6=RqPq?SEiI z8HP7l_tHe+3=*OKAxe_Tts z1Lb{OSdr7LEKiye>?V@|q6NP)Vs)_9jnx*-8c!~H{jICI^m^^q=AxQL zGOKy^Kw8a>^C8}`4gM`8%**KPp3W`c1md*5cQvG}yDes?YWR#?h)gf6`NU+^Aj?M~lx$|~Uf_S4bQnu}Xr z>mIt6fG!PL?odG|B_R-H64adU`EX?C1z9Zy5`6G2K+PE+8xxtJ1UEG`eG+jIfYm+7 zy7ypA0+|qam=|o~zCn#(Y-9wTDiJ}G46j%xHq6`evS2XeTZ;mo;D*#`H}Da8KkdM5 zHX{QH^}SFZxB~ZR*i5cmsfXYj3>%+vyKUFKsgrk2{e3}CuY%%Gsz}}E9J5}A z#2&^&D;Njm!w*~rG8o8x9gTi=TVK6{hlaX(k$YTmh)#CXV4D<|`)l*QrjV1&T;n%< z+hVm9G&{bWqX8#{dqncaYH*JXkB-vT^D0j%8o_M; zo)P`}PuZCE4P5VwVhV7Io-{}abRGG?rHE|i@tGg7#kh+tyD8iT;Wgcl zvo6HgKNGaNCVBO0wn3oX<<_E9K)vdPj1_#_c+I1=&MfBp7>KFt#{1$z;{w+PlU>U| z13{sTB}c?gA4t#{8JZ@epzuC;@N^A?_f@c@02tEUoGrfh$ApODX_AWo4p%s_LshaE z5D4-k8!Z2cahwUkg_+6JJ0qhgM@PqN+GffKyblctfg>d} zVRz;zH)R+v`IKj7o;CYPz%um3fRAdQMCJYXNEzII+B~Z?+F@|_lgK7j`-$-)Ojwor z$TK6YR^t>3>dlu2O-qa$T3=-|IM_w!US&3WR-V0UU;J#^eN*;VevEH4i7kKCX4|UD z=eHQ^9KI+{eJRrNr{|kU)Kf)gj02bv7{b!z4&R@pyXyTTUCUv2n;kK^YeG` zA#DXYg5~;PTi4)O=i5UQY=Eg6{zgIm)o@UGM6=}sAA%35L~F0xygAjVt^}v$&icRs zR~cd)HzyoHOUMz& zf41u9ff)eNIdjG%<|>QO)#o^d5SE2%x9`hU{PT?hF7Wj0nYeQX>>F5Yty-HUwzUcp zquddkZK(Z&(GezR50)KTwq}!upWh^8TCO9w&d~kr-TSe=-Uj%tva)iJ8PI}SF#tWV z-b?DWvH1@Y*h}b_O9$kgC>PG3KTN9T5-u(-&di8Wn9|qN<4063wo_3LHpkgJdfM9B zNcGCLpAN9@By=IdLPC^eT1z|Fn0%67yV=_ANF@4tLL*}|)ZhO|@FLn#dOv25DS!NC#dRm;f8Na^e>nigNM!288-1f842=Q_^^ zmAaRwr&h)dviGDfGb}H{ z!;g)d!LH-oyLSy5povpACPs-ss;={2a}Ks)P+frLadvj5rrr5-yuR#UlaiFA zWP!|~dG-u(OD}lK-Lyg_#+GO6`OT|j`FSeB#Ir7*WLYJ-{~jsA@<(_wLVv zf&%1L!Ekr~q^Re!m4uX)O1~Fa{5w-aKe%n5$&$Dz*zj7-b`0u8)Y@b3{TEnhuwLfUP+vn+ ztdvfTCza%&w!C0FIZ?jTuaY}Mih;^4BS~PyAScf=qEA+UNO-?~8z0+c7+lE4r~JDe z?Rrz&2}oJv!9mn!xY7Dsq&(JfuKVeP!!Asv3`&qrgUFhqdM-4Gkaq#t@aS4*`g|%9 ziXCvYkrA|f#R{|Q*Ejh4fY}J5+O1&2&4)LdsRE>)BXzszAx^o!%{s;^2LE>5=g$Em zR*xBYgYF!=_55dnO(p9Q2TL&{xo{7?cN)dWsDo*4CT6&)5FAd`7;wwr%;!48t(8_e zwhh&YyVyjyYD8otKq|>d&g>ci{q%WlUURbphR)UEIq5r;{a*Em@wk4Q%201eqeQ)WwF=C^!9km@=oI|;uD(8ADFc*Z z5)u;F5%{ujg$dduB@3n{r&1_VvF_fxr>>y^YGNg}+U>E43G8J;vlKPdQ?J5u*vQh% z3@X&i_VzQVqKb-(J#Rbdxp-z|WZ?d3M))V(TM&>{v(f)gV05lLo*o`f!#K$huEBQ5 z0#id#!w%y$HzuLJxj{>-!ZVoyuM<6;I<)Ll}^d??6<@^PnJIm}BA5M9Q2p z-nQ1}!>lS;@wOL~by9|nRYbjR-_8MqmpVoGK{(0xLJ~j+0}1Ma?+>GRtmo(8kdY-J zAxtsGVaA5BX8DYT382aQ%1t9TOX}d;&y)4n!ou6a=fS;6)6(iL0 z*Z#Iz2MLfolcPx%1EKHk5I9s*FEH&_nW4cRlP-szVILaG>(4-v>BQ#AOS?fv_9rTy z97#FDN?WzjALlF11Z?j&*56j~c{(b1@#@5I3VUv&TnV<737e|l+IuFp$y-1xseb9b z;Hr8Y3{E=6O&LDL82%7CfCuH8|KrZ<+UUOsxxMfS#a(;n4ic4?aSFGNp0T#EA=Foq zk-HIv_WZeo@Cif?0~&_)CSoihlxUVRMaUi^e7dKiB8yhbAU^FvM~mrKXva?wdLuD3wi8m@6MF)?+Sk2TUt zB$ve&upo!N!PC<-vawo_c&|KgA%X2v=30|W<&rB&Os!ZqYwg9Kn)H12$y0E$2hc~A znh|{RUzfv?Af>CVMH@@&?DrGNONxq*27+xF6OxmYF-i#ym44NaxF$N@h*M|J?p&+; zrQ6)xJW@tUs$qNaQ?SNQuYG0yN0q?RQ$5L9Jw>Ux^<+rr-MR&MwVPHT_J9&$o-TYz&DNkN?AMHu`jvNtBp^rH_g+rX7+?4^06NyvO z@mIgTFB4q8b}fBh(6IgRviSnx+Nzb6e|D`SAE!-CruA>o-73s1OClT=F#LO2>I#Dp zy5*g1-U7zHV^0WMWK>re2E$(T+fvpa!~)QQXk97%;TO42PC7T~KBe+cLkQebv`CA1 z3CoTh;q@)TA-#ASu)!dY-o!iOGxHZz3MJd%%Q`|Ddq4_KK{r>l!0v~Ym8S;E(oSR3 zHjFk1y$C>+1ymv27iZ`r_bNfEg}`({DNSowK97x|l$Q}B8=iJ3o4Za^MybapVL5@~ zgX5<=3mOz{n&PA1#s)B zgGZ^4am~F#r<=sve92eb=C7ythJXJ|*=smu?${w^zDRSva=S~(fVzUHEb?F#n#|b%$1L@{K#BJ{79&7_OzAl<>I;m{13a8nDgUrK>C_%!@2OU5|q&Y(Y|VF_T!?R7*2eL_JXU$DdWd2;g^^%7ox4GS)Kz^lRRtObNa5OH zXmPx}l2}6`KYAsT?{mujB)ln96(rF_-K4y9a*{WRd(I>o_Gup&0DX`MU_)JjkbLZ7s}q&Gh%6vWj)T74VQw#28D4(Nild#37!LmDNF(En20=FFD`N zz5H+K_7M|TY==4%=u%78G_AmvyUI-LqifM2wPgD;LqE~)=Omv%|5FpPAo!wC z8`CPh56$Ei88_fPwPK~Z$vyRE^6{N`r`ydj#4d@fz0apj9fy}({nd(?nVB_gBX-mt z+W8F_`tZdHmw$91Zocezjq~6P@}q?+wf#%&Hs7IOP0>t1NY?a^yfO{smEr!BF1_ls zgwTP1Y5F~d&fxaX5k2F99KLc@Z@1-e=9+s7&s#6f%S<+qgIw);J|E~WqML2C*t}qY zx*#rLLe>m%HNLbOrOw1LpzlT--m`#>Q4P7p~Ju|fU-ZQ z(8)ta2+VRpIJ1v$F+lYa_bmF$XT9$2Z^N0^#wBhcqgBMCFj#e$frt}0{BK72ArzFp zrG%4p^*LyM*;mG~FFv2SqI!p$f7h+Fl#jzGl`en&RHG85N{ek>o#&7z{)eBvUBer* z(ren)e)^f$?XKoD{P{3%$$ZvBn6nOHpkvU*o6OkPQ4uy5=lx>UrS6K%=(cm^&duw1JwGWw7hD(x~?)A?g0F-c5fkKw#54}*Xc@VMr_FkTA zOvA-ai4p%K-Vf>xWOP1A>2TLVg^OA;%W(dltE7W=dJp|6yXUr4={RxB1|_sQ%kw{T zJ7%74`<8#pmgnFNfDZLtJM*r#4aUxRAGQ($c%P;3p1qjxn9r-$2%O_WbiI^fn1tI5 zz``+jk-X7Dxm^T!Szl!I(HvEGd&UioyC!On(pFj2Q zYBM75lv?>Lic}b%Lj>leq1b>+q~?}$wIlG4x20RL>V&Jx^|GsY2h4`~5aZeJuF&5s z^yHnliQtZX?04ZEgFepEsq8F|u#ekvYAK7YSi(;abz>xrhdXiCzunI-cg$(Bd{#?8 zHM3Zjm)D^)BFx0AOOoUpPBB`&>-R+rO>jDsJzGk21++c4lZW z(4_df{~KPyC-K*E*BJ#VaSx=HX^{T)U!DaGCclwysQH}=dr^p5SP-XL)v_WP>J8(| z#4gONL262y`*4H`l8apTvl>|~Q>x#vQrFOe@Y_WwRNawbPBto(kH6*zvQx}pTiZ^; zXexCHQNPgouXfx`RGELR_3Lq|cEF2VJZuN9ldZU}Zy?UbhCd0$jg$Pnqn<=bxv(nC zcFthx27l0XOloAG<~r#Q`x?yNAhlzz+~hJ`|1_=l!J*!oI1yKh&_)ErNnHg4Z7 zs+nvQs#-3d6l=IT^wD%pn7e5&KYlRI&gaBnA?V51Q~Ja~D)H-sH@Q)U`a7yY>V0Fj z?U{dlv)PBu&}61+1@X_(LQJ)UTv&lCnh$(;g5E&b(qh90cW0l0Zwku5whl}>j5HjM z3m4Exy_U87thp7uMc`%BhcpVvTlxu3D78j9SGoFwh#qkmPe_bY^_Ft{N9}^H=ex<| z72!KUwVqQL;XlCD!DXsWYKoB>`VkSv`m{@Y_Oz&_NurR{)I^A{u}L43xmS8GB6xdV z_)VO%$zfHK_}5Fc=_tu%$G!pWD_sJZjtv$D$~W5dT|IQDo>erBwdC_oheP&L6y;Y8 z+}a{Jjg97SZ{GaIF;dWjx#qbN@4aBf-CWS@$i^DxBu}>Qk#$|&XEXdwBsDfW+nsU` zMCF)xfV`&*KvPY>ZXh@woD~zJc~GUhwY#CIxcFPCe{4}t;PiMRqu%eTsg!oA#7I|9 zuQ9}R(zA0z(cufTUOe~Xl9CJwEtDy=P;*5%-siak1!&yNOki4t!9K85bMwXe!9D~* z){SX{#S0-YWG_i^LK0Z>Z|1{kM4}PC(@30}PBLpdK|&!G@a$5WUakjQ zlGFdGpYgn1Frzaq6pINJEO|yj#BrD$5TPE~xJaq@*0+^ylMK`kZXOH~tmgx_M!PQPi{Esk=v8WXQ|n z>_c~9f~qk!202C6R433Wa>SbX3LAI$1FQV^7bGQyZw=7ygmT3D;=N&enJ~@odXMXy zooX&e?B?Qy0APQa$V2uN4r4Xr49e7$D?8?L{^{$#kAQ*%e-?+?w3nC(Lz%`{r(Bog z5zX5g_?hEu6WB^7&6v5he8Ah}+2PjI82Ft+c@344GC4wo-GyM_)O|dXJoJ~~J4f+4 zQ_7#JzFLI&qnZ1KRt*Wx97+(;^KY5A1nx>fSOfrpxB;|99(&yqW#(- z4**}tqW8pA5^1kCb|WN!kmo^K=q_^2p+0#nu!~61XHXPYxerPzG|4M;SG{ud^DBlt zE&r;@;zhQyC$48r*qD(>FNGT0b?BUz;wd=CXvc``RG*g|7){k=bERa{&SH8NWah=w zn_wW*F*4r&fx~6ce$aTXRi&y$ZYnBKk?3D*o46X13&;!D_}GVVhyrP#e0*PPV;FoFo-rTx>-yC8aXbUHx+PIhgIVHCF z`C&WA0dl1|!Yqmwhk?V=vV7nY_OOSJ2)ls&r293*xsX3qSGNV&+_QsPB+X9DZf64c zB*vdrIh&ma{if1yd~&xxOjPIOF>BcH=$ z=14{PN(aouU-f(GXni~ra&5e=exKR8#bLz#5h*j*&Qb@@|Ejp2(EFc!Eh%-<$%zrR zZ3#z?Oh7495OK@IjyzRqHOPaTpZ$Nm`S%|tkNCJoC=G$M{7-KTwOp4p zSo{;H`qdr&Y&HIT>bI4^X=(jW{z3elO9v2O(OL|^*H;57od;~@iE+( zL!<|b+EjbrUnA~N9#EU-cS_UkA4XenTlYRoo z1t`h~X%ViKFI0$ZB16MTzSphe51z1XkV;81=ilsHLZoaNbYP*bown#+F5R^ zzRXdR-YvR1`rb`9~ zFOy)^Eutm^PJ?J z2}=-R0QJyk^J=ASuf_o3bF%TP;e{j1*le$2;(9GJIavUKasZvdmH)WWA0HpRbc+hI zw9>7=b&vrG$sQd=2pc||4t!2he1P*#-&)2>ct4{*FAo&g(bk6hMGZjz{#W=K&?m(0 z!7HyA!3Mp{h(^2eHoH_(Hl1i{dykIef!UYo%8KQ>I$+?Kmg1?UrrT4 z(eUNn?IL%08eXnX?!nxw)g7OS5l>l5%Rj~)E4hA8&Hv%axxJF5fudi5d{Uwk|npIlEIQBS(H#@C1>8Z3sd*$KELD9?pCPUd#$iHC{95d5!m5dpM+gW+(j6XeWlLBNr4M-`>nnEGh$3P8b4hV= zSXh|YjZKg5zXXeioKSdmvUKxYGMf(^IWi4hg6r%==bM9Y`Oz@TrF$ef%gB`H@IFKM z%(?ZNpjh`q907{Bj0;?J3Ko5_@2B+Qjpw~sB;(Ass#Ui>8&%}t&2W^HdzW~w;Ppx6 zsXYuH?(WT#K1=;hrx?v&jDH0)sN4F0?D-QUA}SN#s5k*C!3|{0H35gp!MrHj;d6d3 z2n(>UM?jx>coe`ory?)^xc5FLs6n~VwFHbE^dYJir5Cw@rzB#SK}xOxW=KI1`~Csr zDdi8RmhD5UX;;MCY!{Bt4DHz2@Ns!Y3}+FU9fcO`Y`D=@_eVW6?fJn94>77J|I0#a z$K4J1;J6ngBqb>XiCb6(sl7)2kIK9i0_ zk40gS%#?-sVZaJ<5#a*`0~1lao|SVezvvhqEBq-dsc&@#EF#j+wgwgXpa!13zx`O8 z@8!<6w%vQ}vF#wA+TMyv=CkSGcF?JeH5Z;o=gap+nw-zn{TkI!f$E4XnDY;)Uygbf z5SWPu%+}Z3-QN}zc;CYWKScLRETVk=%mrD2*Jg^$6bxmtBg=Yd1;-!ZXXCjh#Kgoz zMcvkrV?2XAYdkM-#T#0(=ZKe~+@T}g{HH5;%ALJwbjRavRHCWM&c zICOR2U_WX&0>r}fL2E<3H9ehrFw6?Ri%-2+4_o+2tEU(QADySYM?^Wn*R&h|+rMAP zy8Eut5#V)5F*ANB&lnB;LJ;jWhGV?nmoGaxs=fkD6_J*`nK*-pLOZeT*ssri8-Jv!k9_-ey!XQA&J6TyHksIp8UKuHy4h}EJVft&q266^OTVw+e zbqdWz^mZz78v3TDJz#(P`)7fX?>3R0wZS3^qs?qaJ_OU+{Pe`c+wQf*I)0Xt5Elmq z_X|RV;6)n0hanvR9NW`xn+z7R__Arecz545t7l1!#o_3gsxoP-u^3*#&iLvIB-|2X z8MPMu*ZOvF@VbmPijUy<$3<}yH5ONF`(GqOj^kqcWMOxAcS_K8ML4TvlBJD}ql_X_ zKciZ4=;p>Y*vC23DC+2N%K}XZh^7nWvYJ1sHB<(F@WCl$iG64*)Z1K}|T#k1aaqg=f_0CGDfxh3y zza3+LYifwsj6X7eeVlKhELgvh0rQwSXe*hB;|C0%3AQhyqNe$X@&HmsuH%3Fv&99- z^nX{AhEB(}gK$+5PXScR;`7%o&0lQi$EcLo?55&+m+W7O*WxT(puyop+Cl|P|NlI5 zp}#!yUlF}`mR#Scmg|rHFMi(Nn&K1^SzS)<0x|cs+oa3~MmUHI8$VE3cJ1l_okmlS zoDn6FrgtZ}6%21cT<2j)MXNPMM85aS2TaLz=@z;WVS)Aao^wIMndLb-xm&2bP{Pd3 z&d_A>4LymEmzkdG#F6lJKtWsksMGit96w7ooY=N^Z}-i)gU*w~n!Qq2iEOvCXSa(k z{T|Irjc+|*OjcJ=*shAumK>C*jM=|6o8GScEt!-XH*X$#@Wf;rw`eC=5{~9aDDitl zBM*lo$ql{->%aX>ZSo!%j*$nN54U?tn$Y;itHf}Z`uh(b&i=WGHU&yi;QtUCZPY}F z9-^a=L=1i8Fp$bqQM&x0A%~D@;eaf54z=%~mz9-8VMSzJ#?FHW<+&lOEI?NN zjTWNk$Bz>g6+L^Dhld9O*p{ywlw?y#T?$`yg@p1Dsa#@^d5*j#iR8V#+Ce<>#Yu#q zt=Py>HDy6^cJuV|asZLHQcbm~oU%%UhdVGI^42%+^!~^UzmEaUjTu%MSFs1?8L(Z8 z|AG*mJx0QZb@T8LIDGgBl8QC*_(>EwBn_fG<2I6+Sr09HS7c}|J`92frKQWz$`Lx4 zU;DTZ=|B6p&Mi03euheJ_o0rC4xL=53CNYsN)oYgqEJdv+z|(WDqM3D1hrz5e9C&w zwsg<)^(jRa6|$*;S8~@~Ps{^nMFhQnfQ}@JpRQ@!=DJgE5Wj%})0vQ;R+*5HzIfr{ zv3$4HQo)C$hvyzT_SZc>bME$I~K(N^Hy=LGsK(-BajUz_MqL;&XSot(VLqlAh_Eqrh#VFvW;^JuN zVCx3oZnj9VXvs}WQ;8*RRnuwc;JUdc^umm`uG-lboStq=2!Zk#+j60#K|A4hek=d2 z2M^5JZbp~Oq!VAUNY)9eDoEVX<_TM~WeOik@>?!J`#V8)L33n8$HbKDIybwN$?h2G z?Xhj^U*CdyN<=p0yrq&rIR9!Sf*}@l&?q|mq^xZ1`c%|949xfuGPmG#O_<^~PEJd# zUCX1moRfDMDXkuyJ4pAyBD!OQ6 z}}`k8iQhqexTkz?&jQbUVGg2^#OkYD z8xkF^hL}7!@L&Agc=M%7o7{zt3I11HO>jrfy5#O4A}|r*GPiKF^*{R40VP3 zOM+F?i9gU@wlRu?EytLbFv+ld4cSZ4HexNuNWztk+Scpwy!&B$QBk3@mBS08GLe+npuvn&iv(C|Ph- zuiGQbsRCDkvU0TmUH+ojv0iAx9zTBU_0r5}8`R!*IEpa9xbbWtyxFJMLzNvcRMo;Q zb%h-Ec%G|O4ZQJerxs{rtMycb>dzwwI|TU4XqpBh%)Yf|wV$pOmzK7fpiekPO7r}l z&q(YeMJ)B`n3y7>h4_EZz&`#f0}HPIUs&L4{~M5|Z#0Seb(zW=f8Y-BHzf4pd^qJ_ zP`d8}x$zLFD353Pl0U&E5Kf{4Chq4RCKBKGJ2}qIE4+(^;3$=`)>3{6nxnrNRPtiO z>-W83TwGj!jysawx)lZIv);{|=gsnwd|u^{UH+n5rX`QGcqDse38m#z1 zUVfMqiHy?zHeqKTLzG@K&u@OCTfbKj4858Uc-2BY{rSX8KYs6gfx*8!PG0zpv!}!K z7^^=(EMF$F3y6VPBL5)r_%|5uzdYO*^w_5d^^5N!wjB|v#60;r7bw?pt#kMAkPSZ6 zhf&7LO}3Cu9AxkmJ__jPpoypd=0j$7C~^0kQQ}^YB0gM#_*Mi4duh%$hihR>*!jS1r{GoyzSP4B|5MpBr*qa<;$Y!Ex#p<FtdbX7JRRNCZb zjB_BSmprulw9LE#GcN1m7z5}C#E|g0)6 zEB4=S(ggfQq&BcKQSVRO?jG}T-j7U*$%br4Zu~(Jd`A^>T+u4K0HBRHZ&_szIhVAw zth2@gPj$FY6N(Zf)aIZfX}k=5VJzfUFhaEI$kX2Bz_qK3x> z66V=fYL<3%#C1;@j>Jp-i~6V+MY|^}m#$(|%X4uS7cT(3i}RH}H`TIT0#zBI^np#! zF^UDSUm5ctY;XA47#Gwq;|p2!`~zHOG-+L4Mh=;DHToS zL4a2<#FiWRotPn8Q?cQqoxAxj)t|Z)y@x8nc(V=9i%^4x1)hP0F*GzZNH^KQ2TJ7M zOXepxFmGTITReP)`d7q56Te`f!PK!SD#32aB5ZF80TOQcnlCP#Nj&=o18kr8BcZ0U ztc?B8A)5(dgyb8lkkG2Re4aZgA+c8^%+CX$xA(4}Z~c*M5VtXSYsD~;Wk}zU3E@Zd z@3VIF5{H&>n^YCXQnOb(MsDr}h6){_azy6I!7u2$ktP6RC!?1Vc7W(hvi!fmN zP&*Hz=FhW6Zc?P>Tn44PRpTGvdH``Z5S=VcFS=y`#cj7dv8t#O!IY%=CU3Z5Q8q2D zr|LcA?6^udl8q_+ze6vMaXqHIcK_d2;PzXOH%`xy`sz1O@2>wbJrQr7TBnlDz7EdZ zEXVLR46QZ9p@?}697dhr?11yL*X9R6ymNl!{7u9p>CXknRzX2$dw}juAD?O_4qxgQ z&sZ$FR8C--91nHG+l#}C@nv8R5_SJwn`9!ZU3Xxc6(P5Yp`yX4GmeHB*IGjbBJDr8u4YnzsZT< zGbGaMt8=sEcYQ0x*SU}N)Cz2l$0*lhqK4;>eVd+$M~4*tkA5j1JK}_K-2##D8-W4; z=DchwS~o-qB~3uRIa@~HMyUb zWpDIf9xNS-2Z`BeUVJud;7MVV3mbaeb42ec^iOnhWO@|hedNIZ`E4Aq5b12svzbeC z-EyK*f*h4mE)^<$4Xf31*>Y5;H6eF}1Lj{&r1QMA$>Iowgc)cR~!8@55;WmC_G>pO_$96yrYh) zrw(|8Q(_DG6d#G6T(pz!opb#+or1rJA;vmItBfF!nyA>oy|YJZ_VMlH4?aW#?kwF> zf|NTwSeXQsacBjptWQ9t_(@J_^8rgeRuwN9)7%7N-L|b=kC`bf{Chk&pyYb}+m8i! zU>zA}&i;~8eC(NNCp7#i>30)K(4p{MzILw} z>#lck89F6J>H6=1=3HBu;c^RW&X905Aq6^gegYIgw)gRKkwRkzW%z=-u;NHzeQTb{IT~9Gc&Cowo~w&c0DIpNJCj({boBruF3< zj5l-a8GYQE?^u$J^s#KM>^8;xGq_bd4O3?8(^^}%R7={YpULM>QkIkZQ?_Sg$=VeH zxA)9csVs{o8QTVCl8om%yLOcD7__@oP+n1TN$mVqi@wcKCYHUKcli|UO>=3leL9V} zN~;bu2{ABgg=96I^QX(9uo|TrDlLO?v?6XR#(YviLPWiD`X@{b1xSQ@W zZA^9#&0Dp6`8$zFHpT;wJlxC&nk8eDOA;JLqD}LH^LAbg>}3tlI=<+)XzQNQ2eG<| zVX8=;t9~V5Td9{T6{z4R5nYw135YJ{_H1kvsI1SpKToI>tmK1i4?_XVBZ6EXJ2^u_~*#$3_d(NHuw%X+9HT+^M;nR#netBf^HNRRsdK zjMlbD-DbHtXXNSaJ#;T7Dygm3=V1Mos8A7K%m_5FO)|EMjm!jBfvl`BPo6g`kTJeH8uU*ML0p1IyHa}@iO%`;o#Ua^OJ zjbvlybc`E0KAxk-TPBdnAI#skNPS{ZH!F3gX-&DG zaABg}gX6~+B7@zVPFB$Id_i=z)%och-KK@zot@!FA2fY=$7`{LO*#6BS#wOSw@DEe z<{&2)Xhd0}f?G&PQ)N^N6+onKLwC*YL)1q6zUllJ9janjUQ7&TziIdwga?5SSiG}csGaD)D1clTND zJC7b+s@3T^`=YIR2Jsy2dUl+lHp2mvBUjCs6mqjW>#PLyT5F!X0R97^VAK>h4K2H3 zo=cNn`<9}wLDlBf(bw7bs3*O~sayQ#Z@)#WHy1suN+lNU)g?=7Pc}`3w13-}|9BH9 zv?d#$$#gIuzzT|09~u?%m^%`3S2@9uo5!4C?OFwa&6{;zycl}luI(<_FLc<3^XS+9 z9PWK%7y6wBL$c=Lo%$vPqw0e~9^~D!{Q5p#oQ-~-;+UV*Or78LXe#BK_S{OF)bX+^ zwI^9tsOi(p*i=;lv!1DG%){>R24cz^*r@rxW_kXv2hnpmuX5%Z=M8+LAxua4bHM#D@h5Uf^=9NIlNSyOs7WUkH-?x?j+nDwr)y(o< z>j2Gvv`X8BqCA=O8Mq8q_Q%}%F9+Om3wQA20eO@*UCu;Cd5+5zwnt%=ue4u?Ce>xg z@29?+Eh=TkT8qyX*^=qkta-_E=ltUz56=4`h3$XprKz_o;3Pz=4HrqH7%?4*6gv8= z6`|B|{O0%Z+r&iyvuwX_+(%yw3T>(88UxQ%<46B=IgNb%<{v*5(S{SVk|}=ZV)4Kh z$lVn&d^r#8U}*1;Hf=jU0qy)e7O5OE-a8@2`l)O3ENA-@t+UR2|4-riO9$6lc8j>a ztqHMT{ImVO6#swbue099-U+ro)M@aPFVj)L;X%COgc}j?a#^l5u28V6Fp1sWlQ%or z1F*Pin#D!i89AHj7A+5X^V6JS(JMfY5C$e6ymUpt!nU{PX$0_7P4ZwTTsUH-6E|qrslIev=gP0yzDUfx!w5am-CL4|FQ(lg;nK;n zVGoEPE>Yjh*Q1SaRw-oLeZ>G(Anjs0@oI^$T3TA(ym<;!ZnsVe4DN8j0{0i|fIYs5-iR-7BBib8I z{?O1C{C+kI0h6lT>Jx#650QxB*9t{P-eB=QP9^Y>h}r*CbM)8<<}ZpokeBZ8rj2RvwBJ1ojJ_nidP9n=+$Bh9zJk0qjYYAE;WnnukJZH zIV*X%xs|qvZoflQy-jK?p$36cDL2Y0D+!qeVcWXCb|;21o*54`3fH;6<&yDvFD!%1 ztSnO=iC&ZD-OBj_{K^Sj-FMq<43)yqtnvavSL8mZ7|u@2o&*l4zY7YNa^f;nG!2>> z8oBdnV*6CN?q+cIVnAQM8y2d+Xk?cOWN>$WYhOA#<`J3|;6m?wsVS%tgHw-OHS?CjEQV;wZ7m6P4&IoExdtg}6!6?;d763L-oj)NX2y&lZ6+#QSoxtdP97_o?8D zJOoQYn*^ELG=_j>xz6R1#cTD&ZuTIr*Y4{lEE#$)nQ$8YXHW?ewMvNg;Ff6ev%4;c z`lZfw*3L3edQm5D+#tcw-7i0pFSBazHnk5nAea<-H(O*Ug1*F)LB-m_XZe~;J_s%! zjAGF5j-4U4dUHwnP;nNPS4SpymIktDI)8n$QK1}64-GGoUy<2lfq0T6xmS1H;^X51 zwj$TlBZ|VU-O@Yj;~wo!ELjX?K6MAv8U4qiYB0}x0t&$$ZY3x7h%f2r?`PVuAr*>0 zjHt#WxtZB7e&y=?{;|5@Vl)$68mppfVl~tIF}M0YdA6D#Ny~ZDgD`mIC?UQEE+C?g zad2>0hB5TlJliO?=s<9=80gk}i|gQ*KIivw>Q5!0Qr9bZ6D~$P2 zu0n)db4yV*Bb1^P#s*pfCU7~gZ)niXBo$quG^UyckmHdLL8N=nA${XHwxmfbhN2T3 zINa8%hcc{t{G%vZ2peHkb)JZrq-1)%F%nk)1R8yH%N<<}d>M6gMMLiJdr5^<@@ExL_csJNa*Qi?sY}oLApLCla)p?pH3;P=2E&%{ zON1G3#(eRHmoFce2xDd|@%WLQ9Kfco;JhKcb*W=@ZFO+GMdlnb7dO!;(^$Om+Q2Df z+ph)cG=HzunDO{Q^Y*T`w%auNrxAK_&u!43@x;yG>T}C@OlzjcKl`Tgs3z#d`3E=U zX^2lCOQVpO10ARJRANJZFtfDd8SVwi8OE_1snKeQXQ7zA$JGj~@=ybhB02EKOJ%_M zVTp5TI<;T&x1=2`WMhr+dojl1RW(J0rwQk0#irACaYirdd0U*$?WVL(A6y@z(y^=W zmJ`8tDh)1*Ul}!=W7%FjXqcRq4#-lGPxIYJ`dw6%G;ioY*sBYG0dY$)hLLc+0ylZ0 zFTF(&feR+BM1%#n4v3e9$r(oE?ZV`!T*FFFAoVD#-_o>|>5@dQuf;AQKytA##Tp`d zsa|X9rc5Objc8=u=t#ecUw}F%`;Z6+xDx@nCIWC=#!9W{7tk|8fRA1eO^gv_<7n4xUD)*ZZ3&3i=~z z5n+l`oYKityjrXve{^yjaH9@ic)!MoI~ssCEdw`2caCYZX_{$7SfyDcTe?6c1C4yA z4vwF+C)oKk4AYLHdPWCejg9SnV(g<5AJL~flkoeBFh!ejpM?rn>Z+fZOzcrHd;>j@ z4;HcWc^ut;(9*hoy3R@{_)>{%9~`vX1*!z&1u_4$FBT2!$D2R2?vrcbOPWcKiRr;i zr~yRp;ZT46{D8V0hFn5|q;7{ohc*Z_3Y6neC+Z~W6@j=aEWv1`rHdD1po6M&%tw5E zX;ETYlDDT>>q$%1#Sh`=@{Uc@E4qUO3dCU5oIDap>@?{3 z>1nEyoVc4JHFUS%!>s#>r<1$CqQlhI(t0w&3H7h*h<$4;Q^^$ycb01pR+x^_q62Yc zBPGi#h@wPTNQ?lDv?9-j5CZ}IjHbXEBhOeC^;9%4&JITf1$A5)1*dws^w%PML0@Qa zk#eq+z5W4dqAcdK6i1no8Y~Y9W^$Y~mKYWn5!rOKv1qc=5$c0VYQ%LKlQSGRh656{3wVgM$ue zd9gPf7T;P!yxZVlO>}5gB{*NuP!$RiF#~vV)|7Y08)`1FLP>%<_!F~nh;eq4jWZv! z5h*j)NU1nSl*D?3(I7q$gk4)t&s3$X5dEt6ub!n?=i;ygY-eufvn&J zy3#zM>FnpPw=cSN;%@fl1E-InbJ24P&~YdlUL_DdQr6#M^vpd!7^i@Zkha*AQjZYC z^c(gn-AX<|zwaqS`?0-=;8UaB)Q_rw!eW&Uda_Kg@3EM{n8k~m*~BxrA%fSrY1NY!;z^| z-&sa|nLZG#$R9l}>51%0=A%eoq|bh^j9zNj}>ux z@|wgYVy)Zs-e+1FgP0#vRS`7(pg8ewUC@jrj$ooIVV_2;Q)O#pu&7S1$=4oF32lsF zN zdOe=5(TC@)xQ|#pxrZB5GI^*b`EKy!l4T>-G42u?!OXCAkgtBmfluXo4e37q3e9=1 z4VgHpgKMK0bATb=&en=4f4d@$Xq;49cA*KFl7C_!v7OH_N&zR zA3te4I+fpPevl8(DFmEyjlvf6?&lAuNRa4Csp^=&p$LSE9PeW&rL1l?~0 zK@WUyfwJOF!E>#6P-B-zsb?>}Ip-rk@8f{jk>=7+8{ zs<6njQ16=Gx{CT05*X;>YLetGI{k|Z%%rY?A|KgP%c zA&+o9sG{l8UGW4*POV#f$pWv9S#A%^FX5<9Gg2a47PmC5x4MYWgy=#@_E$ z8ID$rjL@*_JRejVut(7Zk8tU#+568;(qg|%ef7C~xmti^XDMzuoiS9Dq|sMDyJ*Sq zt-!*<<4+~CS~8tacKAM-F*7yIGPddk>v{F6Y0CK~ZvD>a%ZnV5UpPNW`bSwgR_$Cc!1AJXnfp3G*U zUfzF_*&>D=Vem(H;$6PV7qID@G%NA<(a*JLiBEDe?(O8vGw3_APc%|0PJ_p|DYGlC z!K2upou_Z;q&cf{j6-d7dt^lWMO|Vm@X`J&UGK)5|6oH%z+8P_TiXY~@qU8zk0X}Q zT!G35q>8KQ`#j!rHyNs1lt{UgCalR}Lp>G|AL{FWl0@}eLaaK(^rr%eOwG_KSFdiy# z53N2A%yh4k6B1(XYwdLp8|sL=`c&fH-7?1!2l5wh!I_zu*r|)H`2M3$;%7d$K{SWz zQFM>*pTtGGMGR%U%Kt{Ryn4k@>{L(I?XIOwvOhU7_|UMT@0OdU->1E*@uw{;cx{_S z?CCeDIe+|f#f?%r5gD)f zkVC7{zH5*pf9Du8qd?$8yD^=h5rK?()@7W+|6e{iXDKr|FmE0Hgz<*|c6w23xgpc> zU&R#PVZwh^QsSpx{|9YL!mAzpI1T?*$|C4RLFl4f)oYabw=Rd-cx_@LU>qZ0`M`e_ zwjG*HKeC>lBG~uMB;>R{grD!fY1IB#9bZ!YM{iKj?S(3Qu|xM5xq#r9AQ#%^zelk? z#h8m<*M4TCR{W~YPr8NqHUX5)hWWV`y|xs|cs*1hXH(|{rVR_^ zMyGu{K06^{3b)=6UXOhuMVpc!0e$l138H58Qr`6j`YA>#Hs5#*6OZLCY}LhhJWm)i zZ$Rp^;`S>Z>9v+#1+uGLFHedpm*&Pkh`j9z7MJmSI zLjOM3*%7z}&E`XT))jTl&o6n(pjvzL!Dh~0fIUS6k8rsQ(jLc#k8wkQ zuv|lbLwW+RyR`!>HV1g$-ufJtd@Pky9BXmDjU-)hK_k5gPpH(I93_}O1)Xoy;VEq7><}cjT|LzvD8O_@e$?YD-6@IpQRcBc+YdFm3rcIe6#C=qg z-sfe?g?v3J(}P*L+e{jOBGO-ttwb1VS1k|+_8~kb0T4OuU+){-kxyiR$6l`cz|Ng- z248_cytiBag#Ui^BoTJ{gJ-X06F_k5sXyaT0_Yu5b)iJ7@ua|>2 zlu+s3yhN{*QwZ3{jd~M}yY0!l!z(!>DHuwz(g1sBT4w35m#?Y>0yUnwLC*yg7v412 znGscWm%+AE`}gn1-9MudLsWAnTU8Z`^7Dmt1ZRdTfnLR%oqe`~$B>9hAj~2itWx(6 zzJXx4!S`)hmL=c-3kQyM((Q*5i#_8tGB0g0A6mI&sQ_tXTJvlj9tO;fGfu;k< z%5}Dzz`_WKdk_)=Qw~8?CJR&@MoPIuIzb~&j`+o;+%{B-O%n$G5><=z@eXBnJXo_< z_o7YJcgT|wNB7EyiQwB2*c4P%oB&Du4wg(mIpxQ8qkwzeiZ=`fPi>HFup{_nC6~r- zuzSLE5}&JhbM11Tpakdk{fgLetvGq!;0D_5@y5kpyW924MaKS`q7ucOsboz9yL zTqt@!r$yPsgD!Qw(Uj6XRj!ZQbzL4WnqRZ?*nYPLX)nAxHL>d9{;m`40ZC851K^_( z;7+N>wQEM{RrffwHI8=a!+Ax2U52M6*-$n=c;L51i|(oNXt}~T4QL9no%<59w_Avc zi3OdnadzK~(9~__*38VKKMO_1yUy zoEj}D;wCGx#wzuCpjg+RMG34>*hS~X(*`OBw2~?-qQ!JAEiJ`X0Od8bR|g1<+<~1t zb`(wn2s)D~yief1PA+HL-zp7Ma{6FA*B8Jr%fi1A$%ydk8%mIWg9 zuhpu$$}6fpu9SJn@T39CiB2bgM|*YT_m{M!8=YyR-(Z@O4~8VVx~<^-t4*bJ4{uXS zjhri)_Dqcqmh3N?27$w){Y)fsBv5U4&E16DNeQ1gd@DM-nrLN7o#KbOPG3ba$r!** zWfCRjKz-xpd?J5*Uy51X`&YIkgB|>Fe4%kiye+$QWF}4(6|@|2+rlI!0wt-~mraY0 z3V*v~-gV)eKS2$f*KFAm5)d{7XDSwXa%!seg$r`b+N$Z1fK^Rt?c}FHHzdIx&zwi< zx|3ZEW*CUwI7XO`-xJn3bjKL&=v%w?^SyCNC)eyngZ6~tdGs6&71cPLEZ0Pa60V*{;u0;o0(WI znI5i0xmfj%@{oN!0zfj<#_>T)BoW&VqbYJZ1DkyBZ7Iz;`0T3xUgf=&0{ra-$7_tM zp51;-DIIo78)V!2F;uOh+2Y|VnKdyQq0($;2@TfWxy4pKPc*-uT<>MwCo!L(FPk{R zhE9-*r-{MQL)FpB@JZZ#VBamdEYxMP3xtr=!z1c896efCuFw!9HP+UqgUUqAKWDbw2Xh;5=K>+_KY>{B=z%lbjR!C$ z82f(E^4+83IEz(3PlKmo-~1H&2!*^b3tOP4F(Wy1Lgsq;4XS}FwA zc-12hD7v?}pg`PMPW=Pa3L|Crv7)U|`}7|p?xuCp#Hw!ZjvXS-egtoOFC7D;HK-2gA0W)hNhR^+!p?d zW~qUiq*zbz=*eZe8(uhMznFYqgcDeOlW(0A=U$a_fb6@qt$o`-#O^TktaGd1wLf<} zEUAq?#8}1VfNH_krOIgc4G($0lrgJ``-uk$@ws;_okpAfg_VRof5JKi!rlV zb5`!jua)usa?etoH~$IXp|)1}{x^A@x*m)3Xhx)9(CU}mdM9;5SXa~0 zWkLZ(H0Z>~n!ogv8Kb=(WTF-+w!62*#Kn({4-802F-vcntIJ_6k{BW2-~Dby zxv&Up`#a>628_+4BVm4fLRtCNop0tJ#~+6Oh`3zH{hQ??D*q%h_Jb&QT>+ewj5-6S zfA(=sMwoB{8Th{12VV=R5DOLNxcm3-6EtK`dZzu*F7gKRLFDf*SkQLVQ)ZVid5>Ra z!qA#LxB%1-9H-s~a6k3IdQ-;X>@+cmkw?g;QaNw^@z2XhYw?5W4KIXTq?96R$n;{K z|0Lvl?^Xyf-Eo|nL!Pa~-Q5@GW}SO@GZ51V?GG9w%Bt^wtqnTNtY7~cdi8#&-TM3H zKxjjOkw$*Cl$J^DgWmfmr;zUs-X%hS3ge3y-jo{aXP&V>SL**-pOE^lXFAYF*&kV9 zR_RNr(lSh&H)B8%y7(JRa!gPKu?-h67zeRluC8-CCH)KUfY7Ve!boG{LnYMnxe<;4sXg4$MfQEymZ=2 z93AZK%}#0gSC>`Fn$Ot1p8}rOMGmioDqKJ10tDh*hR%8^eIB2e%w-(KtDnHf{QV{R(>;F=hD;`FvSI!@tij{}*AT`nEOecKHT+R&FTl*-5o zRBVixhM7@W9a$628CHgfk*J#kS8NX+5@I8qodck;@B^`4>Q|*+WjbOf=aOIY(D>|a zq4Xhb;;ww*c>MhNU7B#RtUHb{qTF?qF@LEVdUtoL<-jbtw`qBIk0#&NM;b69bUrlQ z0_kzM+qt(ZFIZYm!(jr;W==~{i*=SwLXlYF&u6M&A4vRSaid#U>m35Qn#-L-Js={-|e9szV%?GLFC2H z?ob~=0Y!jlQ14PLIeveJdzBMB_I|_C`>nV$b#mJ6@RATC{i;xhE zy142d*btJKm^c{U8(lL8F+W#*D^!*GAx&AfR5k*Y25dwGlSt>6)*M`4klP6ml}%?b zimmHIVl@Q#`S}7cz)!n4eSYy(7`l9xp2ffaKAqx{ST9j?opGxC-D3+d)pU$n=Vsh@ z1_hwQ&b=!9b@_%Pw9Iu|B?W^HR5dk8`xnj%U1!=RDKnjzVcuXMBXd(waD(dGiuX1~ zc5>!+5N?;W7_19(r@vX(dm@kkVdYXakCz0DJsAJ$=Ks=H3O}MXyR+EjzfK_+L7>Gt@W>_|7+nWqY ziFUd&H`ikH9Va?)=ppWV$ykebVx{`LJ^dmdxSYDU%?ZL#*Sv^osB>5ylE>V#X_H!x zum>x!-cW(iSjLuoi;=DrgTCxM3ntH?!%i@QOwmqnV$ets^%e_Sib<3JS?n9V=xG=h z^BNCcW6O5jUzQ&(6)M3?pRV^kUB4u7c`xa50h!128-&Z;yalLA+H zq!!%gFBl)Uo6rxwb?dqPPzPF2OcEkE@*Vup$?-ur0$9j<<9-!T(-7&wGlIZ3xUj#D zjm@F6$G-{*3UU~1E1C;x6x-Y5G~VjLomd#!K>RMk2wipNNsSXWqxl@Z*XFpP(9L;1 zjCB}FrK}mLo;*3%$hUn6Yk^NdAc~e0uz!FaR-!4njG)QUK8E${A9eVpy(wb0lV9h- zdR}|BFR6<&kJZ{-Y-x3W86&TYC*z5Tow}|DXCALi5?L02@qsKuM;%BebxDcsXVcAf zw=KHQ<9Nk^?_7tSec*#TkKR^hjqPLC;J$NPHz$p^@}*{|*zGm{aC9zbK-3|6{qo(+@%UC|~}``Hs-P~b64P2?x69gJ5lk(Dm_oSV|o zDkSbZqmiKVXnNUL0cHizL0z%}Ck+-wIv&r&ie2g)Dl`U2G3(a1lz5dF+N(b6#^8$` z>?)+qJ$KGr({xFwF@vZWNyGO$Bu0?-ZHu781t6GbJMgg17TJ@S!loUVfp3R{k!^rb zjs?cE6!HU`OniPqPp=KZAEKsI92d1LA-BFLmNJcVJFjJ$%Ob4Qb?wpZxG(nWP21Fw zFnw|j%cKEGyz@bZe4SnKM9mJa1_t)V7sgT9y)}J&^zRAZ&c-a`p*-D>xiBG(SW-<$ zHqYKxCg`Sb)UlHoW!a`CG%i*7lP*Ae!{f99%^ARE^s^w-U|yWfOe#=nh`SNGb7LO1 z4X^o48k#sjT9Lhv)l7j)=J_5T?HRS_-Kr|m z`P26!z`JNs3@zgaVPYZj*pDlp*hv)JH*auc24NjW+`Nr-*luESZ*MbgoEL%< zhUqaIAW1{T78Yp4hefrW9f-NsxK5?)Q2papZr7JP>VjjnvR^pEDG2je2>FCL12$H6 z>S)#keG{FDTJOA!9G(9*=IrkU*-`7kWC6iepY1vAk5pBVuD z8&$CsCEgPc@pw@jd$Ta6q9tQ$K(jV}pz>j-U|PkX#7f(=lQ3 zdJbwIj%I^vZHSZbyokh5<6r*ZpggHL%XJt|I?c5KP1)9~%L)jq z@QE`U2uTg`yZ^B}MKwWjjT#otBz0L%4jTs*W@sykvig2}$3->rbf`Wt5G5R8pt<+z zHdmIEoRj>N)VRjbf_8IF11V|nwxATQ0vPW|RnElXrnGE<+@r&oYH|AXY2y0o=SOT{ zC^CRM*F2MF*|u#Pv{nWfZPwqC2TWlHF`(yI^Enj~$9T8j+MQbcO+rDApL$bkGp~8r z-YqJK3}cimD;Y+CQF{XyMVz=0Zj408HIXtu$dK|Z*;#(xgN=JXz12&zh;jurfYyK-`b1u9^bF|(axK#anhDbU+$`}uuV*?#gZGjBL#WobG5HR=VY zi@$~;yu>t{YY@}^$MWUl#xrMAFTm1S7E~Q@TlLvT`|-jhsRy`Inma35s;BQpox=tT zViHY*!6oLo3PM_BqB%q>UqF8FRN25Lu z4(~5tZnn&QQHCuX7>RP8%R3k)`AK%~@#03pD!*Kq%lN8!;et<1TyR9M7SDy#wEOqd zrpi>kZp9e_Uu40%cMil6xzl#wslDCZu1ePF@$1q(ylfekJj!wE@r|Ev--Z#1LY~RV zDG6lKAEqpX4ZK44#w(ws070J}}$-i|g1?q1ME7w)3q8i}mC$eps27`RF5S}RSM2Y<6%iqwP?vtH%W!E-aqM?}3@V*-XY zO5F*7M8fhEDO!NPv($%Es})5q=|X?@b|6hAoa7mY**$`>`zuLjIivaxjolGjN$2eRI^a9A;_dxb7_s8WwYx zna7^Qn^!%HPq5Hezb_d!RNlm0=bPtx&svD%Zg}CExx*Ry`qON6XPjR3N(Z0Q-vNl1 zSO+r|ft#)2SVdUDhP`$sv>Q#Dvyc1jk}Y%>cF*3XslS6C9(unxJ-3azy_ag{@tGeE z%Edp>83U|k2tW`z@HhvydBF=G=d7+^5!FPukL6j=Mc>BBSXn(eyevVJH#n@4asi$H z@)f4L9iOMBvTN5LJyYEa6F%Hu+a*EjeI;Le%)wE_~9P=YiXZ_6&r4q@k>I92fBUX@@MM8|QBCKQN{ z)MI18g5Rl<&9$UR?YC#Ghrn$n} za~*@u2&0?cJWDNC_#=Dd(NHvz`2;4bPaj^VP{)40pl2Rd!QUfq_;0KyL)Sspz44Ir z`gOjiR~yzlGG7e;f(71kR4#FKMz9ryLfN!_eTvJBLn;A3-@bhtu-SfOJ^|Y%M#QSd zBR>(2x!j44&8g*>fDDa*(&RR1k@*lUroqI(z>hdP9^@xiLGf=M`gin5uN8oJ`#V?{ z;p{ALYW!rzKk14@PKbzH<*oHrK@W37tOX+qmgH%c|H5*Z+B+C&WBF zeDSQ7RwFp-6T-rpDMpX!Y5*#gmvbQE9PyaX0QzH0b$4w7;r3d!g&$L63zq{0ih<4? zl5|Y#BD^Xv^0Yw;J*bjl*}k2HrP`&^H7vNz)PBmXGO0rp+TO~_7(F;)b1>4 z0AsGR*=&4{qp{QObHI*`w_}>MBUJ^U$Qoufb@Lvl{;6w(No!V5W9;(@VaLN?Kaa7Q zoh99kkQPROX`ET`3&%0v$w`$}e>}rEPRZ!h@VHi$mg|2*q?2V;7kTL@#rZgCP=IE> zgChz`;as#u2lV0XF8L(}(r4*^zd~vI3ve~3Tyg(kenUe;Wo0sS;O=2oe_mQ>l8fAD ztSC@mDixG>?)0NB=3f8@3nmcTQjNf%Nt*j{UgTM1+UgEipErTz+PKx&D())%a- zMi9vWwPm+oZ3sV6n6x7}wCm^W`EfxrtLGM(U9g$^S!5IiSL>7c?$&zg2wVW{U^coN zPNF;2dJ)c39pU0*wWEwo&GI=%z7}+VYsQ3x$#EqudZ7}d1q8N3W)-1H*7EK;xsn=6 z(bhy;K%-KUx-Dv=FmYhzmdS|7&T}tc^3+(Uh5669IKjCf9TF0P+=85mjuOkQEJH@^ zf9lPln+rIrt*xyWTC>C8(CXyRx2pjOL~oh#;ni{I451E^dgu1T`ahW1P2h70mB29e zh#TZk8c|6~kwd1&uKWD-|{o_(JUi!e8>4@)x0t30Yw(C+J-Rj@iV1g!^f@*j~Y zUGgi<&;4V(%FRuG3xUa3dYfv|qBUzq^fboet_L-}>uwu){2u8oh)7q{;5ty3r-VuEkpLuT zoQIA@To0t#5&reY%opvY9-lh*KPlu#-*(o}Fx{a{i%INBK5;*SvaDC$4mW{gm$wsk zoDl4KGr&Qx$j<(u$Shx>M1s3C3u`o~2=xS`qBrxHz}d2Ig?F}+Fhh^uw>R9ITM7txHCuXi9goRUR zo5_8~6Iq&8qYvgb-+ZE{LLwfc>(po&yKm)%b;+0YxE}(CYai&Q6tU<(?tO0AzC0p& zlKi(*@z_JchC*)ng*o)QB}Mt$sT~U zi3ZcyQ}vy;!yghxx_>WjaUm9s!}?^F+rk2e*Uybvi4F;sQ?dkTI)#EcHLlAj$I{7& zg;fS!rgxS#BG%mNS9TBWBlHo+biFD+ymZ{xz3uIM+5}bm$MrzSb@t%f+EY067n~9~ zt^}Bo(+YYVfUEk(4TyjRhhJpWinLY)<(tjOfMU4y@SzJXvf#vtc_5s^iqy7ZLI%D+ zMC9Sjw)`^m9N@94Zr_s*Uh~mE3z6HOZl83<<%!m-|X6JrQ=lP7xK zZmQG!-pC4@M{apjIP5%Aw*LR2?7QQ!-v9p3X_rbOMMXs+p^W4b8YFv5W~t0jT!f5v zW-2Qyxg;x8NJeRCqsxqpQ`Uu$z4<*q*QHLU^ZnlU{X38QkNbQd4%hYhyvOVHTrUh- z=;dC5+<_HyvKS!Ya(s~9G^{%Eysp`Hd`KD~9+N;sZ=T==& zl0rV}OtZym3ndtj0J3JDe$TNBDz+uj^;d|FkSN6exFu~-5}hn7%}kU+XU?55c6OKH z<>$A;{2C&4VF^84$jeLC+oXo4A60#dVWl*hPJ}XbE17&w(lRk?eAmGw4ya?LaJL64 zNXNjt@@+&k6L;*^)8(xOH9?F7oPaClN5{Z18l>nd)u8TMS$Q3WDG-PD9+HXc!+CzPz z!fDUlnt>pPB0M|t#sYF9zv_Ru8Y*{l;EA>)9Vx4q{{<;)*P2DZXd~0I`FL%THAfX4 z3m!J3#YLdcu{Z=swU>1-Oto0O^bl}HxRLwp(XHV6t?0H9--$0zUFr#4dR*KfRQJy4 z{^QqklxRed_C2iR5`?8$qdIjZMhj&Gafm&wtSsW^u$^a-K$H?a` z?_7(-(gket?Wp_L`qS36*Ktw`o7RRdQM`lvhTxvM$x{vlw#GGb#63inuV!ckMNf9uOklKrE3Q`uT{@p9(Cgsw^~LV1$3^Pft3jyTpsg>8}o0VFv1XL5J+o@86@$aA005J6La6X zy#xRVJ;+)}o&kzXRQ)G+5=%_H#o^^fge9*-8kB*uhaa~|536!r{jz3gT(-0Qpk<76m1*bj=jghg%;AH)*PK>U7aFgb)y{K+h(ThE z{_`nud|@HKOV~h~C8<{r9_>a9&6yDNzy*T;z(|%7Y`3g=aSfm6uC2sZ?ekq9MUNSJ zb)}tn)lG3pNmh`OBT?o`(0)}_-c9QS86D~zsdd~`>*F)VpfeqZz==aZjcYk#BpmT4 zgex34<^raf?)XP|3-P8|ceybo1_uX|S6YHhii%nt280>wir_Wr;%q`Of5!SAv?hvn z(41{VF{XRl^LUa@#zR<(%a53w%bSeVxZ(f@a$HaD9NRrixSSU{vcw$UH>derHtSg% zBWEowDx^9{Ervt?wzmr|J46lDvh~oK#na~=J}kCj-T1Dt1)J7y)YM$E?Wh=C1T=Ql zzWZtr?d~V{v&Q#aHfZLimVEf&0iOhlb)%in*-ZEnPYNwi3G`QQS6_3L?`Z76pU-%2 z&rz1$77|1ge~1hrI+UJ!s7wCVn0{KpvvRgmCT-&MOsXG0?6>O2mkhtfcr4SGKYUPC zI)%$WoR`P|gBNj~=N#4r0%vE`>UbarT8Z!VC#xy(y+EcdVq#LFBkwRIlqqgKdv*Cw z<-Fv~L-w}1aT{pS9WZ8byQZ27uw}()suS_ zk7xnDzF#<%9$xh(Ji zTR~_wlCT85h4q%ZufM<1Ey81c@~rW-{@Ru`XAK|1O=`F-3`)AkX7N7WLIuo@ z7rzC|uDfv|WS8C|Oiq|NTMlMZbUcnsAzFt1&#leLv4VT zxGIS-fEAX{q4<@nd?npe(4YL<-va#Ut%<+2)#H!9|CY@9uV$hWf~1-Nnv(fB{9?|P zV+w5-7P7v~N10W4reGA}+M#gdKRUo-#l)PZih(cPeTlv&LxWgkB&kU^Kx&r5<9 zm@)Uyk#7t3EdhdKdFaNE$$a;6SKB&23RvtZRYI>Av7Y9l!frA0YmpdAD&`1 zVQoS`$LU)SdyoDu530zwK^7V*=^#8Ac5hGI2&BW=+g&irs)87LP+3YyL@80VX9!F7 zjb;e!(|e4dBWe|c;dt|5s(NeI-~#bcT4FOS;)7nh(SO!rSSau7qC@Be7s5h zC6vR~cE-?LSGYF4TGF0LL{?yDLoru-1JD%35;-HL-jmMT_BcBB0kqixf}W2p2BrWw zF_7oeG8R&my^bX4(p|Z52y4O|UTOW|+!QpV-%vl8?b9^|b}4oZkEoB_;a&Y!pxE z10yf%tcbxwL;?;mf<@jFrx1mh%98vUA}dqZFBdndMSh~EJ*cehs7e!*{fu}DyaW@H zCagU2^S8BPwT6`5CWgi>&ITj{(CNbE%eE%|e_=U6VCc81_}x29S?qc*Qpgr)zD7Gc{-4yp$!6%!?LL6$=suPoz-#lM`<)A3S$%mX>!@prpL# z(6<_j7q|dCgZ&~nV5o~Jk(`A zY;WI?ti!j>EzOo?{t7X+Kul`Pv?%7pph!Gb`FsPyzE4DXWm)qy)C1+{xPeK-l)Xp{ zQSgKbWvo%utC)Ug!ABUmm_NW8 z28a^b9C@7ZpYWJgCF`_7Fb?Q%#UPfts$CWmrTknV8sTG!(aymfyOf4Y?Ok0$oKU_B zbpY68aYoEG(lgQxvz03*CnxooiII>pOc>W5kp!^K%xySfGX~0dcV$=0Uk2z>xlL}g znN^Eh%pxF3ko!~hpnk4}L9S{HNw2U4Nc?#NiTCRvQcYLLeL8REK%6;c?_Q+nm_u<< zHnbZn-)=7UR93WY1~`Z(9lp; z<_HH>I;VDQ8tqj65kgs0BKQX9tu2ksO#PMMqIR^a`DN7 z%ktPCx%QfCS%110*ReK++k4`^6=q3SBLs&3$-0}GWc}lp^d?`9u@Xz&}mLUmFTQQL2z_}h)lmi$u!qZ$7t>T(#uO$6Zu^jU3lx(y51TL5lsu!o-QcZ z`S!>nh(~PGjwpxSLmWO5DU1<2gCS04o`aPTq$Nqoa&vQAAARe%S)mO(aKnZTVZtVP zM_w<*9;FJ0ZK(yrC(IDY$Sj{^_Q{BmKZ6XCX`n1gw1BzQZ`v zLe0Zt0%B@jD#xl-{F`wavJIX&^GCa+jNm%blGww8MktmTUZNZ6w7b2@oN+Yq?Znv? z$r58OZXHZ+mn{bPNzBxKoxpq|&7N`+GvKGys?lUulVxdcbw~L8a>IoVG z3Hv&OHAz^$doL~4QkRyKLuy_T%8x9csjuhDbiSV+`eqGBk`?*Xsg)wkYj$9Er=s;u zu;yKeG#Agl1d% zw9NS#EXvTW$tKg-h=&S#00#g@ZH=vd{~q@d4h|>G5;a+iqA@HyJkeGkMyAIW;}9gG z(g_vu9&0B?Ap-o#EMN+GQ(8)lZtN)a#pBa=|1<%dO%4u_V8Q)+Eew|AGb0v+Ue_=j zLmNo8xwJXKub$Rl#+6C0Wq#D7dJ2_x`^3q#k0QJ0$;->@elu0y&U0Pt_`a8pZ$v5m zv&I$PtbU*|c7~{)j&)Fii+uv7VZeB&MaFQ;1J`JCMm6vARsF}C$5K^wadpIlpOr>L z9!-4br9PIJSB!A`P##j#*RL=0S^3l_UX82*yCbQYyk@8CGL`4GzWDgdVvPM~(Mxj_ zJU?uUhWw<#!uK2buhO;DKaYw{3uX@WnR}d}(|C&ClWHM#0j!eoq1k8*c0oTq^An?m z#BKa)3#mrtJW=XCO*y#q@V4dDw_YrcmwpsS_{b=Xo8;hEc4UiL@q$dqB>q@Mk1n0O zaCtaJO6<~}YkKXq62#rLX+6od?(L67N)+*ow-9h{WaP#JIbluy2b;Nz{oLCVR$|<7 z0O}t`A&eg*R{1)T0Gp1`*R1KmhW3@F3ratH`0)eu-$WFm7Wpr`S` zwC9hnlROt?uH!St7w%ik6vgrRFI@FI-HSc>g9HetNN{l{Be4dXhTRq z^l>b7&Sm_En|!lHwnzw*&|jQbLw|2ud2jfr`$a1xHj~DOdrs3nu5V(Cx#Z394#o24 z>2-|r?S}!%Eo?3?v+r=erLteVCPX;-vMHjm{BPzE`;H4r^6cRqY!%m~a22b_ciDfc>sr z^Qq5Xzdlmkoqfq)y?FM;i_S1qE_}Ci@1+YWA`++lmUD3}mu^aX8{9}f;aXdrQ{O${ zY?zoQV|VPtiNrkTSUCN5oEA2*TYC0v=@!E^sXL8>xc=0ZaqjH9b?Zu5GfIIwE^IP7 zk+PoWR=s}p%J9MgTkd1jXq((C35JWj-mTejFDJ%iww9@v)VIFSEqlZ6NSv7`+*LZh zvF$Nm>vTrt^s?%2{&G=q(I1Lb8kO7h@?Gpq-4ZgitvYNZd94hCljJgkgiC^WNkNyE!~)x018A>-#mkYu8w=Tp7B)d~nGAb4Fw4qN(Mf%jx zlEohToKnmqhK2%PU0HiQywLm9Se{XiQ^lQaWLkgOd~adWSh!;I%|=1fClijJZfwhF zC;8nJ@Rd@OUtD+dVP9jRS4MVFij}@U@dP84uRQ@vc-!8Dc*98}X?ZT~j+OOKqZfF01OsA*E&fERU2lChNE{}Zq+Jc?l#uKNL zL@9*R@m$-ST0aoZ<*+dQcUH?$4(K_jw*ZPjAx3co0Zh<8@Jb-VlZWRBvQtq(hK?aP zMJ;;Aee)&^+7XbD2<^dUAdWKKU1W=+oBUPMS_CapWt5|xw<_piI*yXSE)F^tDgJ#GHG_l+5v{M+rvbjdz`oKVEyNlg?#jwRQ~9nCseb5cuR zKPV5WYk>tzqRq?b4 zZ3BZ-GE5%d;yW*Ks~lYFm2*(sZ?UpS_*6enuju&qsuZJ0{_!D)>f!_rt3#iDm+Z;9a3hm~-ipOTL-M9heVdh5ahab(}wG zuoqf z^nx8A#o!LQIfy4lxZ85)Rj=s^lx#@)UblFspFTn{kE~o7{`IT5*7WDbDGZ-T$c{>( zRgmsZ2|NZsFH-P*&qXIK>8t+$L^xN*q*QNSC;3LUefHjS$pWMdHZEO$w$$pEg5Dz9 zgI7vcEIb*hZ2!{dY~({)l;`TuQyr5$UWRTxw2GY{$Cfa?d?_0_n4X;-IxRwQi79Zq-MMpT zgGav_5*FT8nH0F*NBN5oCj{7*iB$tBMk@&*fl>-_sIEfdA?WioWCnGWlzc~=7A;t? zOa>St_*|jKQTR}6))>Pu3tKPjV(px2YGn9Vd@~eU-XkYszlcQJCVb6UgjAx9T)SqC zho@(Gd3iRMg43p1z4pL_laMY-K=WTss2dbi7pG2~)AUm>KJ2WfWUS(E{rS@;pB+7) zb5Q$y11aI7esme?x1*RX(6p=j4-{}M%VQ{W=8#XEaCL|7>ioRH)B~l4ahg7_=5Neh zOUgQR$|3tmTjY3=<(0PECItg&b!sUlB&`H?n(-KrQ=$agYxk=3KmQymrEDro8*lk*iw5erhKzu?Q@N3 zVbaP;M^&lIUDkp{Z>~!^P$>~NRQFjtaJ4>iB#kXHuarmdA3y%QZ{O5w)8r~W|Ek%(qFxhQsYzp>{S8m2EX_ak zW&YQX+9u8^IreQ?HZ5CZj~&*^IgoMdd1|AzdQM(Sp8YkT{qt{u&tpM~3A9?;7Z=jILq#C6clR=~3DPT8yO)!T)$ z9z0;6iBozmQk)@_I5Nca~QM=`=fKWE2#t>oD3GsT15gUDtI0YQ>D+RL$#tjB46uCY^HZ-Z zON$y&d>n4`zDt@f9mnQrml5sVm$ZYE!)&WFxkDyui2c?3%yD#6@oX74jqKzp$4*x_ zOFiG<>PAHk-S?;Oc1kX7oEWuo7FIhTFg5wDMeyLIoYjuxG$oJgA7&VWwj+ncHtcrn zi#@%POU7MSjl5~oCRz8RPb>Qik$PjL7Yuw1M*IHWrq`i?h&gZumI4r#J6t~T_AI2D zaZh&loq_U>wmc@Xkjeou8z-kB)NqeZHX*6qm)*okC;RFK7DI)^s)#i^PV6cm@Vbi% ziR*Q)i>KbGMCnr#u)pLU2Mf_?mN0#@+~6>CSLl(Kt{wB3o{~vaU;8;ZIA~AYe&wmV zn|0S+G>^WBCfS($fP;lnuDi{Inj8vPu~*{)f~WV3#K*_$_0XUq((G)6ln3^-q!gtV z2eR`1Q;O-x`OeE%6d-LZ4i5=Ail=W^D{c~R?N@^E86OU$ue`6VHFPgCuC5#KQLl`* zD!F~@)?cM|Q`fJ*6C{Pc;1u2X4D`7|4kBZou>A4IQDV^DE;&Pmw&^Z|wJ6$se9r3J z33&TP^_2&tt*@qYw*26*L|4R|1N1U~{``|~C9OW*f)-GKZ4uQ#Te~c7?|j73LV>}) za%Ed{GXxn*SGZ>p(LF{mA@p^ujHxDy@@7-ef=%YxS#ZZG$N{P*mDX!0;& ztKy(jR$J=QW>4Vxv6p2IPZ7A&9ES46A)^S~Du&XXBa zbEpi%@yf=|p7JmxG;{?U+fI)W&C(r!Qbhy=SVHkU{8(IV4)+d&Y{92r_!FZ@9GkF zjGA+87-SOG0E$es9Ur0e)PPhF6vU#78>FNTK1{R@wda^9^`0VpfEtdV89o(Zl^ZMt z!fbj-j@51Nkdj&2(bf+USAuX(tvpbTmvQ>}A)6I3{jIOjj+ky!YHn$fJ!vjKS9XVG zcSuoev1Zh(28ZpOvd@E6jW*AfJ61C3YO{a;A^De2H>${a^y$fshTJ@1&bFN=#gl-Y zmc`t$$wounVb}vi9Q8EDCSs;7TY7`-S*>GT@@H^FJvX1A=nNXpZJr0%C_5A~PlS1NwsT9feHz4~e&FRK`@x%>5Bmp=CuU`P0;(g&Ef?m>uik4VeulQGrT zV}zQo{GNSHU9x?BVs!MHlA9_AIyu(L)IO)Ar=afRUDDzS0Z?Eeo?-doQI;=bqbeslTh&+ z<2RqtP=n9@gThnSZJ=<< z`8y1Tgm{Xv@4IPpexO!$)VFGfcMY8#kYNGKXAcVgs1U@x4X8&P91z1b*;BSQhN3lX z#}Tw5M%nH_-`47eCsfS5@9P`xQ8zo)>2k%el*w(p;PL07&f#xy-zsp0C6q=+MGdx> z%N*-3!|dPLvtzGuJsJ893Bb{c+D_I=vk)cWQHz8m-;zgC)VBgE>M;!*Y!&w{ONH~6 z3aLqNcex&8avo)={G@R=*Tp^er*~1-J1t=96c!enzt~lHc*4|#sUq69?_*9+^s>vY z-MQ&Sg|U?d7UE>r(Ajl zj_}}t<+X|(Y5nZnDU0~r!_>B~2@b^{K0K+rNx;2*M1!TOzz1lM;OB`A<8}$Vn855( zN$=ZRTdNSQjaYXn2wM=*S`)Wi!P2@Ws5nvzK!QMQ)b?iT;9q~K7s~D6>&R@P+`YR+ zVPoeZzegVaQLHi7A|@2d%(dih2H(*mn--q@)bK=We8|qvTP}5!Hdg38IrVt>70y|j zw~efbcj2D6PmkJlw1Vipyv1K@u+gT!$Db;SRyde5#VQkYI<;7S4f6D>-G{zGfPQkk zWMNuRmTh1FIj6O6MP`C5(7dY6q$LqIR>^I-n?L22;w5jpi(H)eSE8zzSmuaZkMF*1 zhfpV)EBmO&kBKt$4dtJ39~0F6KEk$U!|`>|{=92CgY4=Oo3+TwB%=EzOUIG-#(qIZ z`}W-M#+V#|lh;-~tE{XkFIU@)7n|j$uBD_rrAnR}Z{*QaXuF=kO_G*$KH+M(xX*wp zpo|mD$|?tM8pB&g+9?LJ+t!8l%XyXGkI&f?_sF%~s5ss##&-vq!1sC&q(`O-UN_|7 z5gK|!6~QU6chj9A>A0Z48&zj$5kWit+_}@x|7z`L$uX;{{E2;u_t*cpujzsz0!s;r z!v0W}d!6jUWEtv5ppYWh**||W(1_Zuo=RJ@&HR=ZRiJ+7qYdlTr_(#H)7V-n4~)wV zhUD&`@RAB^aB|N&kHx2g z&2(}pz$BPz7{Uoc_IbwdI|h#XzHbi*2zWhoSDrfh`Ej}6@~^@xj@CVLd-?Y5Zf9xE zV;r&*3X+oHX7+2Vz-pFv~;luT?-92D-kkBOiEnoKW*|RV0u*5CqtN=M~dvQ-3I|ts> z_9yFE%2zBi=@)RjAz1R~w!2oA)tGfXBMF*;x}|Bl!fDc+u2!UP&TI|TZd zuB{d9vC)-5!^Y1%+3ApY?i^{meVt})oT;;N-Ug@j4vl|3o0N7LASQf3Uq=ZH%r-o_ zIO0a_$h>{3wz~#Cv`r54`IMXdg* zwm<^z8gK86MH+X_S;|?LWse4M^cw<_&Hn88fa6-PKiH`~TY0cNW`&W+5Axxz zCqeNiyQj@^JP-Cp-tw5Qx^ie(+}>D-zS=61k4QWB0fGfq#?j_sU$>LM*0I4sMveXo znm_|bXvGdy@*-MP@K5N5n5jymnG=myD({Om`1!0tP}q%t4@cu;G)jCkrlyA9P|U6n z*&P$iv;LMoozV+M4)`?NJjQ_*aPx>>2ruqLjLbkR)XMc{&g@DWQtFT z&B%W|z?Q{8J_B0PqWDUjCjUE8>oVRZmY7RC|2idBU8K!9(~)zTs5OZXgArx1&nnzJF?|{;RS{w|>V8dM!r$(l)-cq8K{q zy10dh6vzm1`}JvKz%ijxfxJ*-)&v)Pqer5_|p@`7w4hXgCJ#^}jwx zJYIUKLYE*)yopnMGt_go*r$1M6w7_0n=W|j#nMMmjd=RO{lUBbNjCmi;TiJ4ds>FR zAzluNHpj+?zw`cBB+s>(?4`i}a2im_>IdG131O=xin?CL<#ww142geZ#V{vY^%lNJx^BLO-~4?Qi_* zUh*uwMV}|&H`h_vOy%T z3JMBZAFWiZe*f+r;)7aydSYW@0+-GdP0!EK<_OAe*bI`atzo4AS(nkEDL;*D{`xT@Y#RHEKtQHY|$k>g(ZbgX*ow+NQaUi>?4|Sr%rzN~E_K$1oKOLOboD`?$7ZzTry&-zc zZ^6Z+{eQ-pE^%I1RWiD(K`jeL=3S099cXS6{k;SH@&+`@Ix>c#>DzZjrG8b%hVhqY z^LBP#37Y-qv#&Le*CM~4@mzt*JM@>W53gQa(nURK9D*j-on0`oe zZOsg9jLENFzB~~lU_@N&=alv@3`zD^e{qCP$UuKZT&O=AR$N>6iLQ%>5a2QnkY9=e z`Uu~D%l4rEJvZ~#w_Lu5fh|nO|0$CGTk8Ign(X(_PnWiDH8gc^9~~J9;;%GwA6W3@ zWYav$b!Qf%gd)15f1M4QM_#^u9Wr_HtoG!ws&6#R7K4Ts7Dyon;;?UdEwl83np|0-B^m5yplu=UJ|3wgrnrKr(FM%y8hE(5$_(9G8lM&zel4hDU_n)7<1&+M7FXw0vF#BvZ`QPE#Z3$XED|Z z+f1>AfH~3deA+;tW9*J?6pNO>9<*c@DVZ7$fgg&YOicY%hujtf?!7SEkh;nDKP;iG zONa+?h&MNB9(A-nPKcrlA^*!Gl|HnPp-r4}UaBkV3Gom88;IO9yHM~yY{7;5JXY(5 z`j@1eOzyklp_F#t{M0d7eX@;A*vT-EGrZ?AvOh$w0IAb+{rd6}jWdQyumoV``~g+H zgsdJ9Tg)p)0@<9Vf)6`zXMb4=f8Yek0{<%qP%slUXAT( zkga@cTrgl~WhE&n_#QHdf<9%l1lj~(h1s)6KF^?WaOpBl9W;pal#kdsTKwgOnfTba zjN49*e=g&N-{(;JcPrULD-M6_4hOFf?c6T*^$!c64~c|hI!o#JH{Rr_sd3imm?%F# znuSB7)wfUU-A2bxC1&J1ODl?l%xdeZe`r={$$Tu)H2>!0y@3M2Yac(_Uk*C%9}sYY zoOPfn)E`LzXV*$s*NMpT>?07PNu#_RE9w^hq$B$*`Z^?f z0gqm%)m_h1)z!`sZuDNKRbUIw1r2rfk@gNA(<$_-KI&|%aMi+WIcxQP?q_rU)+*x! z3U#x?p$172c&kz~F6!Ng7nQb`<>PZseSY(1`q3Mp4ZwO0;xsQ@a$ya;PAhPhPSg{$ zq+0#tNd+8O>}ty1*43%z<%)`Udqd%6ew12Xl74oTvfYX72Zx*Xpzx#?Vn7#_8o!Y` zdW%<*mshg_#I&UC&{11kLFS+;o7ZKPmb8y;p`Ty!khBi{=Q|Cn`ao;8K3TctRWXm; z%C(h)-95}D)}F)RMz0+jrQ)g#42PN$&Mmecc1iY;g@%yRY7&s+=~3k{i}CEv8fN9G zHAsyKes?})t%@x-mx3oJU~|7}?G*pBRAs!Kfuv4arp_x`CQMy+lxK{&Vxt{gC@M5&VniH;ohQlaAlU zb)-*3q94Z(;vYt-K-63Tx@32^T#e|FSd)sj;vl8^Jmbt#+zJUo6@rsApj**vR}OZh zPR4p}{|mAEQ#j}#{X-Xq-|=&^ZXgMA)4!R5gincm{Y0WFht8jj`ypibqg-@N%h$4k z-LvuPeE^yUa!ndy*u|6mhQ_|Bsh?g#an!?&);d7`e=ORzpdV4U*AS~U);&+F(Bl#$ z<+}{7mg-CBC}Lagj*s_fXg*mZ%4_UC`bDv4-W>A1dr6&5P4{hw4b`ad>TMX? zKjjZS(9!Ob-=Vel`SUnyu4x%y9kiIx_YBD6G^iywuum_6Nen6^XE|tAg%)g z{jN7rBX(UY7{texJ?`5qR6jIk3Gc36@Y`kO*!+pZLG9+mo%1ispFHVuNz5oGZIkC) z6wtB^1F24&T|&2;og>N}M|5mNO}dqX%CTDdEkq2HU&Sb1!lytPf5PUiXlj+`OWY#m z>~5*4`5NLFD?jyPkF&lh$`uZMZ7DH{P3$??)6^74e17mI|F~C7`nDeMcxaNpJ=rMS zLCIv(=BX)DW|dNvCjYncba|lYv3~7scUGA>O}X#0s?G8>h^goTlD9)zQm>@0uI?`0 zjrk`AyFra!MPZ%$ilL^3^@6a}5%5Jc;f+C@V#*GLszdJQ%+(8Tm&B?D$F+~2Q^bCU z^6!jw|AO_i#NfhXO|*LcPAZSf#PBcF{MuaC@G7V5=^F@>*uZoHuBMX-B zXkq@R@KhLlM$X62e+i&?Kye!epJ+FA|}F)sk-^;+1XHXwUx$Ze6-VSSr+pve&12mwT9YP{3P&Q zl=w7@oLV7m=gB@>suUJQvS+WQ7%w&1_9{`~1+3z)gf5EBQ`Ssc!#%gdjN3mP$h6Jt zyp#Ptp`pk2@4p3BIpAZKHET<$`_k1z=hoxjHP3{A32S3Kbb2 zXxG6I7!+%QM#?HGKoq8VDLP%t3=`vC;hTK>`c>Q5`1m337m8JKf)Z#=5)knjm!i=2 zcwA2WxPe);1+-b$4IkbXW);z)UwYg4lj0*HYGU&FoPE``4702@P4HljjktIP9BU8| zz_(>o3ArNTUVejDL8^c(6VM)nhYHRH_!^?UrPzLWt&~8`< zvMw-_;MHVZ+^;;IuS_%|`w%4m}UAU7OarkTSSr^-9Bo2mPjCtMR$Q zMSrs3IkS$pAGNpNRR7IwCtq=Sd6!7g_d&aGr>}y=y$Wsy?o+{Yd;H^W-=r*OuQG8r zHLYG?lq2L&cKiOGxCKkPHeJ$&e(2iDEfc#`RZ~*c7Nh5+^I1fXNOX}Q*))94I7G1n z8!E((4hUEb_I%qk4uY~WZ8Nh*B$z`LD!*?Zi9}LXu7KMg!=9mnf=U9C+k9F9WTUVB zN?^Ks_3D+fbFV}ju#>g5zk!EUJ1{eB+a$d~NT>_O%4OwH6J?U+k}bSXT46d- zyH_dVvU{J+p1+jFQBzk}fKVp$rvQ@>*~2FAtv$tPAh z(pe5;tz4(!X2_!kP6;#gP4kv&)612B>z8xi*;hNPc{18hg|y6LtBCjXaH7lp@sw2d zG#;YYD^*ZjV)mf*B^{KSgWH@a2pXf!1J7Gkv39(N)iQ;AH(uIoa2!9(KRxY5^L zUA=^RdVJ0>JknEj2CZ+d`T44!41rE;bbK7ax2ay5@Rr?KKktCOOqN5VEEQwF7n)2W zZ)3%xB0Mnp%K+*iRG8#}7zkdb#u-}3 z@%a4w{8dL0f(1*^M_s?XJ8`5D%rc37jMnkrhCB$OFj&Ju38rHTbANm^28c#nZ5^f#NC?0bu}96T z#jP|UN@81d(Q3EeeJ&cFCXwf43hJyCyW^wzv9m$y;>&a?+?Nm-tEwQ%T$NY08 zj(_@2Rd0#E9kfdHK?;t;(DVrZ79#_L3Anb)Jnu-md?R-7$)i5%U^ki#*?u5le#HbF`AXb)YJna)|rmQ zd#z$Fb^LV>QLFF}Qz#ouCg(Q24q6$QQkXLO=^7%2tnBR4qy*E%L<9wK^m?_$oVq;) zr?{TIu-SWgONKY8YDC=6OKNB`dF{V?E20u%RC&ku-M$F@J~mqFLoCF^d-pW66YxcD z-TDiVS&9&7i$wL9%|b$z5`B0Gye!GDaIU^wU%@HC94ECz0^A6O5*=}!UNoQ^6A-!?4P1b|kp4lnJFJ2Y<67Bq#$#9`qp{Xk6 z_g?6wgU=NE0BF)#GUR_%?1upu%`3zo9Mf3uA@Q`k#I|()4|1=FDBsOb<)%kVQBvuX zTlF@Q3Z=6YLONJt@L^#dl0CZrkuIDVS;j9O+O+JnsaPk4<9o)Znf0qrQ+?F01g;V2 z(s(v(Fo)f??vCzWzlUWoLXC9J7@^e2PkLVoUizSH+Z60yq8xtn_eQ8K@%EaO{e-6J zWr?e8U$f-eH8-Kd$&vPqskrIgyQ`<+8D#0g!o@kL4usHe3T^3tobOS7j$yvN*P*|} z{MlbC$6Q{#kWdn*B-)#Bu~lg4{@ZHQ!a|h(vUmrc>m6dX$)*B3S1tQ^xb<=mjU^^B zv#c^{Gs!uv7m}L2d-K7`J+!TEg&1P9LSpL~DEuKjmT{Q!o|SJu$p?*&!;}ZxulE`w z3HY3rkGhD+DJQ2)Ox%Kuzcx410iTf4d$`@rtkESdt{zAXI|s)Xnw1DAdb$2zeMVfQ z0k`CSTnq`t@s6cED@35wIsV~BwK7*Lpd%#zsC87e5IT3i!ou)X`XtJpI3J%?k7Vpx zpk_yS>QD^pS05NLvY~KLrV3bOTlUP;5)}=0E>^aUkEB)Py@C|2XmOE|^eNAqPb?n? z1zqMPIWO4(K@r3h`Q_EVJCJn0#Yi?v8sZr`P|V;4Y!V6hX0{a49?yOr+*RbLWlH5( zQ`bH`zfIoL#TcbvLekN-sw{k_bc8Qi)SlV|I?wfj^WVx00`>ws>3is z5xqjJcJ0%I=?Pk?S_iX3=#^C{DV%4;D;8E|TCRlb`tvFEB-uPu+`td*OcdIyip{F; zlGXIoFm}5ajxF#Y@1$&k(mOdd3nUIbb<&Wt8~z}66UZTMFG`~vV229*|IzeGzrF;I z+d)CSNj>_FlCg6xe+Er=O1>5KeK_x5cU~%ded*-vJTyQKR(5>1T!K34MAd=@X>c_= zTqjn?zujixnI}8#ku-Aav1dH4{;~y%SG)wAOJoc55K%a#+OH^8^d8o^P*8EtAwxHu@ zTL979Nbd{6bhoMvrkFt=^)%dRm8iD}e2rVRra;%m4DOUlX_CZz4+D2u@vNv=v(u|r zcRJcRU7#H$v=uX?6(f@Zl?^@KsBQWqB+*33fJ9hmXz#FQ`wtwpzTT+oQ*NtQZ$y)n z^-2*>!P?8r-qhma7QjFWQ%0aNyAukBEbK?I3R0Mrf6`gwQ82bZ~o??@eKpdzRf2sEp3%$eV#L=1-^CM$M9*APo7j#Qwx<{#l;r!>{oM)axZ)YGecFCzP1blgewcKb#Ynp(B4RxQ!G>4@F7`L zQZm@9wvRA1kW>Lz3|v!>@jyzeF@OViM(wUvoA{ z)Sl;JQcV&}3q79|Yy)qr*4F;jgy3LHfx(xEt zzGogkp^(3WN9Zp(TbbZVIX75btbxbZQwNmGrC>AvEKI!*Bx*@9YC zi>3ZsR~MwjQ82zB_78f(e~ALZ!@@A@^U|eDTvCp_qM~I~s+L zsQA5eJ=5HH~UP9h1p>((C zztMmMjaKs75tfZ@qo|m(hp_(9pZufFraD`H$2dYC!7nI2v`XK;y#~CUDR|OOb6cn& zy8z7RGw0}`vfs#fZ{AH)xog!74GrC3zTO5aL(%K`i&vdMJPb6rOS*qZ45kjLoFX~{ zMqBzL#RlGEV|uj`Yh4;8kI~)s-t(&`}Y?l^_otMd6m5`vyvIbV04n%?0D#`Q{10iNVBT zpa9H3FoVWKM+4dB1G4S$2yg`|hpCYs<}-Qu`Jk{eA3ZV%IDy%s@|FN4p`h~gwwYhG z{KwyCaD|$-M73h=2sbIRD3r$SVK4=tU`wHX{wysjs@-u9s|GnM{A_-hUqj{hErE+E z$EH$Q+|a;aprf)A2C{cX^2l_ywzq%c*rMDk$`Bq**K>YWU!1W0k%#N`VxLwzuv+(h z3YtLuZgq78X_SvWIVN=>f!$yIf2f{r5KOi8h&$Bf2X%FCch+O;TX_z{2Z4YOEn6rr z1o`=|x;TU{^F)BdF>fYIkBdKK=ex;~=^z>cDcQ#>>$;4Xo@+Nz#5QfZ)Tvst=NEv8 zlWXs&kNOemnQ7@aF449)P}ySkgN~tJT;PEJO(Mr#Qn19~eVO}l>fP7>Dww=_%W_a< zK)Q<{+5UHeo`@`-{(83I@p&O3A!Fl60!1`*RQG84LUnJLm{vVhKc+D;QQJ5%${z;m zfRMBYt8Doh9LBi+2?9N754D{x@W1c?i8BB6H|HHLhn3pZwk^H1eE9BgZ|_z4wijjn z08aPp&0j0~KuA>dIhAV4dGytX9LSY{rsiMGDXprqsOhWW2l)73=+2E)ft+HWHMX2n zi^(ykH8%VP8M1}GP<-ecycP0R6dIXJ@AxSHv;0sBSi0&vBJe)T^atRPE$||cItita zy#_=Kfb3OSg2iW}WOACnu^^_HC*D6oXl5h?cYpL;ty`p!_+W~V2vY@=KE%I%nCe@i z=IbwC^tV*_wyb4of`1O%q9PC!6Bc?PNdIGzOrWb_KJ?3z@9?|U1nu#!r4~sI)LdwG z?VesvXhXd@I+~3;iA%y}nHTQLUx`14WX0B$>{mun$b|5fBjPO#tdIbscZfxz_8eIh_;(aw4;;{C|GJ~X(=oF zjfkLLQQA#@U~?UzlgpX@UMh5vhkRnYZwbyjcXxN7Q#d7a{I2}4EzGC~{?+O0&5B|% z0YI9T(_jPVcoWZZR@T&R8X}oo!LRQa!wR$8tm+Z8*>n!-jFNu| zXKV_KpZXDEKsrNyBmgB8^m&jmrPewkQAVEZ!tk)POzOfVKy1{1E}?Q)g*H$HYi-%4 z7H?J{d%=XNlJus5p|d5Yq)I zF=odTj#a!0APaeU`Y+bTXda}9{hruh<)(T4bKKr>go>3!aXXD&jsavT;&$USdO;AQ zUXwRvLSo#z+#k~5Er*ZkLek4u>JKt)PZW*>B*nh3kJscM;@*#Hw*kcz8~`|bFj;#C zsg}s0`1M*{cn1o;0*-4*K^P(k6CzGajF5a(5-Bsh`TMU%2_N^WXKW{{6chrhrfGTF z~OB|SHHeAT&m)BfFVWF}Z1-Q;~O%b+5t?e=<7U|UpTSWG{Ck^OJGC9%~# z6jr1c>7BRuR>IHp56(l0Y_Dw0TapK}@)BrIF8q@s@zYzn;T6W{(Yqb_#9oj7iU&?N z2|w>IVpMvz;O~h)$k0j2`2vI4Gb;5Yl!MWCQ34Srgy=&H1>1baK*TFi#KbyFqqdCY3|N(b?ev>c6_W${6fc^_%U%%+TQmK9=SSv3V zhUGbrPR;g3V}OgMyG{noboJ}kFR0Y1{_OsAQ|YX(_bUpgT$IUwGxF7JF~i-{AMYLZ z+(x$$u(w~9{ryBm0K~le|K&K~3%{i~N^I_v7x8^oVe2R?9d#?iBt6K0xeScPT1`K*%9SH(u zo9hPoFP=jW2U`^jBkSy^-kUC#KJ+qYchR905Oe>x8ukng(`+G@CaCDY3k5pJ|LaXa zV4%Cm+CPDAM)k)CZiSeMKb-bKrm*^Z@ws=E5%@qJ(^ut3FU;7MW(0Jp>n|}Pjr7~> z$Sdv>z*eqIv6T~U6-H4auSdQEHPrvFwqq707{eOIFY`j1_3~$k=#Q2Uf<8AN!oCOf z|HciZQLer8dt)XN^@py2knKGW_AA+T#PoDi-~o)+?DP@gt`vmvUNWq4jGS~ zYRv|iewC6iT*93d$$*A!k+kA9RC5NPL*95#kHTqGM$I7`6V-c=jqnM;3c~MF&*$c1 z40Jv8GF^2wl5{HU7H`hp%R|U-iQUSauK z0nnSDGLFV=$8{^LDw&l7PdZW1wHNL;+|u#dsSNAr5Cy5K1ZVOu4L?ZuWO6vOvLo>r zJjdo}nLQZT3&;M_r5aEw*{+BQ>iSNv>2hKF+7XzOn5HX}UcryF;r30TctAgK&cAIF ze<>-n5vd&gcI|R7I`4y`P^L_rlt9o4cF*TMCBI@BQIH1mw@G2gKc(V^zgzid!9u zdf=9Pd(&R{igFJCPdk{&2l2m~YZiM~LxUX;56|NEb??qizix;)qj$2NIp61jACupK z3#qrhQGE7nU1Y-+x+;xQ<>z}_scw12%efM~?Aa^Ct;~z&ZV+bKD{$+Kxgd3w=A5G} z#tT?9*0ps2)@z}Up_?ikH>HvZTRrvV5UKcO6Reb z`7$!6r@C2UNCHnrhm!bro)&icYnO=DhNbln?K(p$tRNDi?2K=%wr1VW6wLBxJo94i zx4a3wi>Nh!NF5d3Kor>Px#LrVimVDK!LQ57E?c-%$fo(G9^?OyviAU7R|zu%wV z@BGy%qr>I$aL^hivO$u&2*1n)dx9iHvpc9G&{nfy3S ze~@3Z#4hfgfRd>{BwlSd6K&UPZ8ot7w@z4h9%|WL?xpwz zu>URbmn%8$+zpC*B|!Ys_yWUv1~*}o!}mRZ<1H~`e%rjpm~*M5g2=a%|Lw`N#CoK|T*O&N2XgVHT*~K6ndw$c2H=zH2@`zardsw&IygzTmr`K@Dn7^^4^cLzB3$nHt?Esm92y?hTWjY@HvN9tBuI7RsO0PN z@*mcOb8Y4)rK8^Lc3JWB`%d7|{CuL17u&ryp*E5!D2<8Rg^x*usoP6oikQ2=m;J$H zC#qSh&+$UjIA7f&z~dY6KI6ZIYi8ZDi+#zftMAJesciB;RP(|_@_EeO?NJ{8jp(zg)Ks;L!VdsJ@l`?eNY&z6v%Zz>+1> zteeG&LrzB=5qPXK&{6++-Vr`a`+3(s*CWKQ-Eni_XqNGFiCv~%*m`s5a}L}j&NdtI zV$R?0|4)~mtJp>#=GX$7$RX_D+VopHTpIKp7cF|6PQ49O=kA{QU8Lzjz*1?Op!1LD zQPE5_3=0ZU?GF$z%+H471pJ9$-)jv!)tDE6nWd$q%=_}J8lHk&kOr|%YiDPv1|$c6 zAz(Ntm9Zz_Qo+cl&6dpSc0FVE^Pfw>3V`_$2naAn9*2S==Gc&4HC(uXOeO5c?kfRj zLZAc-hxZ>oV00OjxPD$&H(vu0cMj)7zN!-zwa|tH*VR;47n5PsR7+!U?n$=UD8xvt zJy?t44ik-%a%f)8Sy>H$_5Js2GuckO(yf3`VH6CGLuF+pW|~^wm9U3#hUu)dv@}q@ zva&MO4ybm#KPjgcjOoI9_^wOaqU>c(U;#tGH{|zyQ$9$p+I1x7mqK z!kS336SGmU)8HMoX7y?SsuWnT#uvslB{ENn%vQ112f=by1aBG+TC(5$$jK@>Qp zsHjd7431ugtBGPd=UQ-gq)x$JN&8cgM^P6AJRYfQBwK8p^E=OHa`n;a5c?GmwQC=}QegYP z-X2KpO^+VE@*C%_UDA!}1-apO?yzgVc=e+iZ1ESnZS%z4Xl_{u@k;B`09~ zY6rh1pZ8ikpR&(KzJFU)#n|rvcWrP^5*Vw5B|AOl=CtbPrn(wVo)>18Fa|EJyBZQE z*qXe-HXNT(?9qT5u5U0-^!Y9vhsdQ~VQV)CQ}c@LwRO~_c!Zi*jyRN`aKLN{)|||w zeXs#da)627R4NE0<|5@_E`bDb@*}TYFa&_n-=?Qs(;h(CRtH7c)~#EkI`_cHTQ{-m zZd_d4*RNk;QFRcbzk4t04PBDq83NXZS;Nx~Oz$Pjo*chf`|{|@4F{RnEM9EKTAa@- zworq}6-j~?3ATqPNNKItC-a(n>yp(xNcKRcnMWzxqB918AMY%HceYc!E0(t!?>l%< zuaPbpkN^I|hXT48ak`NEN~&*5bD^v^qr*A%sQ@_L@c#XG^!ucCxE7Nnx31rIWFe*e z%)Q*pHxd>6Reed$JG8P610Nece9)VA0M#faCT1SR#>d0wtgfj6R;{M5&v#g+8-ROX zpDW&MkR}9n?|z401J5SXF*u@2vE%TO&VqOZVWVUVbW{hjAwv29&ysUdr?;=X zU*cKj_1jGqX@~Gr%*!sl{1Ih?l-56>`i#~(GN*PWc|*1c+A6JjmUR=Ho;1=^V2f-G zD>q{`C8bnA<>EfEFl3wbowPhgpN8X2HzN3{&sx^c(!b6aI_ zel&tPI5@lpX1>0p`H!(W)>SI@GagqCjN>yUa-omJ@Ju7L`sIB{Ftd?@L0S>!F#_Rb zYOtuDE8nUAp_$|xGU7#?g~IfBVrt>W&>s2({@P~?PUQP5cY}Uxz<_dlLhqgP=2r_@Mhc}(;8A?_EohJQ_^j7onXguV z5Oc(3?<1LD@Q7uV=UDe(u{92#YzMXuY%IEE=+d8wu^d-$IS@p-4kM45QB+Z|ZUA!! zd!;pkOB7Cnq!b_Djp$lJ-_g-=#>@;oWECEv?`mWbj!qc35kvl-TYqO@+{M0Qt2D&0H_SJ*uZyhu zx|k^I<-`|?dbN6UxVGxT&vg(Jmg^Pt6BzG4Ngqp8sC;GskM`t5kDAt8lx(eS?Lup3N`8Mga2N4m1t4bllmhS*fXk$m7Q-66`87*&1 zON)&ER@lpL=!I9g>KWuLzgGzSqXT(^u;-Kw?MY3slt^(_<00!PE3@^$*!@IDf>!+(GTMLyDW58;1+S!R&u+a3kHBVpuRaGyW+t3Kh?*1KphW8q^0>+yjl3j zn|NW~L>CEcLmXc`DTCyLSn;uRroJ>ecS-A@){U@a*iHJVDwubHXmLCYjUDt&! z)AS`?q3yh69ku+{KCIN+DNJ;L(&f_FDNJg02Donx^OMd8|4c&TjC7GDs!Pwhe0UYYLHY*o&Z!w z;RK$_8N0)^gCE%!Zu!Go)OMal_OEun{SGnPHkhAngC>YN5{`}#lftnJ-2bCI4vvnL z`g)q*e*0cuG>aXq2jJYNq*MjTX~5<^FJ8TpR?kN5kJFf*ZZ9V%XJ_|R8{JqHT8H8Q zK7Rh=$B#!l6$=VStHxWTW4i}>!cSn++k^j>Y9yg@aXz4Xokiyb+r_KDo{oy`I31f# za8pkQfli}sZYzKT1_-lI+QkF~fqPC6)Uhzf??6&=GAIDtbvUwoFN#pDT3e@Rd;9y} z>%kgg6{|0uotBJYXs$rPrSC-pg=S4PXRVQe40fHM&On>QIey~f)+I#8zT_`d$Ggk* z#SofRYQXhDZ;;>%4_8yUUc~c3N+No%GR}w-^R+w70_8fuEj8Y^XOBu=mwG05HMTZ+ z-d;@FwY3^tB_iLmKRANMeF1Y4UyOWzJ1}tj3vX}lzyXzB0Wq3wVjP;!Y(5DD+hBo( z)mc+hd6Jrbi|PcH@aQv=i9SWg0Edvn^nW*ZiUzSmK9v@-ii!*%y+mylb9jyN+Q`Vr zS*k#jd<4%{9xE~9 zZMkC6qKAL{12N%NBVWQK3C+Ei*WV*uGn6wr>1X35V{u4sbkPyH6Q^gci5*AQAB{Q% z?5chkUWA8-!?Mv#a;F&O1D2BbiQLQhHA>#|ISnh!6s8}=BJti*@r~gj0#-oOC@u%# z1y6fOdkWR?LdA+Am_}k+d0ZL{n2RkhJh4B)cNCtCmt0)zEAV>%4a1=g^Si%l)2=8q zAU})Jh2LWu_WRx)P3*&amQl`P|2h&}ta z;_OCbs$IFcH5$?x6b`7-zf zv0FiO*^K~`zn{%-L%F%R=v~qmI|~CsZf`enSd@0>zaF?9VvZ*qSllF=dRcKGUcZjZ z&)@oM@D4pbkBU+|GXfDGy;A0dX}&8U0mAy&?^yrv8b45pN4m&Qb6IeDD^aTxNN44~ zlh@d6eu1wR052+PBs?_eG3Np!3^4oAWdX=QWkB8#hO&+@qnU)a%Zl||xsqf5UVZA` z#X??RX;iI}2MOe(9cnU`{Z_;(E zs>cT0jtJ)~+ksWC14OG9LmHm1F+j&7S{n2{s1}^(X5H42u?vienVBcq*GN?^S~bbb z0+)(cTmlyg$wP`!k-%!gpA=^qhAyzsG=Rq=ntb$Y0DhJ)Uk+oDp7&{ywO(fWN=kye zckhOf1x3gw*I~aC-7w0`CRF)98>4wYqRHEUB3?X@@FZYSM?PwxPu6pXEg{HkbTu@jIk-lwMG!{~j{}VgKh!tsjpOA)7+?$(E7X^rK0A(`DHeZ8Qmyb2m{w2`1si0@!WX5A@}j73)nPtTtNbX&pK0r-~__-M`$%#bA-9&=3`E)R5}5TP@d)E z7hzSKO2OV=>ZxOqYytu)5c0sQJ7Dw~b7TPPVk)Nma~u--g})080g|fsFIoBBX5`d? z@2G_joR>M@_kNFbgo_I`@&z8JjzK2YA~^oeH;;I|-p7AZdYRH~IPq9o_Tn`F`2%m1 zD7J7H%MVKQLPYT z0;@?Y+)rt*+6oa%!OK_!l6-!G>U>O|GLmj0od{u-PKFzJ=^8xl!4Dg`O zvQHj58qCltuGtevrWgGrKHpWi8@l@Jj+BP8OyO`%X)}`+vEg z9JK!>1zeZL23v_G#Q5niP{PjC|Cc9imbf6a@KeC99g-H$;YwdW_s z9}Wb}L%rd4M+jJDo;HAgK;29&u!(=9*3gJm)SJ05_#wV|1CU3Ao*z_$(i>%7m(%7O z1oo;7q!yrsz9G~jvhMcrUDS=CTl~Gee#8FG$&xkmkK*ixP($7DocYpr6?sCNMBu3i zBQ9Uk?%uuo+Epm$|Guk_BT4oX-#S{A-obAw*6pmcj7QaVro5l_kUp z-w^ik>XOrcUh?YVATW_Keg=|StduDzSy1imN*;8+-Xjwo9SztYQquP3aJ7fj>nBPT zHnE)LnEMQGAj>X5K$4xCHiaqaIfIXjepoXz$F}7d&L7m31O1}W)U!YZ((cd-*Im3a ze{0qn*T|!LJsPEQZRzX`2@B&7E-fy;=W>AO+kJ>M8xO6wU<48x|i$~7G~h!;D803 z+UFe|>G{2I^oK8BzKoLK{rmUWGNQpwQb-F53~cG@5`kTMJ6O>9htjzH2`e^foG_L( zKjH;-Vu$nRAmspj*{4YK<;$1R3Y5fNWJBYfA|fJ)B49Hop$3ulum1GOC?OxJOcgjX zy+Q=?p-)Tg374^oiHh=ag7yzPWzgwN9@QWXznz=wamGfC_XLyb)~@*ml6tIh{@KJ> zj|1ShN9_PBFkm>wQt|4IbL9X&g}0sog#vX0T+pJ*q4By`uBNJ5`~|*#m4}>PRzgo; zwVvgW2ztW2u3G^CT7w91f1f^X2y@&RHaFcVLHWdB^wh+AauczObRM=(&3+lUtOMfH zsBc&g>Z3rBDVDUvL4k8W#ep;)D|YDj`nu1)u^n5g2KZEEO6YB6Q$_x-MxF=)AP)kGv4K^J&miQWC79N z-*Xy>Cf>p*h4b$&G+(+&Zg1U5l-7ST;qunP!wWkU)uzk1&{7xu`cC|y0kC8J8+{mn zGd$0Y9+$8*_7bKy2|D%I^MK=391|XHh#?0y0PK`$C~$!a%w7fSiDI1Tg!uU@nww`Y z1lT$`-78GjfpA2fM@nJo(xvEzff2?(#W%@0_-xq^R=Jy-Tlc{yxTB;Y>=k$ru!~WU zN_Jr3z4=Q$uegv3uYsbM;ARkeNS=)Dx=n7?~fns1Z>L?hv>>=*~6K#yWRDA_6iT05`N@0V~1w zSQxg;gqxq*yTiP5H^)pneI2 zy5{#~Z>rPL(^ov$S6W|x0bn!!6M@zH(?5jncUdw2>pM94#4a3eO>>&SLe5~hXiv`) zj4|*^7CWO>2CmMeM*ZGfUFtcC+af}Vg>tyCW&bP$j@%&CG&Q+lFvaYNho4g|ze>vy4eerjIAXtU{Y^BvmYVAgyG(Ut6VBMj2dFhvWs-?WD*aA0of z6+#z^CAznRyONCZpU+PuR-|=DcRZk$;#*gO)Ioj_7B+*8N-!Oy&D{(Odxll!W8HlL^PMq1V??R-s^K z?1Ng&Nn%+iARsHNB=skCZ3+1a)-Ot?MuK!MkTJ8{ZGZOnYu>S}sr38?`%Op8K0)qQ zFm9;)GBjHw@pzCLsaIRnwdCq+M|mM9iSJS$)x`8O-+21UXeQ~4n4Bnjeq?TR%RP!) z=|kzUtP9--ocbR4DsFSVSujvUxY#=Ov;Ib{Jy-oG2x!ByH@>4M>u73zX>F~B|NQx9 z@cbk$c;h;90|0Q0NaTBQGH}nT{l9$q0$w)OfTGC+I6>OY&JHH(d7K@9&v-L2O2J$o zV-zI-yU9A*+How5l$x61@$mp}?}k54UHcw+0kuOhfvthDXe`Tqg}UZV#9l+8uwG3eeCivOdiY@O#N?1NHNuAnbt6+`{8OycE78*+D+f1&n5 zb#md$kJ1)k)pacHgG+1ir$;z26fP_!(^SVwuGLyvT7CiM2}QXA!Yo_2K7v&c7H|;c ziKti5MX^zI(u_U10(^aIF1}W$Bakv|z<@3cX}-0Q(FM(!HF_a5jY50(2C+2LdE#(_ z=)llB+*!rg;dscp&CdQ^wq)mURUQl{wEbSJq~Xoz+iTbUSu6yf?^+@-T+FErL$mUo97WDM?`bykFQjlVuo|!4}F{^`3MbDksRspSzVUD5#D1+k* z^`|e4U0)@rqkVr1GqZ@u``J##_#5ko$Hug`F!3aNWSkv(e#MX{v7@cc{P%Y+%H@VA z-AhRvA{P_Pir>Cf&qzP)l*uJJKKkU;OIJ*1&RHd0*eN4>(4Sejy`DxMHWbTv%67~g)lWwM)7U^m@_&DX~J9{4*>FXY8nC+*;NI8l~6fGVs zVvVxU8Bu6VdN!A^v-gB?$IH*BhAC?jS)whJYGuZ%JGKthM8El>UU5W0hhBDgwBN?c zs=dATT=`uIpQYyaOU0Z{o@VO_O0(Fcdd@>KlWE_sc>mc~TQ)VjPbtlZeey){zj{f( z4)02AOYSEPL!%K?2mjjSjbYXHVLvMyWp72O4MtzReDNYf$WUF~#KMB7z%IoYB>>K$ zk?WAB_V~yM@X)xxKr-N<5~J6oZ@0G}U$SIL!v1LDQKk65q(&|chvovUy2KFQoJ*mI zQgVeSm1O-2FBD_Rwfo zi->XY8pA5_L<{rbUx1m1E!~JMalFk*p-*Nh(C`5jLJQtpEKPoJk)z-_$&~Wt6 z=j*o2!9aX)YP6SMu5hl!gVmOcSAuJQsoyXrTBKU_;V+W_(KqxT8h=C$Au|(BvYAz) znp?DhaeT4yn0?7AEd+_)38$bNU2E6SD4x{yNZ@Gt@S)9h#7WpSKQ! z)`MN|h0hIsd8xAsuF0gO8mwta@})v6NOiX~LT^8uOgHI1xMBr=ihc#7W1+Z*_Ow`2 zfvFlheHaEOQ*%c^hUXIdSF3{*)x0eQ7z^q0LW9_b(0G zd!`(mED`&5X)uSw)XZOD9GTFuywgIe^V&^%P+%uV&QreMkD1(3s@is{D^#P~yrL^$E;cHX6ru%UdUcw`%471c5)@7-%;eY(d5M_r z&@A9xEp^QxSKC`aSe2}E;Rm8hZTr#cAk}hSbwx}0dv5(w?U$&-45TDg1``sggn zdPPuQJmzLe${WLwV9^H9;Q?H9aq0Z>B_UiW?dj8vn2^H zXmYlsnOPhdGqda0x4OULa8Fc>X*p zk;A6zNyCFf!Jow5-(euad9~8|_0Ou?T&kBkFuTiH*)9dt~>hB=mcWWL!DwTb}A*FWr5b z=ZiO{Lj#T?Cg9oT1ka-N4Xu1Qoi|vGa45$Q_lUS4yn>b^RR{~4f zgje(O@IZ-NYuZQeh|Rzm7ar&5Ps6he(-4oVYBLrR10dWTK6FULenXhdQ{ISRm%#!A z*?k=C`~>bRlPDQGGTkPzaR+AG4EztDd{eu_Ih82kH9i!xo8NElV)AR`CudRJ%(oE| znV0NmzWE3i=LQ6znL7@s-X~zNX{cL<^es;1c#IOwJ5qa(oqoSW0<%^oNsSLph&;cp z5Th_8oNjgwYA3U`=h%z`bDyb2OSReV;5vM`plI4L#oIe=B*s-?CeSTB)cNYN7Uc@hl0tsJz+ z?I%LPIYT}sD*1UDuL+0Pnb%mI$Z@!P)n3N13xmOwEb?^+v7vc%`8Z2pvk{G;VZ2q z`5Knw8(j)!Cs}JH9_ePzC3Fm5i;$KQlyDIkj@9Gre0#|tDzWwCjaMobJ>Cvo2a8-g zIuAU5`&LL$A{sq4pP^v^ozK`{0prL`iCbn3)snX!N}ugnxQP!ps;YSmGzo4x&H0eN z!_T=6vMN|3bE3AN z=ftDlJv(PfzAN2U{dE7{+P8g3lDqfs*Uh!^A32+=t@tQu`tnQgM4}YP8e}Gl5+!uf ztipKHCPWDTQVsqDRtjCnjjp@RdqNn@#iQwY8Rg`xU*C2&PS;4h=V2hOG*Vg?uSdx+ z8)?VZZic)#5BiM8*~EJldYV21-Vp%F^0fpRDQbQ_GV$@83CD?}k(DKr=X5UWK?fyI zT}`v9&wdN?FJ1Az zc}lK36@^(qUI-G~mbOhyh_nLDu@B!`NX7P)6%TrFC3VLlR~YmwdE{$Gi9hk{DHt4P ze5x*>%15efq3)TlCJMQ%kwYWd}i| zAhJ0zgZ&HQC=Omk8qTsq7mNw(cCnUKK8g(YbVFqCxX+tf{Yx zGPoL9TO6_U=j-@SXu6gj97@1~iT4DJ3`L9n5GZm7DWc27-1$w>*tvBE-<(iDU0q)D z)Ssir$^&s`W;nuh=4%^FKo?%{fBr<*Z+*_iZ3EHjJab=fN&pZ9=urJT#;eqDU~%oA z2(-{CvJTBlu%pGXl2VeBaWGxsES6MAOkeD4k9Vv3W9gZWmA&JOl^Fo#&Yk%W!U9QC z1IbP>o3UfDZj#pBo$$v~oj}ET7IRzo>F;Q4baZvyzy7&WbpoBKtE=nUb?Yz@z|K(h zV7Qh*346xa7#QasOinP@X4<@2L{#+Lr$Phu`(lm>?}dbgv7Z4e7&6D&5)MRzLV&dp zMIIiwYrx=$!Ou=&vjO&x>SdT=Jq=hQ&&w9+n%#nj>!I(gs{%FNM3Q(N=TOyDC7e!4 zS-;P8McwJrHH-m>P_}q2u3VXgn`L7BR~yUY2c%~-PJcpK?;1#}<=DfaBJP|q=tX<2 z*+uZTnMM;y)26^5w7LcG|A>~PDR3>YtpA4P@(T(wN`UKS_HX1@c8J~7l;Fq2#>9Xr z2p5SH{a)peaf1~JI0JM*u%cjL40F8kuV1@9WTnP|L-98RxW81xMh^D#JUqn$t+5fV z-^wt1di3ZK2budJhQDC5AYb9^@e2riFVM_Krlo&W9e4tNz5EQgyl?=L;cvmpw zNUoq^{RdDw82$BQ@^{b@F;rGiQ&Tfno1r)^d{X?cR2a-Dq&duG$$!X7g zIv~H_Zik^*i^i+wV2soDowTfNqkU&tWwWQxbX)`+?>Hy~dNW zvb3RqSMOXu4S2uj&nk>bF&~#51-Leonq*XD82R+~hNowMynvz2D4YmU$)S|ouDkg? zfH{REJ0Hlf@}*~H(uaaVR9RKkX>z%gK8#U-WoVqW4pBet)|SrkL3zAFC?*&L!zUUo z+dgENN2}{vH%wkpcOU4*66pz`5{>V*2j%=#HQWaa9$&t!5)-q_wDK(9)Ej-lR6}sC z4!elCJ@d$m+pzVJh85VGVj}OY0}PU9vU?QbeJfL|SjXl&);_BP?$f?JNohhL~qkc|5A=+Zjz+f8|dv{zKj^U!~Z~FLXoYjjG#7YTrqM62{k5{Rg~nH$J&7X89}S0=;3HvPWxBH_vj!Jdq}45+7c#vw zBZ%>ThgILXk(pRo1!uqLXIcbjfPx^G#vLZw^I|AsZaS8W@xZ?7`3XROoR+_@ui9bf z95eC`M}nW9fy4(CgLS{vd$wRfou`s+dv~O5WMVQmHr|VkL%ViA)X!HEd;t6%3OqD+ zm6c9q+~mBV$YMFbNaL(`<#(iFSb;P!Epx2>@liwcc-FHHs?)Fk+19ey)YjCjSv&Fx zmG^Le&>vqv7e|f8%2gK>9EO){YMkvCE9n3he|G7$Vh=;6`-2ZH9AVZ&NgMLKB4Rwo z%C1yh0NTLetw_G>={Ygdz1Xzs%z(rOmwxB-nXHqwT>-DIxaT@PZOm5pm7a@k3O!Jd zsrQlU%5_zTJAu&H$jVsQ$nd$lFO{sqIo8*7S9WQ+m(1$*LQq~}Q*T87CxIJnFG|>Z z6#ARfW!0&D_Y*SuZW8;oi^H*-GS_b)4Ih}@yC7L?@%k@F?5ppRD}?^&0?SQ4--TwDXC1BEL}2p7q*MN-w9gTG|%omdjcg*5g@d+wP69$ z6?^Q-eIfH8^-Ji85IHQPBFh%wi!bd1>Icqj*{|t-V!NP(l${1@cKHrYC7?p5I#c`_ zL<1Z=F51=w7JG20i<{}IKiZ`+HoOHf24Gs@)Ica^A{w8Z>)b(3RVVE$dW?oB)cA$4 zp#h_OtfG&&o4)1D?r3R`S{ijV{YE1L7|Kj{449`C9R>p%6BLD%{iyfIiJ`DWO*-+0Lb=9|`O)8wuan5nHcBXKNbR2kdyW8a`t+Dm55s>lBU_WSJ&2>kV#C;Zi(>{ zJu4Hq1=f+{dps1-Aos^H(ArSSnLU{vcrbjB~3Mi47b}j<`T9N_UEi`5lQ4uf$bDo#Zm5%LC;+fwsyYkr zIAeFiamTbw-W;3(#M1{iTczIMpanf~=?LC4Hnv~FkT-$KU{8YpO12OA;(YJ3-_+DL z$vVus=C!veoaz)b@pjkM;l`%rDB9BsGvtenX^q*njH9#l9AcK|I{(?>HNAWHxb>uT zrYDcY`(!;+@|^c38BNO$U^t1fv026)FZ3iLa%Un0rFe=5Y>H+$H8>+C*y_ZN%x87x zJ6(u+f2Z&G={gV;8qnwc4s1`j3$dEn?kQ`3tV z)8w1XZ`A`-!x!4M&uG^OeYnc|$eV3RI&+-sZmx|7&XTCfKbPwoj?NyiMz>ChfI-s3 z1N9-{o07VbhP|ULwK}%goV;Bp;iq@nN`GSUP3tDHl`EBkB|9^FOP)Ogy0%+LXtP-D z)VBjU%!})4S^bu3YzcXley?Xn>(fl6u&-3Qqq*tuyIZj?SI~r+|yU&Z7kh1cR-Bo-2 zpFI$pSnpM=qXVmk>8L>S4OyZALP_8eNP9tqw*?S}>z6QYUWvGw(;Q27-hrskd zcC+uklI$T21rKxY?%lR_c8xF$S0|>An9V7LAIbrv5V9mFKd|jQ0HjZF9J5fMgCPS4Z_T3TqS%uN?qx(aH9;!uy>WF55`UYN`O5UP7A>aRL8q%0uj7Qe!$|@P zQf(tl0Kad^jEXV=$=vu1(c?^QC3+l^fdi6rxVW2cQdNY+r`NAf@N`lf1q^>o``(u} zb|hyRg6I>cTgb^Tt$#~qI4HUT6F>`|B#}Gtp^u$a?wp=b%e#;TfB6hw#cr>KQ%gLA zg>(kvdfqFsTw)>odS@|oFLZN(^guui9FFMG%a<2{k!0>hNze%D($8~B*2YjiOFbO@ z*Z%rsy;uW>ghsjxQP}Ba*hCxlW_EA=o5YYOPmWfFD-uN`JqB$YLJm&K@7lq(%+7w_ z(Gi<8@gX8uPF_#1!(T~4wSZ<|P$KEvhdN`X1C@iHLY_w3+1LbR20p2tl(A%>+1fSg zaZccp3v>!d`v(qm&a5<+I%WG+{k++}eQGOLe&|n26rR-V-#(k`3W~~E)Y!!Wtde}H zsS!jY;c;xfkszJkVM~d83@i=9U*%NgOdDa(q>W*4#qio6A`r?R95FQspCoZ<=^NNl zgc?4h{piN07%c1%;N>mRilt%OIv*%@GpU^R`<0#!#$8uo*DYV)O&<0zdiEWKF&4$Z z0gaC@eHwQ#bo8oLa7uj4#?4%7+4_XEUj;~ z2Q_Q9R~o%$KIoKNVYLBe5r|D z2@Bwyxg&kZLchrnU0V07#D;&8SC>heq6p&Qk;6OFEDzd=4H zv~QnASvE1Z8`LivdbJEJTfo5^diR9#V$6j8>(NJ`sghEHAw4$lwUI*er|J4hHKnD) zA$hSSli&WBfP|;fh^F4o3lmtN-s&}0eK`4ALIU^RZ)3IKrrVxnW&YH*#UYJla~Jjy z3^y7j)>pIAHrB>(GD1JsMM2FOy}ChEmUK*ep_`EO86~x5Jp9I{+7y3>q{OO4;T=O_ z$YuYB{OWRw7va?kcDJ|0K^TOJ+B6?JeYy?S?cR1EYxHBT0y-Xa;ZR0{fq?=)xJUAD z10~wvE_EBVkG?*q<5?6jN2;!`4`Jb>FSWo7XzA*8++y`M+A-?7JaqkeP8!fjQe-$| zm1w#sZ=`fTjg|4B$~s(#(rmeBUi7#8Y1}EyacTs_G|s^#Zz|JAk^knq9b(bZ`K@b+ zT3c@VKiAq$TAG@>G!-9-oJX-;DrOCo@YJa%(k;Xchr!|r%<{3vtLNqX zjApa4*>3WLlyt|+t@}%^`;OA=Al}ilEC~R;F|UyA2+dM=f8K)mF9)>G%|Ycx?w1^Z zLAIC8YPj9Gcf6KItYn9U&m^nO>KfJiffERXFt@OHYDQlBua7Zt5hU1)-O(YW$VevQ`f`3Lc?$|~7TG2W zahx#(aq3T?%X`ElE6AhR`=P$6GR2pR&T+-si_lm!lWYfwAsw|n3g`;*Xelt_%+~G6o!OiWAI_5I5`!!>Ld@V4u;;FJ@KSz zqJtMhShTR!Q+=4{c;}0XydRMNv@5~eAc|8qvEtf^?$Xc~2p74N23LZEk1g}Eod@ck zn@IWz8~(tw-;Y$o$>nla(n_$pZtY?mtdT#9Y3#UR!|m;;Kg}o!9Y!Hl5PUh=_3SEl z8L@pN+&f1|onoMLk}5HWsvlzyYwOCA(s4OQRn^FY4wx`rOSSPJd&xN@WKEDCmb7Xo z#Pa1iq**lU8#(`>?iSy@!KQHH>HDOFxcxRd=4NJWJXk!3nL|kOhaDC?>Jbix(_9$A zKV(^>F{r07qvGk*+o^_G5cs8mF$$RWP;HrXOd^qqcI*@GXd$L5deL#aazT3-@366> zg&=Yld-V)azQ7FdzbKU&Hb=Y$z-K!oPBEzyVj?5P4m9&Z6>1%>ToJ8S+EGrK9xN2B zyagXY7sijmv zsK>osd}6)Ln+S&P)XIgm?SC=dQKg#qA!Zi2#9D_->OYs*Vee&(yX7lbNZi1UO-67O9UO!AHezZSH0n{Szdni1e zznmxhyTM{F8JNeFQ+dRqU;V(OXHN#xTn51nura^(AD53plR#V@4j|Ovf48Cl1-klp z2&jXNQk{A>1v`_W1k&9pwo``b2bj7xxNBs5T+8MVmb=ThnXF48 z8x}MY%0*kTi>IfNx{GIr*bm78?56ejexZ3l4expE{79Dy6;-nfM9YHUgMOzMasWONj?`w{?jG4L%i)2Su=Pt4>ZhoBXJs2GMCVYCZu z@5MMA(2ZChrC!42E|a^oVIPf;&Pc^d;^u?qt{`#PZPFoAf}e*+%zZjr8km$6@K7O_ zyz6l|F>2@Dw31k0kmP*kb8GTFu(!|qLdGStS5!ilPINxh6F;8(i^6h4nApwiqhjY< zmmzTIF~XIl_<_~w)5F>kaqJHsMf~*3is1Ms{TKXXfFk!$mR@kZ?(6#ovh1F3=2}5m zN=|D3pD1pU*gk*E%-+ z>Cr_eNrjf zF|aPeDg!zKg8MNBoL4bM){~cy#T|GS+DXDm7bqOHJh(ubaiv?@XHsf0cXmp zCx~rY7Z5$Rt)#w2NWADlAp8|`;5YeuW>>n4d)U?8jU8H$hCxOLDK>1W#19{CdigRE z+r9Al{0j?bFE3t-ks|Qly1WZEDi}zewYFy2u;KQD2TWVG=)tpVHQvV?G_1|h@{DA6 zfLoU?pS0e-9StzE(?$bl1JETzwahsek;&%4$G9kxHJvto!aGj_wC3lvhOECqfkKdX=NFihBx zR5HTv-sKn=1t$eIE+ANxIP2=_Qm#Q_lym0IJp)!UxaFz2>58&I z$#KunFJkwpt6q~B?-{$5_|TISF~dW>rrnTtL6CGus$Meo`{3vnBmd1qt)~yy|6P{~ zGDZEdQPRHMyOlF@tQz*p%fG>?;tiI=a5n)E$sk-JzTF39z17+pzGg6?z$6zQEhS1) zYGXx2hn=u8d5q#XDyDjnkeU&fMU|QfB`jaI42w=r^d@R12T7V@2&oMKmIfEJ668hq zY^QH&&8J|JfpE6&UosyeJ=m~sBoH9Vq-1wXDJTeOg=Ss)srY0s)-ri*}-?4B8 z*@W+;Z*h`u*Ig5;Dy@R5O6zWq*Kjxs{TDsCEcU!RG)C@uU36~(>J0Bv-F4@jSN2ygCY$cNAM7r`FXufgKG2Cq}u1@a1L~-4tFbax|RQ$zDjB@L`G4 zsfEJK*nqBZxbmP<+ccIkAEG65-}9ZT935x1pZhjO9fw^F(B7S^-;@)YK+b_m-Cto4^IDz!i)mbpyz{JClt^eDuy*CZ0j-3u z*!G98lDIzP!2`H!?`)(K#`FzHQ!@E?&;=tEb#)&?4?oDVy-~}}Uade^0rt#$tD#E3 zM+f+gkp)I?2OkC7PR*rV*k!A6*KN+-pX;}5-YaZRz50BAYfs6!em5v6C+53$PRG5x zCnn}zE6lBzr9?}`a7De3)Um$8#r65>8dCI^@c86=jZ;OA;p6$89{c?{_TJ1%shSzu zhaI|aXQrA>!|(S#upf}{5B03&6)zZWjo#WGgZtIk9}xhWSzc|9_d-d7siecA%sY!T z)YhjF=m-kH6wf(Cw;<5Hp~f4hppNT~hVRSWNmm^V*14-5d%JYVu+d^PQK z=@`gCc3zclwAKq*w14h08~ptH__?}C8Mmp4H4XNi3jH5*9332LtD|&o>=)1%8h+V+ zA+vd^GHEE!DfZrzs@d7_NEsRS1Ae}hH&cd-*9b~7&#gbWkQD9K_^f~IwDGY;`F3hb zgk~-Cu^GbAn2BWP?9xz4UWud6EJj^~E#803^T@Rdxaxc{`=ZN%2cq^?0W1c`j!myS zcgt^^K|wA>>A;%WLH* zh}nAP6@f;4Tr6OivV6I__-Jl|X7W{x($l7wHT0&^pzo+{yf`}b*E)o+Ub%`85@_Wep&2-+CB1Cc;2bj zuGE!kl=d1N*&oG@5{m)hK%>md`{tqWIi!NRBsU`~?^}I`+$Q5@XV}qRRX%DuY&muv z9AR&_B})s68q=hmL*AQy`OvmY(Y2zv@Tl_bD*x2_gaVU1r&IUtQ64?&QwpEdwYqe` z+8C~kB@E}M$2Z1!^M7(HI&di8V6;awCB<)lG-o1B+$B}V@uyD@c;yXdi{25MO1cnf zwoNQ!gMo&`>Ygq$R*4HfL&g}w`TML+)ysNjR^Ti(ZF@fAURVA_ZkesaVLENm{WrvH zjG2S8nJ(Q|5hbZv&jSh63K=EZ5vTeW0Njw5U`>Rn_jzO2e8_tnnielMtdf{}d*$N@ zua^DJ(pc4adL1htvj5V` zqRsnuHU9ahqT7**I~HTRcaRFQ7eigFHq;&V>OhL_O!)hY)5TiG6N%d_6V&7FW{*7! zG?uz~?V6jL>!Ip>s<>aip0_u6bn}kEJ!w;wx90tG^XK5;}k2FsHkn=Gcv@dO?Oa%RL|5P)u;& zZ(rB9s+EqEJY!NA=tsJPcjaW5m_8pMU&o%>@{4JrQwMz3bHo0)Vp8?E zvA(}P?X*03STBnvr14Ts&0oSbJV0u&c>K~bD`8+U?#4SdddTX@%xT;IgYGQRpcxJvczmk@N`!nmniyB+Yt5V}@_eb#ypZOM1 zvor75@uliKl=03&;iu0rf%Da|T z{*8sPV@Y{V&-laY3DqB0SZPNcsLn?Xm9u>49f>p`9AbG2wxAHeMU88VN8FI?e0)^J zS*kOoDZcf~g$bXFY14);GE|XBIodjV89y{Oo($dp;@ze&EXd-1$=BI1HIlDo**0)E z!kZFeG_XC_VXBk;m2Xq}g|PP%ZNlEwJ-Eu^1d+$J5rOPR?%mOy#pfk|i@8u(E3_dj zSermLNa?L`GgQ9Y#iv*BTwD3zDrMno+7rg{wq)~m_eHl4vYBRIjQEh(*^U(rF*i+pb*4tRAbl4U$x- zH?o?Y6EV02j^BDiF)c!=fMoyqdALGo?yN)l5v>pBIkyNsn+e%N0NP4&~8 z&Xi`GB1V2a@y?GENmw{5CfWeku_IazvyNHWI{S>2l(No!keF<%^uGGyWcR6)$4SGX zVG+Axi^FEDs|1T!wn@y=BUlCP%Nw;;_bu6_!0anN-dk^w8c@Th>F~U%NvGB^$t>(yvav@H6_f%hu!;iaF-cL+;h^Bh;8X^>*-9TteiTWq?R*EMo z38)8iv$LTxmEVX;^3Nn;jBt51lSJ&=z2Itf^QO##Ioj9p@sPrH0jKmo{_whWOTWO` z5u`1wLD;l;b2ePCO~Wt6pvuKA$D2D0^dBW?X5J3}xc0ZN%=>of_V2{pn18^-l9DiF z{ZVqu7E7DKUAj|z-`O;+7}p%Iq0h|`^(A8p;yTvwEJR>1#A&nWw~ohbtfSqP?pd+N zZ!)yrH?D%&t*L7u$?-_VGds$m^FnF%nHCzM!ovnLDp&s>W$ztG_5S~XcW>)9wNMd7 z5|J`JA3nczR#i5{oL>G_xtM(&hdV~ z=5ss-K*%|b=5|cp8fXr1q1xBPl=b!!c!muXQ9)$(;6Xx0NG?CvvOtIP3q&iT4beeu zzt%Y+)5C8gUQ}A3GY%AR9|e5oB_O=QsWKZ6M&ghdMfH18P)nXWN=_bAm_VKYWwUxy z&^=;gU^rauxHNNkH$M#7?a-?>$zNk)WBGeDPx#2ovk4utFr~TwB3>JR{h5@($~3I*CC2v1Wi%L#$@NefjcXoLB^+ zwIahUL_}wfoxRrNAMyD%f%ovCRCSNwV6GL(IX^K;Nq@z`8v9GHpR)^B9mD8^Ja-co zKr2=usQG~NsA`u*LV5TFK#}?m!cdW|F9b0^bv3mT;Zl##!Kz2PeOhxaG|kYutv0aTT7wf@ zvm*4Wnc-k9BDoNFu7-8hix^@Bi3F|PE#CD3`>m%Wu?8daZBQ-+ua>z~aFWA# zypvx&nI=)pudIj9u6@pjeeCW^2ZL}|+WLocxW)vNwx^P>Srb2>I<)i8uxmE7-&b&u zf3%)|;?*SBx$h;&5V&L6KwC=|n{GS{vKPo)?$_$~jQS)LFIqCJv4l4q0@TAt}#;AD%vT*k$J+d}kpc z1cj{uE&+xtzFAqEdbQ(x&S$PNGUl6hwqa+7Nhga-9qTDdP1*FkPjMK^tS(tOIPzLd zv+~_u2u!yWfJU}7pZZ%Rbe6$U8q+Aqh7&KK^lCyuESe3@#1GddQmhjXtDcjlVpKG0 z&LBOdnm*?^^jwQ8_0VCQQ`vLbVOq~*@q|AEF(a$f7wn&00jC*mFQitm1 z=&R=UuU@|Dx;8T>GRmn{vTe3i(=oH|z4^Z83;jZ%;^@wFq^lhZaJ8Jc;A z6FUu;0lDVr@b~W)r@2-?ku0B$`xTQd2GM@}Sjfjm1y@N(y5miw65*^)Q77tDAtlLugux| zYT#^VRYEc9yqcOmSDix}SBIBiS2#}B_;MJv4X@HT;z6t>%35u=|zSFX5{wYh#AT zxiDB=DH)#q)?=U6R!019dxx-zy}7ZPp<9)YH-r^A@;C++ zIPmh&2Gix3qtF&mey<;$o6s}nx@a92Axf=wvxX7L-DAkwT|puJzV=yb3+Iq zdlq1LIcC~1!PV2`pI->Z$S0z%31A!iy$x2S^yA!z4wQ&G=h{s4jdcnN8tN&T&E*|k z@TwL60U8)FM}+iRFKH4AUZA}4umdjPmd6Y&pFlMj5Ok29b#`=gIj=jW(m~~bhbMnd z01C=*)rh={o{q&@)^%C+49x$E9hW=@b&g`Nvt#W^Dw*+c2ED|0WL{Os*V%|p*>9R~ z>C5ode&5zq#YN(%nm_}2wL%P;uQg5K8SVV z_MDC|x(kqR(7vhTnU;iZBZx3UyXns;iyv};)<8e}N^k8R8=Ju_69FGm6PELzp?dbU zxL9b({IfF+Dn*@tp;2zO)D+&#Ka?pDZmhXcb^2PJyLZnx?sNJTpl08Lt1({+qtc_E zl3%adHr3Lph1*SxKacPpD+mbnl+QM^b_#xT#AYs!w`j!<# z^kAi%+Z=2Sam_9+A+$#`oWyWQHpKW0cP=l&?IzC{pvVfldt@Q{tnT?k0;@UpDPJoq zH7FI0^$@xxWH~Sh#D>sH%i{s17A{kVAAY`|P(9rKAT`+6_j=a4AljR9(L&~hj~&P9 z4@RF~tuK3^uiuRh(`<0&6&zKBC~n-e*ma)d;6-(`c=zQXmA108sqG!Ma&&YpIhIDL zDhY~SHofP7K4WjsaZSP^;ZPC!Ax)D!mMTkemt7co5kuwCJ zx}9Sf3Z~Q#GGVRM1TV&i88-63i^oc@j+m9VWgSS;EUK-P(=@UYv$XxVJGG}^*x(t+ zvy+`X`J;?NKDJ$oo=Z9heGU3GPVaTHNw zPZyjInS3NS6eZvKY*+Muc(yg5C*q@|gXdn4y25t)l}Ho(b8YoeFg(H&IZHN+k{JGQeju z86b((hBjWC7*y2Y!{&4Z!d%M@x?>oCz}I28GA#$2p;QX#{E4>r_i>*|{JNX$Ca$KJ zO|)U+bLgDL{Yxdfnmb-DIDM{FkCVRL1b(>QRHwYskcjK!^M8lyFRp$lt zBHLtLw1K;<4x<%G;?t%F;~@8F{n0fvqbxe`z%)S*57D8mI0aE2^L=I>+Zm5qV#N-J zj><$zbhJ>SyO`9qo>%gv4DwW95)BAo{LUSioi>WMx+aFs&E;Hz%8QF&4Eh7>Jiu1) z@~4T3DDfyj+K4hQ@Nal*V*>(oYJ#)ClGLcVki~I3@9&|aidkh<*XeP$-T_HQD?;fE z>h!OdWMxD|>^ns`Lf8#DqHnrA0F?I=E1^M~?ui2=W=aLQ0SQJCH-{>79RZcMh%IG{ z!Yt4G9Mkhhj!M|n9Jge(wFklN$2}V)sNQhrsWPKjG^!3eI_Wh(n4$Y^-`Z?r9L$uF zmzS>umS1|__P_H(o!4G(&lyrm9ssEoShXX)y}qHoX$-u|Oi!OKbmuv%jHpBLsq`i& z@MDmqq|m%+c)p~pm%i{wwdUAuxhU}fU_8U~?%vl8hp6qO;anj*II~NgI@Z?^B@vSU zMDzKHqhsIh#Iz6owOvEMGdJh!TCbPDx}96&BaH$Ymjfeuku>IH0pg^mPQiSXLb*W< zJKa21-18iR%FLY}6#L^PP=CQoTmsd6&>E~di^?qA6`JlG@xJ}0l)ImzAKx2hMayYc zv~%=t;S7cI;;g>cNlv+#gXGn)h~ca2#~z+VrD#;ArzZ@KjF=DB`5EGJATmPV`8_hq zTv{<0-VFjn{9RWvmLhgcmc@j|7lBwsPd=6cf@`Blnp8^&-fB{kNlvw;+$#@++FQ0M zb(uQSvbp1g7%@Cd{dZb*$@eCSFC15@dOA9=wWQcq9Re9q{Hoca9b;5H8Oka(HPwd_ zfcT3W$&v~h-Fx7GOq@JKm(3MrX9P4X&>2Nm%lF}xE-2Nookf*CzT$hOQ`O8%)>A5u ze|)@lGtN;AbIv!f`1GmAPnsOi!a4(=Q=jY-D)@1Od{X#oo}JAEDMg&4T=U(w8s8;`Mqdac8tn%O4yF#beI6}iMSPbu2@?N9{gE-p>@V07lnm4#Ar zP5BhSWM=|ILU(DA{VZzt0XU53;VK`u=GX8$pOmb|A)P3$N#D|5BBAA~Q$2XR^}T(a zp4M!Cko|2{r6MRN&|>8>fP(-MG)>LT!qe_jNxeq1${7%H+RZsAQWpLA(F_TdOnS5l ztoZN6%M>Z1O2}P1CBec=@11UB!#I8fXE2Uze`M%43ulY}+09WV-UWtJ;o<>|TC*c&e3vzRlkvwAewErfSw0clHziPTnW_QJ1G;0-hvl9A z%m&`5N3I?tCtqG#0*Dp3`U`4>qj;MUx3q^N#wQbm4$|?K4l^cqK^m+%bc- zA&g0oBT2g+WG;bINFm#F>^aLV^s+-A-nr!9QToDj1$0bIKjLDBy9<<MQtkVPy}(xASZYwQE~*ePy{NDvlK5w`|0 ztjI_~CTPAv6jb3$t7Quv>>k~u*jWAEvfXlDK=&`sY@yT;7zE}3=_i8^Fr@N8n-qpx zqCK-P_u{+M)Yn(cwW1CqXt=>zy||jU`bsJN>g$s)&Lq&y@t9kAjFKL=G6Z{{dh`tQ|_`l7Wu{^naPhiwqlMFN1d(Kxsf5%WVwu zq%!E_*M9zN+%{7r_hn&W0Z?}eZS-_>QGg3z42TD&RnKWdT%0Y4>fScLXuu6Js07#{ z4If`2>>MVh(Eue4hKWRE7nt%y4f!0xu>VmTgtB75cNHLmgQNo4K44vQgEI#$h8=90 zAo*0GKwyh`xPL&r0Yq=HBzyMkfhh0=O0EmM7Ca;Y6HC=gvVI0d2nFSJ5k-`L$Jh`` z-lP=m#yGQn#$0XregPtwhyT|d z0OGGmys0|b@;477^aajaQS&`es~|?cTQ3XvMJRJYU@9}I&x;%C?QH;Wtn6+lRXePo ze9nu*7>8t7Yqjgp2mXD8h;_tQLH+yx`RBfs6^JWL0P&eU#*tp(qV{XO4P}y!%UjC> z0)SL&xe*tur{3c5)KC6nzKl2CpW@H(^2JU-_tN-*7`zehC$V@WFh|zkrl>apZu`jd zwa9rLRxF@>L`jL80g3%!jUu~k+kNI2jBx~=aF4_P-uwdF$XQzcjElF7(ZAQfNqiB*)ZwH8(zSKmej^Yvwx~x9l zH#i6fth=+=5jYv|Sf2-@H^hTvQ!(#_Z-*Gj*Gx~}i#FH-1KsSje3nMOpuD_%_wLP1HMF=idKVzi za&ov)s3}2ur>B=5iSF4nBnGJWYc{0zFMpG}1e}wmA>82wk=b4QkAH(!^YF08NQuv( zbB7qN6ITR`EP)Gxph6vGCRF5<5m8X0Mi zm8A_uW~}tqcWHto;Q7BcPgKSmXhXi5HbA$|nxT7;0xaQHBW$nJs2bAQ?V+D@!CRVe z8xnTtUpRv~Z9To+J9Yqs7VHxJNG=ej9~J>}X6~>&f)NjS9@}UKW1b4mRgkkz+6D~j z`E0CSMlZbf$sKeAgIQ!Wswy|{L|68|5-k2lI&7e5Dsv9;H+?D=xg+Y$mYJo#i3W!? z%SSnPy&aPi&)YIBP%^ST5?AD)?iD{&onFUxHR1+XG>+_-Vchb0;AjvSRxu}tZ-qSh zc~Zjh1s;92fRKGQASN&0cw^%vws6z={t56OU-!~MKY`4DFJh!~_Xxvv2IgWYffGKc zJbvDUbB}J_&yNT_hI<3I+r@mX6-D*W1{&^!k=ey*9jLpu0kPTldJ5d0>G#)>nq(Q7Kz^S2q0ntf&FLH}% zb0~yd0;JJZV}wv)GcnzW{eC_WwBCwQCqZW;62_EfX-?x7{d+RX`=;_0$U&(x8 zmUYX4MzDgDJpJ?MixmXVTjGgV^&DtqKmWj=LnD_3B3h8G&Vlg{)sDA5AP80mLldhX z3Y;K-;=4J!e|jMJ;{mtx8V_L{4`Fl#pm4Ch6B*NOC?>V{hc*JU^l<1(_L#i~x3{{# z7S>N(y7O?s7)-s-lYxx~cBnb29Xyswiv;iT&^%C^8ExGR=-BRoHadI`Jd0L#{8$HH zKi$bza6;;5h3)ZrWm{CDQ-oaT;g7vqA0O}3Jx#P~+yY=kI+KcNaF)T5FD|(IS&CMsK(RE4MKjqUc*12DX}cei>(6&sf<^>F z+5fZyj_p$2^8z@A>^f4ypc5O&@-+l$3?C*G_ymhg25CZi*~s6Jd@IgwZdAEaFa}%| zb3eej=S{`C1okGR^?tyfa_56;4RoR5NV*oe;~Dk`~^;2@dK>V{a+28h#jO@S%>P@#&948WjSz{0*IUSVV?CQM2~!Y?b^u&JuJxOcja zA3OqeKtKb`(;mzYD-1<}u+%Ib*Bb{VLdXTd4S0#Ej&C{fE6qWK6`_`kjx#QwoSh|I z*35q(%LF-@0uw|jCt5X?(4i8d>PIl zorH*4kd@Rz>IL#t0OtoiAjA|}R~@_#prEA;kngVm)@{NH?Ne1%O%pkM(CKG&$_B5h}NMa7|N za0WkG-6JKiRJ#m9(nafQ_7V~j2GqDQkb}CYS=dorERYYT*}^rJ?s8yc;*N)BI%{G( z*Qy5@FvClEPboROwcCfd%zBvMs_f~aY9ick_rd4r^LIE_v*@bA^RP+O8KW zW2IzJ+=2)mfz|hepV`eb`aR~)J*5hkDVDsXpc~Gtnst1lt0_Urs4@1gk&%6WRRE}9 zd1Q;Ks~0-tfX9Rp-+UW*a;BPt&T{bJ(zhohkxf4QYqt}dlhv2Yshy7jv`VV+7$$0N zC5+8#Se^;Onu;$ymE!0sHl%<9hYRcpgLph*-Z--z^YTeU<~>Ml>W5(-o5bZUEWrg} zSo4klj;L>b(tNUYMvXvX@g!#vFZUg|@)A5(nvXp`M^z5Z;EbYVyrh&Au+EwtB7DaI zf}n0JEhZLsD+)?GawTbB>mx)+Y;0^QWj!*Yid9rphCQU>F3xTbM@Wdv6v!i{@>FvJ zoh})!=FPAf9uUqQ6&w^?FN1-LK_FF95UduaEKuu)xw?wGiF#9LkT0ox%3BVGz`DI zeFU#s(cIM3G;juS?@j@+G3g~vJE%^bJqiWD0~DNY3ZQsyU(M4?a& z3bw-9n`M%>N}eCXkE10lF`|0Kfe{gvwY@$-SeU7@RvBg44NaRITrXnoZz zwIfo@4;-tG4{3mu7djBJ^N}MFOMr7k!Lt^Kf1W!*J0-OPHn#aSb)4P|>=$Zb=K-HE(hEk_ z&q-45+qZ9Tm1GciJ8)U9uT%DLEV&+ORswz+TE z>Un2|fuExK5#WZ@_r`()2(Wa>_Q4uwPaV81^-L}Q=^lu_JgSJ%mlQ8jM>3T6S7adq z#ry@B(nv8t=n4=<$8!U48AKDN!B*MGgxr-Egm8w+a~u|@KndL{Tl4+>?@(oZNyjv8 z4lcJAaGr^vQrvkA=g&%o^1y;y1<&_#A8IZQ??`28`?}YTu@*o7yo}3c`H7&}wi%bx zpsFvT!Yw|G3M?E(0*x)+WY@>ef}2me7e4VU7SRd{x$Y}Uy)CpKNtt|)93uu%(5odN zSq16COa%3yB>PtT-J306_4yW&`@AJ2*?$?_XD7Kj-d=xlE4bMf@@qT37q>jg8A=cf>P=#2$Vz$0$NPsm4L-M~LK5?AEkkZ2k9 z!c>I){Ge{_^UK|w`Z7gNpFWsOQC6DVLBr|^CsRA5A+#v!?SEF31?eM5_EQsr(AQ6& zzA9QD-0yYHb#6S*&vpM|_Gk4NTen&y;OKnJ_^%l75XM6&YxCn!l+2*-E{U0J>6Xf0 zL9AIdh0zu<;ssmk3XtvG*I#Ixxjz@wxBo?R}g-E48DA3 zxJe=u{E2?y-Vl`nunm3(-m*yk0<~XV@KPEJ()20%aU*hnQE{!d;JN@2x-H)vzj$2f zF@i(IRpOC{fyL`4b@HYuR?Y(KU}nJ0U>6}C{J;a|)_@E`M*M=!1|g>*J81D?Mw+`+ z=1Bhi?@+1xHU8U_J!?zm?*XrXv9FPc+zcr!_`EwZKpE{ZSB~jxhKa@F8DFFF_Gp zSBmuY6%6OsFWNTt@+2#|6w{#ko3-whdyqtS!5qrLrUyQRC!T!|;4d~Jc#+qs5JY4B zHgk$Y7!{=H0=jQdl-$36X3entWU9_oU$|B#pt}LO!(r6jqC$GrVScsi#}DhK1l62e z&Ne^+ozjyS@PM`-6LSJLcWW5WZ05LmNnk}qZ4bJBP0RLAE{k}3-J4D@bEhyG8Sd)3 zsbQa#@*pKpwuyHX=ti=#-@&n(EJ-QFjr!tv!w8-0fe|k43JEwb04??&m_oUQ^h`ky zaa}m;(O7MT>C4GGka{*$Wv-(c$y&WPa-FFAIBt5UDVL0>a*r%%@U;PZLX2bAjt9K! zD{KJbNl~k5QYo-mN6WmB4!USEbT%RsbSKQ>9I%Ua>YfV=F8s>~SQf+Q| zPFYond|%J2o`($8J&}$t<$BOUG0k@^=gf{RyYWUfMUv=wHg)9h2PPCi-!dF#zH+A4 zmEEK^w66SO9%)B^^JKjJhj4*qtI@Blm%c0ml3+MxdZgx&3%)P#x!nl@c_5k+;PF7O z{I>uKw`X(PtW0|pXwe+>@}ozocZDrf*u zJ4jQ`POa=@JB!P4Dn4TV^oc8H$VF7tT5R`A1gcnS{(L2JK-0!E0pbV8rSmmoF5a{z z-7j-)%s&Kpaft*#44XQVx&B{9^B4vQaUMl~A#Kj;2|CG!W0>JV>P*EbddeW?u!svW z0H>N-TmmIV&W32OFZOS42@OK4k1@b-R%Fj`ST8i-np_Edl);~vLIj^di=F=A%Tme* z(D3FCQ~VXI`_4)a!&CSBDuOiahPZK-ha)B__1*r>n|X@Yo&gJW!dV!j+YVcGZI@`B zXluHSdV5wlMEcpzd^A}klwZ>gUmCIDl46Uv6O4Z{vVLM52fw-*5Rmruj*!D7`T7EYGs+3b76TwROP+Jb`1z@3X? zsivrcHGz~iVvQmACqVoB8BpuFs*txBP3m1sQsL%<%y|K&!$MAWUOB-N|Ep8h~71KsJ;_<(@^^t!A9v~3aEA&CpNyVr?n&78QL z{BKWgn;Xum2|%fA-+==UdcDr1rbYlH6wUmq`7S_k0cpH8at09F&s?*IF;)eDB!NRf zkRAfO*IAdvvMF4=(qxRe9^*8~V@z{X83 z1D+CwfbChcn*S)-19OArPN~hAR<7UQo11`j=Z$iuX&Q?O**TnTRfyGz zE)JGY&d*cwqS|K0bofpmAXJt>&KDPBSala9QlN?P4%s3|NC=fnWJCe;=Yo$sgR1`f z&ql_UK%rK=0~tm-0w+c09O*@r4m7wRVM+zoaGIs@C>~Hh08s&EL9s$Yw;Y(u{h!2y zvTjrTb>`O>+A{a0XCw~vX**9fwhTY{9L#&YfCmO1kPW(K-KWo2=#{q^MU7!e)N?aZ zvy#WhI{PwPmY@OGxt=H3B5{zSSvs37xUgQP{MQu;CB@Q@Kkvv4ecUKe54_~B|GxO{ zVjH@<(*bf)>@vITu-c;s#*_xiV}qLB;_V8I3P1o3{7eeB&)F+qTYkHzifq<1!m|Nx zk!a(b3i@PSfcdU-%0?d4tc$Uc)K@FVP{9)-&lnR)yQQJG%}D?l>G1*(NI`xFTXyma zr%}O`_X`a|DR_2yPqc%;spSz<^K{)pNO8m*_@nU)a{%!u35D|@*YOHaK8cqb!zn>C zQdk8@5CzKy38G0Eh&U!6s`hhhXTQE55-_kwaQgPOYhGIR7UFL*f@i)Prvg0vE`H2q zu4vuHJtD$U)NLIIC<5Jw$gBULX{Npa>?h?JomOX(^WMgy=#%k6sKRjXv1+lS`v7v- z#QTj1xIb|m?>I7d*B~OCQGc_%N{H?lZ=vJqdVgIkNn>G2s%O{auWUuhYvIR)=iuTU zfD20zfHY{}2x#EqG(wB+xBybjo`XbR5PdSGRHi&~OqEp$PxYlfE%<=}@Fs)XXBA-< z75D#lFnW zMr9 zGJfEm+8%@(2@Ziz@bXM)ryTDr5O*?k>CMkOS7(mwhHD@(DM2&eKZ5Q6tk6$D1puzx zJ)w3uU{$mB1GZFFx+P-ST3~s7&K{T6Z&{0}J970Zf!6pz5J&@_WHqB>6p~?l@ir5K zMvd=eVW`$}RVk0-0mwK%8C(L)c865k)|8@Caz&H1Vf3^#Z7qog7aUc)Wsns_ zs45Z>e+Wq(>qlV>Pl|NGVE#DG#`W}+q~YF3R%bK0_cDW*04UO*H6;R>)@NV5JstL` zSk@_Nm>b5&@0NcWMQR#;jl@xrjm?#@?OSf(z&87E{`E|_P%`pt*y;Olx< zXN{e3LSh)V*50@LmBxEy7#*@(>p#Y#vjH87Z%*oMj4Lkw^f#bz*)tC#D!2qSY(ma$ zaqJ|xZl6J&_&M!yO@T~~^p+!4to!1e7pxoFowJfc7w6uC&OC#hi;j-jwVfL{owxdo zYUnDM3&>`*goqHHjd~doB60EnVZ(2jgj}OLf^nZHkJO7?@jFG;;vV|L{BuF&rQN?B z4$@NSasGE=>@}5NVkA%KI%J`Huks`xea&aTe2?2ZhpUD%1KX@3gkAE3BSMQ~gTy9%&7L>)C=Narva(tvf$omAfly8CwBNf}rAL4C zjsS&;KrsYkw0y@lvrV`I!HE3cJrR-YZ1;vH-CL|vo8Lf zQ%}<`H32(?e2KPc;B)~qKo{2OD6RDZ5IB-fN%BwhRSI~$5oM}#uYeR*l}0JEq!UdX=FyZQ=_ZwGxMcNLfGwq`U-pYBBvbuV-0lSw z;)3FYl(`dJX(Wlnx*wv;qTKpINg*o$l_sTAN-^ypZqtWUXU4jK!Ycg++CoD3KS~4&-v4>B4|tqX-{3vlAlQ2)EhXDDum5CvN#yV{UXGv-!OS*7>~ngeNV|N1-?ad zf)f4Y>hV-nAY%Zm)@b~P=pe79b$0ksv1)|`74%pepUJ)Y2I<|Irk!fW$6}_ZjfVUC zLvyV9fxrpU0i|K6Tx@z{uRf=_Bp`EvBErAi8G1@HrNA~p#@JyQ!zEY;c;%zj2nZM? z>81nwUA%SAlUX(7J<-Rm|HimmFIbL=N_S(Mo1k9ocUI&wsK1?m8DNY+>=8r+9U84( zr}_9lQEXI6=!t}o6E6SCs|%&CF5>_W*TZbbHC(gz&z{+qeJj7{QG5LfHnKmWJjQ}ea@)l%yKSN^)t2eq44Q#~k` zi{2^CZGL*zv(y5ZIbB|M|Mzk!#L6+}zy+WNXmyMc;Mi+P>HDd>ihyiyuo&TUbXHtaZtgN@;)c4J zPj2LW^o!?b`o)9-{fvYCW;xcYchG46OsiSXAPYoHqv!xszknFll4TMLmHinj|Ht**Klhyo|pD~OsWy6ReD??&8;doIxh8S_tp z118*EdV2d=NT=`h4M?=ci&p0KEdGXeSB`D zX0mm;T`|(xU%ou#>N9einydz9E;)yQMAmm#%R-G*l!PdOGEIzXcvJJz$ zX#=>KGHmP2xQxuJp}`jUw&Tb8)-VZHJzLgQyNuS0B7%rK+i;Xq@k>1u(&Y9>F=IVA{zQ-wrVw5EMiwBz){N zdg)oa+A;u|I?2+Wctr(CO>dgpZ%x7Q-89)(&zobDsc5JtggjNsc0KE&)=>Hcc2<%F#Zh1aD4f9y94mtaU|(7ms3@_6b-w zJ@RS9(lEpzWhEu2QKX*6BGgbagB0=Bdwe7gN&FC!2uMIi7Dm= zAjrb)w~8B5l7=u&D&Ri~TUF>T2g}hn3$IwSUk$C}$JX<2hF!jR=5F*twpQMm1j!j; z`8~l4dB<=DjQ{=qj}~>WfG9204;O+YpNs6MI)bzb-b(%qskT*6pYV{fMPyar2gGh4 z{0kwNBBU)F1p)v&ZX{M4aTcK>@IUY(TeAL3-TPldMIBr*1Q0-~u#my8SdvEd-?_kN zIstf=97hDCyE&+D4H2e4V48^GE#P9dh?^1yeX147_kY#~w!j0bx4=ztl{IGo$AWaF zwA~2kRq7M}UH<+zZiG-{y0%s!^IOA~&|}#qIM{m^daD8)x4~6xB&CQ?o*EQ>wFW_z zFs|Far({p6Bk&}U#{HH>?pEs&X%6g@lN=r^nxNG974#1cl#R2&{i$eXEW6tS1NA(* zS$oh0F74I@H82EHiBMQKCIq^%@9>T2py2$49#81^30ot>K>gSM`BLmDm2U9)T6)3% z9}`0Rn%%VHJ*Wg*QiGQLr&~gLGBPrw>#WewLK38_3V)Q82M!VT$LaHeG0?0iC~#bM z1@=;eJZ=b&|2peD1bQtHjEPZ`zzr#X;f}?AiKss=RSx52)c`E3x5&CGSowd)SyuLtl$JyZ9$jEXmb{Ynr zAfT{yoEh1Fb?7%H9QMM`PTXd73`TX&e;0}F6rKof(H4Y7FnE*(0rEy*Gk$G+-=u%F zAa)MC4Bsyl)4`{NEF8pcX%p>-ECgct8^B-NaLR#_l#C~d+jA?z{t)ITa?4F>x^@R) z7i|E%{h#0gEB~v6MF0&hdV;R`e>H^uuN|RyWn*n`;50YzeaK>kKZ=xTf1WFZAHn}X zsx?l(2tTSQzL=t_i_QS3mm?l+!L;+->cvOCNq5MtZcbBwV0b zD$EKHhOdBl$j{HGq@)Bmbafnvmm}juR3VC{gkil6HN%bL{BJ?M9PO8ZfnEiONd~~r zExiFqrHuzXjiQ!5r{Z&e?=BK5Kyu1<1tNptup#%!K7xWxxD{NEOL=&Bkssw~|0ghQvt|n|US!Na z?iU)&b>>Zqm6cWbl|fc0qCMXK*H;2(9BID#!{#LfK_470=MhdxPSb`oZC%9Va|W;XvIvh051 zf{;1~@&{>9dk`QZ@-yTM2z!2U0VrUbz|cQahtFIaYzSoP`e-)l(%bq-q~W`MAqL=w z$ZKt)LkZ(SeB&bs_+aCeiQt0iNdUQTE^Gpa|MzJo+I}I2VucX8Do}(JV?Q^_z{tpG zl?}@Ops%iP%5d>w7l?N+v{d8)@00_OM!S&L>SICmpEyjoXt&`Ebp3hy_ITC;aRQ+s z+SxV7$M14+q=4)pa9|01>dP+e&19czVX+r zoxg!@2B0!C^B8<50NxIqU=?HnsV}`uqZZDLb^y|Fnsxw}B%A@InrTSa`P!`ky3BhB zvqL;I;M+c|2oA#aK90xVhCc$wgJ%?N!7hN@*>pQ9*?E3-2IcwSa%wQ5@bQtBl9DnuHU=>{ub|Pfu_Q7Kz0{j` zSy_CD0vI0}F9VT9M&XBxYu;#Z3I^dhkPU9arb9;xKB%Se@}1psG$|9j6*9YTPyY@% z3fznIFUO8JpRHLAS_h!`L25pxEI_f!*|Db~l(#5g+|2+i2Y`$a>eNRBL#;Y1Ev*V% z5J8LVD)>6CC8QMEP1kUhmI3}01fboY!9Z2Mh}Xe3+n0M$04DRoX`f5jU;$33Fx%SctUv7j42C8N7 z_7Doopg|0}9_0B-ONCZ2XH5?818xvxs_@sxni5)&r=q?ElrR9%rDkM|&K?36(kO`_ zahh98vJ#bM07|-L@k~Wiy~S|?bd|xOp`-}%phu4$+06r^dnm4Qbkuk<5R4)grw2hc zUY~TTjKU0zD?HAEMt3fH=$4w=N*H+1=IsiervgrJgEW8B%8lIE8*=DmXvKrab-lE= zp_A1rkO2W=c@mJ9_^!#`a;xQN3S;2Rw$Ub||} zQvo*^{Mg=bTh5F}(4lsox@tYzUE~a0%Wg2Ss_6~8Vtyl^3kwz*3#gfzP^5@VG|i_91U19hR_ZoIfa_3;p%ql2T~^BPeJTH zLc~X$hLw|3F%h7oGl($nkINVk<`u4B{D;OsYmd9=i$md1$QNZ+kRVs($;cv8Hx9U! z`}Jgel8P2fFyonKKL2=TZ1Y!-uMyUn3Stzv^@*`n=K+jOmZUNFYtZFgT!4|NbsX=W z=ZmOqVzW$OF|Ym(m8GSX>AC}TT6T%Xl>AQlpw;*N)3YWCi7^Tf1Si!L25|F}S^zXLDlYfXa)XutHqCR*IScd z-v-WICdB{>07&-$5M^T)T*J^S>;O}0y~yo>!(Ki<_4vr7)Xmqw(g%<;LY0eH4IMTp)Cc`3;d2AnKSZv2IfbzVc_WlRF zBGait02hypsY1kk%XiPB03>}wKp^wAOW^V@ShU{fP?Li?*(@$dY4QE*EgkdiHsha3}(+4UE0sA3aQ zcim}&(L#s-lH8DDOxDYABupKbgqM4mHS!f@|D zs*h7<8&00c$Ml8JhJ;ScHht<)LO_Dd-9|iu#9y0&@ms$A>@oNi!p}B-Rd6t3@aW)u z*OR0o2|*j`8fVCAJfz(B;fCJnTW`WtDp*b!%AgI$a&MqfSp0JzADdWN^DRjeE)j9t z6F{Swf`7IXrzBiX9>b{Q{r@W=SeVelCHUb0Cy@mtO# zG+ek8_bUSyO2@J>Fzng-BC$Mu(01^t=0{I-@tR%z0{8jC!h=OW$wZMI!h%9VaKJT~ z67-_4oU^@%;virLPD_JiP~Q6d9x}4P@?3|NN_#+N*lz=Adt|nevyw2HUN0ndRGXP^z_yaVF2@c&}!eX{;y&VRvCAKoZJaozNG#so|6B}MO)>^ z0jJ^>4~(~S%^l`6l6cZ^M7WZlCvAe-Su1qpQ)!q)(A@0wG_z;Wbxotzr(9HiICE-MonsE z)`xzpAPNi&l_c*mb-01a9$AoxRG6H=uAfwk`bQ!F^n7yh1PNw^)xf7v4^#(W&C$ zu&<3VTo$1&0-Gi)a`M3+KVDEb*ECG5tSy^ab(Q?3l+(%eP~4dqDKpcyjKYKjiEGz}qADA-CE5y`&YXGFOTV%n{<`Q}x|>^- zQu278ft*IB5!!eZBzTr>|EHNvpkVT7sI?7L-Oy+)YBWT^YrZVVI z(1?y`CZSZLUH8&RLl3V@g;^|r_!92O!^=B!wY-G=-Ku9_v}=e*t=SQN;M3Q#$Z25dhsl{u_ z3|TV~nzyo9e02l-{dKAuefs;oG1b}yHWS|8zn_VgHIumc(oxvwLq>bmf%B8Lh zg{se4#*1o|FEv2;#-J%a^?U91-E$SGJGndR>gZY1hU>1rJW$kbnv0W1SMeQjV}dq* zEohlBk3j2-EmPF>Fy!N+2K2O{!wfvJ){(b>R&P#E=Q&a2a{p~Q3eHUOF9h$ z&ny;Nrppq7(sh0Of*9IgS~y@Wm!9K<+b49WJ-w6356iZ~@nb(9)F^BqZmn3)T~5|W z`=*;Y_$+h&yoT8b1yT+hmyi1ug}{#9MEo@J3F+zUe;Mb!z@phoO3_|cQ#0GK*a)Xa zAAfUY^$|`JjpL*W4V9Hc14*mV(P@^0R>Oijb_U2z z?^Hg58P?-^@}xRN`Kr>Ke}q(6D^0t|bBF5oyoHp(EJweEoVAf3Y3b}eBO|M``IF=q z*YX`oXWE@9+1o!++Z=?x(GpDNP*PEm&l~lFTzRlSvy8|sd-{YkV=MiU@NHZk@v9>C zpSQHB&fcm>!KMp)F~UJ;g;K|1Lx-XKzhpQjG|lljqADfQ zUyk&}-8?|itk`{Peu^>I*!Gh&#nGrY97cojr zb`S(v^dFdfwC!L(LY}3S+Z%kxqCAC7p@U9KQ@8ct*H4)v_BY|8q}_*|4*xCo|1AKM zcRGy0(~}WH?}yexF}ef}ioOWiiDMBkrF!9Ew?Vl9uIP=({u&<{SaE_EC-T3D*VG3p z!NK2RroNnA;`~`>%DYom#@a%+?{3lW&}+Trw#w|S%<=QqN8-tAU7of3$ek~$x3$#O zmAACmS2qjUCO_Km%!Xch`o2$RPxP{+#PO&wQT6od?duCe5Hoq{vIS9cuK4TQ?+dg@ zcdWb;!fM^|0>t{u%CcVb^hda+EPcyLtoZs}$Ixw)0Pja<

    8M5p>cyS$0$+Rdy7k~_%uIs@h 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 DmlseW@`11G6j5>3e- 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

    y^|e{KYE|L8$FgQqAwDKicjR`E z9@U2>n-ovy3?r^6}RTr3?t7-oXmfX(?HUmDb|H2 zAUdaXbK}&DACG6ILEbgmYd`IGlQ;q(aw^En3rB^zKLJTKJTD91q0$m4yqQyOk2<&a z39_dh)iI_!-HzJP(lR<(T`s^!irHZxaI*G(kl@@}&0AI}h9>bEXR{51+U)1s%ilRp zEL%o0fIx|Sws*hgWB03-a2q;$K|~1i&w^q{WE{1%>NjsLv+K$j8y$@|$lf=aKlosO zHab)A!mX{2^=kNO^Tms9E%|#T9s8H`_A+CBqGe;MLES*rI!Wh|WuU$=b%6+>`qa8O zLwU!ld%MqHiK4j-Z1W{KSZ#a1cyYy~Z5MxXU~jYZ0efHnCr^44a;1#iztCt?Me1X0}E&SECD zjbZv5$qgPwfF{KI#Jgbyg;&kW`h8jMp-_*J)sLpfkG%8_jsOgvGsgglp6mS_6&;d2 zQ`8$fZzr6(0Bqk)gPy3~EBfbkfYiB!BrDbO##(!>R2g z*r0LoF(=h{tlxp#<{E&)k?9W4j^Gee-`lrfiso0S#MN_bA1w+AH~*`Ir2+uM+xRE`wO{8_zfu$5@+!F*Q&{50u69R|Q`F>&x%XEs^Op1Nr#7E*E%H+bj*D+yk4_B3UyOMQ@0#dm ze>p4AynNS&Ye$@_o^0OhEQJbU=ETu!bqOiKs&bBoqUNIso0aQPv^JT~)9!P<)5_$2 zK)i`Ki?U?ss7;zqjOyL#XiGm)XJ_a2&#l+WL@tIM#{)4vDwTCE5%^|gI@*;o1o*N@ z8aFpLhi`Roc)0i7!^`p#>1EC;WH-MIg^e!5YpgV+)^?ZP^69GC7C+HUa~Y?+Uqgw! zA1%8i0SZ!q;;|HNQ`yMax7?@NcQxHTw)I!|c?Tg|5U~o2ee%NOxp29m>D1G5+yxH= z3vRlv-B7Ov&%=4Azz*$_n=-;ZNYBecCz_5ZyJuEfiYO(H-4eQ1R>V|7>$`Gq=7pOa z!WG-}==Y}af!6T;2peS&y$Z)7$;$+=l|H-0_sl1GFi4fZcCCfRY@770jk`kzY+TO z?ti58m*aVxr&`{+J?Ip~D~YQ1^6;MPWyka8r&{&ceyecPpZ+%XX{}Hepdjq1$*&uE1ZEJJq>7Pxqy^zaqfJObeEcAh}8v)b??;^zQ2f4;V#A}k{l5VL9NA?I6LKhHOK7=HKLxkL85cUWk@R`-7k+zYvR z4lv$;S6}NVCr<)yGufBCPA5}(+NpEJ&wYb^Vt|dlpB2zX-<;s(*_nSYZR(N!zD8!# za)sFaM}J8GyTS7oFK+&`#c%E{;IP2O{bw>jF%B%tUh%UZKI8;EyuSX)3$w+FkzUV^ zoP6tVf7je(%iYuZ|399uue*5l>QRK}Uq+=(-e|M|IDVjST|a9t@TQIzTR1_xrnJtm z0FwY{R?`|dY*!-xZq|z_Ps4701U8`Z?&w_2xBUM0-sk_CTato+qXAoD{;hlRdUNH~ z&!+$F!ascO{U7&ew>JA1;eR3jE=`qep7Z>}#I;3E!0Jf$q--Q`l{Ih?cEVQnu$f2J z#GLjrabP0l+XkK+4Z|e diff --git a/contracts/docs/plantuml/oethProcesses.puml b/contracts/docs/plantuml/oethProcesses.puml index 6ac90f4cda..ab3747c685 100644 --- a/contracts/docs/plantuml/oethProcesses.puml +++ b/contracts/docs/plantuml/oethProcesses.puml @@ -83,10 +83,10 @@ api -> api: split(key) note right : splits validator key into multiple KeyShares return -reg -> api: status(uuid) +reg -> api: GET\neth/staking/ssv/request/status/uuid activate api -return status,\nvalidatorRegistration,\nshareData -note right : validatorRegistration contains the pubkey, operatorIds and cluster details +return status,\npubkey\nvalidatorRegistration,\nshareData +note right : validatorRegistration contains the operatorIds and cluster details reg -> nativeStrat : registerSsvValidator(\npublicKey,\noperatorIds,\nsharesData,\namount,\ncluster) activate nativeStrat @@ -107,6 +107,17 @@ return return return +end group + +... 60 minutes ... + +group Registrator stakes to a new SSV validator + +reg -> api: GET\neth/staking/ssv/request/deposit-data/uuid +activate api +return status,\ndepositData +note right : depositData contains the signature and depositDataRoot + reg -> nativeStrat : stakeEth([\npubkey,\nsignature,\ndepositDataRoot]) activate nativeStrat nativeStrat -> nativeStrat diff --git a/contracts/scripts/defender-actions/operateValidators.js b/contracts/scripts/defender-actions/registerValidators.js similarity index 96% rename from contracts/scripts/defender-actions/operateValidators.js rename to contracts/scripts/defender-actions/registerValidators.js index d6c1c5fe07..f635949041 100644 --- a/contracts/scripts/defender-actions/operateValidators.js +++ b/contracts/scripts/defender-actions/registerValidators.js @@ -6,7 +6,7 @@ const { const { KeyValueStoreClient, } = require("@openzeppelin/defender-kvstore-client"); -const { operateValidators } = require("../../tasks/validator"); +const { registerValidators } = require("../../tasks/validator"); const addresses = require("../../utils/addresses"); const nativeStakingStrategyAbi = require("../../abi/native_staking_SSV_strategy.json"); @@ -83,7 +83,7 @@ const handler = async (event) => { clear: true, }; - await operateValidators({ + await registerValidators({ signer, contracts, store, diff --git a/contracts/scripts/defender-actions/rollup.config.cjs b/contracts/scripts/defender-actions/rollup.config.cjs index 939c02e2e1..06704a3159 100644 --- a/contracts/scripts/defender-actions/rollup.config.cjs +++ b/contracts/scripts/defender-actions/rollup.config.cjs @@ -4,7 +4,11 @@ const json = require("@rollup/plugin-json"); const builtins = require("builtin-modules"); const commonConfig = { - plugins: [resolve({ preferBuiltins: true, exportConditions: ["node"] }), commonjs(), json({ compact: true })], + plugins: [ + resolve({ preferBuiltins: true, exportConditions: ["node"] }), + commonjs(), + json({ compact: true }), + ], // Do not bundle these packages. // ethers is required to be bundled even though its an Autotask package. external: [ @@ -25,10 +29,18 @@ const commonConfig = { module.exports = [ { ...commonConfig, - input: "operateValidators.js", + input: "registerValidators.js", + output: { + file: "dist/registerValidators/index.js", + format: "cjs", + }, + }, + { + ...commonConfig, + input: "stakeValidators.js", output: { - file: "dist/operateValidators/index.js", + file: "dist/stakeValidators/index.js", format: "cjs", }, - } + }, ]; diff --git a/contracts/tasks/tasks.js b/contracts/tasks/tasks.js index 60f6e36621..5529744b5a 100644 --- a/contracts/tasks/tasks.js +++ b/contracts/tasks/tasks.js @@ -6,14 +6,8 @@ const { setActionVars } = require("./defender"); const { execute, executeOnFork, proposal, governors } = require("./governance"); const { smokeTest, smokeTestCheck } = require("./smokeTest"); const addresses = require("../utils/addresses"); -const { getDefenderSigner } = require("../utils/signers"); const { networkMap } = require("../utils/hardhat-helpers"); -const { resolveContract } = require("../utils/resolvers"); -const { - KeyValueStoreClient, -} = require("@openzeppelin/defender-kvstore-client"); -const { operateValidators } = require("./validator"); -const { formatUnits } = require("ethers/lib/utils"); +const { getSigner } = require("../utils/signers"); const { storeStorageLayoutForAllContracts, @@ -36,6 +30,7 @@ const { tokenTransfer, tokenTransferFrom, } = require("./tokens"); +const { depositWETH, withdrawWETH } = require("./weth"); const { allocate, capital, @@ -74,6 +69,13 @@ const { setRewardTokenAddresses, checkBalance, } = require("./strategy"); +const { + validatorOperationsConfig, + registerValidators, + stakeValidators, + resetStakeETHTally, + setStakeETHThreshold, +} = require("./validator"); // can not import from utils/deploy since that imports hardhat globally const withConfirmation = async (deployOrTransactionPromise) => { @@ -215,6 +217,37 @@ task("transferFrom").setAction(async (_, __, runSuper) => { return runSuper(); }); +// WETH tasks +subtask("depositWETH", "Deposit ETH into WETH") + .addParam("amount", "Amount of ETH to deposit", undefined, types.float) + .setAction(async (taskArgs) => { + const signer = await getSigner(); + + const { chainId } = await ethers.provider.getNetwork(); + const wethAddress = addresses[networkMap[chainId]].WETH; + const weth = await ethers.getContractAt("IWETH9", wethAddress); + + await depositWETH({ ...taskArgs, weth, signer }); + }); +task("depositWETH").setAction(async (_, __, runSuper) => { + return runSuper(); +}); + +subtask("withdrawWETH", "Withdraw ETH from WETH") + .addParam("amount", "Amount of ETH to withdraw", undefined, types.float) + .setAction(async (taskArgs) => { + const signer = await getSigner(); + + const { chainId } = await ethers.provider.getNetwork(); + const wethAddress = addresses[networkMap[chainId]].WETH; + const weth = await ethers.getContractAt("IWETH9", wethAddress); + + await withdrawWETH({ ...taskArgs, weth, signer }); + }); +task("withdrawWETH").setAction(async (_, __, runSuper) => { + return runSuper(); +}); + // Vault tasks. task("allocate", "Call allocate() on the Vault") .addOptionalParam( @@ -280,6 +313,12 @@ subtask("mint", "Mint OTokens from the Vault using collateral assets") types.string ) .addOptionalParam("min", "Minimum amount of OTokens to mint", 0, types.float) + .addOptionalParam( + "approve", + "Approve the asset to the OETH Vault before the mint", + true, + types.boolean + ) .setAction(mint); task("mint").setAction(async (_, __, runSuper) => { return runSuper(); @@ -869,16 +908,17 @@ subtask("getClusterInfo", "Print out information regarding SSV cluster") types.string ) .setAction(async (taskArgs) => { - const network = await ethers.provider.getNetwork(); - const ssvNetwork = addresses[networkMap[network.chainId]].SSVNetwork; + const { chainId } = await ethers.provider.getNetwork(); + const network = networkMap[chainId]; + const ssvNetwork = addresses[network].SSVNetwork; log( - `Fetching cluster info for cluster owner ${taskArgs.owner} with operator ids: ${taskArgs.operatorids} from the ${network.name} network using ssvNetworkContract ${ssvNetwork}` + `Fetching cluster info for cluster owner ${taskArgs.owner} with operator ids: ${taskArgs.operatorids} from the ${network} network using ssvNetworkContract ${ssvNetwork}` ); await printClusterInfo({ ...taskArgs, ownerAddress: taskArgs.owner, - chainId: network.chainId, + chainId: chainId, ssvNetwork, }); }); @@ -911,15 +951,13 @@ subtask( "deployNativeStakingProxy", "Deploy the native staking proxy via the Defender Relayer" ).setAction(async () => { - const defenderSigner = await getDefenderSigner(); + const signer = await getSigner(); log("Deploy NativeStakingSSVStrategyProxy"); const nativeStakingProxyFactory = await ethers.getContractFactory( "NativeStakingSSVStrategyProxy" ); - const contract = await nativeStakingProxyFactory - .connect(defenderSigner) - .deploy(); + const contract = await nativeStakingProxyFactory.connect(signer).deploy(); await contract.deployed(); log(`Address of deployed contract is: ${contract.address}`); }); @@ -937,16 +975,16 @@ subtask( ) .addParam("address", "Address of the new governor", undefined, types.string) .setAction(async (taskArgs) => { - const defenderSigner = await getDefenderSigner(); + const signer = await getSigner(); - log("Tranfer governance of NativeStakingSSVStrategyProxy"); + log("Transfer governance of NativeStakingSSVStrategyProxy"); const nativeStakingProxyFactory = await ethers.getContract( "NativeStakingSSVStrategyProxy" ); await withConfirmation( nativeStakingProxyFactory - .connect(defenderSigner) + .connect(signer) .transferGovernance(taskArgs.address) ); log( @@ -959,97 +997,83 @@ task("transferGovernanceNativeStakingProxy").setAction( } ); -// Defender +// Validator Operations + subtask( - "operateValidators", + "registerValidators", "Creates the required amount of new SSV validators and stakes ETH" ) - .addOptionalParam("index", "Index of Native Staking contract", 1, types.int) - .addOptionalParam( - "stake", - "Stake 32 ether after registering a new SSV validator", - true, - types.boolean - ) .addOptionalParam( "days", "SSV Cluster operational time in days", 40, types.int ) - .addOptionalParam("clear", "Clear storage", true, types.boolean) + .addOptionalParam("clear", "Clear storage", false, types.boolean) .setAction(async (taskArgs) => { - const network = await ethers.provider.getNetwork(); - const isMainnet = network.chainId === 1; - const isHolesky = network.chainId === 17000; - const addressesSet = isMainnet ? addresses.mainnet : addresses.holesky; - - if (!isMainnet && !isHolesky) { - throw new Error( - "operate validators is supported on Mainnet and Holesky only" - ); - } - - const storeFilePath = require("path").join( - __dirname, - "..", - `.localKeyValueStorage${isMainnet ? "Mainnet" : "Holesky"}` - ); + const config = await validatorOperationsConfig(taskArgs); + await registerValidators(config); + }); +task("registerValidators").setAction(async (_, __, runSuper) => { + return runSuper(); +}); - const store = new KeyValueStoreClient({ path: storeFilePath }); - const signer = await getDefenderSigner(); +subtask( + "stakeValidators", + "Creates the required amount of new SSV validators and stakes ETH" +) + .addOptionalParam( + "uuid", + "uuid of P2P's request SSV validator API call", + undefined, + types.string + ) + .setAction(async (taskArgs) => { + const config = await validatorOperationsConfig(taskArgs); + await stakeValidators(config); + }); +task("stakeValidators").setAction(async (_, __, runSuper) => { + return runSuper(); +}); - const WETH = await ethers.getContractAt("IWETH9", addressesSet.WETH); - const SSV = await ethers.getContractAt("IERC20", addressesSet.SSV); +subtask( + "resetStakeETHTally", + "Resets the amount of Ether staked back to zero" +).setAction(async () => { + const signer = await getSigner(); - // TODO: use index to target different native staking strategies when we have more than 1 - const nativeStakingStrategy = await resolveContract( - "NativeStakingSSVStrategyProxy", - "NativeStakingSSVStrategy" - ); + const nativeStakingProxyFactory = await ethers.getContract( + "NativeStakingSSVStrategyProxy" + ); - log( - "Balance of SSV tokens on the native staking contract: ", - formatUnits(await SSV.balanceOf(nativeStakingStrategy.address)) + await resetStakeETHTally({ + signer, + nativeStakingProxyFactory, + }); +}); +task("resetStakeETHTally").setAction(async (_, __, runSuper) => { + return runSuper(); +}); + +subtask( + "setStakeETHThreshold", + "Sets the amount of Ether than can be staked before needing a reset" +) + .addParam("amount", "Amount in ether", undefined, types.int) + .setAction(async (taskArgs) => { + const signer = await getSigner(); + + const nativeStakingProxyFactory = await ethers.getContract( + "NativeStakingSSVStrategyProxy" ); - const contracts = { - nativeStakingStrategy, - WETH, - }; - const feeAccumulatorAddress = - await nativeStakingStrategy.FEE_ACCUMULATOR_ADDRESS(); - - const p2p_api_key = isMainnet - ? process.env.P2P_MAINNET_API_KEY - : process.env.P2P_HOLESKY_API_KEY; - if (!p2p_api_key) { - throw new Error( - "P2P API key environment variable is not set. P2P_MAINNET_API_KEY or P2P_HOLESKY_API_KEY" - ); - } - const p2p_base_url = isMainnet ? "api.p2p.org" : "api-test-holesky.p2p.org"; - - const config = { - feeAccumulatorAddress, - p2p_api_key, - p2p_base_url, - // how much SSV (expressed in days of runway) gets deposited into the - // SSV Network contract on validator registration. This is calculated - // at a Cluster level rather than a single validator. - validatorSpawnOperationalPeriodInDays: taskArgs.days, - stake: taskArgs.stake, - clear: taskArgs.clear, - }; - - await operateValidators({ + await setStakeETHThreshold({ + ...taskArgs, signer, - contracts, - store, - config, + nativeStakingProxyFactory, }); }); -task("operateValidators").setAction(async (_, __, runSuper) => { +task("setStakeETHThreshold").setAction(async (_, __, runSuper) => { return runSuper(); }); diff --git a/contracts/tasks/validator.js b/contracts/tasks/validator.js index ee033a6162..a194040b4f 100644 --- a/contracts/tasks/validator.js +++ b/contracts/tasks/validator.js @@ -1,14 +1,86 @@ const fetch = require("node-fetch"); -const { defaultAbiCoder, formatUnits, hexDataSlice, parseEther } = +const { defaultAbiCoder, formatUnits, hexDataSlice, parseEther, keccak256 } = require("ethers").utils; const { v4: uuidv4 } = require("uuid"); - -//const { resolveContract } = require("../utils/resolvers"); +const { + KeyValueStoreClient, +} = require("@openzeppelin/defender-kvstore-client"); + +const { getClusterInfo } = require("./ssv"); +const addresses = require("../utils/addresses"); +const { resolveContract } = require("../utils/resolvers"); +const { getSigner } = require("../utils/signers"); const { sleep } = require("../utils/time"); -//const { getClusterInfo } = require("./ssv"); +const { logTxDetails } = require("../utils/txLogger"); +const { networkMap } = require("../utils/hardhat-helpers"); const log = require("../utils/logger")("task:p2p"); +const validatorStateEnum = { + 0: "NOT_REGISTERED", + 1: "REGISTERED", + 2: "STAKED", + 3: "EXITED", + 4: "EXIT_COMPLETE", +}; + +const validatorOperationsConfig = async (taskArgs) => { + const { chainId } = await ethers.provider.getNetwork(); + const network = networkMap[chainId]; + + if (!network) { + throw new Error( + `registerValidators does not support chain with id ${chainId}` + ); + } + const addressesSet = addresses[network]; + const isMainnet = network === "mainnet"; + + const signer = await getSigner(); + + const storeFilePath = require("path").join( + __dirname, + "..", + `.localKeyValueStorage.${network}` + ); + + const WETH = await ethers.getContractAt("IWETH9", addressesSet.WETH); + + const nativeStakingStrategy = await resolveContract( + "NativeStakingSSVStrategyProxy", + "NativeStakingSSVStrategy" + ); + const feeAccumulatorAddress = + await nativeStakingStrategy.FEE_ACCUMULATOR_ADDRESS(); + + const p2p_api_key = isMainnet + ? process.env.P2P_MAINNET_API_KEY + : process.env.P2P_HOLESKY_API_KEY; + if (!p2p_api_key) { + throw new Error( + "P2P API key environment variable is not set. P2P_MAINNET_API_KEY or P2P_HOLESKY_API_KEY" + ); + } + const p2p_base_url = isMainnet ? "api.p2p.org" : "api-test-holesky.p2p.org"; + + return { + store: new KeyValueStoreClient({ path: storeFilePath }), + signer, + p2p_api_key, + p2p_base_url, + nativeStakingStrategy, + feeAccumulatorAddress, + WETH, + // how much SSV (expressed in days of runway) gets deposited into the + // SSV Network contract on validator registration. This is calculated + // at a Cluster level rather than a single validator. + validatorSpawnOperationalPeriodInDays: taskArgs.days, + stake: taskArgs.stake, + clear: taskArgs.clear, + uuid: taskArgs.uuid, + }; +}; + /* When same UUID experiences and error threshold amount of times it is * discarded. */ @@ -32,16 +104,17 @@ const ERROR_THRESHOLD = 5; * - TODO: (implement this) if fuse of the native staking strategy is blown * stop with all the operations */ -const operateValidators = async ({ store, signer, contracts, config }) => { - const { - feeAccumulatorAddress, - p2p_api_key, - p2p_base_url, - validatorSpawnOperationalPeriodInDays, - stake, - clear, - } = config; - +const registerValidators = async ({ + store, + signer, + p2p_api_key, + p2p_base_url, + nativeStakingStrategy, + feeAccumulatorAddress, + WETH, + validatorSpawnOperationalPeriodInDays, + clear, +}) => { let currentState = await getState(store); log("currentState", currentState); @@ -50,13 +123,15 @@ const operateValidators = async ({ store, signer, contracts, config }) => { currentState = undefined; } - if (!(await stakingContractHas32ETH(contracts))) { - log(`Native staking contract doesn't have enough ETH, exiting`); + if (!(await stakingContractHas32ETH(nativeStakingStrategy, WETH))) { + console.log( + `Native staking contract doesn't have enough WETH available to stake. Does depositToStrategy or resetStakeETHTally need to be called?` + ); return; } - if (await stakingContractPaused(contracts)) { - log(`Native staking contract is paused... exiting`); + if (await stakingContractPaused(nativeStakingStrategy)) { + console.log(`Native staking contract is paused... exiting`); return; } @@ -64,33 +139,36 @@ const operateValidators = async ({ store, signer, contracts, config }) => { while (true) { if (!currentState) { await createValidatorRequest( - p2p_api_key, // api key + store, + "validator_creation_issued", // next state + p2p_api_key, p2p_base_url, - contracts.nativeStakingStrategy.address, // SSV owner address & withdrawal address + nativeStakingStrategy.address, // SSV owner address & withdrawal address feeAccumulatorAddress, // execution layer fee recipient - validatorSpawnOperationalPeriodInDays, - store + validatorSpawnOperationalPeriodInDays ); currentState = await getState(store); } if (currentState.state === "validator_creation_issued") { - await confirmValidatorCreatedRequest( - p2p_api_key, - p2p_base_url, + await confirmValidatorRegistered( + store, currentState.uuid, - store + "validator_creation_confirmed", // next state + p2p_api_key, + p2p_base_url ); currentState = await getState(store); } if (currentState.state === "validator_creation_confirmed") { await broadcastRegisterValidator( - signer, store, currentState.uuid, + "register_transaction_broadcast", // next state + signer, currentState.metadata, - contracts.nativeStakingStrategy + nativeStakingStrategy ); currentState = await getState(store); } @@ -99,22 +177,110 @@ const operateValidators = async ({ store, signer, contracts, config }) => { await waitForTransactionAndUpdateStateOnSuccess( store, currentState.uuid, - contracts.nativeStakingStrategy.provider, + "validator_registered", // next state + nativeStakingStrategy.provider, currentState.metadata.validatorRegistrationTx, - "registerSsvValidator", // name of transaction we are waiting for - "validator_registered" // new state when transaction confirmed + "registerSsvValidator" // name of transaction we are waiting for ); currentState = await getState(store); + break; } - if (!stake) break; + await sleep(1000); + } + }; + + try { + if ((await getErrorCount(store)) >= ERROR_THRESHOLD) { + await clearState( + currentState.uuid, + store, + `Errors have reached the threshold(${ERROR_THRESHOLD}) discarding attempt` + ); + return; + } + await executeOperateLoop(); + } catch (e) { + await increaseErrorCount(currentState ? currentState.uuid : "", store, e); + throw e; + } +}; + +const stakeValidators = async ({ + store, + signer, + nativeStakingStrategy, + WETH, + p2p_api_key, + p2p_base_url, + uuid, +}) => { + let currentState; + if (!uuid) { + let currentState = await getState(store); + log("currentState", currentState); + + if (!currentState) { + console.log(`Failed to get state from local storage`); + return; + } + } + + if (!(await stakingContractHas32ETH(nativeStakingStrategy, WETH))) { + console.log(`Native staking contract doesn't have enough ETH, exiting`); + return; + } + + if (await stakingContractPaused(nativeStakingStrategy)) { + console.log(`Native staking contract is paused... exiting`); + return; + } + + const executeOperateLoop = async () => { + while (true) { + if (!currentState) { + await confirmValidatorRegistered( + store, + uuid, + "validator_registered", // next state + p2p_api_key, + p2p_base_url + ); + currentState = await getState(store); + + // Check the validator has not already been staked + const hashedPubkey = keccak256(currentState.metadata.pubkey); + const status = await nativeStakingStrategy.validatorsStates( + hashedPubkey + ); + if (validatorStateEnum[status] !== "REGISTERED") { + console.log( + `Validator with pubkey ${currentState.metadata.pubkey} not in REGISTERED state. Current state: ${validatorStateEnum[status]}` + ); + await clearState(currentState.uuid, store); + break; + } + } if (currentState.state === "validator_registered") { + await getDepositData( + store, + currentState.uuid, + "deposit_data_got", // next state + p2p_api_key, + p2p_base_url + ); + currentState = await getState(store); + } + + if (currentState.state === "deposit_data_got") { await depositEth( - signer, store, currentState.uuid, - contracts.nativeStakingStrategy, + "deposit_transaction_broadcast", // next state + signer, + nativeStakingStrategy, + currentState.metadata.pubkey, currentState.metadata.depositData ); currentState = await getState(store); @@ -124,10 +290,10 @@ const operateValidators = async ({ store, signer, contracts, config }) => { await waitForTransactionAndUpdateStateOnSuccess( store, currentState.uuid, - contracts.nativeStakingStrategy.provider, + "deposit_confirmed", // next state + nativeStakingStrategy.provider, currentState.metadata.depositTx, - "stakeEth", // name of transaction we are waiting for - "deposit_confirmed" // new state when transaction confirmed + "stakeEth" // name of transaction we are waiting for ); currentState = await getState(store); @@ -137,6 +303,7 @@ const operateValidators = async ({ store, signer, contracts, config }) => { await clearState(currentState.uuid, store); break; } + await sleep(1000); } }; @@ -206,6 +373,7 @@ const updateState = async (requestUUID, state, store, metadata = {}) => { "validator_creation_confirmed", "register_transaction_broadcast", "validator_registered", + "deposit_data_got", "deposit_transaction_broadcast", "deposit_confirmed", ].includes(state) @@ -254,46 +422,46 @@ const getState = async (store) => { return JSON.parse(await store.get("currentRequest")); }; -const stakingContractPaused = async (contracts) => { - const paused = await contracts.nativeStakingStrategy.paused(); +const stakingContractPaused = async (nativeStakingStrategy) => { + const paused = await nativeStakingStrategy.paused(); log(`Native staking contract is ${paused ? "" : "not "}paused`); return paused; }; -const stakingContractHas32ETH = async (contracts) => { - const address = contracts.nativeStakingStrategy.address; - const wethBalance = await contracts.WETH.balanceOf(address); +const stakingContractHas32ETH = async (nativeStakingStrategy, WETH) => { + const address = nativeStakingStrategy.address; + const wethBalance = await WETH.balanceOf(address); log( `Native Staking Strategy has ${formatUnits(wethBalance, 18)} WETH in total` ); - const stakeETHThreshold = contracts.nativeStakingStrategy.stakeETHThreshold(); - const stakeETHTally = contracts.nativeStakingStrategy.stakeETHTally(); - const remainingETH = stakeETHThreshold.sub(stakeETHTally); + const stakeETHThreshold = await nativeStakingStrategy.stakeETHThreshold(); + const stakeETHTally = await nativeStakingStrategy.stakeETHTally(); + const remainingWETH = stakeETHThreshold.sub(stakeETHTally); log( `Native Staking Strategy has staked ${formatUnits( stakeETHTally )} of ${formatUnits(stakeETHThreshold)} ETH with ${formatUnits( - remainingETH - )} ETH remaining` + remainingWETH + )} WETH remaining` ); // Take the minimum of the remainingETH and the WETH balance - const availableETH = wethBalance.gt(remainingETH) - ? remainingETH + const availableETH = wethBalance.gt(remainingWETH) + ? remainingWETH : wethBalance; log( `Native Staking Strategy has ${formatUnits( availableETH - )} ETH available to stake` + )} WETH available to stake` ); return availableETH.gte(parseEther("32")); }; -/* Make a GET or POST request to P2P service - * @param api_key: p2p service api key +/* Make a GET or POST request to P2P API + * @param api_key: P2P API key * @param method: http method that can either be POST or GET * @param body: body object in case of a POST request */ @@ -309,7 +477,7 @@ const p2pRequest = async (url, api_key, method, body) => { const bodyString = JSON.stringify(body); log( - `Creating a P2P ${method} request with ${url} `, + `About to call P2P API: ${method} ${url} `, body != undefined ? ` and body: ${bodyString}` : "" ); @@ -321,24 +489,26 @@ const p2pRequest = async (url, api_key, method, body) => { const response = await rawResponse.json(); if (response.error != null) { - log("Request to P2P service failed with an error:", response); + log("Call to P2P API failed with response:", response); throw new Error( - `Call to P2P has failed: ${JSON.stringify(response.error)}` + `Failed to call to P2P API. Error: ${JSON.stringify(response.error)}` ); } else { - log("Request to P2P service succeeded: ", response); + log(`${method} request to P2P API succeeded:`); + log(response); } return response; }; const createValidatorRequest = async ( + store, + nextState, p2p_api_key, p2p_base_url, nativeStakingStrategy, feeAccumulatorAddress, - validatorSpawnOperationalPeriodInDays, - store + validatorSpawnOperationalPeriodInDays ) => { const uuid = uuidv4(); await p2pRequest( @@ -357,19 +527,19 @@ const createValidatorRequest = async ( } ); - await updateState(uuid, "validator_creation_issued", store); + await updateState(uuid, nextState, store); }; const waitForTransactionAndUpdateStateOnSuccess = async ( store, uuid, + nextState, provider, txHash, - methodName, - newState + methodName ) => { log( - `Waiting for transaction with hash "${txHash}" method "${methodName}" and uuid "${uuid}" to be mined...` + `Waiting for transaction with hash "${txHash}", method "${methodName}" and uuid "${uuid}" to be mined...` ); const tx = await provider.waitForTransaction(txHash); if (!tx) { @@ -377,17 +547,22 @@ const waitForTransactionAndUpdateStateOnSuccess = async ( `Transaction with hash "${txHash}" not found for method "${methodName}" and uuid "${uuid}"` ); } - await updateState(uuid, newState, store); + log( + `Transaction with hash "${txHash}", method "${methodName}" and uuid "${uuid}" has been mined` + ); + await updateState(uuid, nextState, store); }; const depositEth = async ( - signer, store, uuid, + nextState, + signer, nativeStakingStrategy, + pubkey, depositData ) => { - const { pubkey, signature, depositDataRoot } = depositData; + const { signature, depositDataRoot } = depositData; try { log(`About to stake ETH with:`); log(`pubkey: ${pubkey}`); @@ -403,7 +578,7 @@ const depositEth = async ( log(`Transaction to stake ETH has been broadcast with hash: ${tx.hash}`); - await updateState(uuid, "deposit_transaction_broadcast", store, { + await updateState(uuid, nextState, store, { depositTx: tx.hash, }); } catch (e) { @@ -414,9 +589,10 @@ const depositEth = async ( }; const broadcastRegisterValidator = async ( - signer, store, uuid, + nextState, + signer, metadata, nativeStakingStrategy ) => { @@ -433,11 +609,9 @@ const broadcastRegisterValidator = async ( // the publicKey and sharesData params are not encoded correctly by P2P so we will ignore them const [, operatorIds, , amount, cluster] = registerTransactionParams; // get publicKey and sharesData state storage - const publicKey = metadata.depositData.pubkey; + const publicKey = metadata.pubkey; if (!publicKey) { - throw Error( - `pubkey not found in metadata.depositData: ${metadata?.depositData}` - ); + throw Error(`pubkey not found in metadata: ${metadata}`); } const { sharesData } = metadata; if (!sharesData) { @@ -466,7 +640,7 @@ const broadcastRegisterValidator = async ( `Transaction to register SSV Validator has been broadcast with hash: ${tx.hash}` ); - await updateState(uuid, "register_transaction_broadcast", store, { + await updateState(uuid, nextState, store, { validatorRegistrationTx: tx.hash, }); } catch (e) { @@ -476,11 +650,12 @@ const broadcastRegisterValidator = async ( } }; -const confirmValidatorCreatedRequest = async ( - p2p_api_key, - p2p_base_url, +const confirmValidatorRegistered = async ( + store, uuid, - store + nextState, + p2p_api_key, + p2p_base_url ) => { const doConfirmation = async () => { const response = await p2pRequest( @@ -488,44 +663,93 @@ const confirmValidatorCreatedRequest = async ( p2p_api_key, "GET" ); + const isReady = + response.result?.status === "ready" || + response.result?.status === "validator-ready"; if (response.error != null) { - log(`Error processing request uuid: ${uuid} error: ${response}`); - } else if (response.result.status === "ready") { + log( + `Error getting validator status with uuid ${uuid}: ${response.error}` + ); + log(response); + return false; + } else if (!isReady) { + log( + `Validators with request uuid ${uuid} are not ready yet. Status: ${response?.result?.status}` + ); + return false; + } else { + log(`Validators requested with uuid ${uuid} are ready`); + + const pubkey = response.result.encryptedShares[0].publicKey; const registerValidatorData = response.result.validatorRegistrationTxs[0].data; - const depositData = response.result.depositData[0]; const sharesData = response.result.encryptedShares[0].sharesData; - await updateState(uuid, "validator_creation_confirmed", store, { + await updateState(uuid, nextState, store, { + pubkey, registerValidatorData, - depositData, sharesData, }); - log(`Validator created using uuid: ${uuid} is ready`); - log(`Primary key: ${depositData.pubkey}`); - log(`signature: ${depositData.signature}`); - log(`depositDataRoot: ${depositData.depositDataRoot}`); + log(`Public key: ${pubkey}`); log(`sharesData: ${sharesData}`); return true; - } else { + } + }; + + await retry(doConfirmation, uuid, store); +}; + +const getDepositData = async ( + store, + uuid, + nextState, + p2p_api_key, + p2p_base_url +) => { + const doConfirmation = async () => { + const response = await p2pRequest( + `https://${p2p_base_url}/api/v1/eth/staking/ssv/request/deposit-data/${uuid}`, + p2p_api_key, + "GET" + ); + if (response.error != null) { + log(`Error getting deposit data with uuid ${uuid}: ${response.error}`); + log(response); + return false; + } else if (response.result?.status != "validator-ready") { log( - `Validator created using uuid: ${uuid} not yet ready. State: ${response.result.status}` + `Deposit data with request uuid ${uuid} are not ready yet. Status: ${response.result?.status}` ); return false; + } else if (response.result?.status === "validator-ready") { + log(`Deposit data with request uuid ${uuid} is ready`); + + const depositData = response.result.depositData[0]; + await updateState(uuid, nextState, store, { + depositData, + }); + log(`signature: ${depositData.signature}`); + log(`depositDataRoot: ${depositData.depositDataRoot}`); + return true; + } else { + log(`Error getting deposit data with uuid ${uuid}: ${response.error}`); + log(response); + throw Error(`Failed to get deposit data with uuid ${uuid}.`); } }; + await retry(doConfirmation, uuid, store); +}; + +const retry = async (apiCall, uuid, store, attempts = 20) => { let counter = 0; - const attempts = 20; while (true) { - if (await doConfirmation()) { + if (await apiCall()) { break; } counter++; if (counter > attempts) { - log( - `Tried validating the validator formation with ${attempts} but failed` - ); + log(`Failed P2P API call after ${attempts} attempts.`); await clearState( uuid, store, @@ -537,42 +761,70 @@ const confirmValidatorCreatedRequest = async ( } }; -// async function exitValidator({ publicKey, signer, operatorIds }) { -// const strategy = await resolveContract( -// "NativeStakingSSVStrategyProxy", -// "NativeStakingSSVStrategy" -// ); - -// log(`About to exit validator`); -// const tx = await strategy -// .connect(signer) -// .exitSsvValidator(publicKey, operatorIds); -// await logTxDetails(tx, "exitSsvValidator"); -// } - -// async function removeValidator({ publicKey, signer, operatorIds }) { -// const strategy = await resolveContract( -// "NativeStakingSSVStrategyProxy", -// "NativeStakingSSVStrategy" -// ); - -// // Cluster details -// const { cluster } = await getClusterInfo({ -// chainId: hre.network.config.chainId, -// ssvNetwork: hre.network.name.toUpperCase(), -// operatorIds, -// ownerAddress: strategy.address, -// }); - -// log(`About to exit validator`); -// const tx = await strategy -// .connect(signer) -// .removeSsvValidator(publicKey, operatorIds, cluster); -// await logTxDetails(tx, "removeSsvValidator"); -// } +async function exitValidator({ publicKey, signer, operatorIds }) { + const strategy = await resolveContract( + "NativeStakingSSVStrategyProxy", + "NativeStakingSSVStrategy" + ); + + log(`About to exit validator`); + const tx = await strategy + .connect(signer) + .exitSsvValidator(publicKey, operatorIds); + await logTxDetails(tx, "exitSsvValidator"); +} + +async function removeValidator({ publicKey, signer, operatorIds }) { + const strategy = await resolveContract( + "NativeStakingSSVStrategyProxy", + "NativeStakingSSVStrategy" + ); + + // Cluster details + const { cluster } = await getClusterInfo({ + chainId: hre.network.config.chainId, + ssvNetwork: hre.network.name.toUpperCase(), + operatorIds, + ownerAddress: strategy.address, + }); + + log(`About to exit validator`); + const tx = await strategy + .connect(signer) + .removeSsvValidator(publicKey, operatorIds, cluster); + await logTxDetails(tx, "removeSsvValidator"); +} + +async function resetStakeETHTally({ signer }) { + const strategy = await resolveContract( + "NativeStakingSSVStrategyProxy", + "NativeStakingSSVStrategy" + ); + + log(`About to resetStakeETHTally`); + const tx = await strategy.connect(signer).resetStakeETHTally(); + await logTxDetails(tx, "resetStakeETHTally"); +} + +async function setStakeETHThreshold({ signer, amount }) { + const strategy = await resolveContract( + "NativeStakingSSVStrategyProxy", + "NativeStakingSSVStrategy" + ); + + const threshold = parseEther(amount.toString()); + + log(`About to setStakeETHThreshold`); + const tx = await strategy.connect(signer).setStakeETHThreshold(threshold); + await logTxDetails(tx, "setStakeETHThreshold"); +} module.exports = { - operateValidators, - //removeValidator, - //exitValidator, + validatorOperationsConfig, + registerValidators, + stakeValidators, + removeValidator, + exitValidator, + resetStakeETHTally, + setStakeETHThreshold, }; diff --git a/contracts/tasks/vault.js b/contracts/tasks/vault.js index f31db84369..ba49d4259b 100644 --- a/contracts/tasks/vault.js +++ b/contracts/tasks/vault.js @@ -133,7 +133,7 @@ async function capital({ symbol, pause }, hre) { } } -async function mint({ amount, asset, symbol, min }, hre) { +async function mint({ amount, asset, symbol, min, approve }, hre) { const signer = await getSigner(); const { vault } = await getContract(hre, symbol); @@ -142,7 +142,12 @@ async function mint({ amount, asset, symbol, min }, hre) { const assetUnits = parseUnits(amount.toString(), await cAsset.decimals()); const minUnits = parseUnits(min.toString()); - await cAsset.connect(signer).approve(vault.address, assetUnits); + if (approve) { + const approveTx = await cAsset + .connect(signer) + .approve(vault.address, assetUnits); + await logTxDetails(approveTx, "approve"); + } log(`About to mint ${symbol} using ${amount} ${asset}`); const tx = await vault diff --git a/contracts/tasks/weth.js b/contracts/tasks/weth.js new file mode 100644 index 0000000000..b9f35396f6 --- /dev/null +++ b/contracts/tasks/weth.js @@ -0,0 +1,23 @@ +const { parseUnits } = require("ethers").utils; + +const { logTxDetails } = require("../utils/txLogger"); + +const log = require("../utils/logger")("task:weth"); + +const depositWETH = async ({ weth, amount, signer }) => { + const etherAmount = parseUnits(amount.toString()); + + log(`About to deposit ${amount} ETH for WETH`); + const tx = await weth.connect(signer).deposit({ value: etherAmount }); + await logTxDetails(tx, "deposit"); +}; + +const withdrawWETH = async ({ weth, amount, signer }) => { + const etherAmount = parseUnits(amount.toString()); + + log(`About to withdraw ${amount} ETH from WETH`); + const tx = await weth.connect(signer).withdraw(etherAmount); + await logTxDetails(tx, "withdraw"); +}; + +module.exports = { depositWETH, withdrawWETH }; diff --git a/contracts/utils/resolvers.js b/contracts/utils/resolvers.js index b47f5b229e..498a1b50fa 100644 --- a/contracts/utils/resolvers.js +++ b/contracts/utils/resolvers.js @@ -1,5 +1,6 @@ const addresses = require("./addresses"); const { ethereumAddress } = require("./regex"); +const { networkMap } = require("./hardhat-helpers"); const log = require("./logger")("task:assets"); @@ -15,12 +16,8 @@ const resolveAsset = async (symbol) => { // Not using helpers here as they import hardhat which won't work for Hardhat tasks if (process.env.FORK === "true" || hre.network.name != "hardhat") { - const network = - hre.network.name != "hardhat" - ? hre.network.name != "hardhat" - : hre.network.config.chainId == 17000 - ? "holesky" - : "mainnet"; + const { chainId } = await hre.ethers.provider.getNetwork(); + const network = networkMap[chainId] || "mainnet"; const assetAddr = addresses[network][symbol + "Proxy"] || addresses[network][symbol]; diff --git a/contracts/utils/signers.js b/contracts/utils/signers.js index 439d6ee07f..520688f3e9 100644 --- a/contracts/utils/signers.js +++ b/contracts/utils/signers.js @@ -1,5 +1,8 @@ const { Wallet } = require("ethers"); -const { Defender } = require("@openzeppelin/defender-sdk"); +const { + DefenderRelaySigner, + DefenderRelayProvider, +} = require("@openzeppelin/defender-relay-client/lib/ethers"); const { ethereumAddress, privateKey } = require("./regex"); const { hardhatSetBalance } = require("../test/_fund"); @@ -59,7 +62,7 @@ async function getSigner(address = undefined) { } const getDefenderSigner = async () => { - const speed = process.env.SPEED || "fast"; + const speed = process.env.SPEED || "fastest"; if (!["safeLow", "average", "fast", "fastest"].includes(speed)) { console.error( `Defender Relay Speed param must be either 'safeLow', 'average', 'fast' or 'fastest'. Not "${speed}"` @@ -67,28 +70,26 @@ const getDefenderSigner = async () => { process.exit(2); } - const network = await ethers.provider.getNetwork(); - const isMainnet = network.chainId === 1; - const isHolesky = network.chainId === 17000; + const { chainId } = await ethers.provider.getNetwork(); + const isMainnet = chainId === 1; - const apiKeyName = isMainnet - ? "DEFENDER_API_KEY" - : "HOLESKY_DEFENDER_API_KEY"; - const apiKeySecret = isMainnet - ? "DEFENDER_API_SECRET" - : "HOLESKY_DEFENDER_API_SECRET"; + const apiKey = isMainnet + ? process.env.DEFENDER_API_KEY + : process.env.HOLESKY_DEFENDER_API_KEY || process.env.DEFENDER_API_KEY; + const apiSecret = isMainnet + ? process.env.DEFENDER_API_SECRET + : process.env.HOLESKY_DEFENDER_API_SECRET || + process.env.DEFENDER_API_SECRET; - const credentials = { - relayerApiKey: process.env[apiKeyName], - relayerApiSecret: process.env[apiKeySecret], - }; + const credentials = { apiKey, apiSecret }; - const client = new Defender(credentials); - const provider = client.relaySigner.getProvider(); + const provider = new DefenderRelayProvider(credentials); + const signer = new DefenderRelaySigner(credentials, provider, { + speed, + }); - const signer = client.relaySigner.getSigner(provider, { speed }); log( - `Using Defender Relayer account ${await signer.getAddress()} from env vars ${apiKeyName} and ${apiKeySecret}` + `Using Defender Relayer account ${await signer.getAddress()} with key ${apiKey} and speed ${speed}` ); return signer; }; From 49439ec4e29c783460f7f4dc6e78ff89a5ee8352 Mon Sep 17 00:00:00 2001 From: Nick Addison Date: Mon, 3 Jun 2024 17:23:12 +1000 Subject: [PATCH 120/273] Hardhat tasks for Native Staking (#2085) * Fixed depositSSV HH tasks * Added exitValidator and removeValidator HH tasks * Added doAccounting Defender Action * Added harvest HH task * Added fixAccounting and pauseStaking HH tasks * Fixed stakeValidators when run without uuid option --- contracts/README.md | 7 +- contracts/dev.env | 12 +- contracts/package.json | 1 + .../scripts/defender-actions/doAccounting.js | 42 ++++++ .../defender-actions/registerValidators.js | 34 ++--- .../defender-actions/rollup.config.cjs | 11 ++ .../defender-actions/stakeValidators.js | 70 ++++++++++ contracts/tasks/harvest.js | 21 +++ contracts/tasks/ssv.js | 2 +- contracts/tasks/tasks.js | 128 +++++++++++++++--- contracts/tasks/validator.js | 86 ++++++++++-- contracts/yarn.lock | 107 ++++++++++++++- 12 files changed, 461 insertions(+), 60 deletions(-) create mode 100644 contracts/scripts/defender-actions/doAccounting.js create mode 100644 contracts/scripts/defender-actions/stakeValidators.js create mode 100644 contracts/tasks/harvest.js diff --git a/contracts/README.md b/contracts/README.md index 84c6df5154..6576e7a8dd 100644 --- a/contracts/README.md +++ b/contracts/README.md @@ -343,15 +343,16 @@ export DEFENDER_TEAM_SECRET= # Set the DEBUG environment variable to oeth* for the Defender Action npx hardhat setActionVars --id 38e44420-f38b-4d4a-86b0-6012a8897ad9 npx hardhat setActionVars --id f4b5b8d4-82ff-483f-bfae-9fef015790ca +npx hardhat setActionVars --id 191d9631-70b9-43c5-9db4-1dd985fde05c -# Upload Deposit to EigenLayer code # The Defender autotask client uses generic env var names so we'll set them first from the values in the .env file export API_KEY=${DEFENDER_TEAM_KEY} export API_SECRET=${DEFENDER_TEAM_SECRET} # Holesky -npx defender-autotask update-code 38e44420-f38b-4d4a-86b0-6012a8897ad9 ./dist/operateValidators +npx defender-autotask update-code 38e44420-f38b-4d4a-86b0-6012a8897ad9 ./dist/registerValidators +npx defender-autotask update-code 191d9631-70b9-43c5-9db4-1dd985fde05c ./dist/doAccounting # Mainnet -npx defender-autotask update-code f4b5b8d4-82ff-483f-bfae-9fef015790ca ./dist/operateValidators +npx defender-autotask update-code f4b5b8d4-82ff-483f-bfae-9fef015790ca ./dist/registerValidators ``` `rollup` and `defender-autotask-client` can be installed globally to avoid the `npx` prefix. diff --git a/contracts/dev.env b/contracts/dev.env index f7754465b6..ccae286df8 100644 --- a/contracts/dev.env +++ b/contracts/dev.env @@ -34,4 +34,14 @@ ACCOUNTS_TO_FUND= #P2P API KEYS P2P_MAINNET_API_KEY=[SET API Key] -P2P_HOLESKY_API_KEY=[SET API Key] \ No newline at end of file +P2P_HOLESKY_API_KEY=[SET API Key] + +# Defender Team Key needed to upload code to Actions +# DEFENDER_TEAM_KEY= +# DEFENDER_TEAM_SECRET= + +# Defender Relayer API key +# HOLESKY_DEFENDER_API_KEY= +# HOLESKY_DEFENDER_API_SECRET= +# DEFENDER_API_KEY= +# DEFENDER_API_SECRET= diff --git a/contracts/package.json b/contracts/package.json index b732aa0ae9..19dcbdfc18 100644 --- a/contracts/package.json +++ b/contracts/package.json @@ -78,6 +78,7 @@ "papaparse": "^5.3.1", "prettier": "^2.3.2", "prettier-plugin-solidity": "1.0.0-beta.17", + "rollup": "^4.18.0", "solc": "0.8.6", "solhint": "^3.4.1", "solidifier": "^2.2.3", diff --git a/contracts/scripts/defender-actions/doAccounting.js b/contracts/scripts/defender-actions/doAccounting.js new file mode 100644 index 0000000000..ee5c9a63cd --- /dev/null +++ b/contracts/scripts/defender-actions/doAccounting.js @@ -0,0 +1,42 @@ +const { ethers } = require("ethers"); +const { + DefenderRelaySigner, + DefenderRelayProvider, +} = require("@openzeppelin/defender-relay-client/lib/ethers"); +const addresses = require("../../utils/addresses"); +const { logTxDetails } = require("../../utils/txLogger"); + +const nativeStakingStrategyAbi = require("../../abi/native_staking_SSV_strategy.json"); + +const log = require("../../utils/logger")("action:doAccounting"); + +// Entrypoint for the Defender Action +const handler = async (event) => { + console.log( + `DEBUG env var in handler before being set: "${process.env.DEBUG}"` + ); + + // Initialize defender relayer provider and signer + const provider = new DefenderRelayProvider(event); + const signer = new DefenderRelaySigner(event, provider, { speed: "fastest" }); + + const network = await provider.getNetwork(); + const networkName = network.chainId === 1 ? "mainnet" : "holesky"; + log(`Network: ${networkName} with chain id (${network.chainId})`); + + const nativeStakingProxyAddress = + addresses[networkName].NativeStakingSSVStrategyProxy; + log( + `Resolved Native Staking Strategy address to ${nativeStakingProxyAddress}` + ); + const nativeStakingStrategy = new ethers.Contract( + nativeStakingProxyAddress, + nativeStakingStrategyAbi, + signer + ); + + const tx = await nativeStakingStrategy.connect(signer).doAccounting(); + await logTxDetails(tx, "doAccounting"); +}; + +module.exports = { handler }; diff --git a/contracts/scripts/defender-actions/registerValidators.js b/contracts/scripts/defender-actions/registerValidators.js index f635949041..15036811d7 100644 --- a/contracts/scripts/defender-actions/registerValidators.js +++ b/contracts/scripts/defender-actions/registerValidators.js @@ -12,32 +12,29 @@ const addresses = require("../../utils/addresses"); const nativeStakingStrategyAbi = require("../../abi/native_staking_SSV_strategy.json"); const IWETH9Abi = require("../../abi/IWETH9.json"); -const log = require("../../utils/logger")("action:operateValidators"); +const log = require("../../utils/logger")("action:registerValidators"); // Entrypoint for the Defender Action const handler = async (event) => { - const store = new KeyValueStoreClient(event); - // Initialize defender relayer provider and signer console.log( `DEBUG env var in handler before being set: "${process.env.DEBUG}"` ); + const store = new KeyValueStoreClient(event); + + // Initialize defender relayer provider and signer const provider = new DefenderRelayProvider(event); const signer = new DefenderRelaySigner(event, provider, { speed: "fastest" }); const network = await provider.getNetwork(); const networkName = network.chainId === 1 ? "mainnet" : "holesky"; log(`Network: ${networkName} with chain id (${network.chainId})`); - console.log(`Network: ${networkName} with chain id (${network.chainId})`); const nativeStakingProxyAddress = addresses[networkName].NativeStakingSSVStrategyProxy; log( `Resolved Native Staking Strategy address to ${nativeStakingProxyAddress}` ); - console.log( - `Resolved Native Staking Strategy address to ${nativeStakingProxyAddress}` - ); const nativeStakingStrategy = new ethers.Contract( nativeStakingProxyAddress, nativeStakingStrategyAbi, @@ -46,17 +43,11 @@ const handler = async (event) => { const wethAddress = addresses[networkName].WETH; log(`Resolved WETH address to ${wethAddress}`); - console.log(`Resolved WETH address to ${wethAddress}`); const WETH = new ethers.Contract(wethAddress, IWETH9Abi, signer); const feeAccumulatorAddress = await nativeStakingStrategy.FEE_ACCUMULATOR_ADDRESS(); - const contracts = { - nativeStakingStrategy, - WETH, - }; - const p2p_api_key = network.chainId === 1 ? event.secrets.P2P_MAINNET_API_KEY @@ -69,7 +60,11 @@ const handler = async (event) => { const p2p_base_url = network.chainId === 1 ? "api.p2p.org" : "api-test-holesky.p2p.org"; - const config = { + await registerValidators({ + signer, + store, + nativeStakingStrategy, + WETH, feeAccumulatorAddress, p2p_api_key, p2p_base_url, @@ -77,17 +72,6 @@ const handler = async (event) => { // SSV Network contract on validator registration. This is calculated // at a Cluster level rather than a single validator. validatorSpawnOperationalPeriodInDays: 1, - // Stake the 32 ETH into the validator - stake: true, - // Clear the local state of the Defender Action - clear: true, - }; - - await registerValidators({ - signer, - contracts, - store, - config, }); }; diff --git a/contracts/scripts/defender-actions/rollup.config.cjs b/contracts/scripts/defender-actions/rollup.config.cjs index 06704a3159..a55e8d10e4 100644 --- a/contracts/scripts/defender-actions/rollup.config.cjs +++ b/contracts/scripts/defender-actions/rollup.config.cjs @@ -32,6 +32,7 @@ module.exports = [ input: "registerValidators.js", output: { file: "dist/registerValidators/index.js", + inlineDynamicImports: true, format: "cjs", }, }, @@ -40,6 +41,16 @@ module.exports = [ input: "stakeValidators.js", output: { file: "dist/stakeValidators/index.js", + inlineDynamicImports: true, + format: "cjs", + }, + }, + { + ...commonConfig, + input: "doAccounting.js", + output: { + file: "dist/doAccounting/index.js", + inlineDynamicImports: true, format: "cjs", }, }, diff --git a/contracts/scripts/defender-actions/stakeValidators.js b/contracts/scripts/defender-actions/stakeValidators.js new file mode 100644 index 0000000000..4422214973 --- /dev/null +++ b/contracts/scripts/defender-actions/stakeValidators.js @@ -0,0 +1,70 @@ +const { ethers } = require("ethers"); +const { + DefenderRelaySigner, + DefenderRelayProvider, +} = require("@openzeppelin/defender-relay-client/lib/ethers"); +const { + KeyValueStoreClient, +} = require("@openzeppelin/defender-kvstore-client"); +const { stakeValidators } = require("../../tasks/validator"); +const addresses = require("../../utils/addresses"); + +const nativeStakingStrategyAbi = require("../../abi/native_staking_SSV_strategy.json"); +const IWETH9Abi = require("../../abi/IWETH9.json"); + +const log = require("../../utils/logger")("action:stakeValidators"); + +// Entrypoint for the Defender Action +const handler = async (event) => { + console.log( + `DEBUG env var in handler before being set: "${process.env.DEBUG}"` + ); + + const store = new KeyValueStoreClient(event); + + // Initialize defender relayer provider and signer + const provider = new DefenderRelayProvider(event); + const signer = new DefenderRelaySigner(event, provider, { speed: "fastest" }); + + const network = await provider.getNetwork(); + const networkName = network.chainId === 1 ? "mainnet" : "holesky"; + log(`Network: ${networkName} with chain id (${network.chainId})`); + + const nativeStakingProxyAddress = + addresses[networkName].NativeStakingSSVStrategyProxy; + log( + `Resolved Native Staking Strategy address to ${nativeStakingProxyAddress}` + ); + const nativeStakingStrategy = new ethers.Contract( + nativeStakingProxyAddress, + nativeStakingStrategyAbi, + signer + ); + + const wethAddress = addresses[networkName].WETH; + log(`Resolved WETH address to ${wethAddress}`); + const WETH = new ethers.Contract(wethAddress, IWETH9Abi, signer); + + const p2p_api_key = + network.chainId === 1 + ? event.secrets.P2P_MAINNET_API_KEY + : event.secrets.P2P_HOLESKY_API_KEY; + if (!p2p_api_key) { + throw new Error( + "Secret with P2P API key not set. Add the P2P_MAINNET_API_KEY or P2P_HOLESKY_API_KEY secret" + ); + } + const p2p_base_url = + network.chainId === 1 ? "api.p2p.org" : "api-test-holesky.p2p.org"; + + await stakeValidators({ + signer, + store, + nativeStakingStrategy, + WETH, + p2p_api_key, + p2p_base_url, + }); +}; + +module.exports = { handler }; diff --git a/contracts/tasks/harvest.js b/contracts/tasks/harvest.js new file mode 100644 index 0000000000..3d789d039e --- /dev/null +++ b/contracts/tasks/harvest.js @@ -0,0 +1,21 @@ +const { resolveContract } = require("../utils/resolvers"); +const { getSigner } = require("../utils/signers"); +const { logTxDetails } = require("../utils/txLogger"); + +const log = require("../utils/logger")("task:harvest"); + +async function harvestAndSwap({ strategy, harvester }) { + const signer = await getSigner(); + + const harvesterContract = await resolveContract(harvester, "OETHHarvester"); + const strategyContract = await resolveContract(strategy); + + log(`Harvesting and swapping for strategy ${strategyContract.address}`); + const tx = await harvesterContract.connect(signer)[ + // eslint-disable-next-line no-unexpected-multiline + "harvestAndSwap(address)" + ](strategyContract.address); + await logTxDetails(tx, "harvestAndSwap"); +} + +module.exports = { harvestAndSwap }; diff --git a/contracts/tasks/ssv.js b/contracts/tasks/ssv.js index 1669d6798a..3212453471 100644 --- a/contracts/tasks/ssv.js +++ b/contracts/tasks/ssv.js @@ -34,7 +34,7 @@ const depositSSV = async ({ amount, operatorids }, hre) => { const clusterInfo = await getClusterInfo({ chainId: hre.network.config.chainId, ssvNetwork: ssvNetwork.address, - operatorIds: operatorids, + operatorids, ownerAddress: strategy.address, }); diff --git a/contracts/tasks/tasks.js b/contracts/tasks/tasks.js index 5529744b5a..720a43ace0 100644 --- a/contracts/tasks/tasks.js +++ b/contracts/tasks/tasks.js @@ -73,9 +73,16 @@ const { validatorOperationsConfig, registerValidators, stakeValidators, + exitValidator, + removeValidator, + doAccounting, resetStakeETHTally, setStakeETHThreshold, + fixAccounting, + pauseStaking, } = require("./validator"); +const { resolveContract } = require("../utils/resolvers"); +const { harvestAndSwap } = require("./harvest"); // can not import from utils/deploy since that imports hardhat globally const withConfirmation = async (deployOrTransactionPromise) => { @@ -892,6 +899,23 @@ task("setRewardTokenAddresses", "Sets the reward token of a strategy") ) .setAction(setRewardTokenAddresses); +// Harvester + +task("harvest", "Harvest and swap rewards for a strategy") + .addParam( + "strategy", + "Name of the strategy proxy contract or address. eg NativeStakingSSVStrategyProxy", + undefined, + types.string + ) + .addOptionalParam( + "harvester", + "Name of the harvester proxy contract or address", + "OETHHarvesterProxy", + types.string + ) + .setAction(harvestAndSwap); + // SSV subtask("getClusterInfo", "Print out information regarding SSV cluster") @@ -1036,21 +1060,69 @@ task("stakeValidators").setAction(async (_, __, runSuper) => { return runSuper(); }); +subtask("exitValidator", "Starts the exit process from a validator") + .addParam( + "pubkey", + "Public key of the validator to exit", + undefined, + types.string + ) + .addParam( + "operatorids", + "Comma separated operator ids. E.g. 60,79,220,349", + undefined, + types.string + ) + .setAction(exitValidator); +task("exitValidator").setAction(async (_, __, runSuper) => { + return runSuper(); +}); + subtask( - "resetStakeETHTally", - "Resets the amount of Ether staked back to zero" + "removeValidator", + "Removes a validator from the SSV cluster after it has exited the beacon chain" +) + .addParam( + "pubkey", + "Public key of the validator to exit", + undefined, + types.string + ) + .addParam( + "operatorids", + "Comma separated operator ids. E.g. 60,79,220,349", + undefined, + types.string + ) + .setAction(removeValidator); +task("removeValidator").setAction(async (_, __, runSuper) => { + return runSuper(); +}); + +subtask( + "doAccounting", + "Account for consensus rewards and validator exits in the Native Staking Strategy" ).setAction(async () => { const signer = await getSigner(); - const nativeStakingProxyFactory = await ethers.getContract( - "NativeStakingSSVStrategyProxy" + const nativeStakingStrategy = await resolveContract( + "NativeStakingSSVStrategyProxy", + "NativeStakingSSVStrategy" ); - await resetStakeETHTally({ + await doAccounting({ signer, - nativeStakingProxyFactory, + nativeStakingStrategy, }); }); +task("doAccounting").setAction(async (_, __, runSuper) => { + return runSuper(); +}); + +subtask( + "resetStakeETHTally", + "Resets the amount of Ether staked back to zero" +).setAction(resetStakeETHTally); task("resetStakeETHTally").setAction(async (_, __, runSuper) => { return runSuper(); }); @@ -1060,20 +1132,40 @@ subtask( "Sets the amount of Ether than can be staked before needing a reset" ) .addParam("amount", "Amount in ether", undefined, types.int) - .setAction(async (taskArgs) => { - const signer = await getSigner(); + .setAction(setStakeETHThreshold); +task("setStakeETHThreshold").setAction(async (_, __, runSuper) => { + return runSuper(); +}); - const nativeStakingProxyFactory = await ethers.getContract( - "NativeStakingSSVStrategyProxy" - ); +subtask("fixAccounting", "Fix the accounting of the Native Staking Strategy.") + .addOptionalParam( + "validators", + "The number of validators to adjust up or down (negative)", + 0, + types.int + ) + .addOptionalParam( + "rewards", + "The number of consensus rewards to adjust up or down (negative) in ether", + 0, + types.float + ) + .addOptionalParam( + "ether", + "amount of ether that gets wrapped into WETH and sent to the Vault", + 0, + types.float + ) + .setAction(fixAccounting); +task("fixAccounting").setAction(async (_, __, runSuper) => { + return runSuper(); +}); - await setStakeETHThreshold({ - ...taskArgs, - signer, - nativeStakingProxyFactory, - }); - }); -task("setStakeETHThreshold").setAction(async (_, __, runSuper) => { +subtask( + "pauseStaking", + "Pause the staking of the Native Staking Strategy" +).setAction(pauseStaking); +task("pauseStaking").setAction(async (_, __, runSuper) => { return runSuper(); }); diff --git a/contracts/tasks/validator.js b/contracts/tasks/validator.js index a194040b4f..b00d58e79f 100644 --- a/contracts/tasks/validator.js +++ b/contracts/tasks/validator.js @@ -6,7 +6,7 @@ const { KeyValueStoreClient, } = require("@openzeppelin/defender-kvstore-client"); -const { getClusterInfo } = require("./ssv"); +const { getClusterInfo } = require("../utils/ssv"); const addresses = require("../utils/addresses"); const { resolveContract } = require("../utils/resolvers"); const { getSigner } = require("../utils/signers"); @@ -75,7 +75,6 @@ const validatorOperationsConfig = async (taskArgs) => { // SSV Network contract on validator registration. This is calculated // at a Cluster level rather than a single validator. validatorSpawnOperationalPeriodInDays: taskArgs.days, - stake: taskArgs.stake, clear: taskArgs.clear, uuid: taskArgs.uuid, }; @@ -186,6 +185,13 @@ const registerValidators = async ({ break; } + if (currentState.state === "validator_registered") { + log( + `Validator has been registered. Run the stakeValidators task to stake the validator` + ); + break; + } + await sleep(1000); } }; @@ -217,7 +223,7 @@ const stakeValidators = async ({ }) => { let currentState; if (!uuid) { - let currentState = await getState(store); + currentState = await getState(store); log("currentState", currentState); if (!currentState) { @@ -489,7 +495,8 @@ const p2pRequest = async (url, api_key, method, body) => { const response = await rawResponse.json(); if (response.error != null) { - log("Call to P2P API failed with response:", response); + log(`Call to P2P API failed: ${method} ${url}`); + log(`response: `, response); throw new Error( `Failed to call to P2P API. Error: ${JSON.stringify(response.error)}` ); @@ -658,6 +665,9 @@ const confirmValidatorRegistered = async ( p2p_base_url ) => { const doConfirmation = async () => { + if (!uuid) { + throw Error(`UUID is required to get validator status.`); + } const response = await p2pRequest( `https://${p2p_base_url}/api/v1/eth/staking/ssv/request/status/${uuid}`, p2p_api_key, @@ -706,6 +716,9 @@ const getDepositData = async ( p2p_base_url ) => { const doConfirmation = async () => { + if (!uuid) { + throw Error(`UUID is required to get deposit data.`); + } const response = await p2pRequest( `https://${p2p_base_url}/api/v1/eth/staking/ssv/request/deposit-data/${uuid}`, p2p_api_key, @@ -761,7 +774,12 @@ const retry = async (apiCall, uuid, store, attempts = 20) => { } }; -async function exitValidator({ publicKey, signer, operatorIds }) { +async function exitValidator({ pubkey, operatorids }) { + const signer = await getSigner(); + + log(`Splitting operator IDs ${operatorids}`); + const operatorIds = operatorids.split(",").map((id) => parseInt(id)); + const strategy = await resolveContract( "NativeStakingSSVStrategyProxy", "NativeStakingSSVStrategy" @@ -770,11 +788,16 @@ async function exitValidator({ publicKey, signer, operatorIds }) { log(`About to exit validator`); const tx = await strategy .connect(signer) - .exitSsvValidator(publicKey, operatorIds); + .exitSsvValidator(pubkey, operatorIds); await logTxDetails(tx, "exitSsvValidator"); } -async function removeValidator({ publicKey, signer, operatorIds }) { +async function removeValidator({ pubkey, operatorids }) { + const signer = await getSigner(); + + log(`Splitting operator IDs ${operatorids}`); + const operatorIds = operatorids.split(",").map((id) => parseInt(id)); + const strategy = await resolveContract( "NativeStakingSSVStrategyProxy", "NativeStakingSSVStrategy" @@ -784,18 +807,26 @@ async function removeValidator({ publicKey, signer, operatorIds }) { const { cluster } = await getClusterInfo({ chainId: hre.network.config.chainId, ssvNetwork: hre.network.name.toUpperCase(), - operatorIds, + operatorids, ownerAddress: strategy.address, }); log(`About to exit validator`); const tx = await strategy .connect(signer) - .removeSsvValidator(publicKey, operatorIds, cluster); + .removeSsvValidator(pubkey, operatorIds, cluster); await logTxDetails(tx, "removeSsvValidator"); } -async function resetStakeETHTally({ signer }) { +async function doAccounting({ signer, nativeStakingStrategy }) { + log(`About to doAccounting`); + const tx = await nativeStakingStrategy.connect(signer).doAccounting(); + await logTxDetails(tx, "doAccounting"); +} + +async function resetStakeETHTally() { + const signer = await getSigner(); + const strategy = await resolveContract( "NativeStakingSSVStrategyProxy", "NativeStakingSSVStrategy" @@ -806,7 +837,9 @@ async function resetStakeETHTally({ signer }) { await logTxDetails(tx, "resetStakeETHTally"); } -async function setStakeETHThreshold({ signer, amount }) { +async function setStakeETHThreshold({ amount }) { + const signer = await getSigner(); + const strategy = await resolveContract( "NativeStakingSSVStrategyProxy", "NativeStakingSSVStrategy" @@ -819,12 +852,43 @@ async function setStakeETHThreshold({ signer, amount }) { await logTxDetails(tx, "setStakeETHThreshold"); } +async function fixAccounting({ validators, rewards, ether }) { + const signer = await getSigner(); + + const strategy = await resolveContract( + "NativeStakingSSVStrategyProxy", + "NativeStakingSSVStrategy" + ); + + log(`About to fix accounting`); + const tx = await strategy + .connect(signer) + .manuallyFixAccounting(validators, rewards, ether); + await logTxDetails(tx, "manuallyFixAccounting"); +} + +async function pauseStaking() { + const signer = await getSigner(); + + const strategy = await resolveContract( + "NativeStakingSSVStrategyProxy", + "NativeStakingSSVStrategy" + ); + + log(`About to pause the Native Staking Strategy`); + const tx = await strategy.connect(signer).pause(); + await logTxDetails(tx, "pause"); +} + module.exports = { validatorOperationsConfig, registerValidators, stakeValidators, removeValidator, exitValidator, + doAccounting, resetStakeETHTally, setStakeETHThreshold, + fixAccounting, + pauseStaking, }; diff --git a/contracts/yarn.lock b/contracts/yarn.lock index cea1711fd5..5e0638a4f1 100644 --- a/contracts/yarn.lock +++ b/contracts/yarn.lock @@ -1334,6 +1334,86 @@ estree-walker "^2.0.2" picomatch "^2.3.1" +"@rollup/rollup-android-arm-eabi@4.18.0": + version "4.18.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.18.0.tgz#bbd0e616b2078cd2d68afc9824d1fadb2f2ffd27" + integrity sha512-Tya6xypR10giZV1XzxmH5wr25VcZSncG0pZIjfePT0OVBvqNEurzValetGNarVrGiq66EBVAFn15iYX4w6FKgQ== + +"@rollup/rollup-android-arm64@4.18.0": + version "4.18.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.18.0.tgz#97255ef6384c5f73f4800c0de91f5f6518e21203" + integrity sha512-avCea0RAP03lTsDhEyfy+hpfr85KfyTctMADqHVhLAF3MlIkq83CP8UfAHUssgXTYd+6er6PaAhx/QGv4L1EiA== + +"@rollup/rollup-darwin-arm64@4.18.0": + version "4.18.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.18.0.tgz#b6dd74e117510dfe94541646067b0545b42ff096" + integrity sha512-IWfdwU7KDSm07Ty0PuA/W2JYoZ4iTj3TUQjkVsO/6U+4I1jN5lcR71ZEvRh52sDOERdnNhhHU57UITXz5jC1/w== + +"@rollup/rollup-darwin-x64@4.18.0": + version "4.18.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.18.0.tgz#e07d76de1cec987673e7f3d48ccb8e106d42c05c" + integrity sha512-n2LMsUz7Ynu7DoQrSQkBf8iNrjOGyPLrdSg802vk6XT3FtsgX6JbE8IHRvposskFm9SNxzkLYGSq9QdpLYpRNA== + +"@rollup/rollup-linux-arm-gnueabihf@4.18.0": + version "4.18.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.18.0.tgz#9f1a6d218b560c9d75185af4b8bb42f9f24736b8" + integrity sha512-C/zbRYRXFjWvz9Z4haRxcTdnkPt1BtCkz+7RtBSuNmKzMzp3ZxdM28Mpccn6pt28/UWUCTXa+b0Mx1k3g6NOMA== + +"@rollup/rollup-linux-arm-musleabihf@4.18.0": + version "4.18.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.18.0.tgz#53618b92e6ffb642c7b620e6e528446511330549" + integrity sha512-l3m9ewPgjQSXrUMHg93vt0hYCGnrMOcUpTz6FLtbwljo2HluS4zTXFy2571YQbisTnfTKPZ01u/ukJdQTLGh9A== + +"@rollup/rollup-linux-arm64-gnu@4.18.0": + version "4.18.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.18.0.tgz#99a7ba5e719d4f053761a698f7b52291cefba577" + integrity sha512-rJ5D47d8WD7J+7STKdCUAgmQk49xuFrRi9pZkWoRD1UeSMakbcepWXPF8ycChBoAqs1pb2wzvbY6Q33WmN2ftw== + +"@rollup/rollup-linux-arm64-musl@4.18.0": + version "4.18.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.18.0.tgz#f53db99a45d9bc00ce94db8a35efa7c3c144a58c" + integrity sha512-be6Yx37b24ZwxQ+wOQXXLZqpq4jTckJhtGlWGZs68TgdKXJgw54lUUoFYrg6Zs/kjzAQwEwYbp8JxZVzZLRepQ== + +"@rollup/rollup-linux-powerpc64le-gnu@4.18.0": + version "4.18.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.18.0.tgz#cbb0837408fe081ce3435cf3730e090febafc9bf" + integrity sha512-hNVMQK+qrA9Todu9+wqrXOHxFiD5YmdEi3paj6vP02Kx1hjd2LLYR2eaN7DsEshg09+9uzWi2W18MJDlG0cxJA== + +"@rollup/rollup-linux-riscv64-gnu@4.18.0": + version "4.18.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.18.0.tgz#8ed09c1d1262ada4c38d791a28ae0fea28b80cc9" + integrity sha512-ROCM7i+m1NfdrsmvwSzoxp9HFtmKGHEqu5NNDiZWQtXLA8S5HBCkVvKAxJ8U+CVctHwV2Gb5VUaK7UAkzhDjlg== + +"@rollup/rollup-linux-s390x-gnu@4.18.0": + version "4.18.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.18.0.tgz#938138d3c8e0c96f022252a28441dcfb17afd7ec" + integrity sha512-0UyyRHyDN42QL+NbqevXIIUnKA47A+45WyasO+y2bGJ1mhQrfrtXUpTxCOrfxCR4esV3/RLYyucGVPiUsO8xjg== + +"@rollup/rollup-linux-x64-gnu@4.18.0": + version "4.18.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.18.0.tgz#1a7481137a54740bee1ded4ae5752450f155d942" + integrity sha512-xuglR2rBVHA5UsI8h8UbX4VJ470PtGCf5Vpswh7p2ukaqBGFTnsfzxUBetoWBWymHMxbIG0Cmx7Y9qDZzr648w== + +"@rollup/rollup-linux-x64-musl@4.18.0": + version "4.18.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.18.0.tgz#f1186afc601ac4f4fc25fac4ca15ecbee3a1874d" + integrity sha512-LKaqQL9osY/ir2geuLVvRRs+utWUNilzdE90TpyoX0eNqPzWjRm14oMEE+YLve4k/NAqCdPkGYDaDF5Sw+xBfg== + +"@rollup/rollup-win32-arm64-msvc@4.18.0": + version "4.18.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.18.0.tgz#ed6603e93636a96203c6915be4117245c1bd2daf" + integrity sha512-7J6TkZQFGo9qBKH0pk2cEVSRhJbL6MtfWxth7Y5YmZs57Pi+4x6c2dStAUvaQkHQLnEQv1jzBUW43GvZW8OFqA== + +"@rollup/rollup-win32-ia32-msvc@4.18.0": + version "4.18.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.18.0.tgz#14e0b404b1c25ebe6157a15edb9c46959ba74c54" + integrity sha512-Txjh+IxBPbkUB9+SXZMpv+b/vnTEtFyfWZgJ6iyCmt2tdx0OF5WhFowLmnh8ENGNpfUlUZkdI//4IEmhwPieNg== + +"@rollup/rollup-win32-x64-msvc@4.18.0": + version "4.18.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.18.0.tgz#5d694d345ce36b6ecf657349e03eb87297e68da4" + integrity sha512-UOo5FdvOL0+eIVTgS4tIdbW+TtnBLWg1YBCcU2KWM7nuNwRz9bksDX1bekJJCpu25N1DVWaCwnT39dVQxzqS8g== + "@scure/base@~1.1.0": version "1.1.1" resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.1.1.tgz#ebb651ee52ff84f420097055f4bf46cfba403938" @@ -1568,7 +1648,7 @@ dependencies: "@types/node" "*" -"@types/estree@*", "@types/estree@^1.0.0": +"@types/estree@*", "@types/estree@1.0.5", "@types/estree@^1.0.0": version "1.0.5" resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.5.tgz#a6ce3e556e00fd9895dd872dd172ad0d4bd687f4" integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw== @@ -7510,6 +7590,31 @@ rlp@^2.2.3, rlp@^2.2.4: dependencies: bn.js "^5.2.0" +rollup@^4.18.0: + version "4.18.0" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.18.0.tgz#497f60f0c5308e4602cf41136339fbf87d5f5dda" + integrity sha512-QmJz14PX3rzbJCN1SG4Xe/bAAX2a6NpCP8ab2vfu2GiUr8AQcr2nCV/oEO3yneFarB67zk8ShlIyWb2LGTb3Sg== + dependencies: + "@types/estree" "1.0.5" + optionalDependencies: + "@rollup/rollup-android-arm-eabi" "4.18.0" + "@rollup/rollup-android-arm64" "4.18.0" + "@rollup/rollup-darwin-arm64" "4.18.0" + "@rollup/rollup-darwin-x64" "4.18.0" + "@rollup/rollup-linux-arm-gnueabihf" "4.18.0" + "@rollup/rollup-linux-arm-musleabihf" "4.18.0" + "@rollup/rollup-linux-arm64-gnu" "4.18.0" + "@rollup/rollup-linux-arm64-musl" "4.18.0" + "@rollup/rollup-linux-powerpc64le-gnu" "4.18.0" + "@rollup/rollup-linux-riscv64-gnu" "4.18.0" + "@rollup/rollup-linux-s390x-gnu" "4.18.0" + "@rollup/rollup-linux-x64-gnu" "4.18.0" + "@rollup/rollup-linux-x64-musl" "4.18.0" + "@rollup/rollup-win32-arm64-msvc" "4.18.0" + "@rollup/rollup-win32-ia32-msvc" "4.18.0" + "@rollup/rollup-win32-x64-msvc" "4.18.0" + fsevents "~2.3.2" + run-async@^2.2.0: version "2.4.1" resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" From 20819190dd019f98e38c39e508e4ce43ca68f42a Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Mon, 3 Jun 2024 21:14:18 +1000 Subject: [PATCH 121/273] bumped the deploy script number --- .../{097_withdraw_queue.js => 098_oeth_withdraw_queue.js} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename contracts/deploy/mainnet/{097_withdraw_queue.js => 098_oeth_withdraw_queue.js} (97%) diff --git a/contracts/deploy/mainnet/097_withdraw_queue.js b/contracts/deploy/mainnet/098_oeth_withdraw_queue.js similarity index 97% rename from contracts/deploy/mainnet/097_withdraw_queue.js rename to contracts/deploy/mainnet/098_oeth_withdraw_queue.js index dfd9e241af..196c0f6d1b 100644 --- a/contracts/deploy/mainnet/097_withdraw_queue.js +++ b/contracts/deploy/mainnet/098_oeth_withdraw_queue.js @@ -3,7 +3,7 @@ const { deploymentWithGovernanceProposal } = require("../../utils/deploy"); module.exports = deploymentWithGovernanceProposal( { - deployName: "097_withdraw_queue", + deployName: "098_oeth_withdraw_queue", forceDeploy: false, //forceSkip: true, reduceQueueTime: true, From 6ecf222045ee300d86f9004ee778dd194170970f Mon Sep 17 00:00:00 2001 From: Nick Addison Date: Tue, 4 Jun 2024 08:34:13 +1000 Subject: [PATCH 122/273] Cap the validators a Native Staking Strategy can hold (#2087) * Added max validators check to Native Staking Strategy --- .../NativeStaking/NativeStakingSSVStrategy.sol | 5 ++++- .../NativeStaking/ValidatorAccountant.sol | 7 +++++-- .../NativeStaking/ValidatorRegistrator.sol | 11 ++++++++++- contracts/deploy/deployActions.js | 2 ++ .../deploy/holesky/012_upgrade_strategy.js | 18 ++++++++++++++++++ .../deploy/mainnet/097_native_ssv_staking.js | 1 + 6 files changed, 40 insertions(+), 4 deletions(-) create mode 100644 contracts/deploy/holesky/012_upgrade_strategy.js diff --git a/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol b/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol index a26b110f29..f209fd36c1 100644 --- a/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol +++ b/contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol @@ -74,6 +74,7 @@ contract NativeStakingSSVStrategy is /// @param _wethAddress Address of the Erc20 WETH Token contract /// @param _ssvToken Address of the Erc20 SSV Token contract /// @param _ssvNetwork Address of the SSV Network contract + /// @param _maxValidators Maximum number of validators that can be registered in the strategy /// @param _feeAccumulator Address of the fee accumulator receiving execution layer validator rewards /// @param _beaconChainDepositContract Address of the beacon chain deposit contract constructor( @@ -81,6 +82,7 @@ contract NativeStakingSSVStrategy is address _wethAddress, address _ssvToken, address _ssvNetwork, + uint256 _maxValidators, address _feeAccumulator, address _beaconChainDepositContract ) @@ -89,7 +91,8 @@ contract NativeStakingSSVStrategy is _wethAddress, _baseConfig.vaultAddress, _beaconChainDepositContract, - _ssvNetwork + _ssvNetwork, + _maxValidators ) { SSV_TOKEN_ADDRESS = _ssvToken; diff --git a/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol b/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol index 441d046ad2..b5afc86798 100644 --- a/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol +++ b/contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol @@ -50,17 +50,20 @@ abstract contract ValidatorAccountant is ValidatorRegistrator { /// @param _vaultAddress Address of the Vault /// @param _beaconChainDepositContract Address of the beacon chain deposit contract /// @param _ssvNetwork Address of the SSV Network contract + /// @param _maxValidators Maximum number of validators that can be registered in the strategy constructor( address _wethAddress, address _vaultAddress, address _beaconChainDepositContract, - address _ssvNetwork + address _ssvNetwork, + uint256 _maxValidators ) ValidatorRegistrator( _wethAddress, _vaultAddress, _beaconChainDepositContract, - _ssvNetwork + _ssvNetwork, + _maxValidators ) {} diff --git a/contracts/contracts/strategies/NativeStaking/ValidatorRegistrator.sol b/contracts/contracts/strategies/NativeStaking/ValidatorRegistrator.sol index 2dc590f69f..1ef7acf4db 100644 --- a/contracts/contracts/strategies/NativeStaking/ValidatorRegistrator.sol +++ b/contracts/contracts/strategies/NativeStaking/ValidatorRegistrator.sol @@ -28,6 +28,8 @@ abstract contract ValidatorRegistrator is Governable, Pausable { address public immutable SSV_NETWORK_ADDRESS; /// @notice Address of the OETH Vault proxy contract address public immutable VAULT_ADDRESS; + /// @notice Maximum number of validators that can be registered in this strategy + uint256 public immutable MAX_VALIDATORS; /// @notice Address of the registrator - allowed to register, exit and remove validators address public validatorRegistrator; @@ -109,16 +111,19 @@ abstract contract ValidatorRegistrator is Governable, Pausable { /// @param _vaultAddress Address of the Vault /// @param _beaconChainDepositContract Address of the beacon chain deposit contract /// @param _ssvNetwork Address of the SSV Network contract + /// @param _maxValidators Maximum number of validators that can be registered in the strategy constructor( address _wethAddress, address _vaultAddress, address _beaconChainDepositContract, - address _ssvNetwork + address _ssvNetwork, + uint256 _maxValidators ) { WETH_TOKEN_ADDRESS = _wethAddress; BEACON_CHAIN_DEPOSIT_CONTRACT = _beaconChainDepositContract; SSV_NETWORK_ADDRESS = _ssvNetwork; VAULT_ADDRESS = _vaultAddress; + MAX_VALIDATORS = _maxValidators; } /// @notice Set the address of the registrator which can register, exit and remove validators @@ -163,6 +168,10 @@ abstract contract ValidatorRegistrator is Governable, Pausable { requiredETH <= IWETH9(WETH_TOKEN_ADDRESS).balanceOf(address(this)), "insufficient WETH" ); + require( + activeDepositedValidators + validators.length <= MAX_VALIDATORS, + "Max validators reached" + ); require( stakeETHTally + requiredETH <= stakeETHThreshold, diff --git a/contracts/deploy/deployActions.js b/contracts/deploy/deployActions.js index 7cb1faead7..63b7c9c8fd 100644 --- a/contracts/deploy/deployActions.js +++ b/contracts/deploy/deployActions.js @@ -854,6 +854,7 @@ const upgradeNativeStakingSSVStrategy = async () => { assetAddresses.WETH, // wethAddress assetAddresses.SSV, // ssvToken assetAddresses.SSVNetwork, // ssvNetwork + 600, // maxValidators cFeeAccumulatorProxy.address, // feeAccumulator assetAddresses.beaconChainDepositContract, // depositContractMock ] @@ -900,6 +901,7 @@ const deployNativeStakingSSVStrategy = async () => { assetAddresses.WETH, // wethAddress assetAddresses.SSV, // ssvToken assetAddresses.SSVNetwork, // ssvNetwork + 600, // maxValidators dFeeAccumulatorProxy.address, // feeAccumulator assetAddresses.beaconChainDepositContract, // depositContractMock ] diff --git a/contracts/deploy/holesky/012_upgrade_strategy.js b/contracts/deploy/holesky/012_upgrade_strategy.js new file mode 100644 index 0000000000..36d68e1e65 --- /dev/null +++ b/contracts/deploy/holesky/012_upgrade_strategy.js @@ -0,0 +1,18 @@ +const { upgradeNativeStakingSSVStrategy } = require("../deployActions"); + +const mainExport = async () => { + console.log("Running 012 deployment on Holesky..."); + + console.log("Upgrading native staking strategy"); + await upgradeNativeStakingSSVStrategy(); + + console.log("Running 012 deployment done"); + return true; +}; + +mainExport.id = "012_upgrade_strategy"; +mainExport.tags = []; +mainExport.dependencies = []; +mainExport.skip = () => false; + +module.exports = mainExport; diff --git a/contracts/deploy/mainnet/097_native_ssv_staking.js b/contracts/deploy/mainnet/097_native_ssv_staking.js index 64fa655a42..e00636c4aa 100644 --- a/contracts/deploy/mainnet/097_native_ssv_staking.js +++ b/contracts/deploy/mainnet/097_native_ssv_staking.js @@ -54,6 +54,7 @@ module.exports = deploymentWithGovernanceProposal( addresses.mainnet.WETH, // wethAddress addresses.mainnet.SSV, // ssvToken addresses.mainnet.SSVNetwork, // ssvNetwork + 600, // maxValidators dFeeAccumulatorProxy.address, // feeAccumulator addresses.mainnet.beaconChainDepositContract, // beacon chain deposit contract ] From c807e8d52fc79319bb0efa3977033d287868455c Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Tue, 4 Jun 2024 10:03:20 +1000 Subject: [PATCH 123/273] don't format Defender Action code in dist folder --- contracts/.prettierignore | 1 + 1 file changed, 1 insertion(+) diff --git a/contracts/.prettierignore b/contracts/.prettierignore index 69d1888e21..79cdd3d840 100644 --- a/contracts/.prettierignore +++ b/contracts/.prettierignore @@ -1,2 +1,3 @@ scripts/compensation/forkDeployment.js coverage +dist \ No newline at end of file From 7f54c949cd43e9ce6a6a5af46e5097cc9c2a1924 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Tue, 4 Jun 2024 15:10:50 +1000 Subject: [PATCH 124/273] Deployed latest NativeStakingSSVStrategy contract to Holesky --- .../deployments/holesky/.migrations.json | 3 +- .../holesky/NativeStakingSSVStrategy.json | 157 ++++++++++++------ .../47ae51f49254a864e8595718d22928c8.json | 107 ++++++++++++ 3 files changed, 211 insertions(+), 56 deletions(-) create mode 100644 contracts/deployments/holesky/solcInputs/47ae51f49254a864e8595718d22928c8.json diff --git a/contracts/deployments/holesky/.migrations.json b/contracts/deployments/holesky/.migrations.json index 662b06449b..620a172807 100644 --- a/contracts/deployments/holesky/.migrations.json +++ b/contracts/deployments/holesky/.migrations.json @@ -9,5 +9,6 @@ "008_upgrade_strategy": 1715341541, "009_upgrade_strategy": 1716360052, "010_upgrade_strategy": 1716890877, - "011_upgrade_strategy": 1717309951 + "011_upgrade_strategy": 1717309951, + "012_upgrade_strategy": 1717477122 } \ No newline at end of file diff --git a/contracts/deployments/holesky/NativeStakingSSVStrategy.json b/contracts/deployments/holesky/NativeStakingSSVStrategy.json index a188d99206..d242b9baec 100644 --- a/contracts/deployments/holesky/NativeStakingSSVStrategy.json +++ b/contracts/deployments/holesky/NativeStakingSSVStrategy.json @@ -1,5 +1,5 @@ { - "address": "0x66629294466DaD7173c44c813F89deC17226BB18", + "address": "0x72045988ac7f8e2c16963d218CD556aB4cE5B554", "abi": [ { "inputs": [ @@ -35,6 +35,11 @@ "name": "_ssvNetwork", "type": "address" }, + { + "internalType": "uint256", + "name": "_maxValidators", + "type": "uint256" + }, { "internalType": "address", "name": "_feeAccumulator", @@ -555,6 +560,19 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "MAX_VALIDATORS", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "MIN_FIX_ACCOUNTING_CADENCE", @@ -732,7 +750,7 @@ }, { "internalType": "uint256", - "name": "amount", + "name": "ssvAmount", "type": "uint256" }, { @@ -1006,7 +1024,7 @@ }, { "internalType": "uint256", - "name": "amount", + "name": "ssvAmount", "type": "uint256" }, { @@ -1443,34 +1461,34 @@ "type": "receive" } ], - "transactionHash": "0xf97b37d50f68cd13725be2f6e3ac057240fb6a8f3df3c13829286aa39b713e38", + "transactionHash": "0x9b8413b8e94da985aa27ae6561dc8380f6f7585042516e8fd99f3616c061430c", "receipt": { "to": null, "from": "0x1b94CA50D3Ad9f8368851F8526132272d1a5028C", - "contractAddress": "0x66629294466DaD7173c44c813F89deC17226BB18", - "transactionIndex": 99, - "gasUsed": "4363797", - "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000000004000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000010000000000010000000000000000000000000000000000000000020000400000000000000000000000000000000000000000000000000000000000000", - "blockHash": "0x8054d9658e27d7ec653db16ec011178c1bebe788407cbbc36b0ea2168187dad6", - "transactionHash": "0xf97b37d50f68cd13725be2f6e3ac057240fb6a8f3df3c13829286aa39b713e38", + "contractAddress": "0x72045988ac7f8e2c16963d218CD556aB4cE5B554", + "transactionIndex": 11, + "gasUsed": "4403238", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000080020000000000000000000800000000000002000000000000000000000004000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000010000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x52da6ae82a05a0972c82c551a902106962cfa41102bccf0896822524fc76a2f6", + "transactionHash": "0x9b8413b8e94da985aa27ae6561dc8380f6f7585042516e8fd99f3616c061430c", "logs": [ { - "transactionIndex": 99, - "blockNumber": 1656029, - "transactionHash": "0xf97b37d50f68cd13725be2f6e3ac057240fb6a8f3df3c13829286aa39b713e38", - "address": "0x66629294466DaD7173c44c813F89deC17226BB18", + "transactionIndex": 11, + "blockNumber": 1668064, + "transactionHash": "0x9b8413b8e94da985aa27ae6561dc8380f6f7585042516e8fd99f3616c061430c", + "address": "0x72045988ac7f8e2c16963d218CD556aB4cE5B554", "topics": [ "0xc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000001b94ca50d3ad9f8368851f8526132272d1a5028c" ], "data": "0x", - "logIndex": 191, - "blockHash": "0x8054d9658e27d7ec653db16ec011178c1bebe788407cbbc36b0ea2168187dad6" + "logIndex": 416, + "blockHash": "0x52da6ae82a05a0972c82c551a902106962cfa41102bccf0896822524fc76a2f6" } ], - "blockNumber": 1656029, - "cumulativeGasUsed": "18040571", + "blockNumber": 1668064, + "cumulativeGasUsed": "19865050", "status": 1, "byzantium": true }, @@ -1482,14 +1500,15 @@ "0x94373a4919B3240D86eA41593D5eBa789FEF3848", "0xad45A78180961079BFaeEe349704F411dfF947C6", "0x38A4794cCEd47d3baf7370CcC43B560D3a1beEFA", + 600, "0x65a289f4BF934c964C942eFF6E6F83b6481BE550", "0x4242424242424242424242424242424242424242" ], - "numDeployments": 6, - "solcInputHash": "2f3753d8399260cc3346b6a657c1cb6c", - "metadata": "{\"compiler\":{\"version\":\"0.8.7+commit.e28d00a7\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"platformAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"vaultAddress\",\"type\":\"address\"}],\"internalType\":\"struct InitializableAbstractStrategy.BaseStrategyConfig\",\"name\":\"_baseConfig\",\"type\":\"tuple\"},{\"internalType\":\"address\",\"name\":\"_wethAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_ssvToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_ssvNetwork\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_feeAccumulator\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_beaconChainDepositContract\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"AccountingConsensusRewards\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"noOfValidators\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"remainingValidators\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"wethSentToVault\",\"type\":\"uint256\"}],\"name\":\"AccountingFullyWithdrawnValidator\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"validatorsDelta\",\"type\":\"int256\"},{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"consensusRewardsDelta\",\"type\":\"int256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"wethToVault\",\"type\":\"uint256\"}],\"name\":\"AccountingManuallyFixed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"remainingValidators\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"wethSentToVault\",\"type\":\"uint256\"}],\"name\":\"AccountingValidatorSlashed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"Deposit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"pubKeyHash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"pubKey\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"withdrawal_credentials\",\"type\":\"bytes\"}],\"name\":\"ETHStaked\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"start\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"end\",\"type\":\"uint256\"}],\"name\":\"FuseIntervalUpdated\",\"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\":\"address\",\"name\":\"_oldHarvesterAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_newHarvesterAddress\",\"type\":\"address\"}],\"name\":\"HarvesterAddressesUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"}],\"name\":\"PTokenAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"}],\"name\":\"PTokenRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Paused\",\"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\":true,\"internalType\":\"address\",\"name\":\"newAddress\",\"type\":\"address\"}],\"name\":\"RegistratorChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"_oldAddresses\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"_newAddresses\",\"type\":\"address[]\"}],\"name\":\"RewardTokenAddressesUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"rewardToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"RewardTokenCollected\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"pubKeyHash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"pubKey\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"}],\"name\":\"SSVValidatorExitCompleted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"pubKeyHash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"pubKey\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"}],\"name\":\"SSVValidatorExitInitiated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"pubKeyHash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"pubKey\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"}],\"name\":\"SSVValidatorRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"StakeETHTallyReset\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"StakeETHThresholdChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newAddress\",\"type\":\"address\"}],\"name\":\"StakingMonitorChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Unpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"Withdrawal\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"BEACON_CHAIN_DEPOSIT_CONTRACT\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_ACCUMULATOR_ADDRESS\",\"outputs\":[{\"internalType\":\"address payable\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MAX_STAKE\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MIN_FIX_ACCOUNTING_CADENCE\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"SSV_NETWORK_ADDRESS\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"SSV_TOKEN_ADDRESS\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"VAULT_ADDRESS\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"WETH_TOKEN_ADDRESS\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"activeDepositedValidators\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"assetToPToken\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"}],\"name\":\"checkBalance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"claimGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"collectRewardTokens\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"consensusRewards\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"depositAll\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"validatorCount\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"networkFeeIndex\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"index\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"active\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"internalType\":\"struct Cluster\",\"name\":\"cluster\",\"type\":\"tuple\"}],\"name\":\"depositSSV\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"depositedWethAccountedFor\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"doAccounting\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"accountingValid\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"publicKey\",\"type\":\"bytes\"},{\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"}],\"name\":\"exitSsvValidator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fuseIntervalEnd\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fuseIntervalStart\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRewardTokenAddresses\",\"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\":\"harvesterAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"_rewardTokenAddresses\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"_assets\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"_pTokens\",\"type\":\"address[]\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isGovernor\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastFixAccountingBlockNumber\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"int256\",\"name\":\"_validatorsDelta\",\"type\":\"int256\"},{\"internalType\":\"int256\",\"name\":\"_consensusRewardsDelta\",\"type\":\"int256\"},{\"internalType\":\"uint256\",\"name\":\"_ethToVaultAmount\",\"type\":\"uint256\"}],\"name\":\"manuallyFixAccounting\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"paused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"platformAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"publicKey\",\"type\":\"bytes\"},{\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"},{\"internalType\":\"bytes\",\"name\":\"sharesData\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"validatorCount\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"networkFeeIndex\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"index\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"active\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"internalType\":\"struct Cluster\",\"name\":\"cluster\",\"type\":\"tuple\"}],\"name\":\"registerSsvValidator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_assetIndex\",\"type\":\"uint256\"}],\"name\":\"removePToken\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"publicKey\",\"type\":\"bytes\"},{\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"validatorCount\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"networkFeeIndex\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"index\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"active\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"internalType\":\"struct Cluster\",\"name\":\"cluster\",\"type\":\"tuple\"}],\"name\":\"removeSsvValidator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"resetStakeETHTally\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"rewardTokenAddresses\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"safeApproveAllTokens\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_fuseIntervalStart\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_fuseIntervalEnd\",\"type\":\"uint256\"}],\"name\":\"setFuseInterval\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_harvesterAddress\",\"type\":\"address\"}],\"name\":\"setHarvesterAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"}],\"name\":\"setPTokenAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"setRegistrator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"_rewardTokenAddresses\",\"type\":\"address[]\"}],\"name\":\"setRewardTokenAddresses\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"setStakeETHThreshold\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"setStakingMonitor\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"stakeETHTally\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"stakeETHThreshold\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"pubkey\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"depositDataRoot\",\"type\":\"bytes32\"}],\"internalType\":\"struct ValidatorStakeData[]\",\"name\":\"validators\",\"type\":\"tuple[]\"}],\"name\":\"stakeEth\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"stakingMonitor\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"}],\"name\":\"supportsAsset\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"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\":\"validatorRegistrator\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"validatorsStates\",\"outputs\":[{\"internalType\":\"enum ValidatorRegistrator.VALIDATOR_STATE\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"vaultAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"withdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdrawAll\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"author\":\"Origin Protocol Inc\",\"details\":\"This contract handles WETH and ETH and in some operations interchanges between the two. Any WETH that is on the contract across multiple blocks (and not just transitory within a transaction) is considered an asset. Meaning deposits increase the balance of the asset and withdrawal decrease it. As opposed to all our other strategies the WETH doesn't immediately get deposited into an underlying strategy and can be present across multiple blocks waiting to be unwrapped to ETH and staked to validators. This separation of WETH and ETH is required since the rewards (reward token) is also in ETH. To simplify the accounting of WETH there is another difference in behavior compared to the other strategies. To withdraw WETH asset - exit message is posted to validators and the ETH hits this contract with multiple days delay. In order to simplify the WETH accounting upon detection of such an event the ValidatorAccountant immediately wraps ETH to WETH and sends it to the Vault. On the other hand any ETH on the contract (across multiple blocks) is there either: - as a result of already accounted for consensus rewards - as a result of not yet accounted for consensus rewards - as a results of not yet accounted for full validator withdrawals (or validator slashes) Even though the strategy assets and rewards are a very similar asset the consensus layer rewards and the execution layer rewards are considered rewards and those are dripped to the Vault over a configurable time interval and not immediately.\",\"kind\":\"dev\",\"methods\":{\"checkBalance(address)\":{\"params\":{\"_asset\":\"Address of weth asset\"},\"returns\":{\"balance\":\" Total value of (W)ETH\"}},\"constructor\":{\"params\":{\"_baseConfig\":\"Base strategy config with platformAddress (ERC-4626 Vault contract), eg sfrxETH or sDAI, and vaultAddress (OToken Vault contract), eg VaultProxy or OETHVaultProxy\",\"_beaconChainDepositContract\":\"Address of the beacon chain deposit contract\",\"_feeAccumulator\":\"Address of the fee accumulator receiving execution layer validator rewards\",\"_ssvNetwork\":\"Address of the SSV Network contract\",\"_ssvToken\":\"Address of the Erc20 SSV Token contract\",\"_wethAddress\":\"Address of the Erc20 WETH Token contract\"}},\"deposit(address,uint256)\":{\"params\":{\"_amount\":\"Amount of assets that were transferred to the strategy by the vault.\",\"_asset\":\"Address of asset to deposit. Has to be WETH.\"}},\"depositSSV(uint64[],uint256,(uint32,uint64,uint64,bool,uint256))\":{\"details\":\"A SSV cluster is defined by the SSVOwnerAddress and the set of operatorIds. uses \\\"onlyStrategist\\\" modifier so continuous front-running can't DOS our maintenance service that tries to top up SSV tokens.\",\"params\":{\"cluster\":\"The SSV cluster details that must be derived from emitted events from the SSVNetwork contract.\"}},\"doAccounting()\":{\"details\":\"This function could in theory be permission-less but lets allow only the Registrator (Defender Action) to call it for now.\",\"returns\":{\"accountingValid\":\"true if accounting was successful, false if fuse is blown\"}},\"getRewardTokenAddresses()\":{\"returns\":{\"_0\":\"address[] the reward token addresses.\"}},\"initialize(address[],address[],address[])\":{\"params\":{\"_assets\":\"Addresses of initial supported assets\",\"_pTokens\":\"Platform Token corresponding addresses\",\"_rewardTokenAddresses\":\"Address of reward token for platform\"}},\"manuallyFixAccounting(int256,int256,uint256)\":{\"details\":\"There is a case when a validator(s) gets slashed so much that the eth swept from the beacon chain enters the fuse area and there are no consensus rewards on the contract to \\\"dip into\\\"/use. To increase the amount of unaccounted ETH over the fuse end interval we need to reduce the amount of active deposited validators and immediately send WETH to the vault, so it doesn't interfere with further accounting.\",\"params\":{\"_consensusRewardsDelta\":\"adjust the accounted for consensus rewards up or down\",\"_ethToVaultAmount\":\"the amount of ETH that gets wrapped into WETH and sent to the Vault\",\"_validatorsDelta\":\"adjust the active validators by up to plus three or minus three\"}},\"paused()\":{\"details\":\"Returns true if the contract is paused, and false otherwise.\"},\"removePToken(uint256)\":{\"params\":{\"_assetIndex\":\"Index of the asset to be removed\"}},\"setHarvesterAddress(address)\":{\"params\":{\"_harvesterAddress\":\"Address of the harvester contract.\"}},\"setPTokenAddress(address,address)\":{\"params\":{\"_asset\":\"Address for the asset\",\"_pToken\":\"Address for the corresponding platform token\"}},\"setRewardTokenAddresses(address[])\":{\"params\":{\"_rewardTokenAddresses\":\"Array of reward token addresses\"}},\"stakeEth((bytes,bytes,bytes32)[])\":{\"params\":{\"validators\":\"A list of validator data needed to stake. The `ValidatorStakeData` struct contains the pubkey, signature and depositDataRoot. Only the registrator can call this function.\"}},\"supportsAsset(address)\":{\"params\":{\"_asset\":\"The address of the asset token.\"}},\"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\"}},\"withdraw(address,address,uint256)\":{\"params\":{\"_amount\":\"Amount of WETH to withdraw\",\"_asset\":\"WETH to withdraw\",\"_recipient\":\"Address to receive withdrawn assets\"}}},\"stateVariables\":{\"FEE_ACCUMULATOR_ADDRESS\":{\"details\":\"this address will receive Execution layer rewards - These are rewards earned for executing transactions on the Ethereum network as part of block proposals. They include priority fees (fees paid by users for their transactions to be included) and MEV rewards (rewards for arranging transactions in a way that benefits the validator).\"},\"depositedWethAccountedFor\":{\"details\":\"This contract receives WETH as the deposit asset, but unlike other strategies doesn't immediately deposit it to an underlying platform. Rather a special privilege account stakes it to the validators. For that reason calling WETH.balanceOf(this) in a deposit function can contain WETH that has just been deposited and also WETH that has previously been deposited. To keep a correct count we need to keep track of WETH that has already been accounted for. This value represents the amount of WETH balance of this contract that has already been accounted for by the deposit events. It is important to note that this variable is not concerned with WETH that is a result of full/partial withdrawal of the validators. It is strictly concerned with WETH that has been deposited and is waiting to be staked.\"}},\"title\":\"Native Staking SSV Strategy\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"BEACON_CHAIN_DEPOSIT_CONTRACT()\":{\"notice\":\"The address of the beacon chain deposit contract\"},\"FEE_ACCUMULATOR_ADDRESS()\":{\"notice\":\"Fee collector address\"},\"MAX_STAKE()\":{\"notice\":\"The maximum amount of ETH that can be staked by a validator\"},\"MIN_FIX_ACCOUNTING_CADENCE()\":{\"notice\":\"The minimum amount of blocks that need to pass between two calls to manuallyFixAccounting\"},\"SSV_NETWORK_ADDRESS()\":{\"notice\":\"The address of the SSV Network contract used to interface with\"},\"SSV_TOKEN_ADDRESS()\":{\"notice\":\"SSV ERC20 token that serves as a payment for operating SSV validators\"},\"VAULT_ADDRESS()\":{\"notice\":\"Address of the OETH Vault proxy contract\"},\"WETH_TOKEN_ADDRESS()\":{\"notice\":\"The address of the Wrapped ETH (WETH) token contract\"},\"activeDepositedValidators()\":{\"notice\":\"The number of validators that have 32 (!) ETH actively deposited. When a new deposit to a validator happens this number increases, when a validator exit is detected this number decreases.\"},\"assetToPToken(address)\":{\"notice\":\"asset => pToken (Platform Specific Token Address)\"},\"checkBalance(address)\":{\"notice\":\"Returns the total value of (W)ETH that is staked to the validators and WETH deposits that are still to be staked. This does not include ETH from consensus rewards sitting in this strategy or ETH from MEV rewards in the FeeAccumulator. These rewards are harvested and sent to the Dripper so will eventually be sent to the Vault as WETH.\"},\"claimGovernance()\":{\"notice\":\"Claim Governance of the contract to a new account (`newGovernor`). Can only be called by the new Governor.\"},\"collectRewardTokens()\":{\"notice\":\"Collect accumulated reward token and send to Vault.\"},\"consensusRewards()\":{\"notice\":\"Keeps track of the total consensus rewards swept from the beacon chain\"},\"deposit(address,uint256)\":{\"notice\":\"Unlike other strategies, this does not deposit assets into the underlying platform. It just checks the asset is WETH and emits the Deposit event. To deposit WETH into validators `registerSsvValidator` and `stakeEth` must be used. Will NOT revert if the strategy is paused from an accounting failure.\"},\"depositAll()\":{\"notice\":\"Unlike other strategies, this does not deposit assets into the underlying platform. It just emits the Deposit event. To deposit WETH into validators `registerSsvValidator` and `stakeEth` must be used. Will NOT revert if the strategy is paused from an accounting failure.\"},\"depositSSV(uint64[],uint256,(uint32,uint64,uint64,bool,uint256))\":{\"notice\":\"Deposits more SSV Tokens to the SSV Network contract which is used to pay the SSV Operators.\"},\"doAccounting()\":{\"notice\":\"This notion page offers a good explanation of how the accounting functions https://www.notion.so/originprotocol/Limited-simplified-native-staking-accounting-67a217c8420d40678eb943b9da0ee77d In short, after dividing by 32, if the ETH remaining on the contract falls between 0 and fuseIntervalStart, the accounting function will treat that ETH as Beacon chain consensus rewards. On the contrary, if after dividing by 32, the ETH remaining on the contract falls between fuseIntervalEnd and 32, the accounting function will treat that as a validator slashing.Perform the accounting attributing beacon chain ETH to either full or partial withdrawals. Returns true when accounting is valid and fuse isn't \\\"blown\\\". Returns false when fuse is blown.\"},\"exitSsvValidator(bytes,uint64[])\":{\"notice\":\"Exit a validator from the Beacon chain. The staked ETH will eventually swept to this native staking strategy. Only the registrator can call this function.\"},\"fuseIntervalEnd()\":{\"notice\":\"end of fuse interval\"},\"fuseIntervalStart()\":{\"notice\":\"start of fuse interval\"},\"getRewardTokenAddresses()\":{\"notice\":\"Get the reward token addresses.\"},\"governor()\":{\"notice\":\"Returns the address of the current Governor.\"},\"harvesterAddress()\":{\"notice\":\"Address of the Harvester contract allowed to collect reward tokens\"},\"initialize(address[],address[],address[])\":{\"notice\":\"initialize function, to set up initial internal state\"},\"isGovernor()\":{\"notice\":\"Returns true if the caller is the current Governor.\"},\"lastFixAccountingBlockNumber()\":{\"notice\":\"last block number manuallyFixAccounting has been called\"},\"manuallyFixAccounting(int256,int256,uint256)\":{\"notice\":\"Allow the Strategist to fix the accounting of this strategy and unpause.\"},\"platformAddress()\":{\"notice\":\"Address of the underlying platform\"},\"registerSsvValidator(bytes,uint64[],bytes,uint256,(uint32,uint64,uint64,bool,uint256))\":{\"notice\":\"Registers a new validator in the SSV Cluster. Only the registrator can call this function.\"},\"removePToken(uint256)\":{\"notice\":\"Remove a supported asset by passing its index. This method can only be called by the system Governor\"},\"removeSsvValidator(bytes,uint64[],(uint32,uint64,uint64,bool,uint256))\":{\"notice\":\"Remove a validator from the SSV Cluster. Make sure `exitSsvValidator` is called before and the validate has exited the Beacon chain. If removed before the validator has exited the beacon chain will result in the validator being slashed. Only the registrator can call this function.\"},\"resetStakeETHTally()\":{\"notice\":\"Reset the stakeETHTally\"},\"rewardTokenAddresses(uint256)\":{\"notice\":\"Address of the reward tokens. eg CRV, BAL, CVX, AURA\"},\"safeApproveAllTokens()\":{\"notice\":\"Approves the SSV Network contract to transfer SSV tokens for deposits\"},\"setFuseInterval(uint256,uint256)\":{\"notice\":\"set fuse interval values\"},\"setHarvesterAddress(address)\":{\"notice\":\"Set the Harvester contract that can collect rewards.\"},\"setPTokenAddress(address,address)\":{\"notice\":\"Provide support for asset by passing its pToken address. This method can only be called by the system Governor\"},\"setRegistrator(address)\":{\"notice\":\"Set the address of the registrator which can register, exit and remove validators\"},\"setRewardTokenAddresses(address[])\":{\"notice\":\"Set the reward token addresses. Any old addresses will be overwritten.\"},\"setStakeETHThreshold(uint256)\":{\"notice\":\"Set the amount of ETH that can be staked before staking monitor\"},\"setStakingMonitor(address)\":{\"notice\":\"Set the address of the staking monitor that is allowed to reset stakeETHTally\"},\"stakeETHTally()\":{\"notice\":\"Amount of ETH that can has been staked since the last governor approval.\"},\"stakeETHThreshold()\":{\"notice\":\"Amount of ETH that can be staked before staking on the contract is suspended and the governor needs to approve further staking\"},\"stakeEth((bytes,bytes,bytes32)[])\":{\"notice\":\"Stakes WETH to the node validators\"},\"stakingMonitor()\":{\"notice\":\"The account that is allowed to modify stakeETHThreshold and reset stakeETHTally\"},\"supportsAsset(address)\":{\"notice\":\"Returns bool indicating whether asset is supported by strategy.\"},\"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 strategy contracts, i.e. mistaken sends.\"},\"validatorRegistrator()\":{\"notice\":\"Address of the registrator - allowed to register, exit and remove validators\"},\"validatorsStates(bytes32)\":{\"notice\":\"State of the validators keccak256(pubKey) => state\"},\"vaultAddress()\":{\"notice\":\"Address of the OToken vault\"},\"withdraw(address,address,uint256)\":{\"notice\":\"Withdraw WETH from this contract. Used only if some WETH for is lingering on the contract. That can happen when: - the deposit was not a multiple of 32 WETH - someone sent WETH directly to this contract Will NOT revert if the strategy is paused from an accounting failure.\"},\"withdrawAll()\":{\"notice\":\"transfer all WETH deposits back to the vault. This does not withdraw from the validators. That has to be done separately with the `exitSsvValidator` and `removeSsvValidator` operations. This does not withdraw any execution rewards from the FeeAccumulator or consensus rewards in this strategy. Any ETH in this strategy that was swept from a full validator withdrawal will not be withdrawn. ETH from full validator withdrawals is sent to the Vault using `doAccounting`. Will NOT revert if the strategy is paused from an accounting failure.\"}},\"notice\":\"Strategy to deploy funds into DVT validators powered by the SSV Network\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol\":\"NativeStakingSSVStrategy\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"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\",\"keccak256\":\"0xe68ed7fb8766ed1e888291f881e36b616037f852b37d96877045319ad298ba87\",\"license\":\"MIT\"},\"@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/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\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@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\",\"keccak256\":\"0xfaad496c1c944b6259b7dc70b4865eb1775d6402bc0c81b38a0b24d9f525ae37\",\"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/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\",\"keccak256\":\"0x598f90bdbc854250bbd5991426bfb43367207e64e33109c41aa8b54323fd8d8e\",\"license\":\"MIT\"},\"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 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 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 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\",\"keccak256\":\"0xbef02bd5257e61dec0a6be4b1531064a7fdfeb4043885443a1902fb5d1b23e1b\",\"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/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 function removeAsset(address _asset) external;\\n}\\n\",\"keccak256\":\"0xa03ba17b6224bec26290794760fc807e017260406037b4f812970701888e72c8\",\"license\":\"MIT\"},\"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\",\"keccak256\":\"0x05b7dce6c24d3cd4e48b5c6346d86e5e40ecc3291bcdf3f3ef091c98fc826519\",\"license\":\"MIT\"},\"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\\nimport { Governable } from \\\"../../governance/Governable.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 is Governable {\\n /// @notice The address of the Native Staking Strategy\\n address public immutable STRATEGY;\\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 }\\n\\n /**\\n * @dev Accept ETH\\n */\\n receive() external payable {}\\n}\\n\",\"keccak256\":\"0xb8fda3b87dc5d6f8aee4bf1d015a585211e5b5a319dfa4b0f4770e3f5a2d5939\",\"license\":\"MIT\"},\"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_ADDRESS;\\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 _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 address _feeAccumulator,\\n address _beaconChainDepositContract\\n )\\n InitializableAbstractStrategy(_baseConfig)\\n ValidatorAccountant(\\n _wethAddress,\\n _baseConfig.vaultAddress,\\n _beaconChainDepositContract,\\n _ssvNetwork\\n )\\n {\\n SSV_TOKEN_ADDRESS = _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 /// @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_TOKEN_ADDRESS).deposit{ value: ethRewards }();\\n\\n emit RewardTokenCollected(\\n harvesterAddress,\\n WETH_TOKEN_ADDRESS,\\n ethRewards\\n );\\n IERC20(WETH_TOKEN_ADDRESS).safeTransfer(\\n harvesterAddress,\\n ethRewards\\n );\\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_TOKEN_ADDRESS, \\\"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_TOKEN_ADDRESS).balanceOf(\\n address(this)\\n );\\n uint256 newWeth = wethBalance - depositedWethAccountedFor;\\n\\n if (newWeth > 0) {\\n depositedWethAccountedFor = wethBalance;\\n\\n _deposit(WETH_TOKEN_ADDRESS, newWeth);\\n }\\n }\\n\\n /// @notice Withdraw WETH from this contract. Used only if some WETH for is lingering on the contract. That\\n /// can happen when:\\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 _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 emit Withdrawal(_asset, address(0), _amount);\\n IERC20(_asset).safeTransfer(_recipient, _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_TOKEN_ADDRESS).balanceOf(\\n address(this)\\n );\\n if (wethBalance > 0) {\\n _withdraw(vaultAddress, WETH_TOKEN_ADDRESS, wethBalance);\\n }\\n }\\n\\n function _abstractSetPToken(address _asset, address) internal override {}\\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_TOKEN_ADDRESS, \\\"Unsupported asset\\\");\\n\\n balance =\\n // add the ETH that has been staked in validators\\n activeDepositedValidators *\\n 32 ether +\\n // add the WETH in the strategy from deposits that are still to be staked\\n IERC20(WETH_TOKEN_ADDRESS).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_TOKEN_ADDRESS;\\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_ADDRESS).approve(\\n SSV_NETWORK_ADDRESS,\\n type(uint256).max\\n );\\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 ||\\n msg.sender == WETH_TOKEN_ADDRESS,\\n \\\"eth not from allowed contracts\\\"\\n );\\n }\\n\\n function _wethWithdrawnToVault(uint256 _amount) internal override {\\n emit Withdrawal(WETH_TOKEN_ADDRESS, address(0), _amount);\\n }\\n\\n function _wethWithdrawnAndStaked(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 direclty\\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\",\"keccak256\":\"0x937ce31cd4b90ad532fdde874dc02eaf0a29a800c2c2292d2d6cb71afa75f32d\",\"license\":\"MIT\"},\"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 /// @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 MAX_STAKE = 32 ether;\\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 constructor(\\n address _wethAddress,\\n address _vaultAddress,\\n address _beaconChainDepositContract,\\n address _ssvNetwork\\n )\\n ValidatorRegistrator(\\n _wethAddress,\\n _vaultAddress,\\n _beaconChainDepositContract,\\n _ssvNetwork\\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 emit FuseIntervalUpdated(_fuseIntervalStart, _fuseIntervalEnd);\\n\\n fuseIntervalStart = _fuseIntervalStart;\\n fuseIntervalEnd = _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 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 >= MAX_STAKE) {\\n uint256 fullyWithdrawnValidators;\\n // safe since MAX_STAKE is hardcoded to 32ETH\\n unchecked {\\n // explicitly cast to uint256 as we want to round to a whole number of validators\\n fullyWithdrawnValidators = uint256(newSweptETH / MAX_STAKE);\\n }\\n activeDepositedValidators -= fullyWithdrawnValidators;\\n\\n uint256 wethToVault = MAX_STAKE * fullyWithdrawnValidators;\\n IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: wethToVault }();\\n // slither-disable-next-line unchecked-transfer\\n IWETH9(WETH_TOKEN_ADDRESS).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 < 32 ether, \\\"unexpected accounting\\\");\\n\\n // If no Beacon chain consensus rewards swept\\n if (ethRemaining == 0) {\\n // do nothing\\n return accountingValid;\\n }\\n // Beacon chain consensus rewards swept (partial validator withdrawals)\\n else if (ethRemaining < fuseIntervalStart) {\\n // solhint-disable-next-line reentrancy\\n consensusRewards += ethRemaining;\\n emit AccountingConsensusRewards(ethRemaining);\\n }\\n // Beacon chain consensus rewards swept but also a slashed validator fully exited\\n else if (ethRemaining > fuseIntervalEnd) {\\n IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: ethRemaining }();\\n // slither-disable-next-line unchecked-transfer\\n IWETH9(WETH_TOKEN_ADDRESS).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 {\\n require(\\n lastFixAccountingBlockNumber + MIN_FIX_ACCOUNTING_CADENCE <\\n block.number,\\n \\\"manuallyFixAccounting 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 emit AccountingManuallyFixed(\\n _validatorsDelta,\\n _consensusRewardsDelta,\\n _ethToVaultAmount\\n );\\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_TOKEN_ADDRESS).deposit{ value: _ethToVaultAmount }();\\n // slither-disable-next-line unchecked-transfer\\n IWETH9(WETH_TOKEN_ADDRESS).transfer(\\n VAULT_ADDRESS,\\n _ethToVaultAmount\\n );\\n _wethWithdrawnToVault(_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 Withdrawal event\\n function _wethWithdrawnToVault(uint256 _amount) internal virtual;\\n}\\n\",\"keccak256\":\"0xabaf2d9369a02523060af32100515478a585c40749c630e68d7ce24258d8ca43\",\"license\":\"MIT\"},\"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 address of the Wrapped ETH (WETH) token contract\\n address public immutable WETH_TOKEN_ADDRESS;\\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_ADDRESS;\\n /// @notice Address of the OETH Vault proxy contract\\n address public immutable VAULT_ADDRESS;\\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 governor needs to approve further staking\\n uint256 public stakeETHThreshold;\\n /// @notice Amount of ETH that can has been staked since the last governor approval.\\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(\\n bytes32 indexed pubKeyHash,\\n bytes pubKey,\\n uint256 amount,\\n bytes withdrawal_credentials\\n );\\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 constructor(\\n address _wethAddress,\\n address _vaultAddress,\\n address _beaconChainDepositContract,\\n address _ssvNetwork\\n ) {\\n WETH_TOKEN_ADDRESS = _wethAddress;\\n BEACON_CHAIN_DEPOSIT_CONTRACT = _beaconChainDepositContract;\\n SSV_NETWORK_ADDRESS = _ssvNetwork;\\n VAULT_ADDRESS = _vaultAddress;\\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 emit RegistratorChanged(_address);\\n validatorRegistrator = _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 emit StakingMonitorChanged(_address);\\n stakingMonitor = _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 emit StakeETHThresholdChanged(_amount);\\n stakeETHThreshold = _amount;\\n }\\n\\n /// @notice Reset the stakeETHTally\\n function resetStakeETHTally() external onlyStakingMonitor {\\n emit StakeETHTallyReset();\\n stakeETHTally = 0;\\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 {\\n uint256 requiredETH = validators.length * 32 ether;\\n\\n // Check there is enough WETH from the deposits sitting in this strategy contract\\n require(\\n requiredETH <= IWETH9(WETH_TOKEN_ADDRESS).balanceOf(address(this)),\\n \\\"insufficient WETH\\\"\\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_TOKEN_ADDRESS).withdraw(requiredETH);\\n _wethWithdrawnAndStaked(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 withdrawal_credentials = abi.encodePacked(\\n bytes1(0x01),\\n bytes11(0),\\n address(this)\\n );\\n\\n uint256 validatorsLength = validators.length;\\n // For each validator\\n for (uint256 i = 0; i < validatorsLength; ) {\\n bytes32 pubKeyHash = keccak256(validators[i].pubkey);\\n VALIDATOR_STATE currentState = validatorsStates[pubKeyHash];\\n\\n require(\\n currentState == VALIDATOR_STATE.REGISTERED,\\n \\\"Validator not registered\\\"\\n );\\n\\n IDepositContract(BEACON_CHAIN_DEPOSIT_CONTRACT).deposit{\\n value: 32 ether\\n }(\\n validators[i].pubkey,\\n withdrawal_credentials,\\n validators[i].signature,\\n validators[i].depositDataRoot\\n );\\n\\n emit ETHStaked(\\n pubKeyHash,\\n validators[i].pubkey,\\n 32 ether,\\n withdrawal_credentials\\n );\\n\\n validatorsStates[pubKeyHash] = VALIDATOR_STATE.STAKED;\\n\\n unchecked {\\n ++i;\\n }\\n }\\n // save gas by changing this storage variable only once rather each time in the loop.\\n activeDepositedValidators += validatorsLength;\\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 // slither-disable-start reentrancy-no-eth\\n function registerSsvValidator(\\n bytes calldata publicKey,\\n uint64[] calldata operatorIds,\\n bytes calldata sharesData,\\n uint256 amount,\\n Cluster calldata cluster\\n ) external onlyRegistrator whenNotPaused {\\n bytes32 pubKeyHash = keccak256(publicKey);\\n require(\\n validatorsStates[pubKeyHash] == VALIDATOR_STATE.NON_REGISTERED,\\n \\\"Validator already registered\\\"\\n );\\n ISSVNetwork(SSV_NETWORK_ADDRESS).registerValidator(\\n publicKey,\\n operatorIds,\\n sharesData,\\n amount,\\n cluster\\n );\\n emit SSVValidatorRegistered(pubKeyHash, publicKey, operatorIds);\\n\\n validatorsStates[pubKeyHash] = VALIDATOR_STATE.REGISTERED;\\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 // 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_ADDRESS).exitValidator(publicKey, operatorIds);\\n emit SSVValidatorExitInitiated(pubKeyHash, publicKey, operatorIds);\\n\\n validatorsStates[pubKeyHash] = VALIDATOR_STATE.EXITING;\\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 // 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_ADDRESS).removeValidator(\\n publicKey,\\n operatorIds,\\n cluster\\n );\\n emit SSVValidatorExitCompleted(pubKeyHash, publicKey, operatorIds);\\n\\n validatorsStates[pubKeyHash] = VALIDATOR_STATE.EXIT_COMPLETE;\\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 cluster The SSV cluster details that must be derived from emitted events from the SSVNetwork contract.\\n function depositSSV(\\n uint64[] memory operatorIds,\\n uint256 amount,\\n Cluster memory cluster\\n ) external onlyStrategist {\\n ISSVNetwork(SSV_NETWORK_ADDRESS).deposit(\\n address(this),\\n operatorIds,\\n amount,\\n cluster\\n );\\n }\\n\\n /***************************************\\n Abstract\\n ****************************************/\\n\\n /// @dev allows for NativeStakingSSVStrategy contract know how much WETH had been staked\\n function _wethWithdrawnAndStaked(uint256 _amount) internal virtual;\\n}\\n\",\"keccak256\":\"0x2638c178c161bf6a311885701327eb0a55221f92513de009a9023807c95bfb0d\",\"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/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\",\"keccak256\":\"0x5e17bb3db9f9e1014b7c5c836547f8fa81e02af7568c0bb8f2a2e0e7c2192db4\",\"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/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\\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\":\"0xcbdb87104749e20c8411bc2acbfa0b7d48e876e3f4e1c46c9a7b00fcdb9722d9\",\"license\":\"MIT\"}},\"version\":1}", - "bytecode": "0x6101806040523480156200001257600080fd5b506040516200515638038062005156833981016040819052620000359162000138565b8585876020015183868383838362000053336200010860201b60201c565b60008051602062005136833981519152546040516001600160a01b03909116906000907fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a908290a36033805460ff191690556001600160601b0319606094851b811660805291841b821660a052831b811660c05290821b811660e0528651821b811661010052602090960151811b86166101205298891b851661014052505050509190931b1661016052506200021392505050565b6000805160206200513683398151915255565b80516001600160a01b03811681146200013357600080fd5b919050565b60008060008060008086880360e08112156200015357600080fd5b60408112156200016257600080fd5b50604080519081016001600160401b03811182821017156200019457634e487b7160e01b600052604160045260246000fd5b604052620001a2886200011b565b8152620001b2602089016200011b565b60208201529550620001c7604088016200011b565b9450620001d7606088016200011b565b9350620001e7608088016200011b565b9250620001f760a088016200011b565b91506200020760c088016200011b565b90509295509295509295565b60805160601c60a05160601c60c05160601c60e05160601c6101005160601c6101205160601c6101405160601c6101605160601c614d7f620003b76000396000818161038a01528181610af4015261325101526000818161068001526126d401526000818161053401528181610f0801528181611b4501528181611cbe01528181612a8d0152612cde01526000610ac001526000818161083b01528181610cd001528181611a7301528181611d0e015281816120d20152818161383d0152613a97015260008181610b7e01528181610da601528181611979015281816126a40152818161284a0152612c08015260008181610a1501526116be0152600081816103bc015281816105de0152818161092c01528181610c3701528181610f7d015281816111c101528181611249015281816113f00152818161154101528181611c2f01528181611cdf0152818161204c0152818161210101528181612d6901528181612e1101528181613356015281816133db0152818161344f015281816136ec015281816137b70152818161386c01528181613a110152613ac60152614d7f6000f3fe60806040526004361061037a5760003560e01c8063853828b6116101d1578063c7af335211610102578063dbe55e56116100a0578063e75292391161006f578063e752923914610b41578063ee7afe2d14610b57578063f1188e4014610b6c578063f6ca71b014610ba057600080fd5b8063dbe55e5614610aae578063dd505df614610ae2578063de34d71314610b16578063de5f626814610b2c57600080fd5b8063d059f6ef116100dc578063d059f6ef14610a37578063d38bfff414610a4e578063d9caed1214610a6e578063d9f00ec714610a8e57600080fd5b8063c7af3352146109d1578063c98517c5146109e6578063cceab75014610a0357600080fd5b8063a3b81e731161016f578063ab12edf511610149578063ab12edf51461095c578063ad1728cb1461097c578063bb1b918d14610991578063c2e1e3f4146109b157600080fd5b8063a3b81e73146108da578063a4f98af4146108fa578063aa388af61461090f57600080fd5b80639092c31c116101ab5780639092c31c146108295780639136616a1461085d57806396d538bb1461087d5780639da0e4621461089d57600080fd5b8063853828b6146107cf57806387bae867146107e45780638d7c0e461461080957600080fd5b80635d36b190116102ab5780636ef38795116102495780637b2d9b2c116102235780637b2d9b2c1461076e5780637b8962f71461078e578063842f5c46146107a45780638456cb59146107ba57600080fd5b80636ef387951461070e57806371a735f31461072e5780637260f8261461074e57600080fd5b8063630923831161028557806363092383146106a257806366e3667e146106b857806367c7066c146106ce5780636e811d38146106ee57600080fd5b80635d36b190146106395780635f5152261461064e5780636093d3801461066e57600080fd5b8063435356d1116103185780635205c380116102f25780635205c380146105ac578063579a7e1a146105cc5780635a063f63146106005780635c975abb1461061557600080fd5b8063435356d11461055657806347e7ef2414610576578063484be8121461059657600080fd5b80631072cbea116103545780631072cbea146104be57806322495dc8146104de5780633c864959146104fe578063430bf08a1461052257600080fd5b80630c340a24146104365780630ed57b3a146104685780630fc3b4c41461048857600080fd5b3661043157336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614806103de5750336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016145b61042f5760405162461bcd60e51b815260206004820152601e60248201527f657468206e6f742066726f6d20616c6c6f77656420636f6e747261637473000060448201526064015b60405180910390fd5b005b600080fd5b34801561044257600080fd5b5061044b610bc2565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561047457600080fd5b5061042f610483366004614122565b610bdf565b34801561049457600080fd5b5061044b6104a33660046140e8565b609f602052600090815260409020546001600160a01b031681565b3480156104ca57600080fd5b5061042f6104d936600461419c565b610c11565b3480156104ea57600080fd5b5061042f6104f9366004614290565b610cce565b34801561050a57600080fd5b5061051460695481565b60405190815260200161045f565b34801561052e57600080fd5b5061044b7f000000000000000000000000000000000000000000000000000000000000000081565b34801561056257600080fd5b5061042f610571366004614209565b610e18565b34801561058257600080fd5b5061042f61059136600461419c565b610efd565b3480156105a257600080fd5b50610514606a5481565b3480156105b857600080fd5b5061042f6105c7366004614366565b61101c565b3480156105d857600080fd5b5061044b7f000000000000000000000000000000000000000000000000000000000000000081565b34801561060c57600080fd5b5061042f611078565b34801561062157600080fd5b5060335460ff165b604051901515815260200161045f565b34801561064557600080fd5b5061042f611117565b34801561065a57600080fd5b506105146106693660046140e8565b6111bd565b34801561067a57600080fd5b5061044b7f000000000000000000000000000000000000000000000000000000000000000081565b3480156106ae57600080fd5b50610514611c2081565b3480156106c457600080fd5b5061051460345481565b3480156106da57600080fd5b5060a35461044b906001600160a01b031681565b3480156106fa57600080fd5b5061042f6107093660046140e8565b6112f1565b34801561071a57600080fd5b5061042f6107293660046141c8565b611371565b34801561073a57600080fd5b5061042f61074936600461449e565b611885565b34801561075a57600080fd5b5060365461044b906001600160a01b031681565b34801561077a57600080fd5b5061044b610789366004614366565b611a47565b34801561079a57600080fd5b5061051460375481565b3480156107b057600080fd5b5061051460685481565b3480156107c657600080fd5b5061042f611a71565b3480156107db57600080fd5b5061042f611b3a565b3480156107f057600080fd5b5060335461044b9061010090046001600160a01b031681565b34801561081557600080fd5b5061042f61082436600461451f565b611d0c565b34801561083557600080fd5b5061044b7f000000000000000000000000000000000000000000000000000000000000000081565b34801561086957600080fd5b5061042f610878366004614366565b6121e1565b34801561088957600080fd5b5061042f6108983660046141c8565b6123ac565b3480156108a957600080fd5b506108cd6108b8366004614366565b60356020526000908152604090205460ff1681565b60405161045f919061498a565b3480156108e657600080fd5b5061042f6108f53660046140e8565b6124cc565b34801561090657600080fd5b50610629612546565b34801561091b57600080fd5b5061062961092a3660046140e8565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0390811691161490565b34801561096857600080fd5b5061042f610977366004614564565b6125a5565b34801561098857600080fd5b5061042f61268d565b34801561099d57600080fd5b5061042f6109ac3660046143ea565b612753565b3480156109bd57600080fd5b5061042f6109cc3660046140e8565b612920565b3480156109dd57600080fd5b506106296129ad565b3480156109f257600080fd5b506105146801bc16d674ec80000081565b348015610a0f57600080fd5b5061044b7f000000000000000000000000000000000000000000000000000000000000000081565b348015610a4357600080fd5b506105146101075481565b348015610a5a57600080fd5b5061042f610a693660046140e8565b6129de565b348015610a7a57600080fd5b5061042f610a8936600461415b565b612a82565b348015610a9a57600080fd5b5061042f610aa936600461437f565b612b15565b348015610aba57600080fd5b5061044b7f000000000000000000000000000000000000000000000000000000000000000081565b348015610aee57600080fd5b5061044b7f000000000000000000000000000000000000000000000000000000000000000081565b348015610b2257600080fd5b5061051460385481565b348015610b3857600080fd5b5061042f612cd3565b348015610b4d57600080fd5b50610514606b5481565b348015610b6357600080fd5b5061042f612e40565b348015610b7857600080fd5b5061044b7f000000000000000000000000000000000000000000000000000000000000000081565b348015610bac57600080fd5b50610bb5612eca565b60405161045f9190614760565b6000610bda600080516020614d2a8339815191525490565b905090565b610be76129ad565b610c035760405162461bcd60e51b8152600401610426906149fc565b610c0d8282612f2c565b5050565b610c196129ad565b610c355760405162461bcd60e51b8152600401610426906149fc565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b039081169083161415610cb25760405162461bcd60e51b815260206004820152601f60248201527f43616e6e6f74207472616e7366657220737570706f72746564206173736574006044820152606401610426565b610c0d610cbd610bc2565b6001600160a01b038416908361308b565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b158015610d2757600080fd5b505afa158015610d3b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d5f9190614105565b6001600160a01b0316336001600160a01b031614610d8f5760405162461bcd60e51b815260040161042690614abc565b60405163bc26e7e560e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063bc26e7e590610de19030908790879087906004016146b0565b600060405180830381600087803b158015610dfb57600080fd5b505af1158015610e0f573d6000803e3d6000fd5b50505050505050565b610e206129ad565b610e3c5760405162461bcd60e51b8152600401610426906149fc565b600054610100900460ff1680610e55575060005460ff16155b610eb85760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610426565b600054610100900460ff16158015610eda576000805461ffff19166101011790555b610ee58484846130dd565b8015610ef7576000805461ff00191690555b50505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610f455760405162461bcd60e51b8152600401610426906149c5565b600080516020614d0a83398151915280546002811415610f775760405162461bcd60e51b815260040161042690614a94565b600282557f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316846001600160a01b031614610ff05760405162461bcd60e51b8152602060048201526011602482015270155b9cdd5c1c1bdc9d195908185cdcd95d607a1b6044820152606401610426565b8261010760008282546110039190614be3565b9091555061101390508484613198565b50600190555050565b6110246129ad565b6110405760405162461bcd60e51b8152600401610426906149fc565b6040518181527fe26b067424903962f951f568e52ec9a3bbe1589526ea54a4e69ca6eaae1a4c779060200160405180910390a1603755565b60a3546001600160a01b031633146110d25760405162461bcd60e51b815260206004820152601b60248201527f43616c6c6572206973206e6f74207468652048617276657374657200000000006044820152606401610426565b600080516020614d0a833981519152805460028114156111045760405162461bcd60e51b815260040161042690614a94565b6002825561111061322a565b5060019055565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b0316146111b25760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b6064820152608401610426565b6111bb33613478565b565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b0316146112345760405162461bcd60e51b8152602060048201526011602482015270155b9cdd5c1c1bdc9d195908185cdcd95d607a1b6044820152606401610426565b6040516370a0823160e01b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b15801561129357600080fd5b505afa1580156112a7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112cb919061454b565b6034546112e1906801bc16d674ec800000614bfb565b6112eb9190614be3565b92915050565b6112f96129ad565b6113155760405162461bcd60e51b8152600401610426906149fc565b6040516001600160a01b038216907f83f29c79feb71f8fba9d0fbc4ba5f0982a28b6b1e868b3fc50e6400d100bca0f90600090a2603380546001600160a01b0390921661010002610100600160a81b0319909216919091179055565b60335461010090046001600160a01b031633146113a05760405162461bcd60e51b815260040161042690614a5d565b60335460ff16156113c35760405162461bcd60e51b815260040161042690614a33565b60006113d8826801bc16d674ec800000614bfb565b6040516370a0823160e01b81523060048201529091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b15801561143a57600080fd5b505afa15801561144e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611472919061454b565b8111156114b55760405162461bcd60e51b81526020600482015260116024820152700d2dce6eaccccd2c6d2cadce840ae8aa89607b1b6044820152606401610426565b603754816038546114c69190614be3565b11156115145760405162461bcd60e51b815260206004820152601a60248201527f5374616b696e6720455448206f766572207468726573686f6c640000000000006044820152606401610426565b80603860008282546115269190614be3565b9091555050604051632e1a7d4d60e01b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561158d57600080fd5b505af11580156115a1573d6000803e3d6000fd5b505050506115ae81613539565b60408051600160f81b60208201526000602182018190526bffffffffffffffffffffffff193060601b16602c830152910160408051601f1981840301815291905290508260005b8181101561186657600086868381811061161157611611614cba565b90506020028101906116239190614b39565b61162d9080614af3565b60405161163b929190614684565b604080519182900390912060008181526035602052919091205490915060ff16600181600481111561166f5761166f614c8e565b146116bc5760405162461bcd60e51b815260206004820152601860248201527f56616c696461746f72206e6f74207265676973746572656400000000000000006044820152606401610426565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663228951186801bc16d674ec8000008a8a8781811061170757611707614cba565b90506020028101906117199190614b39565b6117239080614af3565b898d8d8a81811061173657611736614cba565b90506020028101906117489190614b39565b611756906020810190614af3565b8f8f8c81811061176857611768614cba565b905060200281019061177a9190614b39565b604001356040518863ffffffff1660e01b815260040161179f9695949392919061490f565b6000604051808303818588803b1580156117b857600080fd5b505af11580156117cc573d6000803e3d6000fd5b5050505050817fd44c8fde6d369f70d395b6cdee4641886d11e3a72cb537696ca04134881692ed89898681811061180557611805614cba565b90506020028101906118179190614b39565b6118219080614af3565b6801bc16d674ec8000008960405161183c949392919061495e565b60405180910390a2506000908152603560205260409020805460ff191660021790556001016115f5565b5080603460008282546118799190614be3565b90915550505050505050565b60335461010090046001600160a01b031633146118b45760405162461bcd60e51b815260040161042690614a5d565b60335460ff16156118d75760405162461bcd60e51b815260040161042690614a33565b600085856040516118e9929190614684565b604080519182900390912060008181526035602052919091205490915060ff16600381600481111561191d5761191d614c8e565b146119625760405162461bcd60e51b815260206004820152601560248201527456616c696461746f72206e6f742065786974696e6760581b6044820152606401610426565b6040516312b3fc1960e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906312b3fc19906119b6908a908a908a908a908a906004016148ce565b600060405180830381600087803b1580156119d057600080fd5b505af11580156119e4573d6000803e3d6000fd5b50505050817f6aecca20726a17c1b81989b2fd09dfdf636bae9e564d4066ca18df62dc1f3dc288888888604051611a1e9493929190614845565b60405180910390a2506000908152603560205260409020805460ff191660041790555050505050565b60a48181548110611a5757600080fd5b6000918252602090912001546001600160a01b0316905081565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b158015611aca57600080fd5b505afa158015611ade573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b029190614105565b6001600160a01b0316336001600160a01b031614611b325760405162461bcd60e51b815260040161042690614abc565b6111bb613566565b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161480611b895750611b74610bc2565b6001600160a01b0316336001600160a01b0316145b611be15760405162461bcd60e51b815260206004820152602360248201527f43616c6c6572206973206e6f7420746865205661756c74206f7220476f7665726044820152623737b960e91b6064820152608401610426565b600080516020614d0a83398151915280546002811415611c135760405162461bcd60e51b815260040161042690614a94565b600282556040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b158015611c7957600080fd5b505afa158015611c8d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cb1919061454b565b90508015611d0457611d047f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000836135db565b505060019055565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b158015611d6557600080fd5b505afa158015611d79573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d9d9190614105565b6001600160a01b0316336001600160a01b031614611dcd5760405162461bcd60e51b815260040161042690614abc565b60335460ff16611e165760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610426565b43611c20606b54611e279190614be3565b10611e825760405162461bcd60e51b815260206004820152602560248201527f6d616e75616c6c794669784163636f756e74696e672063616c6c656420746f6f6044820152641039b7b7b760d91b6064820152608401610426565b6002198312158015611e95575060038313155b8015611eaf5750600083603454611eac9190614ba2565b12155b611efb5760405162461bcd60e51b815260206004820152601760248201527f696e76616c69642076616c696461746f727344656c74610000000000000000006044820152606401610426565b6811ff6cf0fd15afffff198212158015611f1e57506811ff6cf0fd15b000008213155b8015611f385750600082606854611f359190614ba2565b12155b611f845760405162461bcd60e51b815260206004820152601d60248201527f696e76616c696420636f6e73656e7375735265776172647344656c74610000006044820152606401610426565b68053444835ec5800000811115611fdd5760405162461bcd60e51b815260206004820152601960248201527f696e76616c69642077657468546f5661756c74416d6f756e74000000000000006044820152606401610426565b60408051848152602081018490529081018290527f80d022717ea022455c5886b8dd8a29c037570aae58aeb4d7b136d7a10ec2e4319060600160405180910390a18260345461202c9190614ba2565b60345560685461203d908390614ba2565b60685543606b55801561218b577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b1580156120a557600080fd5b505af11580156120b9573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb92506044019050602060405180830381600087803b15801561214957600080fd5b505af115801561215d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121819190614349565b5061218b816136d3565b612195600061373b565b6121d45760405162461bcd60e51b815260206004820152601060248201526f333ab9b29039ba34b63610313637bbb760811b6044820152606401610426565b6121dc613bba565b505050565b6121e96129ad565b6122055760405162461bcd60e51b8152600401610426906149fc565b60a05481106122465760405162461bcd60e51b815260206004820152600d60248201526c092dcecc2d8d2c840d2dcc8caf609b1b6044820152606401610426565b600060a0828154811061225b5761225b614cba565b60009182526020808320909101546001600160a01b03908116808452609f90925260409092205460a0549193509091169061229890600190614c1a565b83101561231a5760a080546122af90600190614c1a565b815481106122bf576122bf614cba565b60009182526020909120015460a080546001600160a01b0390921691859081106122eb576122eb614cba565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505b60a080548061232b5761232b614ca4565b60008281526020808220600019908401810180546001600160a01b031990811690915593019093556001600160a01b03858116808352609f855260409283902080549094169093559051908416815290917f16b7600acff27e39a8a96056b3d533045298de927507f5c1d97e4accde60488c910160405180910390a2505050565b6123b46129ad565b6123d05760405162461bcd60e51b8152600401610426906149fc565b8060005b818110156124835760008484838181106123f0576123f0614cba565b905060200201602081019061240591906140e8565b6001600160a01b031614156124735760405162461bcd60e51b815260206004820152602e60248201527f43616e206e6f742073657420616e20656d70747920616464726573732061732060448201526d30903932bbb0b932103a37b5b2b760911b6064820152608401610426565b61247c81614c5d565b90506123d4565b507f04c0b9649497d316554306e53678d5f5f5dbc3a06f97dec13ff4cfe98b986bbc60a484846040516124b8939291906147ad565b60405180910390a1610ef760a48484613e41565b6124d46129ad565b6124f05760405162461bcd60e51b8152600401610426906149fc565b6040516001600160a01b038216907f3329861a0008b3348767567d2405492b997abd79a088d0f2cef6b1a09a8e7ff790600090a2603680546001600160a01b0319166001600160a01b0392909216919091179055565b60335460009061010090046001600160a01b031633146125785760405162461bcd60e51b815260040161042690614a5d565b60335460ff161561259b5760405162461bcd60e51b815260040161042690614a33565b610bda600161373b565b6125ad6129ad565b6125c95760405162461bcd60e51b8152600401610426906149fc565b80821080156125e057506801bc16d674ec80000081105b80156125fd5750673782dace9d9000006125fa8383614c1a565b10155b6126495760405162461bcd60e51b815260206004820152601760248201527f696e636f7272656374206675736520696e74657276616c0000000000000000006044820152606401610426565b60408051838152602081018390527fcb8d24e46eb3c402bf344ee60a6576cba9ef2f59ea1af3b311520704924e901a910160405180910390a1606991909155606a55565b60405163095ea7b360e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015260001960248301527f0000000000000000000000000000000000000000000000000000000000000000169063095ea7b390604401602060405180830381600087803b15801561271857600080fd5b505af115801561272c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127509190614349565b50565b60335461010090046001600160a01b031633146127825760405162461bcd60e51b815260040161042690614a5d565b60335460ff16156127a55760405162461bcd60e51b815260040161042690614a33565b600088886040516127b7929190614684565b60405190819003902090506000808281526035602052604090205460ff1660048111156127e6576127e6614c8e565b146128335760405162461bcd60e51b815260206004820152601c60248201527f56616c696461746f7220616c72656164792072656769737465726564000000006044820152606401610426565b6040516301ba3ee760e21b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906306e8fb9c9061288d908c908c908c908c908c908c908c908c9060040161486c565b600060405180830381600087803b1580156128a757600080fd5b505af11580156128bb573d6000803e3d6000fd5b50505050807facd38e900350661e325d592c959664c0000a306efb2004e7dc283f44e0ea04238a8a8a8a6040516128f59493929190614845565b60405180910390a26000908152603560205260409020805460ff191660011790555050505050505050565b6129286129ad565b6129445760405162461bcd60e51b8152600401610426906149fc565b60a354604080516001600160a01b03928316815291831660208301527fe48386b84419f4d36e0f96c10cc3510b6fb1a33795620c5098b22472bbe90796910160405180910390a160a380546001600160a01b0319166001600160a01b0392909216919091179055565b60006129c5600080516020614d2a8339815191525490565b6001600160a01b0316336001600160a01b031614905090565b6129e66129ad565b612a025760405162461bcd60e51b8152600401610426906149fc565b612a2a817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b0316612a4a600080516020614d2a8339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614612aca5760405162461bcd60e51b8152600401610426906149c5565b600080516020614d0a83398151915280546002811415612afc5760405162461bcd60e51b815260040161042690614a94565b60028255612b0b8585856135db565b5060019055505050565b60335461010090046001600160a01b03163314612b445760405162461bcd60e51b815260040161042690614a5d565b60335460ff1615612b675760405162461bcd60e51b815260040161042690614a33565b60008484604051612b79929190614684565b604080519182900390912060008181526035602052919091205490915060ff166002816004811115612bad57612bad614c8e565b14612bf15760405162461bcd60e51b815260206004820152601460248201527315985b1a59185d1bdc881b9bdd081cdd185ad95960621b6044820152606401610426565b604051633877322b60e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690633877322b90612c43908990899089908990600401614845565b600060405180830381600087803b158015612c5d57600080fd5b505af1158015612c71573d6000803e3d6000fd5b50505050817f8c2e15303eb94e531acc988c2a01d1193bdaaa15eda7f16dda85316ed463578d87878787604051612cab9493929190614845565b60405180910390a2506000908152603560205260409020805460ff1916600317905550505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614612d1b5760405162461bcd60e51b8152600401610426906149c5565b600080516020614d0a83398151915280546002811415612d4d5760405162461bcd60e51b815260040161042690614a94565b600282556040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b158015612db357600080fd5b505afa158015612dc7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612deb919061454b565b905060006101075482612dfe9190614c1a565b90508015612e3657610107829055612e367f000000000000000000000000000000000000000000000000000000000000000082613198565b5050600182555050565b6036546001600160a01b03163314612e9a5760405162461bcd60e51b815260206004820152601960248201527f43616c6c6572206973206e6f7420746865204d6f6e69746f72000000000000006044820152606401610426565b6040517fe765a88a37047c5d793dce22b9ceb5a0f5039d276da139b4c7d29613f341f11090600090a16000603855565b606060a4805480602002602001604051908101604052809291908181526020018280548015612f2257602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612f04575b5050505050905090565b6001600160a01b038281166000908152609f60205260409020541615612f895760405162461bcd60e51b81526020600482015260126024820152711c151bdad95b88185b1c9958591e481cd95d60721b6044820152606401610426565b6001600160a01b03821615801590612fa957506001600160a01b03811615155b612fe95760405162461bcd60e51b8152602060048201526011602482015270496e76616c69642061646472657373657360781b6044820152606401610426565b6001600160a01b038281166000818152609f6020908152604080832080549587166001600160a01b0319968716811790915560a0805460018101825594527f78fdc8d422c49ced035a9edf18d00d3c6a8d81df210f3e5e448e045e77b41e8890930180549095168417909455925190815290917fef6485b84315f9b1483beffa32aae9a0596890395e3d7521f1c5fbb51790e765910160405180910390a25050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b1790526121dc908490613c34565b82516130f09060a4906020860190613ea4565b5081518151811461313a5760405162461bcd60e51b8152602060048201526014602482015273496e76616c696420696e7075742061727261797360601b6044820152606401610426565b60005b818110156131915761318184828151811061315a5761315a614cba565b602002602001015184838151811061317457613174614cba565b6020026020010151612f2c565b61318a81614c5d565b905061313d565b5050505050565b600081116131e15760405162461bcd60e51b81526020600482015260166024820152754d757374206465706f73697420736f6d657468696e6760501b6044820152606401610426565b6040805160008152602081018390526001600160a01b038416917f5548c837ab068cf56a2c2479df0882a4922fd203edb7517321831d95078c5f62910160405180910390a25050565b60335460ff161561324d5760405162461bcd60e51b815260040161042690614a33565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663e52253816040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156132aa57600080fd5b505af11580156132be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132e2919061454b565b90506000606854826132f49190614be3565b9050804710156133465760405162461bcd60e51b815260206004820152601860248201527f696e73756666696369656e74206574682062616c616e636500000000000000006044820152606401610426565b8015610c0d5760006068819055507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b1580156133af57600080fd5b505af11580156133c3573d6000803e3d6000fd5b505060a354604080516001600160a01b0392831681527f0000000000000000000000000000000000000000000000000000000000000000909216602083015281018590527ff6c07a063ed4e63808eb8da7112d46dbcd38de2b40a73dbcc9353c5a94c72353935060600191506134369050565b60405180910390a160a354610c0d906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811691168361308b565b6001600160a01b0381166134ce5760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f7220697320616464726573732830290000000000006044820152606401610426565b806001600160a01b03166134ee600080516020614d2a8339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a361275081600080516020614d2a83398151915255565b60006135488261010754613d06565b905080610107600082825461355d9190614c1a565b90915550505050565b60335460ff16156135895760405162461bcd60e51b815260040161042690614a33565b6033805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586135be3390565b6040516001600160a01b03909116815260200160405180910390a1565b6000811161362b5760405162461bcd60e51b815260206004820152601760248201527f4d75737420776974686472617720736f6d657468696e670000000000000000006044820152606401610426565b6001600160a01b03831661367a5760405162461bcd60e51b8152602060048201526016602482015275135d5cdd081cdc1958da599e481c9958da5c1a595b9d60521b6044820152606401610426565b6040805160008152602081018390526001600160a01b038416917f2717ead6b9200dd235aad468c9809ea400fe33ac69b5bfaa6d3e90fc922b6398910160405180910390a26121dc6001600160a01b038316848361308b565b6040805160008152602081018390526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016917f2717ead6b9200dd235aad468c9809ea400fe33ac69b5bfaa6d3e90fc922b6398910160405180910390a250565b6000606854471015613750576112eb82613d1e565b6000606854476137609190614c1a565b9050600191506801bc16d674ec800000811061393d5760006801bc16d674ec8000008204905080603460008282546137989190614c1a565b90915550600090506137b3826801bc16d674ec800000614bfb565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b15801561381057600080fd5b505af1158015613824573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb92506044019050602060405180830381600087803b1580156138b457600080fd5b505af11580156138c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138ec9190614349565b506138f6816136d3565b60345460408051848152602081019290925281018290527fbe7040030ff7b347853214bf49820c6d455fedf58f3815f85c7bc5216993682b9060600160405180910390a150505b60006068544761394d9190614c1a565b90506801bc16d674ec800000811061399f5760405162461bcd60e51b8152602060048201526015602482015274756e6578706563746564206163636f756e74696e6760581b6044820152606401610426565b806139ab575050919050565b606954811015613a055780606860008282546139c79190614be3565b90915550506040518181527f7a745a2c63a535068f52ceca27debd5297bbad5f7f37ec53d044a59d0362445d906020015b60405180910390a1613bb3565b606a54811115613ba2577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b158015613a6a57600080fd5b505af1158015613a7e573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb92506044019050602060405180830381600087803b158015613b0e57600080fd5b505af1158015613b22573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b469190614349565b50600160346000828254613b5a9190614c1a565b90915550613b699050816136d3565b60345460408051918252602082018390527f6aa7e30787b26429ced603a7aba8b19c4b5d5bcf29a3257da953c8d53bcaa3a691016139f8565b613bab84613d1e565b949350505050565b5050919050565b60335460ff16613c035760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610426565b6033805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa336135be565b6000613c89826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316613d369092919063ffffffff16565b8051909150156121dc5780806020019051810190613ca79190614349565b6121dc5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610426565b6000818310613d155781613d17565b825b9392505050565b60008115613d2e57613d2e613566565b506000919050565b6060613bab848460008585843b613d8f5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610426565b600080866001600160a01b03168587604051613dab9190614694565b60006040518083038185875af1925050503d8060008114613de8576040519150601f19603f3d011682016040523d82523d6000602084013e613ded565b606091505b5091509150613dfd828286613e08565b979650505050505050565b60608315613e17575081613d17565b825115613e275782518084602001fd5b8160405162461bcd60e51b815260040161042691906149b2565b828054828255906000526020600020908101928215613e94579160200282015b82811115613e945781546001600160a01b0319166001600160a01b03843516178255602090920191600190910190613e61565b50613ea0929150613ef9565b5090565b828054828255906000526020600020908101928215613e94579160200282015b82811115613e9457825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190613ec4565b5b80821115613ea05760008155600101613efa565b60008083601f840112613f2057600080fd5b5081356001600160401b03811115613f3757600080fd5b6020830191508360208260051b8501011115613f5257600080fd5b9250929050565b600082601f830112613f6a57600080fd5b81356020613f7f613f7a83614b7f565b614b4f565b80838252828201915082860187848660051b8901011115613f9f57600080fd5b60005b85811015613fc7578135613fb581614ce6565b84529284019290840190600101613fa2565b5090979650505050505050565b60008083601f840112613fe657600080fd5b5081356001600160401b03811115613ffd57600080fd5b602083019150836020828501011115613f5257600080fd5b600060a0828403121561402757600080fd5b50919050565b600060a0828403121561403f57600080fd5b60405160a081018181106001600160401b038211171561406157614061614cd0565b604052905080614070836140b8565b815261407e602084016140d1565b602082015261408f604084016140d1565b604082015260608301356140a281614cfb565b6060820152608092830135920191909152919050565b803563ffffffff811681146140cc57600080fd5b919050565b80356001600160401b03811681146140cc57600080fd5b6000602082840312156140fa57600080fd5b8135613d1781614ce6565b60006020828403121561411757600080fd5b8151613d1781614ce6565b6000806040838503121561413557600080fd5b823561414081614ce6565b9150602083013561415081614ce6565b809150509250929050565b60008060006060848603121561417057600080fd5b833561417b81614ce6565b9250602084013561418b81614ce6565b929592945050506040919091013590565b600080604083850312156141af57600080fd5b82356141ba81614ce6565b946020939093013593505050565b600080602083850312156141db57600080fd5b82356001600160401b038111156141f157600080fd5b6141fd85828601613f0e565b90969095509350505050565b60008060006060848603121561421e57600080fd5b83356001600160401b038082111561423557600080fd5b61424187838801613f59565b9450602086013591508082111561425757600080fd5b61426387838801613f59565b9350604086013591508082111561427957600080fd5b5061428686828701613f59565b9150509250925092565b600080600060e084860312156142a557600080fd5b83356001600160401b038111156142bb57600080fd5b8401601f810186136142cc57600080fd5b803560206142dc613f7a83614b7f565b8083825282820191508285018a848660051b88010111156142fc57600080fd5b600095505b8486101561432657614312816140d1565b835260019590950194918301918301614301565b50965050860135935061434091508690506040860161402d565b90509250925092565b60006020828403121561435b57600080fd5b8151613d1781614cfb565b60006020828403121561437857600080fd5b5035919050565b6000806000806040858703121561439557600080fd5b84356001600160401b03808211156143ac57600080fd5b6143b888838901613fd4565b909650945060208701359150808211156143d157600080fd5b506143de87828801613f0e565b95989497509550505050565b600080600080600080600080610120898b03121561440757600080fd5b88356001600160401b038082111561441e57600080fd5b61442a8c838d01613fd4565b909a50985060208b013591508082111561444357600080fd5b61444f8c838d01613f0e565b909850965060408b013591508082111561446857600080fd5b506144758b828c01613fd4565b9095509350506060890135915061448f8a60808b01614015565b90509295985092959890939650565b600080600080600060e086880312156144b657600080fd5b85356001600160401b03808211156144cd57600080fd5b6144d989838a01613fd4565b909750955060208801359150808211156144f257600080fd5b506144ff88828901613f0e565b909450925061451390508760408801614015565b90509295509295909350565b60008060006060848603121561453457600080fd5b505081359360208301359350604090920135919050565b60006020828403121561455d57600080fd5b5051919050565b6000806040838503121561457757600080fd5b50508035926020909101359150565b8183526000602080850194508260005b858110156145c2576001600160401b036145af836140d1565b1687529582019590820190600101614596565b509495945050505050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6000815180845261460e816020860160208601614c31565b601f01601f19169290920160200192915050565b63ffffffff614630826140b8565b16825261463f602082016140d1565b6001600160401b0380821660208501528061465c604085016140d1565b1660408501525050606081013561467281614cfb565b15156060830152608090810135910152565b8183823760009101908152919050565b600082516146a6818460208701614c31565b9190910192915050565b6001600160a01b03851681526101006020808301829052855191830182905260009161012084019187810191845b818110156147035783516001600160401b0316855293820193928201926001016146de565b505082935086604086015263ffffffff865116606086015280860151925050506001600160401b0380821660808501528060408601511660a085015250506060830151151560c0830152608083015160e083015295945050505050565b6020808252825182820181905260009190848201906040850190845b818110156147a15783516001600160a01b03168352928401929184019160010161477c565b50909695505050505050565b6000604082016040835280865480835260608501915087600052602092508260002060005b828110156147f75781546001600160a01b0316845292840192600191820191016147d2565b505050838103828501528481528590820160005b8681101561483957823561481e81614ce6565b6001600160a01b03168252918301919083019060010161480b565b50979650505050505050565b6040815260006148596040830186886145cd565b8281036020840152613dfd818587614586565b60006101208083526148818184018b8d6145cd565b9050828103602084015261489681898b614586565b905082810360408401526148ab8187896145cd565b9150508360608301526148c16080830184614622565b9998505050505050505050565b60e0815260006148e260e0830187896145cd565b82810360208401526148f5818688614586565b9150506149056040830184614622565b9695505050505050565b60808152600061492360808301888a6145cd565b828103602084015261493581886145f6565b9050828103604084015261494a8186886145cd565b915050826060830152979650505050505050565b6060815260006149726060830186886145cd565b8460208401528281036040840152613dfd81856145f6565b60208101600583106149ac57634e487b7160e01b600052602160045260246000fd5b91905290565b602081526000613d1760208301846145f6565b60208082526017908201527f43616c6c6572206973206e6f7420746865205661756c74000000000000000000604082015260600190565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b60208082526010908201526f14185d5cd8589b194e881c185d5cd95960821b604082015260600190565b6020808252601d908201527f43616c6c6572206973206e6f7420746865205265676973747261746f72000000604082015260600190565b6020808252600e908201526d1499595b9d1c985b9d0818d85b1b60921b604082015260600190565b6020808252601c908201527f43616c6c6572206973206e6f7420746865205374726174656769737400000000604082015260600190565b6000808335601e19843603018112614b0a57600080fd5b8301803591506001600160401b03821115614b2457600080fd5b602001915036819003821315613f5257600080fd5b60008235605e198336030181126146a657600080fd5b604051601f8201601f191681016001600160401b0381118282101715614b7757614b77614cd0565b604052919050565b60006001600160401b03821115614b9857614b98614cd0565b5060051b60200190565b600080821280156001600160ff1b0384900385131615614bc457614bc4614c78565b600160ff1b8390038412811615614bdd57614bdd614c78565b50500190565b60008219821115614bf657614bf6614c78565b500190565b6000816000190483118215151615614c1557614c15614c78565b500290565b600082821015614c2c57614c2c614c78565b500390565b60005b83811015614c4c578181015183820152602001614c34565b83811115610ef75750506000910152565b6000600019821415614c7157614c71614c78565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b038116811461275057600080fd5b801515811461275057600080fdfe53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac45357bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa26469706673582212204d8c7ebaf4c2264e2fd90a3c201009d9efc50419a225e0b4f7f4c66aac9378b664736f6c634300080700337bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a", - "deployedBytecode": "0x60806040526004361061037a5760003560e01c8063853828b6116101d1578063c7af335211610102578063dbe55e56116100a0578063e75292391161006f578063e752923914610b41578063ee7afe2d14610b57578063f1188e4014610b6c578063f6ca71b014610ba057600080fd5b8063dbe55e5614610aae578063dd505df614610ae2578063de34d71314610b16578063de5f626814610b2c57600080fd5b8063d059f6ef116100dc578063d059f6ef14610a37578063d38bfff414610a4e578063d9caed1214610a6e578063d9f00ec714610a8e57600080fd5b8063c7af3352146109d1578063c98517c5146109e6578063cceab75014610a0357600080fd5b8063a3b81e731161016f578063ab12edf511610149578063ab12edf51461095c578063ad1728cb1461097c578063bb1b918d14610991578063c2e1e3f4146109b157600080fd5b8063a3b81e73146108da578063a4f98af4146108fa578063aa388af61461090f57600080fd5b80639092c31c116101ab5780639092c31c146108295780639136616a1461085d57806396d538bb1461087d5780639da0e4621461089d57600080fd5b8063853828b6146107cf57806387bae867146107e45780638d7c0e461461080957600080fd5b80635d36b190116102ab5780636ef38795116102495780637b2d9b2c116102235780637b2d9b2c1461076e5780637b8962f71461078e578063842f5c46146107a45780638456cb59146107ba57600080fd5b80636ef387951461070e57806371a735f31461072e5780637260f8261461074e57600080fd5b8063630923831161028557806363092383146106a257806366e3667e146106b857806367c7066c146106ce5780636e811d38146106ee57600080fd5b80635d36b190146106395780635f5152261461064e5780636093d3801461066e57600080fd5b8063435356d1116103185780635205c380116102f25780635205c380146105ac578063579a7e1a146105cc5780635a063f63146106005780635c975abb1461061557600080fd5b8063435356d11461055657806347e7ef2414610576578063484be8121461059657600080fd5b80631072cbea116103545780631072cbea146104be57806322495dc8146104de5780633c864959146104fe578063430bf08a1461052257600080fd5b80630c340a24146104365780630ed57b3a146104685780630fc3b4c41461048857600080fd5b3661043157336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614806103de5750336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016145b61042f5760405162461bcd60e51b815260206004820152601e60248201527f657468206e6f742066726f6d20616c6c6f77656420636f6e747261637473000060448201526064015b60405180910390fd5b005b600080fd5b34801561044257600080fd5b5061044b610bc2565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561047457600080fd5b5061042f610483366004614122565b610bdf565b34801561049457600080fd5b5061044b6104a33660046140e8565b609f602052600090815260409020546001600160a01b031681565b3480156104ca57600080fd5b5061042f6104d936600461419c565b610c11565b3480156104ea57600080fd5b5061042f6104f9366004614290565b610cce565b34801561050a57600080fd5b5061051460695481565b60405190815260200161045f565b34801561052e57600080fd5b5061044b7f000000000000000000000000000000000000000000000000000000000000000081565b34801561056257600080fd5b5061042f610571366004614209565b610e18565b34801561058257600080fd5b5061042f61059136600461419c565b610efd565b3480156105a257600080fd5b50610514606a5481565b3480156105b857600080fd5b5061042f6105c7366004614366565b61101c565b3480156105d857600080fd5b5061044b7f000000000000000000000000000000000000000000000000000000000000000081565b34801561060c57600080fd5b5061042f611078565b34801561062157600080fd5b5060335460ff165b604051901515815260200161045f565b34801561064557600080fd5b5061042f611117565b34801561065a57600080fd5b506105146106693660046140e8565b6111bd565b34801561067a57600080fd5b5061044b7f000000000000000000000000000000000000000000000000000000000000000081565b3480156106ae57600080fd5b50610514611c2081565b3480156106c457600080fd5b5061051460345481565b3480156106da57600080fd5b5060a35461044b906001600160a01b031681565b3480156106fa57600080fd5b5061042f6107093660046140e8565b6112f1565b34801561071a57600080fd5b5061042f6107293660046141c8565b611371565b34801561073a57600080fd5b5061042f61074936600461449e565b611885565b34801561075a57600080fd5b5060365461044b906001600160a01b031681565b34801561077a57600080fd5b5061044b610789366004614366565b611a47565b34801561079a57600080fd5b5061051460375481565b3480156107b057600080fd5b5061051460685481565b3480156107c657600080fd5b5061042f611a71565b3480156107db57600080fd5b5061042f611b3a565b3480156107f057600080fd5b5060335461044b9061010090046001600160a01b031681565b34801561081557600080fd5b5061042f61082436600461451f565b611d0c565b34801561083557600080fd5b5061044b7f000000000000000000000000000000000000000000000000000000000000000081565b34801561086957600080fd5b5061042f610878366004614366565b6121e1565b34801561088957600080fd5b5061042f6108983660046141c8565b6123ac565b3480156108a957600080fd5b506108cd6108b8366004614366565b60356020526000908152604090205460ff1681565b60405161045f919061498a565b3480156108e657600080fd5b5061042f6108f53660046140e8565b6124cc565b34801561090657600080fd5b50610629612546565b34801561091b57600080fd5b5061062961092a3660046140e8565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0390811691161490565b34801561096857600080fd5b5061042f610977366004614564565b6125a5565b34801561098857600080fd5b5061042f61268d565b34801561099d57600080fd5b5061042f6109ac3660046143ea565b612753565b3480156109bd57600080fd5b5061042f6109cc3660046140e8565b612920565b3480156109dd57600080fd5b506106296129ad565b3480156109f257600080fd5b506105146801bc16d674ec80000081565b348015610a0f57600080fd5b5061044b7f000000000000000000000000000000000000000000000000000000000000000081565b348015610a4357600080fd5b506105146101075481565b348015610a5a57600080fd5b5061042f610a693660046140e8565b6129de565b348015610a7a57600080fd5b5061042f610a8936600461415b565b612a82565b348015610a9a57600080fd5b5061042f610aa936600461437f565b612b15565b348015610aba57600080fd5b5061044b7f000000000000000000000000000000000000000000000000000000000000000081565b348015610aee57600080fd5b5061044b7f000000000000000000000000000000000000000000000000000000000000000081565b348015610b2257600080fd5b5061051460385481565b348015610b3857600080fd5b5061042f612cd3565b348015610b4d57600080fd5b50610514606b5481565b348015610b6357600080fd5b5061042f612e40565b348015610b7857600080fd5b5061044b7f000000000000000000000000000000000000000000000000000000000000000081565b348015610bac57600080fd5b50610bb5612eca565b60405161045f9190614760565b6000610bda600080516020614d2a8339815191525490565b905090565b610be76129ad565b610c035760405162461bcd60e51b8152600401610426906149fc565b610c0d8282612f2c565b5050565b610c196129ad565b610c355760405162461bcd60e51b8152600401610426906149fc565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b039081169083161415610cb25760405162461bcd60e51b815260206004820152601f60248201527f43616e6e6f74207472616e7366657220737570706f72746564206173736574006044820152606401610426565b610c0d610cbd610bc2565b6001600160a01b038416908361308b565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b158015610d2757600080fd5b505afa158015610d3b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d5f9190614105565b6001600160a01b0316336001600160a01b031614610d8f5760405162461bcd60e51b815260040161042690614abc565b60405163bc26e7e560e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063bc26e7e590610de19030908790879087906004016146b0565b600060405180830381600087803b158015610dfb57600080fd5b505af1158015610e0f573d6000803e3d6000fd5b50505050505050565b610e206129ad565b610e3c5760405162461bcd60e51b8152600401610426906149fc565b600054610100900460ff1680610e55575060005460ff16155b610eb85760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610426565b600054610100900460ff16158015610eda576000805461ffff19166101011790555b610ee58484846130dd565b8015610ef7576000805461ff00191690555b50505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610f455760405162461bcd60e51b8152600401610426906149c5565b600080516020614d0a83398151915280546002811415610f775760405162461bcd60e51b815260040161042690614a94565b600282557f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316846001600160a01b031614610ff05760405162461bcd60e51b8152602060048201526011602482015270155b9cdd5c1c1bdc9d195908185cdcd95d607a1b6044820152606401610426565b8261010760008282546110039190614be3565b9091555061101390508484613198565b50600190555050565b6110246129ad565b6110405760405162461bcd60e51b8152600401610426906149fc565b6040518181527fe26b067424903962f951f568e52ec9a3bbe1589526ea54a4e69ca6eaae1a4c779060200160405180910390a1603755565b60a3546001600160a01b031633146110d25760405162461bcd60e51b815260206004820152601b60248201527f43616c6c6572206973206e6f74207468652048617276657374657200000000006044820152606401610426565b600080516020614d0a833981519152805460028114156111045760405162461bcd60e51b815260040161042690614a94565b6002825561111061322a565b5060019055565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b0316146111b25760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b6064820152608401610426565b6111bb33613478565b565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b0316146112345760405162461bcd60e51b8152602060048201526011602482015270155b9cdd5c1c1bdc9d195908185cdcd95d607a1b6044820152606401610426565b6040516370a0823160e01b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b15801561129357600080fd5b505afa1580156112a7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112cb919061454b565b6034546112e1906801bc16d674ec800000614bfb565b6112eb9190614be3565b92915050565b6112f96129ad565b6113155760405162461bcd60e51b8152600401610426906149fc565b6040516001600160a01b038216907f83f29c79feb71f8fba9d0fbc4ba5f0982a28b6b1e868b3fc50e6400d100bca0f90600090a2603380546001600160a01b0390921661010002610100600160a81b0319909216919091179055565b60335461010090046001600160a01b031633146113a05760405162461bcd60e51b815260040161042690614a5d565b60335460ff16156113c35760405162461bcd60e51b815260040161042690614a33565b60006113d8826801bc16d674ec800000614bfb565b6040516370a0823160e01b81523060048201529091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b15801561143a57600080fd5b505afa15801561144e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611472919061454b565b8111156114b55760405162461bcd60e51b81526020600482015260116024820152700d2dce6eaccccd2c6d2cadce840ae8aa89607b1b6044820152606401610426565b603754816038546114c69190614be3565b11156115145760405162461bcd60e51b815260206004820152601a60248201527f5374616b696e6720455448206f766572207468726573686f6c640000000000006044820152606401610426565b80603860008282546115269190614be3565b9091555050604051632e1a7d4d60e01b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561158d57600080fd5b505af11580156115a1573d6000803e3d6000fd5b505050506115ae81613539565b60408051600160f81b60208201526000602182018190526bffffffffffffffffffffffff193060601b16602c830152910160408051601f1981840301815291905290508260005b8181101561186657600086868381811061161157611611614cba565b90506020028101906116239190614b39565b61162d9080614af3565b60405161163b929190614684565b604080519182900390912060008181526035602052919091205490915060ff16600181600481111561166f5761166f614c8e565b146116bc5760405162461bcd60e51b815260206004820152601860248201527f56616c696461746f72206e6f74207265676973746572656400000000000000006044820152606401610426565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663228951186801bc16d674ec8000008a8a8781811061170757611707614cba565b90506020028101906117199190614b39565b6117239080614af3565b898d8d8a81811061173657611736614cba565b90506020028101906117489190614b39565b611756906020810190614af3565b8f8f8c81811061176857611768614cba565b905060200281019061177a9190614b39565b604001356040518863ffffffff1660e01b815260040161179f9695949392919061490f565b6000604051808303818588803b1580156117b857600080fd5b505af11580156117cc573d6000803e3d6000fd5b5050505050817fd44c8fde6d369f70d395b6cdee4641886d11e3a72cb537696ca04134881692ed89898681811061180557611805614cba565b90506020028101906118179190614b39565b6118219080614af3565b6801bc16d674ec8000008960405161183c949392919061495e565b60405180910390a2506000908152603560205260409020805460ff191660021790556001016115f5565b5080603460008282546118799190614be3565b90915550505050505050565b60335461010090046001600160a01b031633146118b45760405162461bcd60e51b815260040161042690614a5d565b60335460ff16156118d75760405162461bcd60e51b815260040161042690614a33565b600085856040516118e9929190614684565b604080519182900390912060008181526035602052919091205490915060ff16600381600481111561191d5761191d614c8e565b146119625760405162461bcd60e51b815260206004820152601560248201527456616c696461746f72206e6f742065786974696e6760581b6044820152606401610426565b6040516312b3fc1960e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906312b3fc19906119b6908a908a908a908a908a906004016148ce565b600060405180830381600087803b1580156119d057600080fd5b505af11580156119e4573d6000803e3d6000fd5b50505050817f6aecca20726a17c1b81989b2fd09dfdf636bae9e564d4066ca18df62dc1f3dc288888888604051611a1e9493929190614845565b60405180910390a2506000908152603560205260409020805460ff191660041790555050505050565b60a48181548110611a5757600080fd5b6000918252602090912001546001600160a01b0316905081565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b158015611aca57600080fd5b505afa158015611ade573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b029190614105565b6001600160a01b0316336001600160a01b031614611b325760405162461bcd60e51b815260040161042690614abc565b6111bb613566565b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161480611b895750611b74610bc2565b6001600160a01b0316336001600160a01b0316145b611be15760405162461bcd60e51b815260206004820152602360248201527f43616c6c6572206973206e6f7420746865205661756c74206f7220476f7665726044820152623737b960e91b6064820152608401610426565b600080516020614d0a83398151915280546002811415611c135760405162461bcd60e51b815260040161042690614a94565b600282556040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b158015611c7957600080fd5b505afa158015611c8d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cb1919061454b565b90508015611d0457611d047f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000836135db565b505060019055565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b158015611d6557600080fd5b505afa158015611d79573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d9d9190614105565b6001600160a01b0316336001600160a01b031614611dcd5760405162461bcd60e51b815260040161042690614abc565b60335460ff16611e165760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610426565b43611c20606b54611e279190614be3565b10611e825760405162461bcd60e51b815260206004820152602560248201527f6d616e75616c6c794669784163636f756e74696e672063616c6c656420746f6f6044820152641039b7b7b760d91b6064820152608401610426565b6002198312158015611e95575060038313155b8015611eaf5750600083603454611eac9190614ba2565b12155b611efb5760405162461bcd60e51b815260206004820152601760248201527f696e76616c69642076616c696461746f727344656c74610000000000000000006044820152606401610426565b6811ff6cf0fd15afffff198212158015611f1e57506811ff6cf0fd15b000008213155b8015611f385750600082606854611f359190614ba2565b12155b611f845760405162461bcd60e51b815260206004820152601d60248201527f696e76616c696420636f6e73656e7375735265776172647344656c74610000006044820152606401610426565b68053444835ec5800000811115611fdd5760405162461bcd60e51b815260206004820152601960248201527f696e76616c69642077657468546f5661756c74416d6f756e74000000000000006044820152606401610426565b60408051848152602081018490529081018290527f80d022717ea022455c5886b8dd8a29c037570aae58aeb4d7b136d7a10ec2e4319060600160405180910390a18260345461202c9190614ba2565b60345560685461203d908390614ba2565b60685543606b55801561218b577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b1580156120a557600080fd5b505af11580156120b9573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb92506044019050602060405180830381600087803b15801561214957600080fd5b505af115801561215d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121819190614349565b5061218b816136d3565b612195600061373b565b6121d45760405162461bcd60e51b815260206004820152601060248201526f333ab9b29039ba34b63610313637bbb760811b6044820152606401610426565b6121dc613bba565b505050565b6121e96129ad565b6122055760405162461bcd60e51b8152600401610426906149fc565b60a05481106122465760405162461bcd60e51b815260206004820152600d60248201526c092dcecc2d8d2c840d2dcc8caf609b1b6044820152606401610426565b600060a0828154811061225b5761225b614cba565b60009182526020808320909101546001600160a01b03908116808452609f90925260409092205460a0549193509091169061229890600190614c1a565b83101561231a5760a080546122af90600190614c1a565b815481106122bf576122bf614cba565b60009182526020909120015460a080546001600160a01b0390921691859081106122eb576122eb614cba565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505b60a080548061232b5761232b614ca4565b60008281526020808220600019908401810180546001600160a01b031990811690915593019093556001600160a01b03858116808352609f855260409283902080549094169093559051908416815290917f16b7600acff27e39a8a96056b3d533045298de927507f5c1d97e4accde60488c910160405180910390a2505050565b6123b46129ad565b6123d05760405162461bcd60e51b8152600401610426906149fc565b8060005b818110156124835760008484838181106123f0576123f0614cba565b905060200201602081019061240591906140e8565b6001600160a01b031614156124735760405162461bcd60e51b815260206004820152602e60248201527f43616e206e6f742073657420616e20656d70747920616464726573732061732060448201526d30903932bbb0b932103a37b5b2b760911b6064820152608401610426565b61247c81614c5d565b90506123d4565b507f04c0b9649497d316554306e53678d5f5f5dbc3a06f97dec13ff4cfe98b986bbc60a484846040516124b8939291906147ad565b60405180910390a1610ef760a48484613e41565b6124d46129ad565b6124f05760405162461bcd60e51b8152600401610426906149fc565b6040516001600160a01b038216907f3329861a0008b3348767567d2405492b997abd79a088d0f2cef6b1a09a8e7ff790600090a2603680546001600160a01b0319166001600160a01b0392909216919091179055565b60335460009061010090046001600160a01b031633146125785760405162461bcd60e51b815260040161042690614a5d565b60335460ff161561259b5760405162461bcd60e51b815260040161042690614a33565b610bda600161373b565b6125ad6129ad565b6125c95760405162461bcd60e51b8152600401610426906149fc565b80821080156125e057506801bc16d674ec80000081105b80156125fd5750673782dace9d9000006125fa8383614c1a565b10155b6126495760405162461bcd60e51b815260206004820152601760248201527f696e636f7272656374206675736520696e74657276616c0000000000000000006044820152606401610426565b60408051838152602081018390527fcb8d24e46eb3c402bf344ee60a6576cba9ef2f59ea1af3b311520704924e901a910160405180910390a1606991909155606a55565b60405163095ea7b360e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015260001960248301527f0000000000000000000000000000000000000000000000000000000000000000169063095ea7b390604401602060405180830381600087803b15801561271857600080fd5b505af115801561272c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127509190614349565b50565b60335461010090046001600160a01b031633146127825760405162461bcd60e51b815260040161042690614a5d565b60335460ff16156127a55760405162461bcd60e51b815260040161042690614a33565b600088886040516127b7929190614684565b60405190819003902090506000808281526035602052604090205460ff1660048111156127e6576127e6614c8e565b146128335760405162461bcd60e51b815260206004820152601c60248201527f56616c696461746f7220616c72656164792072656769737465726564000000006044820152606401610426565b6040516301ba3ee760e21b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906306e8fb9c9061288d908c908c908c908c908c908c908c908c9060040161486c565b600060405180830381600087803b1580156128a757600080fd5b505af11580156128bb573d6000803e3d6000fd5b50505050807facd38e900350661e325d592c959664c0000a306efb2004e7dc283f44e0ea04238a8a8a8a6040516128f59493929190614845565b60405180910390a26000908152603560205260409020805460ff191660011790555050505050505050565b6129286129ad565b6129445760405162461bcd60e51b8152600401610426906149fc565b60a354604080516001600160a01b03928316815291831660208301527fe48386b84419f4d36e0f96c10cc3510b6fb1a33795620c5098b22472bbe90796910160405180910390a160a380546001600160a01b0319166001600160a01b0392909216919091179055565b60006129c5600080516020614d2a8339815191525490565b6001600160a01b0316336001600160a01b031614905090565b6129e66129ad565b612a025760405162461bcd60e51b8152600401610426906149fc565b612a2a817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b0316612a4a600080516020614d2a8339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614612aca5760405162461bcd60e51b8152600401610426906149c5565b600080516020614d0a83398151915280546002811415612afc5760405162461bcd60e51b815260040161042690614a94565b60028255612b0b8585856135db565b5060019055505050565b60335461010090046001600160a01b03163314612b445760405162461bcd60e51b815260040161042690614a5d565b60335460ff1615612b675760405162461bcd60e51b815260040161042690614a33565b60008484604051612b79929190614684565b604080519182900390912060008181526035602052919091205490915060ff166002816004811115612bad57612bad614c8e565b14612bf15760405162461bcd60e51b815260206004820152601460248201527315985b1a59185d1bdc881b9bdd081cdd185ad95960621b6044820152606401610426565b604051633877322b60e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690633877322b90612c43908990899089908990600401614845565b600060405180830381600087803b158015612c5d57600080fd5b505af1158015612c71573d6000803e3d6000fd5b50505050817f8c2e15303eb94e531acc988c2a01d1193bdaaa15eda7f16dda85316ed463578d87878787604051612cab9493929190614845565b60405180910390a2506000908152603560205260409020805460ff1916600317905550505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614612d1b5760405162461bcd60e51b8152600401610426906149c5565b600080516020614d0a83398151915280546002811415612d4d5760405162461bcd60e51b815260040161042690614a94565b600282556040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b158015612db357600080fd5b505afa158015612dc7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612deb919061454b565b905060006101075482612dfe9190614c1a565b90508015612e3657610107829055612e367f000000000000000000000000000000000000000000000000000000000000000082613198565b5050600182555050565b6036546001600160a01b03163314612e9a5760405162461bcd60e51b815260206004820152601960248201527f43616c6c6572206973206e6f7420746865204d6f6e69746f72000000000000006044820152606401610426565b6040517fe765a88a37047c5d793dce22b9ceb5a0f5039d276da139b4c7d29613f341f11090600090a16000603855565b606060a4805480602002602001604051908101604052809291908181526020018280548015612f2257602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612f04575b5050505050905090565b6001600160a01b038281166000908152609f60205260409020541615612f895760405162461bcd60e51b81526020600482015260126024820152711c151bdad95b88185b1c9958591e481cd95d60721b6044820152606401610426565b6001600160a01b03821615801590612fa957506001600160a01b03811615155b612fe95760405162461bcd60e51b8152602060048201526011602482015270496e76616c69642061646472657373657360781b6044820152606401610426565b6001600160a01b038281166000818152609f6020908152604080832080549587166001600160a01b0319968716811790915560a0805460018101825594527f78fdc8d422c49ced035a9edf18d00d3c6a8d81df210f3e5e448e045e77b41e8890930180549095168417909455925190815290917fef6485b84315f9b1483beffa32aae9a0596890395e3d7521f1c5fbb51790e765910160405180910390a25050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b1790526121dc908490613c34565b82516130f09060a4906020860190613ea4565b5081518151811461313a5760405162461bcd60e51b8152602060048201526014602482015273496e76616c696420696e7075742061727261797360601b6044820152606401610426565b60005b818110156131915761318184828151811061315a5761315a614cba565b602002602001015184838151811061317457613174614cba565b6020026020010151612f2c565b61318a81614c5d565b905061313d565b5050505050565b600081116131e15760405162461bcd60e51b81526020600482015260166024820152754d757374206465706f73697420736f6d657468696e6760501b6044820152606401610426565b6040805160008152602081018390526001600160a01b038416917f5548c837ab068cf56a2c2479df0882a4922fd203edb7517321831d95078c5f62910160405180910390a25050565b60335460ff161561324d5760405162461bcd60e51b815260040161042690614a33565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663e52253816040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156132aa57600080fd5b505af11580156132be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132e2919061454b565b90506000606854826132f49190614be3565b9050804710156133465760405162461bcd60e51b815260206004820152601860248201527f696e73756666696369656e74206574682062616c616e636500000000000000006044820152606401610426565b8015610c0d5760006068819055507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b1580156133af57600080fd5b505af11580156133c3573d6000803e3d6000fd5b505060a354604080516001600160a01b0392831681527f0000000000000000000000000000000000000000000000000000000000000000909216602083015281018590527ff6c07a063ed4e63808eb8da7112d46dbcd38de2b40a73dbcc9353c5a94c72353935060600191506134369050565b60405180910390a160a354610c0d906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811691168361308b565b6001600160a01b0381166134ce5760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f7220697320616464726573732830290000000000006044820152606401610426565b806001600160a01b03166134ee600080516020614d2a8339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a361275081600080516020614d2a83398151915255565b60006135488261010754613d06565b905080610107600082825461355d9190614c1a565b90915550505050565b60335460ff16156135895760405162461bcd60e51b815260040161042690614a33565b6033805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586135be3390565b6040516001600160a01b03909116815260200160405180910390a1565b6000811161362b5760405162461bcd60e51b815260206004820152601760248201527f4d75737420776974686472617720736f6d657468696e670000000000000000006044820152606401610426565b6001600160a01b03831661367a5760405162461bcd60e51b8152602060048201526016602482015275135d5cdd081cdc1958da599e481c9958da5c1a595b9d60521b6044820152606401610426565b6040805160008152602081018390526001600160a01b038416917f2717ead6b9200dd235aad468c9809ea400fe33ac69b5bfaa6d3e90fc922b6398910160405180910390a26121dc6001600160a01b038316848361308b565b6040805160008152602081018390526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016917f2717ead6b9200dd235aad468c9809ea400fe33ac69b5bfaa6d3e90fc922b6398910160405180910390a250565b6000606854471015613750576112eb82613d1e565b6000606854476137609190614c1a565b9050600191506801bc16d674ec800000811061393d5760006801bc16d674ec8000008204905080603460008282546137989190614c1a565b90915550600090506137b3826801bc16d674ec800000614bfb565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b15801561381057600080fd5b505af1158015613824573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb92506044019050602060405180830381600087803b1580156138b457600080fd5b505af11580156138c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138ec9190614349565b506138f6816136d3565b60345460408051848152602081019290925281018290527fbe7040030ff7b347853214bf49820c6d455fedf58f3815f85c7bc5216993682b9060600160405180910390a150505b60006068544761394d9190614c1a565b90506801bc16d674ec800000811061399f5760405162461bcd60e51b8152602060048201526015602482015274756e6578706563746564206163636f756e74696e6760581b6044820152606401610426565b806139ab575050919050565b606954811015613a055780606860008282546139c79190614be3565b90915550506040518181527f7a745a2c63a535068f52ceca27debd5297bbad5f7f37ec53d044a59d0362445d906020015b60405180910390a1613bb3565b606a54811115613ba2577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b158015613a6a57600080fd5b505af1158015613a7e573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb92506044019050602060405180830381600087803b158015613b0e57600080fd5b505af1158015613b22573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b469190614349565b50600160346000828254613b5a9190614c1a565b90915550613b699050816136d3565b60345460408051918252602082018390527f6aa7e30787b26429ced603a7aba8b19c4b5d5bcf29a3257da953c8d53bcaa3a691016139f8565b613bab84613d1e565b949350505050565b5050919050565b60335460ff16613c035760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610426565b6033805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa336135be565b6000613c89826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316613d369092919063ffffffff16565b8051909150156121dc5780806020019051810190613ca79190614349565b6121dc5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610426565b6000818310613d155781613d17565b825b9392505050565b60008115613d2e57613d2e613566565b506000919050565b6060613bab848460008585843b613d8f5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610426565b600080866001600160a01b03168587604051613dab9190614694565b60006040518083038185875af1925050503d8060008114613de8576040519150601f19603f3d011682016040523d82523d6000602084013e613ded565b606091505b5091509150613dfd828286613e08565b979650505050505050565b60608315613e17575081613d17565b825115613e275782518084602001fd5b8160405162461bcd60e51b815260040161042691906149b2565b828054828255906000526020600020908101928215613e94579160200282015b82811115613e945781546001600160a01b0319166001600160a01b03843516178255602090920191600190910190613e61565b50613ea0929150613ef9565b5090565b828054828255906000526020600020908101928215613e94579160200282015b82811115613e9457825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190613ec4565b5b80821115613ea05760008155600101613efa565b60008083601f840112613f2057600080fd5b5081356001600160401b03811115613f3757600080fd5b6020830191508360208260051b8501011115613f5257600080fd5b9250929050565b600082601f830112613f6a57600080fd5b81356020613f7f613f7a83614b7f565b614b4f565b80838252828201915082860187848660051b8901011115613f9f57600080fd5b60005b85811015613fc7578135613fb581614ce6565b84529284019290840190600101613fa2565b5090979650505050505050565b60008083601f840112613fe657600080fd5b5081356001600160401b03811115613ffd57600080fd5b602083019150836020828501011115613f5257600080fd5b600060a0828403121561402757600080fd5b50919050565b600060a0828403121561403f57600080fd5b60405160a081018181106001600160401b038211171561406157614061614cd0565b604052905080614070836140b8565b815261407e602084016140d1565b602082015261408f604084016140d1565b604082015260608301356140a281614cfb565b6060820152608092830135920191909152919050565b803563ffffffff811681146140cc57600080fd5b919050565b80356001600160401b03811681146140cc57600080fd5b6000602082840312156140fa57600080fd5b8135613d1781614ce6565b60006020828403121561411757600080fd5b8151613d1781614ce6565b6000806040838503121561413557600080fd5b823561414081614ce6565b9150602083013561415081614ce6565b809150509250929050565b60008060006060848603121561417057600080fd5b833561417b81614ce6565b9250602084013561418b81614ce6565b929592945050506040919091013590565b600080604083850312156141af57600080fd5b82356141ba81614ce6565b946020939093013593505050565b600080602083850312156141db57600080fd5b82356001600160401b038111156141f157600080fd5b6141fd85828601613f0e565b90969095509350505050565b60008060006060848603121561421e57600080fd5b83356001600160401b038082111561423557600080fd5b61424187838801613f59565b9450602086013591508082111561425757600080fd5b61426387838801613f59565b9350604086013591508082111561427957600080fd5b5061428686828701613f59565b9150509250925092565b600080600060e084860312156142a557600080fd5b83356001600160401b038111156142bb57600080fd5b8401601f810186136142cc57600080fd5b803560206142dc613f7a83614b7f565b8083825282820191508285018a848660051b88010111156142fc57600080fd5b600095505b8486101561432657614312816140d1565b835260019590950194918301918301614301565b50965050860135935061434091508690506040860161402d565b90509250925092565b60006020828403121561435b57600080fd5b8151613d1781614cfb565b60006020828403121561437857600080fd5b5035919050565b6000806000806040858703121561439557600080fd5b84356001600160401b03808211156143ac57600080fd5b6143b888838901613fd4565b909650945060208701359150808211156143d157600080fd5b506143de87828801613f0e565b95989497509550505050565b600080600080600080600080610120898b03121561440757600080fd5b88356001600160401b038082111561441e57600080fd5b61442a8c838d01613fd4565b909a50985060208b013591508082111561444357600080fd5b61444f8c838d01613f0e565b909850965060408b013591508082111561446857600080fd5b506144758b828c01613fd4565b9095509350506060890135915061448f8a60808b01614015565b90509295985092959890939650565b600080600080600060e086880312156144b657600080fd5b85356001600160401b03808211156144cd57600080fd5b6144d989838a01613fd4565b909750955060208801359150808211156144f257600080fd5b506144ff88828901613f0e565b909450925061451390508760408801614015565b90509295509295909350565b60008060006060848603121561453457600080fd5b505081359360208301359350604090920135919050565b60006020828403121561455d57600080fd5b5051919050565b6000806040838503121561457757600080fd5b50508035926020909101359150565b8183526000602080850194508260005b858110156145c2576001600160401b036145af836140d1565b1687529582019590820190600101614596565b509495945050505050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6000815180845261460e816020860160208601614c31565b601f01601f19169290920160200192915050565b63ffffffff614630826140b8565b16825261463f602082016140d1565b6001600160401b0380821660208501528061465c604085016140d1565b1660408501525050606081013561467281614cfb565b15156060830152608090810135910152565b8183823760009101908152919050565b600082516146a6818460208701614c31565b9190910192915050565b6001600160a01b03851681526101006020808301829052855191830182905260009161012084019187810191845b818110156147035783516001600160401b0316855293820193928201926001016146de565b505082935086604086015263ffffffff865116606086015280860151925050506001600160401b0380821660808501528060408601511660a085015250506060830151151560c0830152608083015160e083015295945050505050565b6020808252825182820181905260009190848201906040850190845b818110156147a15783516001600160a01b03168352928401929184019160010161477c565b50909695505050505050565b6000604082016040835280865480835260608501915087600052602092508260002060005b828110156147f75781546001600160a01b0316845292840192600191820191016147d2565b505050838103828501528481528590820160005b8681101561483957823561481e81614ce6565b6001600160a01b03168252918301919083019060010161480b565b50979650505050505050565b6040815260006148596040830186886145cd565b8281036020840152613dfd818587614586565b60006101208083526148818184018b8d6145cd565b9050828103602084015261489681898b614586565b905082810360408401526148ab8187896145cd565b9150508360608301526148c16080830184614622565b9998505050505050505050565b60e0815260006148e260e0830187896145cd565b82810360208401526148f5818688614586565b9150506149056040830184614622565b9695505050505050565b60808152600061492360808301888a6145cd565b828103602084015261493581886145f6565b9050828103604084015261494a8186886145cd565b915050826060830152979650505050505050565b6060815260006149726060830186886145cd565b8460208401528281036040840152613dfd81856145f6565b60208101600583106149ac57634e487b7160e01b600052602160045260246000fd5b91905290565b602081526000613d1760208301846145f6565b60208082526017908201527f43616c6c6572206973206e6f7420746865205661756c74000000000000000000604082015260600190565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b60208082526010908201526f14185d5cd8589b194e881c185d5cd95960821b604082015260600190565b6020808252601d908201527f43616c6c6572206973206e6f7420746865205265676973747261746f72000000604082015260600190565b6020808252600e908201526d1499595b9d1c985b9d0818d85b1b60921b604082015260600190565b6020808252601c908201527f43616c6c6572206973206e6f7420746865205374726174656769737400000000604082015260600190565b6000808335601e19843603018112614b0a57600080fd5b8301803591506001600160401b03821115614b2457600080fd5b602001915036819003821315613f5257600080fd5b60008235605e198336030181126146a657600080fd5b604051601f8201601f191681016001600160401b0381118282101715614b7757614b77614cd0565b604052919050565b60006001600160401b03821115614b9857614b98614cd0565b5060051b60200190565b600080821280156001600160ff1b0384900385131615614bc457614bc4614c78565b600160ff1b8390038412811615614bdd57614bdd614c78565b50500190565b60008219821115614bf657614bf6614c78565b500190565b6000816000190483118215151615614c1557614c15614c78565b500290565b600082821015614c2c57614c2c614c78565b500390565b60005b83811015614c4c578181015183820152602001614c34565b83811115610ef75750506000910152565b6000600019821415614c7157614c71614c78565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b038116811461275057600080fd5b801515811461275057600080fdfe53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac45357bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa26469706673582212204d8c7ebaf4c2264e2fd90a3c201009d9efc50419a225e0b4f7f4c66aac9378b664736f6c63430008070033", + "numDeployments": 7, + "solcInputHash": "47ae51f49254a864e8595718d22928c8", + "metadata": "{\"compiler\":{\"version\":\"0.8.7+commit.e28d00a7\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"platformAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"vaultAddress\",\"type\":\"address\"}],\"internalType\":\"struct InitializableAbstractStrategy.BaseStrategyConfig\",\"name\":\"_baseConfig\",\"type\":\"tuple\"},{\"internalType\":\"address\",\"name\":\"_wethAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_ssvToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_ssvNetwork\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_maxValidators\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_feeAccumulator\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_beaconChainDepositContract\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"AccountingConsensusRewards\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"noOfValidators\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"remainingValidators\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"wethSentToVault\",\"type\":\"uint256\"}],\"name\":\"AccountingFullyWithdrawnValidator\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"validatorsDelta\",\"type\":\"int256\"},{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"consensusRewardsDelta\",\"type\":\"int256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"wethToVault\",\"type\":\"uint256\"}],\"name\":\"AccountingManuallyFixed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"remainingValidators\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"wethSentToVault\",\"type\":\"uint256\"}],\"name\":\"AccountingValidatorSlashed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"Deposit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"pubKeyHash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"pubKey\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"withdrawal_credentials\",\"type\":\"bytes\"}],\"name\":\"ETHStaked\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"start\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"end\",\"type\":\"uint256\"}],\"name\":\"FuseIntervalUpdated\",\"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\":\"address\",\"name\":\"_oldHarvesterAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_newHarvesterAddress\",\"type\":\"address\"}],\"name\":\"HarvesterAddressesUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"}],\"name\":\"PTokenAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"}],\"name\":\"PTokenRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Paused\",\"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\":true,\"internalType\":\"address\",\"name\":\"newAddress\",\"type\":\"address\"}],\"name\":\"RegistratorChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"_oldAddresses\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"_newAddresses\",\"type\":\"address[]\"}],\"name\":\"RewardTokenAddressesUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"rewardToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"RewardTokenCollected\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"pubKeyHash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"pubKey\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"}],\"name\":\"SSVValidatorExitCompleted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"pubKeyHash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"pubKey\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"}],\"name\":\"SSVValidatorExitInitiated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"pubKeyHash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"pubKey\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"}],\"name\":\"SSVValidatorRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"StakeETHTallyReset\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"StakeETHThresholdChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newAddress\",\"type\":\"address\"}],\"name\":\"StakingMonitorChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Unpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"Withdrawal\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"BEACON_CHAIN_DEPOSIT_CONTRACT\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_ACCUMULATOR_ADDRESS\",\"outputs\":[{\"internalType\":\"address payable\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MAX_STAKE\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MAX_VALIDATORS\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MIN_FIX_ACCOUNTING_CADENCE\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"SSV_NETWORK_ADDRESS\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"SSV_TOKEN_ADDRESS\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"VAULT_ADDRESS\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"WETH_TOKEN_ADDRESS\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"activeDepositedValidators\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"assetToPToken\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"}],\"name\":\"checkBalance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"claimGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"collectRewardTokens\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"consensusRewards\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"depositAll\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"},{\"internalType\":\"uint256\",\"name\":\"ssvAmount\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"validatorCount\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"networkFeeIndex\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"index\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"active\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"internalType\":\"struct Cluster\",\"name\":\"cluster\",\"type\":\"tuple\"}],\"name\":\"depositSSV\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"depositedWethAccountedFor\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"doAccounting\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"accountingValid\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"publicKey\",\"type\":\"bytes\"},{\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"}],\"name\":\"exitSsvValidator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fuseIntervalEnd\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fuseIntervalStart\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRewardTokenAddresses\",\"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\":\"harvesterAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"_rewardTokenAddresses\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"_assets\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"_pTokens\",\"type\":\"address[]\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isGovernor\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastFixAccountingBlockNumber\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"int256\",\"name\":\"_validatorsDelta\",\"type\":\"int256\"},{\"internalType\":\"int256\",\"name\":\"_consensusRewardsDelta\",\"type\":\"int256\"},{\"internalType\":\"uint256\",\"name\":\"_ethToVaultAmount\",\"type\":\"uint256\"}],\"name\":\"manuallyFixAccounting\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"paused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"platformAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"publicKey\",\"type\":\"bytes\"},{\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"},{\"internalType\":\"bytes\",\"name\":\"sharesData\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"ssvAmount\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"validatorCount\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"networkFeeIndex\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"index\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"active\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"internalType\":\"struct Cluster\",\"name\":\"cluster\",\"type\":\"tuple\"}],\"name\":\"registerSsvValidator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_assetIndex\",\"type\":\"uint256\"}],\"name\":\"removePToken\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"publicKey\",\"type\":\"bytes\"},{\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"validatorCount\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"networkFeeIndex\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"index\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"active\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"internalType\":\"struct Cluster\",\"name\":\"cluster\",\"type\":\"tuple\"}],\"name\":\"removeSsvValidator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"resetStakeETHTally\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"rewardTokenAddresses\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"safeApproveAllTokens\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_fuseIntervalStart\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_fuseIntervalEnd\",\"type\":\"uint256\"}],\"name\":\"setFuseInterval\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_harvesterAddress\",\"type\":\"address\"}],\"name\":\"setHarvesterAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"}],\"name\":\"setPTokenAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"setRegistrator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"_rewardTokenAddresses\",\"type\":\"address[]\"}],\"name\":\"setRewardTokenAddresses\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"setStakeETHThreshold\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"setStakingMonitor\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"stakeETHTally\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"stakeETHThreshold\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"pubkey\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"depositDataRoot\",\"type\":\"bytes32\"}],\"internalType\":\"struct ValidatorStakeData[]\",\"name\":\"validators\",\"type\":\"tuple[]\"}],\"name\":\"stakeEth\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"stakingMonitor\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"}],\"name\":\"supportsAsset\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"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\":\"validatorRegistrator\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"validatorsStates\",\"outputs\":[{\"internalType\":\"enum ValidatorRegistrator.VALIDATOR_STATE\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"vaultAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"withdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdrawAll\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"author\":\"Origin Protocol Inc\",\"details\":\"This contract handles WETH and ETH and in some operations interchanges between the two. Any WETH that is on the contract across multiple blocks (and not just transitory within a transaction) is considered an asset. Meaning deposits increase the balance of the asset and withdrawal decrease it. As opposed to all our other strategies the WETH doesn't immediately get deposited into an underlying strategy and can be present across multiple blocks waiting to be unwrapped to ETH and staked to validators. This separation of WETH and ETH is required since the rewards (reward token) is also in ETH. To simplify the accounting of WETH there is another difference in behavior compared to the other strategies. To withdraw WETH asset - exit message is posted to validators and the ETH hits this contract with multiple days delay. In order to simplify the WETH accounting upon detection of such an event the ValidatorAccountant immediately wraps ETH to WETH and sends it to the Vault. On the other hand any ETH on the contract (across multiple blocks) is there either: - as a result of already accounted for consensus rewards - as a result of not yet accounted for consensus rewards - as a results of not yet accounted for full validator withdrawals (or validator slashes) Even though the strategy assets and rewards are a very similar asset the consensus layer rewards and the execution layer rewards are considered rewards and those are dripped to the Vault over a configurable time interval and not immediately.\",\"kind\":\"dev\",\"methods\":{\"checkBalance(address)\":{\"params\":{\"_asset\":\"Address of weth asset\"},\"returns\":{\"balance\":\" Total value of (W)ETH\"}},\"constructor\":{\"params\":{\"_baseConfig\":\"Base strategy config with platformAddress (ERC-4626 Vault contract), eg sfrxETH or sDAI, and vaultAddress (OToken Vault contract), eg VaultProxy or OETHVaultProxy\",\"_beaconChainDepositContract\":\"Address of the beacon chain deposit contract\",\"_feeAccumulator\":\"Address of the fee accumulator receiving execution layer validator rewards\",\"_maxValidators\":\"Maximum number of validators that can be registered in the strategy\",\"_ssvNetwork\":\"Address of the SSV Network contract\",\"_ssvToken\":\"Address of the Erc20 SSV Token contract\",\"_wethAddress\":\"Address of the Erc20 WETH Token contract\"}},\"deposit(address,uint256)\":{\"params\":{\"_amount\":\"Amount of assets that were transferred to the strategy by the vault.\",\"_asset\":\"Address of asset to deposit. Has to be WETH.\"}},\"depositSSV(uint64[],uint256,(uint32,uint64,uint64,bool,uint256))\":{\"details\":\"A SSV cluster is defined by the SSVOwnerAddress and the set of operatorIds. uses \\\"onlyStrategist\\\" modifier so continuous front-running can't DOS our maintenance service that tries to top up SSV tokens.\",\"params\":{\"cluster\":\"The SSV cluster details including the validator count and SSV balance\",\"operatorIds\":\"The operator IDs of the SSV Cluster\",\"ssvAmount\":\"The amount of SSV tokens to be deposited to the SSV cluster\"}},\"doAccounting()\":{\"details\":\"This function could in theory be permission-less but lets allow only the Registrator (Defender Action) to call it for now.\",\"returns\":{\"accountingValid\":\"true if accounting was successful, false if fuse is blown\"}},\"exitSsvValidator(bytes,uint64[])\":{\"params\":{\"operatorIds\":\"The operator IDs of the SSV Cluster\",\"publicKey\":\"The public key of the validator\"}},\"getRewardTokenAddresses()\":{\"returns\":{\"_0\":\"address[] the reward token addresses.\"}},\"initialize(address[],address[],address[])\":{\"params\":{\"_assets\":\"Addresses of initial supported assets\",\"_pTokens\":\"Platform Token corresponding addresses\",\"_rewardTokenAddresses\":\"Address of reward token for platform\"}},\"manuallyFixAccounting(int256,int256,uint256)\":{\"details\":\"There is a case when a validator(s) gets slashed so much that the eth swept from the beacon chain enters the fuse area and there are no consensus rewards on the contract to \\\"dip into\\\"/use. To increase the amount of unaccounted ETH over the fuse end interval we need to reduce the amount of active deposited validators and immediately send WETH to the vault, so it doesn't interfere with further accounting.\",\"params\":{\"_consensusRewardsDelta\":\"adjust the accounted for consensus rewards up or down\",\"_ethToVaultAmount\":\"the amount of ETH that gets wrapped into WETH and sent to the Vault\",\"_validatorsDelta\":\"adjust the active validators by up to plus three or minus three\"}},\"paused()\":{\"details\":\"Returns true if the contract is paused, and false otherwise.\"},\"registerSsvValidator(bytes,uint64[],bytes,uint256,(uint32,uint64,uint64,bool,uint256))\":{\"params\":{\"cluster\":\"The SSV cluster details including the validator count and SSV balance\",\"operatorIds\":\"The operator IDs of the SSV Cluster\",\"publicKey\":\"The public key of the validator\",\"sharesData\":\"The validator shares data\",\"ssvAmount\":\"The amount of SSV tokens to be deposited to the SSV cluster\"}},\"removePToken(uint256)\":{\"params\":{\"_assetIndex\":\"Index of the asset to be removed\"}},\"removeSsvValidator(bytes,uint64[],(uint32,uint64,uint64,bool,uint256))\":{\"params\":{\"cluster\":\"The SSV cluster details including the validator count and SSV balance\",\"operatorIds\":\"The operator IDs of the SSV Cluster\",\"publicKey\":\"The public key of the validator\"}},\"setHarvesterAddress(address)\":{\"params\":{\"_harvesterAddress\":\"Address of the harvester contract.\"}},\"setPTokenAddress(address,address)\":{\"params\":{\"_asset\":\"Address for the asset\",\"_pToken\":\"Address for the corresponding platform token\"}},\"setRewardTokenAddresses(address[])\":{\"params\":{\"_rewardTokenAddresses\":\"Array of reward token addresses\"}},\"stakeEth((bytes,bytes,bytes32)[])\":{\"params\":{\"validators\":\"A list of validator data needed to stake. The `ValidatorStakeData` struct contains the pubkey, signature and depositDataRoot. Only the registrator can call this function.\"}},\"supportsAsset(address)\":{\"params\":{\"_asset\":\"The address of the asset token.\"}},\"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\"}},\"withdraw(address,address,uint256)\":{\"params\":{\"_amount\":\"Amount of WETH to withdraw\",\"_asset\":\"WETH to withdraw\",\"_recipient\":\"Address to receive withdrawn assets\"}}},\"stateVariables\":{\"FEE_ACCUMULATOR_ADDRESS\":{\"details\":\"this address will receive Execution layer rewards - These are rewards earned for executing transactions on the Ethereum network as part of block proposals. They include priority fees (fees paid by users for their transactions to be included) and MEV rewards (rewards for arranging transactions in a way that benefits the validator).\"},\"depositedWethAccountedFor\":{\"details\":\"This contract receives WETH as the deposit asset, but unlike other strategies doesn't immediately deposit it to an underlying platform. Rather a special privilege account stakes it to the validators. For that reason calling WETH.balanceOf(this) in a deposit function can contain WETH that has just been deposited and also WETH that has previously been deposited. To keep a correct count we need to keep track of WETH that has already been accounted for. This value represents the amount of WETH balance of this contract that has already been accounted for by the deposit events. It is important to note that this variable is not concerned with WETH that is a result of full/partial withdrawal of the validators. It is strictly concerned with WETH that has been deposited and is waiting to be staked.\"}},\"title\":\"Native Staking SSV Strategy\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"BEACON_CHAIN_DEPOSIT_CONTRACT()\":{\"notice\":\"The address of the beacon chain deposit contract\"},\"FEE_ACCUMULATOR_ADDRESS()\":{\"notice\":\"Fee collector address\"},\"MAX_STAKE()\":{\"notice\":\"The maximum amount of ETH that can be staked by a validator\"},\"MAX_VALIDATORS()\":{\"notice\":\"Maximum number of validators that can be registered in this strategy\"},\"MIN_FIX_ACCOUNTING_CADENCE()\":{\"notice\":\"The minimum amount of blocks that need to pass between two calls to manuallyFixAccounting\"},\"SSV_NETWORK_ADDRESS()\":{\"notice\":\"The address of the SSV Network contract used to interface with\"},\"SSV_TOKEN_ADDRESS()\":{\"notice\":\"SSV ERC20 token that serves as a payment for operating SSV validators\"},\"VAULT_ADDRESS()\":{\"notice\":\"Address of the OETH Vault proxy contract\"},\"WETH_TOKEN_ADDRESS()\":{\"notice\":\"The address of the Wrapped ETH (WETH) token contract\"},\"activeDepositedValidators()\":{\"notice\":\"The number of validators that have 32 (!) ETH actively deposited. When a new deposit to a validator happens this number increases, when a validator exit is detected this number decreases.\"},\"assetToPToken(address)\":{\"notice\":\"asset => pToken (Platform Specific Token Address)\"},\"checkBalance(address)\":{\"notice\":\"Returns the total value of (W)ETH that is staked to the validators and WETH deposits that are still to be staked. This does not include ETH from consensus rewards sitting in this strategy or ETH from MEV rewards in the FeeAccumulator. These rewards are harvested and sent to the Dripper so will eventually be sent to the Vault as WETH.\"},\"claimGovernance()\":{\"notice\":\"Claim Governance of the contract to a new account (`newGovernor`). Can only be called by the new Governor.\"},\"collectRewardTokens()\":{\"notice\":\"Collect accumulated reward token and send to Vault.\"},\"consensusRewards()\":{\"notice\":\"Keeps track of the total consensus rewards swept from the beacon chain\"},\"deposit(address,uint256)\":{\"notice\":\"Unlike other strategies, this does not deposit assets into the underlying platform. It just checks the asset is WETH and emits the Deposit event. To deposit WETH into validators `registerSsvValidator` and `stakeEth` must be used. Will NOT revert if the strategy is paused from an accounting failure.\"},\"depositAll()\":{\"notice\":\"Unlike other strategies, this does not deposit assets into the underlying platform. It just emits the Deposit event. To deposit WETH into validators `registerSsvValidator` and `stakeEth` must be used. Will NOT revert if the strategy is paused from an accounting failure.\"},\"depositSSV(uint64[],uint256,(uint32,uint64,uint64,bool,uint256))\":{\"notice\":\"Deposits more SSV Tokens to the SSV Network contract which is used to pay the SSV Operators.\"},\"doAccounting()\":{\"notice\":\"This notion page offers a good explanation of how the accounting functions https://www.notion.so/originprotocol/Limited-simplified-native-staking-accounting-67a217c8420d40678eb943b9da0ee77d In short, after dividing by 32, if the ETH remaining on the contract falls between 0 and fuseIntervalStart, the accounting function will treat that ETH as Beacon chain consensus rewards. On the contrary, if after dividing by 32, the ETH remaining on the contract falls between fuseIntervalEnd and 32, the accounting function will treat that as a validator slashing.Perform the accounting attributing beacon chain ETH to either full or partial withdrawals. Returns true when accounting is valid and fuse isn't \\\"blown\\\". Returns false when fuse is blown.\"},\"exitSsvValidator(bytes,uint64[])\":{\"notice\":\"Exit a validator from the Beacon chain. The staked ETH will eventually swept to this native staking strategy. Only the registrator can call this function.\"},\"fuseIntervalEnd()\":{\"notice\":\"end of fuse interval\"},\"fuseIntervalStart()\":{\"notice\":\"start of fuse interval\"},\"getRewardTokenAddresses()\":{\"notice\":\"Get the reward token addresses.\"},\"governor()\":{\"notice\":\"Returns the address of the current Governor.\"},\"harvesterAddress()\":{\"notice\":\"Address of the Harvester contract allowed to collect reward tokens\"},\"initialize(address[],address[],address[])\":{\"notice\":\"initialize function, to set up initial internal state\"},\"isGovernor()\":{\"notice\":\"Returns true if the caller is the current Governor.\"},\"lastFixAccountingBlockNumber()\":{\"notice\":\"last block number manuallyFixAccounting has been called\"},\"manuallyFixAccounting(int256,int256,uint256)\":{\"notice\":\"Allow the Strategist to fix the accounting of this strategy and unpause.\"},\"platformAddress()\":{\"notice\":\"Address of the underlying platform\"},\"registerSsvValidator(bytes,uint64[],bytes,uint256,(uint32,uint64,uint64,bool,uint256))\":{\"notice\":\"Registers a new validator in the SSV Cluster. Only the registrator can call this function.\"},\"removePToken(uint256)\":{\"notice\":\"Remove a supported asset by passing its index. This method can only be called by the system Governor\"},\"removeSsvValidator(bytes,uint64[],(uint32,uint64,uint64,bool,uint256))\":{\"notice\":\"Remove a validator from the SSV Cluster. Make sure `exitSsvValidator` is called before and the validate has exited the Beacon chain. If removed before the validator has exited the beacon chain will result in the validator being slashed. Only the registrator can call this function.\"},\"resetStakeETHTally()\":{\"notice\":\"Reset the stakeETHTally\"},\"rewardTokenAddresses(uint256)\":{\"notice\":\"Address of the reward tokens. eg CRV, BAL, CVX, AURA\"},\"safeApproveAllTokens()\":{\"notice\":\"Approves the SSV Network contract to transfer SSV tokens for deposits\"},\"setFuseInterval(uint256,uint256)\":{\"notice\":\"set fuse interval values\"},\"setHarvesterAddress(address)\":{\"notice\":\"Set the Harvester contract that can collect rewards.\"},\"setPTokenAddress(address,address)\":{\"notice\":\"Provide support for asset by passing its pToken address. This method can only be called by the system Governor\"},\"setRegistrator(address)\":{\"notice\":\"Set the address of the registrator which can register, exit and remove validators\"},\"setRewardTokenAddresses(address[])\":{\"notice\":\"Set the reward token addresses. Any old addresses will be overwritten.\"},\"setStakeETHThreshold(uint256)\":{\"notice\":\"Set the amount of ETH that can be staked before staking monitor\"},\"setStakingMonitor(address)\":{\"notice\":\"Set the address of the staking monitor that is allowed to reset stakeETHTally\"},\"stakeETHTally()\":{\"notice\":\"Amount of ETH that can has been staked since the last governor approval.\"},\"stakeETHThreshold()\":{\"notice\":\"Amount of ETH that can be staked before staking on the contract is suspended and the governor needs to approve further staking\"},\"stakeEth((bytes,bytes,bytes32)[])\":{\"notice\":\"Stakes WETH to the node validators\"},\"stakingMonitor()\":{\"notice\":\"The account that is allowed to modify stakeETHThreshold and reset stakeETHTally\"},\"supportsAsset(address)\":{\"notice\":\"Returns bool indicating whether asset is supported by strategy.\"},\"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 strategy contracts, i.e. mistaken sends.\"},\"validatorRegistrator()\":{\"notice\":\"Address of the registrator - allowed to register, exit and remove validators\"},\"validatorsStates(bytes32)\":{\"notice\":\"State of the validators keccak256(pubKey) => state\"},\"vaultAddress()\":{\"notice\":\"Address of the OToken vault\"},\"withdraw(address,address,uint256)\":{\"notice\":\"Withdraw WETH from this contract. Used only if some WETH for is lingering on the contract. That can happen when: - the deposit was not a multiple of 32 WETH - someone sent WETH directly to this contract Will NOT revert if the strategy is paused from an accounting failure.\"},\"withdrawAll()\":{\"notice\":\"transfer all WETH deposits back to the vault. This does not withdraw from the validators. That has to be done separately with the `exitSsvValidator` and `removeSsvValidator` operations. This does not withdraw any execution rewards from the FeeAccumulator or consensus rewards in this strategy. Any ETH in this strategy that was swept from a full validator withdrawal will not be withdrawn. ETH from full validator withdrawals is sent to the Vault using `doAccounting`. Will NOT revert if the strategy is paused from an accounting failure.\"}},\"notice\":\"Strategy to deploy funds into DVT validators powered by the SSV Network\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol\":\"NativeStakingSSVStrategy\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"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\",\"keccak256\":\"0xe68ed7fb8766ed1e888291f881e36b616037f852b37d96877045319ad298ba87\",\"license\":\"MIT\"},\"@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/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\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@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\",\"keccak256\":\"0xfaad496c1c944b6259b7dc70b4865eb1775d6402bc0c81b38a0b24d9f525ae37\",\"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/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\",\"keccak256\":\"0x598f90bdbc854250bbd5991426bfb43367207e64e33109c41aa8b54323fd8d8e\",\"license\":\"MIT\"},\"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 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 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 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\",\"keccak256\":\"0xbef02bd5257e61dec0a6be4b1531064a7fdfeb4043885443a1902fb5d1b23e1b\",\"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/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 function removeAsset(address _asset) external;\\n}\\n\",\"keccak256\":\"0xa03ba17b6224bec26290794760fc807e017260406037b4f812970701888e72c8\",\"license\":\"MIT\"},\"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\",\"keccak256\":\"0x05b7dce6c24d3cd4e48b5c6346d86e5e40ecc3291bcdf3f3ef091c98fc826519\",\"license\":\"MIT\"},\"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\\nimport { Governable } from \\\"../../governance/Governable.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 is Governable {\\n /// @notice The address of the Native Staking Strategy\\n address public immutable STRATEGY;\\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 }\\n\\n /**\\n * @dev Accept ETH\\n */\\n receive() external payable {}\\n}\\n\",\"keccak256\":\"0xb8fda3b87dc5d6f8aee4bf1d015a585211e5b5a319dfa4b0f4770e3f5a2d5939\",\"license\":\"MIT\"},\"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_ADDRESS;\\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_ADDRESS = _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 /// @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_TOKEN_ADDRESS).deposit{ value: ethRewards }();\\n\\n emit RewardTokenCollected(\\n harvesterAddress,\\n WETH_TOKEN_ADDRESS,\\n ethRewards\\n );\\n IERC20(WETH_TOKEN_ADDRESS).safeTransfer(\\n harvesterAddress,\\n ethRewards\\n );\\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_TOKEN_ADDRESS, \\\"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_TOKEN_ADDRESS).balanceOf(\\n address(this)\\n );\\n uint256 newWeth = wethBalance - depositedWethAccountedFor;\\n\\n if (newWeth > 0) {\\n depositedWethAccountedFor = wethBalance;\\n\\n _deposit(WETH_TOKEN_ADDRESS, newWeth);\\n }\\n }\\n\\n /// @notice Withdraw WETH from this contract. Used only if some WETH for is lingering on the contract. That\\n /// can happen when:\\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 _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 emit Withdrawal(_asset, address(0), _amount);\\n IERC20(_asset).safeTransfer(_recipient, _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_TOKEN_ADDRESS).balanceOf(\\n address(this)\\n );\\n if (wethBalance > 0) {\\n _withdraw(vaultAddress, WETH_TOKEN_ADDRESS, wethBalance);\\n }\\n }\\n\\n function _abstractSetPToken(address _asset, address) internal override {}\\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_TOKEN_ADDRESS, \\\"Unsupported asset\\\");\\n\\n balance =\\n // add the ETH that has been staked in validators\\n activeDepositedValidators *\\n 32 ether +\\n // add the WETH in the strategy from deposits that are still to be staked\\n IERC20(WETH_TOKEN_ADDRESS).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_TOKEN_ADDRESS;\\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_ADDRESS).approve(\\n SSV_NETWORK_ADDRESS,\\n type(uint256).max\\n );\\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 ||\\n msg.sender == WETH_TOKEN_ADDRESS,\\n \\\"eth not from allowed contracts\\\"\\n );\\n }\\n\\n function _wethWithdrawnToVault(uint256 _amount) internal override {\\n emit Withdrawal(WETH_TOKEN_ADDRESS, address(0), _amount);\\n }\\n\\n function _wethWithdrawnAndStaked(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 direclty\\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\",\"keccak256\":\"0x34c14896bd8b1ef61672511da04db41f7bc141225a8d1c7bae87bba94feb86da\",\"license\":\"MIT\"},\"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 /// @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 MAX_STAKE = 32 ether;\\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 emit FuseIntervalUpdated(_fuseIntervalStart, _fuseIntervalEnd);\\n\\n fuseIntervalStart = _fuseIntervalStart;\\n fuseIntervalEnd = _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 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 >= MAX_STAKE) {\\n uint256 fullyWithdrawnValidators;\\n // safe since MAX_STAKE is hardcoded to 32ETH\\n unchecked {\\n // explicitly cast to uint256 as we want to round to a whole number of validators\\n fullyWithdrawnValidators = uint256(newSweptETH / MAX_STAKE);\\n }\\n activeDepositedValidators -= fullyWithdrawnValidators;\\n\\n uint256 wethToVault = MAX_STAKE * fullyWithdrawnValidators;\\n IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: wethToVault }();\\n // slither-disable-next-line unchecked-transfer\\n IWETH9(WETH_TOKEN_ADDRESS).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 < 32 ether, \\\"unexpected accounting\\\");\\n\\n // If no Beacon chain consensus rewards swept\\n if (ethRemaining == 0) {\\n // do nothing\\n return accountingValid;\\n }\\n // Beacon chain consensus rewards swept (partial validator withdrawals)\\n else if (ethRemaining < fuseIntervalStart) {\\n // solhint-disable-next-line reentrancy\\n consensusRewards += ethRemaining;\\n emit AccountingConsensusRewards(ethRemaining);\\n }\\n // Beacon chain consensus rewards swept but also a slashed validator fully exited\\n else if (ethRemaining > fuseIntervalEnd) {\\n IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: ethRemaining }();\\n // slither-disable-next-line unchecked-transfer\\n IWETH9(WETH_TOKEN_ADDRESS).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 {\\n require(\\n lastFixAccountingBlockNumber + MIN_FIX_ACCOUNTING_CADENCE <\\n block.number,\\n \\\"manuallyFixAccounting 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 emit AccountingManuallyFixed(\\n _validatorsDelta,\\n _consensusRewardsDelta,\\n _ethToVaultAmount\\n );\\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_TOKEN_ADDRESS).deposit{ value: _ethToVaultAmount }();\\n // slither-disable-next-line unchecked-transfer\\n IWETH9(WETH_TOKEN_ADDRESS).transfer(\\n VAULT_ADDRESS,\\n _ethToVaultAmount\\n );\\n _wethWithdrawnToVault(_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 Withdrawal event\\n function _wethWithdrawnToVault(uint256 _amount) internal virtual;\\n}\\n\",\"keccak256\":\"0xd4822fde6975d6163bcb73e50a1b2a7437b11fdaa9c85cc36a794a6fc5fc0209\",\"license\":\"MIT\"},\"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 address of the Wrapped ETH (WETH) token contract\\n address public immutable WETH_TOKEN_ADDRESS;\\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_ADDRESS;\\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 governor needs to approve further staking\\n uint256 public stakeETHThreshold;\\n /// @notice Amount of ETH that can has been staked since the last governor approval.\\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(\\n bytes32 indexed pubKeyHash,\\n bytes pubKey,\\n uint256 amount,\\n bytes withdrawal_credentials\\n );\\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_TOKEN_ADDRESS = _wethAddress;\\n BEACON_CHAIN_DEPOSIT_CONTRACT = _beaconChainDepositContract;\\n SSV_NETWORK_ADDRESS = _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 emit RegistratorChanged(_address);\\n validatorRegistrator = _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 emit StakingMonitorChanged(_address);\\n stakingMonitor = _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 emit StakeETHThresholdChanged(_amount);\\n stakeETHThreshold = _amount;\\n }\\n\\n /// @notice Reset the stakeETHTally\\n function resetStakeETHTally() external onlyStakingMonitor {\\n emit StakeETHTallyReset();\\n stakeETHTally = 0;\\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 {\\n uint256 requiredETH = validators.length * 32 ether;\\n\\n // Check there is enough WETH from the deposits sitting in this strategy contract\\n require(\\n requiredETH <= IWETH9(WETH_TOKEN_ADDRESS).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_TOKEN_ADDRESS).withdraw(requiredETH);\\n _wethWithdrawnAndStaked(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 withdrawal_credentials = abi.encodePacked(\\n bytes1(0x01),\\n bytes11(0),\\n address(this)\\n );\\n\\n uint256 validatorsLength = validators.length;\\n // For each validator\\n for (uint256 i = 0; i < validatorsLength; ) {\\n bytes32 pubKeyHash = keccak256(validators[i].pubkey);\\n VALIDATOR_STATE currentState = validatorsStates[pubKeyHash];\\n\\n require(\\n currentState == VALIDATOR_STATE.REGISTERED,\\n \\\"Validator not registered\\\"\\n );\\n\\n IDepositContract(BEACON_CHAIN_DEPOSIT_CONTRACT).deposit{\\n value: 32 ether\\n }(\\n validators[i].pubkey,\\n withdrawal_credentials,\\n validators[i].signature,\\n validators[i].depositDataRoot\\n );\\n\\n emit ETHStaked(\\n pubKeyHash,\\n validators[i].pubkey,\\n 32 ether,\\n withdrawal_credentials\\n );\\n\\n validatorsStates[pubKeyHash] = VALIDATOR_STATE.STAKED;\\n\\n unchecked {\\n ++i;\\n }\\n }\\n // save gas by changing this storage variable only once rather each time in the loop.\\n activeDepositedValidators += validatorsLength;\\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 publicKey The public key of the validator\\n /// @param operatorIds The operator IDs of the SSV Cluster\\n /// @param sharesData The validator shares data\\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 registerSsvValidator(\\n bytes calldata publicKey,\\n uint64[] calldata operatorIds,\\n bytes calldata sharesData,\\n uint256 ssvAmount,\\n Cluster calldata cluster\\n ) external onlyRegistrator whenNotPaused {\\n bytes32 pubKeyHash = keccak256(publicKey);\\n require(\\n validatorsStates[pubKeyHash] == VALIDATOR_STATE.NON_REGISTERED,\\n \\\"Validator already registered\\\"\\n );\\n ISSVNetwork(SSV_NETWORK_ADDRESS).registerValidator(\\n publicKey,\\n operatorIds,\\n sharesData,\\n ssvAmount,\\n cluster\\n );\\n emit SSVValidatorRegistered(pubKeyHash, publicKey, operatorIds);\\n\\n validatorsStates[pubKeyHash] = VALIDATOR_STATE.REGISTERED;\\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_ADDRESS).exitValidator(publicKey, operatorIds);\\n emit SSVValidatorExitInitiated(pubKeyHash, publicKey, operatorIds);\\n\\n validatorsStates[pubKeyHash] = VALIDATOR_STATE.EXITING;\\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_ADDRESS).removeValidator(\\n publicKey,\\n operatorIds,\\n cluster\\n );\\n emit SSVValidatorExitCompleted(pubKeyHash, publicKey, operatorIds);\\n\\n validatorsStates[pubKeyHash] = VALIDATOR_STATE.EXIT_COMPLETE;\\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_ADDRESS).deposit(\\n address(this),\\n operatorIds,\\n ssvAmount,\\n cluster\\n );\\n }\\n\\n /***************************************\\n Abstract\\n ****************************************/\\n\\n /// @dev allows for NativeStakingSSVStrategy contract know how much WETH had been staked\\n function _wethWithdrawnAndStaked(uint256 _amount) internal virtual;\\n}\\n\",\"keccak256\":\"0x987cbb442eff12384cc61eb162845912c488169d690173c8dd7f672283900ae6\",\"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/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\",\"keccak256\":\"0x5e17bb3db9f9e1014b7c5c836547f8fa81e02af7568c0bb8f2a2e0e7c2192db4\",\"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/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\\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\":\"0xcbdb87104749e20c8411bc2acbfa0b7d48e876e3f4e1c46c9a7b00fcdb9722d9\",\"license\":\"MIT\"}},\"version\":1}", + "bytecode": "0x6101a06040523480156200001257600080fd5b506040516200523638038062005236833981016040819052620000359162000144565b86868860200151838787848484848462000055336200011460201b60201c565b60008051602062005216833981519152546040516001600160a01b03909116906000907fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a908290a36033805460ff191690556001600160601b0319606095861b811660805292851b831660a05290841b821660c05291831b811660e052610100919091528751821b811661012052602090970151811b8716610140529a8b1b86166101605250505050509190941b1661018052506200022b9350505050565b6000805160206200521683398151915255565b80516001600160a01b03811681146200013f57600080fd5b919050565b60008060008060008060008789036101008112156200016257600080fd5b60408112156200017157600080fd5b50604080519081016001600160401b0381118282101715620001a357634e487b7160e01b600052604160045260246000fd5b604052620001b18962000127565b8152620001c160208a0162000127565b60208201529650620001d66040890162000127565b9550620001e66060890162000127565b9450620001f66080890162000127565b935060a088015192506200020d60c0890162000127565b91506200021d60e0890162000127565b905092959891949750929550565b60805160601c60a05160601c60c05160601c60e05160601c610100516101205160601c6101405160601c6101605160601c6101805160601c614e35620003e16000396000818161039501528181610b33015261330701526000818161068b015261278a01526000818161053f01528181610f4701528181611bfb01528181611d7401528181612b430152612d9401526000610aff01526000818161074b01526114f901526000818161087a01528181610d0f01528181611b2901528181611dc401528181612188015281816138f30152613b4d015260008181610bbd01528181610de501528181611a2f0152818161275a015281816129000152612cbe015260008181610a5401526117740152600081816103c7015281816105e90152818161096b01528181610c7601528181610fbc01528181611200015281816112880152818161142f015281816115f701528181611ce501528181611d9501528181612102015281816121b701528181612e1f01528181612ec70152818161340c0152818161349101528181613505015281816137a20152818161386d0152818161392201528181613ac70152613b7c0152614e356000f3fe6080604052600436106103855760003560e01c8063853828b6116101d1578063c7af335211610102578063dbe55e56116100a0578063e75292391161006f578063e752923914610b80578063ee7afe2d14610b96578063f1188e4014610bab578063f6ca71b014610bdf57600080fd5b8063dbe55e5614610aed578063dd505df614610b21578063de34d71314610b55578063de5f626814610b6b57600080fd5b8063d059f6ef116100dc578063d059f6ef14610a76578063d38bfff414610a8d578063d9caed1214610aad578063d9f00ec714610acd57600080fd5b8063c7af335214610a10578063c98517c514610a25578063cceab75014610a4257600080fd5b8063a3b81e731161016f578063ab12edf511610149578063ab12edf51461099b578063ad1728cb146109bb578063bb1b918d146109d0578063c2e1e3f4146109f057600080fd5b8063a3b81e7314610919578063a4f98af414610939578063aa388af61461094e57600080fd5b80639092c31c116101ab5780639092c31c146108685780639136616a1461089c57806396d538bb146108bc5780639da0e462146108dc57600080fd5b8063853828b61461080e57806387bae867146108235780638d7c0e461461084857600080fd5b80635d36b190116102b65780636ef38795116102545780637b2d9b2c116102235780637b2d9b2c146107ad5780637b8962f7146107cd578063842f5c46146107e35780638456cb59146107f957600080fd5b80636ef3879514610719578063714897df1461073957806371a735f31461076d5780637260f8261461078d57600080fd5b8063630923831161029057806363092383146106ad57806366e3667e146106c357806367c7066c146106d95780636e811d38146106f957600080fd5b80635d36b190146106445780635f515226146106595780636093d3801461067957600080fd5b8063435356d1116103235780635205c380116102fd5780635205c380146105b7578063579a7e1a146105d75780635a063f631461060b5780635c975abb1461062057600080fd5b8063435356d11461056157806347e7ef2414610581578063484be812146105a157600080fd5b80631072cbea1161035f5780631072cbea146104c957806322495dc8146104e95780633c86495914610509578063430bf08a1461052d57600080fd5b80630c340a24146104415780630ed57b3a146104735780630fc3b4c41461049357600080fd5b3661043c57336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614806103e95750336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016145b61043a5760405162461bcd60e51b815260206004820152601e60248201527f657468206e6f742066726f6d20616c6c6f77656420636f6e747261637473000060448201526064015b60405180910390fd5b005b600080fd5b34801561044d57600080fd5b50610456610c01565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561047f57600080fd5b5061043a61048e3660046141d8565b610c1e565b34801561049f57600080fd5b506104566104ae36600461419e565b609f602052600090815260409020546001600160a01b031681565b3480156104d557600080fd5b5061043a6104e4366004614252565b610c50565b3480156104f557600080fd5b5061043a610504366004614346565b610d0d565b34801561051557600080fd5b5061051f60695481565b60405190815260200161046a565b34801561053957600080fd5b506104567f000000000000000000000000000000000000000000000000000000000000000081565b34801561056d57600080fd5b5061043a61057c3660046142bf565b610e57565b34801561058d57600080fd5b5061043a61059c366004614252565b610f3c565b3480156105ad57600080fd5b5061051f606a5481565b3480156105c357600080fd5b5061043a6105d236600461441c565b61105b565b3480156105e357600080fd5b506104567f000000000000000000000000000000000000000000000000000000000000000081565b34801561061757600080fd5b5061043a6110b7565b34801561062c57600080fd5b5060335460ff165b604051901515815260200161046a565b34801561065057600080fd5b5061043a611156565b34801561066557600080fd5b5061051f61067436600461419e565b6111fc565b34801561068557600080fd5b506104567f000000000000000000000000000000000000000000000000000000000000000081565b3480156106b957600080fd5b5061051f611c2081565b3480156106cf57600080fd5b5061051f60345481565b3480156106e557600080fd5b5060a354610456906001600160a01b031681565b34801561070557600080fd5b5061043a61071436600461419e565b611330565b34801561072557600080fd5b5061043a61073436600461427e565b6113b0565b34801561074557600080fd5b5061051f7f000000000000000000000000000000000000000000000000000000000000000081565b34801561077957600080fd5b5061043a610788366004614554565b61193b565b34801561079957600080fd5b50603654610456906001600160a01b031681565b3480156107b957600080fd5b506104566107c836600461441c565b611afd565b3480156107d957600080fd5b5061051f60375481565b3480156107ef57600080fd5b5061051f60685481565b34801561080557600080fd5b5061043a611b27565b34801561081a57600080fd5b5061043a611bf0565b34801561082f57600080fd5b506033546104569061010090046001600160a01b031681565b34801561085457600080fd5b5061043a6108633660046145d5565b611dc2565b34801561087457600080fd5b506104567f000000000000000000000000000000000000000000000000000000000000000081565b3480156108a857600080fd5b5061043a6108b736600461441c565b612297565b3480156108c857600080fd5b5061043a6108d736600461427e565b612462565b3480156108e857600080fd5b5061090c6108f736600461441c565b60356020526000908152604090205460ff1681565b60405161046a9190614a40565b34801561092557600080fd5b5061043a61093436600461419e565b612582565b34801561094557600080fd5b506106346125fc565b34801561095a57600080fd5b5061063461096936600461419e565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0390811691161490565b3480156109a757600080fd5b5061043a6109b636600461461a565b61265b565b3480156109c757600080fd5b5061043a612743565b3480156109dc57600080fd5b5061043a6109eb3660046144a0565b612809565b3480156109fc57600080fd5b5061043a610a0b36600461419e565b6129d6565b348015610a1c57600080fd5b50610634612a63565b348015610a3157600080fd5b5061051f6801bc16d674ec80000081565b348015610a4e57600080fd5b506104567f000000000000000000000000000000000000000000000000000000000000000081565b348015610a8257600080fd5b5061051f6101075481565b348015610a9957600080fd5b5061043a610aa836600461419e565b612a94565b348015610ab957600080fd5b5061043a610ac8366004614211565b612b38565b348015610ad957600080fd5b5061043a610ae8366004614435565b612bcb565b348015610af957600080fd5b506104567f000000000000000000000000000000000000000000000000000000000000000081565b348015610b2d57600080fd5b506104567f000000000000000000000000000000000000000000000000000000000000000081565b348015610b6157600080fd5b5061051f60385481565b348015610b7757600080fd5b5061043a612d89565b348015610b8c57600080fd5b5061051f606b5481565b348015610ba257600080fd5b5061043a612ef6565b348015610bb757600080fd5b506104567f000000000000000000000000000000000000000000000000000000000000000081565b348015610beb57600080fd5b50610bf4612f80565b60405161046a9190614816565b6000610c19600080516020614de08339815191525490565b905090565b610c26612a63565b610c425760405162461bcd60e51b815260040161043190614ab2565b610c4c8282612fe2565b5050565b610c58612a63565b610c745760405162461bcd60e51b815260040161043190614ab2565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b039081169083161415610cf15760405162461bcd60e51b815260206004820152601f60248201527f43616e6e6f74207472616e7366657220737570706f72746564206173736574006044820152606401610431565b610c4c610cfc610c01565b6001600160a01b0384169083613141565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b158015610d6657600080fd5b505afa158015610d7a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d9e91906141bb565b6001600160a01b0316336001600160a01b031614610dce5760405162461bcd60e51b815260040161043190614b72565b60405163bc26e7e560e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063bc26e7e590610e20903090879087908790600401614766565b600060405180830381600087803b158015610e3a57600080fd5b505af1158015610e4e573d6000803e3d6000fd5b50505050505050565b610e5f612a63565b610e7b5760405162461bcd60e51b815260040161043190614ab2565b600054610100900460ff1680610e94575060005460ff16155b610ef75760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610431565b600054610100900460ff16158015610f19576000805461ffff19166101011790555b610f24848484613193565b8015610f36576000805461ff00191690555b50505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610f845760405162461bcd60e51b815260040161043190614a7b565b600080516020614dc083398151915280546002811415610fb65760405162461bcd60e51b815260040161043190614b4a565b600282557f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316846001600160a01b03161461102f5760405162461bcd60e51b8152602060048201526011602482015270155b9cdd5c1c1bdc9d195908185cdcd95d607a1b6044820152606401610431565b8261010760008282546110429190614c99565b909155506110529050848461324e565b50600190555050565b611063612a63565b61107f5760405162461bcd60e51b815260040161043190614ab2565b6040518181527fe26b067424903962f951f568e52ec9a3bbe1589526ea54a4e69ca6eaae1a4c779060200160405180910390a1603755565b60a3546001600160a01b031633146111115760405162461bcd60e51b815260206004820152601b60248201527f43616c6c6572206973206e6f74207468652048617276657374657200000000006044820152606401610431565b600080516020614dc0833981519152805460028114156111435760405162461bcd60e51b815260040161043190614b4a565b6002825561114f6132e0565b5060019055565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b0316146111f15760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b6064820152608401610431565b6111fa3361352e565b565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b0316146112735760405162461bcd60e51b8152602060048201526011602482015270155b9cdd5c1c1bdc9d195908185cdcd95d607a1b6044820152606401610431565b6040516370a0823160e01b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b1580156112d257600080fd5b505afa1580156112e6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061130a9190614601565b603454611320906801bc16d674ec800000614cb1565b61132a9190614c99565b92915050565b611338612a63565b6113545760405162461bcd60e51b815260040161043190614ab2565b6040516001600160a01b038216907f83f29c79feb71f8fba9d0fbc4ba5f0982a28b6b1e868b3fc50e6400d100bca0f90600090a2603380546001600160a01b0390921661010002610100600160a81b0319909216919091179055565b60335461010090046001600160a01b031633146113df5760405162461bcd60e51b815260040161043190614b13565b60335460ff16156114025760405162461bcd60e51b815260040161043190614ae9565b6000611417826801bc16d674ec800000614cb1565b6040516370a0823160e01b81523060048201529091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b15801561147957600080fd5b505afa15801561148d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114b19190614601565b8111156114f45760405162461bcd60e51b81526020600482015260116024820152700d2dce6eaccccd2c6d2cadce840ae8aa89607b1b6044820152606401610431565b6034547f000000000000000000000000000000000000000000000000000000000000000090611524908490614c99565b111561156b5760405162461bcd60e51b815260206004820152601660248201527513585e081d985b1a59185d1bdc9cc81c995858da195960521b6044820152606401610431565b6037548160385461157c9190614c99565b11156115ca5760405162461bcd60e51b815260206004820152601a60248201527f5374616b696e6720455448206f766572207468726573686f6c640000000000006044820152606401610431565b80603860008282546115dc9190614c99565b9091555050604051632e1a7d4d60e01b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561164357600080fd5b505af1158015611657573d6000803e3d6000fd5b50505050611664816135ef565b60408051600160f81b60208201526000602182018190526bffffffffffffffffffffffff193060601b16602c830152910160408051601f1981840301815291905290508260005b8181101561191c5760008686838181106116c7576116c7614d70565b90506020028101906116d99190614bef565b6116e39080614ba9565b6040516116f192919061473a565b604080519182900390912060008181526035602052919091205490915060ff16600181600481111561172557611725614d44565b146117725760405162461bcd60e51b815260206004820152601860248201527f56616c696461746f72206e6f74207265676973746572656400000000000000006044820152606401610431565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663228951186801bc16d674ec8000008a8a878181106117bd576117bd614d70565b90506020028101906117cf9190614bef565b6117d99080614ba9565b898d8d8a8181106117ec576117ec614d70565b90506020028101906117fe9190614bef565b61180c906020810190614ba9565b8f8f8c81811061181e5761181e614d70565b90506020028101906118309190614bef565b604001356040518863ffffffff1660e01b8152600401611855969594939291906149c5565b6000604051808303818588803b15801561186e57600080fd5b505af1158015611882573d6000803e3d6000fd5b5050505050817fd44c8fde6d369f70d395b6cdee4641886d11e3a72cb537696ca04134881692ed8989868181106118bb576118bb614d70565b90506020028101906118cd9190614bef565b6118d79080614ba9565b6801bc16d674ec800000896040516118f29493929190614a14565b60405180910390a2506000908152603560205260409020805460ff191660021790556001016116ab565b50806034600082825461192f9190614c99565b90915550505050505050565b60335461010090046001600160a01b0316331461196a5760405162461bcd60e51b815260040161043190614b13565b60335460ff161561198d5760405162461bcd60e51b815260040161043190614ae9565b6000858560405161199f92919061473a565b604080519182900390912060008181526035602052919091205490915060ff1660038160048111156119d3576119d3614d44565b14611a185760405162461bcd60e51b815260206004820152601560248201527456616c696461746f72206e6f742065786974696e6760581b6044820152606401610431565b6040516312b3fc1960e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906312b3fc1990611a6c908a908a908a908a908a90600401614984565b600060405180830381600087803b158015611a8657600080fd5b505af1158015611a9a573d6000803e3d6000fd5b50505050817f6aecca20726a17c1b81989b2fd09dfdf636bae9e564d4066ca18df62dc1f3dc288888888604051611ad494939291906148fb565b60405180910390a2506000908152603560205260409020805460ff191660041790555050505050565b60a48181548110611b0d57600080fd5b6000918252602090912001546001600160a01b0316905081565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b158015611b8057600080fd5b505afa158015611b94573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bb891906141bb565b6001600160a01b0316336001600160a01b031614611be85760405162461bcd60e51b815260040161043190614b72565b6111fa61361c565b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161480611c3f5750611c2a610c01565b6001600160a01b0316336001600160a01b0316145b611c975760405162461bcd60e51b815260206004820152602360248201527f43616c6c6572206973206e6f7420746865205661756c74206f7220476f7665726044820152623737b960e91b6064820152608401610431565b600080516020614dc083398151915280546002811415611cc95760405162461bcd60e51b815260040161043190614b4a565b600282556040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b158015611d2f57600080fd5b505afa158015611d43573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d679190614601565b90508015611dba57611dba7f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000083613691565b505060019055565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b158015611e1b57600080fd5b505afa158015611e2f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e5391906141bb565b6001600160a01b0316336001600160a01b031614611e835760405162461bcd60e51b815260040161043190614b72565b60335460ff16611ecc5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610431565b43611c20606b54611edd9190614c99565b10611f385760405162461bcd60e51b815260206004820152602560248201527f6d616e75616c6c794669784163636f756e74696e672063616c6c656420746f6f6044820152641039b7b7b760d91b6064820152608401610431565b6002198312158015611f4b575060038313155b8015611f655750600083603454611f629190614c58565b12155b611fb15760405162461bcd60e51b815260206004820152601760248201527f696e76616c69642076616c696461746f727344656c74610000000000000000006044820152606401610431565b6811ff6cf0fd15afffff198212158015611fd457506811ff6cf0fd15b000008213155b8015611fee5750600082606854611feb9190614c58565b12155b61203a5760405162461bcd60e51b815260206004820152601d60248201527f696e76616c696420636f6e73656e7375735265776172647344656c74610000006044820152606401610431565b68053444835ec58000008111156120935760405162461bcd60e51b815260206004820152601960248201527f696e76616c69642077657468546f5661756c74416d6f756e74000000000000006044820152606401610431565b60408051848152602081018490529081018290527f80d022717ea022455c5886b8dd8a29c037570aae58aeb4d7b136d7a10ec2e4319060600160405180910390a1826034546120e29190614c58565b6034556068546120f3908390614c58565b60685543606b558015612241577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b15801561215b57600080fd5b505af115801561216f573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb92506044019050602060405180830381600087803b1580156121ff57600080fd5b505af1158015612213573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061223791906143ff565b5061224181613789565b61224b60006137f1565b61228a5760405162461bcd60e51b815260206004820152601060248201526f333ab9b29039ba34b63610313637bbb760811b6044820152606401610431565b612292613c70565b505050565b61229f612a63565b6122bb5760405162461bcd60e51b815260040161043190614ab2565b60a05481106122fc5760405162461bcd60e51b815260206004820152600d60248201526c092dcecc2d8d2c840d2dcc8caf609b1b6044820152606401610431565b600060a0828154811061231157612311614d70565b60009182526020808320909101546001600160a01b03908116808452609f90925260409092205460a0549193509091169061234e90600190614cd0565b8310156123d05760a0805461236590600190614cd0565b8154811061237557612375614d70565b60009182526020909120015460a080546001600160a01b0390921691859081106123a1576123a1614d70565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505b60a08054806123e1576123e1614d5a565b60008281526020808220600019908401810180546001600160a01b031990811690915593019093556001600160a01b03858116808352609f855260409283902080549094169093559051908416815290917f16b7600acff27e39a8a96056b3d533045298de927507f5c1d97e4accde60488c910160405180910390a2505050565b61246a612a63565b6124865760405162461bcd60e51b815260040161043190614ab2565b8060005b818110156125395760008484838181106124a6576124a6614d70565b90506020020160208101906124bb919061419e565b6001600160a01b031614156125295760405162461bcd60e51b815260206004820152602e60248201527f43616e206e6f742073657420616e20656d70747920616464726573732061732060448201526d30903932bbb0b932103a37b5b2b760911b6064820152608401610431565b61253281614d13565b905061248a565b507f04c0b9649497d316554306e53678d5f5f5dbc3a06f97dec13ff4cfe98b986bbc60a4848460405161256e93929190614863565b60405180910390a1610f3660a48484613ef7565b61258a612a63565b6125a65760405162461bcd60e51b815260040161043190614ab2565b6040516001600160a01b038216907f3329861a0008b3348767567d2405492b997abd79a088d0f2cef6b1a09a8e7ff790600090a2603680546001600160a01b0319166001600160a01b0392909216919091179055565b60335460009061010090046001600160a01b0316331461262e5760405162461bcd60e51b815260040161043190614b13565b60335460ff16156126515760405162461bcd60e51b815260040161043190614ae9565b610c1960016137f1565b612663612a63565b61267f5760405162461bcd60e51b815260040161043190614ab2565b808210801561269657506801bc16d674ec80000081105b80156126b35750673782dace9d9000006126b08383614cd0565b10155b6126ff5760405162461bcd60e51b815260206004820152601760248201527f696e636f7272656374206675736520696e74657276616c0000000000000000006044820152606401610431565b60408051838152602081018390527fcb8d24e46eb3c402bf344ee60a6576cba9ef2f59ea1af3b311520704924e901a910160405180910390a1606991909155606a55565b60405163095ea7b360e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015260001960248301527f0000000000000000000000000000000000000000000000000000000000000000169063095ea7b390604401602060405180830381600087803b1580156127ce57600080fd5b505af11580156127e2573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061280691906143ff565b50565b60335461010090046001600160a01b031633146128385760405162461bcd60e51b815260040161043190614b13565b60335460ff161561285b5760405162461bcd60e51b815260040161043190614ae9565b6000888860405161286d92919061473a565b60405190819003902090506000808281526035602052604090205460ff16600481111561289c5761289c614d44565b146128e95760405162461bcd60e51b815260206004820152601c60248201527f56616c696461746f7220616c72656164792072656769737465726564000000006044820152606401610431565b6040516301ba3ee760e21b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906306e8fb9c90612943908c908c908c908c908c908c908c908c90600401614922565b600060405180830381600087803b15801561295d57600080fd5b505af1158015612971573d6000803e3d6000fd5b50505050807facd38e900350661e325d592c959664c0000a306efb2004e7dc283f44e0ea04238a8a8a8a6040516129ab94939291906148fb565b60405180910390a26000908152603560205260409020805460ff191660011790555050505050505050565b6129de612a63565b6129fa5760405162461bcd60e51b815260040161043190614ab2565b60a354604080516001600160a01b03928316815291831660208301527fe48386b84419f4d36e0f96c10cc3510b6fb1a33795620c5098b22472bbe90796910160405180910390a160a380546001600160a01b0319166001600160a01b0392909216919091179055565b6000612a7b600080516020614de08339815191525490565b6001600160a01b0316336001600160a01b031614905090565b612a9c612a63565b612ab85760405162461bcd60e51b815260040161043190614ab2565b612ae0817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b0316612b00600080516020614de08339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614612b805760405162461bcd60e51b815260040161043190614a7b565b600080516020614dc083398151915280546002811415612bb25760405162461bcd60e51b815260040161043190614b4a565b60028255612bc1858585613691565b5060019055505050565b60335461010090046001600160a01b03163314612bfa5760405162461bcd60e51b815260040161043190614b13565b60335460ff1615612c1d5760405162461bcd60e51b815260040161043190614ae9565b60008484604051612c2f92919061473a565b604080519182900390912060008181526035602052919091205490915060ff166002816004811115612c6357612c63614d44565b14612ca75760405162461bcd60e51b815260206004820152601460248201527315985b1a59185d1bdc881b9bdd081cdd185ad95960621b6044820152606401610431565b604051633877322b60e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690633877322b90612cf99089908990899089906004016148fb565b600060405180830381600087803b158015612d1357600080fd5b505af1158015612d27573d6000803e3d6000fd5b50505050817f8c2e15303eb94e531acc988c2a01d1193bdaaa15eda7f16dda85316ed463578d87878787604051612d6194939291906148fb565b60405180910390a2506000908152603560205260409020805460ff1916600317905550505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614612dd15760405162461bcd60e51b815260040161043190614a7b565b600080516020614dc083398151915280546002811415612e035760405162461bcd60e51b815260040161043190614b4a565b600282556040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b158015612e6957600080fd5b505afa158015612e7d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ea19190614601565b905060006101075482612eb49190614cd0565b90508015612eec57610107829055612eec7f00000000000000000000000000000000000000000000000000000000000000008261324e565b5050600182555050565b6036546001600160a01b03163314612f505760405162461bcd60e51b815260206004820152601960248201527f43616c6c6572206973206e6f7420746865204d6f6e69746f72000000000000006044820152606401610431565b6040517fe765a88a37047c5d793dce22b9ceb5a0f5039d276da139b4c7d29613f341f11090600090a16000603855565b606060a4805480602002602001604051908101604052809291908181526020018280548015612fd857602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612fba575b5050505050905090565b6001600160a01b038281166000908152609f6020526040902054161561303f5760405162461bcd60e51b81526020600482015260126024820152711c151bdad95b88185b1c9958591e481cd95d60721b6044820152606401610431565b6001600160a01b0382161580159061305f57506001600160a01b03811615155b61309f5760405162461bcd60e51b8152602060048201526011602482015270496e76616c69642061646472657373657360781b6044820152606401610431565b6001600160a01b038281166000818152609f6020908152604080832080549587166001600160a01b0319968716811790915560a0805460018101825594527f78fdc8d422c49ced035a9edf18d00d3c6a8d81df210f3e5e448e045e77b41e8890930180549095168417909455925190815290917fef6485b84315f9b1483beffa32aae9a0596890395e3d7521f1c5fbb51790e765910160405180910390a25050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052612292908490613cea565b82516131a69060a4906020860190613f5a565b508151815181146131f05760405162461bcd60e51b8152602060048201526014602482015273496e76616c696420696e7075742061727261797360601b6044820152606401610431565b60005b818110156132475761323784828151811061321057613210614d70565b602002602001015184838151811061322a5761322a614d70565b6020026020010151612fe2565b61324081614d13565b90506131f3565b5050505050565b600081116132975760405162461bcd60e51b81526020600482015260166024820152754d757374206465706f73697420736f6d657468696e6760501b6044820152606401610431565b6040805160008152602081018390526001600160a01b038416917f5548c837ab068cf56a2c2479df0882a4922fd203edb7517321831d95078c5f62910160405180910390a25050565b60335460ff16156133035760405162461bcd60e51b815260040161043190614ae9565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663e52253816040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561336057600080fd5b505af1158015613374573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133989190614601565b90506000606854826133aa9190614c99565b9050804710156133fc5760405162461bcd60e51b815260206004820152601860248201527f696e73756666696369656e74206574682062616c616e636500000000000000006044820152606401610431565b8015610c4c5760006068819055507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b15801561346557600080fd5b505af1158015613479573d6000803e3d6000fd5b505060a354604080516001600160a01b0392831681527f0000000000000000000000000000000000000000000000000000000000000000909216602083015281018590527ff6c07a063ed4e63808eb8da7112d46dbcd38de2b40a73dbcc9353c5a94c72353935060600191506134ec9050565b60405180910390a160a354610c4c906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116911683613141565b6001600160a01b0381166135845760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f7220697320616464726573732830290000000000006044820152606401610431565b806001600160a01b03166135a4600080516020614de08339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a361280681600080516020614de083398151915255565b60006135fe8261010754613dbc565b90508061010760008282546136139190614cd0565b90915550505050565b60335460ff161561363f5760405162461bcd60e51b815260040161043190614ae9565b6033805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586136743390565b6040516001600160a01b03909116815260200160405180910390a1565b600081116136e15760405162461bcd60e51b815260206004820152601760248201527f4d75737420776974686472617720736f6d657468696e670000000000000000006044820152606401610431565b6001600160a01b0383166137305760405162461bcd60e51b8152602060048201526016602482015275135d5cdd081cdc1958da599e481c9958da5c1a595b9d60521b6044820152606401610431565b6040805160008152602081018390526001600160a01b038416917f2717ead6b9200dd235aad468c9809ea400fe33ac69b5bfaa6d3e90fc922b6398910160405180910390a26122926001600160a01b0383168483613141565b6040805160008152602081018390526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016917f2717ead6b9200dd235aad468c9809ea400fe33ac69b5bfaa6d3e90fc922b6398910160405180910390a250565b60006068544710156138065761132a82613dd4565b6000606854476138169190614cd0565b9050600191506801bc16d674ec80000081106139f35760006801bc16d674ec80000082049050806034600082825461384e9190614cd0565b9091555060009050613869826801bc16d674ec800000614cb1565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b1580156138c657600080fd5b505af11580156138da573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb92506044019050602060405180830381600087803b15801561396a57600080fd5b505af115801561397e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139a291906143ff565b506139ac81613789565b60345460408051848152602081019290925281018290527fbe7040030ff7b347853214bf49820c6d455fedf58f3815f85c7bc5216993682b9060600160405180910390a150505b600060685447613a039190614cd0565b90506801bc16d674ec8000008110613a555760405162461bcd60e51b8152602060048201526015602482015274756e6578706563746564206163636f756e74696e6760581b6044820152606401610431565b80613a61575050919050565b606954811015613abb578060686000828254613a7d9190614c99565b90915550506040518181527f7a745a2c63a535068f52ceca27debd5297bbad5f7f37ec53d044a59d0362445d906020015b60405180910390a1613c69565b606a54811115613c58577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b158015613b2057600080fd5b505af1158015613b34573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb92506044019050602060405180830381600087803b158015613bc457600080fd5b505af1158015613bd8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613bfc91906143ff565b50600160346000828254613c109190614cd0565b90915550613c1f905081613789565b60345460408051918252602082018390527f6aa7e30787b26429ced603a7aba8b19c4b5d5bcf29a3257da953c8d53bcaa3a69101613aae565b613c6184613dd4565b949350505050565b5050919050565b60335460ff16613cb95760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610431565b6033805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa33613674565b6000613d3f826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316613dec9092919063ffffffff16565b8051909150156122925780806020019051810190613d5d91906143ff565b6122925760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610431565b6000818310613dcb5781613dcd565b825b9392505050565b60008115613de457613de461361c565b506000919050565b6060613c61848460008585843b613e455760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610431565b600080866001600160a01b03168587604051613e61919061474a565b60006040518083038185875af1925050503d8060008114613e9e576040519150601f19603f3d011682016040523d82523d6000602084013e613ea3565b606091505b5091509150613eb3828286613ebe565b979650505050505050565b60608315613ecd575081613dcd565b825115613edd5782518084602001fd5b8160405162461bcd60e51b81526004016104319190614a68565b828054828255906000526020600020908101928215613f4a579160200282015b82811115613f4a5781546001600160a01b0319166001600160a01b03843516178255602090920191600190910190613f17565b50613f56929150613faf565b5090565b828054828255906000526020600020908101928215613f4a579160200282015b82811115613f4a57825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190613f7a565b5b80821115613f565760008155600101613fb0565b60008083601f840112613fd657600080fd5b5081356001600160401b03811115613fed57600080fd5b6020830191508360208260051b850101111561400857600080fd5b9250929050565b600082601f83011261402057600080fd5b8135602061403561403083614c35565b614c05565b80838252828201915082860187848660051b890101111561405557600080fd5b60005b8581101561407d57813561406b81614d9c565b84529284019290840190600101614058565b5090979650505050505050565b60008083601f84011261409c57600080fd5b5081356001600160401b038111156140b357600080fd5b60208301915083602082850101111561400857600080fd5b600060a082840312156140dd57600080fd5b50919050565b600060a082840312156140f557600080fd5b60405160a081018181106001600160401b038211171561411757614117614d86565b6040529050806141268361416e565b815261413460208401614187565b602082015261414560408401614187565b6040820152606083013561415881614db1565b6060820152608092830135920191909152919050565b803563ffffffff8116811461418257600080fd5b919050565b80356001600160401b038116811461418257600080fd5b6000602082840312156141b057600080fd5b8135613dcd81614d9c565b6000602082840312156141cd57600080fd5b8151613dcd81614d9c565b600080604083850312156141eb57600080fd5b82356141f681614d9c565b9150602083013561420681614d9c565b809150509250929050565b60008060006060848603121561422657600080fd5b833561423181614d9c565b9250602084013561424181614d9c565b929592945050506040919091013590565b6000806040838503121561426557600080fd5b823561427081614d9c565b946020939093013593505050565b6000806020838503121561429157600080fd5b82356001600160401b038111156142a757600080fd5b6142b385828601613fc4565b90969095509350505050565b6000806000606084860312156142d457600080fd5b83356001600160401b03808211156142eb57600080fd5b6142f78783880161400f565b9450602086013591508082111561430d57600080fd5b6143198783880161400f565b9350604086013591508082111561432f57600080fd5b5061433c8682870161400f565b9150509250925092565b600080600060e0848603121561435b57600080fd5b83356001600160401b0381111561437157600080fd5b8401601f8101861361438257600080fd5b8035602061439261403083614c35565b8083825282820191508285018a848660051b88010111156143b257600080fd5b600095505b848610156143dc576143c881614187565b8352600195909501949183019183016143b7565b5096505086013593506143f69150869050604086016140e3565b90509250925092565b60006020828403121561441157600080fd5b8151613dcd81614db1565b60006020828403121561442e57600080fd5b5035919050565b6000806000806040858703121561444b57600080fd5b84356001600160401b038082111561446257600080fd5b61446e8883890161408a565b9096509450602087013591508082111561448757600080fd5b5061449487828801613fc4565b95989497509550505050565b600080600080600080600080610120898b0312156144bd57600080fd5b88356001600160401b03808211156144d457600080fd5b6144e08c838d0161408a565b909a50985060208b01359150808211156144f957600080fd5b6145058c838d01613fc4565b909850965060408b013591508082111561451e57600080fd5b5061452b8b828c0161408a565b909550935050606089013591506145458a60808b016140cb565b90509295985092959890939650565b600080600080600060e0868803121561456c57600080fd5b85356001600160401b038082111561458357600080fd5b61458f89838a0161408a565b909750955060208801359150808211156145a857600080fd5b506145b588828901613fc4565b90945092506145c9905087604088016140cb565b90509295509295909350565b6000806000606084860312156145ea57600080fd5b505081359360208301359350604090920135919050565b60006020828403121561461357600080fd5b5051919050565b6000806040838503121561462d57600080fd5b50508035926020909101359150565b8183526000602080850194508260005b85811015614678576001600160401b0361466583614187565b168752958201959082019060010161464c565b509495945050505050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b600081518084526146c4816020860160208601614ce7565b601f01601f19169290920160200192915050565b63ffffffff6146e68261416e565b1682526146f560208201614187565b6001600160401b0380821660208501528061471260408501614187565b1660408501525050606081013561472881614db1565b15156060830152608090810135910152565b8183823760009101908152919050565b6000825161475c818460208701614ce7565b9190910192915050565b6001600160a01b03851681526101006020808301829052855191830182905260009161012084019187810191845b818110156147b95783516001600160401b031685529382019392820192600101614794565b505082935086604086015263ffffffff865116606086015280860151925050506001600160401b0380821660808501528060408601511660a085015250506060830151151560c0830152608083015160e083015295945050505050565b6020808252825182820181905260009190848201906040850190845b818110156148575783516001600160a01b031683529284019291840191600101614832565b50909695505050505050565b6000604082016040835280865480835260608501915087600052602092508260002060005b828110156148ad5781546001600160a01b031684529284019260019182019101614888565b505050838103828501528481528590820160005b868110156148ef5782356148d481614d9c565b6001600160a01b0316825291830191908301906001016148c1565b50979650505050505050565b60408152600061490f604083018688614683565b8281036020840152613eb381858761463c565b60006101208083526149378184018b8d614683565b9050828103602084015261494c81898b61463c565b90508281036040840152614961818789614683565b91505083606083015261497760808301846146d8565b9998505050505050505050565b60e08152600061499860e083018789614683565b82810360208401526149ab81868861463c565b9150506149bb60408301846146d8565b9695505050505050565b6080815260006149d960808301888a614683565b82810360208401526149eb81886146ac565b90508281036040840152614a00818688614683565b915050826060830152979650505050505050565b606081526000614a28606083018688614683565b8460208401528281036040840152613eb381856146ac565b6020810160058310614a6257634e487b7160e01b600052602160045260246000fd5b91905290565b602081526000613dcd60208301846146ac565b60208082526017908201527f43616c6c6572206973206e6f7420746865205661756c74000000000000000000604082015260600190565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b60208082526010908201526f14185d5cd8589b194e881c185d5cd95960821b604082015260600190565b6020808252601d908201527f43616c6c6572206973206e6f7420746865205265676973747261746f72000000604082015260600190565b6020808252600e908201526d1499595b9d1c985b9d0818d85b1b60921b604082015260600190565b6020808252601c908201527f43616c6c6572206973206e6f7420746865205374726174656769737400000000604082015260600190565b6000808335601e19843603018112614bc057600080fd5b8301803591506001600160401b03821115614bda57600080fd5b60200191503681900382131561400857600080fd5b60008235605e1983360301811261475c57600080fd5b604051601f8201601f191681016001600160401b0381118282101715614c2d57614c2d614d86565b604052919050565b60006001600160401b03821115614c4e57614c4e614d86565b5060051b60200190565b600080821280156001600160ff1b0384900385131615614c7a57614c7a614d2e565b600160ff1b8390038412811615614c9357614c93614d2e565b50500190565b60008219821115614cac57614cac614d2e565b500190565b6000816000190483118215151615614ccb57614ccb614d2e565b500290565b600082821015614ce257614ce2614d2e565b500390565b60005b83811015614d02578181015183820152602001614cea565b83811115610f365750506000910152565b6000600019821415614d2757614d27614d2e565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b038116811461280657600080fd5b801515811461280657600080fdfe53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac45357bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa264697066735822122022c067cacd1532e922314924802c9c6549951b66ed82fb2629890bc62b7b120a64736f6c634300080700337bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a", + "deployedBytecode": "0x6080604052600436106103855760003560e01c8063853828b6116101d1578063c7af335211610102578063dbe55e56116100a0578063e75292391161006f578063e752923914610b80578063ee7afe2d14610b96578063f1188e4014610bab578063f6ca71b014610bdf57600080fd5b8063dbe55e5614610aed578063dd505df614610b21578063de34d71314610b55578063de5f626814610b6b57600080fd5b8063d059f6ef116100dc578063d059f6ef14610a76578063d38bfff414610a8d578063d9caed1214610aad578063d9f00ec714610acd57600080fd5b8063c7af335214610a10578063c98517c514610a25578063cceab75014610a4257600080fd5b8063a3b81e731161016f578063ab12edf511610149578063ab12edf51461099b578063ad1728cb146109bb578063bb1b918d146109d0578063c2e1e3f4146109f057600080fd5b8063a3b81e7314610919578063a4f98af414610939578063aa388af61461094e57600080fd5b80639092c31c116101ab5780639092c31c146108685780639136616a1461089c57806396d538bb146108bc5780639da0e462146108dc57600080fd5b8063853828b61461080e57806387bae867146108235780638d7c0e461461084857600080fd5b80635d36b190116102b65780636ef38795116102545780637b2d9b2c116102235780637b2d9b2c146107ad5780637b8962f7146107cd578063842f5c46146107e35780638456cb59146107f957600080fd5b80636ef3879514610719578063714897df1461073957806371a735f31461076d5780637260f8261461078d57600080fd5b8063630923831161029057806363092383146106ad57806366e3667e146106c357806367c7066c146106d95780636e811d38146106f957600080fd5b80635d36b190146106445780635f515226146106595780636093d3801461067957600080fd5b8063435356d1116103235780635205c380116102fd5780635205c380146105b7578063579a7e1a146105d75780635a063f631461060b5780635c975abb1461062057600080fd5b8063435356d11461056157806347e7ef2414610581578063484be812146105a157600080fd5b80631072cbea1161035f5780631072cbea146104c957806322495dc8146104e95780633c86495914610509578063430bf08a1461052d57600080fd5b80630c340a24146104415780630ed57b3a146104735780630fc3b4c41461049357600080fd5b3661043c57336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614806103e95750336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016145b61043a5760405162461bcd60e51b815260206004820152601e60248201527f657468206e6f742066726f6d20616c6c6f77656420636f6e747261637473000060448201526064015b60405180910390fd5b005b600080fd5b34801561044d57600080fd5b50610456610c01565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561047f57600080fd5b5061043a61048e3660046141d8565b610c1e565b34801561049f57600080fd5b506104566104ae36600461419e565b609f602052600090815260409020546001600160a01b031681565b3480156104d557600080fd5b5061043a6104e4366004614252565b610c50565b3480156104f557600080fd5b5061043a610504366004614346565b610d0d565b34801561051557600080fd5b5061051f60695481565b60405190815260200161046a565b34801561053957600080fd5b506104567f000000000000000000000000000000000000000000000000000000000000000081565b34801561056d57600080fd5b5061043a61057c3660046142bf565b610e57565b34801561058d57600080fd5b5061043a61059c366004614252565b610f3c565b3480156105ad57600080fd5b5061051f606a5481565b3480156105c357600080fd5b5061043a6105d236600461441c565b61105b565b3480156105e357600080fd5b506104567f000000000000000000000000000000000000000000000000000000000000000081565b34801561061757600080fd5b5061043a6110b7565b34801561062c57600080fd5b5060335460ff165b604051901515815260200161046a565b34801561065057600080fd5b5061043a611156565b34801561066557600080fd5b5061051f61067436600461419e565b6111fc565b34801561068557600080fd5b506104567f000000000000000000000000000000000000000000000000000000000000000081565b3480156106b957600080fd5b5061051f611c2081565b3480156106cf57600080fd5b5061051f60345481565b3480156106e557600080fd5b5060a354610456906001600160a01b031681565b34801561070557600080fd5b5061043a61071436600461419e565b611330565b34801561072557600080fd5b5061043a61073436600461427e565b6113b0565b34801561074557600080fd5b5061051f7f000000000000000000000000000000000000000000000000000000000000000081565b34801561077957600080fd5b5061043a610788366004614554565b61193b565b34801561079957600080fd5b50603654610456906001600160a01b031681565b3480156107b957600080fd5b506104566107c836600461441c565b611afd565b3480156107d957600080fd5b5061051f60375481565b3480156107ef57600080fd5b5061051f60685481565b34801561080557600080fd5b5061043a611b27565b34801561081a57600080fd5b5061043a611bf0565b34801561082f57600080fd5b506033546104569061010090046001600160a01b031681565b34801561085457600080fd5b5061043a6108633660046145d5565b611dc2565b34801561087457600080fd5b506104567f000000000000000000000000000000000000000000000000000000000000000081565b3480156108a857600080fd5b5061043a6108b736600461441c565b612297565b3480156108c857600080fd5b5061043a6108d736600461427e565b612462565b3480156108e857600080fd5b5061090c6108f736600461441c565b60356020526000908152604090205460ff1681565b60405161046a9190614a40565b34801561092557600080fd5b5061043a61093436600461419e565b612582565b34801561094557600080fd5b506106346125fc565b34801561095a57600080fd5b5061063461096936600461419e565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0390811691161490565b3480156109a757600080fd5b5061043a6109b636600461461a565b61265b565b3480156109c757600080fd5b5061043a612743565b3480156109dc57600080fd5b5061043a6109eb3660046144a0565b612809565b3480156109fc57600080fd5b5061043a610a0b36600461419e565b6129d6565b348015610a1c57600080fd5b50610634612a63565b348015610a3157600080fd5b5061051f6801bc16d674ec80000081565b348015610a4e57600080fd5b506104567f000000000000000000000000000000000000000000000000000000000000000081565b348015610a8257600080fd5b5061051f6101075481565b348015610a9957600080fd5b5061043a610aa836600461419e565b612a94565b348015610ab957600080fd5b5061043a610ac8366004614211565b612b38565b348015610ad957600080fd5b5061043a610ae8366004614435565b612bcb565b348015610af957600080fd5b506104567f000000000000000000000000000000000000000000000000000000000000000081565b348015610b2d57600080fd5b506104567f000000000000000000000000000000000000000000000000000000000000000081565b348015610b6157600080fd5b5061051f60385481565b348015610b7757600080fd5b5061043a612d89565b348015610b8c57600080fd5b5061051f606b5481565b348015610ba257600080fd5b5061043a612ef6565b348015610bb757600080fd5b506104567f000000000000000000000000000000000000000000000000000000000000000081565b348015610beb57600080fd5b50610bf4612f80565b60405161046a9190614816565b6000610c19600080516020614de08339815191525490565b905090565b610c26612a63565b610c425760405162461bcd60e51b815260040161043190614ab2565b610c4c8282612fe2565b5050565b610c58612a63565b610c745760405162461bcd60e51b815260040161043190614ab2565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b039081169083161415610cf15760405162461bcd60e51b815260206004820152601f60248201527f43616e6e6f74207472616e7366657220737570706f72746564206173736574006044820152606401610431565b610c4c610cfc610c01565b6001600160a01b0384169083613141565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b158015610d6657600080fd5b505afa158015610d7a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d9e91906141bb565b6001600160a01b0316336001600160a01b031614610dce5760405162461bcd60e51b815260040161043190614b72565b60405163bc26e7e560e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063bc26e7e590610e20903090879087908790600401614766565b600060405180830381600087803b158015610e3a57600080fd5b505af1158015610e4e573d6000803e3d6000fd5b50505050505050565b610e5f612a63565b610e7b5760405162461bcd60e51b815260040161043190614ab2565b600054610100900460ff1680610e94575060005460ff16155b610ef75760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610431565b600054610100900460ff16158015610f19576000805461ffff19166101011790555b610f24848484613193565b8015610f36576000805461ff00191690555b50505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610f845760405162461bcd60e51b815260040161043190614a7b565b600080516020614dc083398151915280546002811415610fb65760405162461bcd60e51b815260040161043190614b4a565b600282557f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316846001600160a01b03161461102f5760405162461bcd60e51b8152602060048201526011602482015270155b9cdd5c1c1bdc9d195908185cdcd95d607a1b6044820152606401610431565b8261010760008282546110429190614c99565b909155506110529050848461324e565b50600190555050565b611063612a63565b61107f5760405162461bcd60e51b815260040161043190614ab2565b6040518181527fe26b067424903962f951f568e52ec9a3bbe1589526ea54a4e69ca6eaae1a4c779060200160405180910390a1603755565b60a3546001600160a01b031633146111115760405162461bcd60e51b815260206004820152601b60248201527f43616c6c6572206973206e6f74207468652048617276657374657200000000006044820152606401610431565b600080516020614dc0833981519152805460028114156111435760405162461bcd60e51b815260040161043190614b4a565b6002825561114f6132e0565b5060019055565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b0316146111f15760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b6064820152608401610431565b6111fa3361352e565b565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b0316146112735760405162461bcd60e51b8152602060048201526011602482015270155b9cdd5c1c1bdc9d195908185cdcd95d607a1b6044820152606401610431565b6040516370a0823160e01b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b1580156112d257600080fd5b505afa1580156112e6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061130a9190614601565b603454611320906801bc16d674ec800000614cb1565b61132a9190614c99565b92915050565b611338612a63565b6113545760405162461bcd60e51b815260040161043190614ab2565b6040516001600160a01b038216907f83f29c79feb71f8fba9d0fbc4ba5f0982a28b6b1e868b3fc50e6400d100bca0f90600090a2603380546001600160a01b0390921661010002610100600160a81b0319909216919091179055565b60335461010090046001600160a01b031633146113df5760405162461bcd60e51b815260040161043190614b13565b60335460ff16156114025760405162461bcd60e51b815260040161043190614ae9565b6000611417826801bc16d674ec800000614cb1565b6040516370a0823160e01b81523060048201529091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b15801561147957600080fd5b505afa15801561148d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114b19190614601565b8111156114f45760405162461bcd60e51b81526020600482015260116024820152700d2dce6eaccccd2c6d2cadce840ae8aa89607b1b6044820152606401610431565b6034547f000000000000000000000000000000000000000000000000000000000000000090611524908490614c99565b111561156b5760405162461bcd60e51b815260206004820152601660248201527513585e081d985b1a59185d1bdc9cc81c995858da195960521b6044820152606401610431565b6037548160385461157c9190614c99565b11156115ca5760405162461bcd60e51b815260206004820152601a60248201527f5374616b696e6720455448206f766572207468726573686f6c640000000000006044820152606401610431565b80603860008282546115dc9190614c99565b9091555050604051632e1a7d4d60e01b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561164357600080fd5b505af1158015611657573d6000803e3d6000fd5b50505050611664816135ef565b60408051600160f81b60208201526000602182018190526bffffffffffffffffffffffff193060601b16602c830152910160408051601f1981840301815291905290508260005b8181101561191c5760008686838181106116c7576116c7614d70565b90506020028101906116d99190614bef565b6116e39080614ba9565b6040516116f192919061473a565b604080519182900390912060008181526035602052919091205490915060ff16600181600481111561172557611725614d44565b146117725760405162461bcd60e51b815260206004820152601860248201527f56616c696461746f72206e6f74207265676973746572656400000000000000006044820152606401610431565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663228951186801bc16d674ec8000008a8a878181106117bd576117bd614d70565b90506020028101906117cf9190614bef565b6117d99080614ba9565b898d8d8a8181106117ec576117ec614d70565b90506020028101906117fe9190614bef565b61180c906020810190614ba9565b8f8f8c81811061181e5761181e614d70565b90506020028101906118309190614bef565b604001356040518863ffffffff1660e01b8152600401611855969594939291906149c5565b6000604051808303818588803b15801561186e57600080fd5b505af1158015611882573d6000803e3d6000fd5b5050505050817fd44c8fde6d369f70d395b6cdee4641886d11e3a72cb537696ca04134881692ed8989868181106118bb576118bb614d70565b90506020028101906118cd9190614bef565b6118d79080614ba9565b6801bc16d674ec800000896040516118f29493929190614a14565b60405180910390a2506000908152603560205260409020805460ff191660021790556001016116ab565b50806034600082825461192f9190614c99565b90915550505050505050565b60335461010090046001600160a01b0316331461196a5760405162461bcd60e51b815260040161043190614b13565b60335460ff161561198d5760405162461bcd60e51b815260040161043190614ae9565b6000858560405161199f92919061473a565b604080519182900390912060008181526035602052919091205490915060ff1660038160048111156119d3576119d3614d44565b14611a185760405162461bcd60e51b815260206004820152601560248201527456616c696461746f72206e6f742065786974696e6760581b6044820152606401610431565b6040516312b3fc1960e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906312b3fc1990611a6c908a908a908a908a908a90600401614984565b600060405180830381600087803b158015611a8657600080fd5b505af1158015611a9a573d6000803e3d6000fd5b50505050817f6aecca20726a17c1b81989b2fd09dfdf636bae9e564d4066ca18df62dc1f3dc288888888604051611ad494939291906148fb565b60405180910390a2506000908152603560205260409020805460ff191660041790555050505050565b60a48181548110611b0d57600080fd5b6000918252602090912001546001600160a01b0316905081565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b158015611b8057600080fd5b505afa158015611b94573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bb891906141bb565b6001600160a01b0316336001600160a01b031614611be85760405162461bcd60e51b815260040161043190614b72565b6111fa61361c565b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161480611c3f5750611c2a610c01565b6001600160a01b0316336001600160a01b0316145b611c975760405162461bcd60e51b815260206004820152602360248201527f43616c6c6572206973206e6f7420746865205661756c74206f7220476f7665726044820152623737b960e91b6064820152608401610431565b600080516020614dc083398151915280546002811415611cc95760405162461bcd60e51b815260040161043190614b4a565b600282556040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b158015611d2f57600080fd5b505afa158015611d43573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d679190614601565b90508015611dba57611dba7f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000083613691565b505060019055565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663570d8e1d6040518163ffffffff1660e01b815260040160206040518083038186803b158015611e1b57600080fd5b505afa158015611e2f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e5391906141bb565b6001600160a01b0316336001600160a01b031614611e835760405162461bcd60e51b815260040161043190614b72565b60335460ff16611ecc5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610431565b43611c20606b54611edd9190614c99565b10611f385760405162461bcd60e51b815260206004820152602560248201527f6d616e75616c6c794669784163636f756e74696e672063616c6c656420746f6f6044820152641039b7b7b760d91b6064820152608401610431565b6002198312158015611f4b575060038313155b8015611f655750600083603454611f629190614c58565b12155b611fb15760405162461bcd60e51b815260206004820152601760248201527f696e76616c69642076616c696461746f727344656c74610000000000000000006044820152606401610431565b6811ff6cf0fd15afffff198212158015611fd457506811ff6cf0fd15b000008213155b8015611fee5750600082606854611feb9190614c58565b12155b61203a5760405162461bcd60e51b815260206004820152601d60248201527f696e76616c696420636f6e73656e7375735265776172647344656c74610000006044820152606401610431565b68053444835ec58000008111156120935760405162461bcd60e51b815260206004820152601960248201527f696e76616c69642077657468546f5661756c74416d6f756e74000000000000006044820152606401610431565b60408051848152602081018490529081018290527f80d022717ea022455c5886b8dd8a29c037570aae58aeb4d7b136d7a10ec2e4319060600160405180910390a1826034546120e29190614c58565b6034556068546120f3908390614c58565b60685543606b558015612241577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b15801561215b57600080fd5b505af115801561216f573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb92506044019050602060405180830381600087803b1580156121ff57600080fd5b505af1158015612213573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061223791906143ff565b5061224181613789565b61224b60006137f1565b61228a5760405162461bcd60e51b815260206004820152601060248201526f333ab9b29039ba34b63610313637bbb760811b6044820152606401610431565b612292613c70565b505050565b61229f612a63565b6122bb5760405162461bcd60e51b815260040161043190614ab2565b60a05481106122fc5760405162461bcd60e51b815260206004820152600d60248201526c092dcecc2d8d2c840d2dcc8caf609b1b6044820152606401610431565b600060a0828154811061231157612311614d70565b60009182526020808320909101546001600160a01b03908116808452609f90925260409092205460a0549193509091169061234e90600190614cd0565b8310156123d05760a0805461236590600190614cd0565b8154811061237557612375614d70565b60009182526020909120015460a080546001600160a01b0390921691859081106123a1576123a1614d70565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505b60a08054806123e1576123e1614d5a565b60008281526020808220600019908401810180546001600160a01b031990811690915593019093556001600160a01b03858116808352609f855260409283902080549094169093559051908416815290917f16b7600acff27e39a8a96056b3d533045298de927507f5c1d97e4accde60488c910160405180910390a2505050565b61246a612a63565b6124865760405162461bcd60e51b815260040161043190614ab2565b8060005b818110156125395760008484838181106124a6576124a6614d70565b90506020020160208101906124bb919061419e565b6001600160a01b031614156125295760405162461bcd60e51b815260206004820152602e60248201527f43616e206e6f742073657420616e20656d70747920616464726573732061732060448201526d30903932bbb0b932103a37b5b2b760911b6064820152608401610431565b61253281614d13565b905061248a565b507f04c0b9649497d316554306e53678d5f5f5dbc3a06f97dec13ff4cfe98b986bbc60a4848460405161256e93929190614863565b60405180910390a1610f3660a48484613ef7565b61258a612a63565b6125a65760405162461bcd60e51b815260040161043190614ab2565b6040516001600160a01b038216907f3329861a0008b3348767567d2405492b997abd79a088d0f2cef6b1a09a8e7ff790600090a2603680546001600160a01b0319166001600160a01b0392909216919091179055565b60335460009061010090046001600160a01b0316331461262e5760405162461bcd60e51b815260040161043190614b13565b60335460ff16156126515760405162461bcd60e51b815260040161043190614ae9565b610c1960016137f1565b612663612a63565b61267f5760405162461bcd60e51b815260040161043190614ab2565b808210801561269657506801bc16d674ec80000081105b80156126b35750673782dace9d9000006126b08383614cd0565b10155b6126ff5760405162461bcd60e51b815260206004820152601760248201527f696e636f7272656374206675736520696e74657276616c0000000000000000006044820152606401610431565b60408051838152602081018390527fcb8d24e46eb3c402bf344ee60a6576cba9ef2f59ea1af3b311520704924e901a910160405180910390a1606991909155606a55565b60405163095ea7b360e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015260001960248301527f0000000000000000000000000000000000000000000000000000000000000000169063095ea7b390604401602060405180830381600087803b1580156127ce57600080fd5b505af11580156127e2573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061280691906143ff565b50565b60335461010090046001600160a01b031633146128385760405162461bcd60e51b815260040161043190614b13565b60335460ff161561285b5760405162461bcd60e51b815260040161043190614ae9565b6000888860405161286d92919061473a565b60405190819003902090506000808281526035602052604090205460ff16600481111561289c5761289c614d44565b146128e95760405162461bcd60e51b815260206004820152601c60248201527f56616c696461746f7220616c72656164792072656769737465726564000000006044820152606401610431565b6040516301ba3ee760e21b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906306e8fb9c90612943908c908c908c908c908c908c908c908c90600401614922565b600060405180830381600087803b15801561295d57600080fd5b505af1158015612971573d6000803e3d6000fd5b50505050807facd38e900350661e325d592c959664c0000a306efb2004e7dc283f44e0ea04238a8a8a8a6040516129ab94939291906148fb565b60405180910390a26000908152603560205260409020805460ff191660011790555050505050505050565b6129de612a63565b6129fa5760405162461bcd60e51b815260040161043190614ab2565b60a354604080516001600160a01b03928316815291831660208301527fe48386b84419f4d36e0f96c10cc3510b6fb1a33795620c5098b22472bbe90796910160405180910390a160a380546001600160a01b0319166001600160a01b0392909216919091179055565b6000612a7b600080516020614de08339815191525490565b6001600160a01b0316336001600160a01b031614905090565b612a9c612a63565b612ab85760405162461bcd60e51b815260040161043190614ab2565b612ae0817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b0316612b00600080516020614de08339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614612b805760405162461bcd60e51b815260040161043190614a7b565b600080516020614dc083398151915280546002811415612bb25760405162461bcd60e51b815260040161043190614b4a565b60028255612bc1858585613691565b5060019055505050565b60335461010090046001600160a01b03163314612bfa5760405162461bcd60e51b815260040161043190614b13565b60335460ff1615612c1d5760405162461bcd60e51b815260040161043190614ae9565b60008484604051612c2f92919061473a565b604080519182900390912060008181526035602052919091205490915060ff166002816004811115612c6357612c63614d44565b14612ca75760405162461bcd60e51b815260206004820152601460248201527315985b1a59185d1bdc881b9bdd081cdd185ad95960621b6044820152606401610431565b604051633877322b60e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690633877322b90612cf99089908990899089906004016148fb565b600060405180830381600087803b158015612d1357600080fd5b505af1158015612d27573d6000803e3d6000fd5b50505050817f8c2e15303eb94e531acc988c2a01d1193bdaaa15eda7f16dda85316ed463578d87878787604051612d6194939291906148fb565b60405180910390a2506000908152603560205260409020805460ff1916600317905550505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614612dd15760405162461bcd60e51b815260040161043190614a7b565b600080516020614dc083398151915280546002811415612e035760405162461bcd60e51b815260040161043190614b4a565b600282556040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b158015612e6957600080fd5b505afa158015612e7d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ea19190614601565b905060006101075482612eb49190614cd0565b90508015612eec57610107829055612eec7f00000000000000000000000000000000000000000000000000000000000000008261324e565b5050600182555050565b6036546001600160a01b03163314612f505760405162461bcd60e51b815260206004820152601960248201527f43616c6c6572206973206e6f7420746865204d6f6e69746f72000000000000006044820152606401610431565b6040517fe765a88a37047c5d793dce22b9ceb5a0f5039d276da139b4c7d29613f341f11090600090a16000603855565b606060a4805480602002602001604051908101604052809291908181526020018280548015612fd857602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612fba575b5050505050905090565b6001600160a01b038281166000908152609f6020526040902054161561303f5760405162461bcd60e51b81526020600482015260126024820152711c151bdad95b88185b1c9958591e481cd95d60721b6044820152606401610431565b6001600160a01b0382161580159061305f57506001600160a01b03811615155b61309f5760405162461bcd60e51b8152602060048201526011602482015270496e76616c69642061646472657373657360781b6044820152606401610431565b6001600160a01b038281166000818152609f6020908152604080832080549587166001600160a01b0319968716811790915560a0805460018101825594527f78fdc8d422c49ced035a9edf18d00d3c6a8d81df210f3e5e448e045e77b41e8890930180549095168417909455925190815290917fef6485b84315f9b1483beffa32aae9a0596890395e3d7521f1c5fbb51790e765910160405180910390a25050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052612292908490613cea565b82516131a69060a4906020860190613f5a565b508151815181146131f05760405162461bcd60e51b8152602060048201526014602482015273496e76616c696420696e7075742061727261797360601b6044820152606401610431565b60005b818110156132475761323784828151811061321057613210614d70565b602002602001015184838151811061322a5761322a614d70565b6020026020010151612fe2565b61324081614d13565b90506131f3565b5050505050565b600081116132975760405162461bcd60e51b81526020600482015260166024820152754d757374206465706f73697420736f6d657468696e6760501b6044820152606401610431565b6040805160008152602081018390526001600160a01b038416917f5548c837ab068cf56a2c2479df0882a4922fd203edb7517321831d95078c5f62910160405180910390a25050565b60335460ff16156133035760405162461bcd60e51b815260040161043190614ae9565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663e52253816040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561336057600080fd5b505af1158015613374573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133989190614601565b90506000606854826133aa9190614c99565b9050804710156133fc5760405162461bcd60e51b815260206004820152601860248201527f696e73756666696369656e74206574682062616c616e636500000000000000006044820152606401610431565b8015610c4c5760006068819055507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b15801561346557600080fd5b505af1158015613479573d6000803e3d6000fd5b505060a354604080516001600160a01b0392831681527f0000000000000000000000000000000000000000000000000000000000000000909216602083015281018590527ff6c07a063ed4e63808eb8da7112d46dbcd38de2b40a73dbcc9353c5a94c72353935060600191506134ec9050565b60405180910390a160a354610c4c906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116911683613141565b6001600160a01b0381166135845760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f7220697320616464726573732830290000000000006044820152606401610431565b806001600160a01b03166135a4600080516020614de08339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a361280681600080516020614de083398151915255565b60006135fe8261010754613dbc565b90508061010760008282546136139190614cd0565b90915550505050565b60335460ff161561363f5760405162461bcd60e51b815260040161043190614ae9565b6033805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586136743390565b6040516001600160a01b03909116815260200160405180910390a1565b600081116136e15760405162461bcd60e51b815260206004820152601760248201527f4d75737420776974686472617720736f6d657468696e670000000000000000006044820152606401610431565b6001600160a01b0383166137305760405162461bcd60e51b8152602060048201526016602482015275135d5cdd081cdc1958da599e481c9958da5c1a595b9d60521b6044820152606401610431565b6040805160008152602081018390526001600160a01b038416917f2717ead6b9200dd235aad468c9809ea400fe33ac69b5bfaa6d3e90fc922b6398910160405180910390a26122926001600160a01b0383168483613141565b6040805160008152602081018390526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016917f2717ead6b9200dd235aad468c9809ea400fe33ac69b5bfaa6d3e90fc922b6398910160405180910390a250565b60006068544710156138065761132a82613dd4565b6000606854476138169190614cd0565b9050600191506801bc16d674ec80000081106139f35760006801bc16d674ec80000082049050806034600082825461384e9190614cd0565b9091555060009050613869826801bc16d674ec800000614cb1565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b1580156138c657600080fd5b505af11580156138da573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb92506044019050602060405180830381600087803b15801561396a57600080fd5b505af115801561397e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139a291906143ff565b506139ac81613789565b60345460408051848152602081019290925281018290527fbe7040030ff7b347853214bf49820c6d455fedf58f3815f85c7bc5216993682b9060600160405180910390a150505b600060685447613a039190614cd0565b90506801bc16d674ec8000008110613a555760405162461bcd60e51b8152602060048201526015602482015274756e6578706563746564206163636f756e74696e6760581b6044820152606401610431565b80613a61575050919050565b606954811015613abb578060686000828254613a7d9190614c99565b90915550506040518181527f7a745a2c63a535068f52ceca27debd5297bbad5f7f37ec53d044a59d0362445d906020015b60405180910390a1613c69565b606a54811115613c58577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b158015613b2057600080fd5b505af1158015613b34573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb92506044019050602060405180830381600087803b158015613bc457600080fd5b505af1158015613bd8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613bfc91906143ff565b50600160346000828254613c109190614cd0565b90915550613c1f905081613789565b60345460408051918252602082018390527f6aa7e30787b26429ced603a7aba8b19c4b5d5bcf29a3257da953c8d53bcaa3a69101613aae565b613c6184613dd4565b949350505050565b5050919050565b60335460ff16613cb95760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610431565b6033805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa33613674565b6000613d3f826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316613dec9092919063ffffffff16565b8051909150156122925780806020019051810190613d5d91906143ff565b6122925760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610431565b6000818310613dcb5781613dcd565b825b9392505050565b60008115613de457613de461361c565b506000919050565b6060613c61848460008585843b613e455760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610431565b600080866001600160a01b03168587604051613e61919061474a565b60006040518083038185875af1925050503d8060008114613e9e576040519150601f19603f3d011682016040523d82523d6000602084013e613ea3565b606091505b5091509150613eb3828286613ebe565b979650505050505050565b60608315613ecd575081613dcd565b825115613edd5782518084602001fd5b8160405162461bcd60e51b81526004016104319190614a68565b828054828255906000526020600020908101928215613f4a579160200282015b82811115613f4a5781546001600160a01b0319166001600160a01b03843516178255602090920191600190910190613f17565b50613f56929150613faf565b5090565b828054828255906000526020600020908101928215613f4a579160200282015b82811115613f4a57825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190613f7a565b5b80821115613f565760008155600101613fb0565b60008083601f840112613fd657600080fd5b5081356001600160401b03811115613fed57600080fd5b6020830191508360208260051b850101111561400857600080fd5b9250929050565b600082601f83011261402057600080fd5b8135602061403561403083614c35565b614c05565b80838252828201915082860187848660051b890101111561405557600080fd5b60005b8581101561407d57813561406b81614d9c565b84529284019290840190600101614058565b5090979650505050505050565b60008083601f84011261409c57600080fd5b5081356001600160401b038111156140b357600080fd5b60208301915083602082850101111561400857600080fd5b600060a082840312156140dd57600080fd5b50919050565b600060a082840312156140f557600080fd5b60405160a081018181106001600160401b038211171561411757614117614d86565b6040529050806141268361416e565b815261413460208401614187565b602082015261414560408401614187565b6040820152606083013561415881614db1565b6060820152608092830135920191909152919050565b803563ffffffff8116811461418257600080fd5b919050565b80356001600160401b038116811461418257600080fd5b6000602082840312156141b057600080fd5b8135613dcd81614d9c565b6000602082840312156141cd57600080fd5b8151613dcd81614d9c565b600080604083850312156141eb57600080fd5b82356141f681614d9c565b9150602083013561420681614d9c565b809150509250929050565b60008060006060848603121561422657600080fd5b833561423181614d9c565b9250602084013561424181614d9c565b929592945050506040919091013590565b6000806040838503121561426557600080fd5b823561427081614d9c565b946020939093013593505050565b6000806020838503121561429157600080fd5b82356001600160401b038111156142a757600080fd5b6142b385828601613fc4565b90969095509350505050565b6000806000606084860312156142d457600080fd5b83356001600160401b03808211156142eb57600080fd5b6142f78783880161400f565b9450602086013591508082111561430d57600080fd5b6143198783880161400f565b9350604086013591508082111561432f57600080fd5b5061433c8682870161400f565b9150509250925092565b600080600060e0848603121561435b57600080fd5b83356001600160401b0381111561437157600080fd5b8401601f8101861361438257600080fd5b8035602061439261403083614c35565b8083825282820191508285018a848660051b88010111156143b257600080fd5b600095505b848610156143dc576143c881614187565b8352600195909501949183019183016143b7565b5096505086013593506143f69150869050604086016140e3565b90509250925092565b60006020828403121561441157600080fd5b8151613dcd81614db1565b60006020828403121561442e57600080fd5b5035919050565b6000806000806040858703121561444b57600080fd5b84356001600160401b038082111561446257600080fd5b61446e8883890161408a565b9096509450602087013591508082111561448757600080fd5b5061449487828801613fc4565b95989497509550505050565b600080600080600080600080610120898b0312156144bd57600080fd5b88356001600160401b03808211156144d457600080fd5b6144e08c838d0161408a565b909a50985060208b01359150808211156144f957600080fd5b6145058c838d01613fc4565b909850965060408b013591508082111561451e57600080fd5b5061452b8b828c0161408a565b909550935050606089013591506145458a60808b016140cb565b90509295985092959890939650565b600080600080600060e0868803121561456c57600080fd5b85356001600160401b038082111561458357600080fd5b61458f89838a0161408a565b909750955060208801359150808211156145a857600080fd5b506145b588828901613fc4565b90945092506145c9905087604088016140cb565b90509295509295909350565b6000806000606084860312156145ea57600080fd5b505081359360208301359350604090920135919050565b60006020828403121561461357600080fd5b5051919050565b6000806040838503121561462d57600080fd5b50508035926020909101359150565b8183526000602080850194508260005b85811015614678576001600160401b0361466583614187565b168752958201959082019060010161464c565b509495945050505050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b600081518084526146c4816020860160208601614ce7565b601f01601f19169290920160200192915050565b63ffffffff6146e68261416e565b1682526146f560208201614187565b6001600160401b0380821660208501528061471260408501614187565b1660408501525050606081013561472881614db1565b15156060830152608090810135910152565b8183823760009101908152919050565b6000825161475c818460208701614ce7565b9190910192915050565b6001600160a01b03851681526101006020808301829052855191830182905260009161012084019187810191845b818110156147b95783516001600160401b031685529382019392820192600101614794565b505082935086604086015263ffffffff865116606086015280860151925050506001600160401b0380821660808501528060408601511660a085015250506060830151151560c0830152608083015160e083015295945050505050565b6020808252825182820181905260009190848201906040850190845b818110156148575783516001600160a01b031683529284019291840191600101614832565b50909695505050505050565b6000604082016040835280865480835260608501915087600052602092508260002060005b828110156148ad5781546001600160a01b031684529284019260019182019101614888565b505050838103828501528481528590820160005b868110156148ef5782356148d481614d9c565b6001600160a01b0316825291830191908301906001016148c1565b50979650505050505050565b60408152600061490f604083018688614683565b8281036020840152613eb381858761463c565b60006101208083526149378184018b8d614683565b9050828103602084015261494c81898b61463c565b90508281036040840152614961818789614683565b91505083606083015261497760808301846146d8565b9998505050505050505050565b60e08152600061499860e083018789614683565b82810360208401526149ab81868861463c565b9150506149bb60408301846146d8565b9695505050505050565b6080815260006149d960808301888a614683565b82810360208401526149eb81886146ac565b90508281036040840152614a00818688614683565b915050826060830152979650505050505050565b606081526000614a28606083018688614683565b8460208401528281036040840152613eb381856146ac565b6020810160058310614a6257634e487b7160e01b600052602160045260246000fd5b91905290565b602081526000613dcd60208301846146ac565b60208082526017908201527f43616c6c6572206973206e6f7420746865205661756c74000000000000000000604082015260600190565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b60208082526010908201526f14185d5cd8589b194e881c185d5cd95960821b604082015260600190565b6020808252601d908201527f43616c6c6572206973206e6f7420746865205265676973747261746f72000000604082015260600190565b6020808252600e908201526d1499595b9d1c985b9d0818d85b1b60921b604082015260600190565b6020808252601c908201527f43616c6c6572206973206e6f7420746865205374726174656769737400000000604082015260600190565b6000808335601e19843603018112614bc057600080fd5b8301803591506001600160401b03821115614bda57600080fd5b60200191503681900382131561400857600080fd5b60008235605e1983360301811261475c57600080fd5b604051601f8201601f191681016001600160401b0381118282101715614c2d57614c2d614d86565b604052919050565b60006001600160401b03821115614c4e57614c4e614d86565b5060051b60200190565b600080821280156001600160ff1b0384900385131615614c7a57614c7a614d2e565b600160ff1b8390038412811615614c9357614c93614d2e565b50500190565b60008219821115614cac57614cac614d2e565b500190565b6000816000190483118215151615614ccb57614ccb614d2e565b500290565b600082821015614ce257614ce2614d2e565b500390565b60005b83811015614d02578181015183820152602001614cea565b83811115610f365750506000910152565b6000600019821415614d2757614d27614d2e565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b038116811461280657600080fd5b801515811461280657600080fdfe53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac45357bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa264697066735822122022c067cacd1532e922314924802c9c6549951b66ed82fb2629890bc62b7b120a64736f6c63430008070033", "libraries": {}, "devdoc": { "author": "Origin Protocol Inc", @@ -1509,6 +1528,7 @@ "_baseConfig": "Base strategy config with platformAddress (ERC-4626 Vault contract), eg sfrxETH or sDAI, and vaultAddress (OToken Vault contract), eg VaultProxy or OETHVaultProxy", "_beaconChainDepositContract": "Address of the beacon chain deposit contract", "_feeAccumulator": "Address of the fee accumulator receiving execution layer validator rewards", + "_maxValidators": "Maximum number of validators that can be registered in the strategy", "_ssvNetwork": "Address of the SSV Network contract", "_ssvToken": "Address of the Erc20 SSV Token contract", "_wethAddress": "Address of the Erc20 WETH Token contract" @@ -1523,7 +1543,9 @@ "depositSSV(uint64[],uint256,(uint32,uint64,uint64,bool,uint256))": { "details": "A SSV cluster is defined by the SSVOwnerAddress and the set of operatorIds. uses \"onlyStrategist\" modifier so continuous front-running can't DOS our maintenance service that tries to top up SSV tokens.", "params": { - "cluster": "The SSV cluster details that must be derived from emitted events from the SSVNetwork contract." + "cluster": "The SSV cluster details including the validator count and SSV balance", + "operatorIds": "The operator IDs of the SSV Cluster", + "ssvAmount": "The amount of SSV tokens to be deposited to the SSV cluster" } }, "doAccounting()": { @@ -1532,6 +1554,12 @@ "accountingValid": "true if accounting was successful, false if fuse is blown" } }, + "exitSsvValidator(bytes,uint64[])": { + "params": { + "operatorIds": "The operator IDs of the SSV Cluster", + "publicKey": "The public key of the validator" + } + }, "getRewardTokenAddresses()": { "returns": { "_0": "address[] the reward token addresses." @@ -1555,11 +1583,27 @@ "paused()": { "details": "Returns true if the contract is paused, and false otherwise." }, + "registerSsvValidator(bytes,uint64[],bytes,uint256,(uint32,uint64,uint64,bool,uint256))": { + "params": { + "cluster": "The SSV cluster details including the validator count and SSV balance", + "operatorIds": "The operator IDs of the SSV Cluster", + "publicKey": "The public key of the validator", + "sharesData": "The validator shares data", + "ssvAmount": "The amount of SSV tokens to be deposited to the SSV cluster" + } + }, "removePToken(uint256)": { "params": { "_assetIndex": "Index of the asset to be removed" } }, + "removeSsvValidator(bytes,uint64[],(uint32,uint64,uint64,bool,uint256))": { + "params": { + "cluster": "The SSV cluster details including the validator count and SSV balance", + "operatorIds": "The operator IDs of the SSV Cluster", + "publicKey": "The public key of the validator" + } + }, "setHarvesterAddress(address)": { "params": { "_harvesterAddress": "Address of the harvester contract." @@ -1628,6 +1672,9 @@ "MAX_STAKE()": { "notice": "The maximum amount of ETH that can be staked by a validator" }, + "MAX_VALIDATORS()": { + "notice": "Maximum number of validators that can be registered in this strategy" + }, "MIN_FIX_ACCOUNTING_CADENCE()": { "notice": "The minimum amount of blocks that need to pass between two calls to manuallyFixAccounting" }, @@ -1788,7 +1835,7 @@ "storageLayout": { "storage": [ { - "astId": 42141, + "astId": 5605, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "initialized", "offset": 0, @@ -1796,7 +1843,7 @@ "type": "t_bool" }, { - "astId": 42144, + "astId": 5608, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "initializing", "offset": 1, @@ -1804,7 +1851,7 @@ "type": "t_bool" }, { - "astId": 42184, + "astId": 5648, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "______gap", "offset": 0, @@ -1812,7 +1859,7 @@ "type": "t_array(t_uint256)50_storage" }, { - "astId": 656, + "astId": 17, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "_paused", "offset": 0, @@ -1820,7 +1867,7 @@ "type": "t_bool" }, { - "astId": 35132, + "astId": 3714, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "validatorRegistrator", "offset": 1, @@ -1828,7 +1875,7 @@ "type": "t_address" }, { - "astId": 35135, + "astId": 3717, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "activeDepositedValidators", "offset": 0, @@ -1836,15 +1883,15 @@ "type": "t_uint256" }, { - "astId": 35141, + "astId": 3723, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "validatorsStates", "offset": 0, "slot": "53", - "type": "t_mapping(t_bytes32,t_enum(VALIDATOR_STATE)35160)" + "type": "t_mapping(t_bytes32,t_enum(VALIDATOR_STATE)3742)" }, { - "astId": 35144, + "astId": 3726, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "stakingMonitor", "offset": 0, @@ -1852,7 +1899,7 @@ "type": "t_address" }, { - "astId": 35147, + "astId": 3729, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "stakeETHThreshold", "offset": 0, @@ -1860,7 +1907,7 @@ "type": "t_uint256" }, { - "astId": 35150, + "astId": 3732, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "stakeETHTally", "offset": 0, @@ -1868,7 +1915,7 @@ "type": "t_uint256" }, { - "astId": 35154, + "astId": 3736, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "__gap", "offset": 0, @@ -1876,7 +1923,7 @@ "type": "t_array(t_uint256)47_storage" }, { - "astId": 34631, + "astId": 3207, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "consensusRewards", "offset": 0, @@ -1884,7 +1931,7 @@ "type": "t_uint256" }, { - "astId": 34634, + "astId": 3210, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "fuseIntervalStart", "offset": 0, @@ -1892,7 +1939,7 @@ "type": "t_uint256" }, { - "astId": 34637, + "astId": 3213, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "fuseIntervalEnd", "offset": 0, @@ -1900,7 +1947,7 @@ "type": "t_uint256" }, { - "astId": 34640, + "astId": 3216, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "lastFixAccountingBlockNumber", "offset": 0, @@ -1908,7 +1955,7 @@ "type": "t_uint256" }, { - "astId": 34644, + "astId": 3220, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "__gap", "offset": 0, @@ -1916,7 +1963,7 @@ "type": "t_array(t_uint256)49_storage" }, { - "astId": 42264, + "astId": 5728, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "_deprecated_platformAddress", "offset": 0, @@ -1924,7 +1971,7 @@ "type": "t_address" }, { - "astId": 42267, + "astId": 5731, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "_deprecated_vaultAddress", "offset": 0, @@ -1932,7 +1979,7 @@ "type": "t_address" }, { - "astId": 42272, + "astId": 5736, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "assetToPToken", "offset": 0, @@ -1940,7 +1987,7 @@ "type": "t_mapping(t_address,t_address)" }, { - "astId": 42276, + "astId": 5740, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "assetsMapped", "offset": 0, @@ -1948,7 +1995,7 @@ "type": "t_array(t_address)dyn_storage" }, { - "astId": 42278, + "astId": 5742, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "_deprecated_rewardTokenAddress", "offset": 0, @@ -1956,7 +2003,7 @@ "type": "t_address" }, { - "astId": 42280, + "astId": 5744, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "_deprecated_rewardLiquidationThreshold", "offset": 0, @@ -1964,7 +2011,7 @@ "type": "t_uint256" }, { - "astId": 42283, + "astId": 5747, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "harvesterAddress", "offset": 0, @@ -1972,7 +2019,7 @@ "type": "t_address" }, { - "astId": 42287, + "astId": 5751, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "rewardTokenAddresses", "offset": 0, @@ -1980,7 +2027,7 @@ "type": "t_array(t_address)dyn_storage" }, { - "astId": 42291, + "astId": 5755, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "_reserved", "offset": 0, @@ -1988,7 +2035,7 @@ "type": "t_array(t_int256)98_storage" }, { - "astId": 34145, + "astId": 2718, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "depositedWethAccountedFor", "offset": 0, @@ -1996,7 +2043,7 @@ "type": "t_uint256" }, { - "astId": 34149, + "astId": 2722, "contract": "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol:NativeStakingSSVStrategy", "label": "__gap", "offset": 0, @@ -2050,7 +2097,7 @@ "label": "bytes32", "numberOfBytes": "32" }, - "t_enum(VALIDATOR_STATE)35160": { + "t_enum(VALIDATOR_STATE)3742": { "encoding": "inplace", "label": "enum ValidatorRegistrator.VALIDATOR_STATE", "numberOfBytes": "1" @@ -2067,12 +2114,12 @@ "numberOfBytes": "32", "value": "t_address" }, - "t_mapping(t_bytes32,t_enum(VALIDATOR_STATE)35160)": { + "t_mapping(t_bytes32,t_enum(VALIDATOR_STATE)3742)": { "encoding": "mapping", "key": "t_bytes32", "label": "mapping(bytes32 => enum ValidatorRegistrator.VALIDATOR_STATE)", "numberOfBytes": "32", - "value": "t_enum(VALIDATOR_STATE)35160" + "value": "t_enum(VALIDATOR_STATE)3742" }, "t_uint256": { "encoding": "inplace", diff --git a/contracts/deployments/holesky/solcInputs/47ae51f49254a864e8595718d22928c8.json b/contracts/deployments/holesky/solcInputs/47ae51f49254a864e8595718d22928c8.json new file mode 100644 index 0000000000..8b4b73f500 --- /dev/null +++ b/contracts/deployments/holesky/solcInputs/47ae51f49254a864e8595718d22928c8.json @@ -0,0 +1,107 @@ +{ + "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/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/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" + }, + "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/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/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/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 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 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 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/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 function removeAsset(address _asset) external;\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/strategies/NativeStaking/FeeAccumulator.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { Address } from \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport { Governable } from \"../../governance/Governable.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 is Governable {\n /// @notice The address of the Native Staking Strategy\n address public immutable STRATEGY;\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 }\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_ADDRESS;\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_ADDRESS = _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 /// @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_TOKEN_ADDRESS).deposit{ value: ethRewards }();\n\n emit RewardTokenCollected(\n harvesterAddress,\n WETH_TOKEN_ADDRESS,\n ethRewards\n );\n IERC20(WETH_TOKEN_ADDRESS).safeTransfer(\n harvesterAddress,\n ethRewards\n );\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_TOKEN_ADDRESS, \"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_TOKEN_ADDRESS).balanceOf(\n address(this)\n );\n uint256 newWeth = wethBalance - depositedWethAccountedFor;\n\n if (newWeth > 0) {\n depositedWethAccountedFor = wethBalance;\n\n _deposit(WETH_TOKEN_ADDRESS, newWeth);\n }\n }\n\n /// @notice Withdraw WETH from this contract. Used only if some WETH for is lingering on the contract. That\n /// can happen when:\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 _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 emit Withdrawal(_asset, address(0), _amount);\n IERC20(_asset).safeTransfer(_recipient, _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_TOKEN_ADDRESS).balanceOf(\n address(this)\n );\n if (wethBalance > 0) {\n _withdraw(vaultAddress, WETH_TOKEN_ADDRESS, wethBalance);\n }\n }\n\n function _abstractSetPToken(address _asset, address) internal override {}\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_TOKEN_ADDRESS, \"Unsupported asset\");\n\n balance =\n // add the ETH that has been staked in validators\n activeDepositedValidators *\n 32 ether +\n // add the WETH in the strategy from deposits that are still to be staked\n IERC20(WETH_TOKEN_ADDRESS).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_TOKEN_ADDRESS;\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_ADDRESS).approve(\n SSV_NETWORK_ADDRESS,\n type(uint256).max\n );\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 ||\n msg.sender == WETH_TOKEN_ADDRESS,\n \"eth not from allowed contracts\"\n );\n }\n\n function _wethWithdrawnToVault(uint256 _amount) internal override {\n emit Withdrawal(WETH_TOKEN_ADDRESS, address(0), _amount);\n }\n\n function _wethWithdrawnAndStaked(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 direclty\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 /// @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 MAX_STAKE = 32 ether;\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 emit FuseIntervalUpdated(_fuseIntervalStart, _fuseIntervalEnd);\n\n fuseIntervalStart = _fuseIntervalStart;\n fuseIntervalEnd = _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 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 >= MAX_STAKE) {\n uint256 fullyWithdrawnValidators;\n // safe since MAX_STAKE is hardcoded to 32ETH\n unchecked {\n // explicitly cast to uint256 as we want to round to a whole number of validators\n fullyWithdrawnValidators = uint256(newSweptETH / MAX_STAKE);\n }\n activeDepositedValidators -= fullyWithdrawnValidators;\n\n uint256 wethToVault = MAX_STAKE * fullyWithdrawnValidators;\n IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: wethToVault }();\n // slither-disable-next-line unchecked-transfer\n IWETH9(WETH_TOKEN_ADDRESS).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 < 32 ether, \"unexpected accounting\");\n\n // If no Beacon chain consensus rewards swept\n if (ethRemaining == 0) {\n // do nothing\n return accountingValid;\n }\n // Beacon chain consensus rewards swept (partial validator withdrawals)\n else if (ethRemaining < fuseIntervalStart) {\n // solhint-disable-next-line reentrancy\n consensusRewards += ethRemaining;\n emit AccountingConsensusRewards(ethRemaining);\n }\n // Beacon chain consensus rewards swept but also a slashed validator fully exited\n else if (ethRemaining > fuseIntervalEnd) {\n IWETH9(WETH_TOKEN_ADDRESS).deposit{ value: ethRemaining }();\n // slither-disable-next-line unchecked-transfer\n IWETH9(WETH_TOKEN_ADDRESS).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 {\n require(\n lastFixAccountingBlockNumber + MIN_FIX_ACCOUNTING_CADENCE <\n block.number,\n \"manuallyFixAccounting 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 emit AccountingManuallyFixed(\n _validatorsDelta,\n _consensusRewardsDelta,\n _ethToVaultAmount\n );\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_TOKEN_ADDRESS).deposit{ value: _ethToVaultAmount }();\n // slither-disable-next-line unchecked-transfer\n IWETH9(WETH_TOKEN_ADDRESS).transfer(\n VAULT_ADDRESS,\n _ethToVaultAmount\n );\n _wethWithdrawnToVault(_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 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 address of the Wrapped ETH (WETH) token contract\n address public immutable WETH_TOKEN_ADDRESS;\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_ADDRESS;\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 governor needs to approve further staking\n uint256 public stakeETHThreshold;\n /// @notice Amount of ETH that can has been staked since the last governor approval.\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(\n bytes32 indexed pubKeyHash,\n bytes pubKey,\n uint256 amount,\n bytes withdrawal_credentials\n );\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_TOKEN_ADDRESS = _wethAddress;\n BEACON_CHAIN_DEPOSIT_CONTRACT = _beaconChainDepositContract;\n SSV_NETWORK_ADDRESS = _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 emit RegistratorChanged(_address);\n validatorRegistrator = _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 emit StakingMonitorChanged(_address);\n stakingMonitor = _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 emit StakeETHThresholdChanged(_amount);\n stakeETHThreshold = _amount;\n }\n\n /// @notice Reset the stakeETHTally\n function resetStakeETHTally() external onlyStakingMonitor {\n emit StakeETHTallyReset();\n stakeETHTally = 0;\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 {\n uint256 requiredETH = validators.length * 32 ether;\n\n // Check there is enough WETH from the deposits sitting in this strategy contract\n require(\n requiredETH <= IWETH9(WETH_TOKEN_ADDRESS).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_TOKEN_ADDRESS).withdraw(requiredETH);\n _wethWithdrawnAndStaked(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 withdrawal_credentials = abi.encodePacked(\n bytes1(0x01),\n bytes11(0),\n address(this)\n );\n\n uint256 validatorsLength = validators.length;\n // For each validator\n for (uint256 i = 0; i < validatorsLength; ) {\n bytes32 pubKeyHash = keccak256(validators[i].pubkey);\n VALIDATOR_STATE currentState = validatorsStates[pubKeyHash];\n\n require(\n currentState == VALIDATOR_STATE.REGISTERED,\n \"Validator not registered\"\n );\n\n IDepositContract(BEACON_CHAIN_DEPOSIT_CONTRACT).deposit{\n value: 32 ether\n }(\n validators[i].pubkey,\n withdrawal_credentials,\n validators[i].signature,\n validators[i].depositDataRoot\n );\n\n emit ETHStaked(\n pubKeyHash,\n validators[i].pubkey,\n 32 ether,\n withdrawal_credentials\n );\n\n validatorsStates[pubKeyHash] = VALIDATOR_STATE.STAKED;\n\n unchecked {\n ++i;\n }\n }\n // save gas by changing this storage variable only once rather each time in the loop.\n activeDepositedValidators += validatorsLength;\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 publicKey The public key of the validator\n /// @param operatorIds The operator IDs of the SSV Cluster\n /// @param sharesData The validator shares data\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 registerSsvValidator(\n bytes calldata publicKey,\n uint64[] calldata operatorIds,\n bytes calldata sharesData,\n uint256 ssvAmount,\n Cluster calldata cluster\n ) external onlyRegistrator whenNotPaused {\n bytes32 pubKeyHash = keccak256(publicKey);\n require(\n validatorsStates[pubKeyHash] == VALIDATOR_STATE.NON_REGISTERED,\n \"Validator already registered\"\n );\n ISSVNetwork(SSV_NETWORK_ADDRESS).registerValidator(\n publicKey,\n operatorIds,\n sharesData,\n ssvAmount,\n cluster\n );\n emit SSVValidatorRegistered(pubKeyHash, publicKey, operatorIds);\n\n validatorsStates[pubKeyHash] = VALIDATOR_STATE.REGISTERED;\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_ADDRESS).exitValidator(publicKey, operatorIds);\n emit SSVValidatorExitInitiated(pubKeyHash, publicKey, operatorIds);\n\n validatorsStates[pubKeyHash] = VALIDATOR_STATE.EXITING;\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_ADDRESS).removeValidator(\n publicKey,\n operatorIds,\n cluster\n );\n emit SSVValidatorExitCompleted(pubKeyHash, publicKey, operatorIds);\n\n validatorsStates[pubKeyHash] = VALIDATOR_STATE.EXIT_COMPLETE;\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_ADDRESS).deposit(\n address(this),\n operatorIds,\n ssvAmount,\n cluster\n );\n }\n\n /***************************************\n Abstract\n ****************************************/\n\n /// @dev allows for NativeStakingSSVStrategy contract know how much WETH had been staked\n function _wethWithdrawnAndStaked(uint256 _amount) internal virtual;\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/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/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\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" + } + }, + "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 From 2c90f9f86621942581bc91409ce619ab7db5c454 Mon Sep 17 00:00:00 2001 From: Shahul Hameed <10547529+shahthepro@users.noreply.github.com> Date: Fri, 28 Jun 2024 12:24:03 +0530 Subject: [PATCH 125/273] Fix deployment file --- contracts/deploy/mainnet/098_oeth_withdraw_queue.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/deploy/mainnet/098_oeth_withdraw_queue.js b/contracts/deploy/mainnet/098_oeth_withdraw_queue.js index 196c0f6d1b..df26995ee7 100644 --- a/contracts/deploy/mainnet/098_oeth_withdraw_queue.js +++ b/contracts/deploy/mainnet/098_oeth_withdraw_queue.js @@ -33,7 +33,7 @@ module.exports = deploymentWithGovernanceProposal( // 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("DripperProxy"); + const cDripperProxy = await ethers.getContract("OETHDripperProxy"); // Governance Actions // ---------------- From d8b0fead6c0ca5c686a5be033a7cf4d3be9d30f5 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Wed, 3 Jul 2024 18:28:59 +1000 Subject: [PATCH 126/273] updated deploy number for OETH withdrawal queue --- .../{098_oeth_withdraw_queue.js => 100_oeth_withdraw_queue.js} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename contracts/deploy/mainnet/{098_oeth_withdraw_queue.js => 100_oeth_withdraw_queue.js} (97%) diff --git a/contracts/deploy/mainnet/098_oeth_withdraw_queue.js b/contracts/deploy/mainnet/100_oeth_withdraw_queue.js similarity index 97% rename from contracts/deploy/mainnet/098_oeth_withdraw_queue.js rename to contracts/deploy/mainnet/100_oeth_withdraw_queue.js index df26995ee7..54c44bb149 100644 --- a/contracts/deploy/mainnet/098_oeth_withdraw_queue.js +++ b/contracts/deploy/mainnet/100_oeth_withdraw_queue.js @@ -3,7 +3,7 @@ const { deploymentWithGovernanceProposal } = require("../../utils/deploy"); module.exports = deploymentWithGovernanceProposal( { - deployName: "098_oeth_withdraw_queue", + deployName: "100_oeth_withdraw_queue", forceDeploy: false, //forceSkip: true, reduceQueueTime: true, From a2dada18c60c6c75b029448ba8ef6aaa1daffbbb Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Wed, 3 Jul 2024 18:40:40 +1000 Subject: [PATCH 127/273] Fixed unit tests --- contracts/fork-test.sh | 2 +- .../nativeSsvStaking.holesky-fork-test.js | 42 ------------------- 2 files changed, 1 insertion(+), 43 deletions(-) delete mode 100644 contracts/test/strategies/nativeSsvStaking.holesky-fork-test.js diff --git a/contracts/fork-test.sh b/contracts/fork-test.sh index ed1dbef6c1..915031e176 100755 --- a/contracts/fork-test.sh +++ b/contracts/fork-test.sh @@ -73,7 +73,7 @@ main() if [[ $FORK_NETWORK_NAME == "holesky" ]]; then # Run all files with `.holesky.fork-test.js` suffix when no file name param is given # pass all other params along - params+="test/**/*.holesky-fork-test.js" + params+="test/**/*.holesky.fork-test.js" else # Run all files with `.fork-test.js` suffix when no file name param is given # pass all other params along diff --git a/contracts/test/strategies/nativeSsvStaking.holesky-fork-test.js b/contracts/test/strategies/nativeSsvStaking.holesky-fork-test.js deleted file mode 100644 index babdd482ef..0000000000 --- a/contracts/test/strategies/nativeSsvStaking.holesky-fork-test.js +++ /dev/null @@ -1,42 +0,0 @@ -const { loadSimpleOETHFixture } = require("./../_fixture"); -const { shouldBehaveLikeAnSsvStrategy } = require("../behaviour/ssvStrategy"); -const addresses = require("../../utils/addresses"); -const { impersonateAndFund } = require("../../utils/signers"); - -describe("Holesky ForkTest: Native SSV Staking Strategy", function () { - this.timeout(0); - - let fixture; - beforeEach(async () => { - fixture = await loadSimpleOETHFixture(); - }); - - shouldBehaveLikeAnSsvStrategy(async () => { - return { - ...fixture, - addresses: addresses.holesky, - validatorRegistrator: await impersonateAndFund( - addresses.holesky.validatorRegistrator - ), - ssvNetwork: await ethers.getContractAt( - "ISSVNetwork", - addresses.holesky.SSVNetwork - ), - nativeStakingFeeAccumulator: await ethers.getContractAt( - "FeeAccumulator", - await fixture.nativeStakingSSVStrategy.FEE_ACCUMULATOR_ADDRESS() - ), - testValidator: { - publicKey: - "0x8c463b743efcea2acd67357acce713519444f4d55ece45fba603d66f488e69a781ba9592f017cb3d47ce6e35f10bc5f7", - operatorIds: [111, 119, 230, 252], - sharesData: - "0x8cc3e43193adde4dba3109918a1be4fbeaeb3c446d3859d689578342bc4a8cc14b02d06e7beba6aa68b71b4de3d9d337137a98dae8299e7ae06250357fd355d1380b0a2da2c35b821cfa39bb24cac3867cd6693ab3e9f85b49d936e54fbb87a180108acfe3f6f757875477614f83758ae09b8f6f8aa42b32c84933d8dcd2cb67f587fcbd0c23797758a4472495f86d9da1906636e26632ab876c9e8923ea9bc4a20ca1c37d019ee9763467964a2535210a2beeee39d93d164e0df34d1e382b4b8d3ea82e799e5d41b8edd17be893d646a27815750b08ef1ca1e136c3ce08cbed4980ccf72de6ecee53d53784c16228cd83dabc6f3db1872c323169f653d49b5214723c35117deb7f944a9dde9d0b11446673744f212f3797e748d8c9ad1e8737a58af47b050d99556254d347854cae6211826b668b92a878e676bee46d393e4701eb342a4667cbf4880614853e316b2e4b849eedd27a9243aac4cd0b8ca3c1186ae51fec04d9f95017d69b3a7b25d389d46b8f2571b4983fe42b7f718fd12f5197414ba73ce98a8a0df2bf5d8d7f71bde9b324535bd8c2f5cc89b24d985975707a79e0c59bf416a39b501963655276b97b9545988c479ccee25cefdd8786b1586b97cc922a3c46445e1e0495a36243abaa40bedf09a41fc90cf9d65eebbc50b931f5c598b0d12e0aaf38923ffb19ce6bebbd324692e5fdebee5716e3afa91c3b0a589afb04896c04d87abd4742ea2b03922922adc9badc1a92ded6d5c73b820d430c40ce9ce9c559caa400f6b880982b78c71db8d0b38c982a8b15776dc5f1290592ca5cc99ebe4d4677177243db86c0cfab9979e37f821bc6a1070fa0d9b7c1b5eeff393034b0b8d8cb8089960dcd9db47d4c7cd88e67ad40dc1857d7c655554d0771aa14810a18c3cd38f930adb8734992882b7942c001c971196ebc2ed74b5a7559127fa8f0561cb6ad5efccc2b8be858773b523ef6611430f05e878aa4e560e3bfbcab47777fc6763f1ab1957fa5cbf663f1cd3238022d0e1348b56726eaee420909acd2b8017ef9c2308baf58cc85d56270a6e85fca636a8b49eba6650d514edd95bebe464843f154559bc1019c6f303df43bebb2110e4f2f4df7e36e03869be204fd2b966f3c328ee3b642510da3ced59f82ff61702529a9ed80c8b3899eeb8865e9483b159e0e2f750181e60a5454cdfb3e15d3ba76b3f2cf38a281dbbe266dd4d210920a8bd6ac1eec1ab13faadb4372b323e23f804a9ea303f4806fdf470f5df08e8d6a9ee3fb0c93dff220087d6129943b5626756664e9d649f83085e439d964337134e0bccd15338a988f238a2ac03a5e29e20fe9477a32347ca45932992b433d7eda470052980d07018919d91613f3925d6bed5dea7cacf246c71321dc371809e3b8b94cb779c3811b5ff11f6c9dd19cb05cc6bc21c75b0366c9809472bd10e54f10acaec6f3266665dfa4a05676dad0d2e3958e74443631aa8c52ee02e0ae6a8019f19c0118e472a9b3aab1ca618413e22edb82ee976deb4d1c44c6609a14954957b389ff38ef08a6ad0cf067a70e485ad0d8aff075f16bc1f9374ec6b9fc5ebd76dbe118bcfe14fba8669687603edcbdfb845d79f2f9847476542a84045589bfb6ff80dce7757527b96af96c85e6109a21e64303d4ada08b1093ac6ef4354c233fa4bcddb86af7f2e0cc836d3076ac62a903f1b74026049046b8460717c101dd5e674eeded11d0fa3e61f2f17f296192a2385f8abd576893d72163d0707b0201c391b1d55a63deee508e9e982ffd623fdbf5ac171fdffa87dda6b8662504cf69fc6e91617dc9e846fdb1f4ca93de618ea763915a13426ee7b8", - signature: - "0x83284a7b54224056515bcd0ade22521881755a31d15410d911a9d680a7b7fbf34707118881a880aad04bff2ea58595660a057f6a9889b869246c10d2da0cf243f7b78ab705b71d37cfa282fbeaeeee3092848148b818fe5e764f5d1c09ee6fd9", - depositDataRoot: - "0xf867a406f19c798b5fef29e37a5e7a0eb9b75ffcbeb72b7f337628ccebd3d73a", - }, - }; - }); -}); From 532e9b91da6f6bbc14605dabc7bf97b41bba58f0 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Wed, 3 Jul 2024 20:37:06 +1000 Subject: [PATCH 128/273] Remove stETH from Vault in OETH Withdrawal Queue deployment is not already done Skip Lido Withdrawal Strategy tests --- .../deploy/mainnet/100_oeth_withdraw_queue.js | 42 +++++++++++++++++-- ...o_withdrawal_strategy.mainnet.fork-test.js | 3 +- 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/contracts/deploy/mainnet/100_oeth_withdraw_queue.js b/contracts/deploy/mainnet/100_oeth_withdraw_queue.js index 54c44bb149..7923c81ccb 100644 --- a/contracts/deploy/mainnet/100_oeth_withdraw_queue.js +++ b/contracts/deploy/mainnet/100_oeth_withdraw_queue.js @@ -1,3 +1,5 @@ +const { formatUnits } = require("ethers/lib/utils"); + const addresses = require("../../utils/addresses"); const { deploymentWithGovernanceProposal } = require("../../utils/deploy"); @@ -35,24 +37,58 @@ module.exports = deploymentWithGovernanceProposal( const cVault = await ethers.getContractAt("OETHVault", cVaultProxy.address); const cDripperProxy = await ethers.getContract("OETHDripperProxy"); + const cLidoWithdrawStrategyProxy = await ethers.getContract( + "LidoWithdrawalStrategyProxy" + ); + + 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` + ); + + // If there is more than 1 wei of stETH in the Vault, we need to remove it using the Lido Withdrawal Strategy + const removeStEthActions = stEthInVault.gt(1) + ? [ + // 1. Deposit all stETH in the Vault to the Lido Withdrawal Strategy + { + contract: cVault, + signature: "depositToStrategy(address,address[],uint256[])", + args: [ + cLidoWithdrawStrategyProxy.address, + [stETH.address], + [stEthInVault], + ], + }, + // 2. Remove stETH from the OETH Vault + { + contract: cVault, + signature: "removeAsset(address)", + args: [stETH.address], + }, + ] + : []; + // Governance Actions // ---------------- return { name: "Upgrade OETH Vault to support queued withdrawals", actions: [ - // 1. Upgrade the OETH Vault proxy to the new core vault implementation + // Remove stETH if not done already + ...removeStEthActions, + // 3. Upgrade the OETH Vault proxy to the new core vault implementation { contract: cVaultProxy, signature: "upgradeTo(address)", args: [dVaultCore.address], }, - // 2. set OETH Vault proxy to the new admin vault implementation + // 4. set OETH Vault proxy to the new admin vault implementation { contract: cVault, signature: "setAdminImpl(address)", args: [dVaultAdmin.address], }, - // 3. Set the Dripper contract + // 5. Set the Dripper contract { contract: cVault, signature: "setDripper(address)", diff --git a/contracts/test/strategies/lido_withdrawal_strategy.mainnet.fork-test.js b/contracts/test/strategies/lido_withdrawal_strategy.mainnet.fork-test.js index 16728abde1..6050f503cc 100644 --- a/contracts/test/strategies/lido_withdrawal_strategy.mainnet.fork-test.js +++ b/contracts/test/strategies/lido_withdrawal_strategy.mainnet.fork-test.js @@ -7,7 +7,8 @@ const { ousdUnits, isCI } = require("../helpers"); const { impersonateAccount } = require("../../utils/signers"); const { parseUnits } = require("ethers/lib/utils"); -describe("ForkTest: Lido Withdrawal Strategy", function () { +// Skipping as Lido Withdrawal Strategy has already been used +describe.skip("ForkTest: Lido Withdrawal Strategy", function () { this.timeout(360 * 1000); // Retry up to 3 times on CI From 2075e66d70daac079a78dbdf087d3617dffcd69f Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Wed, 3 Jul 2024 20:45:31 +1000 Subject: [PATCH 129/273] Skipping OETH Vault collateral swaps --- contracts/test/vault/collateral-swaps.mainnet.fork-test.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/contracts/test/vault/collateral-swaps.mainnet.fork-test.js b/contracts/test/vault/collateral-swaps.mainnet.fork-test.js index f9ced0127d..30e3462944 100644 --- a/contracts/test/vault/collateral-swaps.mainnet.fork-test.js +++ b/contracts/test/vault/collateral-swaps.mainnet.fork-test.js @@ -14,7 +14,8 @@ const { resolveAsset } = require("../../utils/resolvers"); const log = require("../../utils/logger")("test:fork:swaps"); -describe("ForkTest: OETH Vault", function () { +// Skipping as the OETH vault should now only contain WETH so no more swaps +describe.skip("ForkTest: OETH Vault", function () { this.timeout(0); // Retry up to 3 times on CI From 4ecffacb1b6ab2ab3c7bf45ed9d804e0bb87d87b Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Wed, 3 Jul 2024 20:56:36 +1000 Subject: [PATCH 130/273] Skipping OETH whale redeem in fork tests Added OETH whale request withdrawal to fork tests --- .../vault/oeth-vault.mainnet.fork-test.js | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/contracts/test/vault/oeth-vault.mainnet.fork-test.js b/contracts/test/vault/oeth-vault.mainnet.fork-test.js index 8f3b17b3e4..dde3968e9b 100644 --- a/contracts/test/vault/oeth-vault.mainnet.fork-test.js +++ b/contracts/test/vault/oeth-vault.mainnet.fork-test.js @@ -188,7 +188,8 @@ describe("ForkTest: OETH Vault", function () { .to.emit(oethVault, "Redeem") .withNamedArgs({ _addr: oethWhaleAddress }); }); - it("should not do full redeem by OETH whale", async () => { + // Skipping as this depends on the WETH available in the Vault + it.skip("should not do full redeem by OETH whale", async () => { const { oeth, oethVault } = fixture; const oethWhaleBalance = await oeth.balanceOf(oethWhaleAddress); @@ -199,6 +200,25 @@ describe("ForkTest: OETH Vault", function () { const tx = oethVault.connect(oethWhaleSigner).redeem(oethWhaleBalance, 0); await expect(tx).to.revertedWith("Liquidity error"); }); + it("should request a withdraw by OETH whale", async () => { + const { oeth, oethVault } = fixture; + + const oethWhaleBalance = await oeth.balanceOf(oethWhaleAddress); + expect(oethWhaleBalance, "no longer an OETH whale").to.gt( + parseUnits("100", 18) + ); + + const tx = await oethVault + .connect(oethWhaleSigner) + .requestWithdrawal(oethWhaleBalance); + + await expect(tx) + .to.emit(oethVault, "WithdrawalRequested") + .withNamedArgs({ + _withdrawer: await oethWhaleSigner.getAddress(), + _amount: oethWhaleBalance, + }); + }); it("OETH whale can redeem after withdraw from all strategies", async () => { const { oeth, oethVault, timelock } = fixture; From f2c278b7b871e0b35795869e918ca66fafb9f227 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Wed, 3 Jul 2024 21:33:07 +1000 Subject: [PATCH 131/273] Fixed spelling in comments of VaultStorage --- contracts/contracts/vault/VaultStorage.sol | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/contracts/contracts/vault/VaultStorage.sol b/contracts/contracts/vault/VaultStorage.sol index 705cb097d0..7824e44489 100644 --- a/contracts/contracts/vault/VaultStorage.sol +++ b/contracts/contracts/vault/VaultStorage.sol @@ -96,7 +96,7 @@ contract VaultStorage is Initializable, Governable { bool isSupported; uint256 _deprecated; // Deprecated storage slot } - /// @dev mapping of strategy contracts to their configiration + /// @dev mapping of strategy contracts to their configuration mapping(address => Strategy) internal strategies; /// @dev list of all vault strategies address[] internal allStrategies; @@ -189,9 +189,9 @@ contract VaultStorage is Initializable, Governable { /// Withdrawal Queue Storage ///// struct WithdrawalQueueMetadata { - // cumulative total of all withdrawal requests included the ones that have already bene claimed + // 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 included the ones that have already bene claimed + // cumulative total of all the requests that can be claimed included the ones that have already been claimed uint128 claimable; // total of all the requests that have been claimed uint128 claimed; From 8f46a2be115fea3890f5f630130e1fc02abe38ed Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Wed, 3 Jul 2024 22:12:08 +1000 Subject: [PATCH 132/273] Fail CI if any mainnet fork tests fail --- .github/workflows/defi.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/defi.yml b/.github/workflows/defi.yml index a201b5035c..a2f15bcfd9 100644 --- a/.github/workflows/defi.yml +++ b/.github/workflows/defi.yml @@ -99,7 +99,7 @@ jobs: strategy: matrix: chunk_id: [0,1,2,3] - continue-on-error: true + continue-on-error: false env: HARDHAT_CACHE_DIR: ./cache PROVIDER_URL: ${{ secrets.PROVIDER_URL }} From 2f90d782d3df585f52dd50d9ce10d1600880de0e Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Wed, 3 Jul 2024 23:12:55 +1000 Subject: [PATCH 133/273] Continue with fork tests if any fail but still fail the CI job --- .github/workflows/defi.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/defi.yml b/.github/workflows/defi.yml index a2f15bcfd9..6f149249e3 100644 --- a/.github/workflows/defi.yml +++ b/.github/workflows/defi.yml @@ -99,7 +99,6 @@ jobs: strategy: matrix: chunk_id: [0,1,2,3] - continue-on-error: false env: HARDHAT_CACHE_DIR: ./cache PROVIDER_URL: ${{ secrets.PROVIDER_URL }} @@ -130,6 +129,7 @@ jobs: - run: yarn run test:coverage:fork working-directory: ./contracts + continue-on-error: true - uses: actions/upload-artifact@v4 with: From faf9521889f6d48253c51042d4172dd95910444f Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Wed, 3 Jul 2024 23:53:27 +1000 Subject: [PATCH 134/273] increment deploy script number --- .../{100_oeth_withdraw_queue.js => 101_oeth_withdraw_queue.js} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename contracts/deploy/mainnet/{100_oeth_withdraw_queue.js => 101_oeth_withdraw_queue.js} (98%) diff --git a/contracts/deploy/mainnet/100_oeth_withdraw_queue.js b/contracts/deploy/mainnet/101_oeth_withdraw_queue.js similarity index 98% rename from contracts/deploy/mainnet/100_oeth_withdraw_queue.js rename to contracts/deploy/mainnet/101_oeth_withdraw_queue.js index 7923c81ccb..24d8f82f96 100644 --- a/contracts/deploy/mainnet/100_oeth_withdraw_queue.js +++ b/contracts/deploy/mainnet/101_oeth_withdraw_queue.js @@ -5,7 +5,7 @@ const { deploymentWithGovernanceProposal } = require("../../utils/deploy"); module.exports = deploymentWithGovernanceProposal( { - deployName: "100_oeth_withdraw_queue", + deployName: "101_oeth_withdraw_queue", forceDeploy: false, //forceSkip: true, reduceQueueTime: true, From 8094ddd381454e33f38bc2ab0e91d141bea71878 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Thu, 4 Jul 2024 00:06:56 +1000 Subject: [PATCH 135/273] restore Github Actions config --- .github/workflows/defi.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/defi.yml b/.github/workflows/defi.yml index 6f149249e3..a201b5035c 100644 --- a/.github/workflows/defi.yml +++ b/.github/workflows/defi.yml @@ -99,6 +99,7 @@ jobs: strategy: matrix: chunk_id: [0,1,2,3] + continue-on-error: true env: HARDHAT_CACHE_DIR: ./cache PROVIDER_URL: ${{ secrets.PROVIDER_URL }} @@ -129,7 +130,6 @@ jobs: - run: yarn run test:coverage:fork working-directory: ./contracts - continue-on-error: true - uses: actions/upload-artifact@v4 with: From e811fc79e046a7a83b15673b222c39dac433e20a Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Thu, 4 Jul 2024 12:52:42 +1000 Subject: [PATCH 136/273] Updated OETHVaultCore comments --- contracts/contracts/vault/OETHVaultCore.sol | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/contracts/contracts/vault/OETHVaultCore.sol b/contracts/contracts/vault/OETHVaultCore.sol index 6b67cb2594..4539daeb4f 100644 --- a/contracts/contracts/vault/OETHVaultCore.sol +++ b/contracts/contracts/vault/OETHVaultCore.sol @@ -273,6 +273,7 @@ contract OETHVaultCore is VaultCore { /// @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(); @@ -294,8 +295,6 @@ contract OETHVaultCore is VaultCore { if (queueShortfall > 0) { uint256 wethBalance = IERC20(weth).balanceOf(address(this)); - // TODO do we also need to look for WETH in the default strategy? - // Of the claimable withdrawal requests, how much is unclaimed? uint256 unclaimed = queue.claimable - queue.claimed; if (wethBalance > unclaimed) { From 0cd7ac230f8298b6573028481f466919fa2a851c Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Thu, 4 Jul 2024 13:49:53 +1000 Subject: [PATCH 137/273] Upgraded OETH Vault on Holesky to include the withdrawal queue --- .../holesky/015_oeth_withdrawal_queue.js | 58 ++ .../deployments/holesky/.migrations.json | 3 +- .../deployments/holesky/OETHVaultAdmin.json | 515 +++++++++++++--- .../deployments/holesky/OETHVaultCore.json | 561 +++++++++++++++--- .../9b811e7a632431f9f724307daee2b897.json | 344 +++++++++++ 5 files changed, 1331 insertions(+), 150 deletions(-) create mode 100644 contracts/deploy/holesky/015_oeth_withdrawal_queue.js create mode 100644 contracts/deployments/holesky/solcInputs/9b811e7a632431f9f724307daee2b897.json 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/deployments/holesky/.migrations.json b/contracts/deployments/holesky/.migrations.json index 69ffd70ede..5c64f68c24 100644 --- a/contracts/deployments/holesky/.migrations.json +++ b/contracts/deployments/holesky/.migrations.json @@ -12,5 +12,6 @@ "011_upgrade_strategy": 1717309951, "012_upgrade_strategy": 1717477122, "013_upgrade_strategy": 1717803989, - "014_upgrade_strategy": 1717806940 + "014_upgrade_strategy": 1717806940, + "015_oeth_withdrawal_queue": 1720063996 } \ No newline at end of file diff --git a/contracts/deployments/holesky/OETHVaultAdmin.json b/contracts/deployments/holesky/OETHVaultAdmin.json index c58d7d080f..4828a22e3d 100644 --- a/contracts/deployments/holesky/OETHVaultAdmin.json +++ b/contracts/deployments/holesky/OETHVaultAdmin.json @@ -1,6 +1,17 @@ { - "address": "0xa94c4aab0Cf9f6E79bB064DB145fBe2506b9Fa75", + "address": "0x8AAcc620050a399F5829422bD0c45Db1Af90ea37", "abi": [ + { + "inputs": [ + { + "internalType": "address", + "name": "_weth", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, { "anonymous": false, "inputs": [ @@ -58,6 +69,19 @@ "name": "AssetDefaultStrategyUpdated", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_asset", + "type": "address" + } + ], + "name": "AssetRemoved", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -83,6 +107,19 @@ "name": "CapitalUnpaused", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_dripper", + "type": "address" + } + ], + "name": "DripperChanged", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -403,6 +440,81 @@ "name": "VaultBufferUpdated", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_claimable", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_newClaimable", + "type": "uint256" + } + ], + "name": "WithdrawalClaimable", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_withdrawer", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "_requestId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + } + ], + "name": "WithdrawalClaimed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_withdrawer", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "_requestId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_queued", + "type": "uint256" + } + ], + "name": "WithdrawalRequested", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -542,6 +654,19 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [], + "name": "dripper", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "governor", @@ -686,6 +811,19 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "_asset", + "type": "address" + } + ], + "name": "removeAsset", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -743,6 +881,19 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "_dripper", + "type": "address" + } + ], + "name": "setDripper", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -1084,6 +1235,19 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "weth", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "withdrawAllFromStrategies", @@ -1126,45 +1290,109 @@ "outputs": [], "stateMutability": "nonpayable", "type": "function" + }, + { + "inputs": [], + "name": "withdrawalQueueMetadata", + "outputs": [ + { + "internalType": "uint128", + "name": "queued", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "claimable", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "claimed", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "nextWithdrawalIndex", + "type": "uint128" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "withdrawalRequests", + "outputs": [ + { + "internalType": "address", + "name": "withdrawer", + "type": "address" + }, + { + "internalType": "bool", + "name": "claimed", + "type": "bool" + }, + { + "internalType": "uint128", + "name": "amount", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "queued", + "type": "uint128" + } + ], + "stateMutability": "view", + "type": "function" } ], - "transactionHash": "0xe29b0302a257a781d787f590e9502246b3ac3fe2f2d3c39d37d3ac9e856057eb", + "transactionHash": "0xcbe9723c967f2ca8cd45fd0b0d7060699b801811bf5e4d5a07eb76f72e60bc54", "receipt": { "to": null, "from": "0x1b94CA50D3Ad9f8368851F8526132272d1a5028C", - "contractAddress": "0xa94c4aab0Cf9f6E79bB064DB145fBe2506b9Fa75", - "transactionIndex": 39, - "gasUsed": "3146556", - "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000040000010000000000000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000000004000000000000002000000000000000000040000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000010000000000010000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000", - "blockHash": "0x50619ec9fad9061d57a94456471009c7fa5c0cf4d68201956bf36a07a219f708", - "transactionHash": "0xe29b0302a257a781d787f590e9502246b3ac3fe2f2d3c39d37d3ac9e856057eb", + "contractAddress": "0x8AAcc620050a399F5829422bD0c45Db1Af90ea37", + "transactionIndex": 20, + "gasUsed": "3664700", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000008040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000000004000000000000002000000002000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000010000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0xb489f8e204ab36549d803d7e70f4b001e6285d7b51066908f22d01af75b10d1e", + "transactionHash": "0xcbe9723c967f2ca8cd45fd0b0d7060699b801811bf5e4d5a07eb76f72e60bc54", "logs": [ { - "transactionIndex": 39, - "blockNumber": 1405067, - "transactionHash": "0xe29b0302a257a781d787f590e9502246b3ac3fe2f2d3c39d37d3ac9e856057eb", - "address": "0xa94c4aab0Cf9f6E79bB064DB145fBe2506b9Fa75", + "transactionIndex": 20, + "blockNumber": 1860261, + "transactionHash": "0xcbe9723c967f2ca8cd45fd0b0d7060699b801811bf5e4d5a07eb76f72e60bc54", + "address": "0x8AAcc620050a399F5829422bD0c45Db1Af90ea37", "topics": [ "0xc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000001b94ca50d3ad9f8368851f8526132272d1a5028c" ], "data": "0x", - "logIndex": 121, - "blockHash": "0x50619ec9fad9061d57a94456471009c7fa5c0cf4d68201956bf36a07a219f708" + "logIndex": 20, + "blockHash": "0xb489f8e204ab36549d803d7e70f4b001e6285d7b51066908f22d01af75b10d1e" } ], - "blockNumber": 1405067, - "cumulativeGasUsed": "6442389", + "blockNumber": 1860261, + "cumulativeGasUsed": "6071664", "status": 1, "byzantium": true }, - "args": [], - "numDeployments": 1, - "solcInputHash": "da4c2bc4af0be4b969e54f8b43895033", - "metadata": "{\"compiler\":{\"version\":\"0.8.7+commit.e28d00a7\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_threshold\",\"type\":\"uint256\"}],\"name\":\"AllocateThresholdUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_strategy\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"AssetAllocated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_strategy\",\"type\":\"address\"}],\"name\":\"AssetDefaultStrategyUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"}],\"name\":\"AssetSupported\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"CapitalPaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"CapitalUnpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousGovernor\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newGovernor\",\"type\":\"address\"}],\"name\":\"GovernorshipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"maxSupplyDiff\",\"type\":\"uint256\"}],\"name\":\"MaxSupplyDiffChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"Mint\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_threshold\",\"type\":\"uint256\"}],\"name\":\"NetOusdMintForStrategyThresholdChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_ousdMetaStrategy\",\"type\":\"address\"}],\"name\":\"OusdMetaStrategyUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousGovernor\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newGovernor\",\"type\":\"address\"}],\"name\":\"PendingGovernorshipTransfer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_priceProvider\",\"type\":\"address\"}],\"name\":\"PriceProviderUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"RebasePaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_threshold\",\"type\":\"uint256\"}],\"name\":\"RebaseThresholdUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"RebaseUnpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"Redeem\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_redeemFeeBps\",\"type\":\"uint256\"}],\"name\":\"RedeemFeeUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"StrategistUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"}],\"name\":\"StrategyApproved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"}],\"name\":\"StrategyRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_basis\",\"type\":\"uint256\"}],\"name\":\"SwapAllowedUndervalueChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_basis\",\"type\":\"uint256\"}],\"name\":\"SwapSlippageChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_fromAsset\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_toAsset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_fromAssetAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_toAssetAmount\",\"type\":\"uint256\"}],\"name\":\"Swapped\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"SwapperChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"TrusteeAddressChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_basis\",\"type\":\"uint256\"}],\"name\":\"TrusteeFeeBpsChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_vaultBuffer\",\"type\":\"uint256\"}],\"name\":\"VaultBufferUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_yield\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_fee\",\"type\":\"uint256\"}],\"name\":\"YieldDistribution\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"allowedSwapUndervalue\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"}],\"name\":\"approveStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"assetDefaultStrategies\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"autoAllocateThreshold\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"}],\"name\":\"cacheDecimals\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"capitalPaused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"claimGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_strategyToAddress\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"_assets\",\"type\":\"address[]\"},{\"internalType\":\"uint256[]\",\"name\":\"_amounts\",\"type\":\"uint256[]\"}],\"name\":\"depositToStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"governor\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isGovernor\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"maxSupplyDiff\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"netOusdMintForStrategyThreshold\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"netOusdMintedForStrategy\",\"outputs\":[{\"internalType\":\"int256\",\"name\":\"\",\"type\":\"int256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"ousdMetaStrategy\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pauseCapital\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pauseRebase\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"priceProvider\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rebasePaused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rebaseThreshold\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"redeemFeeBps\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"}],\"name\":\"removeStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newImpl\",\"type\":\"address\"}],\"name\":\"setAdminImpl\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_strategy\",\"type\":\"address\"}],\"name\":\"setAssetDefaultStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_threshold\",\"type\":\"uint256\"}],\"name\":\"setAutoAllocateThreshold\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_maxSupplyDiff\",\"type\":\"uint256\"}],\"name\":\"setMaxSupplyDiff\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_threshold\",\"type\":\"uint256\"}],\"name\":\"setNetOusdMintForStrategyThreshold\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"uint16\",\"name\":\"_allowedOracleSlippageBps\",\"type\":\"uint16\"}],\"name\":\"setOracleSlippage\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_ousdMetaStrategy\",\"type\":\"address\"}],\"name\":\"setOusdMetaStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_priceProvider\",\"type\":\"address\"}],\"name\":\"setPriceProvider\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_threshold\",\"type\":\"uint256\"}],\"name\":\"setRebaseThreshold\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_redeemFeeBps\",\"type\":\"uint256\"}],\"name\":\"setRedeemFeeBps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"setStrategistAddr\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"_basis\",\"type\":\"uint16\"}],\"name\":\"setSwapAllowedUndervalue\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_swapperAddr\",\"type\":\"address\"}],\"name\":\"setSwapper\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"setTrusteeAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_basis\",\"type\":\"uint256\"}],\"name\":\"setTrusteeFeeBps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_vaultBuffer\",\"type\":\"uint256\"}],\"name\":\"setVaultBuffer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"strategistAddr\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"_unitConversion\",\"type\":\"uint8\"}],\"name\":\"supportAsset\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_fromAsset\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_toAsset\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_fromAssetAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_minToAssetAmount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"swapCollateral\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"toAssetAmount\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"swapper\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"swapper_\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_newGovernor\",\"type\":\"address\"}],\"name\":\"transferGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"transferToken\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"trusteeAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"trusteeFeeBps\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"unpauseCapital\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"unpauseRebase\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"vaultBuffer\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdrawAllFromStrategies\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_strategyAddr\",\"type\":\"address\"}],\"name\":\"withdrawAllFromStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_strategyFromAddress\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"_assets\",\"type\":\"address[]\"},{\"internalType\":\"uint256[]\",\"name\":\"_amounts\",\"type\":\"uint256[]\"}],\"name\":\"withdrawFromStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"author\":\"Origin Protocol Inc\",\"kind\":\"dev\",\"methods\":{\"allowedSwapUndervalue()\":{\"returns\":{\"value\":\"Percentage in basis points.\"}},\"approveStrategy(address)\":{\"params\":{\"_addr\":\"Address of the strategy to add\"}},\"cacheDecimals(address)\":{\"params\":{\"_asset\":\"Address of asset token\"}},\"depositToStrategy(address,address[],uint256[])\":{\"params\":{\"_amounts\":\"Array of amounts of each corresponding asset to deposit.\",\"_assets\":\"Array of asset address that will be deposited into the strategy.\",\"_strategyToAddress\":\"Address of the Strategy to deposit assets into.\"}},\"removeStrategy(address)\":{\"params\":{\"_addr\":\"Address of the strategy to remove\"}},\"setAdminImpl(address)\":{\"params\":{\"newImpl\":\"address of the implementation\"}},\"setAssetDefaultStrategy(address,address)\":{\"params\":{\"_asset\":\"Address of the asset\",\"_strategy\":\"Address of the Strategy\"}},\"setAutoAllocateThreshold(uint256)\":{\"params\":{\"_threshold\":\"OToken amount with 18 fixed decimals.\"}},\"setNetOusdMintForStrategyThreshold(uint256)\":{\"params\":{\"_threshold\":\"OToken amount with 18 fixed decimals.\"}},\"setOracleSlippage(address,uint16)\":{\"params\":{\"_allowedOracleSlippageBps\":\"allowed slippage from Oracle in basis points. eg 20 = 0.2%. Max 10%.\",\"_asset\":\"Address of the asset token.\"}},\"setOusdMetaStrategy(address)\":{\"params\":{\"_ousdMetaStrategy\":\"Address of OToken metapool strategy\"}},\"setPriceProvider(address)\":{\"params\":{\"_priceProvider\":\"Address of price provider\"}},\"setRebaseThreshold(uint256)\":{\"params\":{\"_threshold\":\"OToken amount with 18 fixed decimals.\"}},\"setRedeemFeeBps(uint256)\":{\"params\":{\"_redeemFeeBps\":\"Basis point fee to be charged\"}},\"setStrategistAddr(address)\":{\"params\":{\"_address\":\"Address of Strategist\"}},\"setSwapAllowedUndervalue(uint16)\":{\"params\":{\"_basis\":\"Percentage in basis points. eg 100 == 1%\"}},\"setSwapper(address)\":{\"params\":{\"_swapperAddr\":\"Address of the Swapper contract that implements the ISwapper interface.\"}},\"setVaultBuffer(uint256)\":{\"params\":{\"_vaultBuffer\":\"Percentage using 18 decimals. 100% = 1e18.\"}},\"supportAsset(address,uint8)\":{\"params\":{\"_asset\":\"Address of asset\"}},\"swapCollateral(address,address,uint256,uint256,bytes)\":{\"params\":{\"_data\":\"implementation specific data. eg 1Inch swap data\",\"_fromAsset\":\"The token address of the asset being sold by the vault.\",\"_fromAssetAmount\":\"The amount of assets being sold by the vault.\",\"_minToAssetAmount\":\"The minimum amount of assets to be purchased.\",\"_toAsset\":\"The token address of the asset being purchased by the vault.\"},\"returns\":{\"toAssetAmount\":\"The amount of toAssets that was received from the swap\"}},\"transferGovernance(address)\":{\"params\":{\"_newGovernor\":\"Address of the new Governor\"}},\"transferToken(address,uint256)\":{\"params\":{\"_amount\":\"Amount of the asset to transfer\",\"_asset\":\"Address for the asset\"}},\"withdrawAllFromStrategy(address)\":{\"params\":{\"_strategyAddr\":\"Strategy address.\"}},\"withdrawFromStrategy(address,address[],uint256[])\":{\"params\":{\"_amounts\":\"Array of amounts of each corresponding asset to withdraw.\",\"_assets\":\"Array of asset address that will be withdrawn from the strategy.\",\"_strategyFromAddress\":\"Address of the Strategy to withdraw assets from.\"}}},\"title\":\"OETH VaultAdmin Contract\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"allowedSwapUndervalue()\":{\"notice\":\"Max allowed percentage the vault total value can drop below the OToken total supply in basis points when executing a collateral swap. For example 100 == 1%\"},\"approveStrategy(address)\":{\"notice\":\"Add a strategy to the Vault.\"},\"assetDefaultStrategies(address)\":{\"notice\":\"Mapping of asset address to the Strategy that they should automatically\"},\"autoAllocateThreshold()\":{\"notice\":\"OToken mints over this amount automatically allocate funds. 18 decimals.\"},\"cacheDecimals(address)\":{\"notice\":\"Cache decimals on OracleRouter for a particular asset. This action is required before that asset's price can be accessed.\"},\"capitalPaused()\":{\"notice\":\"pause operations that change the OToken supply. eg mint, redeem, allocate, mint/burn for strategy\"},\"claimGovernance()\":{\"notice\":\"Claim Governance of the contract to a new account (`newGovernor`). Can only be called by the new Governor.\"},\"depositToStrategy(address,address[],uint256[])\":{\"notice\":\"Deposit multiple assets from the vault into the strategy.\"},\"governor()\":{\"notice\":\"Returns the address of the current Governor.\"},\"isGovernor()\":{\"notice\":\"Returns true if the caller is the current Governor.\"},\"maxSupplyDiff()\":{\"notice\":\"Max difference between total supply and total value of assets. 18 decimals.\"},\"netOusdMintForStrategyThreshold()\":{\"notice\":\"How much net total OTokens are allowed to be minted by all strategies\"},\"netOusdMintedForStrategy()\":{\"notice\":\"How much OTokens are currently minted by the strategy\"},\"ousdMetaStrategy()\":{\"notice\":\"Metapool strategy that is allowed to mint/burn OTokens without changing collateral\"},\"pauseCapital()\":{\"notice\":\"Set the deposit paused flag to true to prevent capital movement.\"},\"pauseRebase()\":{\"notice\":\"Set the deposit paused flag to true to prevent rebasing.\"},\"priceProvider()\":{\"notice\":\"Address of the Oracle price provider contract\"},\"rebasePaused()\":{\"notice\":\"pause rebasing if true\"},\"rebaseThreshold()\":{\"notice\":\"OToken mints over this amount automatically rebase. 18 decimals.\"},\"redeemFeeBps()\":{\"notice\":\"Redemption fee in basis points. eg 50 = 0.5%\"},\"removeStrategy(address)\":{\"notice\":\"Remove a strategy from the Vault.\"},\"setAdminImpl(address)\":{\"notice\":\"set the implementation for the admin, this needs to be in a base class else we cannot set it\"},\"setAssetDefaultStrategy(address,address)\":{\"notice\":\"Set the default Strategy for an asset, i.e. the one which the asset will be automatically allocated to and withdrawn from\"},\"setAutoAllocateThreshold(uint256)\":{\"notice\":\"Sets the minimum amount of OTokens in a mint to trigger an automatic allocation of funds afterwords.\"},\"setMaxSupplyDiff(uint256)\":{\"notice\":\"Sets the maximum allowable difference between total supply and backing assets' value.\"},\"setNetOusdMintForStrategyThreshold(uint256)\":{\"notice\":\"Set maximum amount of OTokens that can at any point be minted and deployed to strategy (used only by ConvexOUSDMetaStrategy for now).\"},\"setOracleSlippage(address,uint16)\":{\"notice\":\"Set the allowed slippage from the Oracle price for collateral asset swaps.\"},\"setOusdMetaStrategy(address)\":{\"notice\":\"Set OToken Metapool strategy\"},\"setPriceProvider(address)\":{\"notice\":\"Set address of price provider.\"},\"setRebaseThreshold(uint256)\":{\"notice\":\"Set a minimum amount of OTokens in a mint or redeem that triggers a rebase\"},\"setRedeemFeeBps(uint256)\":{\"notice\":\"Set a fee in basis points to be charged for a redeem.\"},\"setStrategistAddr(address)\":{\"notice\":\"Set address of Strategist\"},\"setSwapAllowedUndervalue(uint16)\":{\"notice\":\"Set max allowed percentage the vault total value can drop below the OToken total supply in basis points when executing collateral swaps.\"},\"setSwapper(address)\":{\"notice\":\"Set the contract the performs swaps of collateral assets.\"},\"setTrusteeAddress(address)\":{\"notice\":\"Sets the trusteeAddress that can receive a portion of yield. Setting to the zero address disables this feature.\"},\"setTrusteeFeeBps(uint256)\":{\"notice\":\"Sets the TrusteeFeeBps to the percentage of yield that should be received in basis points.\"},\"setVaultBuffer(uint256)\":{\"notice\":\"Set a buffer of assets to keep in the Vault to handle most redemptions without needing to spend gas unwinding assets from a Strategy.\"},\"strategistAddr()\":{\"notice\":\"Address of the Strategist\"},\"supportAsset(address,uint8)\":{\"notice\":\"Add a supported asset to the contract, i.e. one that can be to mint OTokens.\"},\"swapCollateral(address,address,uint256,uint256,bytes)\":{\"notice\":\"Strategist swaps collateral assets sitting in the vault.\"},\"swapper()\":{\"notice\":\"Contract that swaps the vault's collateral assets\"},\"transferGovernance(address)\":{\"notice\":\"Transfers Governance of the contract to a new account (`newGovernor`). Can only be called by the current Governor. Must be claimed for this to complete\"},\"transferToken(address,uint256)\":{\"notice\":\"Transfer token to governor. Intended for recovering tokens stuck in contract, i.e. mistaken sends.\"},\"trusteeAddress()\":{\"notice\":\"Trustee contract that can collect a percentage of yield\"},\"trusteeFeeBps()\":{\"notice\":\"Amount of yield collected in basis points. eg 2000 = 20%\"},\"unpauseCapital()\":{\"notice\":\"Set the deposit paused flag to false to enable capital movement.\"},\"unpauseRebase()\":{\"notice\":\"Set the deposit paused flag to true to allow rebasing.\"},\"vaultBuffer()\":{\"notice\":\"Percentage of assets to keep in Vault to handle (most) withdrawals. 100% = 1e18.\"},\"withdrawAllFromStrategies()\":{\"notice\":\"Withdraws all assets from all the strategies and sends assets to the Vault.\"},\"withdrawAllFromStrategy(address)\":{\"notice\":\"Withdraws all assets from the strategy and sends assets to the Vault.\"},\"withdrawFromStrategy(address,address[],uint256[])\":{\"notice\":\"Withdraw multiple assets from the strategy to the vault.\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/vault/OETHVaultAdmin.sol\":\"OETHVaultAdmin\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `recipient`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address recipient, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `sender` to `recipient` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address sender,\\n address recipient,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0x61437cb513a887a1bbad006e7b1c8b414478427d33de47c5600af3c748f108da\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Address.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize, which returns 0 for contracts in\\n // construction, since the code is only stored at the end of the\\n // constructor execution.\\n\\n uint256 size;\\n assembly {\\n size := extcodesize(account)\\n }\\n return size > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x51b758a8815ecc9596c66c37d56b1d33883a444631a3f916b9fe65cb863ef7c4\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/math/SafeMath.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeMath.sol)\\n\\npragma solidity ^0.8.0;\\n\\n// CAUTION\\n// This version of SafeMath should only be used with Solidity 0.8 or later,\\n// because it relies on the compiler's built in overflow checks.\\n\\n/**\\n * @dev Wrappers over Solidity's arithmetic operations.\\n *\\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\\n * now has built in overflow checking.\\n */\\nlibrary SafeMath {\\n /**\\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n uint256 c = a + b;\\n if (c < a) return (false, 0);\\n return (true, c);\\n }\\n }\\n\\n /**\\n * @dev Returns the substraction of two unsigned integers, with an overflow flag.\\n *\\n * _Available since v3.4._\\n */\\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n if (b > a) return (false, 0);\\n return (true, a - b);\\n }\\n }\\n\\n /**\\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\\n // benefit is lost if 'b' is also tested.\\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\\n if (a == 0) return (true, 0);\\n uint256 c = a * b;\\n if (c / a != b) return (false, 0);\\n return (true, c);\\n }\\n }\\n\\n /**\\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n if (b == 0) return (false, 0);\\n return (true, a / b);\\n }\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n if (b == 0) return (false, 0);\\n return (true, a % b);\\n }\\n }\\n\\n /**\\n * @dev Returns the addition of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `+` operator.\\n *\\n * Requirements:\\n *\\n * - Addition cannot overflow.\\n */\\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a + b;\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting on\\n * overflow (when the result is negative).\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n *\\n * - Subtraction cannot overflow.\\n */\\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a - b;\\n }\\n\\n /**\\n * @dev Returns the multiplication of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `*` operator.\\n *\\n * Requirements:\\n *\\n * - Multiplication cannot overflow.\\n */\\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a * b;\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers, reverting on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator.\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a / b;\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * reverting when dividing by zero.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a % b;\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\\n * overflow (when the result is negative).\\n *\\n * CAUTION: This function is deprecated because it requires allocating memory for the error\\n * message unnecessarily. For custom revert reasons use {trySub}.\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n *\\n * - Subtraction cannot overflow.\\n */\\n function sub(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n unchecked {\\n require(b <= a, errorMessage);\\n return a - b;\\n }\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator. Note: this function uses a\\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\\n * uses an invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function div(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n unchecked {\\n require(b > 0, errorMessage);\\n return a / b;\\n }\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * reverting with custom message when dividing by zero.\\n *\\n * CAUTION: This function is deprecated because it requires allocating memory for the error\\n * message unnecessarily. For custom revert reasons use {tryMod}.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function mod(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n unchecked {\\n require(b > 0, errorMessage);\\n return a % b;\\n }\\n }\\n}\\n\",\"keccak256\":\"0xa2f576be637946f767aa56601c26d717f48a0aff44f82e46f13807eea1009a21\",\"license\":\"MIT\"},\"contracts/governance/Governable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Base for contracts that are managed by the Origin Protocol's Governor.\\n * @dev Copy of the openzeppelin Ownable.sol contract with nomenclature change\\n * from owner to governor and renounce methods removed. Does not use\\n * Context.sol like Ownable.sol does for simplification.\\n * @author Origin Protocol Inc\\n */\\ncontract Governable {\\n // Storage position of the owner and pendingOwner of the contract\\n // keccak256(\\\"OUSD.governor\\\");\\n bytes32 private constant governorPosition =\\n 0x7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a;\\n\\n // keccak256(\\\"OUSD.pending.governor\\\");\\n bytes32 private constant pendingGovernorPosition =\\n 0x44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db;\\n\\n // keccak256(\\\"OUSD.reentry.status\\\");\\n bytes32 private constant reentryStatusPosition =\\n 0x53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac4535;\\n\\n // See OpenZeppelin ReentrancyGuard implementation\\n uint256 constant _NOT_ENTERED = 1;\\n uint256 constant _ENTERED = 2;\\n\\n event PendingGovernorshipTransfer(\\n address indexed previousGovernor,\\n address indexed newGovernor\\n );\\n\\n event GovernorshipTransferred(\\n address indexed previousGovernor,\\n address indexed newGovernor\\n );\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial Governor.\\n */\\n constructor() {\\n _setGovernor(msg.sender);\\n emit GovernorshipTransferred(address(0), _governor());\\n }\\n\\n /**\\n * @notice Returns the address of the current Governor.\\n */\\n function governor() public view returns (address) {\\n return _governor();\\n }\\n\\n /**\\n * @dev Returns the address of the current Governor.\\n */\\n function _governor() internal view returns (address governorOut) {\\n bytes32 position = governorPosition;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n governorOut := sload(position)\\n }\\n }\\n\\n /**\\n * @dev Returns the address of the pending Governor.\\n */\\n function _pendingGovernor()\\n internal\\n view\\n returns (address pendingGovernor)\\n {\\n bytes32 position = pendingGovernorPosition;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n pendingGovernor := sload(position)\\n }\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the Governor.\\n */\\n modifier onlyGovernor() {\\n require(isGovernor(), \\\"Caller is not the Governor\\\");\\n _;\\n }\\n\\n /**\\n * @notice Returns true if the caller is the current Governor.\\n */\\n function isGovernor() public view returns (bool) {\\n return msg.sender == _governor();\\n }\\n\\n function _setGovernor(address newGovernor) internal {\\n bytes32 position = governorPosition;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n sstore(position, newGovernor)\\n }\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a `nonReentrant` function from another `nonReentrant`\\n * function is not supported. It is possible to prevent this from happening\\n * by making the `nonReentrant` function external, and make it call a\\n * `private` function that does the actual work.\\n */\\n modifier nonReentrant() {\\n bytes32 position = reentryStatusPosition;\\n uint256 _reentry_status;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n _reentry_status := sload(position)\\n }\\n\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_reentry_status != _ENTERED, \\\"Reentrant call\\\");\\n\\n // Any calls to nonReentrant after this point will fail\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n sstore(position, _ENTERED)\\n }\\n\\n _;\\n\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n sstore(position, _NOT_ENTERED)\\n }\\n }\\n\\n function _setPendingGovernor(address newGovernor) internal {\\n bytes32 position = pendingGovernorPosition;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n sstore(position, newGovernor)\\n }\\n }\\n\\n /**\\n * @notice Transfers Governance of the contract to a new account (`newGovernor`).\\n * Can only be called by the current Governor. Must be claimed for this to complete\\n * @param _newGovernor Address of the new Governor\\n */\\n function transferGovernance(address _newGovernor) external onlyGovernor {\\n _setPendingGovernor(_newGovernor);\\n emit PendingGovernorshipTransfer(_governor(), _newGovernor);\\n }\\n\\n /**\\n * @notice Claim Governance of the contract to a new account (`newGovernor`).\\n * Can only be called by the new Governor.\\n */\\n function claimGovernance() external {\\n require(\\n msg.sender == _pendingGovernor(),\\n \\\"Only the pending Governor can complete the claim\\\"\\n );\\n _changeGovernor(msg.sender);\\n }\\n\\n /**\\n * @dev Change Governance of the contract to a new account (`newGovernor`).\\n * @param _newGovernor Address of the new Governor\\n */\\n function _changeGovernor(address _newGovernor) internal {\\n require(_newGovernor != address(0), \\\"New Governor is address(0)\\\");\\n emit GovernorshipTransferred(_governor(), _newGovernor);\\n _setGovernor(_newGovernor);\\n }\\n}\\n\",\"keccak256\":\"0xb7133d6ce7a9e673ff79fcedb3fd41ae6e58e251f94915bb65731abe524270b4\",\"license\":\"MIT\"},\"contracts/interfaces/IBasicToken.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IBasicToken {\\n function symbol() external view returns (string memory);\\n\\n function decimals() external view returns (uint8);\\n}\\n\",\"keccak256\":\"0xa562062698aa12572123b36dfd2072f1a39e44fed2031cc19c2c9fd522f96ec2\",\"license\":\"MIT\"},\"contracts/interfaces/IOracle.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IOracle {\\n /**\\n * @dev returns the asset price in USD, in 8 decimal digits.\\n *\\n * The version of priceProvider deployed for OETH has 18 decimal digits\\n */\\n function price(address asset) external view returns (uint256);\\n}\\n\",\"keccak256\":\"0x9eabf152389f145c9c23ed71972af73fb1708cbc4b26e524a9ba29a557b7cfe5\",\"license\":\"MIT\"},\"contracts/interfaces/IStrategy.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Platform interface to integrate with lending platform like Compound, AAVE etc.\\n */\\ninterface IStrategy {\\n /**\\n * @dev Deposit the given asset to platform\\n * @param _asset asset address\\n * @param _amount Amount to deposit\\n */\\n function deposit(address _asset, uint256 _amount) external;\\n\\n /**\\n * @dev Deposit the entire balance of all supported assets in the Strategy\\n * to the platform\\n */\\n function depositAll() external;\\n\\n /**\\n * @dev Withdraw given asset from Lending platform\\n */\\n function withdraw(\\n address _recipient,\\n address _asset,\\n uint256 _amount\\n ) external;\\n\\n /**\\n * @dev Liquidate all assets in strategy and return them to Vault.\\n */\\n function withdrawAll() external;\\n\\n /**\\n * @dev Returns the current balance of the given asset.\\n */\\n function checkBalance(address _asset)\\n external\\n view\\n returns (uint256 balance);\\n\\n /**\\n * @dev Returns bool indicating whether strategy supports asset.\\n */\\n function supportsAsset(address _asset) external view returns (bool);\\n\\n /**\\n * @dev Collect reward tokens from the Strategy.\\n */\\n function collectRewardTokens() external;\\n\\n /**\\n * @dev The address array of the reward tokens for the Strategy.\\n */\\n function getRewardTokenAddresses() external view returns (address[] memory);\\n}\\n\",\"keccak256\":\"0xb291e409a9b95527f9ed19cd6bff8eeb9921a21c1f5194a48c0bb9ce6613959a\",\"license\":\"MIT\"},\"contracts/interfaces/ISwapper.sol\":{\"content\":\"pragma solidity ^0.8.0;\\n\\ninterface ISwapper {\\n /**\\n * @param fromAsset The token address of the asset being sold.\\n * @param toAsset The token address of the asset being purchased.\\n * @param fromAssetAmount The amount of assets being sold.\\n * @param minToAssetAmmount The minimum amount of assets to be purchased.\\n * @param data tx.data returned from 1Inch's /v5.0/1/swap API\\n */\\n function swap(\\n address fromAsset,\\n address toAsset,\\n uint256 fromAssetAmount,\\n uint256 minToAssetAmmount,\\n bytes calldata data\\n ) external returns (uint256 toAssetAmount);\\n}\\n\",\"keccak256\":\"0xf6452c70d5dbfde99e6e82cd6b49d8cbec8efb48da77e28603bea981b8b0759e\"},\"contracts/interfaces/IVault.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport { VaultStorage } from \\\"../vault/VaultStorage.sol\\\";\\n\\ninterface IVault {\\n event AssetSupported(address _asset);\\n event AssetDefaultStrategyUpdated(address _asset, address _strategy);\\n event AssetAllocated(address _asset, address _strategy, uint256 _amount);\\n event StrategyApproved(address _addr);\\n event StrategyRemoved(address _addr);\\n event Mint(address _addr, uint256 _value);\\n event Redeem(address _addr, uint256 _value);\\n event CapitalPaused();\\n event CapitalUnpaused();\\n event RebasePaused();\\n event RebaseUnpaused();\\n event VaultBufferUpdated(uint256 _vaultBuffer);\\n event RedeemFeeUpdated(uint256 _redeemFeeBps);\\n event PriceProviderUpdated(address _priceProvider);\\n event AllocateThresholdUpdated(uint256 _threshold);\\n event RebaseThresholdUpdated(uint256 _threshold);\\n event StrategistUpdated(address _address);\\n event MaxSupplyDiffChanged(uint256 maxSupplyDiff);\\n event YieldDistribution(address _to, uint256 _yield, uint256 _fee);\\n event TrusteeFeeBpsChanged(uint256 _basis);\\n event TrusteeAddressChanged(address _address);\\n event SwapperChanged(address _address);\\n event SwapAllowedUndervalueChanged(uint256 _basis);\\n event SwapSlippageChanged(address _asset, uint256 _basis);\\n event Swapped(\\n address indexed _fromAsset,\\n address indexed _toAsset,\\n uint256 _fromAssetAmount,\\n uint256 _toAssetAmount\\n );\\n\\n // Governable.sol\\n function transferGovernance(address _newGovernor) external;\\n\\n function claimGovernance() external;\\n\\n function governor() external view returns (address);\\n\\n // VaultAdmin.sol\\n function setPriceProvider(address _priceProvider) external;\\n\\n function priceProvider() external view returns (address);\\n\\n function setRedeemFeeBps(uint256 _redeemFeeBps) external;\\n\\n function redeemFeeBps() external view returns (uint256);\\n\\n function setVaultBuffer(uint256 _vaultBuffer) external;\\n\\n function vaultBuffer() external view returns (uint256);\\n\\n function setAutoAllocateThreshold(uint256 _threshold) external;\\n\\n function autoAllocateThreshold() external view returns (uint256);\\n\\n function setRebaseThreshold(uint256 _threshold) external;\\n\\n function rebaseThreshold() external view returns (uint256);\\n\\n function setStrategistAddr(address _address) external;\\n\\n function strategistAddr() external view returns (address);\\n\\n function setMaxSupplyDiff(uint256 _maxSupplyDiff) external;\\n\\n function maxSupplyDiff() external view returns (uint256);\\n\\n function setTrusteeAddress(address _address) external;\\n\\n function trusteeAddress() external view returns (address);\\n\\n function setTrusteeFeeBps(uint256 _basis) external;\\n\\n function trusteeFeeBps() external view returns (uint256);\\n\\n function ousdMetaStrategy() external view returns (address);\\n\\n function setSwapper(address _swapperAddr) external;\\n\\n function setSwapAllowedUndervalue(uint16 _percentageBps) external;\\n\\n function setOracleSlippage(address _asset, uint16 _allowedOracleSlippageBps)\\n external;\\n\\n function supportAsset(address _asset, uint8 _supportsAsset) external;\\n\\n function approveStrategy(address _addr) external;\\n\\n function removeStrategy(address _addr) external;\\n\\n function setAssetDefaultStrategy(address _asset, address _strategy)\\n external;\\n\\n function assetDefaultStrategies(address _asset)\\n external\\n view\\n returns (address);\\n\\n function pauseRebase() external;\\n\\n function unpauseRebase() external;\\n\\n function rebasePaused() external view returns (bool);\\n\\n function pauseCapital() external;\\n\\n function unpauseCapital() external;\\n\\n function capitalPaused() external view returns (bool);\\n\\n function transferToken(address _asset, uint256 _amount) external;\\n\\n function priceUnitMint(address asset) external view returns (uint256);\\n\\n function priceUnitRedeem(address asset) external view returns (uint256);\\n\\n function withdrawAllFromStrategy(address _strategyAddr) external;\\n\\n function withdrawAllFromStrategies() external;\\n\\n function withdrawFromStrategy(\\n address _strategyFromAddress,\\n address[] calldata _assets,\\n uint256[] calldata _amounts\\n ) external;\\n\\n function depositToStrategy(\\n address _strategyToAddress,\\n address[] calldata _assets,\\n uint256[] calldata _amounts\\n ) external;\\n\\n // VaultCore.sol\\n function mint(\\n address _asset,\\n uint256 _amount,\\n uint256 _minimumOusdAmount\\n ) external;\\n\\n function mintForStrategy(uint256 _amount) external;\\n\\n function redeem(uint256 _amount, uint256 _minimumUnitAmount) external;\\n\\n function burnForStrategy(uint256 _amount) external;\\n\\n function redeemAll(uint256 _minimumUnitAmount) external;\\n\\n function allocate() external;\\n\\n function rebase() external;\\n\\n function swapCollateral(\\n address fromAsset,\\n address toAsset,\\n uint256 fromAssetAmount,\\n uint256 minToAssetAmount,\\n bytes calldata data\\n ) external returns (uint256 toAssetAmount);\\n\\n function totalValue() external view returns (uint256 value);\\n\\n function checkBalance(address _asset) external view returns (uint256);\\n\\n function calculateRedeemOutputs(uint256 _amount)\\n external\\n view\\n returns (uint256[] memory);\\n\\n function getAssetCount() external view returns (uint256);\\n\\n function getAssetConfig(address _asset)\\n external\\n view\\n returns (VaultStorage.Asset memory config);\\n\\n function getAllAssets() external view returns (address[] memory);\\n\\n function getStrategyCount() external view returns (uint256);\\n\\n function swapper() external view returns (address);\\n\\n function allowedSwapUndervalue() external view returns (uint256);\\n\\n function getAllStrategies() external view returns (address[] memory);\\n\\n function isSupportedAsset(address _asset) external view returns (bool);\\n\\n function netOusdMintForStrategyThreshold() external view returns (uint256);\\n\\n function setOusdMetaStrategy(address _ousdMetaStrategy) external;\\n\\n function setNetOusdMintForStrategyThreshold(uint256 _threshold) external;\\n\\n function netOusdMintedForStrategy() external view returns (int256);\\n\\n function weth() external view returns (address);\\n\\n function cacheWETHAssetIndex() external;\\n\\n function wethAssetIndex() external view returns (uint256);\\n\\n function initialize(address, address) external;\\n\\n function setAdminImpl(address) external;\\n}\\n\",\"keccak256\":\"0xe8ab2f09127dc86bda14d2ad7f58d4f5ef214959101742f0dd977be3599f9d5f\",\"license\":\"MIT\"},\"contracts/token/OUSD.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title OUSD Token Contract\\n * @dev ERC20 compatible contract for OUSD\\n * @dev Implements an elastic supply\\n * @author Origin Protocol Inc\\n */\\nimport { SafeMath } from \\\"@openzeppelin/contracts/utils/math/SafeMath.sol\\\";\\nimport { Address } from \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\n\\nimport { Initializable } from \\\"../utils/Initializable.sol\\\";\\nimport { InitializableERC20Detailed } from \\\"../utils/InitializableERC20Detailed.sol\\\";\\nimport { StableMath } from \\\"../utils/StableMath.sol\\\";\\nimport { Governable } from \\\"../governance/Governable.sol\\\";\\n\\n/**\\n * NOTE that this is an ERC20 token but the invariant that the sum of\\n * balanceOf(x) for all x is not >= totalSupply(). This is a consequence of the\\n * rebasing design. Any integrations with OUSD should be aware.\\n */\\n\\ncontract OUSD is Initializable, InitializableERC20Detailed, Governable {\\n using SafeMath for uint256;\\n using StableMath for uint256;\\n\\n event TotalSupplyUpdatedHighres(\\n uint256 totalSupply,\\n uint256 rebasingCredits,\\n uint256 rebasingCreditsPerToken\\n );\\n event AccountRebasingEnabled(address account);\\n event AccountRebasingDisabled(address account);\\n\\n enum RebaseOptions {\\n NotSet,\\n OptOut,\\n OptIn\\n }\\n\\n uint256 private constant MAX_SUPPLY = ~uint128(0); // (2^128) - 1\\n uint256 public _totalSupply;\\n mapping(address => mapping(address => uint256)) private _allowances;\\n address public vaultAddress = address(0);\\n mapping(address => uint256) private _creditBalances;\\n uint256 private _rebasingCredits;\\n uint256 private _rebasingCreditsPerToken;\\n // Frozen address/credits are non rebasing (value is held in contracts which\\n // do not receive yield unless they explicitly opt in)\\n uint256 public nonRebasingSupply;\\n mapping(address => uint256) public nonRebasingCreditsPerToken;\\n mapping(address => RebaseOptions) public rebaseState;\\n mapping(address => uint256) public isUpgraded;\\n\\n uint256 private constant RESOLUTION_INCREASE = 1e9;\\n\\n function initialize(\\n string calldata _nameArg,\\n string calldata _symbolArg,\\n address _vaultAddress,\\n uint256 _initialCreditsPerToken\\n ) external onlyGovernor initializer {\\n InitializableERC20Detailed._initialize(_nameArg, _symbolArg, 18);\\n _rebasingCreditsPerToken = _initialCreditsPerToken;\\n vaultAddress = _vaultAddress;\\n }\\n\\n /**\\n * @dev Verifies that the caller is the Vault contract\\n */\\n modifier onlyVault() {\\n require(vaultAddress == msg.sender, \\\"Caller is not the Vault\\\");\\n _;\\n }\\n\\n /**\\n * @return The total supply of OUSD.\\n */\\n function totalSupply() public view override returns (uint256) {\\n return _totalSupply;\\n }\\n\\n /**\\n * @return Low resolution rebasingCreditsPerToken\\n */\\n function rebasingCreditsPerToken() public view returns (uint256) {\\n return _rebasingCreditsPerToken / RESOLUTION_INCREASE;\\n }\\n\\n /**\\n * @return Low resolution total number of rebasing credits\\n */\\n function rebasingCredits() public view returns (uint256) {\\n return _rebasingCredits / RESOLUTION_INCREASE;\\n }\\n\\n /**\\n * @return High resolution rebasingCreditsPerToken\\n */\\n function rebasingCreditsPerTokenHighres() public view returns (uint256) {\\n return _rebasingCreditsPerToken;\\n }\\n\\n /**\\n * @return High resolution total number of rebasing credits\\n */\\n function rebasingCreditsHighres() public view returns (uint256) {\\n return _rebasingCredits;\\n }\\n\\n /**\\n * @dev Gets the balance of the specified address.\\n * @param _account Address to query the balance of.\\n * @return A uint256 representing the amount of base units owned by the\\n * specified address.\\n */\\n function balanceOf(address _account)\\n public\\n view\\n override\\n returns (uint256)\\n {\\n if (_creditBalances[_account] == 0) return 0;\\n return\\n _creditBalances[_account].divPrecisely(_creditsPerToken(_account));\\n }\\n\\n /**\\n * @dev Gets the credits balance of the specified address.\\n * @dev Backwards compatible with old low res credits per token.\\n * @param _account The address to query the balance of.\\n * @return (uint256, uint256) Credit balance and credits per token of the\\n * address\\n */\\n function creditsBalanceOf(address _account)\\n public\\n view\\n returns (uint256, uint256)\\n {\\n uint256 cpt = _creditsPerToken(_account);\\n if (cpt == 1e27) {\\n // For a period before the resolution upgrade, we created all new\\n // contract accounts at high resolution. Since they are not changing\\n // as a result of this upgrade, we will return their true values\\n return (_creditBalances[_account], cpt);\\n } else {\\n return (\\n _creditBalances[_account] / RESOLUTION_INCREASE,\\n cpt / RESOLUTION_INCREASE\\n );\\n }\\n }\\n\\n /**\\n * @dev Gets the credits balance of the specified address.\\n * @param _account The address to query the balance of.\\n * @return (uint256, uint256, bool) Credit balance, credits per token of the\\n * address, and isUpgraded\\n */\\n function creditsBalanceOfHighres(address _account)\\n public\\n view\\n returns (\\n uint256,\\n uint256,\\n bool\\n )\\n {\\n return (\\n _creditBalances[_account],\\n _creditsPerToken(_account),\\n isUpgraded[_account] == 1\\n );\\n }\\n\\n /**\\n * @dev Transfer tokens to a specified address.\\n * @param _to the address to transfer to.\\n * @param _value the amount to be transferred.\\n * @return true on success.\\n */\\n function transfer(address _to, uint256 _value)\\n public\\n override\\n returns (bool)\\n {\\n require(_to != address(0), \\\"Transfer to zero address\\\");\\n require(\\n _value <= balanceOf(msg.sender),\\n \\\"Transfer greater than balance\\\"\\n );\\n\\n _executeTransfer(msg.sender, _to, _value);\\n\\n emit Transfer(msg.sender, _to, _value);\\n\\n return true;\\n }\\n\\n /**\\n * @dev Transfer tokens from one address to another.\\n * @param _from The address you want to send tokens from.\\n * @param _to The address you want to transfer to.\\n * @param _value The amount of tokens to be transferred.\\n */\\n function transferFrom(\\n address _from,\\n address _to,\\n uint256 _value\\n ) public override returns (bool) {\\n require(_to != address(0), \\\"Transfer to zero address\\\");\\n require(_value <= balanceOf(_from), \\\"Transfer greater than balance\\\");\\n\\n _allowances[_from][msg.sender] = _allowances[_from][msg.sender].sub(\\n _value\\n );\\n\\n _executeTransfer(_from, _to, _value);\\n\\n emit Transfer(_from, _to, _value);\\n\\n return true;\\n }\\n\\n /**\\n * @dev Update the count of non rebasing credits in response to a transfer\\n * @param _from The address you want to send tokens from.\\n * @param _to The address you want to transfer to.\\n * @param _value Amount of OUSD to transfer\\n */\\n function _executeTransfer(\\n address _from,\\n address _to,\\n uint256 _value\\n ) internal {\\n bool isNonRebasingTo = _isNonRebasingAccount(_to);\\n bool isNonRebasingFrom = _isNonRebasingAccount(_from);\\n\\n // Credits deducted and credited might be different due to the\\n // differing creditsPerToken used by each account\\n uint256 creditsCredited = _value.mulTruncate(_creditsPerToken(_to));\\n uint256 creditsDeducted = _value.mulTruncate(_creditsPerToken(_from));\\n\\n _creditBalances[_from] = _creditBalances[_from].sub(\\n creditsDeducted,\\n \\\"Transfer amount exceeds balance\\\"\\n );\\n _creditBalances[_to] = _creditBalances[_to].add(creditsCredited);\\n\\n if (isNonRebasingTo && !isNonRebasingFrom) {\\n // Transfer to non-rebasing account from rebasing account, credits\\n // are removed from the non rebasing tally\\n nonRebasingSupply = nonRebasingSupply.add(_value);\\n // Update rebasingCredits by subtracting the deducted amount\\n _rebasingCredits = _rebasingCredits.sub(creditsDeducted);\\n } else if (!isNonRebasingTo && isNonRebasingFrom) {\\n // Transfer to rebasing account from non-rebasing account\\n // Decreasing non-rebasing credits by the amount that was sent\\n nonRebasingSupply = nonRebasingSupply.sub(_value);\\n // Update rebasingCredits by adding the credited amount\\n _rebasingCredits = _rebasingCredits.add(creditsCredited);\\n }\\n }\\n\\n /**\\n * @dev Function to check the amount of tokens that _owner has allowed to\\n * `_spender`.\\n * @param _owner The address which owns the funds.\\n * @param _spender The address which will spend the funds.\\n * @return The number of tokens still available for the _spender.\\n */\\n function allowance(address _owner, address _spender)\\n public\\n view\\n override\\n returns (uint256)\\n {\\n return _allowances[_owner][_spender];\\n }\\n\\n /**\\n * @dev Approve the passed address to spend the specified amount of tokens\\n * on behalf of msg.sender. This method is included for ERC20\\n * compatibility. `increaseAllowance` and `decreaseAllowance` should be\\n * used instead.\\n *\\n * Changing an allowance with this method brings the risk that someone\\n * may transfer both the old and the new allowance - if they are both\\n * greater than zero - if a transfer transaction is mined before the\\n * later approve() call is mined.\\n * @param _spender The address which will spend the funds.\\n * @param _value The amount of tokens to be spent.\\n */\\n function approve(address _spender, uint256 _value)\\n public\\n override\\n returns (bool)\\n {\\n _allowances[msg.sender][_spender] = _value;\\n emit Approval(msg.sender, _spender, _value);\\n return true;\\n }\\n\\n /**\\n * @dev Increase the amount of tokens that an owner has allowed to\\n * `_spender`.\\n * This method should be used instead of approve() to avoid the double\\n * approval vulnerability described above.\\n * @param _spender The address which will spend the funds.\\n * @param _addedValue The amount of tokens to increase the allowance by.\\n */\\n function increaseAllowance(address _spender, uint256 _addedValue)\\n public\\n returns (bool)\\n {\\n _allowances[msg.sender][_spender] = _allowances[msg.sender][_spender]\\n .add(_addedValue);\\n emit Approval(msg.sender, _spender, _allowances[msg.sender][_spender]);\\n return true;\\n }\\n\\n /**\\n * @dev Decrease the amount of tokens that an owner has allowed to\\n `_spender`.\\n * @param _spender The address which will spend the funds.\\n * @param _subtractedValue The amount of tokens to decrease the allowance\\n * by.\\n */\\n function decreaseAllowance(address _spender, uint256 _subtractedValue)\\n public\\n returns (bool)\\n {\\n uint256 oldValue = _allowances[msg.sender][_spender];\\n if (_subtractedValue >= oldValue) {\\n _allowances[msg.sender][_spender] = 0;\\n } else {\\n _allowances[msg.sender][_spender] = oldValue.sub(_subtractedValue);\\n }\\n emit Approval(msg.sender, _spender, _allowances[msg.sender][_spender]);\\n return true;\\n }\\n\\n /**\\n * @dev Mints new tokens, increasing totalSupply.\\n */\\n function mint(address _account, uint256 _amount) external onlyVault {\\n _mint(_account, _amount);\\n }\\n\\n /**\\n * @dev Creates `_amount` tokens and assigns them to `_account`, increasing\\n * the total supply.\\n *\\n * Emits a {Transfer} event with `from` set to the zero address.\\n *\\n * Requirements\\n *\\n * - `to` cannot be the zero address.\\n */\\n function _mint(address _account, uint256 _amount) internal nonReentrant {\\n require(_account != address(0), \\\"Mint to the zero address\\\");\\n\\n bool isNonRebasingAccount = _isNonRebasingAccount(_account);\\n\\n uint256 creditAmount = _amount.mulTruncate(_creditsPerToken(_account));\\n _creditBalances[_account] = _creditBalances[_account].add(creditAmount);\\n\\n // If the account is non rebasing and doesn't have a set creditsPerToken\\n // then set it i.e. this is a mint from a fresh contract\\n if (isNonRebasingAccount) {\\n nonRebasingSupply = nonRebasingSupply.add(_amount);\\n } else {\\n _rebasingCredits = _rebasingCredits.add(creditAmount);\\n }\\n\\n _totalSupply = _totalSupply.add(_amount);\\n\\n require(_totalSupply < MAX_SUPPLY, \\\"Max supply\\\");\\n\\n emit Transfer(address(0), _account, _amount);\\n }\\n\\n /**\\n * @dev Burns tokens, decreasing totalSupply.\\n */\\n function burn(address account, uint256 amount) external onlyVault {\\n _burn(account, amount);\\n }\\n\\n /**\\n * @dev Destroys `_amount` tokens from `_account`, reducing the\\n * total supply.\\n *\\n * Emits a {Transfer} event with `to` set to the zero address.\\n *\\n * Requirements\\n *\\n * - `_account` cannot be the zero address.\\n * - `_account` must have at least `_amount` tokens.\\n */\\n function _burn(address _account, uint256 _amount) internal nonReentrant {\\n require(_account != address(0), \\\"Burn from the zero address\\\");\\n if (_amount == 0) {\\n return;\\n }\\n\\n bool isNonRebasingAccount = _isNonRebasingAccount(_account);\\n uint256 creditAmount = _amount.mulTruncate(_creditsPerToken(_account));\\n uint256 currentCredits = _creditBalances[_account];\\n\\n // Remove the credits, burning rounding errors\\n if (\\n currentCredits == creditAmount || currentCredits - 1 == creditAmount\\n ) {\\n // Handle dust from rounding\\n _creditBalances[_account] = 0;\\n } else if (currentCredits > creditAmount) {\\n _creditBalances[_account] = _creditBalances[_account].sub(\\n creditAmount\\n );\\n } else {\\n revert(\\\"Remove exceeds balance\\\");\\n }\\n\\n // Remove from the credit tallies and non-rebasing supply\\n if (isNonRebasingAccount) {\\n nonRebasingSupply = nonRebasingSupply.sub(_amount);\\n } else {\\n _rebasingCredits = _rebasingCredits.sub(creditAmount);\\n }\\n\\n _totalSupply = _totalSupply.sub(_amount);\\n\\n emit Transfer(_account, address(0), _amount);\\n }\\n\\n /**\\n * @dev Get the credits per token for an account. Returns a fixed amount\\n * if the account is non-rebasing.\\n * @param _account Address of the account.\\n */\\n function _creditsPerToken(address _account)\\n internal\\n view\\n returns (uint256)\\n {\\n if (nonRebasingCreditsPerToken[_account] != 0) {\\n return nonRebasingCreditsPerToken[_account];\\n } else {\\n return _rebasingCreditsPerToken;\\n }\\n }\\n\\n /**\\n * @dev Is an account using rebasing accounting or non-rebasing accounting?\\n * Also, ensure contracts are non-rebasing if they have not opted in.\\n * @param _account Address of the account.\\n */\\n function _isNonRebasingAccount(address _account) internal returns (bool) {\\n bool isContract = Address.isContract(_account);\\n if (isContract && rebaseState[_account] == RebaseOptions.NotSet) {\\n _ensureRebasingMigration(_account);\\n }\\n return nonRebasingCreditsPerToken[_account] > 0;\\n }\\n\\n /**\\n * @dev Ensures internal account for rebasing and non-rebasing credits and\\n * supply is updated following deployment of frozen yield change.\\n */\\n function _ensureRebasingMigration(address _account) internal {\\n if (nonRebasingCreditsPerToken[_account] == 0) {\\n emit AccountRebasingDisabled(_account);\\n if (_creditBalances[_account] == 0) {\\n // Since there is no existing balance, we can directly set to\\n // high resolution, and do not have to do any other bookkeeping\\n nonRebasingCreditsPerToken[_account] = 1e27;\\n } else {\\n // Migrate an existing account:\\n\\n // Set fixed credits per token for this account\\n nonRebasingCreditsPerToken[_account] = _rebasingCreditsPerToken;\\n // Update non rebasing supply\\n nonRebasingSupply = nonRebasingSupply.add(balanceOf(_account));\\n // Update credit tallies\\n _rebasingCredits = _rebasingCredits.sub(\\n _creditBalances[_account]\\n );\\n }\\n }\\n }\\n\\n /**\\n * @notice Enable rebasing for an account.\\n * @dev Add a contract address to the non-rebasing exception list. The\\n * address's balance will be part of rebases and the account will be exposed\\n * to upside and downside.\\n * @param _account Address of the account.\\n */\\n function governanceRebaseOptIn(address _account)\\n public\\n nonReentrant\\n onlyGovernor\\n {\\n _rebaseOptIn(_account);\\n }\\n\\n /**\\n * @dev Add a contract address to the non-rebasing exception list. The\\n * address's balance will be part of rebases and the account will be exposed\\n * to upside and downside.\\n */\\n function rebaseOptIn() public nonReentrant {\\n _rebaseOptIn(msg.sender);\\n }\\n\\n function _rebaseOptIn(address _account) internal {\\n require(_isNonRebasingAccount(_account), \\\"Account has not opted out\\\");\\n\\n // Convert balance into the same amount at the current exchange rate\\n uint256 newCreditBalance = _creditBalances[_account]\\n .mul(_rebasingCreditsPerToken)\\n .div(_creditsPerToken(_account));\\n\\n // Decreasing non rebasing supply\\n nonRebasingSupply = nonRebasingSupply.sub(balanceOf(_account));\\n\\n _creditBalances[_account] = newCreditBalance;\\n\\n // Increase rebasing credits, totalSupply remains unchanged so no\\n // adjustment necessary\\n _rebasingCredits = _rebasingCredits.add(_creditBalances[_account]);\\n\\n rebaseState[_account] = RebaseOptions.OptIn;\\n\\n // Delete any fixed credits per token\\n delete nonRebasingCreditsPerToken[_account];\\n emit AccountRebasingEnabled(_account);\\n }\\n\\n /**\\n * @dev Explicitly mark that an address is non-rebasing.\\n */\\n function rebaseOptOut() public nonReentrant {\\n require(!_isNonRebasingAccount(msg.sender), \\\"Account has not opted in\\\");\\n\\n // Increase non rebasing supply\\n nonRebasingSupply = nonRebasingSupply.add(balanceOf(msg.sender));\\n // Set fixed credits per token\\n nonRebasingCreditsPerToken[msg.sender] = _rebasingCreditsPerToken;\\n\\n // Decrease rebasing credits, total supply remains unchanged so no\\n // adjustment necessary\\n _rebasingCredits = _rebasingCredits.sub(_creditBalances[msg.sender]);\\n\\n // Mark explicitly opted out of rebasing\\n rebaseState[msg.sender] = RebaseOptions.OptOut;\\n emit AccountRebasingDisabled(msg.sender);\\n }\\n\\n /**\\n * @dev Modify the supply without minting new tokens. This uses a change in\\n * the exchange rate between \\\"credits\\\" and OUSD tokens to change balances.\\n * @param _newTotalSupply New total supply of OUSD.\\n */\\n function changeSupply(uint256 _newTotalSupply)\\n external\\n onlyVault\\n nonReentrant\\n {\\n require(_totalSupply > 0, \\\"Cannot increase 0 supply\\\");\\n\\n if (_totalSupply == _newTotalSupply) {\\n emit TotalSupplyUpdatedHighres(\\n _totalSupply,\\n _rebasingCredits,\\n _rebasingCreditsPerToken\\n );\\n return;\\n }\\n\\n _totalSupply = _newTotalSupply > MAX_SUPPLY\\n ? MAX_SUPPLY\\n : _newTotalSupply;\\n\\n _rebasingCreditsPerToken = _rebasingCredits.divPrecisely(\\n _totalSupply.sub(nonRebasingSupply)\\n );\\n\\n require(_rebasingCreditsPerToken > 0, \\\"Invalid change in supply\\\");\\n\\n _totalSupply = _rebasingCredits\\n .divPrecisely(_rebasingCreditsPerToken)\\n .add(nonRebasingSupply);\\n\\n emit TotalSupplyUpdatedHighres(\\n _totalSupply,\\n _rebasingCredits,\\n _rebasingCreditsPerToken\\n );\\n }\\n}\\n\",\"keccak256\":\"0x2dc66b1ba02716d64eb47dd9117fda62650d8b57669e6c351437e0ad29ad5f19\",\"license\":\"MIT\"},\"contracts/utils/Helpers.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport { IBasicToken } from \\\"../interfaces/IBasicToken.sol\\\";\\n\\nlibrary Helpers {\\n /**\\n * @notice Fetch the `symbol()` from an ERC20 token\\n * @dev Grabs the `symbol()` from a contract\\n * @param _token Address of the ERC20 token\\n * @return string Symbol of the ERC20 token\\n */\\n function getSymbol(address _token) internal view returns (string memory) {\\n string memory symbol = IBasicToken(_token).symbol();\\n return symbol;\\n }\\n\\n /**\\n * @notice Fetch the `decimals()` from an ERC20 token\\n * @dev Grabs the `decimals()` from a contract and fails if\\n * the decimal value does not live within a certain range\\n * @param _token Address of the ERC20 token\\n * @return uint256 Decimals of the ERC20 token\\n */\\n function getDecimals(address _token) internal view returns (uint256) {\\n uint256 decimals = IBasicToken(_token).decimals();\\n require(\\n decimals >= 4 && decimals <= 18,\\n \\\"Token must have sufficient decimal places\\\"\\n );\\n\\n return decimals;\\n }\\n}\\n\",\"keccak256\":\"0x108b7a69e0140da0072ca18f90a03a3340574400f81aa6076cd2cccdf13699c2\",\"license\":\"MIT\"},\"contracts/utils/Initializable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Base contract any contracts that need to initialize state after deployment.\\n * @author Origin Protocol Inc\\n */\\nabstract contract Initializable {\\n /**\\n * @dev Indicates that the contract has been initialized.\\n */\\n bool private initialized;\\n\\n /**\\n * @dev Indicates that the contract is in the process of being initialized.\\n */\\n bool private initializing;\\n\\n /**\\n * @dev Modifier to protect an initializer function from being invoked twice.\\n */\\n modifier initializer() {\\n require(\\n initializing || !initialized,\\n \\\"Initializable: contract is already initialized\\\"\\n );\\n\\n bool isTopLevelCall = !initializing;\\n if (isTopLevelCall) {\\n initializing = true;\\n initialized = true;\\n }\\n\\n _;\\n\\n if (isTopLevelCall) {\\n initializing = false;\\n }\\n }\\n\\n uint256[50] private ______gap;\\n}\\n\",\"keccak256\":\"0xaadbcc138114afed4af4f353c2ced2916e6ee14be91434789187f192caf0d786\",\"license\":\"MIT\"},\"contracts/utils/InitializableERC20Detailed.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport { IERC20 } from \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @dev Optional functions from the ERC20 standard.\\n * Converted from openzeppelin/contracts/token/ERC20/ERC20Detailed.sol\\n * @author Origin Protocol Inc\\n */\\nabstract contract InitializableERC20Detailed is IERC20 {\\n // Storage gap to skip storage from prior to OUSD reset\\n uint256[100] private _____gap;\\n\\n string private _name;\\n string private _symbol;\\n uint8 private _decimals;\\n\\n /**\\n * @dev Sets the values for `name`, `symbol`, and `decimals`. All three of\\n * these values are immutable: they can only be set once during\\n * construction.\\n * @notice To avoid variable shadowing appended `Arg` after arguments name.\\n */\\n function _initialize(\\n string memory nameArg,\\n string memory symbolArg,\\n uint8 decimalsArg\\n ) internal {\\n _name = nameArg;\\n _symbol = symbolArg;\\n _decimals = decimalsArg;\\n }\\n\\n /**\\n * @notice Returns the name of the token.\\n */\\n function name() public view returns (string memory) {\\n return _name;\\n }\\n\\n /**\\n * @notice Returns the symbol of the token, usually a shorter version of the\\n * name.\\n */\\n function symbol() public view returns (string memory) {\\n return _symbol;\\n }\\n\\n /**\\n * @notice Returns the number of decimals used to get its user representation.\\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\\n * be displayed to a user as `5,05` (`505 / 10 ** 2`).\\n *\\n * Tokens usually opt for a value of 18, imitating the relationship between\\n * Ether and Wei.\\n *\\n * NOTE: This information is only used for _display_ purposes: it in\\n * no way affects any of the arithmetic of the contract, including\\n * {IERC20-balanceOf} and {IERC20-transfer}.\\n */\\n function decimals() public view returns (uint8) {\\n return _decimals;\\n }\\n}\\n\",\"keccak256\":\"0xe35ac2d813a30d845a3b52bba72588d7e936c2b3f3373d15568c14db46aeed60\",\"license\":\"MIT\"},\"contracts/utils/StableMath.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport { SafeMath } from \\\"@openzeppelin/contracts/utils/math/SafeMath.sol\\\";\\n\\n// Based on StableMath from Stability Labs Pty. Ltd.\\n// https://github.com/mstable/mStable-contracts/blob/master/contracts/shared/StableMath.sol\\n\\nlibrary StableMath {\\n using SafeMath for uint256;\\n\\n /**\\n * @dev Scaling unit for use in specific calculations,\\n * where 1 * 10**18, or 1e18 represents a unit '1'\\n */\\n uint256 private constant FULL_SCALE = 1e18;\\n\\n /***************************************\\n Helpers\\n ****************************************/\\n\\n /**\\n * @dev Adjust the scale of an integer\\n * @param to Decimals to scale to\\n * @param from Decimals to scale from\\n */\\n function scaleBy(\\n uint256 x,\\n uint256 to,\\n uint256 from\\n ) internal pure returns (uint256) {\\n if (to > from) {\\n x = x.mul(10**(to - from));\\n } else if (to < from) {\\n // slither-disable-next-line divide-before-multiply\\n x = x.div(10**(from - to));\\n }\\n return x;\\n }\\n\\n /***************************************\\n Precise Arithmetic\\n ****************************************/\\n\\n /**\\n * @dev Multiplies two precise units, and then truncates by the full scale\\n * @param x Left hand input to multiplication\\n * @param y Right hand input to multiplication\\n * @return Result after multiplying the two inputs and then dividing by the shared\\n * scale unit\\n */\\n function mulTruncate(uint256 x, uint256 y) internal pure returns (uint256) {\\n return mulTruncateScale(x, y, FULL_SCALE);\\n }\\n\\n /**\\n * @dev Multiplies two precise units, and then truncates by the given scale. For example,\\n * when calculating 90% of 10e18, (10e18 * 9e17) / 1e18 = (9e36) / 1e18 = 9e18\\n * @param x Left hand input to multiplication\\n * @param y Right hand input to multiplication\\n * @param scale Scale unit\\n * @return Result after multiplying the two inputs and then dividing by the shared\\n * scale unit\\n */\\n function mulTruncateScale(\\n uint256 x,\\n uint256 y,\\n uint256 scale\\n ) internal pure returns (uint256) {\\n // e.g. assume scale = fullScale\\n // z = 10e18 * 9e17 = 9e36\\n uint256 z = x.mul(y);\\n // return 9e36 / 1e18 = 9e18\\n return z.div(scale);\\n }\\n\\n /**\\n * @dev Multiplies two precise units, and then truncates by the full scale, rounding up the result\\n * @param x Left hand input to multiplication\\n * @param y Right hand input to multiplication\\n * @return Result after multiplying the two inputs and then dividing by the shared\\n * scale unit, rounded up to the closest base unit.\\n */\\n function mulTruncateCeil(uint256 x, uint256 y)\\n internal\\n pure\\n returns (uint256)\\n {\\n // e.g. 8e17 * 17268172638 = 138145381104e17\\n uint256 scaled = x.mul(y);\\n // e.g. 138145381104e17 + 9.99...e17 = 138145381113.99...e17\\n uint256 ceil = scaled.add(FULL_SCALE.sub(1));\\n // e.g. 13814538111.399...e18 / 1e18 = 13814538111\\n return ceil.div(FULL_SCALE);\\n }\\n\\n /**\\n * @dev Precisely divides two units, by first scaling the left hand operand. Useful\\n * for finding percentage weightings, i.e. 8e18/10e18 = 80% (or 8e17)\\n * @param x Left hand input to division\\n * @param y Right hand input to division\\n * @return Result after multiplying the left operand by the scale, and\\n * executing the division on the right hand input.\\n */\\n function divPrecisely(uint256 x, uint256 y)\\n internal\\n pure\\n returns (uint256)\\n {\\n // e.g. 8e18 * 1e18 = 8e36\\n uint256 z = x.mul(FULL_SCALE);\\n // e.g. 8e36 / 10e18 = 8e17\\n return z.div(y);\\n }\\n}\\n\",\"keccak256\":\"0x1eb49f6f79045d9e0a8e1dced8e01d9e559e5fac554dcbb53e43140b601b04e7\",\"license\":\"MIT\"},\"contracts/vault/OETHVaultAdmin.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport { VaultAdmin } from \\\"./VaultAdmin.sol\\\";\\n\\n/**\\n * @title OETH VaultAdmin Contract\\n * @author Origin Protocol Inc\\n */\\ncontract OETHVaultAdmin is VaultAdmin {\\n\\n}\\n\",\"keccak256\":\"0xe6aa33bc5fb6bf1e3b7d3f8f3786ee4991f9a511cdcb858da867f7c81eb6a46a\",\"license\":\"MIT\"},\"contracts/vault/VaultAdmin.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title OToken VaultAdmin contract\\n * @notice The VaultAdmin contract makes configuration and admin calls on the vault.\\n * @author Origin Protocol Inc\\n */\\n\\nimport { SafeERC20 } from \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\n\\nimport { IOracle } from \\\"../interfaces/IOracle.sol\\\";\\nimport { ISwapper } from \\\"../interfaces/ISwapper.sol\\\";\\nimport { IVault } from \\\"../interfaces/IVault.sol\\\";\\nimport { StableMath } from \\\"../utils/StableMath.sol\\\";\\n\\nimport \\\"./VaultStorage.sol\\\";\\n\\ncontract VaultAdmin is VaultStorage {\\n using SafeERC20 for IERC20;\\n using StableMath for uint256;\\n\\n /**\\n * @dev Verifies that the caller is the Governor or Strategist.\\n */\\n modifier onlyGovernorOrStrategist() {\\n require(\\n msg.sender == strategistAddr || isGovernor(),\\n \\\"Caller is not the Strategist or Governor\\\"\\n );\\n _;\\n }\\n\\n /***************************************\\n Configuration\\n ****************************************/\\n\\n /**\\n * @notice Set address of price provider.\\n * @param _priceProvider Address of price provider\\n */\\n function setPriceProvider(address _priceProvider) external onlyGovernor {\\n priceProvider = _priceProvider;\\n emit PriceProviderUpdated(_priceProvider);\\n }\\n\\n /**\\n * @notice Set a fee in basis points to be charged for a redeem.\\n * @param _redeemFeeBps Basis point fee to be charged\\n */\\n function setRedeemFeeBps(uint256 _redeemFeeBps) external onlyGovernor {\\n require(_redeemFeeBps <= 1000, \\\"Redeem fee should not be over 10%\\\");\\n redeemFeeBps = _redeemFeeBps;\\n emit RedeemFeeUpdated(_redeemFeeBps);\\n }\\n\\n /**\\n * @notice Set a buffer of assets to keep in the Vault to handle most\\n * redemptions without needing to spend gas unwinding assets from a Strategy.\\n * @param _vaultBuffer Percentage using 18 decimals. 100% = 1e18.\\n */\\n function setVaultBuffer(uint256 _vaultBuffer)\\n external\\n onlyGovernorOrStrategist\\n {\\n require(_vaultBuffer <= 1e18, \\\"Invalid value\\\");\\n vaultBuffer = _vaultBuffer;\\n emit VaultBufferUpdated(_vaultBuffer);\\n }\\n\\n /**\\n * @notice Sets the minimum amount of OTokens in a mint to trigger an\\n * automatic allocation of funds afterwords.\\n * @param _threshold OToken amount with 18 fixed decimals.\\n */\\n function setAutoAllocateThreshold(uint256 _threshold)\\n external\\n onlyGovernor\\n {\\n autoAllocateThreshold = _threshold;\\n emit AllocateThresholdUpdated(_threshold);\\n }\\n\\n /**\\n * @notice Set a minimum amount of OTokens in a mint or redeem that triggers a\\n * rebase\\n * @param _threshold OToken amount with 18 fixed decimals.\\n */\\n function setRebaseThreshold(uint256 _threshold) external onlyGovernor {\\n rebaseThreshold = _threshold;\\n emit RebaseThresholdUpdated(_threshold);\\n }\\n\\n /**\\n * @notice Set address of Strategist\\n * @param _address Address of Strategist\\n */\\n function setStrategistAddr(address _address) external onlyGovernor {\\n strategistAddr = _address;\\n emit StrategistUpdated(_address);\\n }\\n\\n /**\\n * @notice Set the default Strategy for an asset, i.e. the one which the asset\\n will be automatically allocated to and withdrawn from\\n * @param _asset Address of the asset\\n * @param _strategy Address of the Strategy\\n */\\n function setAssetDefaultStrategy(address _asset, address _strategy)\\n external\\n onlyGovernorOrStrategist\\n {\\n emit AssetDefaultStrategyUpdated(_asset, _strategy);\\n // If its a zero address being passed for the strategy we are removing\\n // the default strategy\\n if (_strategy != address(0)) {\\n // Make sure the strategy meets some criteria\\n require(strategies[_strategy].isSupported, \\\"Strategy not approved\\\");\\n IStrategy strategy = IStrategy(_strategy);\\n require(assets[_asset].isSupported, \\\"Asset is not supported\\\");\\n require(\\n strategy.supportsAsset(_asset),\\n \\\"Asset not supported by Strategy\\\"\\n );\\n }\\n assetDefaultStrategies[_asset] = _strategy;\\n }\\n\\n /**\\n * @notice Set maximum amount of OTokens that can at any point be minted and deployed\\n * to strategy (used only by ConvexOUSDMetaStrategy for now).\\n * @param _threshold OToken amount with 18 fixed decimals.\\n */\\n function setNetOusdMintForStrategyThreshold(uint256 _threshold)\\n external\\n onlyGovernor\\n {\\n /**\\n * Because `netOusdMintedForStrategy` check in vault core works both ways\\n * (positive and negative) the actual impact of the amount of OToken minted\\n * could be double the threshold. E.g.:\\n * - contract has threshold set to 100\\n * - state of netOusdMinted is -90\\n * - in effect it can mint 190 OToken and still be within limits\\n *\\n * We are somewhat mitigating this behaviour by resetting the netOusdMinted\\n * counter whenever new threshold is set. So it can only move one threshold\\n * amount in each direction. This also enables us to reduce the threshold\\n * amount and not have problems with current netOusdMinted being near\\n * limits on either side.\\n */\\n netOusdMintedForStrategy = 0;\\n netOusdMintForStrategyThreshold = _threshold;\\n emit NetOusdMintForStrategyThresholdChanged(_threshold);\\n }\\n\\n /***************************************\\n Swaps\\n ****************************************/\\n\\n /**\\n * @notice Strategist swaps collateral assets sitting in the vault.\\n * @param _fromAsset The token address of the asset being sold by the vault.\\n * @param _toAsset The token address of the asset being purchased by the vault.\\n * @param _fromAssetAmount The amount of assets being sold by the vault.\\n * @param _minToAssetAmount The minimum amount of assets to be purchased.\\n * @param _data implementation specific data. eg 1Inch swap data\\n * @return toAssetAmount The amount of toAssets that was received from the swap\\n */\\n function swapCollateral(\\n address _fromAsset,\\n address _toAsset,\\n uint256 _fromAssetAmount,\\n uint256 _minToAssetAmount,\\n bytes calldata _data\\n )\\n external\\n nonReentrant\\n onlyGovernorOrStrategist\\n returns (uint256 toAssetAmount)\\n {\\n // Check fromAsset and toAsset are valid\\n Asset memory fromAssetConfig = assets[address(_fromAsset)];\\n Asset memory toAssetConfig = assets[_toAsset];\\n require(fromAssetConfig.isSupported, \\\"From asset is not supported\\\");\\n require(toAssetConfig.isSupported, \\\"To asset is not supported\\\");\\n\\n // Load swap config into memory to avoid separate SLOADs\\n SwapConfig memory config = swapConfig;\\n\\n // Scope a new block to remove toAssetBalBefore from the scope of swapCollateral.\\n // This avoids a stack too deep error.\\n {\\n uint256 toAssetBalBefore = IERC20(_toAsset).balanceOf(\\n address(this)\\n );\\n\\n // Transfer from assets to the swapper contract\\n IERC20(_fromAsset).safeTransfer(config.swapper, _fromAssetAmount);\\n\\n // Call to the Swapper contract to do the actual swap\\n // The -1 is required for stETH which sometimes transfers 1 wei less than what was specified.\\n // slither-disable-next-line unused-return\\n ISwapper(config.swapper).swap(\\n _fromAsset,\\n _toAsset,\\n _fromAssetAmount - 1,\\n _minToAssetAmount,\\n _data\\n );\\n\\n // Compute the change in asset balance held by the Vault\\n toAssetAmount =\\n IERC20(_toAsset).balanceOf(address(this)) -\\n toAssetBalBefore;\\n }\\n\\n // Check the to assets returned is above slippage amount specified by the strategist\\n require(\\n toAssetAmount >= _minToAssetAmount,\\n \\\"Strategist slippage limit\\\"\\n );\\n\\n // Scope a new block to remove minOracleToAssetAmount from the scope of swapCollateral.\\n // This avoids a stack too deep error.\\n {\\n // Check the slippage against the Oracle in case the strategist made a mistake or has become malicious.\\n // to asset amount = from asset amount * from asset price / to asset price\\n uint256 minOracleToAssetAmount = (_fromAssetAmount *\\n (1e4 - fromAssetConfig.allowedOracleSlippageBps) *\\n IOracle(priceProvider).price(_fromAsset)) /\\n (IOracle(priceProvider).price(_toAsset) *\\n (1e4 + toAssetConfig.allowedOracleSlippageBps));\\n\\n // Scale both sides up to 18 decimals to compare\\n require(\\n toAssetAmount.scaleBy(18, toAssetConfig.decimals) >=\\n minOracleToAssetAmount.scaleBy(\\n 18,\\n fromAssetConfig.decimals\\n ),\\n \\\"Oracle slippage limit exceeded\\\"\\n );\\n }\\n\\n // Check the vault's total value hasn't gone below the OToken total supply\\n // by more than the allowed percentage.\\n require(\\n IVault(address(this)).totalValue() >=\\n (oUSD.totalSupply() * ((1e4 - config.allowedUndervalueBps))) /\\n 1e4,\\n \\\"Allowed value < supply\\\"\\n );\\n\\n emit Swapped(_fromAsset, _toAsset, _fromAssetAmount, toAssetAmount);\\n }\\n\\n /***************************************\\n Swap Config\\n ****************************************/\\n\\n /**\\n * @notice Set the contract the performs swaps of collateral assets.\\n * @param _swapperAddr Address of the Swapper contract that implements the ISwapper interface.\\n */\\n function setSwapper(address _swapperAddr) external onlyGovernor {\\n swapConfig.swapper = _swapperAddr;\\n emit SwapperChanged(_swapperAddr);\\n }\\n\\n /// @notice Contract that swaps the vault's collateral assets\\n function swapper() external view returns (address swapper_) {\\n swapper_ = swapConfig.swapper;\\n }\\n\\n /**\\n * @notice Set max allowed percentage the vault total value can drop below the OToken total supply in basis points\\n * when executing collateral swaps.\\n * @param _basis Percentage in basis points. eg 100 == 1%\\n */\\n function setSwapAllowedUndervalue(uint16 _basis) external onlyGovernor {\\n require(_basis < 10001, \\\"Invalid basis points\\\");\\n swapConfig.allowedUndervalueBps = _basis;\\n emit SwapAllowedUndervalueChanged(_basis);\\n }\\n\\n /**\\n * @notice Max allowed percentage the vault total value can drop below the OToken total supply in basis points\\n * when executing a collateral swap.\\n * For example 100 == 1%\\n * @return value Percentage in basis points.\\n */\\n function allowedSwapUndervalue() external view returns (uint256 value) {\\n value = swapConfig.allowedUndervalueBps;\\n }\\n\\n /**\\n * @notice Set the allowed slippage from the Oracle price for collateral asset swaps.\\n * @param _asset Address of the asset token.\\n * @param _allowedOracleSlippageBps allowed slippage from Oracle in basis points. eg 20 = 0.2%. Max 10%.\\n */\\n function setOracleSlippage(address _asset, uint16 _allowedOracleSlippageBps)\\n external\\n onlyGovernor\\n {\\n require(assets[_asset].isSupported, \\\"Asset not supported\\\");\\n require(_allowedOracleSlippageBps < 1000, \\\"Slippage too high\\\");\\n\\n assets[_asset].allowedOracleSlippageBps = _allowedOracleSlippageBps;\\n\\n emit SwapSlippageChanged(_asset, _allowedOracleSlippageBps);\\n }\\n\\n /***************************************\\n Asset Config\\n ****************************************/\\n\\n /**\\n * @notice Add a supported asset to the contract, i.e. one that can be\\n * to mint OTokens.\\n * @param _asset Address of asset\\n */\\n function supportAsset(address _asset, uint8 _unitConversion)\\n external\\n onlyGovernor\\n {\\n require(!assets[_asset].isSupported, \\\"Asset already supported\\\");\\n\\n assets[_asset] = Asset({\\n isSupported: true,\\n unitConversion: UnitConversion(_unitConversion),\\n decimals: 0, // will be overridden in _cacheDecimals\\n allowedOracleSlippageBps: 0 // 0% by default\\n });\\n\\n _cacheDecimals(_asset);\\n allAssets.push(_asset);\\n\\n // Verify that our oracle supports the asset\\n // slither-disable-next-line unused-return\\n IOracle(priceProvider).price(_asset);\\n\\n emit AssetSupported(_asset);\\n }\\n\\n /**\\n * @notice Cache decimals on OracleRouter for a particular asset. This action\\n * is required before that asset's price can be accessed.\\n * @param _asset Address of asset token\\n */\\n function cacheDecimals(address _asset) external onlyGovernor {\\n _cacheDecimals(_asset);\\n }\\n\\n /***************************************\\n Strategy Config\\n ****************************************/\\n\\n /**\\n * @notice Add a strategy to the Vault.\\n * @param _addr Address of the strategy to add\\n */\\n function approveStrategy(address _addr) external onlyGovernor {\\n require(!strategies[_addr].isSupported, \\\"Strategy already approved\\\");\\n strategies[_addr] = Strategy({ isSupported: true, _deprecated: 0 });\\n allStrategies.push(_addr);\\n emit StrategyApproved(_addr);\\n }\\n\\n /**\\n * @notice Remove a strategy from the Vault.\\n * @param _addr Address of the strategy to remove\\n */\\n\\n function removeStrategy(address _addr) external onlyGovernor {\\n require(strategies[_addr].isSupported, \\\"Strategy not approved\\\");\\n\\n uint256 assetCount = allAssets.length;\\n for (uint256 i = 0; i < assetCount; ++i) {\\n require(\\n assetDefaultStrategies[allAssets[i]] != _addr,\\n \\\"Strategy is default for an asset\\\"\\n );\\n }\\n\\n // Initialize strategyIndex with out of bounds result so function will\\n // revert if no valid index found\\n uint256 stratCount = allStrategies.length;\\n uint256 strategyIndex = stratCount;\\n for (uint256 i = 0; i < stratCount; ++i) {\\n if (allStrategies[i] == _addr) {\\n strategyIndex = i;\\n break;\\n }\\n }\\n\\n if (strategyIndex < stratCount) {\\n allStrategies[strategyIndex] = allStrategies[stratCount - 1];\\n allStrategies.pop();\\n\\n // Mark the strategy as not supported\\n strategies[_addr].isSupported = false;\\n\\n // Withdraw all assets\\n IStrategy strategy = IStrategy(_addr);\\n strategy.withdrawAll();\\n\\n emit StrategyRemoved(_addr);\\n }\\n }\\n\\n /***************************************\\n Strategies\\n ****************************************/\\n\\n /**\\n * @notice Deposit multiple assets from the vault into the strategy.\\n * @param _strategyToAddress Address of the Strategy to deposit assets into.\\n * @param _assets Array of asset address that will be deposited into the strategy.\\n * @param _amounts Array of amounts of each corresponding asset to deposit.\\n */\\n function depositToStrategy(\\n address _strategyToAddress,\\n address[] calldata _assets,\\n uint256[] calldata _amounts\\n ) external onlyGovernorOrStrategist nonReentrant {\\n _depositToStrategy(_strategyToAddress, _assets, _amounts);\\n }\\n\\n function _depositToStrategy(\\n address _strategyToAddress,\\n address[] calldata _assets,\\n uint256[] calldata _amounts\\n ) internal {\\n require(\\n strategies[_strategyToAddress].isSupported,\\n \\\"Invalid to Strategy\\\"\\n );\\n require(_assets.length == _amounts.length, \\\"Parameter length mismatch\\\");\\n\\n uint256 assetCount = _assets.length;\\n for (uint256 i = 0; i < assetCount; ++i) {\\n address assetAddr = _assets[i];\\n require(\\n IStrategy(_strategyToAddress).supportsAsset(assetAddr),\\n \\\"Asset unsupported\\\"\\n );\\n // Send required amount of funds to the strategy\\n IERC20(assetAddr).safeTransfer(_strategyToAddress, _amounts[i]);\\n }\\n\\n // Deposit all the funds that have been sent to the strategy\\n IStrategy(_strategyToAddress).depositAll();\\n }\\n\\n /**\\n * @notice Withdraw multiple assets from the strategy to the vault.\\n * @param _strategyFromAddress Address of the Strategy to withdraw assets from.\\n * @param _assets Array of asset address that will be withdrawn from the strategy.\\n * @param _amounts Array of amounts of each corresponding asset to withdraw.\\n */\\n function withdrawFromStrategy(\\n address _strategyFromAddress,\\n address[] calldata _assets,\\n uint256[] calldata _amounts\\n ) external onlyGovernorOrStrategist nonReentrant {\\n _withdrawFromStrategy(\\n address(this),\\n _strategyFromAddress,\\n _assets,\\n _amounts\\n );\\n }\\n\\n /**\\n * @param _recipient can either be a strategy or the Vault\\n */\\n function _withdrawFromStrategy(\\n address _recipient,\\n address _strategyFromAddress,\\n address[] calldata _assets,\\n uint256[] calldata _amounts\\n ) internal {\\n require(\\n strategies[_strategyFromAddress].isSupported,\\n \\\"Invalid from Strategy\\\"\\n );\\n require(_assets.length == _amounts.length, \\\"Parameter length mismatch\\\");\\n\\n uint256 assetCount = _assets.length;\\n for (uint256 i = 0; i < assetCount; ++i) {\\n // Withdraw from Strategy to the recipient\\n IStrategy(_strategyFromAddress).withdraw(\\n _recipient,\\n _assets[i],\\n _amounts[i]\\n );\\n }\\n }\\n\\n /**\\n * @notice Sets the maximum allowable difference between\\n * total supply and backing assets' value.\\n */\\n function setMaxSupplyDiff(uint256 _maxSupplyDiff) external onlyGovernor {\\n maxSupplyDiff = _maxSupplyDiff;\\n emit MaxSupplyDiffChanged(_maxSupplyDiff);\\n }\\n\\n /**\\n * @notice Sets the trusteeAddress that can receive a portion of yield.\\n * Setting to the zero address disables this feature.\\n */\\n function setTrusteeAddress(address _address) external onlyGovernor {\\n trusteeAddress = _address;\\n emit TrusteeAddressChanged(_address);\\n }\\n\\n /**\\n * @notice Sets the TrusteeFeeBps to the percentage of yield that should be\\n * received in basis points.\\n */\\n function setTrusteeFeeBps(uint256 _basis) external onlyGovernor {\\n require(_basis <= 5000, \\\"basis cannot exceed 50%\\\");\\n trusteeFeeBps = _basis;\\n emit TrusteeFeeBpsChanged(_basis);\\n }\\n\\n /**\\n * @notice Set OToken Metapool strategy\\n * @param _ousdMetaStrategy Address of OToken metapool strategy\\n */\\n function setOusdMetaStrategy(address _ousdMetaStrategy)\\n external\\n onlyGovernor\\n {\\n ousdMetaStrategy = _ousdMetaStrategy;\\n emit OusdMetaStrategyUpdated(_ousdMetaStrategy);\\n }\\n\\n /***************************************\\n Pause\\n ****************************************/\\n\\n /**\\n * @notice Set the deposit paused flag to true to prevent rebasing.\\n */\\n function pauseRebase() external onlyGovernorOrStrategist {\\n rebasePaused = true;\\n emit RebasePaused();\\n }\\n\\n /**\\n * @notice Set the deposit paused flag to true to allow rebasing.\\n */\\n function unpauseRebase() external onlyGovernorOrStrategist {\\n rebasePaused = false;\\n emit RebaseUnpaused();\\n }\\n\\n /**\\n * @notice Set the deposit paused flag to true to prevent capital movement.\\n */\\n function pauseCapital() external onlyGovernorOrStrategist {\\n capitalPaused = true;\\n emit CapitalPaused();\\n }\\n\\n /**\\n * @notice Set the deposit paused flag to false to enable capital movement.\\n */\\n function unpauseCapital() external onlyGovernorOrStrategist {\\n capitalPaused = false;\\n emit CapitalUnpaused();\\n }\\n\\n /***************************************\\n Utils\\n ****************************************/\\n\\n /**\\n * @notice Transfer token to governor. Intended for recovering tokens stuck in\\n * contract, i.e. mistaken sends.\\n * @param _asset Address for the asset\\n * @param _amount Amount of the asset to transfer\\n */\\n function transferToken(address _asset, uint256 _amount)\\n external\\n onlyGovernor\\n {\\n require(!assets[_asset].isSupported, \\\"Only unsupported assets\\\");\\n IERC20(_asset).safeTransfer(governor(), _amount);\\n }\\n\\n /***************************************\\n Strategies Admin\\n ****************************************/\\n\\n /**\\n * @notice Withdraws all assets from the strategy and sends assets to the Vault.\\n * @param _strategyAddr Strategy address.\\n */\\n function withdrawAllFromStrategy(address _strategyAddr)\\n external\\n onlyGovernorOrStrategist\\n {\\n require(\\n strategies[_strategyAddr].isSupported,\\n \\\"Strategy is not supported\\\"\\n );\\n IStrategy strategy = IStrategy(_strategyAddr);\\n strategy.withdrawAll();\\n }\\n\\n /**\\n * @notice Withdraws all assets from all the strategies and sends assets to the Vault.\\n */\\n function withdrawAllFromStrategies() external onlyGovernorOrStrategist {\\n uint256 stratCount = allStrategies.length;\\n for (uint256 i = 0; i < stratCount; ++i) {\\n IStrategy(allStrategies[i]).withdrawAll();\\n }\\n }\\n\\n /***************************************\\n Utils\\n ****************************************/\\n\\n function _cacheDecimals(address token) internal {\\n Asset storage tokenAsset = assets[token];\\n if (tokenAsset.decimals != 0) {\\n return;\\n }\\n uint8 decimals = IBasicToken(token).decimals();\\n require(decimals >= 6 && decimals <= 18, \\\"Unexpected precision\\\");\\n tokenAsset.decimals = decimals;\\n }\\n}\\n\",\"keccak256\":\"0x597e6301fdcc77fe239b1d8dd7fea534f61b4031016d6035a6027b7dad9412d6\",\"license\":\"MIT\"},\"contracts/vault/VaultStorage.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title OToken VaultStorage contract\\n * @notice The VaultStorage contract defines the storage for the Vault contracts\\n * @author Origin Protocol Inc\\n */\\n\\nimport { IERC20 } from \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport { SafeERC20 } from \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\nimport { Address } from \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\n\\nimport { IStrategy } from \\\"../interfaces/IStrategy.sol\\\";\\nimport { Governable } from \\\"../governance/Governable.sol\\\";\\nimport { OUSD } from \\\"../token/OUSD.sol\\\";\\nimport { Initializable } from \\\"../utils/Initializable.sol\\\";\\nimport \\\"../utils/Helpers.sol\\\";\\n\\ncontract VaultStorage is Initializable, Governable {\\n using SafeERC20 for IERC20;\\n\\n event AssetSupported(address _asset);\\n event AssetDefaultStrategyUpdated(address _asset, address _strategy);\\n event AssetAllocated(address _asset, address _strategy, uint256 _amount);\\n event StrategyApproved(address _addr);\\n event StrategyRemoved(address _addr);\\n event Mint(address _addr, uint256 _value);\\n event Redeem(address _addr, uint256 _value);\\n event CapitalPaused();\\n event CapitalUnpaused();\\n event RebasePaused();\\n event RebaseUnpaused();\\n event VaultBufferUpdated(uint256 _vaultBuffer);\\n event OusdMetaStrategyUpdated(address _ousdMetaStrategy);\\n event RedeemFeeUpdated(uint256 _redeemFeeBps);\\n event PriceProviderUpdated(address _priceProvider);\\n event AllocateThresholdUpdated(uint256 _threshold);\\n event RebaseThresholdUpdated(uint256 _threshold);\\n event StrategistUpdated(address _address);\\n event MaxSupplyDiffChanged(uint256 maxSupplyDiff);\\n event YieldDistribution(address _to, uint256 _yield, uint256 _fee);\\n event TrusteeFeeBpsChanged(uint256 _basis);\\n event TrusteeAddressChanged(address _address);\\n event NetOusdMintForStrategyThresholdChanged(uint256 _threshold);\\n event SwapperChanged(address _address);\\n event SwapAllowedUndervalueChanged(uint256 _basis);\\n event SwapSlippageChanged(address _asset, uint256 _basis);\\n event Swapped(\\n address indexed _fromAsset,\\n address indexed _toAsset,\\n uint256 _fromAssetAmount,\\n uint256 _toAssetAmount\\n );\\n\\n // Assets supported by the Vault, i.e. Stablecoins\\n enum UnitConversion {\\n DECIMALS,\\n GETEXCHANGERATE\\n }\\n // Changed to fit into a single storage slot so the decimals needs to be recached\\n struct Asset {\\n // Note: OETHVaultCore doesn't use `isSupported` when minting,\\n // redeeming or checking balance of assets.\\n bool isSupported;\\n UnitConversion unitConversion;\\n uint8 decimals;\\n // Max allowed slippage from the Oracle price when swapping collateral assets in basis points.\\n // For example 40 == 0.4% slippage\\n uint16 allowedOracleSlippageBps;\\n }\\n\\n /// @dev mapping of supported vault assets to their configuration\\n // slither-disable-next-line uninitialized-state\\n mapping(address => Asset) internal assets;\\n /// @dev list of all assets supported by the vault.\\n // slither-disable-next-line uninitialized-state\\n address[] internal allAssets;\\n\\n // Strategies approved for use by the Vault\\n struct Strategy {\\n bool isSupported;\\n uint256 _deprecated; // Deprecated storage slot\\n }\\n /// @dev mapping of strategy contracts to their configiration\\n mapping(address => Strategy) internal strategies;\\n /// @dev list of all vault strategies\\n address[] internal allStrategies;\\n\\n /// @notice Address of the Oracle price provider contract\\n // slither-disable-next-line uninitialized-state\\n address public priceProvider;\\n /// @notice pause rebasing if true\\n bool public rebasePaused = false;\\n /// @notice pause operations that change the OToken supply.\\n /// eg mint, redeem, allocate, mint/burn for strategy\\n bool public capitalPaused = true;\\n /// @notice Redemption fee in basis points. eg 50 = 0.5%\\n uint256 public redeemFeeBps;\\n /// @notice Percentage of assets to keep in Vault to handle (most) withdrawals. 100% = 1e18.\\n uint256 public vaultBuffer;\\n /// @notice OToken mints over this amount automatically allocate funds. 18 decimals.\\n uint256 public autoAllocateThreshold;\\n /// @notice OToken mints over this amount automatically rebase. 18 decimals.\\n uint256 public rebaseThreshold;\\n\\n /// @dev Address of the OToken token. eg OUSD or OETH.\\n // slither-disable-next-line uninitialized-state\\n OUSD internal oUSD;\\n\\n //keccak256(\\\"OUSD.vault.governor.admin.impl\\\");\\n bytes32 constant adminImplPosition =\\n 0xa2bd3d3cf188a41358c8b401076eb59066b09dec5775650c0de4c55187d17bd9;\\n\\n // Address of the contract responsible for post rebase syncs with AMMs\\n address private _deprecated_rebaseHooksAddr = address(0);\\n\\n // Deprecated: Address of Uniswap\\n // slither-disable-next-line constable-states\\n address private _deprecated_uniswapAddr = address(0);\\n\\n /// @notice Address of the Strategist\\n address public strategistAddr = address(0);\\n\\n /// @notice Mapping of asset address to the Strategy that they should automatically\\n // be allocated to\\n // slither-disable-next-line uninitialized-state\\n mapping(address => address) public assetDefaultStrategies;\\n\\n /// @notice Max difference between total supply and total value of assets. 18 decimals.\\n // slither-disable-next-line uninitialized-state\\n uint256 public maxSupplyDiff;\\n\\n /// @notice Trustee contract that can collect a percentage of yield\\n address public trusteeAddress;\\n\\n /// @notice Amount of yield collected in basis points. eg 2000 = 20%\\n uint256 public trusteeFeeBps;\\n\\n /// @dev Deprecated: Tokens that should be swapped for stablecoins\\n address[] private _deprecated_swapTokens;\\n\\n uint256 constant MINT_MINIMUM_UNIT_PRICE = 0.998e18;\\n\\n /// @notice Metapool strategy that is allowed to mint/burn OTokens without changing collateral\\n address public ousdMetaStrategy = address(0);\\n\\n /// @notice How much OTokens are currently minted by the strategy\\n int256 public netOusdMintedForStrategy = 0;\\n\\n /// @notice How much net total OTokens are allowed to be minted by all strategies\\n uint256 public netOusdMintForStrategyThreshold = 0;\\n\\n uint256 constant MIN_UNIT_PRICE_DRIFT = 0.7e18;\\n uint256 constant MAX_UNIT_PRICE_DRIFT = 1.3e18;\\n\\n /// @notice Collateral swap configuration.\\n /// @dev is packed into a single storage slot to save gas.\\n struct SwapConfig {\\n // Contract that swaps the vault's collateral assets\\n address swapper;\\n // Max allowed percentage the total value can drop below the total supply in basis points.\\n // For example 100 == 1%\\n uint16 allowedUndervalueBps;\\n }\\n SwapConfig internal swapConfig = SwapConfig(address(0), 0);\\n\\n // For future use\\n uint256[50] private __gap;\\n\\n /**\\n * @notice set the implementation for the admin, this needs to be in a base class else we cannot set it\\n * @param newImpl address of the implementation\\n */\\n function setAdminImpl(address newImpl) external onlyGovernor {\\n require(\\n Address.isContract(newImpl),\\n \\\"new implementation is not a contract\\\"\\n );\\n bytes32 position = adminImplPosition;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n sstore(position, newImpl)\\n }\\n }\\n}\\n\",\"keccak256\":\"0xbcefeb5e2b88d99a54dbe6542dc25d0a68eeaf3adfe6e12fb70049cc024b1a79\",\"license\":\"MIT\"}},\"version\":1}", - "bytecode": "0x6037805461ffff60a01b1916600160a81b179055603d80546001600160a01b0319908116909155603e805482169055603f80548216905560458054909116905560006046819055604781905560c0604052608081905260a052604880546001600160b01b03191690553480156200007557600080fd5b506200008e33600080516020620037a983398151915255565b600080516020620037a9833981519152546040516001600160a01b03909116906000907fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a908290a36136c380620000e66000396000f3fe608060405234801561001057600080fd5b50600436106102f15760003560e01c80636c7561e81161019d578063b888879e116100e9578063d38bfff4116100a2578063e6cc54321161007c578063e6cc54321461061d578063e829cc1614610631578063eb03654b14610644578063fc0cfeee1461065757600080fd5b8063d38bfff4146105ee578063d58e3b3a14610601578063e45cc9f01461061457600080fd5b8063b888879e1461059d578063b890ebf6146105b0578063bc90106b146105c3578063c5f00841146105d6578063c7af3352146105de578063c9919112146105e657600080fd5b80638ec489a2116101565780639fa1826e116101305780639fa1826e14610545578063a403e4d51461054e578063ae69f3cb14610577578063b2c9336d1461058a57600080fd5b80638ec489a21461051757806394828ffd1461052a5780639c82f2a41461053257600080fd5b80636c7561e8146104b9578063773540b3146104cc5780637a2202f3146104df5780637b9a7096146104e8578063840c4c7a146104fb5780638e510b521461050e57600080fd5b8063372aa2241161025c57806352d38e5d11610215578063597c8910116101ef578063597c8910146104785780635d36b1901461048b578063636e6c4014610493578063663e64ce146104a657600080fd5b806352d38e5d1461043857806353ca9f2414610441578063570d8e1d1461046557600080fd5b8063372aa224146103d15780633b8ae397146103e45780633dbc911f146103f757806349c1d54d146103ff5780634bed3bc01461041257806350ba711c1461042557600080fd5b806318ce56bd116102ae57806318ce56bd146103755780631edfe3da14610388578063207134b0146103915780632b3297f91461039a5780632da845a8146103ab57806336b6d944146103be57600080fd5b806309f49bf5146102f657806309f6442c146103005780630acbda751461031c5780630c340a241461032f5780631072cbea1461034f578063175188e814610362575b600080fd5b6102fe61066a565b005b61030960385481565b6040519081526020015b60405180910390f35b6102fe61032a366004613292565b6106e3565b610337610795565b6040516001600160a01b039091168152602001610313565b6102fe61035d3660046131f4565b6107b2565b6102fe610370366004613055565b61085f565b604554610337906001600160a01b031681565b61030960395481565b61030960435481565b6048546001600160a01b0316610337565b6102fe6103b9366004613055565b610b60565b6102fe6103cc366004613055565b610bd2565b6102fe6103df366004613055565b610c02565b6102fe6103f2366004613055565b610c74565b6102fe610db1565b604254610337906001600160a01b031681565b604854600160a01b900461ffff16610309565b6103096104333660046130a3565b610e27565b610309603b5481565b60375461045590600160a01b900460ff1681565b6040519015158152602001610313565b603f54610337906001600160a01b031681565b6102fe610486366004613055565b611647565b6102fe611743565b6102fe6104a1366004613292565b6117e9565b6102fe6104b4366004613292565b611847565b6102fe6104c736600461321e565b6118a0565b6102fe6104da366004613055565b611b1e565b61030960475481565b6102fe6104f63660046131ca565b611b90565b6102fe610509366004613149565b611cc6565b61030960415481565b6102fe610525366004613292565b611d5f565b6102fe611e14565b6102fe610540366004613055565b611e84565b610309603a5481565b61033761055c366004613055565b6040602081905260009182529020546001600160a01b031681565b6102fe610585366004613149565b611ef6565b6102fe610598366004613292565b611f84565b603754610337906001600160a01b031681565b6102fe6105be366004613292565b611fdd565b6102fe6105d1366004613070565b612036565b6102fe612278565b6104556122ee565b6102fe61231f565b6102fe6105fc366004613055565b6123e9565b6102fe61060f366004613055565b61248d565b61030960465481565b60375461045590600160a81b900460ff1681565b6102fe61063f366004613277565b6124ff565b6102fe610652366004613292565b6125bf565b6102fe610665366004613055565b612674565b603f546001600160a01b031633148061068657506106866122ee565b6106ab5760405162461bcd60e51b81526004016106a2906133c3565b60405180910390fd5b6037805460ff60a01b191690556040517fbc044409505c95b6b851433df96e1beae715c909d8e7c1d6d7ab783300d4e3b990600090a1565b6106eb6122ee565b6107075760405162461bcd60e51b81526004016106a29061338c565b6113888111156107595760405162461bcd60e51b815260206004820152601760248201527f62617369732063616e6e6f74206578636565642035302500000000000000000060448201526064016106a2565b60438190556040518181527f56287a45051933ea374811b3d5d165033047be5572cac676f7c28b8be4f746c7906020015b60405180910390a150565b60006107ad60008051602061366e8339815191525490565b905090565b6107ba6122ee565b6107d65760405162461bcd60e51b81526004016106a29061338c565b6001600160a01b03821660009081526033602052604090205460ff161561083f5760405162461bcd60e51b815260206004820152601760248201527f4f6e6c7920756e737570706f727465642061737365747300000000000000000060448201526064016106a2565b61085b61084a610795565b6001600160a01b0384169083612716565b5050565b6108676122ee565b6108835760405162461bcd60e51b81526004016106a29061338c565b6001600160a01b03811660009081526035602052604090205460ff166108e35760405162461bcd60e51b815260206004820152601560248201527414dd1c985d1959de481b9bdd08185c1c1c9bdd9959605a1b60448201526064016106a2565b60345460005b8181101561099b57826001600160a01b0316604060006034848154811061091257610912613648565b60009182526020808320909101546001600160a01b03908116845290830193909352604090910190205416141561098b5760405162461bcd60e51b815260206004820181905260248201527f53747261746567792069732064656661756c7420666f7220616e20617373657460448201526064016106a2565b610994816135eb565b90506108e9565b506036548060005b828110156109fb57846001600160a01b0316603682815481106109c8576109c8613648565b6000918252602090912001546001600160a01b031614156109eb578091506109fb565b6109f4816135eb565b90506109a3565b5081811015610b5a576036610a116001846135a8565b81548110610a2157610a21613648565b600091825260209091200154603680546001600160a01b039092169183908110610a4d57610a4d613648565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055506036805480610a8c57610a8c613632565b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b03861680835260359091526040808320805460ff19169055805163429c145b60e11b81529051879363853828b6926004808201939182900301818387803b158015610b0357600080fd5b505af1158015610b17573d6000803e3d6000fd5b50506040516001600160a01b03881681527f09a1db4b80c32706328728508c941a6b954f31eb5affd32f236c1fd405f8fea49250602001905060405180910390a1505b50505050565b610b686122ee565b610b845760405162461bcd60e51b81526004016106a29061338c565b604280546001600160a01b0319166001600160a01b0383169081179091556040519081527f1e4af5ac389e8cde1bdaa6830881b6c987c62a45cfb3b33d27d805cde3b577509060200161078a565b610bda6122ee565b610bf65760405162461bcd60e51b81526004016106a29061338c565b610bff8161276d565b50565b610c0a6122ee565b610c265760405162461bcd60e51b81526004016106a29061338c565b603780546001600160a01b0319166001600160a01b0383169081179091556040519081527fb266add5f3044b17d27db796af992cecbe413921b4e8aaaee03c719e16b9806a9060200161078a565b610c7c6122ee565b610c985760405162461bcd60e51b81526004016106a29061338c565b6001600160a01b03811660009081526035602052604090205460ff1615610d015760405162461bcd60e51b815260206004820152601960248201527f537472617465677920616c726561647920617070726f7665640000000000000060448201526064016106a2565b6040805180820182526001808252600060208084018281526001600160a01b038716808452603583528684209551865460ff19169015151786559051948401949094556036805493840181559091527f4a11f94e20a93c79f6ec743a1954ec4fc2c08429ae2122118bf234b2185c81b890910180546001600160a01b0319168317905591519081527f960dd94cbb79169f09a4e445d58b895df2d9bffa5b31055d0932d801724a20d1910161078a565b603f546001600160a01b0316331480610dcd5750610dcd6122ee565b610de95760405162461bcd60e51b81526004016106a2906133c3565b6037805460ff60a81b1916600160a81b1790556040517f71f0e5b62f846a22e0b4d159e516e62fa9c2b8eb570be15f83e67d98a2ee51e090600090a1565b7f53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac45358054600091906002811415610e6f5760405162461bcd60e51b81526004016106a29061340b565b60028255603f546001600160a01b0316331480610e8f5750610e8f6122ee565b610eab5760405162461bcd60e51b81526004016106a2906133c3565b6001600160a01b0389166000908152603360209081526040808320815160808101909252805460ff808216151584529293919291840191610100909104166001811115610efa57610efa61361c565b6001811115610f0b57610f0b61361c565b8152905462010000810460ff908116602080850191909152630100000090920461ffff166040938401526001600160a01b038d1660009081526033835283812084516080810190955280548084161515865295965090949092840191610100909104166001811115610f7f57610f7f61361c565b6001811115610f9057610f9061361c565b8152905462010000810460ff1660208301526301000000900461ffff1660409091015282519091506110045760405162461bcd60e51b815260206004820152601b60248201527f46726f6d206173736574206973206e6f7420737570706f72746564000000000060448201526064016106a2565b80516110525760405162461bcd60e51b815260206004820152601960248201527f546f206173736574206973206e6f7420737570706f727465640000000000000060448201526064016106a2565b6040805180820182526048546001600160a01b038082168352600160a01b90910461ffff16602083015291516370a0823160e01b81523060048201529091600091908d16906370a082319060240160206040518083038186803b1580156110b857600080fd5b505afa1580156110cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110f091906132ab565b825190915061110a906001600160a01b038f16908d612716565b81600001516001600160a01b0316632506c0188e8e60018f61112c91906135a8565b8e8e8e6040518763ffffffff1660e01b8152600401611150969594939291906132fd565b602060405180830381600087803b15801561116a57600080fd5b505af115801561117e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111a291906132ab565b506040516370a0823160e01b815230600482015281906001600160a01b038e16906370a082319060240160206040518083038186803b1580156111e457600080fd5b505afa1580156111f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061121c91906132ab565b61122691906135a8565b965050888610156112795760405162461bcd60e51b815260206004820152601960248201527f5374726174656769737420736c697070616765206c696d69740000000000000060448201526064016106a2565b6000826060015161271061128d9190613433565b6037546040516315d5220f60e31b81526001600160a01b038f8116600483015261ffff93909316929091169063aea910789060240160206040518083038186803b1580156112da57600080fd5b505afa1580156112ee573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061131291906132ab565b61131c9190613566565b603760009054906101000a90046001600160a01b03166001600160a01b031663aea910788f6040518263ffffffff1660e01b815260040161136c91906001600160a01b0391909116815260200190565b60206040518083038186803b15801561138457600080fd5b505afa158015611398573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113bc91906132ab565b60608601516113cd90612710613585565b6113db9061ffff168e613566565b6113e59190613566565b6113ef9190613459565b905061140e6012856040015160ff16836128839092919063ffffffff16565b604084015161142490899060129060ff16612883565b10156114725760405162461bcd60e51b815260206004820152601e60248201527f4f7261636c6520736c697070616765206c696d6974206578636565646564000060448201526064016106a2565b5061271081602001516127106114889190613585565b61ffff16603c60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b1580156114da57600080fd5b505afa1580156114ee573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061151291906132ab565b61151c9190613566565b6115269190613459565b306001600160a01b031663d4c3eea06040518163ffffffff1660e01b815260040160206040518083038186803b15801561155f57600080fd5b505afa158015611573573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061159791906132ab565b10156115de5760405162461bcd60e51b8152602060048201526016602482015275416c6c6f7765642076616c7565203c20737570706c7960501b60448201526064016106a2565b8a6001600160a01b03168c6001600160a01b03167fa078c4190abe07940190effc1846be0ccf03ad6007bc9e93f9697d0b460befbb8c8960405161162c929190918252602082015260400190565b60405180910390a35050506001825550509695505050505050565b603f546001600160a01b031633148061166357506116636122ee565b61167f5760405162461bcd60e51b81526004016106a2906133c3565b6001600160a01b03811660009081526035602052604090205460ff166116e75760405162461bcd60e51b815260206004820152601960248201527f5374726174656779206973206e6f7420737570706f727465640000000000000060448201526064016106a2565b6000819050806001600160a01b031663853828b66040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561172757600080fd5b505af115801561173b573d6000803e3d6000fd5b505050505050565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b0316146117de5760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b60648201526084016106a2565b6117e7336128e7565b565b6117f16122ee565b61180d5760405162461bcd60e51b81526004016106a29061338c565b600060465560478190556040518181527fc29d6fedbc6bdf267a08166c2b976fbd72aca5d6a769528616f8b9224c8f197f9060200161078a565b61184f6122ee565b61186b5760405162461bcd60e51b81526004016106a29061338c565b60418190556040518181527f95201f9c21f26877223b1ff4073936a6484c35495649e60e55730497aeb60d939060200161078a565b6118a86122ee565b6118c45760405162461bcd60e51b81526004016106a29061338c565b6001600160a01b03821660009081526033602052604090205460ff161561192d5760405162461bcd60e51b815260206004820152601760248201527f417373657420616c726561647920737570706f7274656400000000000000000060448201526064016106a2565b60405180608001604052806001151581526020018260ff1660018111156119565761195661361c565b60018111156119675761196761361c565b81526000602080830182905260409283018290526001600160a01b0386168252603381529190208251815490151560ff19821681178355928401519192839161ff001990911661ffff19909116176101008360018111156119ca576119ca61361c565b02179055506040820151815460609093015161ffff1663010000000264ffff0000001960ff90921662010000029190911664ffffff00001990931692909217919091179055611a188261276d565b603480546001810182556000919091527f46bddb1178e94d7f2892ff5f366840eb658911794f2c3a44c450aa2c505186c10180546001600160a01b0319166001600160a01b038481169182179092556037546040516315d5220f60e31b815260048101929092529091169063aea910789060240160206040518083038186803b158015611aa457600080fd5b505afa158015611ab8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611adc91906132ab565b506040516001600160a01b03831681527f4f1ac48525e50059cc1cc6e0e1940ece0dd653a4db4841538d6aef036be2fb7b906020015b60405180910390a15050565b611b266122ee565b611b425760405162461bcd60e51b81526004016106a29061338c565b603f80546001600160a01b0319166001600160a01b0383169081179091556040519081527f869e0abd13cc3a975de7b93be3df1cb2255c802b1cead85963cc79d99f131bee9060200161078a565b611b986122ee565b611bb45760405162461bcd60e51b81526004016106a29061338c565b6001600160a01b03821660009081526033602052604090205460ff16611c125760405162461bcd60e51b8152602060048201526013602482015272105cdcd95d081b9bdd081cdd5c1c1bdc9d1959606a1b60448201526064016106a2565b6103e88161ffff1610611c5b5760405162461bcd60e51b81526020600482015260116024820152700a6d8d2e0e0c2ceca40e8dede40d0d2ced607b1b60448201526064016106a2565b6001600160a01b038216600081815260336020908152604091829020805464ffff0000001916630100000061ffff8716908102919091179091558251938452908301527f8d22e9d2cbe8bb65a3c4412bd8970743864512a1a0e004e8d00fb96277b78b949101611b12565b603f546001600160a01b0316331480611ce25750611ce26122ee565b611cfe5760405162461bcd60e51b81526004016106a2906133c3565b7f53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac453580546002811415611d425760405162461bcd60e51b81526004016106a29061340b565b60028255611d5387878787876129a8565b50600190555050505050565b603f546001600160a01b0316331480611d7b5750611d7b6122ee565b611d975760405162461bcd60e51b81526004016106a2906133c3565b670de0b6b3a7640000811115611ddf5760405162461bcd60e51b815260206004820152600d60248201526c496e76616c69642076616c756560981b60448201526064016106a2565b60398190556040518181527f41ecb23a0e7865b25f38c268b7c3012220d822929e9edff07326e89d5bb822b59060200161078a565b603f546001600160a01b0316331480611e305750611e306122ee565b611e4c5760405162461bcd60e51b81526004016106a2906133c3565b6037805460ff60a81b191690556040517f891ebab18da80ebeeea06b1b1cede098329c4c008906a98370c2ac7a80b571cb90600090a1565b611e8c6122ee565b611ea85760405162461bcd60e51b81526004016106a29061338c565b604880546001600160a01b0319166001600160a01b0383169081179091556040519081527f7d7719313229e558c5a3893cad2eb86a86a049156d1d9ebd5c63a8eedefd1c039060200161078a565b603f546001600160a01b0316331480611f125750611f126122ee565b611f2e5760405162461bcd60e51b81526004016106a2906133c3565b7f53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac453580546002811415611f725760405162461bcd60e51b81526004016106a29061340b565b60028255611d53308888888888612be6565b611f8c6122ee565b611fa85760405162461bcd60e51b81526004016106a29061338c565b603a8190556040518181527f2ec5fb5a3d2703edc461252d92ccd2799c3c74f01d97212b20388207fa17ae459060200161078a565b611fe56122ee565b6120015760405162461bcd60e51b81526004016106a29061338c565b603b8190556040518181527f39367850377ac04920a9a670f2180e7a94d83b15ad302e59875ec58fd10bd37d9060200161078a565b603f546001600160a01b031633148061205257506120526122ee565b61206e5760405162461bcd60e51b81526004016106a2906133c3565b604080516001600160a01b038085168252831660208201527fba58ce12801c949fa65f41c46ed108671c219baf945fa48d21026cea99ff252a910160405180910390a16001600160a01b0381161561224a576001600160a01b03811660009081526035602052604090205460ff166121205760405162461bcd60e51b815260206004820152601560248201527414dd1c985d1959de481b9bdd08185c1c1c9bdd9959605a1b60448201526064016106a2565b6001600160a01b038216600090815260336020526040902054819060ff166121835760405162461bcd60e51b8152602060048201526016602482015275105cdcd95d081a5cc81b9bdd081cdd5c1c1bdc9d195960521b60448201526064016106a2565b60405163551c457b60e11b81526001600160a01b03848116600483015282169063aa388af69060240160206040518083038186803b1580156121c457600080fd5b505afa1580156121d8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121fc9190613255565b6122485760405162461bcd60e51b815260206004820152601f60248201527f4173736574206e6f7420737570706f727465642062792053747261746567790060448201526064016106a2565b505b6001600160a01b03918216600090815260406020819052902080546001600160a01b03191691909216179055565b603f546001600160a01b031633148061229457506122946122ee565b6122b05760405162461bcd60e51b81526004016106a2906133c3565b6037805460ff60a01b1916600160a01b1790556040517f8cff26a5985614b3d30629cc4ab83824bf115aec971b718d8f2f99562032e97290600090a1565b600061230660008051602061366e8339815191525490565b6001600160a01b0316336001600160a01b031614905090565b603f546001600160a01b031633148061233b575061233b6122ee565b6123575760405162461bcd60e51b81526004016106a2906133c3565b60365460005b8181101561085b576036818154811061237857612378613648565b60009182526020822001546040805163429c145b60e11b815290516001600160a01b039092169263853828b69260048084019382900301818387803b1580156123c057600080fd5b505af11580156123d4573d6000803e3d6000fd5b50505050806123e2906135eb565b905061235d565b6123f16122ee565b61240d5760405162461bcd60e51b81526004016106a29061338c565b612435817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b031661245560008051602061366e8339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b6124956122ee565b6124b15760405162461bcd60e51b81526004016106a29061338c565b604580546001600160a01b0319166001600160a01b0383169081179091556040519081527fa12850fb726e0b2b7b3c9a9342031e1268a8148d0eb06b4bea8613204ffcd2b89060200161078a565b6125076122ee565b6125235760405162461bcd60e51b81526004016106a29061338c565b6127118161ffff161061256f5760405162461bcd60e51b8152602060048201526014602482015273496e76616c696420626173697320706f696e747360601b60448201526064016106a2565b6048805461ffff60a01b1916600160a01b61ffff8416908102919091179091556040519081527ff12c00256bee2b6facb111a88a9b1cff86e79132939b44f1353212d6f74695579060200161078a565b6125c76122ee565b6125e35760405162461bcd60e51b81526004016106a29061338c565b6103e881111561263f5760405162461bcd60e51b815260206004820152602160248201527f52656465656d206665652073686f756c64206e6f74206265206f7665722031306044820152602560f81b60648201526084016106a2565b60388190556040518181527fd6c7508d6658ccee36b7b7d7fd72e5cbaeefb40c64eff24e9ae7470e846304ee9060200161078a565b61267c6122ee565b6126985760405162461bcd60e51b81526004016106a29061338c565b803b6126f25760405162461bcd60e51b8152602060048201526024808201527f6e657720696d706c656d656e746174696f6e206973206e6f74206120636f6e746044820152631c9858dd60e21b60648201526084016106a2565b7fa2bd3d3cf188a41358c8b401076eb59066b09dec5775650c0de4c55187d17bd955565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052612768908490612d70565b505050565b6001600160a01b0381166000908152603360205260409020805462010000900460ff1615612799575050565b6000826001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b1580156127d457600080fd5b505afa1580156127e8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061280c91906132c4565b905060068160ff1610158015612826575060128160ff1611155b6128695760405162461bcd60e51b81526020600482015260146024820152732ab732bc3832b1ba32b210383932b1b4b9b4b7b760611b60448201526064016106a2565b815460ff909116620100000262ff00001990911617905550565b6000818311156128b3576128ac61289a83856135a8565b6128a590600a6134be565b8590612e42565b93506128dd565b818310156128dd576128da6128c884846135a8565b6128d390600a6134be565b8590612e57565b93505b50825b9392505050565b6001600160a01b03811661293d5760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f72206973206164647265737328302900000000000060448201526064016106a2565b806001600160a01b031661295d60008051602061366e8339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a3610bff8160008051602061366e83398151915255565b6001600160a01b03851660009081526035602052604090205460ff16612a065760405162461bcd60e51b8152602060048201526013602482015272496e76616c696420746f20537472617465677960681b60448201526064016106a2565b828114612a515760405162461bcd60e51b81526020600482015260196024820152780a0c2e4c2dacae8cae440d8cadccee8d040dad2e6dac2e8c6d603b1b60448201526064016106a2565b8260005b81811015612b8a576000868683818110612a7157612a71613648565b9050602002016020810190612a869190613055565b60405163551c457b60e11b81526001600160a01b0380831660048301529192509089169063aa388af69060240160206040518083038186803b158015612acb57600080fd5b505afa158015612adf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b039190613255565b612b435760405162461bcd60e51b8152602060048201526011602482015270105cdcd95d081d5b9cdd5c1c1bdc9d1959607a1b60448201526064016106a2565b612b7988868685818110612b5957612b59613648565b90506020020135836001600160a01b03166127169092919063ffffffff16565b50612b83816135eb565b9050612a55565b50856001600160a01b031663de5f62686040518163ffffffff1660e01b8152600401600060405180830381600087803b158015612bc657600080fd5b505af1158015612bda573d6000803e3d6000fd5b50505050505050505050565b6001600160a01b03851660009081526035602052604090205460ff16612c465760405162461bcd60e51b8152602060048201526015602482015274496e76616c69642066726f6d20537472617465677960581b60448201526064016106a2565b828114612c915760405162461bcd60e51b81526020600482015260196024820152780a0c2e4c2dacae8cae440d8cadccee8d040dad2e6dac2e8c6d603b1b60448201526064016106a2565b8260005b81811015612d6657866001600160a01b031663d9caed1289888885818110612cbf57612cbf613648565b9050602002016020810190612cd49190613055565b878786818110612ce657612ce6613648565b6040516001600160e01b031960e088901b1681526001600160a01b03958616600482015294909316602485015250602090910201356044820152606401600060405180830381600087803b158015612d3d57600080fd5b505af1158015612d51573d6000803e3d6000fd5b5050505080612d5f906135eb565b9050612c95565b5050505050505050565b6000612dc5826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316612e639092919063ffffffff16565b8051909150156127685780806020019051810190612de39190613255565b6127685760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016106a2565b6000612e4e8284613566565b90505b92915050565b6000612e4e8284613459565b6060612e728484600085612e7a565b949350505050565b606082471015612edb5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016106a2565b843b612f295760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016106a2565b600080866001600160a01b03168587604051612f4591906132e1565b60006040518083038185875af1925050503d8060008114612f82576040519150601f19603f3d011682016040523d82523d6000602084013e612f87565b606091505b5091509150612f97828286612fa2565b979650505050505050565b60608315612fb15750816128e0565b825115612fc15782518084602001fd5b8160405162461bcd60e51b81526004016106a29190613359565b80356001600160a01b0381168114612ff257600080fd5b919050565b60008083601f84011261300957600080fd5b50813567ffffffffffffffff81111561302157600080fd5b6020830191508360208260051b850101111561303c57600080fd5b9250929050565b803561ffff81168114612ff257600080fd5b60006020828403121561306757600080fd5b612e4e82612fdb565b6000806040838503121561308357600080fd5b61308c83612fdb565b915061309a60208401612fdb565b90509250929050565b60008060008060008060a087890312156130bc57600080fd5b6130c587612fdb565b95506130d360208801612fdb565b94506040870135935060608701359250608087013567ffffffffffffffff808211156130fe57600080fd5b818901915089601f83011261311257600080fd5b81358181111561312157600080fd5b8a602082850101111561313357600080fd5b6020830194508093505050509295509295509295565b60008060008060006060868803121561316157600080fd5b61316a86612fdb565b9450602086013567ffffffffffffffff8082111561318757600080fd5b61319389838a01612ff7565b909650945060408801359150808211156131ac57600080fd5b506131b988828901612ff7565b969995985093965092949392505050565b600080604083850312156131dd57600080fd5b6131e683612fdb565b915061309a60208401613043565b6000806040838503121561320757600080fd5b61321083612fdb565b946020939093013593505050565b6000806040838503121561323157600080fd5b61323a83612fdb565b9150602083013561324a8161365e565b809150509250929050565b60006020828403121561326757600080fd5b815180151581146128e057600080fd5b60006020828403121561328957600080fd5b612e4e82613043565b6000602082840312156132a457600080fd5b5035919050565b6000602082840312156132bd57600080fd5b5051919050565b6000602082840312156132d657600080fd5b81516128e08161365e565b600082516132f38184602087016135bf565b9190910192915050565b6001600160a01b03878116825286166020820152604081018590526060810184905260a06080820181905281018290526000828460c0840137600060c0848401015260c0601f19601f8501168301019050979650505050505050565b60208152600082518060208401526133788160408501602087016135bf565b601f01601f19169190910160400192915050565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b60208082526028908201527f43616c6c6572206973206e6f74207468652053747261746567697374206f722060408201526723b7bb32b93737b960c11b606082015260800190565b6020808252600e908201526d1499595b9d1c985b9d0818d85b1b60921b604082015260600190565b600061ffff80831681851680830382111561345057613450613606565b01949350505050565b60008261347657634e487b7160e01b600052601260045260246000fd5b500490565b600181815b808511156134b657816000190482111561349c5761349c613606565b808516156134a957918102915b93841c9390800290613480565b509250929050565b6000612e4e83836000826134d457506001612e51565b816134e157506000612e51565b81600181146134f757600281146135015761351d565b6001915050612e51565b60ff84111561351257613512613606565b50506001821b612e51565b5060208310610133831016604e8410600b8410161715613540575081810a612e51565b61354a838361347b565b806000190482111561355e5761355e613606565b029392505050565b600081600019048311821515161561358057613580613606565b500290565b600061ffff838116908316818110156135a0576135a0613606565b039392505050565b6000828210156135ba576135ba613606565b500390565b60005b838110156135da5781810151838201526020016135c2565b83811115610b5a5750506000910152565b60006000198214156135ff576135ff613606565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b60ff81168114610bff57600080fdfe7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa2646970667358221220856c9fec2e98e8d950cc7553495c5c13452851bc0b706e1a29005d23345bcb1364736f6c634300080700337bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a", - "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106102f15760003560e01c80636c7561e81161019d578063b888879e116100e9578063d38bfff4116100a2578063e6cc54321161007c578063e6cc54321461061d578063e829cc1614610631578063eb03654b14610644578063fc0cfeee1461065757600080fd5b8063d38bfff4146105ee578063d58e3b3a14610601578063e45cc9f01461061457600080fd5b8063b888879e1461059d578063b890ebf6146105b0578063bc90106b146105c3578063c5f00841146105d6578063c7af3352146105de578063c9919112146105e657600080fd5b80638ec489a2116101565780639fa1826e116101305780639fa1826e14610545578063a403e4d51461054e578063ae69f3cb14610577578063b2c9336d1461058a57600080fd5b80638ec489a21461051757806394828ffd1461052a5780639c82f2a41461053257600080fd5b80636c7561e8146104b9578063773540b3146104cc5780637a2202f3146104df5780637b9a7096146104e8578063840c4c7a146104fb5780638e510b521461050e57600080fd5b8063372aa2241161025c57806352d38e5d11610215578063597c8910116101ef578063597c8910146104785780635d36b1901461048b578063636e6c4014610493578063663e64ce146104a657600080fd5b806352d38e5d1461043857806353ca9f2414610441578063570d8e1d1461046557600080fd5b8063372aa224146103d15780633b8ae397146103e45780633dbc911f146103f757806349c1d54d146103ff5780634bed3bc01461041257806350ba711c1461042557600080fd5b806318ce56bd116102ae57806318ce56bd146103755780631edfe3da14610388578063207134b0146103915780632b3297f91461039a5780632da845a8146103ab57806336b6d944146103be57600080fd5b806309f49bf5146102f657806309f6442c146103005780630acbda751461031c5780630c340a241461032f5780631072cbea1461034f578063175188e814610362575b600080fd5b6102fe61066a565b005b61030960385481565b6040519081526020015b60405180910390f35b6102fe61032a366004613292565b6106e3565b610337610795565b6040516001600160a01b039091168152602001610313565b6102fe61035d3660046131f4565b6107b2565b6102fe610370366004613055565b61085f565b604554610337906001600160a01b031681565b61030960395481565b61030960435481565b6048546001600160a01b0316610337565b6102fe6103b9366004613055565b610b60565b6102fe6103cc366004613055565b610bd2565b6102fe6103df366004613055565b610c02565b6102fe6103f2366004613055565b610c74565b6102fe610db1565b604254610337906001600160a01b031681565b604854600160a01b900461ffff16610309565b6103096104333660046130a3565b610e27565b610309603b5481565b60375461045590600160a01b900460ff1681565b6040519015158152602001610313565b603f54610337906001600160a01b031681565b6102fe610486366004613055565b611647565b6102fe611743565b6102fe6104a1366004613292565b6117e9565b6102fe6104b4366004613292565b611847565b6102fe6104c736600461321e565b6118a0565b6102fe6104da366004613055565b611b1e565b61030960475481565b6102fe6104f63660046131ca565b611b90565b6102fe610509366004613149565b611cc6565b61030960415481565b6102fe610525366004613292565b611d5f565b6102fe611e14565b6102fe610540366004613055565b611e84565b610309603a5481565b61033761055c366004613055565b6040602081905260009182529020546001600160a01b031681565b6102fe610585366004613149565b611ef6565b6102fe610598366004613292565b611f84565b603754610337906001600160a01b031681565b6102fe6105be366004613292565b611fdd565b6102fe6105d1366004613070565b612036565b6102fe612278565b6104556122ee565b6102fe61231f565b6102fe6105fc366004613055565b6123e9565b6102fe61060f366004613055565b61248d565b61030960465481565b60375461045590600160a81b900460ff1681565b6102fe61063f366004613277565b6124ff565b6102fe610652366004613292565b6125bf565b6102fe610665366004613055565b612674565b603f546001600160a01b031633148061068657506106866122ee565b6106ab5760405162461bcd60e51b81526004016106a2906133c3565b60405180910390fd5b6037805460ff60a01b191690556040517fbc044409505c95b6b851433df96e1beae715c909d8e7c1d6d7ab783300d4e3b990600090a1565b6106eb6122ee565b6107075760405162461bcd60e51b81526004016106a29061338c565b6113888111156107595760405162461bcd60e51b815260206004820152601760248201527f62617369732063616e6e6f74206578636565642035302500000000000000000060448201526064016106a2565b60438190556040518181527f56287a45051933ea374811b3d5d165033047be5572cac676f7c28b8be4f746c7906020015b60405180910390a150565b60006107ad60008051602061366e8339815191525490565b905090565b6107ba6122ee565b6107d65760405162461bcd60e51b81526004016106a29061338c565b6001600160a01b03821660009081526033602052604090205460ff161561083f5760405162461bcd60e51b815260206004820152601760248201527f4f6e6c7920756e737570706f727465642061737365747300000000000000000060448201526064016106a2565b61085b61084a610795565b6001600160a01b0384169083612716565b5050565b6108676122ee565b6108835760405162461bcd60e51b81526004016106a29061338c565b6001600160a01b03811660009081526035602052604090205460ff166108e35760405162461bcd60e51b815260206004820152601560248201527414dd1c985d1959de481b9bdd08185c1c1c9bdd9959605a1b60448201526064016106a2565b60345460005b8181101561099b57826001600160a01b0316604060006034848154811061091257610912613648565b60009182526020808320909101546001600160a01b03908116845290830193909352604090910190205416141561098b5760405162461bcd60e51b815260206004820181905260248201527f53747261746567792069732064656661756c7420666f7220616e20617373657460448201526064016106a2565b610994816135eb565b90506108e9565b506036548060005b828110156109fb57846001600160a01b0316603682815481106109c8576109c8613648565b6000918252602090912001546001600160a01b031614156109eb578091506109fb565b6109f4816135eb565b90506109a3565b5081811015610b5a576036610a116001846135a8565b81548110610a2157610a21613648565b600091825260209091200154603680546001600160a01b039092169183908110610a4d57610a4d613648565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055506036805480610a8c57610a8c613632565b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b03861680835260359091526040808320805460ff19169055805163429c145b60e11b81529051879363853828b6926004808201939182900301818387803b158015610b0357600080fd5b505af1158015610b17573d6000803e3d6000fd5b50506040516001600160a01b03881681527f09a1db4b80c32706328728508c941a6b954f31eb5affd32f236c1fd405f8fea49250602001905060405180910390a1505b50505050565b610b686122ee565b610b845760405162461bcd60e51b81526004016106a29061338c565b604280546001600160a01b0319166001600160a01b0383169081179091556040519081527f1e4af5ac389e8cde1bdaa6830881b6c987c62a45cfb3b33d27d805cde3b577509060200161078a565b610bda6122ee565b610bf65760405162461bcd60e51b81526004016106a29061338c565b610bff8161276d565b50565b610c0a6122ee565b610c265760405162461bcd60e51b81526004016106a29061338c565b603780546001600160a01b0319166001600160a01b0383169081179091556040519081527fb266add5f3044b17d27db796af992cecbe413921b4e8aaaee03c719e16b9806a9060200161078a565b610c7c6122ee565b610c985760405162461bcd60e51b81526004016106a29061338c565b6001600160a01b03811660009081526035602052604090205460ff1615610d015760405162461bcd60e51b815260206004820152601960248201527f537472617465677920616c726561647920617070726f7665640000000000000060448201526064016106a2565b6040805180820182526001808252600060208084018281526001600160a01b038716808452603583528684209551865460ff19169015151786559051948401949094556036805493840181559091527f4a11f94e20a93c79f6ec743a1954ec4fc2c08429ae2122118bf234b2185c81b890910180546001600160a01b0319168317905591519081527f960dd94cbb79169f09a4e445d58b895df2d9bffa5b31055d0932d801724a20d1910161078a565b603f546001600160a01b0316331480610dcd5750610dcd6122ee565b610de95760405162461bcd60e51b81526004016106a2906133c3565b6037805460ff60a81b1916600160a81b1790556040517f71f0e5b62f846a22e0b4d159e516e62fa9c2b8eb570be15f83e67d98a2ee51e090600090a1565b7f53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac45358054600091906002811415610e6f5760405162461bcd60e51b81526004016106a29061340b565b60028255603f546001600160a01b0316331480610e8f5750610e8f6122ee565b610eab5760405162461bcd60e51b81526004016106a2906133c3565b6001600160a01b0389166000908152603360209081526040808320815160808101909252805460ff808216151584529293919291840191610100909104166001811115610efa57610efa61361c565b6001811115610f0b57610f0b61361c565b8152905462010000810460ff908116602080850191909152630100000090920461ffff166040938401526001600160a01b038d1660009081526033835283812084516080810190955280548084161515865295965090949092840191610100909104166001811115610f7f57610f7f61361c565b6001811115610f9057610f9061361c565b8152905462010000810460ff1660208301526301000000900461ffff1660409091015282519091506110045760405162461bcd60e51b815260206004820152601b60248201527f46726f6d206173736574206973206e6f7420737570706f72746564000000000060448201526064016106a2565b80516110525760405162461bcd60e51b815260206004820152601960248201527f546f206173736574206973206e6f7420737570706f727465640000000000000060448201526064016106a2565b6040805180820182526048546001600160a01b038082168352600160a01b90910461ffff16602083015291516370a0823160e01b81523060048201529091600091908d16906370a082319060240160206040518083038186803b1580156110b857600080fd5b505afa1580156110cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110f091906132ab565b825190915061110a906001600160a01b038f16908d612716565b81600001516001600160a01b0316632506c0188e8e60018f61112c91906135a8565b8e8e8e6040518763ffffffff1660e01b8152600401611150969594939291906132fd565b602060405180830381600087803b15801561116a57600080fd5b505af115801561117e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111a291906132ab565b506040516370a0823160e01b815230600482015281906001600160a01b038e16906370a082319060240160206040518083038186803b1580156111e457600080fd5b505afa1580156111f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061121c91906132ab565b61122691906135a8565b965050888610156112795760405162461bcd60e51b815260206004820152601960248201527f5374726174656769737420736c697070616765206c696d69740000000000000060448201526064016106a2565b6000826060015161271061128d9190613433565b6037546040516315d5220f60e31b81526001600160a01b038f8116600483015261ffff93909316929091169063aea910789060240160206040518083038186803b1580156112da57600080fd5b505afa1580156112ee573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061131291906132ab565b61131c9190613566565b603760009054906101000a90046001600160a01b03166001600160a01b031663aea910788f6040518263ffffffff1660e01b815260040161136c91906001600160a01b0391909116815260200190565b60206040518083038186803b15801561138457600080fd5b505afa158015611398573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113bc91906132ab565b60608601516113cd90612710613585565b6113db9061ffff168e613566565b6113e59190613566565b6113ef9190613459565b905061140e6012856040015160ff16836128839092919063ffffffff16565b604084015161142490899060129060ff16612883565b10156114725760405162461bcd60e51b815260206004820152601e60248201527f4f7261636c6520736c697070616765206c696d6974206578636565646564000060448201526064016106a2565b5061271081602001516127106114889190613585565b61ffff16603c60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b1580156114da57600080fd5b505afa1580156114ee573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061151291906132ab565b61151c9190613566565b6115269190613459565b306001600160a01b031663d4c3eea06040518163ffffffff1660e01b815260040160206040518083038186803b15801561155f57600080fd5b505afa158015611573573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061159791906132ab565b10156115de5760405162461bcd60e51b8152602060048201526016602482015275416c6c6f7765642076616c7565203c20737570706c7960501b60448201526064016106a2565b8a6001600160a01b03168c6001600160a01b03167fa078c4190abe07940190effc1846be0ccf03ad6007bc9e93f9697d0b460befbb8c8960405161162c929190918252602082015260400190565b60405180910390a35050506001825550509695505050505050565b603f546001600160a01b031633148061166357506116636122ee565b61167f5760405162461bcd60e51b81526004016106a2906133c3565b6001600160a01b03811660009081526035602052604090205460ff166116e75760405162461bcd60e51b815260206004820152601960248201527f5374726174656779206973206e6f7420737570706f727465640000000000000060448201526064016106a2565b6000819050806001600160a01b031663853828b66040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561172757600080fd5b505af115801561173b573d6000803e3d6000fd5b505050505050565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b0316146117de5760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b60648201526084016106a2565b6117e7336128e7565b565b6117f16122ee565b61180d5760405162461bcd60e51b81526004016106a29061338c565b600060465560478190556040518181527fc29d6fedbc6bdf267a08166c2b976fbd72aca5d6a769528616f8b9224c8f197f9060200161078a565b61184f6122ee565b61186b5760405162461bcd60e51b81526004016106a29061338c565b60418190556040518181527f95201f9c21f26877223b1ff4073936a6484c35495649e60e55730497aeb60d939060200161078a565b6118a86122ee565b6118c45760405162461bcd60e51b81526004016106a29061338c565b6001600160a01b03821660009081526033602052604090205460ff161561192d5760405162461bcd60e51b815260206004820152601760248201527f417373657420616c726561647920737570706f7274656400000000000000000060448201526064016106a2565b60405180608001604052806001151581526020018260ff1660018111156119565761195661361c565b60018111156119675761196761361c565b81526000602080830182905260409283018290526001600160a01b0386168252603381529190208251815490151560ff19821681178355928401519192839161ff001990911661ffff19909116176101008360018111156119ca576119ca61361c565b02179055506040820151815460609093015161ffff1663010000000264ffff0000001960ff90921662010000029190911664ffffff00001990931692909217919091179055611a188261276d565b603480546001810182556000919091527f46bddb1178e94d7f2892ff5f366840eb658911794f2c3a44c450aa2c505186c10180546001600160a01b0319166001600160a01b038481169182179092556037546040516315d5220f60e31b815260048101929092529091169063aea910789060240160206040518083038186803b158015611aa457600080fd5b505afa158015611ab8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611adc91906132ab565b506040516001600160a01b03831681527f4f1ac48525e50059cc1cc6e0e1940ece0dd653a4db4841538d6aef036be2fb7b906020015b60405180910390a15050565b611b266122ee565b611b425760405162461bcd60e51b81526004016106a29061338c565b603f80546001600160a01b0319166001600160a01b0383169081179091556040519081527f869e0abd13cc3a975de7b93be3df1cb2255c802b1cead85963cc79d99f131bee9060200161078a565b611b986122ee565b611bb45760405162461bcd60e51b81526004016106a29061338c565b6001600160a01b03821660009081526033602052604090205460ff16611c125760405162461bcd60e51b8152602060048201526013602482015272105cdcd95d081b9bdd081cdd5c1c1bdc9d1959606a1b60448201526064016106a2565b6103e88161ffff1610611c5b5760405162461bcd60e51b81526020600482015260116024820152700a6d8d2e0e0c2ceca40e8dede40d0d2ced607b1b60448201526064016106a2565b6001600160a01b038216600081815260336020908152604091829020805464ffff0000001916630100000061ffff8716908102919091179091558251938452908301527f8d22e9d2cbe8bb65a3c4412bd8970743864512a1a0e004e8d00fb96277b78b949101611b12565b603f546001600160a01b0316331480611ce25750611ce26122ee565b611cfe5760405162461bcd60e51b81526004016106a2906133c3565b7f53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac453580546002811415611d425760405162461bcd60e51b81526004016106a29061340b565b60028255611d5387878787876129a8565b50600190555050505050565b603f546001600160a01b0316331480611d7b5750611d7b6122ee565b611d975760405162461bcd60e51b81526004016106a2906133c3565b670de0b6b3a7640000811115611ddf5760405162461bcd60e51b815260206004820152600d60248201526c496e76616c69642076616c756560981b60448201526064016106a2565b60398190556040518181527f41ecb23a0e7865b25f38c268b7c3012220d822929e9edff07326e89d5bb822b59060200161078a565b603f546001600160a01b0316331480611e305750611e306122ee565b611e4c5760405162461bcd60e51b81526004016106a2906133c3565b6037805460ff60a81b191690556040517f891ebab18da80ebeeea06b1b1cede098329c4c008906a98370c2ac7a80b571cb90600090a1565b611e8c6122ee565b611ea85760405162461bcd60e51b81526004016106a29061338c565b604880546001600160a01b0319166001600160a01b0383169081179091556040519081527f7d7719313229e558c5a3893cad2eb86a86a049156d1d9ebd5c63a8eedefd1c039060200161078a565b603f546001600160a01b0316331480611f125750611f126122ee565b611f2e5760405162461bcd60e51b81526004016106a2906133c3565b7f53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac453580546002811415611f725760405162461bcd60e51b81526004016106a29061340b565b60028255611d53308888888888612be6565b611f8c6122ee565b611fa85760405162461bcd60e51b81526004016106a29061338c565b603a8190556040518181527f2ec5fb5a3d2703edc461252d92ccd2799c3c74f01d97212b20388207fa17ae459060200161078a565b611fe56122ee565b6120015760405162461bcd60e51b81526004016106a29061338c565b603b8190556040518181527f39367850377ac04920a9a670f2180e7a94d83b15ad302e59875ec58fd10bd37d9060200161078a565b603f546001600160a01b031633148061205257506120526122ee565b61206e5760405162461bcd60e51b81526004016106a2906133c3565b604080516001600160a01b038085168252831660208201527fba58ce12801c949fa65f41c46ed108671c219baf945fa48d21026cea99ff252a910160405180910390a16001600160a01b0381161561224a576001600160a01b03811660009081526035602052604090205460ff166121205760405162461bcd60e51b815260206004820152601560248201527414dd1c985d1959de481b9bdd08185c1c1c9bdd9959605a1b60448201526064016106a2565b6001600160a01b038216600090815260336020526040902054819060ff166121835760405162461bcd60e51b8152602060048201526016602482015275105cdcd95d081a5cc81b9bdd081cdd5c1c1bdc9d195960521b60448201526064016106a2565b60405163551c457b60e11b81526001600160a01b03848116600483015282169063aa388af69060240160206040518083038186803b1580156121c457600080fd5b505afa1580156121d8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121fc9190613255565b6122485760405162461bcd60e51b815260206004820152601f60248201527f4173736574206e6f7420737570706f727465642062792053747261746567790060448201526064016106a2565b505b6001600160a01b03918216600090815260406020819052902080546001600160a01b03191691909216179055565b603f546001600160a01b031633148061229457506122946122ee565b6122b05760405162461bcd60e51b81526004016106a2906133c3565b6037805460ff60a01b1916600160a01b1790556040517f8cff26a5985614b3d30629cc4ab83824bf115aec971b718d8f2f99562032e97290600090a1565b600061230660008051602061366e8339815191525490565b6001600160a01b0316336001600160a01b031614905090565b603f546001600160a01b031633148061233b575061233b6122ee565b6123575760405162461bcd60e51b81526004016106a2906133c3565b60365460005b8181101561085b576036818154811061237857612378613648565b60009182526020822001546040805163429c145b60e11b815290516001600160a01b039092169263853828b69260048084019382900301818387803b1580156123c057600080fd5b505af11580156123d4573d6000803e3d6000fd5b50505050806123e2906135eb565b905061235d565b6123f16122ee565b61240d5760405162461bcd60e51b81526004016106a29061338c565b612435817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b031661245560008051602061366e8339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b6124956122ee565b6124b15760405162461bcd60e51b81526004016106a29061338c565b604580546001600160a01b0319166001600160a01b0383169081179091556040519081527fa12850fb726e0b2b7b3c9a9342031e1268a8148d0eb06b4bea8613204ffcd2b89060200161078a565b6125076122ee565b6125235760405162461bcd60e51b81526004016106a29061338c565b6127118161ffff161061256f5760405162461bcd60e51b8152602060048201526014602482015273496e76616c696420626173697320706f696e747360601b60448201526064016106a2565b6048805461ffff60a01b1916600160a01b61ffff8416908102919091179091556040519081527ff12c00256bee2b6facb111a88a9b1cff86e79132939b44f1353212d6f74695579060200161078a565b6125c76122ee565b6125e35760405162461bcd60e51b81526004016106a29061338c565b6103e881111561263f5760405162461bcd60e51b815260206004820152602160248201527f52656465656d206665652073686f756c64206e6f74206265206f7665722031306044820152602560f81b60648201526084016106a2565b60388190556040518181527fd6c7508d6658ccee36b7b7d7fd72e5cbaeefb40c64eff24e9ae7470e846304ee9060200161078a565b61267c6122ee565b6126985760405162461bcd60e51b81526004016106a29061338c565b803b6126f25760405162461bcd60e51b8152602060048201526024808201527f6e657720696d706c656d656e746174696f6e206973206e6f74206120636f6e746044820152631c9858dd60e21b60648201526084016106a2565b7fa2bd3d3cf188a41358c8b401076eb59066b09dec5775650c0de4c55187d17bd955565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052612768908490612d70565b505050565b6001600160a01b0381166000908152603360205260409020805462010000900460ff1615612799575050565b6000826001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b1580156127d457600080fd5b505afa1580156127e8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061280c91906132c4565b905060068160ff1610158015612826575060128160ff1611155b6128695760405162461bcd60e51b81526020600482015260146024820152732ab732bc3832b1ba32b210383932b1b4b9b4b7b760611b60448201526064016106a2565b815460ff909116620100000262ff00001990911617905550565b6000818311156128b3576128ac61289a83856135a8565b6128a590600a6134be565b8590612e42565b93506128dd565b818310156128dd576128da6128c884846135a8565b6128d390600a6134be565b8590612e57565b93505b50825b9392505050565b6001600160a01b03811661293d5760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f72206973206164647265737328302900000000000060448201526064016106a2565b806001600160a01b031661295d60008051602061366e8339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a3610bff8160008051602061366e83398151915255565b6001600160a01b03851660009081526035602052604090205460ff16612a065760405162461bcd60e51b8152602060048201526013602482015272496e76616c696420746f20537472617465677960681b60448201526064016106a2565b828114612a515760405162461bcd60e51b81526020600482015260196024820152780a0c2e4c2dacae8cae440d8cadccee8d040dad2e6dac2e8c6d603b1b60448201526064016106a2565b8260005b81811015612b8a576000868683818110612a7157612a71613648565b9050602002016020810190612a869190613055565b60405163551c457b60e11b81526001600160a01b0380831660048301529192509089169063aa388af69060240160206040518083038186803b158015612acb57600080fd5b505afa158015612adf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b039190613255565b612b435760405162461bcd60e51b8152602060048201526011602482015270105cdcd95d081d5b9cdd5c1c1bdc9d1959607a1b60448201526064016106a2565b612b7988868685818110612b5957612b59613648565b90506020020135836001600160a01b03166127169092919063ffffffff16565b50612b83816135eb565b9050612a55565b50856001600160a01b031663de5f62686040518163ffffffff1660e01b8152600401600060405180830381600087803b158015612bc657600080fd5b505af1158015612bda573d6000803e3d6000fd5b50505050505050505050565b6001600160a01b03851660009081526035602052604090205460ff16612c465760405162461bcd60e51b8152602060048201526015602482015274496e76616c69642066726f6d20537472617465677960581b60448201526064016106a2565b828114612c915760405162461bcd60e51b81526020600482015260196024820152780a0c2e4c2dacae8cae440d8cadccee8d040dad2e6dac2e8c6d603b1b60448201526064016106a2565b8260005b81811015612d6657866001600160a01b031663d9caed1289888885818110612cbf57612cbf613648565b9050602002016020810190612cd49190613055565b878786818110612ce657612ce6613648565b6040516001600160e01b031960e088901b1681526001600160a01b03958616600482015294909316602485015250602090910201356044820152606401600060405180830381600087803b158015612d3d57600080fd5b505af1158015612d51573d6000803e3d6000fd5b5050505080612d5f906135eb565b9050612c95565b5050505050505050565b6000612dc5826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316612e639092919063ffffffff16565b8051909150156127685780806020019051810190612de39190613255565b6127685760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016106a2565b6000612e4e8284613566565b90505b92915050565b6000612e4e8284613459565b6060612e728484600085612e7a565b949350505050565b606082471015612edb5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016106a2565b843b612f295760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016106a2565b600080866001600160a01b03168587604051612f4591906132e1565b60006040518083038185875af1925050503d8060008114612f82576040519150601f19603f3d011682016040523d82523d6000602084013e612f87565b606091505b5091509150612f97828286612fa2565b979650505050505050565b60608315612fb15750816128e0565b825115612fc15782518084602001fd5b8160405162461bcd60e51b81526004016106a29190613359565b80356001600160a01b0381168114612ff257600080fd5b919050565b60008083601f84011261300957600080fd5b50813567ffffffffffffffff81111561302157600080fd5b6020830191508360208260051b850101111561303c57600080fd5b9250929050565b803561ffff81168114612ff257600080fd5b60006020828403121561306757600080fd5b612e4e82612fdb565b6000806040838503121561308357600080fd5b61308c83612fdb565b915061309a60208401612fdb565b90509250929050565b60008060008060008060a087890312156130bc57600080fd5b6130c587612fdb565b95506130d360208801612fdb565b94506040870135935060608701359250608087013567ffffffffffffffff808211156130fe57600080fd5b818901915089601f83011261311257600080fd5b81358181111561312157600080fd5b8a602082850101111561313357600080fd5b6020830194508093505050509295509295509295565b60008060008060006060868803121561316157600080fd5b61316a86612fdb565b9450602086013567ffffffffffffffff8082111561318757600080fd5b61319389838a01612ff7565b909650945060408801359150808211156131ac57600080fd5b506131b988828901612ff7565b969995985093965092949392505050565b600080604083850312156131dd57600080fd5b6131e683612fdb565b915061309a60208401613043565b6000806040838503121561320757600080fd5b61321083612fdb565b946020939093013593505050565b6000806040838503121561323157600080fd5b61323a83612fdb565b9150602083013561324a8161365e565b809150509250929050565b60006020828403121561326757600080fd5b815180151581146128e057600080fd5b60006020828403121561328957600080fd5b612e4e82613043565b6000602082840312156132a457600080fd5b5035919050565b6000602082840312156132bd57600080fd5b5051919050565b6000602082840312156132d657600080fd5b81516128e08161365e565b600082516132f38184602087016135bf565b9190910192915050565b6001600160a01b03878116825286166020820152604081018590526060810184905260a06080820181905281018290526000828460c0840137600060c0848401015260c0601f19601f8501168301019050979650505050505050565b60208152600082518060208401526133788160408501602087016135bf565b601f01601f19169190910160400192915050565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b60208082526028908201527f43616c6c6572206973206e6f74207468652053747261746567697374206f722060408201526723b7bb32b93737b960c11b606082015260800190565b6020808252600e908201526d1499595b9d1c985b9d0818d85b1b60921b604082015260600190565b600061ffff80831681851680830382111561345057613450613606565b01949350505050565b60008261347657634e487b7160e01b600052601260045260246000fd5b500490565b600181815b808511156134b657816000190482111561349c5761349c613606565b808516156134a957918102915b93841c9390800290613480565b509250929050565b6000612e4e83836000826134d457506001612e51565b816134e157506000612e51565b81600181146134f757600281146135015761351d565b6001915050612e51565b60ff84111561351257613512613606565b50506001821b612e51565b5060208310610133831016604e8410600b8410161715613540575081810a612e51565b61354a838361347b565b806000190482111561355e5761355e613606565b029392505050565b600081600019048311821515161561358057613580613606565b500290565b600061ffff838116908316818110156135a0576135a0613606565b039392505050565b6000828210156135ba576135ba613606565b500390565b60005b838110156135da5781810151838201526020016135c2565b83811115610b5a5750506000910152565b60006000198214156135ff576135ff613606565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b60ff81168114610bff57600080fdfe7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa2646970667358221220856c9fec2e98e8d950cc7553495c5c13452851bc0b706e1a29005d23345bcb1364736f6c63430008070033", + "args": [ + "0x94373a4919B3240D86eA41593D5eBa789FEF3848" + ], + "numDeployments": 2, + "solcInputHash": "9b811e7a632431f9f724307daee2b897", + "metadata": "{\"compiler\":{\"version\":\"0.8.7+commit.e28d00a7\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_weth\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_threshold\",\"type\":\"uint256\"}],\"name\":\"AllocateThresholdUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_strategy\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"AssetAllocated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_strategy\",\"type\":\"address\"}],\"name\":\"AssetDefaultStrategyUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"}],\"name\":\"AssetRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"}],\"name\":\"AssetSupported\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"CapitalPaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"CapitalUnpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_dripper\",\"type\":\"address\"}],\"name\":\"DripperChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousGovernor\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newGovernor\",\"type\":\"address\"}],\"name\":\"GovernorshipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"maxSupplyDiff\",\"type\":\"uint256\"}],\"name\":\"MaxSupplyDiffChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"Mint\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_threshold\",\"type\":\"uint256\"}],\"name\":\"NetOusdMintForStrategyThresholdChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_ousdMetaStrategy\",\"type\":\"address\"}],\"name\":\"OusdMetaStrategyUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousGovernor\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newGovernor\",\"type\":\"address\"}],\"name\":\"PendingGovernorshipTransfer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_priceProvider\",\"type\":\"address\"}],\"name\":\"PriceProviderUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"RebasePaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_threshold\",\"type\":\"uint256\"}],\"name\":\"RebaseThresholdUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"RebaseUnpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"Redeem\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_redeemFeeBps\",\"type\":\"uint256\"}],\"name\":\"RedeemFeeUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"StrategistUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"}],\"name\":\"StrategyApproved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"}],\"name\":\"StrategyRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_basis\",\"type\":\"uint256\"}],\"name\":\"SwapAllowedUndervalueChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_basis\",\"type\":\"uint256\"}],\"name\":\"SwapSlippageChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_fromAsset\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_toAsset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_fromAssetAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_toAssetAmount\",\"type\":\"uint256\"}],\"name\":\"Swapped\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"SwapperChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"TrusteeAddressChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_basis\",\"type\":\"uint256\"}],\"name\":\"TrusteeFeeBpsChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_vaultBuffer\",\"type\":\"uint256\"}],\"name\":\"VaultBufferUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_claimable\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_newClaimable\",\"type\":\"uint256\"}],\"name\":\"WithdrawalClaimable\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_withdrawer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"WithdrawalClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_withdrawer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_queued\",\"type\":\"uint256\"}],\"name\":\"WithdrawalRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_yield\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_fee\",\"type\":\"uint256\"}],\"name\":\"YieldDistribution\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"allowedSwapUndervalue\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"}],\"name\":\"approveStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"assetDefaultStrategies\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"autoAllocateThreshold\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"}],\"name\":\"cacheDecimals\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"capitalPaused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"claimGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_strategyToAddress\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"_assets\",\"type\":\"address[]\"},{\"internalType\":\"uint256[]\",\"name\":\"_amounts\",\"type\":\"uint256[]\"}],\"name\":\"depositToStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"dripper\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"governor\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isGovernor\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"maxSupplyDiff\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"netOusdMintForStrategyThreshold\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"netOusdMintedForStrategy\",\"outputs\":[{\"internalType\":\"int256\",\"name\":\"\",\"type\":\"int256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"ousdMetaStrategy\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pauseCapital\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pauseRebase\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"priceProvider\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rebasePaused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rebaseThreshold\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"redeemFeeBps\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"}],\"name\":\"removeAsset\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"}],\"name\":\"removeStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newImpl\",\"type\":\"address\"}],\"name\":\"setAdminImpl\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_strategy\",\"type\":\"address\"}],\"name\":\"setAssetDefaultStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_threshold\",\"type\":\"uint256\"}],\"name\":\"setAutoAllocateThreshold\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_dripper\",\"type\":\"address\"}],\"name\":\"setDripper\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_maxSupplyDiff\",\"type\":\"uint256\"}],\"name\":\"setMaxSupplyDiff\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_threshold\",\"type\":\"uint256\"}],\"name\":\"setNetOusdMintForStrategyThreshold\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"uint16\",\"name\":\"_allowedOracleSlippageBps\",\"type\":\"uint16\"}],\"name\":\"setOracleSlippage\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_ousdMetaStrategy\",\"type\":\"address\"}],\"name\":\"setOusdMetaStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_priceProvider\",\"type\":\"address\"}],\"name\":\"setPriceProvider\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_threshold\",\"type\":\"uint256\"}],\"name\":\"setRebaseThreshold\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_redeemFeeBps\",\"type\":\"uint256\"}],\"name\":\"setRedeemFeeBps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"setStrategistAddr\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"_basis\",\"type\":\"uint16\"}],\"name\":\"setSwapAllowedUndervalue\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_swapperAddr\",\"type\":\"address\"}],\"name\":\"setSwapper\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"setTrusteeAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_basis\",\"type\":\"uint256\"}],\"name\":\"setTrusteeFeeBps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_vaultBuffer\",\"type\":\"uint256\"}],\"name\":\"setVaultBuffer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"strategistAddr\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"_unitConversion\",\"type\":\"uint8\"}],\"name\":\"supportAsset\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_fromAsset\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_toAsset\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_fromAssetAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_minToAssetAmount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"swapCollateral\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"toAssetAmount\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"swapper\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"swapper_\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_newGovernor\",\"type\":\"address\"}],\"name\":\"transferGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"transferToken\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"trusteeAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"trusteeFeeBps\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"unpauseCapital\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"unpauseRebase\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"vaultBuffer\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"weth\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdrawAllFromStrategies\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_strategyAddr\",\"type\":\"address\"}],\"name\":\"withdrawAllFromStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_strategyFromAddress\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"_assets\",\"type\":\"address[]\"},{\"internalType\":\"uint256[]\",\"name\":\"_amounts\",\"type\":\"uint256[]\"}],\"name\":\"withdrawFromStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdrawalQueueMetadata\",\"outputs\":[{\"internalType\":\"uint128\",\"name\":\"queued\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"claimable\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"claimed\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"nextWithdrawalIndex\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"withdrawalRequests\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"withdrawer\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"claimed\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"amount\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"queued\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"author\":\"Origin Protocol Inc\",\"kind\":\"dev\",\"methods\":{\"allowedSwapUndervalue()\":{\"returns\":{\"value\":\"Percentage in basis points.\"}},\"approveStrategy(address)\":{\"params\":{\"_addr\":\"Address of the strategy to add\"}},\"cacheDecimals(address)\":{\"params\":{\"_asset\":\"Address of asset token\"}},\"depositToStrategy(address,address[],uint256[])\":{\"params\":{\"_amounts\":\"Array of amounts of each corresponding asset to deposit.\",\"_assets\":\"Array of asset address that will be deposited into the strategy.\",\"_strategyToAddress\":\"Address of the Strategy to deposit assets into.\"}},\"removeAsset(address)\":{\"params\":{\"_asset\":\"Address of asset\"}},\"removeStrategy(address)\":{\"params\":{\"_addr\":\"Address of the strategy to remove\"}},\"setAdminImpl(address)\":{\"params\":{\"newImpl\":\"address of the implementation\"}},\"setAssetDefaultStrategy(address,address)\":{\"params\":{\"_asset\":\"Address of the asset\",\"_strategy\":\"Address of the Strategy\"}},\"setAutoAllocateThreshold(uint256)\":{\"params\":{\"_threshold\":\"OToken amount with 18 fixed decimals.\"}},\"setDripper(address)\":{\"params\":{\"_dripper\":\"Address of the Dripper contract.\"}},\"setNetOusdMintForStrategyThreshold(uint256)\":{\"params\":{\"_threshold\":\"OToken amount with 18 fixed decimals.\"}},\"setOracleSlippage(address,uint16)\":{\"params\":{\"_allowedOracleSlippageBps\":\"allowed slippage from Oracle in basis points. eg 20 = 0.2%. Max 10%.\",\"_asset\":\"Address of the asset token.\"}},\"setOusdMetaStrategy(address)\":{\"params\":{\"_ousdMetaStrategy\":\"Address of OToken metapool strategy\"}},\"setPriceProvider(address)\":{\"params\":{\"_priceProvider\":\"Address of price provider\"}},\"setRebaseThreshold(uint256)\":{\"params\":{\"_threshold\":\"OToken amount with 18 fixed decimals.\"}},\"setRedeemFeeBps(uint256)\":{\"params\":{\"_redeemFeeBps\":\"Basis point fee to be charged\"}},\"setStrategistAddr(address)\":{\"params\":{\"_address\":\"Address of Strategist\"}},\"setSwapAllowedUndervalue(uint16)\":{\"params\":{\"_basis\":\"Percentage in basis points. eg 100 == 1%\"}},\"setSwapper(address)\":{\"params\":{\"_swapperAddr\":\"Address of the Swapper contract that implements the ISwapper interface.\"}},\"setVaultBuffer(uint256)\":{\"params\":{\"_vaultBuffer\":\"Percentage using 18 decimals. 100% = 1e18.\"}},\"supportAsset(address,uint8)\":{\"params\":{\"_asset\":\"Address of asset\"}},\"swapCollateral(address,address,uint256,uint256,bytes)\":{\"params\":{\"_data\":\"implementation specific data. eg 1Inch swap data\",\"_fromAsset\":\"The token address of the asset being sold by the vault.\",\"_fromAssetAmount\":\"The amount of assets being sold by the vault.\",\"_minToAssetAmount\":\"The minimum amount of assets to be purchased.\",\"_toAsset\":\"The token address of the asset being purchased by the vault.\"},\"returns\":{\"toAssetAmount\":\"The amount of toAssets that was received from the swap\"}},\"transferGovernance(address)\":{\"params\":{\"_newGovernor\":\"Address of the new Governor\"}},\"transferToken(address,uint256)\":{\"params\":{\"_amount\":\"Amount of the asset to transfer\",\"_asset\":\"Address for the asset\"}},\"withdrawAllFromStrategy(address)\":{\"params\":{\"_strategyAddr\":\"Strategy address.\"}},\"withdrawFromStrategy(address,address[],uint256[])\":{\"params\":{\"_amounts\":\"Array of amounts of each corresponding asset to withdraw.\",\"_assets\":\"Array of asset address that will be withdrawn from the strategy.\",\"_strategyFromAddress\":\"Address of the Strategy to withdraw assets from.\"}}},\"title\":\"OETH VaultAdmin Contract\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"allowedSwapUndervalue()\":{\"notice\":\"Max allowed percentage the vault total value can drop below the OToken total supply in basis points when executing a collateral swap. For example 100 == 1%\"},\"approveStrategy(address)\":{\"notice\":\"Add a strategy to the Vault.\"},\"assetDefaultStrategies(address)\":{\"notice\":\"Mapping of asset address to the Strategy that they should automatically\"},\"autoAllocateThreshold()\":{\"notice\":\"OToken mints over this amount automatically allocate funds. 18 decimals.\"},\"cacheDecimals(address)\":{\"notice\":\"Cache decimals on OracleRouter for a particular asset. This action is required before that asset's price can be accessed.\"},\"capitalPaused()\":{\"notice\":\"pause operations that change the OToken supply. eg mint, redeem, allocate, mint/burn for strategy\"},\"claimGovernance()\":{\"notice\":\"Claim Governance of the contract to a new account (`newGovernor`). Can only be called by the new Governor.\"},\"depositToStrategy(address,address[],uint256[])\":{\"notice\":\"Deposit multiple assets from the vault into the strategy.\"},\"dripper()\":{\"notice\":\"Address of the Dripper contract that streams harvested rewards to the Vault\"},\"governor()\":{\"notice\":\"Returns the address of the current Governor.\"},\"isGovernor()\":{\"notice\":\"Returns true if the caller is the current Governor.\"},\"maxSupplyDiff()\":{\"notice\":\"Max difference between total supply and total value of assets. 18 decimals.\"},\"netOusdMintForStrategyThreshold()\":{\"notice\":\"How much net total OTokens are allowed to be minted by all strategies\"},\"netOusdMintedForStrategy()\":{\"notice\":\"How much OTokens are currently minted by the strategy\"},\"ousdMetaStrategy()\":{\"notice\":\"Metapool strategy that is allowed to mint/burn OTokens without changing collateral\"},\"pauseCapital()\":{\"notice\":\"Set the deposit paused flag to true to prevent capital movement.\"},\"pauseRebase()\":{\"notice\":\"Set the deposit paused flag to true to prevent rebasing.\"},\"priceProvider()\":{\"notice\":\"Address of the Oracle price provider contract\"},\"rebasePaused()\":{\"notice\":\"pause rebasing if true\"},\"rebaseThreshold()\":{\"notice\":\"OToken mints over this amount automatically rebase. 18 decimals.\"},\"redeemFeeBps()\":{\"notice\":\"Redemption fee in basis points. eg 50 = 0.5%\"},\"removeAsset(address)\":{\"notice\":\"Remove a supported asset from the Vault\"},\"removeStrategy(address)\":{\"notice\":\"Remove a strategy from the Vault.\"},\"setAdminImpl(address)\":{\"notice\":\"set the implementation for the admin, this needs to be in a base class else we cannot set it\"},\"setAssetDefaultStrategy(address,address)\":{\"notice\":\"Set the default Strategy for an asset, i.e. the one which the asset will be automatically allocated to and withdrawn from\"},\"setAutoAllocateThreshold(uint256)\":{\"notice\":\"Sets the minimum amount of OTokens in a mint to trigger an automatic allocation of funds afterwords.\"},\"setDripper(address)\":{\"notice\":\"Set the Dripper contract that streams harvested rewards to the vault.\"},\"setMaxSupplyDiff(uint256)\":{\"notice\":\"Sets the maximum allowable difference between total supply and backing assets' value.\"},\"setNetOusdMintForStrategyThreshold(uint256)\":{\"notice\":\"Set maximum amount of OTokens that can at any point be minted and deployed to strategy (used only by ConvexOUSDMetaStrategy for now).\"},\"setOracleSlippage(address,uint16)\":{\"notice\":\"Set the allowed slippage from the Oracle price for collateral asset swaps.\"},\"setOusdMetaStrategy(address)\":{\"notice\":\"Set OToken Metapool strategy\"},\"setPriceProvider(address)\":{\"notice\":\"Set address of price provider.\"},\"setRebaseThreshold(uint256)\":{\"notice\":\"Set a minimum amount of OTokens in a mint or redeem that triggers a rebase\"},\"setRedeemFeeBps(uint256)\":{\"notice\":\"Set a fee in basis points to be charged for a redeem.\"},\"setStrategistAddr(address)\":{\"notice\":\"Set address of Strategist\"},\"setSwapAllowedUndervalue(uint16)\":{\"notice\":\"Set max allowed percentage the vault total value can drop below the OToken total supply in basis points when executing collateral swaps.\"},\"setSwapper(address)\":{\"notice\":\"Set the contract the performs swaps of collateral assets.\"},\"setTrusteeAddress(address)\":{\"notice\":\"Sets the trusteeAddress that can receive a portion of yield. Setting to the zero address disables this feature.\"},\"setTrusteeFeeBps(uint256)\":{\"notice\":\"Sets the TrusteeFeeBps to the percentage of yield that should be received in basis points.\"},\"setVaultBuffer(uint256)\":{\"notice\":\"Set a buffer of assets to keep in the Vault to handle most redemptions without needing to spend gas unwinding assets from a Strategy.\"},\"strategistAddr()\":{\"notice\":\"Address of the Strategist\"},\"supportAsset(address,uint8)\":{\"notice\":\"Add a supported asset to the contract, i.e. one that can be to mint OTokens.\"},\"swapCollateral(address,address,uint256,uint256,bytes)\":{\"notice\":\"Strategist swaps collateral assets sitting in the vault.\"},\"swapper()\":{\"notice\":\"Contract that swaps the vault's collateral assets\"},\"transferGovernance(address)\":{\"notice\":\"Transfers Governance of the contract to a new account (`newGovernor`). Can only be called by the current Governor. Must be claimed for this to complete\"},\"transferToken(address,uint256)\":{\"notice\":\"Transfer token to governor. Intended for recovering tokens stuck in contract, i.e. mistaken sends.\"},\"trusteeAddress()\":{\"notice\":\"Trustee contract that can collect a percentage of yield\"},\"trusteeFeeBps()\":{\"notice\":\"Amount of yield collected in basis points. eg 2000 = 20%\"},\"unpauseCapital()\":{\"notice\":\"Set the deposit paused flag to false to enable capital movement.\"},\"unpauseRebase()\":{\"notice\":\"Set the deposit paused flag to true to allow rebasing.\"},\"vaultBuffer()\":{\"notice\":\"Percentage of assets to keep in Vault to handle (most) withdrawals. 100% = 1e18.\"},\"withdrawAllFromStrategies()\":{\"notice\":\"Withdraws all assets from all the strategies and sends assets to the Vault.\"},\"withdrawAllFromStrategy(address)\":{\"notice\":\"Withdraws all assets from the strategy and sends assets to the Vault.\"},\"withdrawFromStrategy(address,address[],uint256[])\":{\"notice\":\"Withdraw multiple assets from the strategy to the vault.\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/vault/OETHVaultAdmin.sol\":\"OETHVaultAdmin\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `recipient`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address recipient, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `sender` to `recipient` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address sender,\\n address recipient,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0x61437cb513a887a1bbad006e7b1c8b414478427d33de47c5600af3c748f108da\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Address.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize, which returns 0 for contracts in\\n // construction, since the code is only stored at the end of the\\n // constructor execution.\\n\\n uint256 size;\\n assembly {\\n size := extcodesize(account)\\n }\\n return size > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x51b758a8815ecc9596c66c37d56b1d33883a444631a3f916b9fe65cb863ef7c4\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/math/SafeMath.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeMath.sol)\\n\\npragma solidity ^0.8.0;\\n\\n// CAUTION\\n// This version of SafeMath should only be used with Solidity 0.8 or later,\\n// because it relies on the compiler's built in overflow checks.\\n\\n/**\\n * @dev Wrappers over Solidity's arithmetic operations.\\n *\\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\\n * now has built in overflow checking.\\n */\\nlibrary SafeMath {\\n /**\\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n uint256 c = a + b;\\n if (c < a) return (false, 0);\\n return (true, c);\\n }\\n }\\n\\n /**\\n * @dev Returns the substraction of two unsigned integers, with an overflow flag.\\n *\\n * _Available since v3.4._\\n */\\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n if (b > a) return (false, 0);\\n return (true, a - b);\\n }\\n }\\n\\n /**\\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\\n // benefit is lost if 'b' is also tested.\\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\\n if (a == 0) return (true, 0);\\n uint256 c = a * b;\\n if (c / a != b) return (false, 0);\\n return (true, c);\\n }\\n }\\n\\n /**\\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n if (b == 0) return (false, 0);\\n return (true, a / b);\\n }\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n if (b == 0) return (false, 0);\\n return (true, a % b);\\n }\\n }\\n\\n /**\\n * @dev Returns the addition of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `+` operator.\\n *\\n * Requirements:\\n *\\n * - Addition cannot overflow.\\n */\\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a + b;\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting on\\n * overflow (when the result is negative).\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n *\\n * - Subtraction cannot overflow.\\n */\\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a - b;\\n }\\n\\n /**\\n * @dev Returns the multiplication of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `*` operator.\\n *\\n * Requirements:\\n *\\n * - Multiplication cannot overflow.\\n */\\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a * b;\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers, reverting on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator.\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a / b;\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * reverting when dividing by zero.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a % b;\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\\n * overflow (when the result is negative).\\n *\\n * CAUTION: This function is deprecated because it requires allocating memory for the error\\n * message unnecessarily. For custom revert reasons use {trySub}.\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n *\\n * - Subtraction cannot overflow.\\n */\\n function sub(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n unchecked {\\n require(b <= a, errorMessage);\\n return a - b;\\n }\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator. Note: this function uses a\\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\\n * uses an invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function div(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n unchecked {\\n require(b > 0, errorMessage);\\n return a / b;\\n }\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * reverting with custom message when dividing by zero.\\n *\\n * CAUTION: This function is deprecated because it requires allocating memory for the error\\n * message unnecessarily. For custom revert reasons use {tryMod}.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function mod(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n unchecked {\\n require(b > 0, errorMessage);\\n return a % b;\\n }\\n }\\n}\\n\",\"keccak256\":\"0xa2f576be637946f767aa56601c26d717f48a0aff44f82e46f13807eea1009a21\",\"license\":\"MIT\"},\"contracts/governance/Governable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Base for contracts that are managed by the Origin Protocol's Governor.\\n * @dev Copy of the openzeppelin Ownable.sol contract with nomenclature change\\n * from owner to governor and renounce methods removed. Does not use\\n * Context.sol like Ownable.sol does for simplification.\\n * @author Origin Protocol Inc\\n */\\ncontract Governable {\\n // Storage position of the owner and pendingOwner of the contract\\n // keccak256(\\\"OUSD.governor\\\");\\n bytes32 private constant governorPosition =\\n 0x7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a;\\n\\n // keccak256(\\\"OUSD.pending.governor\\\");\\n bytes32 private constant pendingGovernorPosition =\\n 0x44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db;\\n\\n // keccak256(\\\"OUSD.reentry.status\\\");\\n bytes32 private constant reentryStatusPosition =\\n 0x53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac4535;\\n\\n // See OpenZeppelin ReentrancyGuard implementation\\n uint256 constant _NOT_ENTERED = 1;\\n uint256 constant _ENTERED = 2;\\n\\n event PendingGovernorshipTransfer(\\n address indexed previousGovernor,\\n address indexed newGovernor\\n );\\n\\n event GovernorshipTransferred(\\n address indexed previousGovernor,\\n address indexed newGovernor\\n );\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial Governor.\\n */\\n constructor() {\\n _setGovernor(msg.sender);\\n emit GovernorshipTransferred(address(0), _governor());\\n }\\n\\n /**\\n * @notice Returns the address of the current Governor.\\n */\\n function governor() public view returns (address) {\\n return _governor();\\n }\\n\\n /**\\n * @dev Returns the address of the current Governor.\\n */\\n function _governor() internal view returns (address governorOut) {\\n bytes32 position = governorPosition;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n governorOut := sload(position)\\n }\\n }\\n\\n /**\\n * @dev Returns the address of the pending Governor.\\n */\\n function _pendingGovernor()\\n internal\\n view\\n returns (address pendingGovernor)\\n {\\n bytes32 position = pendingGovernorPosition;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n pendingGovernor := sload(position)\\n }\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the Governor.\\n */\\n modifier onlyGovernor() {\\n require(isGovernor(), \\\"Caller is not the Governor\\\");\\n _;\\n }\\n\\n /**\\n * @notice Returns true if the caller is the current Governor.\\n */\\n function isGovernor() public view returns (bool) {\\n return msg.sender == _governor();\\n }\\n\\n function _setGovernor(address newGovernor) internal {\\n bytes32 position = governorPosition;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n sstore(position, newGovernor)\\n }\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a `nonReentrant` function from another `nonReentrant`\\n * function is not supported. It is possible to prevent this from happening\\n * by making the `nonReentrant` function external, and make it call a\\n * `private` function that does the actual work.\\n */\\n modifier nonReentrant() {\\n bytes32 position = reentryStatusPosition;\\n uint256 _reentry_status;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n _reentry_status := sload(position)\\n }\\n\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_reentry_status != _ENTERED, \\\"Reentrant call\\\");\\n\\n // Any calls to nonReentrant after this point will fail\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n sstore(position, _ENTERED)\\n }\\n\\n _;\\n\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n sstore(position, _NOT_ENTERED)\\n }\\n }\\n\\n function _setPendingGovernor(address newGovernor) internal {\\n bytes32 position = pendingGovernorPosition;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n sstore(position, newGovernor)\\n }\\n }\\n\\n /**\\n * @notice Transfers Governance of the contract to a new account (`newGovernor`).\\n * Can only be called by the current Governor. Must be claimed for this to complete\\n * @param _newGovernor Address of the new Governor\\n */\\n function transferGovernance(address _newGovernor) external onlyGovernor {\\n _setPendingGovernor(_newGovernor);\\n emit PendingGovernorshipTransfer(_governor(), _newGovernor);\\n }\\n\\n /**\\n * @notice Claim Governance of the contract to a new account (`newGovernor`).\\n * Can only be called by the new Governor.\\n */\\n function claimGovernance() external {\\n require(\\n msg.sender == _pendingGovernor(),\\n \\\"Only the pending Governor can complete the claim\\\"\\n );\\n _changeGovernor(msg.sender);\\n }\\n\\n /**\\n * @dev Change Governance of the contract to a new account (`newGovernor`).\\n * @param _newGovernor Address of the new Governor\\n */\\n function _changeGovernor(address _newGovernor) internal {\\n require(_newGovernor != address(0), \\\"New Governor is address(0)\\\");\\n emit GovernorshipTransferred(_governor(), _newGovernor);\\n _setGovernor(_newGovernor);\\n }\\n}\\n\",\"keccak256\":\"0xb7133d6ce7a9e673ff79fcedb3fd41ae6e58e251f94915bb65731abe524270b4\",\"license\":\"MIT\"},\"contracts/interfaces/IBasicToken.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IBasicToken {\\n function symbol() external view returns (string memory);\\n\\n function decimals() external view returns (uint8);\\n}\\n\",\"keccak256\":\"0xa562062698aa12572123b36dfd2072f1a39e44fed2031cc19c2c9fd522f96ec2\",\"license\":\"MIT\"},\"contracts/interfaces/IOracle.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IOracle {\\n /**\\n * @dev returns the asset price in USD, in 8 decimal digits.\\n *\\n * The version of priceProvider deployed for OETH has 18 decimal digits\\n */\\n function price(address asset) external view returns (uint256);\\n}\\n\",\"keccak256\":\"0x9eabf152389f145c9c23ed71972af73fb1708cbc4b26e524a9ba29a557b7cfe5\",\"license\":\"MIT\"},\"contracts/interfaces/IStrategy.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Platform interface to integrate with lending platform like Compound, AAVE etc.\\n */\\ninterface IStrategy {\\n /**\\n * @dev Deposit the given asset to platform\\n * @param _asset asset address\\n * @param _amount Amount to deposit\\n */\\n function deposit(address _asset, uint256 _amount) external;\\n\\n /**\\n * @dev Deposit the entire balance of all supported assets in the Strategy\\n * to the platform\\n */\\n function depositAll() external;\\n\\n /**\\n * @dev Withdraw given asset from Lending platform\\n */\\n function withdraw(\\n address _recipient,\\n address _asset,\\n uint256 _amount\\n ) external;\\n\\n /**\\n * @dev Liquidate all assets in strategy and return them to Vault.\\n */\\n function withdrawAll() external;\\n\\n /**\\n * @dev Returns the current balance of the given asset.\\n */\\n function checkBalance(address _asset)\\n external\\n view\\n returns (uint256 balance);\\n\\n /**\\n * @dev Returns bool indicating whether strategy supports asset.\\n */\\n function supportsAsset(address _asset) external view returns (bool);\\n\\n /**\\n * @dev Collect reward tokens from the Strategy.\\n */\\n function collectRewardTokens() external;\\n\\n /**\\n * @dev The address array of the reward tokens for the Strategy.\\n */\\n function getRewardTokenAddresses() external view returns (address[] memory);\\n}\\n\",\"keccak256\":\"0xb291e409a9b95527f9ed19cd6bff8eeb9921a21c1f5194a48c0bb9ce6613959a\",\"license\":\"MIT\"},\"contracts/interfaces/ISwapper.sol\":{\"content\":\"pragma solidity ^0.8.0;\\n\\ninterface ISwapper {\\n /**\\n * @param fromAsset The token address of the asset being sold.\\n * @param toAsset The token address of the asset being purchased.\\n * @param fromAssetAmount The amount of assets being sold.\\n * @param minToAssetAmmount The minimum amount of assets to be purchased.\\n * @param data tx.data returned from 1Inch's /v5.0/1/swap API\\n */\\n function swap(\\n address fromAsset,\\n address toAsset,\\n uint256 fromAssetAmount,\\n uint256 minToAssetAmmount,\\n bytes calldata data\\n ) external returns (uint256 toAssetAmount);\\n}\\n\",\"keccak256\":\"0xf6452c70d5dbfde99e6e82cd6b49d8cbec8efb48da77e28603bea981b8b0759e\"},\"contracts/interfaces/IVault.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport { VaultStorage } from \\\"../vault/VaultStorage.sol\\\";\\n\\ninterface IVault {\\n event AssetSupported(address _asset);\\n event AssetDefaultStrategyUpdated(address _asset, address _strategy);\\n event AssetAllocated(address _asset, address _strategy, uint256 _amount);\\n event StrategyApproved(address _addr);\\n event StrategyRemoved(address _addr);\\n event Mint(address _addr, uint256 _value);\\n event Redeem(address _addr, uint256 _value);\\n event CapitalPaused();\\n event CapitalUnpaused();\\n event RebasePaused();\\n event RebaseUnpaused();\\n event VaultBufferUpdated(uint256 _vaultBuffer);\\n event RedeemFeeUpdated(uint256 _redeemFeeBps);\\n event PriceProviderUpdated(address _priceProvider);\\n event AllocateThresholdUpdated(uint256 _threshold);\\n event RebaseThresholdUpdated(uint256 _threshold);\\n event StrategistUpdated(address _address);\\n event MaxSupplyDiffChanged(uint256 maxSupplyDiff);\\n event YieldDistribution(address _to, uint256 _yield, uint256 _fee);\\n event TrusteeFeeBpsChanged(uint256 _basis);\\n event TrusteeAddressChanged(address _address);\\n event SwapperChanged(address _address);\\n event SwapAllowedUndervalueChanged(uint256 _basis);\\n event SwapSlippageChanged(address _asset, uint256 _basis);\\n event Swapped(\\n address indexed _fromAsset,\\n address indexed _toAsset,\\n uint256 _fromAssetAmount,\\n uint256 _toAssetAmount\\n );\\n event DripperChanged(address indexed _dripper);\\n event WithdrawalRequested(\\n address indexed _withdrawer,\\n uint256 indexed _requestId,\\n uint256 _amount,\\n uint256 _queued\\n );\\n event WithdrawalClaimed(\\n address indexed _withdrawer,\\n uint256 indexed _requestId,\\n uint256 _amount\\n );\\n event WithdrawalClaimable(uint256 _claimable, uint256 _newClaimable);\\n\\n // Governable.sol\\n function transferGovernance(address _newGovernor) external;\\n\\n function claimGovernance() external;\\n\\n function governor() external view returns (address);\\n\\n // VaultAdmin.sol\\n function setPriceProvider(address _priceProvider) external;\\n\\n function priceProvider() external view returns (address);\\n\\n function setRedeemFeeBps(uint256 _redeemFeeBps) external;\\n\\n function redeemFeeBps() external view returns (uint256);\\n\\n function setVaultBuffer(uint256 _vaultBuffer) external;\\n\\n function vaultBuffer() external view returns (uint256);\\n\\n function setAutoAllocateThreshold(uint256 _threshold) external;\\n\\n function autoAllocateThreshold() external view returns (uint256);\\n\\n function setRebaseThreshold(uint256 _threshold) external;\\n\\n function rebaseThreshold() external view returns (uint256);\\n\\n function setStrategistAddr(address _address) external;\\n\\n function strategistAddr() external view returns (address);\\n\\n function setMaxSupplyDiff(uint256 _maxSupplyDiff) external;\\n\\n function maxSupplyDiff() external view returns (uint256);\\n\\n function setTrusteeAddress(address _address) external;\\n\\n function trusteeAddress() external view returns (address);\\n\\n function setTrusteeFeeBps(uint256 _basis) external;\\n\\n function trusteeFeeBps() external view returns (uint256);\\n\\n function ousdMetaStrategy() external view returns (address);\\n\\n function setSwapper(address _swapperAddr) external;\\n\\n function setSwapAllowedUndervalue(uint16 _percentageBps) external;\\n\\n function setOracleSlippage(address _asset, uint16 _allowedOracleSlippageBps)\\n external;\\n\\n function supportAsset(address _asset, uint8 _supportsAsset) external;\\n\\n function approveStrategy(address _addr) external;\\n\\n function removeStrategy(address _addr) external;\\n\\n function setAssetDefaultStrategy(address _asset, address _strategy)\\n external;\\n\\n function assetDefaultStrategies(address _asset)\\n external\\n view\\n returns (address);\\n\\n function pauseRebase() external;\\n\\n function unpauseRebase() external;\\n\\n function rebasePaused() external view returns (bool);\\n\\n function pauseCapital() external;\\n\\n function unpauseCapital() external;\\n\\n function capitalPaused() external view returns (bool);\\n\\n function transferToken(address _asset, uint256 _amount) external;\\n\\n function priceUnitMint(address asset) external view returns (uint256);\\n\\n function priceUnitRedeem(address asset) external view returns (uint256);\\n\\n function withdrawAllFromStrategy(address _strategyAddr) external;\\n\\n function withdrawAllFromStrategies() external;\\n\\n function withdrawFromStrategy(\\n address _strategyFromAddress,\\n address[] calldata _assets,\\n uint256[] calldata _amounts\\n ) external;\\n\\n function depositToStrategy(\\n address _strategyToAddress,\\n address[] calldata _assets,\\n uint256[] calldata _amounts\\n ) external;\\n\\n // VaultCore.sol\\n function mint(\\n address _asset,\\n uint256 _amount,\\n uint256 _minimumOusdAmount\\n ) external;\\n\\n function mintForStrategy(uint256 _amount) external;\\n\\n function redeem(uint256 _amount, uint256 _minimumUnitAmount) external;\\n\\n function burnForStrategy(uint256 _amount) external;\\n\\n function redeemAll(uint256 _minimumUnitAmount) external;\\n\\n function allocate() external;\\n\\n function rebase() external;\\n\\n function swapCollateral(\\n address fromAsset,\\n address toAsset,\\n uint256 fromAssetAmount,\\n uint256 minToAssetAmount,\\n bytes calldata data\\n ) external returns (uint256 toAssetAmount);\\n\\n function totalValue() external view returns (uint256 value);\\n\\n function checkBalance(address _asset) external view returns (uint256);\\n\\n function calculateRedeemOutputs(uint256 _amount)\\n external\\n view\\n returns (uint256[] memory);\\n\\n function getAssetCount() external view returns (uint256);\\n\\n function getAssetConfig(address _asset)\\n external\\n view\\n returns (VaultStorage.Asset memory config);\\n\\n function getAllAssets() external view returns (address[] memory);\\n\\n function getStrategyCount() external view returns (uint256);\\n\\n function swapper() external view returns (address);\\n\\n function allowedSwapUndervalue() external view returns (uint256);\\n\\n function getAllStrategies() external view returns (address[] memory);\\n\\n function isSupportedAsset(address _asset) external view returns (bool);\\n\\n function netOusdMintForStrategyThreshold() external view returns (uint256);\\n\\n function setOusdMetaStrategy(address _ousdMetaStrategy) external;\\n\\n function setNetOusdMintForStrategyThreshold(uint256 _threshold) external;\\n\\n function netOusdMintedForStrategy() external view returns (int256);\\n\\n function setDripper(address _dripper) external;\\n\\n function weth() external view returns (address);\\n\\n function cacheWETHAssetIndex() external;\\n\\n function wethAssetIndex() external view returns (uint256);\\n\\n function initialize(address, address) external;\\n\\n function setAdminImpl(address) external;\\n\\n function removeAsset(address _asset) external;\\n\\n // These are OETH specific functions\\n function addWithdrawalQueueLiquidity() external;\\n\\n function requestWithdrawal(uint256 _amount)\\n external\\n returns (uint256 requestId, uint256 queued);\\n\\n function claimWithdrawal(uint256 requestId)\\n external\\n returns (uint256 amount);\\n\\n function claimWithdrawals(uint256[] memory requestIds)\\n external\\n returns (uint256[] memory amounts, uint256 totalAmount);\\n\\n function withdrawalQueueMetadata()\\n external\\n view\\n returns (VaultStorage.WithdrawalQueueMetadata memory);\\n\\n function withdrawalRequests(uint256 requestId)\\n external\\n view\\n returns (VaultStorage.WithdrawalRequest memory);\\n}\\n\",\"keccak256\":\"0x5cc3617c2dfed68097a4dc754f17c6c32dd6e11038e6fc9c18ff6f68cd6b029f\",\"license\":\"MIT\"},\"contracts/token/OUSD.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title OUSD Token Contract\\n * @dev ERC20 compatible contract for OUSD\\n * @dev Implements an elastic supply\\n * @author Origin Protocol Inc\\n */\\nimport { SafeMath } from \\\"@openzeppelin/contracts/utils/math/SafeMath.sol\\\";\\nimport { Address } from \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\n\\nimport { Initializable } from \\\"../utils/Initializable.sol\\\";\\nimport { InitializableERC20Detailed } from \\\"../utils/InitializableERC20Detailed.sol\\\";\\nimport { StableMath } from \\\"../utils/StableMath.sol\\\";\\nimport { Governable } from \\\"../governance/Governable.sol\\\";\\n\\n/**\\n * NOTE that this is an ERC20 token but the invariant that the sum of\\n * balanceOf(x) for all x is not >= totalSupply(). This is a consequence of the\\n * rebasing design. Any integrations with OUSD should be aware.\\n */\\n\\ncontract OUSD is Initializable, InitializableERC20Detailed, Governable {\\n using SafeMath for uint256;\\n using StableMath for uint256;\\n\\n event TotalSupplyUpdatedHighres(\\n uint256 totalSupply,\\n uint256 rebasingCredits,\\n uint256 rebasingCreditsPerToken\\n );\\n event AccountRebasingEnabled(address account);\\n event AccountRebasingDisabled(address account);\\n\\n enum RebaseOptions {\\n NotSet,\\n OptOut,\\n OptIn\\n }\\n\\n uint256 private constant MAX_SUPPLY = ~uint128(0); // (2^128) - 1\\n uint256 public _totalSupply;\\n mapping(address => mapping(address => uint256)) private _allowances;\\n address public vaultAddress = address(0);\\n mapping(address => uint256) private _creditBalances;\\n uint256 private _rebasingCredits;\\n uint256 private _rebasingCreditsPerToken;\\n // Frozen address/credits are non rebasing (value is held in contracts which\\n // do not receive yield unless they explicitly opt in)\\n uint256 public nonRebasingSupply;\\n mapping(address => uint256) public nonRebasingCreditsPerToken;\\n mapping(address => RebaseOptions) public rebaseState;\\n mapping(address => uint256) public isUpgraded;\\n\\n uint256 private constant RESOLUTION_INCREASE = 1e9;\\n\\n function initialize(\\n string calldata _nameArg,\\n string calldata _symbolArg,\\n address _vaultAddress,\\n uint256 _initialCreditsPerToken\\n ) external onlyGovernor initializer {\\n InitializableERC20Detailed._initialize(_nameArg, _symbolArg, 18);\\n _rebasingCreditsPerToken = _initialCreditsPerToken;\\n vaultAddress = _vaultAddress;\\n }\\n\\n /**\\n * @dev Verifies that the caller is the Vault contract\\n */\\n modifier onlyVault() {\\n require(vaultAddress == msg.sender, \\\"Caller is not the Vault\\\");\\n _;\\n }\\n\\n /**\\n * @return The total supply of OUSD.\\n */\\n function totalSupply() public view override returns (uint256) {\\n return _totalSupply;\\n }\\n\\n /**\\n * @return Low resolution rebasingCreditsPerToken\\n */\\n function rebasingCreditsPerToken() public view returns (uint256) {\\n return _rebasingCreditsPerToken / RESOLUTION_INCREASE;\\n }\\n\\n /**\\n * @return Low resolution total number of rebasing credits\\n */\\n function rebasingCredits() public view returns (uint256) {\\n return _rebasingCredits / RESOLUTION_INCREASE;\\n }\\n\\n /**\\n * @return High resolution rebasingCreditsPerToken\\n */\\n function rebasingCreditsPerTokenHighres() public view returns (uint256) {\\n return _rebasingCreditsPerToken;\\n }\\n\\n /**\\n * @return High resolution total number of rebasing credits\\n */\\n function rebasingCreditsHighres() public view returns (uint256) {\\n return _rebasingCredits;\\n }\\n\\n /**\\n * @dev Gets the balance of the specified address.\\n * @param _account Address to query the balance of.\\n * @return A uint256 representing the amount of base units owned by the\\n * specified address.\\n */\\n function balanceOf(address _account)\\n public\\n view\\n override\\n returns (uint256)\\n {\\n if (_creditBalances[_account] == 0) return 0;\\n return\\n _creditBalances[_account].divPrecisely(_creditsPerToken(_account));\\n }\\n\\n /**\\n * @dev Gets the credits balance of the specified address.\\n * @dev Backwards compatible with old low res credits per token.\\n * @param _account The address to query the balance of.\\n * @return (uint256, uint256) Credit balance and credits per token of the\\n * address\\n */\\n function creditsBalanceOf(address _account)\\n public\\n view\\n returns (uint256, uint256)\\n {\\n uint256 cpt = _creditsPerToken(_account);\\n if (cpt == 1e27) {\\n // For a period before the resolution upgrade, we created all new\\n // contract accounts at high resolution. Since they are not changing\\n // as a result of this upgrade, we will return their true values\\n return (_creditBalances[_account], cpt);\\n } else {\\n return (\\n _creditBalances[_account] / RESOLUTION_INCREASE,\\n cpt / RESOLUTION_INCREASE\\n );\\n }\\n }\\n\\n /**\\n * @dev Gets the credits balance of the specified address.\\n * @param _account The address to query the balance of.\\n * @return (uint256, uint256, bool) Credit balance, credits per token of the\\n * address, and isUpgraded\\n */\\n function creditsBalanceOfHighres(address _account)\\n public\\n view\\n returns (\\n uint256,\\n uint256,\\n bool\\n )\\n {\\n return (\\n _creditBalances[_account],\\n _creditsPerToken(_account),\\n isUpgraded[_account] == 1\\n );\\n }\\n\\n /**\\n * @dev Transfer tokens to a specified address.\\n * @param _to the address to transfer to.\\n * @param _value the amount to be transferred.\\n * @return true on success.\\n */\\n function transfer(address _to, uint256 _value)\\n public\\n override\\n returns (bool)\\n {\\n require(_to != address(0), \\\"Transfer to zero address\\\");\\n require(\\n _value <= balanceOf(msg.sender),\\n \\\"Transfer greater than balance\\\"\\n );\\n\\n _executeTransfer(msg.sender, _to, _value);\\n\\n emit Transfer(msg.sender, _to, _value);\\n\\n return true;\\n }\\n\\n /**\\n * @dev Transfer tokens from one address to another.\\n * @param _from The address you want to send tokens from.\\n * @param _to The address you want to transfer to.\\n * @param _value The amount of tokens to be transferred.\\n */\\n function transferFrom(\\n address _from,\\n address _to,\\n uint256 _value\\n ) public override returns (bool) {\\n require(_to != address(0), \\\"Transfer to zero address\\\");\\n require(_value <= balanceOf(_from), \\\"Transfer greater than balance\\\");\\n\\n _allowances[_from][msg.sender] = _allowances[_from][msg.sender].sub(\\n _value\\n );\\n\\n _executeTransfer(_from, _to, _value);\\n\\n emit Transfer(_from, _to, _value);\\n\\n return true;\\n }\\n\\n /**\\n * @dev Update the count of non rebasing credits in response to a transfer\\n * @param _from The address you want to send tokens from.\\n * @param _to The address you want to transfer to.\\n * @param _value Amount of OUSD to transfer\\n */\\n function _executeTransfer(\\n address _from,\\n address _to,\\n uint256 _value\\n ) internal {\\n bool isNonRebasingTo = _isNonRebasingAccount(_to);\\n bool isNonRebasingFrom = _isNonRebasingAccount(_from);\\n\\n // Credits deducted and credited might be different due to the\\n // differing creditsPerToken used by each account\\n uint256 creditsCredited = _value.mulTruncate(_creditsPerToken(_to));\\n uint256 creditsDeducted = _value.mulTruncate(_creditsPerToken(_from));\\n\\n _creditBalances[_from] = _creditBalances[_from].sub(\\n creditsDeducted,\\n \\\"Transfer amount exceeds balance\\\"\\n );\\n _creditBalances[_to] = _creditBalances[_to].add(creditsCredited);\\n\\n if (isNonRebasingTo && !isNonRebasingFrom) {\\n // Transfer to non-rebasing account from rebasing account, credits\\n // are removed from the non rebasing tally\\n nonRebasingSupply = nonRebasingSupply.add(_value);\\n // Update rebasingCredits by subtracting the deducted amount\\n _rebasingCredits = _rebasingCredits.sub(creditsDeducted);\\n } else if (!isNonRebasingTo && isNonRebasingFrom) {\\n // Transfer to rebasing account from non-rebasing account\\n // Decreasing non-rebasing credits by the amount that was sent\\n nonRebasingSupply = nonRebasingSupply.sub(_value);\\n // Update rebasingCredits by adding the credited amount\\n _rebasingCredits = _rebasingCredits.add(creditsCredited);\\n }\\n }\\n\\n /**\\n * @dev Function to check the amount of tokens that _owner has allowed to\\n * `_spender`.\\n * @param _owner The address which owns the funds.\\n * @param _spender The address which will spend the funds.\\n * @return The number of tokens still available for the _spender.\\n */\\n function allowance(address _owner, address _spender)\\n public\\n view\\n override\\n returns (uint256)\\n {\\n return _allowances[_owner][_spender];\\n }\\n\\n /**\\n * @dev Approve the passed address to spend the specified amount of tokens\\n * on behalf of msg.sender. This method is included for ERC20\\n * compatibility. `increaseAllowance` and `decreaseAllowance` should be\\n * used instead.\\n *\\n * Changing an allowance with this method brings the risk that someone\\n * may transfer both the old and the new allowance - if they are both\\n * greater than zero - if a transfer transaction is mined before the\\n * later approve() call is mined.\\n * @param _spender The address which will spend the funds.\\n * @param _value The amount of tokens to be spent.\\n */\\n function approve(address _spender, uint256 _value)\\n public\\n override\\n returns (bool)\\n {\\n _allowances[msg.sender][_spender] = _value;\\n emit Approval(msg.sender, _spender, _value);\\n return true;\\n }\\n\\n /**\\n * @dev Increase the amount of tokens that an owner has allowed to\\n * `_spender`.\\n * This method should be used instead of approve() to avoid the double\\n * approval vulnerability described above.\\n * @param _spender The address which will spend the funds.\\n * @param _addedValue The amount of tokens to increase the allowance by.\\n */\\n function increaseAllowance(address _spender, uint256 _addedValue)\\n public\\n returns (bool)\\n {\\n _allowances[msg.sender][_spender] = _allowances[msg.sender][_spender]\\n .add(_addedValue);\\n emit Approval(msg.sender, _spender, _allowances[msg.sender][_spender]);\\n return true;\\n }\\n\\n /**\\n * @dev Decrease the amount of tokens that an owner has allowed to\\n `_spender`.\\n * @param _spender The address which will spend the funds.\\n * @param _subtractedValue The amount of tokens to decrease the allowance\\n * by.\\n */\\n function decreaseAllowance(address _spender, uint256 _subtractedValue)\\n public\\n returns (bool)\\n {\\n uint256 oldValue = _allowances[msg.sender][_spender];\\n if (_subtractedValue >= oldValue) {\\n _allowances[msg.sender][_spender] = 0;\\n } else {\\n _allowances[msg.sender][_spender] = oldValue.sub(_subtractedValue);\\n }\\n emit Approval(msg.sender, _spender, _allowances[msg.sender][_spender]);\\n return true;\\n }\\n\\n /**\\n * @dev Mints new tokens, increasing totalSupply.\\n */\\n function mint(address _account, uint256 _amount) external onlyVault {\\n _mint(_account, _amount);\\n }\\n\\n /**\\n * @dev Creates `_amount` tokens and assigns them to `_account`, increasing\\n * the total supply.\\n *\\n * Emits a {Transfer} event with `from` set to the zero address.\\n *\\n * Requirements\\n *\\n * - `to` cannot be the zero address.\\n */\\n function _mint(address _account, uint256 _amount) internal nonReentrant {\\n require(_account != address(0), \\\"Mint to the zero address\\\");\\n\\n bool isNonRebasingAccount = _isNonRebasingAccount(_account);\\n\\n uint256 creditAmount = _amount.mulTruncate(_creditsPerToken(_account));\\n _creditBalances[_account] = _creditBalances[_account].add(creditAmount);\\n\\n // If the account is non rebasing and doesn't have a set creditsPerToken\\n // then set it i.e. this is a mint from a fresh contract\\n if (isNonRebasingAccount) {\\n nonRebasingSupply = nonRebasingSupply.add(_amount);\\n } else {\\n _rebasingCredits = _rebasingCredits.add(creditAmount);\\n }\\n\\n _totalSupply = _totalSupply.add(_amount);\\n\\n require(_totalSupply < MAX_SUPPLY, \\\"Max supply\\\");\\n\\n emit Transfer(address(0), _account, _amount);\\n }\\n\\n /**\\n * @dev Burns tokens, decreasing totalSupply.\\n */\\n function burn(address account, uint256 amount) external onlyVault {\\n _burn(account, amount);\\n }\\n\\n /**\\n * @dev Destroys `_amount` tokens from `_account`, reducing the\\n * total supply.\\n *\\n * Emits a {Transfer} event with `to` set to the zero address.\\n *\\n * Requirements\\n *\\n * - `_account` cannot be the zero address.\\n * - `_account` must have at least `_amount` tokens.\\n */\\n function _burn(address _account, uint256 _amount) internal nonReentrant {\\n require(_account != address(0), \\\"Burn from the zero address\\\");\\n if (_amount == 0) {\\n return;\\n }\\n\\n bool isNonRebasingAccount = _isNonRebasingAccount(_account);\\n uint256 creditAmount = _amount.mulTruncate(_creditsPerToken(_account));\\n uint256 currentCredits = _creditBalances[_account];\\n\\n // Remove the credits, burning rounding errors\\n if (\\n currentCredits == creditAmount || currentCredits - 1 == creditAmount\\n ) {\\n // Handle dust from rounding\\n _creditBalances[_account] = 0;\\n } else if (currentCredits > creditAmount) {\\n _creditBalances[_account] = _creditBalances[_account].sub(\\n creditAmount\\n );\\n } else {\\n revert(\\\"Remove exceeds balance\\\");\\n }\\n\\n // Remove from the credit tallies and non-rebasing supply\\n if (isNonRebasingAccount) {\\n nonRebasingSupply = nonRebasingSupply.sub(_amount);\\n } else {\\n _rebasingCredits = _rebasingCredits.sub(creditAmount);\\n }\\n\\n _totalSupply = _totalSupply.sub(_amount);\\n\\n emit Transfer(_account, address(0), _amount);\\n }\\n\\n /**\\n * @dev Get the credits per token for an account. Returns a fixed amount\\n * if the account is non-rebasing.\\n * @param _account Address of the account.\\n */\\n function _creditsPerToken(address _account)\\n internal\\n view\\n returns (uint256)\\n {\\n if (nonRebasingCreditsPerToken[_account] != 0) {\\n return nonRebasingCreditsPerToken[_account];\\n } else {\\n return _rebasingCreditsPerToken;\\n }\\n }\\n\\n /**\\n * @dev Is an account using rebasing accounting or non-rebasing accounting?\\n * Also, ensure contracts are non-rebasing if they have not opted in.\\n * @param _account Address of the account.\\n */\\n function _isNonRebasingAccount(address _account) internal returns (bool) {\\n bool isContract = Address.isContract(_account);\\n if (isContract && rebaseState[_account] == RebaseOptions.NotSet) {\\n _ensureRebasingMigration(_account);\\n }\\n return nonRebasingCreditsPerToken[_account] > 0;\\n }\\n\\n /**\\n * @dev Ensures internal account for rebasing and non-rebasing credits and\\n * supply is updated following deployment of frozen yield change.\\n */\\n function _ensureRebasingMigration(address _account) internal {\\n if (nonRebasingCreditsPerToken[_account] == 0) {\\n emit AccountRebasingDisabled(_account);\\n if (_creditBalances[_account] == 0) {\\n // Since there is no existing balance, we can directly set to\\n // high resolution, and do not have to do any other bookkeeping\\n nonRebasingCreditsPerToken[_account] = 1e27;\\n } else {\\n // Migrate an existing account:\\n\\n // Set fixed credits per token for this account\\n nonRebasingCreditsPerToken[_account] = _rebasingCreditsPerToken;\\n // Update non rebasing supply\\n nonRebasingSupply = nonRebasingSupply.add(balanceOf(_account));\\n // Update credit tallies\\n _rebasingCredits = _rebasingCredits.sub(\\n _creditBalances[_account]\\n );\\n }\\n }\\n }\\n\\n /**\\n * @notice Enable rebasing for an account.\\n * @dev Add a contract address to the non-rebasing exception list. The\\n * address's balance will be part of rebases and the account will be exposed\\n * to upside and downside.\\n * @param _account Address of the account.\\n */\\n function governanceRebaseOptIn(address _account)\\n public\\n nonReentrant\\n onlyGovernor\\n {\\n _rebaseOptIn(_account);\\n }\\n\\n /**\\n * @dev Add a contract address to the non-rebasing exception list. The\\n * address's balance will be part of rebases and the account will be exposed\\n * to upside and downside.\\n */\\n function rebaseOptIn() public nonReentrant {\\n _rebaseOptIn(msg.sender);\\n }\\n\\n function _rebaseOptIn(address _account) internal {\\n require(_isNonRebasingAccount(_account), \\\"Account has not opted out\\\");\\n\\n // Convert balance into the same amount at the current exchange rate\\n uint256 newCreditBalance = _creditBalances[_account]\\n .mul(_rebasingCreditsPerToken)\\n .div(_creditsPerToken(_account));\\n\\n // Decreasing non rebasing supply\\n nonRebasingSupply = nonRebasingSupply.sub(balanceOf(_account));\\n\\n _creditBalances[_account] = newCreditBalance;\\n\\n // Increase rebasing credits, totalSupply remains unchanged so no\\n // adjustment necessary\\n _rebasingCredits = _rebasingCredits.add(_creditBalances[_account]);\\n\\n rebaseState[_account] = RebaseOptions.OptIn;\\n\\n // Delete any fixed credits per token\\n delete nonRebasingCreditsPerToken[_account];\\n emit AccountRebasingEnabled(_account);\\n }\\n\\n /**\\n * @dev Explicitly mark that an address is non-rebasing.\\n */\\n function rebaseOptOut() public nonReentrant {\\n require(!_isNonRebasingAccount(msg.sender), \\\"Account has not opted in\\\");\\n\\n // Increase non rebasing supply\\n nonRebasingSupply = nonRebasingSupply.add(balanceOf(msg.sender));\\n // Set fixed credits per token\\n nonRebasingCreditsPerToken[msg.sender] = _rebasingCreditsPerToken;\\n\\n // Decrease rebasing credits, total supply remains unchanged so no\\n // adjustment necessary\\n _rebasingCredits = _rebasingCredits.sub(_creditBalances[msg.sender]);\\n\\n // Mark explicitly opted out of rebasing\\n rebaseState[msg.sender] = RebaseOptions.OptOut;\\n emit AccountRebasingDisabled(msg.sender);\\n }\\n\\n /**\\n * @dev Modify the supply without minting new tokens. This uses a change in\\n * the exchange rate between \\\"credits\\\" and OUSD tokens to change balances.\\n * @param _newTotalSupply New total supply of OUSD.\\n */\\n function changeSupply(uint256 _newTotalSupply)\\n external\\n onlyVault\\n nonReentrant\\n {\\n require(_totalSupply > 0, \\\"Cannot increase 0 supply\\\");\\n\\n if (_totalSupply == _newTotalSupply) {\\n emit TotalSupplyUpdatedHighres(\\n _totalSupply,\\n _rebasingCredits,\\n _rebasingCreditsPerToken\\n );\\n return;\\n }\\n\\n _totalSupply = _newTotalSupply > MAX_SUPPLY\\n ? MAX_SUPPLY\\n : _newTotalSupply;\\n\\n _rebasingCreditsPerToken = _rebasingCredits.divPrecisely(\\n _totalSupply.sub(nonRebasingSupply)\\n );\\n\\n require(_rebasingCreditsPerToken > 0, \\\"Invalid change in supply\\\");\\n\\n _totalSupply = _rebasingCredits\\n .divPrecisely(_rebasingCreditsPerToken)\\n .add(nonRebasingSupply);\\n\\n emit TotalSupplyUpdatedHighres(\\n _totalSupply,\\n _rebasingCredits,\\n _rebasingCreditsPerToken\\n );\\n }\\n}\\n\",\"keccak256\":\"0x2dc66b1ba02716d64eb47dd9117fda62650d8b57669e6c351437e0ad29ad5f19\",\"license\":\"MIT\"},\"contracts/utils/Helpers.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport { IBasicToken } from \\\"../interfaces/IBasicToken.sol\\\";\\n\\nlibrary Helpers {\\n /**\\n * @notice Fetch the `symbol()` from an ERC20 token\\n * @dev Grabs the `symbol()` from a contract\\n * @param _token Address of the ERC20 token\\n * @return string Symbol of the ERC20 token\\n */\\n function getSymbol(address _token) internal view returns (string memory) {\\n string memory symbol = IBasicToken(_token).symbol();\\n return symbol;\\n }\\n\\n /**\\n * @notice Fetch the `decimals()` from an ERC20 token\\n * @dev Grabs the `decimals()` from a contract and fails if\\n * the decimal value does not live within a certain range\\n * @param _token Address of the ERC20 token\\n * @return uint256 Decimals of the ERC20 token\\n */\\n function getDecimals(address _token) internal view returns (uint256) {\\n uint256 decimals = IBasicToken(_token).decimals();\\n require(\\n decimals >= 4 && decimals <= 18,\\n \\\"Token must have sufficient decimal places\\\"\\n );\\n\\n return decimals;\\n }\\n}\\n\",\"keccak256\":\"0x108b7a69e0140da0072ca18f90a03a3340574400f81aa6076cd2cccdf13699c2\",\"license\":\"MIT\"},\"contracts/utils/Initializable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Base contract any contracts that need to initialize state after deployment.\\n * @author Origin Protocol Inc\\n */\\nabstract contract Initializable {\\n /**\\n * @dev Indicates that the contract has been initialized.\\n */\\n bool private initialized;\\n\\n /**\\n * @dev Indicates that the contract is in the process of being initialized.\\n */\\n bool private initializing;\\n\\n /**\\n * @dev Modifier to protect an initializer function from being invoked twice.\\n */\\n modifier initializer() {\\n require(\\n initializing || !initialized,\\n \\\"Initializable: contract is already initialized\\\"\\n );\\n\\n bool isTopLevelCall = !initializing;\\n if (isTopLevelCall) {\\n initializing = true;\\n initialized = true;\\n }\\n\\n _;\\n\\n if (isTopLevelCall) {\\n initializing = false;\\n }\\n }\\n\\n uint256[50] private ______gap;\\n}\\n\",\"keccak256\":\"0xaadbcc138114afed4af4f353c2ced2916e6ee14be91434789187f192caf0d786\",\"license\":\"MIT\"},\"contracts/utils/InitializableERC20Detailed.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport { IERC20 } from \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @dev Optional functions from the ERC20 standard.\\n * Converted from openzeppelin/contracts/token/ERC20/ERC20Detailed.sol\\n * @author Origin Protocol Inc\\n */\\nabstract contract InitializableERC20Detailed is IERC20 {\\n // Storage gap to skip storage from prior to OUSD reset\\n uint256[100] private _____gap;\\n\\n string private _name;\\n string private _symbol;\\n uint8 private _decimals;\\n\\n /**\\n * @dev Sets the values for `name`, `symbol`, and `decimals`. All three of\\n * these values are immutable: they can only be set once during\\n * construction.\\n * @notice To avoid variable shadowing appended `Arg` after arguments name.\\n */\\n function _initialize(\\n string memory nameArg,\\n string memory symbolArg,\\n uint8 decimalsArg\\n ) internal {\\n _name = nameArg;\\n _symbol = symbolArg;\\n _decimals = decimalsArg;\\n }\\n\\n /**\\n * @notice Returns the name of the token.\\n */\\n function name() public view returns (string memory) {\\n return _name;\\n }\\n\\n /**\\n * @notice Returns the symbol of the token, usually a shorter version of the\\n * name.\\n */\\n function symbol() public view returns (string memory) {\\n return _symbol;\\n }\\n\\n /**\\n * @notice Returns the number of decimals used to get its user representation.\\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\\n * be displayed to a user as `5,05` (`505 / 10 ** 2`).\\n *\\n * Tokens usually opt for a value of 18, imitating the relationship between\\n * Ether and Wei.\\n *\\n * NOTE: This information is only used for _display_ purposes: it in\\n * no way affects any of the arithmetic of the contract, including\\n * {IERC20-balanceOf} and {IERC20-transfer}.\\n */\\n function decimals() public view returns (uint8) {\\n return _decimals;\\n }\\n}\\n\",\"keccak256\":\"0xe35ac2d813a30d845a3b52bba72588d7e936c2b3f3373d15568c14db46aeed60\",\"license\":\"MIT\"},\"contracts/utils/StableMath.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport { SafeMath } from \\\"@openzeppelin/contracts/utils/math/SafeMath.sol\\\";\\n\\n// Based on StableMath from Stability Labs Pty. Ltd.\\n// https://github.com/mstable/mStable-contracts/blob/master/contracts/shared/StableMath.sol\\n\\nlibrary StableMath {\\n using SafeMath for uint256;\\n\\n /**\\n * @dev Scaling unit for use in specific calculations,\\n * where 1 * 10**18, or 1e18 represents a unit '1'\\n */\\n uint256 private constant FULL_SCALE = 1e18;\\n\\n /***************************************\\n Helpers\\n ****************************************/\\n\\n /**\\n * @dev Adjust the scale of an integer\\n * @param to Decimals to scale to\\n * @param from Decimals to scale from\\n */\\n function scaleBy(\\n uint256 x,\\n uint256 to,\\n uint256 from\\n ) internal pure returns (uint256) {\\n if (to > from) {\\n x = x.mul(10**(to - from));\\n } else if (to < from) {\\n // slither-disable-next-line divide-before-multiply\\n x = x.div(10**(from - to));\\n }\\n return x;\\n }\\n\\n /***************************************\\n Precise Arithmetic\\n ****************************************/\\n\\n /**\\n * @dev Multiplies two precise units, and then truncates by the full scale\\n * @param x Left hand input to multiplication\\n * @param y Right hand input to multiplication\\n * @return Result after multiplying the two inputs and then dividing by the shared\\n * scale unit\\n */\\n function mulTruncate(uint256 x, uint256 y) internal pure returns (uint256) {\\n return mulTruncateScale(x, y, FULL_SCALE);\\n }\\n\\n /**\\n * @dev Multiplies two precise units, and then truncates by the given scale. For example,\\n * when calculating 90% of 10e18, (10e18 * 9e17) / 1e18 = (9e36) / 1e18 = 9e18\\n * @param x Left hand input to multiplication\\n * @param y Right hand input to multiplication\\n * @param scale Scale unit\\n * @return Result after multiplying the two inputs and then dividing by the shared\\n * scale unit\\n */\\n function mulTruncateScale(\\n uint256 x,\\n uint256 y,\\n uint256 scale\\n ) internal pure returns (uint256) {\\n // e.g. assume scale = fullScale\\n // z = 10e18 * 9e17 = 9e36\\n uint256 z = x.mul(y);\\n // return 9e36 / 1e18 = 9e18\\n return z.div(scale);\\n }\\n\\n /**\\n * @dev Multiplies two precise units, and then truncates by the full scale, rounding up the result\\n * @param x Left hand input to multiplication\\n * @param y Right hand input to multiplication\\n * @return Result after multiplying the two inputs and then dividing by the shared\\n * scale unit, rounded up to the closest base unit.\\n */\\n function mulTruncateCeil(uint256 x, uint256 y)\\n internal\\n pure\\n returns (uint256)\\n {\\n // e.g. 8e17 * 17268172638 = 138145381104e17\\n uint256 scaled = x.mul(y);\\n // e.g. 138145381104e17 + 9.99...e17 = 138145381113.99...e17\\n uint256 ceil = scaled.add(FULL_SCALE.sub(1));\\n // e.g. 13814538111.399...e18 / 1e18 = 13814538111\\n return ceil.div(FULL_SCALE);\\n }\\n\\n /**\\n * @dev Precisely divides two units, by first scaling the left hand operand. Useful\\n * for finding percentage weightings, i.e. 8e18/10e18 = 80% (or 8e17)\\n * @param x Left hand input to division\\n * @param y Right hand input to division\\n * @return Result after multiplying the left operand by the scale, and\\n * executing the division on the right hand input.\\n */\\n function divPrecisely(uint256 x, uint256 y)\\n internal\\n pure\\n returns (uint256)\\n {\\n // e.g. 8e18 * 1e18 = 8e36\\n uint256 z = x.mul(FULL_SCALE);\\n // e.g. 8e36 / 10e18 = 8e17\\n return z.div(y);\\n }\\n}\\n\",\"keccak256\":\"0x1eb49f6f79045d9e0a8e1dced8e01d9e559e5fac554dcbb53e43140b601b04e7\",\"license\":\"MIT\"},\"contracts/vault/OETHVaultAdmin.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport { SafeERC20 } from \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\nimport { IERC20 } from \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\nimport { IStrategy } from \\\"../interfaces/IStrategy.sol\\\";\\nimport { IVault } from \\\"../interfaces/IVault.sol\\\";\\nimport { VaultAdmin } from \\\"./VaultAdmin.sol\\\";\\n\\n/**\\n * @title OETH VaultAdmin Contract\\n * @author Origin Protocol Inc\\n */\\ncontract OETHVaultAdmin is VaultAdmin {\\n using SafeERC20 for IERC20;\\n\\n address public immutable weth;\\n\\n constructor(address _weth) {\\n weth = _weth;\\n }\\n\\n /// @dev Simplified version of the deposit function as WETH is the only supported asset.\\n function _depositToStrategy(\\n address _strategyToAddress,\\n address[] calldata _assets,\\n uint256[] calldata _amounts\\n ) internal override {\\n require(\\n strategies[_strategyToAddress].isSupported,\\n \\\"Invalid to Strategy\\\"\\n );\\n require(\\n _assets.length == 1 && _amounts.length == 1 && _assets[0] == weth,\\n \\\"Only WETH is supported\\\"\\n );\\n\\n // Check the there is enough WETH to transfer once the WETH reserved for the withdrawal queue is accounted for\\n require(_amounts[0] <= _wethAvailable(), \\\"Not enough WETH available\\\");\\n\\n // Send required amount of funds to the strategy\\n IERC20(weth).safeTransfer(_strategyToAddress, _amounts[0]);\\n\\n // Deposit all the funds that have been sent to the strategy\\n IStrategy(_strategyToAddress).depositAll();\\n }\\n\\n function _withdrawFromStrategy(\\n address _recipient,\\n address _strategyFromAddress,\\n address[] calldata _assets,\\n uint256[] calldata _amounts\\n ) internal override {\\n super._withdrawFromStrategy(\\n _recipient,\\n _strategyFromAddress,\\n _assets,\\n _amounts\\n );\\n\\n IVault(address(this)).addWithdrawalQueueLiquidity();\\n }\\n\\n function _withdrawAllFromStrategy(address _strategyAddr) internal override {\\n super._withdrawAllFromStrategy(_strategyAddr);\\n\\n IVault(address(this)).addWithdrawalQueueLiquidity();\\n }\\n\\n function _withdrawAllFromStrategies() internal override {\\n super._withdrawAllFromStrategies();\\n\\n IVault(address(this)).addWithdrawalQueueLiquidity();\\n }\\n\\n // TODO move to a library?\\n function _wethAvailable() internal view returns (uint256 wethAvailable) {\\n WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata;\\n\\n // Check if the claimable WETH is less than the queued amount\\n uint256 queueShortfall = queue.queued - queue.claimable;\\n uint256 wethBalance = IERC20(weth).balanceOf(address(this));\\n // Of the claimable withdrawal requests, how much is unclaimed?\\n uint256 unclaimed = queue.claimable - queue.claimed;\\n\\n if (wethBalance > queueShortfall + unclaimed) {\\n wethAvailable = wethBalance - queueShortfall - unclaimed;\\n }\\n }\\n\\n function _swapCollateral(\\n address _fromAsset,\\n address _toAsset,\\n uint256 _fromAssetAmount,\\n uint256 _minToAssetAmount,\\n bytes calldata _data\\n ) internal override returns (uint256 toAssetAmount) {\\n require(_fromAsset != weth, \\\"swap from WETH not supported\\\");\\n require(_toAsset == weth, \\\"only swap to WETH\\\");\\n toAssetAmount = super._swapCollateral(\\n _fromAsset,\\n _toAsset,\\n _fromAssetAmount,\\n _minToAssetAmount,\\n _data\\n );\\n\\n // Add any new WETH to the withdrawal queue first\\n IVault(address(this)).addWithdrawalQueueLiquidity();\\n }\\n}\\n\",\"keccak256\":\"0x4c322850471633079ed3648094b4b3f166dbe2da6ce143edce47c999e51cbd0b\",\"license\":\"MIT\"},\"contracts/vault/VaultAdmin.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title OToken VaultAdmin contract\\n * @notice The VaultAdmin contract makes configuration and admin calls on the vault.\\n * @author Origin Protocol Inc\\n */\\n\\nimport { SafeERC20 } from \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\n\\nimport { IOracle } from \\\"../interfaces/IOracle.sol\\\";\\nimport { ISwapper } from \\\"../interfaces/ISwapper.sol\\\";\\nimport { IVault } from \\\"../interfaces/IVault.sol\\\";\\nimport { StableMath } from \\\"../utils/StableMath.sol\\\";\\n\\nimport \\\"./VaultStorage.sol\\\";\\n\\ncontract VaultAdmin is VaultStorage {\\n using SafeERC20 for IERC20;\\n using StableMath for uint256;\\n\\n /**\\n * @dev Verifies that the caller is the Governor or Strategist.\\n */\\n modifier onlyGovernorOrStrategist() {\\n require(\\n msg.sender == strategistAddr || isGovernor(),\\n \\\"Caller is not the Strategist or Governor\\\"\\n );\\n _;\\n }\\n\\n /***************************************\\n Configuration\\n ****************************************/\\n\\n /**\\n * @notice Set address of price provider.\\n * @param _priceProvider Address of price provider\\n */\\n function setPriceProvider(address _priceProvider) external onlyGovernor {\\n priceProvider = _priceProvider;\\n emit PriceProviderUpdated(_priceProvider);\\n }\\n\\n /**\\n * @notice Set a fee in basis points to be charged for a redeem.\\n * @param _redeemFeeBps Basis point fee to be charged\\n */\\n function setRedeemFeeBps(uint256 _redeemFeeBps) external onlyGovernor {\\n require(_redeemFeeBps <= 1000, \\\"Redeem fee should not be over 10%\\\");\\n redeemFeeBps = _redeemFeeBps;\\n emit RedeemFeeUpdated(_redeemFeeBps);\\n }\\n\\n /**\\n * @notice Set a buffer of assets to keep in the Vault to handle most\\n * redemptions without needing to spend gas unwinding assets from a Strategy.\\n * @param _vaultBuffer Percentage using 18 decimals. 100% = 1e18.\\n */\\n function setVaultBuffer(uint256 _vaultBuffer)\\n external\\n onlyGovernorOrStrategist\\n {\\n require(_vaultBuffer <= 1e18, \\\"Invalid value\\\");\\n vaultBuffer = _vaultBuffer;\\n emit VaultBufferUpdated(_vaultBuffer);\\n }\\n\\n /**\\n * @notice Sets the minimum amount of OTokens in a mint to trigger an\\n * automatic allocation of funds afterwords.\\n * @param _threshold OToken amount with 18 fixed decimals.\\n */\\n function setAutoAllocateThreshold(uint256 _threshold)\\n external\\n onlyGovernor\\n {\\n autoAllocateThreshold = _threshold;\\n emit AllocateThresholdUpdated(_threshold);\\n }\\n\\n /**\\n * @notice Set a minimum amount of OTokens in a mint or redeem that triggers a\\n * rebase\\n * @param _threshold OToken amount with 18 fixed decimals.\\n */\\n function setRebaseThreshold(uint256 _threshold) external onlyGovernor {\\n rebaseThreshold = _threshold;\\n emit RebaseThresholdUpdated(_threshold);\\n }\\n\\n /**\\n * @notice Set address of Strategist\\n * @param _address Address of Strategist\\n */\\n function setStrategistAddr(address _address) external onlyGovernor {\\n strategistAddr = _address;\\n emit StrategistUpdated(_address);\\n }\\n\\n /**\\n * @notice Set the default Strategy for an asset, i.e. the one which the asset\\n will be automatically allocated to and withdrawn from\\n * @param _asset Address of the asset\\n * @param _strategy Address of the Strategy\\n */\\n function setAssetDefaultStrategy(address _asset, address _strategy)\\n external\\n onlyGovernorOrStrategist\\n {\\n emit AssetDefaultStrategyUpdated(_asset, _strategy);\\n // If its a zero address being passed for the strategy we are removing\\n // the default strategy\\n if (_strategy != address(0)) {\\n // Make sure the strategy meets some criteria\\n require(strategies[_strategy].isSupported, \\\"Strategy not approved\\\");\\n IStrategy strategy = IStrategy(_strategy);\\n require(assets[_asset].isSupported, \\\"Asset is not supported\\\");\\n require(\\n strategy.supportsAsset(_asset),\\n \\\"Asset not supported by Strategy\\\"\\n );\\n }\\n assetDefaultStrategies[_asset] = _strategy;\\n }\\n\\n /**\\n * @notice Set maximum amount of OTokens that can at any point be minted and deployed\\n * to strategy (used only by ConvexOUSDMetaStrategy for now).\\n * @param _threshold OToken amount with 18 fixed decimals.\\n */\\n function setNetOusdMintForStrategyThreshold(uint256 _threshold)\\n external\\n onlyGovernor\\n {\\n /**\\n * Because `netOusdMintedForStrategy` check in vault core works both ways\\n * (positive and negative) the actual impact of the amount of OToken minted\\n * could be double the threshold. E.g.:\\n * - contract has threshold set to 100\\n * - state of netOusdMinted is -90\\n * - in effect it can mint 190 OToken and still be within limits\\n *\\n * We are somewhat mitigating this behaviour by resetting the netOusdMinted\\n * counter whenever new threshold is set. So it can only move one threshold\\n * amount in each direction. This also enables us to reduce the threshold\\n * amount and not have problems with current netOusdMinted being near\\n * limits on either side.\\n */\\n netOusdMintedForStrategy = 0;\\n netOusdMintForStrategyThreshold = _threshold;\\n emit NetOusdMintForStrategyThresholdChanged(_threshold);\\n }\\n\\n /**\\n * @notice Set the Dripper contract that streams harvested rewards to the vault.\\n * @param _dripper Address of the Dripper contract.\\n */\\n function setDripper(address _dripper) external onlyGovernor {\\n dripper = _dripper;\\n emit DripperChanged(_dripper);\\n }\\n\\n /***************************************\\n Swaps\\n ****************************************/\\n\\n /**\\n * @notice Strategist swaps collateral assets sitting in the vault.\\n * @param _fromAsset The token address of the asset being sold by the vault.\\n * @param _toAsset The token address of the asset being purchased by the vault.\\n * @param _fromAssetAmount The amount of assets being sold by the vault.\\n * @param _minToAssetAmount The minimum amount of assets to be purchased.\\n * @param _data implementation specific data. eg 1Inch swap data\\n * @return toAssetAmount The amount of toAssets that was received from the swap\\n */\\n function swapCollateral(\\n address _fromAsset,\\n address _toAsset,\\n uint256 _fromAssetAmount,\\n uint256 _minToAssetAmount,\\n bytes calldata _data\\n )\\n external\\n nonReentrant\\n onlyGovernorOrStrategist\\n returns (uint256 toAssetAmount)\\n {\\n toAssetAmount = _swapCollateral(\\n _fromAsset,\\n _toAsset,\\n _fromAssetAmount,\\n _minToAssetAmount,\\n _data\\n );\\n }\\n\\n function _swapCollateral(\\n address _fromAsset,\\n address _toAsset,\\n uint256 _fromAssetAmount,\\n uint256 _minToAssetAmount,\\n bytes calldata _data\\n ) internal virtual returns (uint256 toAssetAmount) {\\n // Check fromAsset and toAsset are valid\\n Asset memory fromAssetConfig = assets[address(_fromAsset)];\\n Asset memory toAssetConfig = assets[_toAsset];\\n require(fromAssetConfig.isSupported, \\\"From asset is not supported\\\");\\n require(toAssetConfig.isSupported, \\\"To asset is not supported\\\");\\n\\n // Load swap config into memory to avoid separate SLOADs\\n SwapConfig memory config = swapConfig;\\n\\n // Scope a new block to remove toAssetBalBefore from the scope of swapCollateral.\\n // This avoids a stack too deep error.\\n {\\n uint256 toAssetBalBefore = IERC20(_toAsset).balanceOf(\\n address(this)\\n );\\n\\n // Transfer from assets to the swapper contract\\n IERC20(_fromAsset).safeTransfer(config.swapper, _fromAssetAmount);\\n\\n // Call to the Swapper contract to do the actual swap\\n // The -1 is required for stETH which sometimes transfers 1 wei less than what was specified.\\n // slither-disable-next-line unused-return\\n ISwapper(config.swapper).swap(\\n _fromAsset,\\n _toAsset,\\n _fromAssetAmount - 1,\\n _minToAssetAmount,\\n _data\\n );\\n\\n // Compute the change in asset balance held by the Vault\\n toAssetAmount =\\n IERC20(_toAsset).balanceOf(address(this)) -\\n toAssetBalBefore;\\n }\\n\\n // Check the to assets returned is above slippage amount specified by the strategist\\n require(\\n toAssetAmount >= _minToAssetAmount,\\n \\\"Strategist slippage limit\\\"\\n );\\n\\n // Scope a new block to remove minOracleToAssetAmount from the scope of swapCollateral.\\n // This avoids a stack too deep error.\\n {\\n // Check the slippage against the Oracle in case the strategist made a mistake or has become malicious.\\n // to asset amount = from asset amount * from asset price / to asset price\\n uint256 minOracleToAssetAmount = (_fromAssetAmount *\\n (1e4 - fromAssetConfig.allowedOracleSlippageBps) *\\n IOracle(priceProvider).price(_fromAsset)) /\\n (IOracle(priceProvider).price(_toAsset) *\\n (1e4 + toAssetConfig.allowedOracleSlippageBps));\\n\\n // Scale both sides up to 18 decimals to compare\\n require(\\n toAssetAmount.scaleBy(18, toAssetConfig.decimals) >=\\n minOracleToAssetAmount.scaleBy(\\n 18,\\n fromAssetConfig.decimals\\n ),\\n \\\"Oracle slippage limit exceeded\\\"\\n );\\n }\\n\\n // Check the vault's total value hasn't gone below the OToken total supply\\n // by more than the allowed percentage.\\n require(\\n IVault(address(this)).totalValue() >=\\n (oUSD.totalSupply() * ((1e4 - config.allowedUndervalueBps))) /\\n 1e4,\\n \\\"Allowed value < supply\\\"\\n );\\n\\n emit Swapped(_fromAsset, _toAsset, _fromAssetAmount, toAssetAmount);\\n }\\n\\n /***************************************\\n Swap Config\\n ****************************************/\\n\\n /**\\n * @notice Set the contract the performs swaps of collateral assets.\\n * @param _swapperAddr Address of the Swapper contract that implements the ISwapper interface.\\n */\\n function setSwapper(address _swapperAddr) external onlyGovernor {\\n swapConfig.swapper = _swapperAddr;\\n emit SwapperChanged(_swapperAddr);\\n }\\n\\n /// @notice Contract that swaps the vault's collateral assets\\n function swapper() external view returns (address swapper_) {\\n swapper_ = swapConfig.swapper;\\n }\\n\\n /**\\n * @notice Set max allowed percentage the vault total value can drop below the OToken total supply in basis points\\n * when executing collateral swaps.\\n * @param _basis Percentage in basis points. eg 100 == 1%\\n */\\n function setSwapAllowedUndervalue(uint16 _basis) external onlyGovernor {\\n require(_basis < 10001, \\\"Invalid basis points\\\");\\n swapConfig.allowedUndervalueBps = _basis;\\n emit SwapAllowedUndervalueChanged(_basis);\\n }\\n\\n /**\\n * @notice Max allowed percentage the vault total value can drop below the OToken total supply in basis points\\n * when executing a collateral swap.\\n * For example 100 == 1%\\n * @return value Percentage in basis points.\\n */\\n function allowedSwapUndervalue() external view returns (uint256 value) {\\n value = swapConfig.allowedUndervalueBps;\\n }\\n\\n /**\\n * @notice Set the allowed slippage from the Oracle price for collateral asset swaps.\\n * @param _asset Address of the asset token.\\n * @param _allowedOracleSlippageBps allowed slippage from Oracle in basis points. eg 20 = 0.2%. Max 10%.\\n */\\n function setOracleSlippage(address _asset, uint16 _allowedOracleSlippageBps)\\n external\\n onlyGovernor\\n {\\n require(assets[_asset].isSupported, \\\"Asset not supported\\\");\\n require(_allowedOracleSlippageBps < 1000, \\\"Slippage too high\\\");\\n\\n assets[_asset].allowedOracleSlippageBps = _allowedOracleSlippageBps;\\n\\n emit SwapSlippageChanged(_asset, _allowedOracleSlippageBps);\\n }\\n\\n /***************************************\\n Asset Config\\n ****************************************/\\n\\n /**\\n * @notice Add a supported asset to the contract, i.e. one that can be\\n * to mint OTokens.\\n * @param _asset Address of asset\\n */\\n function supportAsset(address _asset, uint8 _unitConversion)\\n external\\n onlyGovernor\\n {\\n require(!assets[_asset].isSupported, \\\"Asset already supported\\\");\\n\\n assets[_asset] = Asset({\\n isSupported: true,\\n unitConversion: UnitConversion(_unitConversion),\\n decimals: 0, // will be overridden in _cacheDecimals\\n allowedOracleSlippageBps: 0 // 0% by default\\n });\\n\\n _cacheDecimals(_asset);\\n allAssets.push(_asset);\\n\\n // Verify that our oracle supports the asset\\n // slither-disable-next-line unused-return\\n IOracle(priceProvider).price(_asset);\\n\\n emit AssetSupported(_asset);\\n }\\n\\n /**\\n * @notice Remove a supported asset from the Vault\\n * @param _asset Address of asset\\n */\\n function removeAsset(address _asset) external onlyGovernor {\\n require(assets[_asset].isSupported, \\\"Asset not supported\\\");\\n require(\\n IVault(address(this)).checkBalance(_asset) <= 1e13,\\n \\\"Vault still holds asset\\\"\\n );\\n\\n uint256 assetsCount = allAssets.length;\\n uint256 assetIndex = assetsCount; // initialize at invaid index\\n for (uint256 i = 0; i < assetsCount; ++i) {\\n if (allAssets[i] == _asset) {\\n assetIndex = i;\\n break;\\n }\\n }\\n\\n // Note: If asset is not found in `allAssets`, the following line\\n // will revert with an out-of-bound error. However, there's no\\n // reason why an asset would have `Asset.isSupported = true` but\\n // not exist in `allAssets`.\\n\\n // Update allAssets array\\n allAssets[assetIndex] = allAssets[assetsCount - 1];\\n allAssets.pop();\\n\\n // Reset default strategy\\n assetDefaultStrategies[_asset] = address(0);\\n emit AssetDefaultStrategyUpdated(_asset, address(0));\\n\\n // Remove asset from storage\\n delete assets[_asset];\\n\\n emit AssetRemoved(_asset);\\n }\\n\\n /**\\n * @notice Cache decimals on OracleRouter for a particular asset. This action\\n * is required before that asset's price can be accessed.\\n * @param _asset Address of asset token\\n */\\n function cacheDecimals(address _asset) external onlyGovernor {\\n _cacheDecimals(_asset);\\n }\\n\\n /***************************************\\n Strategy Config\\n ****************************************/\\n\\n /**\\n * @notice Add a strategy to the Vault.\\n * @param _addr Address of the strategy to add\\n */\\n function approveStrategy(address _addr) external onlyGovernor {\\n require(!strategies[_addr].isSupported, \\\"Strategy already approved\\\");\\n strategies[_addr] = Strategy({ isSupported: true, _deprecated: 0 });\\n allStrategies.push(_addr);\\n emit StrategyApproved(_addr);\\n }\\n\\n /**\\n * @notice Remove a strategy from the Vault.\\n * @param _addr Address of the strategy to remove\\n */\\n\\n function removeStrategy(address _addr) external onlyGovernor {\\n require(strategies[_addr].isSupported, \\\"Strategy not approved\\\");\\n\\n uint256 assetCount = allAssets.length;\\n for (uint256 i = 0; i < assetCount; ++i) {\\n require(\\n assetDefaultStrategies[allAssets[i]] != _addr,\\n \\\"Strategy is default for an asset\\\"\\n );\\n }\\n\\n // Initialize strategyIndex with out of bounds result so function will\\n // revert if no valid index found\\n uint256 stratCount = allStrategies.length;\\n uint256 strategyIndex = stratCount;\\n for (uint256 i = 0; i < stratCount; ++i) {\\n if (allStrategies[i] == _addr) {\\n strategyIndex = i;\\n break;\\n }\\n }\\n\\n if (strategyIndex < stratCount) {\\n allStrategies[strategyIndex] = allStrategies[stratCount - 1];\\n allStrategies.pop();\\n\\n // Mark the strategy as not supported\\n strategies[_addr].isSupported = false;\\n\\n // Withdraw all assets\\n IStrategy strategy = IStrategy(_addr);\\n strategy.withdrawAll();\\n\\n emit StrategyRemoved(_addr);\\n }\\n }\\n\\n /***************************************\\n Strategies\\n ****************************************/\\n\\n /**\\n * @notice Deposit multiple assets from the vault into the strategy.\\n * @param _strategyToAddress Address of the Strategy to deposit assets into.\\n * @param _assets Array of asset address that will be deposited into the strategy.\\n * @param _amounts Array of amounts of each corresponding asset to deposit.\\n */\\n function depositToStrategy(\\n address _strategyToAddress,\\n address[] calldata _assets,\\n uint256[] calldata _amounts\\n ) external onlyGovernorOrStrategist nonReentrant {\\n _depositToStrategy(_strategyToAddress, _assets, _amounts);\\n }\\n\\n function _depositToStrategy(\\n address _strategyToAddress,\\n address[] calldata _assets,\\n uint256[] calldata _amounts\\n ) internal virtual {\\n require(\\n strategies[_strategyToAddress].isSupported,\\n \\\"Invalid to Strategy\\\"\\n );\\n require(_assets.length == _amounts.length, \\\"Parameter length mismatch\\\");\\n\\n uint256 assetCount = _assets.length;\\n for (uint256 i = 0; i < assetCount; ++i) {\\n address assetAddr = _assets[i];\\n require(\\n IStrategy(_strategyToAddress).supportsAsset(assetAddr),\\n \\\"Asset unsupported\\\"\\n );\\n // Send required amount of funds to the strategy\\n IERC20(assetAddr).safeTransfer(_strategyToAddress, _amounts[i]);\\n }\\n\\n // Deposit all the funds that have been sent to the strategy\\n IStrategy(_strategyToAddress).depositAll();\\n }\\n\\n /**\\n * @notice Withdraw multiple assets from the strategy to the vault.\\n * @param _strategyFromAddress Address of the Strategy to withdraw assets from.\\n * @param _assets Array of asset address that will be withdrawn from the strategy.\\n * @param _amounts Array of amounts of each corresponding asset to withdraw.\\n */\\n function withdrawFromStrategy(\\n address _strategyFromAddress,\\n address[] calldata _assets,\\n uint256[] calldata _amounts\\n ) external onlyGovernorOrStrategist nonReentrant {\\n _withdrawFromStrategy(\\n address(this),\\n _strategyFromAddress,\\n _assets,\\n _amounts\\n );\\n }\\n\\n /**\\n * @param _recipient can either be a strategy or the Vault\\n */\\n function _withdrawFromStrategy(\\n address _recipient,\\n address _strategyFromAddress,\\n address[] calldata _assets,\\n uint256[] calldata _amounts\\n ) internal virtual {\\n require(\\n strategies[_strategyFromAddress].isSupported,\\n \\\"Invalid from Strategy\\\"\\n );\\n require(_assets.length == _amounts.length, \\\"Parameter length mismatch\\\");\\n\\n uint256 assetCount = _assets.length;\\n for (uint256 i = 0; i < assetCount; ++i) {\\n // Withdraw from Strategy to the recipient\\n IStrategy(_strategyFromAddress).withdraw(\\n _recipient,\\n _assets[i],\\n _amounts[i]\\n );\\n }\\n }\\n\\n /**\\n * @notice Sets the maximum allowable difference between\\n * total supply and backing assets' value.\\n */\\n function setMaxSupplyDiff(uint256 _maxSupplyDiff) external onlyGovernor {\\n maxSupplyDiff = _maxSupplyDiff;\\n emit MaxSupplyDiffChanged(_maxSupplyDiff);\\n }\\n\\n /**\\n * @notice Sets the trusteeAddress that can receive a portion of yield.\\n * Setting to the zero address disables this feature.\\n */\\n function setTrusteeAddress(address _address) external onlyGovernor {\\n trusteeAddress = _address;\\n emit TrusteeAddressChanged(_address);\\n }\\n\\n /**\\n * @notice Sets the TrusteeFeeBps to the percentage of yield that should be\\n * received in basis points.\\n */\\n function setTrusteeFeeBps(uint256 _basis) external onlyGovernor {\\n require(_basis <= 5000, \\\"basis cannot exceed 50%\\\");\\n trusteeFeeBps = _basis;\\n emit TrusteeFeeBpsChanged(_basis);\\n }\\n\\n /**\\n * @notice Set OToken Metapool strategy\\n * @param _ousdMetaStrategy Address of OToken metapool strategy\\n */\\n function setOusdMetaStrategy(address _ousdMetaStrategy)\\n external\\n onlyGovernor\\n {\\n ousdMetaStrategy = _ousdMetaStrategy;\\n emit OusdMetaStrategyUpdated(_ousdMetaStrategy);\\n }\\n\\n /***************************************\\n Pause\\n ****************************************/\\n\\n /**\\n * @notice Set the deposit paused flag to true to prevent rebasing.\\n */\\n function pauseRebase() external onlyGovernorOrStrategist {\\n rebasePaused = true;\\n emit RebasePaused();\\n }\\n\\n /**\\n * @notice Set the deposit paused flag to true to allow rebasing.\\n */\\n function unpauseRebase() external onlyGovernorOrStrategist {\\n rebasePaused = false;\\n emit RebaseUnpaused();\\n }\\n\\n /**\\n * @notice Set the deposit paused flag to true to prevent capital movement.\\n */\\n function pauseCapital() external onlyGovernorOrStrategist {\\n capitalPaused = true;\\n emit CapitalPaused();\\n }\\n\\n /**\\n * @notice Set the deposit paused flag to false to enable capital movement.\\n */\\n function unpauseCapital() external onlyGovernorOrStrategist {\\n capitalPaused = false;\\n emit CapitalUnpaused();\\n }\\n\\n /***************************************\\n Utils\\n ****************************************/\\n\\n /**\\n * @notice Transfer token to governor. Intended for recovering tokens stuck in\\n * contract, i.e. mistaken sends.\\n * @param _asset Address for the asset\\n * @param _amount Amount of the asset to transfer\\n */\\n function transferToken(address _asset, uint256 _amount)\\n external\\n onlyGovernor\\n {\\n require(!assets[_asset].isSupported, \\\"Only unsupported assets\\\");\\n IERC20(_asset).safeTransfer(governor(), _amount);\\n }\\n\\n /***************************************\\n Strategies Admin\\n ****************************************/\\n\\n /**\\n * @notice Withdraws all assets from the strategy and sends assets to the Vault.\\n * @param _strategyAddr Strategy address.\\n */\\n function withdrawAllFromStrategy(address _strategyAddr)\\n external\\n onlyGovernorOrStrategist\\n {\\n _withdrawAllFromStrategy(_strategyAddr);\\n }\\n\\n function _withdrawAllFromStrategy(address _strategyAddr) internal virtual {\\n require(\\n strategies[_strategyAddr].isSupported,\\n \\\"Strategy is not supported\\\"\\n );\\n IStrategy strategy = IStrategy(_strategyAddr);\\n strategy.withdrawAll();\\n }\\n\\n /**\\n * @notice Withdraws all assets from all the strategies and sends assets to the Vault.\\n */\\n function withdrawAllFromStrategies() external onlyGovernorOrStrategist {\\n _withdrawAllFromStrategies();\\n }\\n\\n function _withdrawAllFromStrategies() internal virtual {\\n uint256 stratCount = allStrategies.length;\\n for (uint256 i = 0; i < stratCount; ++i) {\\n IStrategy(allStrategies[i]).withdrawAll();\\n }\\n }\\n\\n /***************************************\\n Utils\\n ****************************************/\\n\\n function _cacheDecimals(address token) internal {\\n Asset storage tokenAsset = assets[token];\\n if (tokenAsset.decimals != 0) {\\n return;\\n }\\n uint8 decimals = IBasicToken(token).decimals();\\n require(decimals >= 6 && decimals <= 18, \\\"Unexpected precision\\\");\\n tokenAsset.decimals = decimals;\\n }\\n}\\n\",\"keccak256\":\"0xc4daad97bdcc4d62e7cf595301c949195d989739dd108f2e3dfefd3f96624762\",\"license\":\"MIT\"},\"contracts/vault/VaultStorage.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title OToken VaultStorage contract\\n * @notice The VaultStorage contract defines the storage for the Vault contracts\\n * @author Origin Protocol Inc\\n */\\n\\nimport { IERC20 } from \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport { SafeERC20 } from \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\nimport { Address } from \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\n\\nimport { IStrategy } from \\\"../interfaces/IStrategy.sol\\\";\\nimport { Governable } from \\\"../governance/Governable.sol\\\";\\nimport { OUSD } from \\\"../token/OUSD.sol\\\";\\nimport { Initializable } from \\\"../utils/Initializable.sol\\\";\\nimport \\\"../utils/Helpers.sol\\\";\\n\\ncontract VaultStorage is Initializable, Governable {\\n using SafeERC20 for IERC20;\\n\\n event AssetSupported(address _asset);\\n event AssetRemoved(address _asset);\\n event AssetDefaultStrategyUpdated(address _asset, address _strategy);\\n event AssetAllocated(address _asset, address _strategy, uint256 _amount);\\n event StrategyApproved(address _addr);\\n event StrategyRemoved(address _addr);\\n event Mint(address _addr, uint256 _value);\\n event Redeem(address _addr, uint256 _value);\\n event CapitalPaused();\\n event CapitalUnpaused();\\n event RebasePaused();\\n event RebaseUnpaused();\\n event VaultBufferUpdated(uint256 _vaultBuffer);\\n event OusdMetaStrategyUpdated(address _ousdMetaStrategy);\\n event RedeemFeeUpdated(uint256 _redeemFeeBps);\\n event PriceProviderUpdated(address _priceProvider);\\n event AllocateThresholdUpdated(uint256 _threshold);\\n event RebaseThresholdUpdated(uint256 _threshold);\\n event StrategistUpdated(address _address);\\n event MaxSupplyDiffChanged(uint256 maxSupplyDiff);\\n event YieldDistribution(address _to, uint256 _yield, uint256 _fee);\\n event TrusteeFeeBpsChanged(uint256 _basis);\\n event TrusteeAddressChanged(address _address);\\n event NetOusdMintForStrategyThresholdChanged(uint256 _threshold);\\n event SwapperChanged(address _address);\\n event SwapAllowedUndervalueChanged(uint256 _basis);\\n event SwapSlippageChanged(address _asset, uint256 _basis);\\n event Swapped(\\n address indexed _fromAsset,\\n address indexed _toAsset,\\n uint256 _fromAssetAmount,\\n uint256 _toAssetAmount\\n );\\n event DripperChanged(address indexed _dripper);\\n event WithdrawalRequested(\\n address indexed _withdrawer,\\n uint256 indexed _requestId,\\n uint256 _amount,\\n uint256 _queued\\n );\\n event WithdrawalClaimed(\\n address indexed _withdrawer,\\n uint256 indexed _requestId,\\n uint256 _amount\\n );\\n event WithdrawalClaimable(uint256 _claimable, uint256 _newClaimable);\\n\\n // Assets supported by the Vault, i.e. Stablecoins\\n enum UnitConversion {\\n DECIMALS,\\n GETEXCHANGERATE\\n }\\n // Changed to fit into a single storage slot so the decimals needs to be recached\\n struct Asset {\\n // Note: OETHVaultCore doesn't use `isSupported` when minting,\\n // redeeming or checking balance of assets.\\n bool isSupported;\\n UnitConversion unitConversion;\\n uint8 decimals;\\n // Max allowed slippage from the Oracle price when swapping collateral assets in basis points.\\n // For example 40 == 0.4% slippage\\n uint16 allowedOracleSlippageBps;\\n }\\n\\n /// @dev mapping of supported vault assets to their configuration\\n // slither-disable-next-line uninitialized-state\\n mapping(address => Asset) internal assets;\\n /// @dev list of all assets supported by the vault.\\n // slither-disable-next-line uninitialized-state\\n address[] internal allAssets;\\n\\n // Strategies approved for use by the Vault\\n struct Strategy {\\n bool isSupported;\\n uint256 _deprecated; // Deprecated storage slot\\n }\\n /// @dev mapping of strategy contracts to their configuration\\n mapping(address => Strategy) internal strategies;\\n /// @dev list of all vault strategies\\n address[] internal allStrategies;\\n\\n /// @notice Address of the Oracle price provider contract\\n // slither-disable-next-line uninitialized-state\\n address public priceProvider;\\n /// @notice pause rebasing if true\\n bool public rebasePaused = false;\\n /// @notice pause operations that change the OToken supply.\\n /// eg mint, redeem, allocate, mint/burn for strategy\\n bool public capitalPaused = true;\\n /// @notice Redemption fee in basis points. eg 50 = 0.5%\\n uint256 public redeemFeeBps;\\n /// @notice Percentage of assets to keep in Vault to handle (most) withdrawals. 100% = 1e18.\\n uint256 public vaultBuffer;\\n /// @notice OToken mints over this amount automatically allocate funds. 18 decimals.\\n uint256 public autoAllocateThreshold;\\n /// @notice OToken mints over this amount automatically rebase. 18 decimals.\\n uint256 public rebaseThreshold;\\n\\n /// @dev Address of the OToken token. eg OUSD or OETH.\\n // slither-disable-next-line uninitialized-state\\n OUSD internal oUSD;\\n\\n //keccak256(\\\"OUSD.vault.governor.admin.impl\\\");\\n bytes32 constant adminImplPosition =\\n 0xa2bd3d3cf188a41358c8b401076eb59066b09dec5775650c0de4c55187d17bd9;\\n\\n // Address of the contract responsible for post rebase syncs with AMMs\\n address private _deprecated_rebaseHooksAddr = address(0);\\n\\n // Deprecated: Address of Uniswap\\n // slither-disable-next-line constable-states\\n address private _deprecated_uniswapAddr = address(0);\\n\\n /// @notice Address of the Strategist\\n address public strategistAddr = address(0);\\n\\n /// @notice Mapping of asset address to the Strategy that they should automatically\\n // be allocated to\\n // slither-disable-next-line uninitialized-state\\n mapping(address => address) public assetDefaultStrategies;\\n\\n /// @notice Max difference between total supply and total value of assets. 18 decimals.\\n // slither-disable-next-line uninitialized-state\\n uint256 public maxSupplyDiff;\\n\\n /// @notice Trustee contract that can collect a percentage of yield\\n address public trusteeAddress;\\n\\n /// @notice Amount of yield collected in basis points. eg 2000 = 20%\\n uint256 public trusteeFeeBps;\\n\\n /// @dev Deprecated: Tokens that should be swapped for stablecoins\\n address[] private _deprecated_swapTokens;\\n\\n uint256 constant MINT_MINIMUM_UNIT_PRICE = 0.998e18;\\n\\n /// @notice Metapool strategy that is allowed to mint/burn OTokens without changing collateral\\n address public ousdMetaStrategy = address(0);\\n\\n /// @notice How much OTokens are currently minted by the strategy\\n int256 public netOusdMintedForStrategy = 0;\\n\\n /// @notice How much net total OTokens are allowed to be minted by all strategies\\n uint256 public netOusdMintForStrategyThreshold = 0;\\n\\n uint256 constant MIN_UNIT_PRICE_DRIFT = 0.7e18;\\n uint256 constant MAX_UNIT_PRICE_DRIFT = 1.3e18;\\n\\n /// @notice Collateral swap configuration.\\n /// @dev is packed into a single storage slot to save gas.\\n struct SwapConfig {\\n // Contract that swaps the vault's collateral assets\\n address swapper;\\n // Max allowed percentage the total value can drop below the total supply in basis points.\\n // For example 100 == 1%\\n uint16 allowedUndervalueBps;\\n }\\n SwapConfig internal swapConfig = SwapConfig(address(0), 0);\\n\\n /// @notice Address of the Dripper contract that streams harvested rewards to the Vault\\n /// @dev The vault is proxied so needs to be set with setDripper against the proxy contract.\\n // slither-disable-start constable-states\\n // slither-disable-next-line uninitialized-state\\n address public dripper;\\n // slither-disable-end constable-states\\n\\n /// Withdrawal Queue Storage /////\\n\\n struct WithdrawalQueueMetadata {\\n // cumulative total of all withdrawal requests included the ones that have already been claimed\\n uint128 queued;\\n // cumulative total of all the requests that can be claimed included the ones that have already been claimed\\n uint128 claimable;\\n // total of all the requests that have been claimed\\n uint128 claimed;\\n // index of the next withdrawal request starting at 0\\n uint128 nextWithdrawalIndex;\\n }\\n\\n // slither-disable-next-line uninitialized-state\\n WithdrawalQueueMetadata public withdrawalQueueMetadata;\\n\\n struct WithdrawalRequest {\\n address withdrawer;\\n bool claimed;\\n // Amount of oTokens to redeem\\n uint128 amount;\\n // cumulative total of all withdrawal requests including this one.\\n // this request can be claimed when this queued amount is less than or equal to the queue's claimable amount.\\n uint128 queued;\\n }\\n\\n // Mapping of withdrawal requests indexes to the user withdrawal request data\\n mapping(uint256 => WithdrawalRequest) public withdrawalRequests;\\n\\n // For future use\\n uint256[46] private __gap;\\n\\n /**\\n * @notice set the implementation for the admin, this needs to be in a base class else we cannot set it\\n * @param newImpl address of the implementation\\n */\\n function setAdminImpl(address newImpl) external onlyGovernor {\\n require(\\n Address.isContract(newImpl),\\n \\\"new implementation is not a contract\\\"\\n );\\n bytes32 position = adminImplPosition;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n sstore(position, newImpl)\\n }\\n }\\n}\\n\",\"keccak256\":\"0xe13565f58d63805320aa4aac336b294fa6b6e55b028a6727510bf99764ebce14\",\"license\":\"MIT\"}},\"version\":1}", + "bytecode": "0x6037805461ffff60a01b1916600160a81b179055603d80546001600160a01b0319908116909155603e805482169055603f80548216905560458054909116905560006046819055604781905560e060405260a081905260c052604880546001600160b01b03191690553480156200007557600080fd5b50604051620041c1380380620041c183398101604081905262000098916200010e565b620000b033600080516020620041a183398151915255565b600080516020620041a1833981519152546040516001600160a01b03909116906000907fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a908290a360601b6001600160601b03191660805262000140565b6000602082840312156200012157600080fd5b81516001600160a01b03811681146200013957600080fd5b9392505050565b60805160601c61401f62000182600039600081816105080152818161251b0152818161259d01528181612814015281816129440152613415015261401f6000f3fe608060405234801561001057600080fd5b50600436106103835760003560e01c8063636e6c40116101de578063ae69f3cb1161010f578063c9919112116100ad578063e6cc54321161007c578063e6cc5432146107f8578063e829cc161461080c578063eb03654b1461081f578063fc0cfeee1461083257600080fd5b8063c9919112146107c1578063d38bfff4146107c9578063d58e3b3a146107dc578063e45cc9f0146107ef57600080fd5b8063b890ebf6116100e9578063b890ebf61461078b578063bc90106b1461079e578063c5f00841146107b1578063c7af3352146107b957600080fd5b8063ae69f3cb14610752578063b2c9336d14610765578063b888879e1461077857600080fd5b80638e510b521161017c57806394828ffd1161015657806394828ffd146107055780639c82f2a41461070d5780639fa1826e14610720578063a403e4d51461072957600080fd5b80638e510b521461065f5780638ec489a214610668578063937b25811461067b57600080fd5b8063773540b3116101b8578063773540b31461061d5780637a2202f3146106305780637b9a709614610639578063840c4c7a1461064c57600080fd5b8063636e6c40146105e4578063663e64ce146105f75780636c7561e81461060a57600080fd5b8063372aa224116102b857806350ba711c11610256578063570d8e1d11610230578063570d8e1d146105a3578063597c8910146105b65780635d36b190146105c9578063603ea03b146105d157600080fd5b806350ba711c1461056357806352d38e5d1461057657806353ca9f241461057f57600080fd5b80633fc8cef3116102925780633fc8cef31461050357806349c1d54d1461052a5780634a5e42b11461053d5780634bed3bc01461055057600080fd5b8063372aa224146104d55780633b8ae397146104e85780633dbc911f146104fb57600080fd5b80631edfe3da116103255780632da845a8116102ff5780632da845a81461043d5780632e9958ab14610450578063362bd1a31461046357806336b6d944146104c257600080fd5b80631edfe3da1461041a578063207134b0146104235780632b3297f91461042c57600080fd5b80630c340a24116103615780630c340a24146103c15780631072cbea146103e1578063175188e8146103f457806318ce56bd1461040757600080fd5b806309f49bf51461038857806309f6442c146103925780630acbda75146103ae575b600080fd5b610390610845565b005b61039b60385481565b6040519081526020015b60405180910390f35b6103906103bc366004613bb6565b6108be565b6103c9610970565b6040516001600160a01b0390911681526020016103a5565b6103906103ef366004613b18565b61098d565b610390610402366004613979565b610a3a565b6045546103c9906001600160a01b031681565b61039b60395481565b61039b60435481565b6048546001600160a01b03166103c9565b61039061044b366004613979565b610d3b565b61039061045e366004613979565b610dad565b604a54604b5461048f916001600160801b0380821692600160801b928390048216928183169291041684565b604080516001600160801b03958616815293851660208501529184169183019190915290911660608201526080016103a5565b6103906104d0366004613979565b610e1b565b6103906104e3366004613979565b610e4b565b6103906104f6366004613979565b610ebd565b610390610ffa565b6103c97f000000000000000000000000000000000000000000000000000000000000000081565b6042546103c9906001600160a01b031681565b61039061054b366004613979565b611070565b604854600160a01b900461ffff1661039b565b61039b6105713660046139c7565b61137d565b61039b603b5481565b60375461059390600160a01b900460ff1681565b60405190151581526020016103a5565b603f546103c9906001600160a01b031681565b6103906105c4366004613979565b611420565b610390611461565b6049546103c9906001600160a01b031681565b6103906105f2366004613bb6565b611507565b610390610605366004613bb6565b611565565b610390610618366004613b42565b6115be565b61039061062b366004613979565b61183c565b61039b60475481565b610390610647366004613aee565b6118ae565b61039061065a366004613a6d565b6119e4565b61039b60415481565b610390610676366004613bb6565b611a7d565b6106cc610689366004613bb6565b604c60205260009081526040902080546001909101546001600160a01b03821691600160a01b900460ff16906001600160801b0380821691600160801b90041684565b604080516001600160a01b03909516855292151560208501526001600160801b03918216928401929092521660608201526080016103a5565b610390611b32565b61039061071b366004613979565b611ba2565b61039b603a5481565b6103c9610737366004613979565b6040602081905260009182529020546001600160a01b031681565b610390610760366004613a6d565b611c14565b610390610773366004613bb6565b611ca2565b6037546103c9906001600160a01b031681565b610390610799366004613bb6565b611cfb565b6103906107ac366004613994565b611d54565b610390611f96565b61059361200c565b61039061203d565b6103906107d7366004613979565b61207d565b6103906107ea366004613979565b612121565b61039b60465481565b60375461059390600160a81b900460ff1681565b61039061081a366004613b9b565b612193565b61039061082d366004613bb6565b612253565b610390610840366004613979565b612308565b603f546001600160a01b0316331480610861575061086161200c565b6108865760405162461bcd60e51b815260040161087d90613ce7565b60405180910390fd5b6037805460ff60a01b191690556040517fbc044409505c95b6b851433df96e1beae715c909d8e7c1d6d7ab783300d4e3b990600090a1565b6108c661200c565b6108e25760405162461bcd60e51b815260040161087d90613cb0565b6113888111156109345760405162461bcd60e51b815260206004820152601760248201527f62617369732063616e6e6f742065786365656420353025000000000000000000604482015260640161087d565b60438190556040518181527f56287a45051933ea374811b3d5d165033047be5572cac676f7c28b8be4f746c7906020015b60405180910390a150565b6000610988600080516020613fca8339815191525490565b905090565b61099561200c565b6109b15760405162461bcd60e51b815260040161087d90613cb0565b6001600160a01b03821660009081526033602052604090205460ff1615610a1a5760405162461bcd60e51b815260206004820152601760248201527f4f6e6c7920756e737570706f7274656420617373657473000000000000000000604482015260640161087d565b610a36610a25610970565b6001600160a01b03841690836123aa565b5050565b610a4261200c565b610a5e5760405162461bcd60e51b815260040161087d90613cb0565b6001600160a01b03811660009081526035602052604090205460ff16610abe5760405162461bcd60e51b815260206004820152601560248201527414dd1c985d1959de481b9bdd08185c1c1c9bdd9959605a1b604482015260640161087d565b60345460005b81811015610b7657826001600160a01b03166040600060348481548110610aed57610aed613fa4565b60009182526020808320909101546001600160a01b039081168452908301939093526040909101902054161415610b665760405162461bcd60e51b815260206004820181905260248201527f53747261746567792069732064656661756c7420666f7220616e206173736574604482015260640161087d565b610b6f81613f47565b9050610ac4565b506036548060005b82811015610bd657846001600160a01b031660368281548110610ba357610ba3613fa4565b6000918252602090912001546001600160a01b03161415610bc657809150610bd6565b610bcf81613f47565b9050610b7e565b5081811015610d35576036610bec600184613f04565b81548110610bfc57610bfc613fa4565b600091825260209091200154603680546001600160a01b039092169183908110610c2857610c28613fa4565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055506036805480610c6757610c67613f8e565b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b03861680835260359091526040808320805460ff19169055805163429c145b60e11b81529051879363853828b6926004808201939182900301818387803b158015610cde57600080fd5b505af1158015610cf2573d6000803e3d6000fd5b50506040516001600160a01b03881681527f09a1db4b80c32706328728508c941a6b954f31eb5affd32f236c1fd405f8fea49250602001905060405180910390a1505b50505050565b610d4361200c565b610d5f5760405162461bcd60e51b815260040161087d90613cb0565b604280546001600160a01b0319166001600160a01b0383169081179091556040519081527f1e4af5ac389e8cde1bdaa6830881b6c987c62a45cfb3b33d27d805cde3b5775090602001610965565b610db561200c565b610dd15760405162461bcd60e51b815260040161087d90613cb0565b604980546001600160a01b0319166001600160a01b0383169081179091556040517faf2910d9759321733de15af1827a49830692912adeb2b3646334861f2cd2eed490600090a250565b610e2361200c565b610e3f5760405162461bcd60e51b815260040161087d90613cb0565b610e4881612401565b50565b610e5361200c565b610e6f5760405162461bcd60e51b815260040161087d90613cb0565b603780546001600160a01b0319166001600160a01b0383169081179091556040519081527fb266add5f3044b17d27db796af992cecbe413921b4e8aaaee03c719e16b9806a90602001610965565b610ec561200c565b610ee15760405162461bcd60e51b815260040161087d90613cb0565b6001600160a01b03811660009081526035602052604090205460ff1615610f4a5760405162461bcd60e51b815260206004820152601960248201527f537472617465677920616c726561647920617070726f76656400000000000000604482015260640161087d565b6040805180820182526001808252600060208084018281526001600160a01b038716808452603583528684209551865460ff19169015151786559051948401949094556036805493840181559091527f4a11f94e20a93c79f6ec743a1954ec4fc2c08429ae2122118bf234b2185c81b890910180546001600160a01b0319168317905591519081527f960dd94cbb79169f09a4e445d58b895df2d9bffa5b31055d0932d801724a20d19101610965565b603f546001600160a01b0316331480611016575061101661200c565b6110325760405162461bcd60e51b815260040161087d90613ce7565b6037805460ff60a81b1916600160a81b1790556040517f71f0e5b62f846a22e0b4d159e516e62fa9c2b8eb570be15f83e67d98a2ee51e090600090a1565b61107861200c565b6110945760405162461bcd60e51b815260040161087d90613cb0565b6001600160a01b03811660009081526033602052604090205460ff166110f25760405162461bcd60e51b8152602060048201526013602482015272105cdcd95d081b9bdd081cdd5c1c1bdc9d1959606a1b604482015260640161087d565b604051632fa8a91360e11b81526001600160a01b03821660048201526509184e72a000903090635f5152269060240160206040518083038186803b15801561113957600080fd5b505afa15801561114d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111719190613bcf565b11156111bf5760405162461bcd60e51b815260206004820152601760248201527f5661756c74207374696c6c20686f6c6473206173736574000000000000000000604482015260640161087d565b6034548060005b8281101561121e57836001600160a01b0316603482815481106111eb576111eb613fa4565b6000918252602090912001546001600160a01b0316141561120e5780915061121e565b61121781613f47565b90506111c6565b50603461122c600184613f04565b8154811061123c5761123c613fa4565b600091825260209091200154603480546001600160a01b03909216918390811061126857611268613fa4565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060348054806112a7576112a7613f8e565b60008281526020808220600019908401810180546001600160a01b031990811690915593019093556001600160a01b038616808252604080855280832080549094169093558251908152928301527fba58ce12801c949fa65f41c46ed108671c219baf945fa48d21026cea99ff252a910160405180910390a16001600160a01b038316600081815260336020908152604091829020805464ffffffffff1916905590519182527f37803e2125c48ee96c38ddf04e826daf335b0e1603579040fd275aba6d06b6fc910160405180910390a1505050565b7f53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac453580546000919060028114156113c55760405162461bcd60e51b815260040161087d90613d2f565b60028255603f546001600160a01b03163314806113e557506113e561200c565b6114015760405162461bcd60e51b815260040161087d90613ce7565b61140f898989898989612517565b600190925550979650505050505050565b603f546001600160a01b031633148061143c575061143c61200c565b6114585760405162461bcd60e51b815260040161087d90613ce7565b610e488161267d565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b0316146114fc5760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b606482015260840161087d565b611505336126dc565b565b61150f61200c565b61152b5760405162461bcd60e51b815260040161087d90613cb0565b600060465560478190556040518181527fc29d6fedbc6bdf267a08166c2b976fbd72aca5d6a769528616f8b9224c8f197f90602001610965565b61156d61200c565b6115895760405162461bcd60e51b815260040161087d90613cb0565b60418190556040518181527f95201f9c21f26877223b1ff4073936a6484c35495649e60e55730497aeb60d9390602001610965565b6115c661200c565b6115e25760405162461bcd60e51b815260040161087d90613cb0565b6001600160a01b03821660009081526033602052604090205460ff161561164b5760405162461bcd60e51b815260206004820152601760248201527f417373657420616c726561647920737570706f72746564000000000000000000604482015260640161087d565b60405180608001604052806001151581526020018260ff16600181111561167457611674613f78565b600181111561168557611685613f78565b81526000602080830182905260409283018290526001600160a01b0386168252603381529190208251815490151560ff19821681178355928401519192839161ff001990911661ffff19909116176101008360018111156116e8576116e8613f78565b02179055506040820151815460609093015161ffff1663010000000264ffff0000001960ff90921662010000029190911664ffffff0000199093169290921791909117905561173682612401565b603480546001810182556000919091527f46bddb1178e94d7f2892ff5f366840eb658911794f2c3a44c450aa2c505186c10180546001600160a01b0319166001600160a01b038481169182179092556037546040516315d5220f60e31b815260048101929092529091169063aea910789060240160206040518083038186803b1580156117c257600080fd5b505afa1580156117d6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117fa9190613bcf565b506040516001600160a01b03831681527f4f1ac48525e50059cc1cc6e0e1940ece0dd653a4db4841538d6aef036be2fb7b906020015b60405180910390a15050565b61184461200c565b6118605760405162461bcd60e51b815260040161087d90613cb0565b603f80546001600160a01b0319166001600160a01b0383169081179091556040519081527f869e0abd13cc3a975de7b93be3df1cb2255c802b1cead85963cc79d99f131bee90602001610965565b6118b661200c565b6118d25760405162461bcd60e51b815260040161087d90613cb0565b6001600160a01b03821660009081526033602052604090205460ff166119305760405162461bcd60e51b8152602060048201526013602482015272105cdcd95d081b9bdd081cdd5c1c1bdc9d1959606a1b604482015260640161087d565b6103e88161ffff16106119795760405162461bcd60e51b81526020600482015260116024820152700a6d8d2e0e0c2ceca40e8dede40d0d2ced607b1b604482015260640161087d565b6001600160a01b038216600081815260336020908152604091829020805464ffff0000001916630100000061ffff8716908102919091179091558251938452908301527f8d22e9d2cbe8bb65a3c4412bd8970743864512a1a0e004e8d00fb96277b78b949101611830565b603f546001600160a01b0316331480611a005750611a0061200c565b611a1c5760405162461bcd60e51b815260040161087d90613ce7565b7f53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac453580546002811415611a605760405162461bcd60e51b815260040161087d90613d2f565b60028255611a71878787878761279d565b50600190555050505050565b603f546001600160a01b0316331480611a995750611a9961200c565b611ab55760405162461bcd60e51b815260040161087d90613ce7565b670de0b6b3a7640000811115611afd5760405162461bcd60e51b815260206004820152600d60248201526c496e76616c69642076616c756560981b604482015260640161087d565b60398190556040518181527f41ecb23a0e7865b25f38c268b7c3012220d822929e9edff07326e89d5bb822b590602001610965565b603f546001600160a01b0316331480611b4e5750611b4e61200c565b611b6a5760405162461bcd60e51b815260040161087d90613ce7565b6037805460ff60a81b191690556040517f891ebab18da80ebeeea06b1b1cede098329c4c008906a98370c2ac7a80b571cb90600090a1565b611baa61200c565b611bc65760405162461bcd60e51b815260040161087d90613cb0565b604880546001600160a01b0319166001600160a01b0383169081179091556040519081527f7d7719313229e558c5a3893cad2eb86a86a049156d1d9ebd5c63a8eedefd1c0390602001610965565b603f546001600160a01b0316331480611c305750611c3061200c565b611c4c5760405162461bcd60e51b815260040161087d90613ce7565b7f53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac453580546002811415611c905760405162461bcd60e51b815260040161087d90613d2f565b60028255611a713088888888886129d5565b611caa61200c565b611cc65760405162461bcd60e51b815260040161087d90613cb0565b603a8190556040518181527f2ec5fb5a3d2703edc461252d92ccd2799c3c74f01d97212b20388207fa17ae4590602001610965565b611d0361200c565b611d1f5760405162461bcd60e51b815260040161087d90613cb0565b603b8190556040518181527f39367850377ac04920a9a670f2180e7a94d83b15ad302e59875ec58fd10bd37d90602001610965565b603f546001600160a01b0316331480611d705750611d7061200c565b611d8c5760405162461bcd60e51b815260040161087d90613ce7565b604080516001600160a01b038085168252831660208201527fba58ce12801c949fa65f41c46ed108671c219baf945fa48d21026cea99ff252a910160405180910390a16001600160a01b03811615611f68576001600160a01b03811660009081526035602052604090205460ff16611e3e5760405162461bcd60e51b815260206004820152601560248201527414dd1c985d1959de481b9bdd08185c1c1c9bdd9959605a1b604482015260640161087d565b6001600160a01b038216600090815260336020526040902054819060ff16611ea15760405162461bcd60e51b8152602060048201526016602482015275105cdcd95d081a5cc81b9bdd081cdd5c1c1bdc9d195960521b604482015260640161087d565b60405163551c457b60e11b81526001600160a01b03848116600483015282169063aa388af69060240160206040518083038186803b158015611ee257600080fd5b505afa158015611ef6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f1a9190613b79565b611f665760405162461bcd60e51b815260206004820152601f60248201527f4173736574206e6f7420737570706f7274656420627920537472617465677900604482015260640161087d565b505b6001600160a01b03918216600090815260406020819052902080546001600160a01b03191691909216179055565b603f546001600160a01b0316331480611fb25750611fb261200c565b611fce5760405162461bcd60e51b815260040161087d90613ce7565b6037805460ff60a01b1916600160a01b1790556040517f8cff26a5985614b3d30629cc4ab83824bf115aec971b718d8f2f99562032e97290600090a1565b6000612024600080516020613fca8339815191525490565b6001600160a01b0316336001600160a01b031614905090565b603f546001600160a01b0316331480612059575061205961200c565b6120755760405162461bcd60e51b815260040161087d90613ce7565b611505612a3e565b61208561200c565b6120a15760405162461bcd60e51b815260040161087d90613cb0565b6120c9817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b03166120e9600080516020613fca8339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b61212961200c565b6121455760405162461bcd60e51b815260040161087d90613cb0565b604580546001600160a01b0319166001600160a01b0383169081179091556040519081527fa12850fb726e0b2b7b3c9a9342031e1268a8148d0eb06b4bea8613204ffcd2b890602001610965565b61219b61200c565b6121b75760405162461bcd60e51b815260040161087d90613cb0565b6127118161ffff16106122035760405162461bcd60e51b8152602060048201526014602482015273496e76616c696420626173697320706f696e747360601b604482015260640161087d565b6048805461ffff60a01b1916600160a01b61ffff8416908102919091179091556040519081527ff12c00256bee2b6facb111a88a9b1cff86e79132939b44f1353212d6f746955790602001610965565b61225b61200c565b6122775760405162461bcd60e51b815260040161087d90613cb0565b6103e88111156122d35760405162461bcd60e51b815260206004820152602160248201527f52656465656d206665652073686f756c64206e6f74206265206f7665722031306044820152602560f81b606482015260840161087d565b60388190556040518181527fd6c7508d6658ccee36b7b7d7fd72e5cbaeefb40c64eff24e9ae7470e846304ee90602001610965565b61231061200c565b61232c5760405162461bcd60e51b815260040161087d90613cb0565b803b6123865760405162461bcd60e51b8152602060048201526024808201527f6e657720696d706c656d656e746174696f6e206973206e6f74206120636f6e746044820152631c9858dd60e21b606482015260840161087d565b7fa2bd3d3cf188a41358c8b401076eb59066b09dec5775650c0de4c55187d17bd955565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b1790526123fc908490612a95565b505050565b6001600160a01b0381166000908152603360205260409020805462010000900460ff161561242d575050565b6000826001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b15801561246857600080fd5b505afa15801561247c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124a09190613be8565b905060068160ff16101580156124ba575060128160ff1611155b6124fd5760405162461bcd60e51b81526020600482015260146024820152732ab732bc3832b1ba32b210383932b1b4b9b4b7b760611b604482015260640161087d565b815460ff909116620100000262ff00001990911617905550565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316876001600160a01b0316141561259b5760405162461bcd60e51b815260206004820152601c60248201527f737761702066726f6d2057455448206e6f7420737570706f7274656400000000604482015260640161087d565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316866001600160a01b0316146126105760405162461bcd60e51b81526020600482015260116024820152700dedcd8f240e6eec2e040e8de40ae8aa89607b1b604482015260640161087d565b61261e878787878787612b67565b9050306001600160a01b031663b9b17f9f6040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561265b57600080fd5b505af115801561266f573d6000803e3d6000fd5b505050509695505050505050565b612686816132d1565b306001600160a01b031663b9b17f9f6040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156126c157600080fd5b505af11580156126d5573d6000803e3d6000fd5b5050505050565b6001600160a01b0381166127325760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f722069732061646472657373283029000000000000604482015260640161087d565b806001600160a01b0316612752600080516020613fca8339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a3610e4881600080516020613fca83398151915255565b6001600160a01b03851660009081526035602052604090205460ff166127fb5760405162461bcd60e51b8152602060048201526013602482015272496e76616c696420746f20537472617465677960681b604482015260640161087d565b60018314801561280b5750600181145b801561286f57507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168484600081811061284f5761284f613fa4565b90506020020160208101906128649190613979565b6001600160a01b0316145b6128b45760405162461bcd60e51b815260206004820152601660248201527513db9b1e4815d15512081a5cc81cdd5c1c1bdc9d195960521b604482015260640161087d565b6128bc613395565b828260008181106128cf576128cf613fa4565b9050602002013511156129245760405162461bcd60e51b815260206004820152601960248201527f4e6f7420656e6f756768205745544820617661696c61626c6500000000000000604482015260640161087d565b61297b858383600081811061293b5761293b613fa4565b905060200201357f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166123aa9092919063ffffffff16565b846001600160a01b031663de5f62686040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156129b657600080fd5b505af11580156129ca573d6000803e3d6000fd5b505050505050505050565b6129e38686868686866134e2565b306001600160a01b031663b9b17f9f6040518163ffffffff1660e01b8152600401600060405180830381600087803b158015612a1e57600080fd5b505af1158015612a32573d6000803e3d6000fd5b50505050505050505050565b612a46613670565b306001600160a01b031663b9b17f9f6040518163ffffffff1660e01b8152600401600060405180830381600087803b158015612a8157600080fd5b505af1158015610d35573d6000803e3d6000fd5b6000612aea826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166137029092919063ffffffff16565b8051909150156123fc5780806020019051810190612b089190613b79565b6123fc5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840161087d565b6001600160a01b0386166000908152603360209081526040808320815160808101909252805460ff8082161515845285948401916101009004166001811115612bb257612bb2613f78565b6001811115612bc357612bc3613f78565b8152905462010000810460ff908116602080850191909152630100000090920461ffff166040938401526001600160a01b038b1660009081526033835283812084516080810190955280548084161515865295965090949092840191610100909104166001811115612c3757612c37613f78565b6001811115612c4857612c48613f78565b8152905462010000810460ff1660208301526301000000900461ffff166040909101528251909150612cbc5760405162461bcd60e51b815260206004820152601b60248201527f46726f6d206173736574206973206e6f7420737570706f727465640000000000604482015260640161087d565b8051612d0a5760405162461bcd60e51b815260206004820152601960248201527f546f206173736574206973206e6f7420737570706f7274656400000000000000604482015260640161087d565b6040805180820182526048546001600160a01b038082168352600160a01b90910461ffff16602083015291516370a0823160e01b81523060048201529091600091908b16906370a082319060240160206040518083038186803b158015612d7057600080fd5b505afa158015612d84573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612da89190613bcf565b8251909150612dc2906001600160a01b038d16908b6123aa565b81516001600160a01b0316632506c0188c8c612ddf60018e613f04565b8c8c8c6040518763ffffffff1660e01b8152600401612e0396959493929190613c21565b602060405180830381600087803b158015612e1d57600080fd5b505af1158015612e31573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e559190613bcf565b506040516370a0823160e01b815230600482015281906001600160a01b038c16906370a082319060240160206040518083038186803b158015612e9757600080fd5b505afa158015612eab573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ecf9190613bcf565b612ed99190613f04565b94505086841015612f2c5760405162461bcd60e51b815260206004820152601960248201527f5374726174656769737420736c697070616765206c696d697400000000000000604482015260640161087d565b60008260600151612710612f409190613d57565b6037546040516315d5220f60e31b81526001600160a01b038d8116600483015261ffff93909316929091169063aea910789060240160206040518083038186803b158015612f8d57600080fd5b505afa158015612fa1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fc59190613bcf565b612fcf9190613ea2565b6037546040516315d5220f60e31b81526001600160a01b038e811660048301529091169063aea910789060240160206040518083038186803b15801561301457600080fd5b505afa158015613028573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061304c9190613bcf565b606086015161305d90612710613ee9565b61306b9061ffff168c613ea2565b6130759190613ea2565b61307f9190613d95565b905061309e6012856040015160ff168361371b9092919063ffffffff16565b60408401516130b490879060129060ff1661371b565b10156131025760405162461bcd60e51b815260206004820152601e60248201527f4f7261636c6520736c697070616765206c696d69742065786365656465640000604482015260640161087d565b5061271081602001516127106131189190613ee9565b61ffff16603c60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561316a57600080fd5b505afa15801561317e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131a29190613bcf565b6131ac9190613ea2565b6131b69190613d95565b306001600160a01b031663d4c3eea06040518163ffffffff1660e01b815260040160206040518083038186803b1580156131ef57600080fd5b505afa158015613203573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132279190613bcf565b101561326e5760405162461bcd60e51b8152602060048201526016602482015275416c6c6f7765642076616c7565203c20737570706c7960501b604482015260640161087d565b886001600160a01b03168a6001600160a01b03167fa078c4190abe07940190effc1846be0ccf03ad6007bc9e93f9697d0b460befbb8a876040516132bc929190918252602082015260400190565b60405180910390a35050509695505050505050565b6001600160a01b03811660009081526035602052604090205460ff166133395760405162461bcd60e51b815260206004820152601960248201527f5374726174656779206973206e6f7420737570706f7274656400000000000000604482015260640161087d565b6000819050806001600160a01b031663853828b66040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561337957600080fd5b505af115801561338d573d6000803e3d6000fd5b505050505050565b60408051608081018252604a546001600160801b03808216808452600160801b92839004821660208501819052604b54808416968601969096529290940416606083015260009283916133e791613ec1565b6040516370a0823160e01b81523060048201526001600160801b039190911691506000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a082319060240160206040518083038186803b15801561345757600080fd5b505afa15801561346b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061348f9190613bcf565b90506000836040015184602001516134a79190613ec1565b6001600160801b031690506134bc8184613d7d565b8211156134db57806134ce8484613f04565b6134d89190613f04565b94505b5050505090565b6001600160a01b03851660009081526035602052604090205460ff166135425760405162461bcd60e51b8152602060048201526015602482015274496e76616c69642066726f6d20537472617465677960581b604482015260640161087d565b8281146135915760405162461bcd60e51b815260206004820152601960248201527f506172616d65746572206c656e677468206d69736d6174636800000000000000604482015260640161087d565b8260005b8181101561366657866001600160a01b031663d9caed12898888858181106135bf576135bf613fa4565b90506020020160208101906135d49190613979565b8787868181106135e6576135e6613fa4565b6040516001600160e01b031960e088901b1681526001600160a01b03958616600482015294909316602485015250602090910201356044820152606401600060405180830381600087803b15801561363d57600080fd5b505af1158015613651573d6000803e3d6000fd5b505050508061365f90613f47565b9050613595565b5050505050505050565b60365460005b81811015610a36576036818154811061369157613691613fa4565b60009182526020822001546040805163429c145b60e11b815290516001600160a01b039092169263853828b69260048084019382900301818387803b1580156136d957600080fd5b505af11580156136ed573d6000803e3d6000fd5b50505050806136fb90613f47565b9050613676565b6060613711848460008561377d565b90505b9392505050565b60008183111561374b576137446137328385613f04565b61373d90600a613dfa565b85906138a5565b9350613775565b81831015613775576137726137608484613f04565b61376b90600a613dfa565b85906138ba565b93505b509192915050565b6060824710156137de5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840161087d565b843b61382c5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161087d565b600080866001600160a01b031685876040516138489190613c05565b60006040518083038185875af1925050503d8060008114613885576040519150601f19603f3d011682016040523d82523d6000602084013e61388a565b606091505b509150915061389a8282866138c6565b979650505050505050565b60006138b18284613ea2565b90505b92915050565b60006138b18284613d95565b606083156138d5575081613714565b8251156138e55782518084602001fd5b8160405162461bcd60e51b815260040161087d9190613c7d565b80356001600160a01b038116811461391657600080fd5b919050565b60008083601f84011261392d57600080fd5b50813567ffffffffffffffff81111561394557600080fd5b6020830191508360208260051b850101111561396057600080fd5b9250929050565b803561ffff8116811461391657600080fd5b60006020828403121561398b57600080fd5b6138b1826138ff565b600080604083850312156139a757600080fd5b6139b0836138ff565b91506139be602084016138ff565b90509250929050565b60008060008060008060a087890312156139e057600080fd5b6139e9876138ff565b95506139f7602088016138ff565b94506040870135935060608701359250608087013567ffffffffffffffff80821115613a2257600080fd5b818901915089601f830112613a3657600080fd5b813581811115613a4557600080fd5b8a6020828501011115613a5757600080fd5b6020830194508093505050509295509295509295565b600080600080600060608688031215613a8557600080fd5b613a8e866138ff565b9450602086013567ffffffffffffffff80821115613aab57600080fd5b613ab789838a0161391b565b90965094506040880135915080821115613ad057600080fd5b50613add8882890161391b565b969995985093965092949392505050565b60008060408385031215613b0157600080fd5b613b0a836138ff565b91506139be60208401613967565b60008060408385031215613b2b57600080fd5b613b34836138ff565b946020939093013593505050565b60008060408385031215613b5557600080fd5b613b5e836138ff565b91506020830135613b6e81613fba565b809150509250929050565b600060208284031215613b8b57600080fd5b8151801515811461371457600080fd5b600060208284031215613bad57600080fd5b6138b182613967565b600060208284031215613bc857600080fd5b5035919050565b600060208284031215613be157600080fd5b5051919050565b600060208284031215613bfa57600080fd5b815161371481613fba565b60008251613c17818460208701613f1b565b9190910192915050565b6001600160a01b03878116825286166020820152604081018590526060810184905260a06080820181905281018290526000828460c0840137600060c0848401015260c0601f19601f8501168301019050979650505050505050565b6020815260008251806020840152613c9c816040850160208701613f1b565b601f01601f19169190910160400192915050565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b60208082526028908201527f43616c6c6572206973206e6f74207468652053747261746567697374206f722060408201526723b7bb32b93737b960c11b606082015260800190565b6020808252600e908201526d1499595b9d1c985b9d0818d85b1b60921b604082015260600190565b600061ffff808316818516808303821115613d7457613d74613f62565b01949350505050565b60008219821115613d9057613d90613f62565b500190565b600082613db257634e487b7160e01b600052601260045260246000fd5b500490565b600181815b80851115613df2578160001904821115613dd857613dd8613f62565b80851615613de557918102915b93841c9390800290613dbc565b509250929050565b60006138b18383600082613e10575060016138b4565b81613e1d575060006138b4565b8160018114613e335760028114613e3d57613e59565b60019150506138b4565b60ff841115613e4e57613e4e613f62565b50506001821b6138b4565b5060208310610133831016604e8410600b8410161715613e7c575081810a6138b4565b613e868383613db7565b8060001904821115613e9a57613e9a613f62565b029392505050565b6000816000190483118215151615613ebc57613ebc613f62565b500290565b60006001600160801b0383811690831681811015613ee157613ee1613f62565b039392505050565b600061ffff83811690831681811015613ee157613ee1613f62565b600082821015613f1657613f16613f62565b500390565b60005b83811015613f36578181015183820152602001613f1e565b83811115610d355750506000910152565b6000600019821415613f5b57613f5b613f62565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b60ff81168114610e4857600080fdfe7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa26469706673582212204c349976718ffeea8451b6fc51a97a047f4b6a442f1c7d8cb4ff7a709c77e97e64736f6c634300080700337bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a", + "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106103835760003560e01c8063636e6c40116101de578063ae69f3cb1161010f578063c9919112116100ad578063e6cc54321161007c578063e6cc5432146107f8578063e829cc161461080c578063eb03654b1461081f578063fc0cfeee1461083257600080fd5b8063c9919112146107c1578063d38bfff4146107c9578063d58e3b3a146107dc578063e45cc9f0146107ef57600080fd5b8063b890ebf6116100e9578063b890ebf61461078b578063bc90106b1461079e578063c5f00841146107b1578063c7af3352146107b957600080fd5b8063ae69f3cb14610752578063b2c9336d14610765578063b888879e1461077857600080fd5b80638e510b521161017c57806394828ffd1161015657806394828ffd146107055780639c82f2a41461070d5780639fa1826e14610720578063a403e4d51461072957600080fd5b80638e510b521461065f5780638ec489a214610668578063937b25811461067b57600080fd5b8063773540b3116101b8578063773540b31461061d5780637a2202f3146106305780637b9a709614610639578063840c4c7a1461064c57600080fd5b8063636e6c40146105e4578063663e64ce146105f75780636c7561e81461060a57600080fd5b8063372aa224116102b857806350ba711c11610256578063570d8e1d11610230578063570d8e1d146105a3578063597c8910146105b65780635d36b190146105c9578063603ea03b146105d157600080fd5b806350ba711c1461056357806352d38e5d1461057657806353ca9f241461057f57600080fd5b80633fc8cef3116102925780633fc8cef31461050357806349c1d54d1461052a5780634a5e42b11461053d5780634bed3bc01461055057600080fd5b8063372aa224146104d55780633b8ae397146104e85780633dbc911f146104fb57600080fd5b80631edfe3da116103255780632da845a8116102ff5780632da845a81461043d5780632e9958ab14610450578063362bd1a31461046357806336b6d944146104c257600080fd5b80631edfe3da1461041a578063207134b0146104235780632b3297f91461042c57600080fd5b80630c340a24116103615780630c340a24146103c15780631072cbea146103e1578063175188e8146103f457806318ce56bd1461040757600080fd5b806309f49bf51461038857806309f6442c146103925780630acbda75146103ae575b600080fd5b610390610845565b005b61039b60385481565b6040519081526020015b60405180910390f35b6103906103bc366004613bb6565b6108be565b6103c9610970565b6040516001600160a01b0390911681526020016103a5565b6103906103ef366004613b18565b61098d565b610390610402366004613979565b610a3a565b6045546103c9906001600160a01b031681565b61039b60395481565b61039b60435481565b6048546001600160a01b03166103c9565b61039061044b366004613979565b610d3b565b61039061045e366004613979565b610dad565b604a54604b5461048f916001600160801b0380821692600160801b928390048216928183169291041684565b604080516001600160801b03958616815293851660208501529184169183019190915290911660608201526080016103a5565b6103906104d0366004613979565b610e1b565b6103906104e3366004613979565b610e4b565b6103906104f6366004613979565b610ebd565b610390610ffa565b6103c97f000000000000000000000000000000000000000000000000000000000000000081565b6042546103c9906001600160a01b031681565b61039061054b366004613979565b611070565b604854600160a01b900461ffff1661039b565b61039b6105713660046139c7565b61137d565b61039b603b5481565b60375461059390600160a01b900460ff1681565b60405190151581526020016103a5565b603f546103c9906001600160a01b031681565b6103906105c4366004613979565b611420565b610390611461565b6049546103c9906001600160a01b031681565b6103906105f2366004613bb6565b611507565b610390610605366004613bb6565b611565565b610390610618366004613b42565b6115be565b61039061062b366004613979565b61183c565b61039b60475481565b610390610647366004613aee565b6118ae565b61039061065a366004613a6d565b6119e4565b61039b60415481565b610390610676366004613bb6565b611a7d565b6106cc610689366004613bb6565b604c60205260009081526040902080546001909101546001600160a01b03821691600160a01b900460ff16906001600160801b0380821691600160801b90041684565b604080516001600160a01b03909516855292151560208501526001600160801b03918216928401929092521660608201526080016103a5565b610390611b32565b61039061071b366004613979565b611ba2565b61039b603a5481565b6103c9610737366004613979565b6040602081905260009182529020546001600160a01b031681565b610390610760366004613a6d565b611c14565b610390610773366004613bb6565b611ca2565b6037546103c9906001600160a01b031681565b610390610799366004613bb6565b611cfb565b6103906107ac366004613994565b611d54565b610390611f96565b61059361200c565b61039061203d565b6103906107d7366004613979565b61207d565b6103906107ea366004613979565b612121565b61039b60465481565b60375461059390600160a81b900460ff1681565b61039061081a366004613b9b565b612193565b61039061082d366004613bb6565b612253565b610390610840366004613979565b612308565b603f546001600160a01b0316331480610861575061086161200c565b6108865760405162461bcd60e51b815260040161087d90613ce7565b60405180910390fd5b6037805460ff60a01b191690556040517fbc044409505c95b6b851433df96e1beae715c909d8e7c1d6d7ab783300d4e3b990600090a1565b6108c661200c565b6108e25760405162461bcd60e51b815260040161087d90613cb0565b6113888111156109345760405162461bcd60e51b815260206004820152601760248201527f62617369732063616e6e6f742065786365656420353025000000000000000000604482015260640161087d565b60438190556040518181527f56287a45051933ea374811b3d5d165033047be5572cac676f7c28b8be4f746c7906020015b60405180910390a150565b6000610988600080516020613fca8339815191525490565b905090565b61099561200c565b6109b15760405162461bcd60e51b815260040161087d90613cb0565b6001600160a01b03821660009081526033602052604090205460ff1615610a1a5760405162461bcd60e51b815260206004820152601760248201527f4f6e6c7920756e737570706f7274656420617373657473000000000000000000604482015260640161087d565b610a36610a25610970565b6001600160a01b03841690836123aa565b5050565b610a4261200c565b610a5e5760405162461bcd60e51b815260040161087d90613cb0565b6001600160a01b03811660009081526035602052604090205460ff16610abe5760405162461bcd60e51b815260206004820152601560248201527414dd1c985d1959de481b9bdd08185c1c1c9bdd9959605a1b604482015260640161087d565b60345460005b81811015610b7657826001600160a01b03166040600060348481548110610aed57610aed613fa4565b60009182526020808320909101546001600160a01b039081168452908301939093526040909101902054161415610b665760405162461bcd60e51b815260206004820181905260248201527f53747261746567792069732064656661756c7420666f7220616e206173736574604482015260640161087d565b610b6f81613f47565b9050610ac4565b506036548060005b82811015610bd657846001600160a01b031660368281548110610ba357610ba3613fa4565b6000918252602090912001546001600160a01b03161415610bc657809150610bd6565b610bcf81613f47565b9050610b7e565b5081811015610d35576036610bec600184613f04565b81548110610bfc57610bfc613fa4565b600091825260209091200154603680546001600160a01b039092169183908110610c2857610c28613fa4565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055506036805480610c6757610c67613f8e565b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b03861680835260359091526040808320805460ff19169055805163429c145b60e11b81529051879363853828b6926004808201939182900301818387803b158015610cde57600080fd5b505af1158015610cf2573d6000803e3d6000fd5b50506040516001600160a01b03881681527f09a1db4b80c32706328728508c941a6b954f31eb5affd32f236c1fd405f8fea49250602001905060405180910390a1505b50505050565b610d4361200c565b610d5f5760405162461bcd60e51b815260040161087d90613cb0565b604280546001600160a01b0319166001600160a01b0383169081179091556040519081527f1e4af5ac389e8cde1bdaa6830881b6c987c62a45cfb3b33d27d805cde3b5775090602001610965565b610db561200c565b610dd15760405162461bcd60e51b815260040161087d90613cb0565b604980546001600160a01b0319166001600160a01b0383169081179091556040517faf2910d9759321733de15af1827a49830692912adeb2b3646334861f2cd2eed490600090a250565b610e2361200c565b610e3f5760405162461bcd60e51b815260040161087d90613cb0565b610e4881612401565b50565b610e5361200c565b610e6f5760405162461bcd60e51b815260040161087d90613cb0565b603780546001600160a01b0319166001600160a01b0383169081179091556040519081527fb266add5f3044b17d27db796af992cecbe413921b4e8aaaee03c719e16b9806a90602001610965565b610ec561200c565b610ee15760405162461bcd60e51b815260040161087d90613cb0565b6001600160a01b03811660009081526035602052604090205460ff1615610f4a5760405162461bcd60e51b815260206004820152601960248201527f537472617465677920616c726561647920617070726f76656400000000000000604482015260640161087d565b6040805180820182526001808252600060208084018281526001600160a01b038716808452603583528684209551865460ff19169015151786559051948401949094556036805493840181559091527f4a11f94e20a93c79f6ec743a1954ec4fc2c08429ae2122118bf234b2185c81b890910180546001600160a01b0319168317905591519081527f960dd94cbb79169f09a4e445d58b895df2d9bffa5b31055d0932d801724a20d19101610965565b603f546001600160a01b0316331480611016575061101661200c565b6110325760405162461bcd60e51b815260040161087d90613ce7565b6037805460ff60a81b1916600160a81b1790556040517f71f0e5b62f846a22e0b4d159e516e62fa9c2b8eb570be15f83e67d98a2ee51e090600090a1565b61107861200c565b6110945760405162461bcd60e51b815260040161087d90613cb0565b6001600160a01b03811660009081526033602052604090205460ff166110f25760405162461bcd60e51b8152602060048201526013602482015272105cdcd95d081b9bdd081cdd5c1c1bdc9d1959606a1b604482015260640161087d565b604051632fa8a91360e11b81526001600160a01b03821660048201526509184e72a000903090635f5152269060240160206040518083038186803b15801561113957600080fd5b505afa15801561114d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111719190613bcf565b11156111bf5760405162461bcd60e51b815260206004820152601760248201527f5661756c74207374696c6c20686f6c6473206173736574000000000000000000604482015260640161087d565b6034548060005b8281101561121e57836001600160a01b0316603482815481106111eb576111eb613fa4565b6000918252602090912001546001600160a01b0316141561120e5780915061121e565b61121781613f47565b90506111c6565b50603461122c600184613f04565b8154811061123c5761123c613fa4565b600091825260209091200154603480546001600160a01b03909216918390811061126857611268613fa4565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060348054806112a7576112a7613f8e565b60008281526020808220600019908401810180546001600160a01b031990811690915593019093556001600160a01b038616808252604080855280832080549094169093558251908152928301527fba58ce12801c949fa65f41c46ed108671c219baf945fa48d21026cea99ff252a910160405180910390a16001600160a01b038316600081815260336020908152604091829020805464ffffffffff1916905590519182527f37803e2125c48ee96c38ddf04e826daf335b0e1603579040fd275aba6d06b6fc910160405180910390a1505050565b7f53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac453580546000919060028114156113c55760405162461bcd60e51b815260040161087d90613d2f565b60028255603f546001600160a01b03163314806113e557506113e561200c565b6114015760405162461bcd60e51b815260040161087d90613ce7565b61140f898989898989612517565b600190925550979650505050505050565b603f546001600160a01b031633148061143c575061143c61200c565b6114585760405162461bcd60e51b815260040161087d90613ce7565b610e488161267d565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b0316146114fc5760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b606482015260840161087d565b611505336126dc565b565b61150f61200c565b61152b5760405162461bcd60e51b815260040161087d90613cb0565b600060465560478190556040518181527fc29d6fedbc6bdf267a08166c2b976fbd72aca5d6a769528616f8b9224c8f197f90602001610965565b61156d61200c565b6115895760405162461bcd60e51b815260040161087d90613cb0565b60418190556040518181527f95201f9c21f26877223b1ff4073936a6484c35495649e60e55730497aeb60d9390602001610965565b6115c661200c565b6115e25760405162461bcd60e51b815260040161087d90613cb0565b6001600160a01b03821660009081526033602052604090205460ff161561164b5760405162461bcd60e51b815260206004820152601760248201527f417373657420616c726561647920737570706f72746564000000000000000000604482015260640161087d565b60405180608001604052806001151581526020018260ff16600181111561167457611674613f78565b600181111561168557611685613f78565b81526000602080830182905260409283018290526001600160a01b0386168252603381529190208251815490151560ff19821681178355928401519192839161ff001990911661ffff19909116176101008360018111156116e8576116e8613f78565b02179055506040820151815460609093015161ffff1663010000000264ffff0000001960ff90921662010000029190911664ffffff0000199093169290921791909117905561173682612401565b603480546001810182556000919091527f46bddb1178e94d7f2892ff5f366840eb658911794f2c3a44c450aa2c505186c10180546001600160a01b0319166001600160a01b038481169182179092556037546040516315d5220f60e31b815260048101929092529091169063aea910789060240160206040518083038186803b1580156117c257600080fd5b505afa1580156117d6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117fa9190613bcf565b506040516001600160a01b03831681527f4f1ac48525e50059cc1cc6e0e1940ece0dd653a4db4841538d6aef036be2fb7b906020015b60405180910390a15050565b61184461200c565b6118605760405162461bcd60e51b815260040161087d90613cb0565b603f80546001600160a01b0319166001600160a01b0383169081179091556040519081527f869e0abd13cc3a975de7b93be3df1cb2255c802b1cead85963cc79d99f131bee90602001610965565b6118b661200c565b6118d25760405162461bcd60e51b815260040161087d90613cb0565b6001600160a01b03821660009081526033602052604090205460ff166119305760405162461bcd60e51b8152602060048201526013602482015272105cdcd95d081b9bdd081cdd5c1c1bdc9d1959606a1b604482015260640161087d565b6103e88161ffff16106119795760405162461bcd60e51b81526020600482015260116024820152700a6d8d2e0e0c2ceca40e8dede40d0d2ced607b1b604482015260640161087d565b6001600160a01b038216600081815260336020908152604091829020805464ffff0000001916630100000061ffff8716908102919091179091558251938452908301527f8d22e9d2cbe8bb65a3c4412bd8970743864512a1a0e004e8d00fb96277b78b949101611830565b603f546001600160a01b0316331480611a005750611a0061200c565b611a1c5760405162461bcd60e51b815260040161087d90613ce7565b7f53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac453580546002811415611a605760405162461bcd60e51b815260040161087d90613d2f565b60028255611a71878787878761279d565b50600190555050505050565b603f546001600160a01b0316331480611a995750611a9961200c565b611ab55760405162461bcd60e51b815260040161087d90613ce7565b670de0b6b3a7640000811115611afd5760405162461bcd60e51b815260206004820152600d60248201526c496e76616c69642076616c756560981b604482015260640161087d565b60398190556040518181527f41ecb23a0e7865b25f38c268b7c3012220d822929e9edff07326e89d5bb822b590602001610965565b603f546001600160a01b0316331480611b4e5750611b4e61200c565b611b6a5760405162461bcd60e51b815260040161087d90613ce7565b6037805460ff60a81b191690556040517f891ebab18da80ebeeea06b1b1cede098329c4c008906a98370c2ac7a80b571cb90600090a1565b611baa61200c565b611bc65760405162461bcd60e51b815260040161087d90613cb0565b604880546001600160a01b0319166001600160a01b0383169081179091556040519081527f7d7719313229e558c5a3893cad2eb86a86a049156d1d9ebd5c63a8eedefd1c0390602001610965565b603f546001600160a01b0316331480611c305750611c3061200c565b611c4c5760405162461bcd60e51b815260040161087d90613ce7565b7f53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac453580546002811415611c905760405162461bcd60e51b815260040161087d90613d2f565b60028255611a713088888888886129d5565b611caa61200c565b611cc65760405162461bcd60e51b815260040161087d90613cb0565b603a8190556040518181527f2ec5fb5a3d2703edc461252d92ccd2799c3c74f01d97212b20388207fa17ae4590602001610965565b611d0361200c565b611d1f5760405162461bcd60e51b815260040161087d90613cb0565b603b8190556040518181527f39367850377ac04920a9a670f2180e7a94d83b15ad302e59875ec58fd10bd37d90602001610965565b603f546001600160a01b0316331480611d705750611d7061200c565b611d8c5760405162461bcd60e51b815260040161087d90613ce7565b604080516001600160a01b038085168252831660208201527fba58ce12801c949fa65f41c46ed108671c219baf945fa48d21026cea99ff252a910160405180910390a16001600160a01b03811615611f68576001600160a01b03811660009081526035602052604090205460ff16611e3e5760405162461bcd60e51b815260206004820152601560248201527414dd1c985d1959de481b9bdd08185c1c1c9bdd9959605a1b604482015260640161087d565b6001600160a01b038216600090815260336020526040902054819060ff16611ea15760405162461bcd60e51b8152602060048201526016602482015275105cdcd95d081a5cc81b9bdd081cdd5c1c1bdc9d195960521b604482015260640161087d565b60405163551c457b60e11b81526001600160a01b03848116600483015282169063aa388af69060240160206040518083038186803b158015611ee257600080fd5b505afa158015611ef6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f1a9190613b79565b611f665760405162461bcd60e51b815260206004820152601f60248201527f4173736574206e6f7420737570706f7274656420627920537472617465677900604482015260640161087d565b505b6001600160a01b03918216600090815260406020819052902080546001600160a01b03191691909216179055565b603f546001600160a01b0316331480611fb25750611fb261200c565b611fce5760405162461bcd60e51b815260040161087d90613ce7565b6037805460ff60a01b1916600160a01b1790556040517f8cff26a5985614b3d30629cc4ab83824bf115aec971b718d8f2f99562032e97290600090a1565b6000612024600080516020613fca8339815191525490565b6001600160a01b0316336001600160a01b031614905090565b603f546001600160a01b0316331480612059575061205961200c565b6120755760405162461bcd60e51b815260040161087d90613ce7565b611505612a3e565b61208561200c565b6120a15760405162461bcd60e51b815260040161087d90613cb0565b6120c9817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b03166120e9600080516020613fca8339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b61212961200c565b6121455760405162461bcd60e51b815260040161087d90613cb0565b604580546001600160a01b0319166001600160a01b0383169081179091556040519081527fa12850fb726e0b2b7b3c9a9342031e1268a8148d0eb06b4bea8613204ffcd2b890602001610965565b61219b61200c565b6121b75760405162461bcd60e51b815260040161087d90613cb0565b6127118161ffff16106122035760405162461bcd60e51b8152602060048201526014602482015273496e76616c696420626173697320706f696e747360601b604482015260640161087d565b6048805461ffff60a01b1916600160a01b61ffff8416908102919091179091556040519081527ff12c00256bee2b6facb111a88a9b1cff86e79132939b44f1353212d6f746955790602001610965565b61225b61200c565b6122775760405162461bcd60e51b815260040161087d90613cb0565b6103e88111156122d35760405162461bcd60e51b815260206004820152602160248201527f52656465656d206665652073686f756c64206e6f74206265206f7665722031306044820152602560f81b606482015260840161087d565b60388190556040518181527fd6c7508d6658ccee36b7b7d7fd72e5cbaeefb40c64eff24e9ae7470e846304ee90602001610965565b61231061200c565b61232c5760405162461bcd60e51b815260040161087d90613cb0565b803b6123865760405162461bcd60e51b8152602060048201526024808201527f6e657720696d706c656d656e746174696f6e206973206e6f74206120636f6e746044820152631c9858dd60e21b606482015260840161087d565b7fa2bd3d3cf188a41358c8b401076eb59066b09dec5775650c0de4c55187d17bd955565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b1790526123fc908490612a95565b505050565b6001600160a01b0381166000908152603360205260409020805462010000900460ff161561242d575050565b6000826001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b15801561246857600080fd5b505afa15801561247c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124a09190613be8565b905060068160ff16101580156124ba575060128160ff1611155b6124fd5760405162461bcd60e51b81526020600482015260146024820152732ab732bc3832b1ba32b210383932b1b4b9b4b7b760611b604482015260640161087d565b815460ff909116620100000262ff00001990911617905550565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316876001600160a01b0316141561259b5760405162461bcd60e51b815260206004820152601c60248201527f737761702066726f6d2057455448206e6f7420737570706f7274656400000000604482015260640161087d565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316866001600160a01b0316146126105760405162461bcd60e51b81526020600482015260116024820152700dedcd8f240e6eec2e040e8de40ae8aa89607b1b604482015260640161087d565b61261e878787878787612b67565b9050306001600160a01b031663b9b17f9f6040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561265b57600080fd5b505af115801561266f573d6000803e3d6000fd5b505050509695505050505050565b612686816132d1565b306001600160a01b031663b9b17f9f6040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156126c157600080fd5b505af11580156126d5573d6000803e3d6000fd5b5050505050565b6001600160a01b0381166127325760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f722069732061646472657373283029000000000000604482015260640161087d565b806001600160a01b0316612752600080516020613fca8339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a3610e4881600080516020613fca83398151915255565b6001600160a01b03851660009081526035602052604090205460ff166127fb5760405162461bcd60e51b8152602060048201526013602482015272496e76616c696420746f20537472617465677960681b604482015260640161087d565b60018314801561280b5750600181145b801561286f57507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168484600081811061284f5761284f613fa4565b90506020020160208101906128649190613979565b6001600160a01b0316145b6128b45760405162461bcd60e51b815260206004820152601660248201527513db9b1e4815d15512081a5cc81cdd5c1c1bdc9d195960521b604482015260640161087d565b6128bc613395565b828260008181106128cf576128cf613fa4565b9050602002013511156129245760405162461bcd60e51b815260206004820152601960248201527f4e6f7420656e6f756768205745544820617661696c61626c6500000000000000604482015260640161087d565b61297b858383600081811061293b5761293b613fa4565b905060200201357f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166123aa9092919063ffffffff16565b846001600160a01b031663de5f62686040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156129b657600080fd5b505af11580156129ca573d6000803e3d6000fd5b505050505050505050565b6129e38686868686866134e2565b306001600160a01b031663b9b17f9f6040518163ffffffff1660e01b8152600401600060405180830381600087803b158015612a1e57600080fd5b505af1158015612a32573d6000803e3d6000fd5b50505050505050505050565b612a46613670565b306001600160a01b031663b9b17f9f6040518163ffffffff1660e01b8152600401600060405180830381600087803b158015612a8157600080fd5b505af1158015610d35573d6000803e3d6000fd5b6000612aea826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166137029092919063ffffffff16565b8051909150156123fc5780806020019051810190612b089190613b79565b6123fc5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840161087d565b6001600160a01b0386166000908152603360209081526040808320815160808101909252805460ff8082161515845285948401916101009004166001811115612bb257612bb2613f78565b6001811115612bc357612bc3613f78565b8152905462010000810460ff908116602080850191909152630100000090920461ffff166040938401526001600160a01b038b1660009081526033835283812084516080810190955280548084161515865295965090949092840191610100909104166001811115612c3757612c37613f78565b6001811115612c4857612c48613f78565b8152905462010000810460ff1660208301526301000000900461ffff166040909101528251909150612cbc5760405162461bcd60e51b815260206004820152601b60248201527f46726f6d206173736574206973206e6f7420737570706f727465640000000000604482015260640161087d565b8051612d0a5760405162461bcd60e51b815260206004820152601960248201527f546f206173736574206973206e6f7420737570706f7274656400000000000000604482015260640161087d565b6040805180820182526048546001600160a01b038082168352600160a01b90910461ffff16602083015291516370a0823160e01b81523060048201529091600091908b16906370a082319060240160206040518083038186803b158015612d7057600080fd5b505afa158015612d84573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612da89190613bcf565b8251909150612dc2906001600160a01b038d16908b6123aa565b81516001600160a01b0316632506c0188c8c612ddf60018e613f04565b8c8c8c6040518763ffffffff1660e01b8152600401612e0396959493929190613c21565b602060405180830381600087803b158015612e1d57600080fd5b505af1158015612e31573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e559190613bcf565b506040516370a0823160e01b815230600482015281906001600160a01b038c16906370a082319060240160206040518083038186803b158015612e9757600080fd5b505afa158015612eab573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ecf9190613bcf565b612ed99190613f04565b94505086841015612f2c5760405162461bcd60e51b815260206004820152601960248201527f5374726174656769737420736c697070616765206c696d697400000000000000604482015260640161087d565b60008260600151612710612f409190613d57565b6037546040516315d5220f60e31b81526001600160a01b038d8116600483015261ffff93909316929091169063aea910789060240160206040518083038186803b158015612f8d57600080fd5b505afa158015612fa1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fc59190613bcf565b612fcf9190613ea2565b6037546040516315d5220f60e31b81526001600160a01b038e811660048301529091169063aea910789060240160206040518083038186803b15801561301457600080fd5b505afa158015613028573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061304c9190613bcf565b606086015161305d90612710613ee9565b61306b9061ffff168c613ea2565b6130759190613ea2565b61307f9190613d95565b905061309e6012856040015160ff168361371b9092919063ffffffff16565b60408401516130b490879060129060ff1661371b565b10156131025760405162461bcd60e51b815260206004820152601e60248201527f4f7261636c6520736c697070616765206c696d69742065786365656465640000604482015260640161087d565b5061271081602001516127106131189190613ee9565b61ffff16603c60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561316a57600080fd5b505afa15801561317e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131a29190613bcf565b6131ac9190613ea2565b6131b69190613d95565b306001600160a01b031663d4c3eea06040518163ffffffff1660e01b815260040160206040518083038186803b1580156131ef57600080fd5b505afa158015613203573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132279190613bcf565b101561326e5760405162461bcd60e51b8152602060048201526016602482015275416c6c6f7765642076616c7565203c20737570706c7960501b604482015260640161087d565b886001600160a01b03168a6001600160a01b03167fa078c4190abe07940190effc1846be0ccf03ad6007bc9e93f9697d0b460befbb8a876040516132bc929190918252602082015260400190565b60405180910390a35050509695505050505050565b6001600160a01b03811660009081526035602052604090205460ff166133395760405162461bcd60e51b815260206004820152601960248201527f5374726174656779206973206e6f7420737570706f7274656400000000000000604482015260640161087d565b6000819050806001600160a01b031663853828b66040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561337957600080fd5b505af115801561338d573d6000803e3d6000fd5b505050505050565b60408051608081018252604a546001600160801b03808216808452600160801b92839004821660208501819052604b54808416968601969096529290940416606083015260009283916133e791613ec1565b6040516370a0823160e01b81523060048201526001600160801b039190911691506000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a082319060240160206040518083038186803b15801561345757600080fd5b505afa15801561346b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061348f9190613bcf565b90506000836040015184602001516134a79190613ec1565b6001600160801b031690506134bc8184613d7d565b8211156134db57806134ce8484613f04565b6134d89190613f04565b94505b5050505090565b6001600160a01b03851660009081526035602052604090205460ff166135425760405162461bcd60e51b8152602060048201526015602482015274496e76616c69642066726f6d20537472617465677960581b604482015260640161087d565b8281146135915760405162461bcd60e51b815260206004820152601960248201527f506172616d65746572206c656e677468206d69736d6174636800000000000000604482015260640161087d565b8260005b8181101561366657866001600160a01b031663d9caed12898888858181106135bf576135bf613fa4565b90506020020160208101906135d49190613979565b8787868181106135e6576135e6613fa4565b6040516001600160e01b031960e088901b1681526001600160a01b03958616600482015294909316602485015250602090910201356044820152606401600060405180830381600087803b15801561363d57600080fd5b505af1158015613651573d6000803e3d6000fd5b505050508061365f90613f47565b9050613595565b5050505050505050565b60365460005b81811015610a36576036818154811061369157613691613fa4565b60009182526020822001546040805163429c145b60e11b815290516001600160a01b039092169263853828b69260048084019382900301818387803b1580156136d957600080fd5b505af11580156136ed573d6000803e3d6000fd5b50505050806136fb90613f47565b9050613676565b6060613711848460008561377d565b90505b9392505050565b60008183111561374b576137446137328385613f04565b61373d90600a613dfa565b85906138a5565b9350613775565b81831015613775576137726137608484613f04565b61376b90600a613dfa565b85906138ba565b93505b509192915050565b6060824710156137de5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840161087d565b843b61382c5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161087d565b600080866001600160a01b031685876040516138489190613c05565b60006040518083038185875af1925050503d8060008114613885576040519150601f19603f3d011682016040523d82523d6000602084013e61388a565b606091505b509150915061389a8282866138c6565b979650505050505050565b60006138b18284613ea2565b90505b92915050565b60006138b18284613d95565b606083156138d5575081613714565b8251156138e55782518084602001fd5b8160405162461bcd60e51b815260040161087d9190613c7d565b80356001600160a01b038116811461391657600080fd5b919050565b60008083601f84011261392d57600080fd5b50813567ffffffffffffffff81111561394557600080fd5b6020830191508360208260051b850101111561396057600080fd5b9250929050565b803561ffff8116811461391657600080fd5b60006020828403121561398b57600080fd5b6138b1826138ff565b600080604083850312156139a757600080fd5b6139b0836138ff565b91506139be602084016138ff565b90509250929050565b60008060008060008060a087890312156139e057600080fd5b6139e9876138ff565b95506139f7602088016138ff565b94506040870135935060608701359250608087013567ffffffffffffffff80821115613a2257600080fd5b818901915089601f830112613a3657600080fd5b813581811115613a4557600080fd5b8a6020828501011115613a5757600080fd5b6020830194508093505050509295509295509295565b600080600080600060608688031215613a8557600080fd5b613a8e866138ff565b9450602086013567ffffffffffffffff80821115613aab57600080fd5b613ab789838a0161391b565b90965094506040880135915080821115613ad057600080fd5b50613add8882890161391b565b969995985093965092949392505050565b60008060408385031215613b0157600080fd5b613b0a836138ff565b91506139be60208401613967565b60008060408385031215613b2b57600080fd5b613b34836138ff565b946020939093013593505050565b60008060408385031215613b5557600080fd5b613b5e836138ff565b91506020830135613b6e81613fba565b809150509250929050565b600060208284031215613b8b57600080fd5b8151801515811461371457600080fd5b600060208284031215613bad57600080fd5b6138b182613967565b600060208284031215613bc857600080fd5b5035919050565b600060208284031215613be157600080fd5b5051919050565b600060208284031215613bfa57600080fd5b815161371481613fba565b60008251613c17818460208701613f1b565b9190910192915050565b6001600160a01b03878116825286166020820152604081018590526060810184905260a06080820181905281018290526000828460c0840137600060c0848401015260c0601f19601f8501168301019050979650505050505050565b6020815260008251806020840152613c9c816040850160208701613f1b565b601f01601f19169190910160400192915050565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b60208082526028908201527f43616c6c6572206973206e6f74207468652053747261746567697374206f722060408201526723b7bb32b93737b960c11b606082015260800190565b6020808252600e908201526d1499595b9d1c985b9d0818d85b1b60921b604082015260600190565b600061ffff808316818516808303821115613d7457613d74613f62565b01949350505050565b60008219821115613d9057613d90613f62565b500190565b600082613db257634e487b7160e01b600052601260045260246000fd5b500490565b600181815b80851115613df2578160001904821115613dd857613dd8613f62565b80851615613de557918102915b93841c9390800290613dbc565b509250929050565b60006138b18383600082613e10575060016138b4565b81613e1d575060006138b4565b8160018114613e335760028114613e3d57613e59565b60019150506138b4565b60ff841115613e4e57613e4e613f62565b50506001821b6138b4565b5060208310610133831016604e8410600b8410161715613e7c575081810a6138b4565b613e868383613db7565b8060001904821115613e9a57613e9a613f62565b029392505050565b6000816000190483118215151615613ebc57613ebc613f62565b500290565b60006001600160801b0383811690831681811015613ee157613ee1613f62565b039392505050565b600061ffff83811690831681811015613ee157613ee1613f62565b600082821015613f1657613f16613f62565b500390565b60005b83811015613f36578181015183820152602001613f1e565b83811115610d355750506000910152565b6000600019821415613f5b57613f5b613f62565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b60ff81168114610e4857600080fdfe7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa26469706673582212204c349976718ffeea8451b6fc51a97a047f4b6a442f1c7d8cb4ff7a709c77e97e64736f6c63430008070033", "libraries": {}, "devdoc": { "author": "Origin Protocol Inc", @@ -1192,6 +1420,11 @@ "_strategyToAddress": "Address of the Strategy to deposit assets into." } }, + "removeAsset(address)": { + "params": { + "_asset": "Address of asset" + } + }, "removeStrategy(address)": { "params": { "_addr": "Address of the strategy to remove" @@ -1213,6 +1446,11 @@ "_threshold": "OToken amount with 18 fixed decimals." } }, + "setDripper(address)": { + "params": { + "_dripper": "Address of the Dripper contract." + } + }, "setNetOusdMintForStrategyThreshold(uint256)": { "params": { "_threshold": "OToken amount with 18 fixed decimals." @@ -1335,6 +1573,9 @@ "depositToStrategy(address,address[],uint256[])": { "notice": "Deposit multiple assets from the vault into the strategy." }, + "dripper()": { + "notice": "Address of the Dripper contract that streams harvested rewards to the Vault" + }, "governor()": { "notice": "Returns the address of the current Governor." }, @@ -1371,6 +1612,9 @@ "redeemFeeBps()": { "notice": "Redemption fee in basis points. eg 50 = 0.5%" }, + "removeAsset(address)": { + "notice": "Remove a supported asset from the Vault" + }, "removeStrategy(address)": { "notice": "Remove a strategy from the Vault." }, @@ -1383,6 +1627,9 @@ "setAutoAllocateThreshold(uint256)": { "notice": "Sets the minimum amount of OTokens in a mint to trigger an automatic allocation of funds afterwords." }, + "setDripper(address)": { + "notice": "Set the Dripper contract that streams harvested rewards to the vault." + }, "setMaxSupplyDiff(uint256)": { "notice": "Sets the maximum allowable difference between total supply and backing assets' value." }, @@ -1470,7 +1717,7 @@ "storageLayout": { "storage": [ { - "astId": 41419, + "astId": 24111, "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", "label": "initialized", "offset": 0, @@ -1478,7 +1725,7 @@ "type": "t_bool" }, { - "astId": 41422, + "astId": 24114, "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", "label": "initializing", "offset": 1, @@ -1486,7 +1733,7 @@ "type": "t_bool" }, { - "astId": 41462, + "astId": 24154, "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", "label": "______gap", "offset": 0, @@ -1494,15 +1741,15 @@ "type": "t_array(t_uint256)50_storage" }, { - "astId": 46069, + "astId": 29745, "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", "label": "assets", "offset": 0, "slot": "51", - "type": "t_mapping(t_address,t_struct(Asset)46063_storage)" + "type": "t_mapping(t_address,t_struct(Asset)29739_storage)" }, { - "astId": 46073, + "astId": 29749, "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", "label": "allAssets", "offset": 0, @@ -1510,15 +1757,15 @@ "type": "t_array(t_address)dyn_storage" }, { - "astId": 46084, + "astId": 29760, "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", "label": "strategies", "offset": 0, "slot": "53", - "type": "t_mapping(t_address,t_struct(Strategy)46078_storage)" + "type": "t_mapping(t_address,t_struct(Strategy)29754_storage)" }, { - "astId": 46088, + "astId": 29764, "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", "label": "allStrategies", "offset": 0, @@ -1526,7 +1773,7 @@ "type": "t_array(t_address)dyn_storage" }, { - "astId": 46091, + "astId": 29767, "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", "label": "priceProvider", "offset": 0, @@ -1534,7 +1781,7 @@ "type": "t_address" }, { - "astId": 46095, + "astId": 29771, "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", "label": "rebasePaused", "offset": 20, @@ -1542,7 +1789,7 @@ "type": "t_bool" }, { - "astId": 46099, + "astId": 29775, "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", "label": "capitalPaused", "offset": 21, @@ -1550,7 +1797,7 @@ "type": "t_bool" }, { - "astId": 46102, + "astId": 29778, "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", "label": "redeemFeeBps", "offset": 0, @@ -1558,7 +1805,7 @@ "type": "t_uint256" }, { - "astId": 46105, + "astId": 29781, "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", "label": "vaultBuffer", "offset": 0, @@ -1566,7 +1813,7 @@ "type": "t_uint256" }, { - "astId": 46108, + "astId": 29784, "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", "label": "autoAllocateThreshold", "offset": 0, @@ -1574,7 +1821,7 @@ "type": "t_uint256" }, { - "astId": 46111, + "astId": 29787, "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", "label": "rebaseThreshold", "offset": 0, @@ -1582,15 +1829,15 @@ "type": "t_uint256" }, { - "astId": 46115, + "astId": 29791, "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", "label": "oUSD", "offset": 0, "slot": "60", - "type": "t_contract(OUSD)40245" + "type": "t_contract(OUSD)23477" }, { - "astId": 46124, + "astId": 29800, "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", "label": "_deprecated_rebaseHooksAddr", "offset": 0, @@ -1598,7 +1845,7 @@ "type": "t_address" }, { - "astId": 46130, + "astId": 29806, "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", "label": "_deprecated_uniswapAddr", "offset": 0, @@ -1606,7 +1853,7 @@ "type": "t_address" }, { - "astId": 46137, + "astId": 29813, "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", "label": "strategistAddr", "offset": 0, @@ -1614,7 +1861,7 @@ "type": "t_address" }, { - "astId": 46142, + "astId": 29818, "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", "label": "assetDefaultStrategies", "offset": 0, @@ -1622,7 +1869,7 @@ "type": "t_mapping(t_address,t_address)" }, { - "astId": 46145, + "astId": 29821, "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", "label": "maxSupplyDiff", "offset": 0, @@ -1630,7 +1877,7 @@ "type": "t_uint256" }, { - "astId": 46148, + "astId": 29824, "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", "label": "trusteeAddress", "offset": 0, @@ -1638,7 +1885,7 @@ "type": "t_address" }, { - "astId": 46151, + "astId": 29827, "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", "label": "trusteeFeeBps", "offset": 0, @@ -1646,7 +1893,7 @@ "type": "t_uint256" }, { - "astId": 46155, + "astId": 29831, "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", "label": "_deprecated_swapTokens", "offset": 0, @@ -1654,7 +1901,7 @@ "type": "t_array(t_address)dyn_storage" }, { - "astId": 46165, + "astId": 29841, "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", "label": "ousdMetaStrategy", "offset": 0, @@ -1662,7 +1909,7 @@ "type": "t_address" }, { - "astId": 46169, + "astId": 29845, "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", "label": "netOusdMintedForStrategy", "offset": 0, @@ -1670,7 +1917,7 @@ "type": "t_int256" }, { - "astId": 46173, + "astId": 29849, "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", "label": "netOusdMintForStrategyThreshold", "offset": 0, @@ -1678,20 +1925,44 @@ "type": "t_uint256" }, { - "astId": 46194, + "astId": 29870, "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", "label": "swapConfig", "offset": 0, "slot": "72", - "type": "t_struct(SwapConfig)46184_storage" + "type": "t_struct(SwapConfig)29860_storage" }, { - "astId": 46198, + "astId": 29873, "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", - "label": "__gap", + "label": "dripper", "offset": 0, "slot": "73", - "type": "t_array(t_uint256)50_storage" + "type": "t_address" + }, + { + "astId": 29885, + "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", + "label": "withdrawalQueueMetadata", + "offset": 0, + "slot": "74", + "type": "t_struct(WithdrawalQueueMetadata)29882_storage" + }, + { + "astId": 29899, + "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", + "label": "withdrawalRequests", + "offset": 0, + "slot": "76", + "type": "t_mapping(t_uint256,t_struct(WithdrawalRequest)29894_storage)" + }, + { + "astId": 29903, + "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", + "label": "__gap", + "offset": 0, + "slot": "77", + "type": "t_array(t_uint256)46_storage" } ], "types": { @@ -1706,6 +1977,12 @@ "label": "address[]", "numberOfBytes": "32" }, + "t_array(t_uint256)46_storage": { + "base": "t_uint256", + "encoding": "inplace", + "label": "uint256[46]", + "numberOfBytes": "1472" + }, "t_array(t_uint256)50_storage": { "base": "t_uint256", "encoding": "inplace", @@ -1717,12 +1994,12 @@ "label": "bool", "numberOfBytes": "1" }, - "t_contract(OUSD)40245": { + "t_contract(OUSD)23477": { "encoding": "inplace", "label": "contract OUSD", "numberOfBytes": "20" }, - "t_enum(UnitConversion)46053": { + "t_enum(UnitConversion)29729": { "encoding": "inplace", "label": "enum VaultStorage.UnitConversion", "numberOfBytes": "1" @@ -1739,26 +2016,33 @@ "numberOfBytes": "32", "value": "t_address" }, - "t_mapping(t_address,t_struct(Asset)46063_storage)": { + "t_mapping(t_address,t_struct(Asset)29739_storage)": { "encoding": "mapping", "key": "t_address", "label": "mapping(address => struct VaultStorage.Asset)", "numberOfBytes": "32", - "value": "t_struct(Asset)46063_storage" + "value": "t_struct(Asset)29739_storage" }, - "t_mapping(t_address,t_struct(Strategy)46078_storage)": { + "t_mapping(t_address,t_struct(Strategy)29754_storage)": { "encoding": "mapping", "key": "t_address", "label": "mapping(address => struct VaultStorage.Strategy)", "numberOfBytes": "32", - "value": "t_struct(Strategy)46078_storage" + "value": "t_struct(Strategy)29754_storage" }, - "t_struct(Asset)46063_storage": { + "t_mapping(t_uint256,t_struct(WithdrawalRequest)29894_storage)": { + "encoding": "mapping", + "key": "t_uint256", + "label": "mapping(uint256 => struct VaultStorage.WithdrawalRequest)", + "numberOfBytes": "32", + "value": "t_struct(WithdrawalRequest)29894_storage" + }, + "t_struct(Asset)29739_storage": { "encoding": "inplace", "label": "struct VaultStorage.Asset", "members": [ { - "astId": 46055, + "astId": 29731, "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", "label": "isSupported", "offset": 0, @@ -1766,15 +2050,15 @@ "type": "t_bool" }, { - "astId": 46058, + "astId": 29734, "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", "label": "unitConversion", "offset": 1, "slot": "0", - "type": "t_enum(UnitConversion)46053" + "type": "t_enum(UnitConversion)29729" }, { - "astId": 46060, + "astId": 29736, "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", "label": "decimals", "offset": 2, @@ -1782,7 +2066,7 @@ "type": "t_uint8" }, { - "astId": 46062, + "astId": 29738, "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", "label": "allowedOracleSlippageBps", "offset": 3, @@ -1792,12 +2076,12 @@ ], "numberOfBytes": "32" }, - "t_struct(Strategy)46078_storage": { + "t_struct(Strategy)29754_storage": { "encoding": "inplace", "label": "struct VaultStorage.Strategy", "members": [ { - "astId": 46075, + "astId": 29751, "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", "label": "isSupported", "offset": 0, @@ -1805,7 +2089,7 @@ "type": "t_bool" }, { - "astId": 46077, + "astId": 29753, "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", "label": "_deprecated", "offset": 0, @@ -1815,12 +2099,12 @@ ], "numberOfBytes": "64" }, - "t_struct(SwapConfig)46184_storage": { + "t_struct(SwapConfig)29860_storage": { "encoding": "inplace", "label": "struct VaultStorage.SwapConfig", "members": [ { - "astId": 46181, + "astId": 29857, "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", "label": "swapper", "offset": 0, @@ -1828,7 +2112,7 @@ "type": "t_address" }, { - "astId": 46183, + "astId": 29859, "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", "label": "allowedUndervalueBps", "offset": 20, @@ -1838,6 +2122,89 @@ ], "numberOfBytes": "32" }, + "t_struct(WithdrawalQueueMetadata)29882_storage": { + "encoding": "inplace", + "label": "struct VaultStorage.WithdrawalQueueMetadata", + "members": [ + { + "astId": 29875, + "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", + "label": "queued", + "offset": 0, + "slot": "0", + "type": "t_uint128" + }, + { + "astId": 29877, + "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", + "label": "claimable", + "offset": 16, + "slot": "0", + "type": "t_uint128" + }, + { + "astId": 29879, + "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", + "label": "claimed", + "offset": 0, + "slot": "1", + "type": "t_uint128" + }, + { + "astId": 29881, + "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", + "label": "nextWithdrawalIndex", + "offset": 16, + "slot": "1", + "type": "t_uint128" + } + ], + "numberOfBytes": "64" + }, + "t_struct(WithdrawalRequest)29894_storage": { + "encoding": "inplace", + "label": "struct VaultStorage.WithdrawalRequest", + "members": [ + { + "astId": 29887, + "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", + "label": "withdrawer", + "offset": 0, + "slot": "0", + "type": "t_address" + }, + { + "astId": 29889, + "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", + "label": "claimed", + "offset": 20, + "slot": "0", + "type": "t_bool" + }, + { + "astId": 29891, + "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", + "label": "amount", + "offset": 0, + "slot": "1", + "type": "t_uint128" + }, + { + "astId": 29893, + "contract": "contracts/vault/OETHVaultAdmin.sol:OETHVaultAdmin", + "label": "queued", + "offset": 16, + "slot": "1", + "type": "t_uint128" + } + ], + "numberOfBytes": "64" + }, + "t_uint128": { + "encoding": "inplace", + "label": "uint128", + "numberOfBytes": "16" + }, "t_uint16": { "encoding": "inplace", "label": "uint16", diff --git a/contracts/deployments/holesky/OETHVaultCore.json b/contracts/deployments/holesky/OETHVaultCore.json index d3580e13ac..97fc97998d 100644 --- a/contracts/deployments/holesky/OETHVaultCore.json +++ b/contracts/deployments/holesky/OETHVaultCore.json @@ -1,5 +1,5 @@ { - "address": "0xE92e25B81E44B8377Df1362f8fFBc426A00d6ef4", + "address": "0x89018e7e6994BBDDC0991743fd30fcEE18Ce4705", "abi": [ { "inputs": [ @@ -69,6 +69,19 @@ "name": "AssetDefaultStrategyUpdated", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_asset", + "type": "address" + } + ], + "name": "AssetRemoved", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -94,6 +107,19 @@ "name": "CapitalUnpaused", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_dripper", + "type": "address" + } + ], + "name": "DripperChanged", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -414,6 +440,81 @@ "name": "VaultBufferUpdated", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_claimable", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_newClaimable", + "type": "uint256" + } + ], + "name": "WithdrawalClaimable", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_withdrawer", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "_requestId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + } + ], + "name": "WithdrawalClaimed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_withdrawer", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "_requestId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_queued", + "type": "uint256" + } + ], + "name": "WithdrawalRequested", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -443,6 +544,13 @@ "stateMutability": "nonpayable", "type": "fallback" }, + { + "inputs": [], + "name": "addWithdrawalQueueLiquidity", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [], "name": "allocate", @@ -560,6 +668,62 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "requestId", + "type": "uint256" + } + ], + "name": "claimWithdrawal", + "outputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256[]", + "name": "requestIds", + "type": "uint256[]" + } + ], + "name": "claimWithdrawals", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + }, + { + "internalType": "uint256", + "name": "totalAmount", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "dripper", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "getAllAssets", @@ -932,6 +1096,30 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + } + ], + "name": "requestWithdrawal", + "outputs": [ + { + "internalType": "uint256", + "name": "requestId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "queued", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -1048,52 +1236,117 @@ ], "stateMutability": "view", "type": "function" + }, + { + "inputs": [], + "name": "withdrawalQueueMetadata", + "outputs": [ + { + "internalType": "uint128", + "name": "queued", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "claimable", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "claimed", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "nextWithdrawalIndex", + "type": "uint128" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "withdrawalRequests", + "outputs": [ + { + "internalType": "address", + "name": "withdrawer", + "type": "address" + }, + { + "internalType": "bool", + "name": "claimed", + "type": "bool" + }, + { + "internalType": "uint128", + "name": "amount", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "queued", + "type": "uint128" + } + ], + "stateMutability": "view", + "type": "function" } ], - "transactionHash": "0x9f75d36ce4de616c56e32c5f1e66ea8b705994a63d163d096f71d3e5c1eecdc1", + "transactionHash": "0xd28b24bfaa083ba1af8b408e526ed8dc917f6a372c757591c50fadfcf212d80c", "receipt": { "to": null, "from": "0x1b94CA50D3Ad9f8368851F8526132272d1a5028C", - "contractAddress": "0xE92e25B81E44B8377Df1362f8fFBc426A00d6ef4", - "transactionIndex": 68, - "gasUsed": "3024025", - "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000020000000000000000000800000000000000000000000000000000000004000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000010000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000080000000000000", - "blockHash": "0xf2aa29665c1af068ced76d7b539f3bcc67a7d534c1019c51316beecb731cbc01", - "transactionHash": "0x9f75d36ce4de616c56e32c5f1e66ea8b705994a63d163d096f71d3e5c1eecdc1", + "contractAddress": "0x89018e7e6994BBDDC0991743fd30fcEE18Ce4705", + "transactionIndex": 3, + "gasUsed": "3843460", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000020000100000000000000800000000000000000000000000000000000004000000000000002000000000000000000040000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000010000000000010000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x442c930bd060984abbdc0a15633fa1b620f25febac9df91a526e1c68e0bf25c7", + "transactionHash": "0xd28b24bfaa083ba1af8b408e526ed8dc917f6a372c757591c50fadfcf212d80c", "logs": [ { - "transactionIndex": 68, - "blockNumber": 1405063, - "transactionHash": "0x9f75d36ce4de616c56e32c5f1e66ea8b705994a63d163d096f71d3e5c1eecdc1", - "address": "0xE92e25B81E44B8377Df1362f8fFBc426A00d6ef4", + "transactionIndex": 3, + "blockNumber": 1860257, + "transactionHash": "0xd28b24bfaa083ba1af8b408e526ed8dc917f6a372c757591c50fadfcf212d80c", + "address": "0x89018e7e6994BBDDC0991743fd30fcEE18Ce4705", "topics": [ "0xc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000001b94ca50d3ad9f8368851f8526132272d1a5028c" ], "data": "0x", - "logIndex": 80, - "blockHash": "0xf2aa29665c1af068ced76d7b539f3bcc67a7d534c1019c51316beecb731cbc01" + "logIndex": 1, + "blockHash": "0x442c930bd060984abbdc0a15633fa1b620f25febac9df91a526e1c68e0bf25c7" } ], - "blockNumber": 1405063, - "cumulativeGasUsed": "14256235", + "blockNumber": 1860257, + "cumulativeGasUsed": "4298576", "status": 1, "byzantium": true }, "args": [ - "0x94373a4919b3240d86ea41593d5eba789fef3848" + "0x94373a4919B3240D86eA41593D5eBa789FEF3848" ], - "numDeployments": 1, - "solcInputHash": "da4c2bc4af0be4b969e54f8b43895033", - "metadata": "{\"compiler\":{\"version\":\"0.8.7+commit.e28d00a7\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_weth\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_threshold\",\"type\":\"uint256\"}],\"name\":\"AllocateThresholdUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_strategy\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"AssetAllocated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_strategy\",\"type\":\"address\"}],\"name\":\"AssetDefaultStrategyUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"}],\"name\":\"AssetSupported\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"CapitalPaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"CapitalUnpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousGovernor\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newGovernor\",\"type\":\"address\"}],\"name\":\"GovernorshipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"maxSupplyDiff\",\"type\":\"uint256\"}],\"name\":\"MaxSupplyDiffChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"Mint\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_threshold\",\"type\":\"uint256\"}],\"name\":\"NetOusdMintForStrategyThresholdChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_ousdMetaStrategy\",\"type\":\"address\"}],\"name\":\"OusdMetaStrategyUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousGovernor\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newGovernor\",\"type\":\"address\"}],\"name\":\"PendingGovernorshipTransfer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_priceProvider\",\"type\":\"address\"}],\"name\":\"PriceProviderUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"RebasePaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_threshold\",\"type\":\"uint256\"}],\"name\":\"RebaseThresholdUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"RebaseUnpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"Redeem\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_redeemFeeBps\",\"type\":\"uint256\"}],\"name\":\"RedeemFeeUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"StrategistUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"}],\"name\":\"StrategyApproved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"}],\"name\":\"StrategyRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_basis\",\"type\":\"uint256\"}],\"name\":\"SwapAllowedUndervalueChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_basis\",\"type\":\"uint256\"}],\"name\":\"SwapSlippageChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_fromAsset\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_toAsset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_fromAssetAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_toAssetAmount\",\"type\":\"uint256\"}],\"name\":\"Swapped\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"SwapperChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"TrusteeAddressChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_basis\",\"type\":\"uint256\"}],\"name\":\"TrusteeFeeBpsChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_vaultBuffer\",\"type\":\"uint256\"}],\"name\":\"VaultBufferUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_yield\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_fee\",\"type\":\"uint256\"}],\"name\":\"YieldDistribution\",\"type\":\"event\"},{\"stateMutability\":\"nonpayable\",\"type\":\"fallback\"},{\"inputs\":[],\"name\":\"allocate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"assetDefaultStrategies\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"autoAllocateThreshold\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"burnForStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"cacheWETHAssetIndex\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"calculateRedeemOutputs\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"capitalPaused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"}],\"name\":\"checkBalance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"claimGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllAssets\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllStrategies\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"}],\"name\":\"getAssetConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"isSupported\",\"type\":\"bool\"},{\"internalType\":\"enum VaultStorage.UnitConversion\",\"name\":\"unitConversion\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"decimals\",\"type\":\"uint8\"},{\"internalType\":\"uint16\",\"name\":\"allowedOracleSlippageBps\",\"type\":\"uint16\"}],\"internalType\":\"struct VaultStorage.Asset\",\"name\":\"config\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAssetCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getStrategyCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"governor\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_priceProvider\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_oToken\",\"type\":\"address\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isGovernor\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"}],\"name\":\"isSupportedAsset\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"maxSupplyDiff\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_minimumOusdAmount\",\"type\":\"uint256\"}],\"name\":\"mint\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"mintForStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"netOusdMintForStrategyThreshold\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"netOusdMintedForStrategy\",\"outputs\":[{\"internalType\":\"int256\",\"name\":\"\",\"type\":\"int256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"ousdMetaStrategy\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"priceProvider\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"asset\",\"type\":\"address\"}],\"name\":\"priceUnitMint\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"price\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"asset\",\"type\":\"address\"}],\"name\":\"priceUnitRedeem\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"price\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rebase\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rebasePaused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rebaseThreshold\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_minimumUnitAmount\",\"type\":\"uint256\"}],\"name\":\"redeem\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_minimumUnitAmount\",\"type\":\"uint256\"}],\"name\":\"redeemAll\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"redeemFeeBps\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newImpl\",\"type\":\"address\"}],\"name\":\"setAdminImpl\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"strategistAddr\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalValue\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_newGovernor\",\"type\":\"address\"}],\"name\":\"transferGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"trusteeAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"trusteeFeeBps\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"vaultBuffer\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"weth\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"wethAssetIndex\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"author\":\"Origin Protocol Inc\",\"kind\":\"dev\",\"methods\":{\"burnForStrategy(uint256)\":{\"details\":\"Notice: can't use `nonReentrant` modifier since the `redeem` function could require withdrawal on `ConvexOUSDMetaStrategy` and that one can call `burnForStrategy` while the execution of the `redeem` has not yet completed -> causing a `nonReentrant` collision. Also important to understand is that this is a limitation imposed by the test suite. Production / mainnet contracts should never be configured in a way where mint/redeem functions that are moving funds between the Vault and end user wallets can influence strategies utilizing this function.\",\"params\":{\"_amount\":\"Amount of OUSD to burn\"}},\"cacheWETHAssetIndex()\":{\"details\":\"Caches WETH's index in `allAssets` variable. Reduces gas usage by redeem by caching that.\"},\"checkBalance(address)\":{\"params\":{\"_asset\":\"Address of asset\"},\"returns\":{\"_0\":\"uint256 Balance of asset in decimals of asset\"}},\"isSupportedAsset(address)\":{\"params\":{\"_asset\":\"address of the asset\"},\"returns\":{\"_0\":\"true if supported\"}},\"mint(address,uint256,uint256)\":{\"params\":{\"_amount\":\"Amount of the asset being deposited\",\"_asset\":\"Address of the asset being deposited\",\"_minimumOusdAmount\":\"Minimum OTokens to mint\"}},\"mintForStrategy(uint256)\":{\"params\":{\"_amount\":\"Amount of the asset being deposited Notice: can't use `nonReentrant` modifier since the `mint` function can call `allocate`, and that can trigger `ConvexOUSDMetaStrategy` to call this function while the execution of the `mint` has not yet completed -> causing a `nonReentrant` collision. Also important to understand is that this is a limitation imposed by the test suite. Production / mainnet contracts should never be configured in a way where mint/redeem functions that are moving funds between the Vault and end user wallets can influence strategies utilizing this function.\"}},\"priceUnitMint(address)\":{\"params\":{\"asset\":\"address of the asset\"},\"returns\":{\"price\":\"uint256: unit (USD / ETH) price for 1 unit of the asset, in 18 decimal fixed\"}},\"priceUnitRedeem(address)\":{\"params\":{\"asset\":\"Address of the asset\"},\"returns\":{\"price\":\"uint256: unit (USD / ETH) price for 1 unit of the asset, in 18 decimal fixed\"}},\"redeem(uint256,uint256)\":{\"params\":{\"_amount\":\"Amount of OTokens to burn\",\"_minimumUnitAmount\":\"Minimum stablecoin units to receive in return\"}},\"redeemAll(uint256)\":{\"params\":{\"_minimumUnitAmount\":\"Minimum stablecoin units to receive in return\"}},\"setAdminImpl(address)\":{\"params\":{\"newImpl\":\"address of the implementation\"}},\"totalValue()\":{\"returns\":{\"value\":\"Total value in USD/ETH (1e18)\"}},\"transferGovernance(address)\":{\"params\":{\"_newGovernor\":\"Address of the new Governor\"}}},\"title\":\"OETH VaultCore Contract\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"allocate()\":{\"notice\":\"Allocate unallocated funds on Vault to strategies.*\"},\"assetDefaultStrategies(address)\":{\"notice\":\"Mapping of asset address to the Strategy that they should automatically\"},\"autoAllocateThreshold()\":{\"notice\":\"OToken mints over this amount automatically allocate funds. 18 decimals.\"},\"burnForStrategy(uint256)\":{\"notice\":\"Burn OTokens for Metapool Strategy\"},\"calculateRedeemOutputs(uint256)\":{\"notice\":\"Calculate the outputs for a redeem function, i.e. the mix of coins that will be returned\"},\"capitalPaused()\":{\"notice\":\"pause operations that change the OToken supply. eg mint, redeem, allocate, mint/burn for strategy\"},\"checkBalance(address)\":{\"notice\":\"Get the balance of an asset held in Vault and all strategies.\"},\"claimGovernance()\":{\"notice\":\"Claim Governance of the contract to a new account (`newGovernor`). Can only be called by the new Governor.\"},\"getAllAssets()\":{\"notice\":\"Return all vault asset addresses in order\"},\"getAllStrategies()\":{\"notice\":\"Return the array of all strategies\"},\"getAssetConfig(address)\":{\"notice\":\"Gets the vault configuration of a supported asset.\"},\"getAssetCount()\":{\"notice\":\"Return the number of assets supported by the Vault.\"},\"getStrategyCount()\":{\"notice\":\"Return the number of strategies active on the Vault.\"},\"governor()\":{\"notice\":\"Returns the address of the current Governor.\"},\"isGovernor()\":{\"notice\":\"Returns true if the caller is the current Governor.\"},\"isSupportedAsset(address)\":{\"notice\":\"Returns whether the vault supports the asset\"},\"maxSupplyDiff()\":{\"notice\":\"Max difference between total supply and total value of assets. 18 decimals.\"},\"mint(address,uint256,uint256)\":{\"notice\":\"Deposit a supported asset and mint OTokens.\"},\"mintForStrategy(uint256)\":{\"notice\":\"Mint OTokens for a Metapool Strategy\"},\"netOusdMintForStrategyThreshold()\":{\"notice\":\"How much net total OTokens are allowed to be minted by all strategies\"},\"netOusdMintedForStrategy()\":{\"notice\":\"How much OTokens are currently minted by the strategy\"},\"ousdMetaStrategy()\":{\"notice\":\"Metapool strategy that is allowed to mint/burn OTokens without changing collateral\"},\"priceProvider()\":{\"notice\":\"Address of the Oracle price provider contract\"},\"priceUnitMint(address)\":{\"notice\":\"Returns the total price in 18 digit units for a given asset. Never goes above 1, since that is how we price mints.\"},\"priceUnitRedeem(address)\":{\"notice\":\"Returns the total price in 18 digit unit for a given asset. Never goes below 1, since that is how we price redeems\"},\"rebase()\":{\"notice\":\"Calculate the total value of assets held by the Vault and all strategies and update the supply of OTokens.\"},\"rebasePaused()\":{\"notice\":\"pause rebasing if true\"},\"rebaseThreshold()\":{\"notice\":\"OToken mints over this amount automatically rebase. 18 decimals.\"},\"redeem(uint256,uint256)\":{\"notice\":\"Withdraw a supported asset and burn OTokens.\"},\"redeemAll(uint256)\":{\"notice\":\"Withdraw a supported asset and burn all OTokens.\"},\"redeemFeeBps()\":{\"notice\":\"Redemption fee in basis points. eg 50 = 0.5%\"},\"setAdminImpl(address)\":{\"notice\":\"set the implementation for the admin, this needs to be in a base class else we cannot set it\"},\"strategistAddr()\":{\"notice\":\"Address of the Strategist\"},\"totalValue()\":{\"notice\":\"Determine the total value of assets held by the vault and its strategies.\"},\"transferGovernance(address)\":{\"notice\":\"Transfers Governance of the contract to a new account (`newGovernor`). Can only be called by the current Governor. Must be claimed for this to complete\"},\"trusteeAddress()\":{\"notice\":\"Trustee contract that can collect a percentage of yield\"},\"trusteeFeeBps()\":{\"notice\":\"Amount of yield collected in basis points. eg 2000 = 20%\"},\"vaultBuffer()\":{\"notice\":\"Percentage of assets to keep in Vault to handle (most) withdrawals. 100% = 1e18.\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/vault/OETHVaultCore.sol\":\"OETHVaultCore\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `recipient`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address recipient, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `sender` to `recipient` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address sender,\\n address recipient,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0x61437cb513a887a1bbad006e7b1c8b414478427d33de47c5600af3c748f108da\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Address.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize, which returns 0 for contracts in\\n // construction, since the code is only stored at the end of the\\n // constructor execution.\\n\\n uint256 size;\\n assembly {\\n size := extcodesize(account)\\n }\\n return size > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x51b758a8815ecc9596c66c37d56b1d33883a444631a3f916b9fe65cb863ef7c4\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/math/SafeMath.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeMath.sol)\\n\\npragma solidity ^0.8.0;\\n\\n// CAUTION\\n// This version of SafeMath should only be used with Solidity 0.8 or later,\\n// because it relies on the compiler's built in overflow checks.\\n\\n/**\\n * @dev Wrappers over Solidity's arithmetic operations.\\n *\\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\\n * now has built in overflow checking.\\n */\\nlibrary SafeMath {\\n /**\\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n uint256 c = a + b;\\n if (c < a) return (false, 0);\\n return (true, c);\\n }\\n }\\n\\n /**\\n * @dev Returns the substraction of two unsigned integers, with an overflow flag.\\n *\\n * _Available since v3.4._\\n */\\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n if (b > a) return (false, 0);\\n return (true, a - b);\\n }\\n }\\n\\n /**\\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\\n // benefit is lost if 'b' is also tested.\\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\\n if (a == 0) return (true, 0);\\n uint256 c = a * b;\\n if (c / a != b) return (false, 0);\\n return (true, c);\\n }\\n }\\n\\n /**\\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n if (b == 0) return (false, 0);\\n return (true, a / b);\\n }\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n if (b == 0) return (false, 0);\\n return (true, a % b);\\n }\\n }\\n\\n /**\\n * @dev Returns the addition of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `+` operator.\\n *\\n * Requirements:\\n *\\n * - Addition cannot overflow.\\n */\\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a + b;\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting on\\n * overflow (when the result is negative).\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n *\\n * - Subtraction cannot overflow.\\n */\\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a - b;\\n }\\n\\n /**\\n * @dev Returns the multiplication of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `*` operator.\\n *\\n * Requirements:\\n *\\n * - Multiplication cannot overflow.\\n */\\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a * b;\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers, reverting on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator.\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a / b;\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * reverting when dividing by zero.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a % b;\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\\n * overflow (when the result is negative).\\n *\\n * CAUTION: This function is deprecated because it requires allocating memory for the error\\n * message unnecessarily. For custom revert reasons use {trySub}.\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n *\\n * - Subtraction cannot overflow.\\n */\\n function sub(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n unchecked {\\n require(b <= a, errorMessage);\\n return a - b;\\n }\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator. Note: this function uses a\\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\\n * uses an invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function div(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n unchecked {\\n require(b > 0, errorMessage);\\n return a / b;\\n }\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * reverting with custom message when dividing by zero.\\n *\\n * CAUTION: This function is deprecated because it requires allocating memory for the error\\n * message unnecessarily. For custom revert reasons use {tryMod}.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function mod(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n unchecked {\\n require(b > 0, errorMessage);\\n return a % b;\\n }\\n }\\n}\\n\",\"keccak256\":\"0xa2f576be637946f767aa56601c26d717f48a0aff44f82e46f13807eea1009a21\",\"license\":\"MIT\"},\"contracts/governance/Governable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Base for contracts that are managed by the Origin Protocol's Governor.\\n * @dev Copy of the openzeppelin Ownable.sol contract with nomenclature change\\n * from owner to governor and renounce methods removed. Does not use\\n * Context.sol like Ownable.sol does for simplification.\\n * @author Origin Protocol Inc\\n */\\ncontract Governable {\\n // Storage position of the owner and pendingOwner of the contract\\n // keccak256(\\\"OUSD.governor\\\");\\n bytes32 private constant governorPosition =\\n 0x7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a;\\n\\n // keccak256(\\\"OUSD.pending.governor\\\");\\n bytes32 private constant pendingGovernorPosition =\\n 0x44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db;\\n\\n // keccak256(\\\"OUSD.reentry.status\\\");\\n bytes32 private constant reentryStatusPosition =\\n 0x53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac4535;\\n\\n // See OpenZeppelin ReentrancyGuard implementation\\n uint256 constant _NOT_ENTERED = 1;\\n uint256 constant _ENTERED = 2;\\n\\n event PendingGovernorshipTransfer(\\n address indexed previousGovernor,\\n address indexed newGovernor\\n );\\n\\n event GovernorshipTransferred(\\n address indexed previousGovernor,\\n address indexed newGovernor\\n );\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial Governor.\\n */\\n constructor() {\\n _setGovernor(msg.sender);\\n emit GovernorshipTransferred(address(0), _governor());\\n }\\n\\n /**\\n * @notice Returns the address of the current Governor.\\n */\\n function governor() public view returns (address) {\\n return _governor();\\n }\\n\\n /**\\n * @dev Returns the address of the current Governor.\\n */\\n function _governor() internal view returns (address governorOut) {\\n bytes32 position = governorPosition;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n governorOut := sload(position)\\n }\\n }\\n\\n /**\\n * @dev Returns the address of the pending Governor.\\n */\\n function _pendingGovernor()\\n internal\\n view\\n returns (address pendingGovernor)\\n {\\n bytes32 position = pendingGovernorPosition;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n pendingGovernor := sload(position)\\n }\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the Governor.\\n */\\n modifier onlyGovernor() {\\n require(isGovernor(), \\\"Caller is not the Governor\\\");\\n _;\\n }\\n\\n /**\\n * @notice Returns true if the caller is the current Governor.\\n */\\n function isGovernor() public view returns (bool) {\\n return msg.sender == _governor();\\n }\\n\\n function _setGovernor(address newGovernor) internal {\\n bytes32 position = governorPosition;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n sstore(position, newGovernor)\\n }\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a `nonReentrant` function from another `nonReentrant`\\n * function is not supported. It is possible to prevent this from happening\\n * by making the `nonReentrant` function external, and make it call a\\n * `private` function that does the actual work.\\n */\\n modifier nonReentrant() {\\n bytes32 position = reentryStatusPosition;\\n uint256 _reentry_status;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n _reentry_status := sload(position)\\n }\\n\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_reentry_status != _ENTERED, \\\"Reentrant call\\\");\\n\\n // Any calls to nonReentrant after this point will fail\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n sstore(position, _ENTERED)\\n }\\n\\n _;\\n\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n sstore(position, _NOT_ENTERED)\\n }\\n }\\n\\n function _setPendingGovernor(address newGovernor) internal {\\n bytes32 position = pendingGovernorPosition;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n sstore(position, newGovernor)\\n }\\n }\\n\\n /**\\n * @notice Transfers Governance of the contract to a new account (`newGovernor`).\\n * Can only be called by the current Governor. Must be claimed for this to complete\\n * @param _newGovernor Address of the new Governor\\n */\\n function transferGovernance(address _newGovernor) external onlyGovernor {\\n _setPendingGovernor(_newGovernor);\\n emit PendingGovernorshipTransfer(_governor(), _newGovernor);\\n }\\n\\n /**\\n * @notice Claim Governance of the contract to a new account (`newGovernor`).\\n * Can only be called by the new Governor.\\n */\\n function claimGovernance() external {\\n require(\\n msg.sender == _pendingGovernor(),\\n \\\"Only the pending Governor can complete the claim\\\"\\n );\\n _changeGovernor(msg.sender);\\n }\\n\\n /**\\n * @dev Change Governance of the contract to a new account (`newGovernor`).\\n * @param _newGovernor Address of the new Governor\\n */\\n function _changeGovernor(address _newGovernor) internal {\\n require(_newGovernor != address(0), \\\"New Governor is address(0)\\\");\\n emit GovernorshipTransferred(_governor(), _newGovernor);\\n _setGovernor(_newGovernor);\\n }\\n}\\n\",\"keccak256\":\"0xb7133d6ce7a9e673ff79fcedb3fd41ae6e58e251f94915bb65731abe524270b4\",\"license\":\"MIT\"},\"contracts/interfaces/IBasicToken.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IBasicToken {\\n function symbol() external view returns (string memory);\\n\\n function decimals() external view returns (uint8);\\n}\\n\",\"keccak256\":\"0xa562062698aa12572123b36dfd2072f1a39e44fed2031cc19c2c9fd522f96ec2\",\"license\":\"MIT\"},\"contracts/interfaces/IGetExchangeRateToken.sol\":{\"content\":\"pragma solidity ^0.8.0;\\n\\ninterface IGetExchangeRateToken {\\n function getExchangeRate() external view returns (uint256 _exchangeRate);\\n}\\n\",\"keccak256\":\"0x641d5892d570f3f9e256d39a9571e58b02c39368726b01c4cdf7d91f45e349d8\"},\"contracts/interfaces/IOracle.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IOracle {\\n /**\\n * @dev returns the asset price in USD, in 8 decimal digits.\\n *\\n * The version of priceProvider deployed for OETH has 18 decimal digits\\n */\\n function price(address asset) external view returns (uint256);\\n}\\n\",\"keccak256\":\"0x9eabf152389f145c9c23ed71972af73fb1708cbc4b26e524a9ba29a557b7cfe5\",\"license\":\"MIT\"},\"contracts/interfaces/IStrategy.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Platform interface to integrate with lending platform like Compound, AAVE etc.\\n */\\ninterface IStrategy {\\n /**\\n * @dev Deposit the given asset to platform\\n * @param _asset asset address\\n * @param _amount Amount to deposit\\n */\\n function deposit(address _asset, uint256 _amount) external;\\n\\n /**\\n * @dev Deposit the entire balance of all supported assets in the Strategy\\n * to the platform\\n */\\n function depositAll() external;\\n\\n /**\\n * @dev Withdraw given asset from Lending platform\\n */\\n function withdraw(\\n address _recipient,\\n address _asset,\\n uint256 _amount\\n ) external;\\n\\n /**\\n * @dev Liquidate all assets in strategy and return them to Vault.\\n */\\n function withdrawAll() external;\\n\\n /**\\n * @dev Returns the current balance of the given asset.\\n */\\n function checkBalance(address _asset)\\n external\\n view\\n returns (uint256 balance);\\n\\n /**\\n * @dev Returns bool indicating whether strategy supports asset.\\n */\\n function supportsAsset(address _asset) external view returns (bool);\\n\\n /**\\n * @dev Collect reward tokens from the Strategy.\\n */\\n function collectRewardTokens() external;\\n\\n /**\\n * @dev The address array of the reward tokens for the Strategy.\\n */\\n function getRewardTokenAddresses() external view returns (address[] memory);\\n}\\n\",\"keccak256\":\"0xb291e409a9b95527f9ed19cd6bff8eeb9921a21c1f5194a48c0bb9ce6613959a\",\"license\":\"MIT\"},\"contracts/token/OUSD.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title OUSD Token Contract\\n * @dev ERC20 compatible contract for OUSD\\n * @dev Implements an elastic supply\\n * @author Origin Protocol Inc\\n */\\nimport { SafeMath } from \\\"@openzeppelin/contracts/utils/math/SafeMath.sol\\\";\\nimport { Address } from \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\n\\nimport { Initializable } from \\\"../utils/Initializable.sol\\\";\\nimport { InitializableERC20Detailed } from \\\"../utils/InitializableERC20Detailed.sol\\\";\\nimport { StableMath } from \\\"../utils/StableMath.sol\\\";\\nimport { Governable } from \\\"../governance/Governable.sol\\\";\\n\\n/**\\n * NOTE that this is an ERC20 token but the invariant that the sum of\\n * balanceOf(x) for all x is not >= totalSupply(). This is a consequence of the\\n * rebasing design. Any integrations with OUSD should be aware.\\n */\\n\\ncontract OUSD is Initializable, InitializableERC20Detailed, Governable {\\n using SafeMath for uint256;\\n using StableMath for uint256;\\n\\n event TotalSupplyUpdatedHighres(\\n uint256 totalSupply,\\n uint256 rebasingCredits,\\n uint256 rebasingCreditsPerToken\\n );\\n event AccountRebasingEnabled(address account);\\n event AccountRebasingDisabled(address account);\\n\\n enum RebaseOptions {\\n NotSet,\\n OptOut,\\n OptIn\\n }\\n\\n uint256 private constant MAX_SUPPLY = ~uint128(0); // (2^128) - 1\\n uint256 public _totalSupply;\\n mapping(address => mapping(address => uint256)) private _allowances;\\n address public vaultAddress = address(0);\\n mapping(address => uint256) private _creditBalances;\\n uint256 private _rebasingCredits;\\n uint256 private _rebasingCreditsPerToken;\\n // Frozen address/credits are non rebasing (value is held in contracts which\\n // do not receive yield unless they explicitly opt in)\\n uint256 public nonRebasingSupply;\\n mapping(address => uint256) public nonRebasingCreditsPerToken;\\n mapping(address => RebaseOptions) public rebaseState;\\n mapping(address => uint256) public isUpgraded;\\n\\n uint256 private constant RESOLUTION_INCREASE = 1e9;\\n\\n function initialize(\\n string calldata _nameArg,\\n string calldata _symbolArg,\\n address _vaultAddress,\\n uint256 _initialCreditsPerToken\\n ) external onlyGovernor initializer {\\n InitializableERC20Detailed._initialize(_nameArg, _symbolArg, 18);\\n _rebasingCreditsPerToken = _initialCreditsPerToken;\\n vaultAddress = _vaultAddress;\\n }\\n\\n /**\\n * @dev Verifies that the caller is the Vault contract\\n */\\n modifier onlyVault() {\\n require(vaultAddress == msg.sender, \\\"Caller is not the Vault\\\");\\n _;\\n }\\n\\n /**\\n * @return The total supply of OUSD.\\n */\\n function totalSupply() public view override returns (uint256) {\\n return _totalSupply;\\n }\\n\\n /**\\n * @return Low resolution rebasingCreditsPerToken\\n */\\n function rebasingCreditsPerToken() public view returns (uint256) {\\n return _rebasingCreditsPerToken / RESOLUTION_INCREASE;\\n }\\n\\n /**\\n * @return Low resolution total number of rebasing credits\\n */\\n function rebasingCredits() public view returns (uint256) {\\n return _rebasingCredits / RESOLUTION_INCREASE;\\n }\\n\\n /**\\n * @return High resolution rebasingCreditsPerToken\\n */\\n function rebasingCreditsPerTokenHighres() public view returns (uint256) {\\n return _rebasingCreditsPerToken;\\n }\\n\\n /**\\n * @return High resolution total number of rebasing credits\\n */\\n function rebasingCreditsHighres() public view returns (uint256) {\\n return _rebasingCredits;\\n }\\n\\n /**\\n * @dev Gets the balance of the specified address.\\n * @param _account Address to query the balance of.\\n * @return A uint256 representing the amount of base units owned by the\\n * specified address.\\n */\\n function balanceOf(address _account)\\n public\\n view\\n override\\n returns (uint256)\\n {\\n if (_creditBalances[_account] == 0) return 0;\\n return\\n _creditBalances[_account].divPrecisely(_creditsPerToken(_account));\\n }\\n\\n /**\\n * @dev Gets the credits balance of the specified address.\\n * @dev Backwards compatible with old low res credits per token.\\n * @param _account The address to query the balance of.\\n * @return (uint256, uint256) Credit balance and credits per token of the\\n * address\\n */\\n function creditsBalanceOf(address _account)\\n public\\n view\\n returns (uint256, uint256)\\n {\\n uint256 cpt = _creditsPerToken(_account);\\n if (cpt == 1e27) {\\n // For a period before the resolution upgrade, we created all new\\n // contract accounts at high resolution. Since they are not changing\\n // as a result of this upgrade, we will return their true values\\n return (_creditBalances[_account], cpt);\\n } else {\\n return (\\n _creditBalances[_account] / RESOLUTION_INCREASE,\\n cpt / RESOLUTION_INCREASE\\n );\\n }\\n }\\n\\n /**\\n * @dev Gets the credits balance of the specified address.\\n * @param _account The address to query the balance of.\\n * @return (uint256, uint256, bool) Credit balance, credits per token of the\\n * address, and isUpgraded\\n */\\n function creditsBalanceOfHighres(address _account)\\n public\\n view\\n returns (\\n uint256,\\n uint256,\\n bool\\n )\\n {\\n return (\\n _creditBalances[_account],\\n _creditsPerToken(_account),\\n isUpgraded[_account] == 1\\n );\\n }\\n\\n /**\\n * @dev Transfer tokens to a specified address.\\n * @param _to the address to transfer to.\\n * @param _value the amount to be transferred.\\n * @return true on success.\\n */\\n function transfer(address _to, uint256 _value)\\n public\\n override\\n returns (bool)\\n {\\n require(_to != address(0), \\\"Transfer to zero address\\\");\\n require(\\n _value <= balanceOf(msg.sender),\\n \\\"Transfer greater than balance\\\"\\n );\\n\\n _executeTransfer(msg.sender, _to, _value);\\n\\n emit Transfer(msg.sender, _to, _value);\\n\\n return true;\\n }\\n\\n /**\\n * @dev Transfer tokens from one address to another.\\n * @param _from The address you want to send tokens from.\\n * @param _to The address you want to transfer to.\\n * @param _value The amount of tokens to be transferred.\\n */\\n function transferFrom(\\n address _from,\\n address _to,\\n uint256 _value\\n ) public override returns (bool) {\\n require(_to != address(0), \\\"Transfer to zero address\\\");\\n require(_value <= balanceOf(_from), \\\"Transfer greater than balance\\\");\\n\\n _allowances[_from][msg.sender] = _allowances[_from][msg.sender].sub(\\n _value\\n );\\n\\n _executeTransfer(_from, _to, _value);\\n\\n emit Transfer(_from, _to, _value);\\n\\n return true;\\n }\\n\\n /**\\n * @dev Update the count of non rebasing credits in response to a transfer\\n * @param _from The address you want to send tokens from.\\n * @param _to The address you want to transfer to.\\n * @param _value Amount of OUSD to transfer\\n */\\n function _executeTransfer(\\n address _from,\\n address _to,\\n uint256 _value\\n ) internal {\\n bool isNonRebasingTo = _isNonRebasingAccount(_to);\\n bool isNonRebasingFrom = _isNonRebasingAccount(_from);\\n\\n // Credits deducted and credited might be different due to the\\n // differing creditsPerToken used by each account\\n uint256 creditsCredited = _value.mulTruncate(_creditsPerToken(_to));\\n uint256 creditsDeducted = _value.mulTruncate(_creditsPerToken(_from));\\n\\n _creditBalances[_from] = _creditBalances[_from].sub(\\n creditsDeducted,\\n \\\"Transfer amount exceeds balance\\\"\\n );\\n _creditBalances[_to] = _creditBalances[_to].add(creditsCredited);\\n\\n if (isNonRebasingTo && !isNonRebasingFrom) {\\n // Transfer to non-rebasing account from rebasing account, credits\\n // are removed from the non rebasing tally\\n nonRebasingSupply = nonRebasingSupply.add(_value);\\n // Update rebasingCredits by subtracting the deducted amount\\n _rebasingCredits = _rebasingCredits.sub(creditsDeducted);\\n } else if (!isNonRebasingTo && isNonRebasingFrom) {\\n // Transfer to rebasing account from non-rebasing account\\n // Decreasing non-rebasing credits by the amount that was sent\\n nonRebasingSupply = nonRebasingSupply.sub(_value);\\n // Update rebasingCredits by adding the credited amount\\n _rebasingCredits = _rebasingCredits.add(creditsCredited);\\n }\\n }\\n\\n /**\\n * @dev Function to check the amount of tokens that _owner has allowed to\\n * `_spender`.\\n * @param _owner The address which owns the funds.\\n * @param _spender The address which will spend the funds.\\n * @return The number of tokens still available for the _spender.\\n */\\n function allowance(address _owner, address _spender)\\n public\\n view\\n override\\n returns (uint256)\\n {\\n return _allowances[_owner][_spender];\\n }\\n\\n /**\\n * @dev Approve the passed address to spend the specified amount of tokens\\n * on behalf of msg.sender. This method is included for ERC20\\n * compatibility. `increaseAllowance` and `decreaseAllowance` should be\\n * used instead.\\n *\\n * Changing an allowance with this method brings the risk that someone\\n * may transfer both the old and the new allowance - if they are both\\n * greater than zero - if a transfer transaction is mined before the\\n * later approve() call is mined.\\n * @param _spender The address which will spend the funds.\\n * @param _value The amount of tokens to be spent.\\n */\\n function approve(address _spender, uint256 _value)\\n public\\n override\\n returns (bool)\\n {\\n _allowances[msg.sender][_spender] = _value;\\n emit Approval(msg.sender, _spender, _value);\\n return true;\\n }\\n\\n /**\\n * @dev Increase the amount of tokens that an owner has allowed to\\n * `_spender`.\\n * This method should be used instead of approve() to avoid the double\\n * approval vulnerability described above.\\n * @param _spender The address which will spend the funds.\\n * @param _addedValue The amount of tokens to increase the allowance by.\\n */\\n function increaseAllowance(address _spender, uint256 _addedValue)\\n public\\n returns (bool)\\n {\\n _allowances[msg.sender][_spender] = _allowances[msg.sender][_spender]\\n .add(_addedValue);\\n emit Approval(msg.sender, _spender, _allowances[msg.sender][_spender]);\\n return true;\\n }\\n\\n /**\\n * @dev Decrease the amount of tokens that an owner has allowed to\\n `_spender`.\\n * @param _spender The address which will spend the funds.\\n * @param _subtractedValue The amount of tokens to decrease the allowance\\n * by.\\n */\\n function decreaseAllowance(address _spender, uint256 _subtractedValue)\\n public\\n returns (bool)\\n {\\n uint256 oldValue = _allowances[msg.sender][_spender];\\n if (_subtractedValue >= oldValue) {\\n _allowances[msg.sender][_spender] = 0;\\n } else {\\n _allowances[msg.sender][_spender] = oldValue.sub(_subtractedValue);\\n }\\n emit Approval(msg.sender, _spender, _allowances[msg.sender][_spender]);\\n return true;\\n }\\n\\n /**\\n * @dev Mints new tokens, increasing totalSupply.\\n */\\n function mint(address _account, uint256 _amount) external onlyVault {\\n _mint(_account, _amount);\\n }\\n\\n /**\\n * @dev Creates `_amount` tokens and assigns them to `_account`, increasing\\n * the total supply.\\n *\\n * Emits a {Transfer} event with `from` set to the zero address.\\n *\\n * Requirements\\n *\\n * - `to` cannot be the zero address.\\n */\\n function _mint(address _account, uint256 _amount) internal nonReentrant {\\n require(_account != address(0), \\\"Mint to the zero address\\\");\\n\\n bool isNonRebasingAccount = _isNonRebasingAccount(_account);\\n\\n uint256 creditAmount = _amount.mulTruncate(_creditsPerToken(_account));\\n _creditBalances[_account] = _creditBalances[_account].add(creditAmount);\\n\\n // If the account is non rebasing and doesn't have a set creditsPerToken\\n // then set it i.e. this is a mint from a fresh contract\\n if (isNonRebasingAccount) {\\n nonRebasingSupply = nonRebasingSupply.add(_amount);\\n } else {\\n _rebasingCredits = _rebasingCredits.add(creditAmount);\\n }\\n\\n _totalSupply = _totalSupply.add(_amount);\\n\\n require(_totalSupply < MAX_SUPPLY, \\\"Max supply\\\");\\n\\n emit Transfer(address(0), _account, _amount);\\n }\\n\\n /**\\n * @dev Burns tokens, decreasing totalSupply.\\n */\\n function burn(address account, uint256 amount) external onlyVault {\\n _burn(account, amount);\\n }\\n\\n /**\\n * @dev Destroys `_amount` tokens from `_account`, reducing the\\n * total supply.\\n *\\n * Emits a {Transfer} event with `to` set to the zero address.\\n *\\n * Requirements\\n *\\n * - `_account` cannot be the zero address.\\n * - `_account` must have at least `_amount` tokens.\\n */\\n function _burn(address _account, uint256 _amount) internal nonReentrant {\\n require(_account != address(0), \\\"Burn from the zero address\\\");\\n if (_amount == 0) {\\n return;\\n }\\n\\n bool isNonRebasingAccount = _isNonRebasingAccount(_account);\\n uint256 creditAmount = _amount.mulTruncate(_creditsPerToken(_account));\\n uint256 currentCredits = _creditBalances[_account];\\n\\n // Remove the credits, burning rounding errors\\n if (\\n currentCredits == creditAmount || currentCredits - 1 == creditAmount\\n ) {\\n // Handle dust from rounding\\n _creditBalances[_account] = 0;\\n } else if (currentCredits > creditAmount) {\\n _creditBalances[_account] = _creditBalances[_account].sub(\\n creditAmount\\n );\\n } else {\\n revert(\\\"Remove exceeds balance\\\");\\n }\\n\\n // Remove from the credit tallies and non-rebasing supply\\n if (isNonRebasingAccount) {\\n nonRebasingSupply = nonRebasingSupply.sub(_amount);\\n } else {\\n _rebasingCredits = _rebasingCredits.sub(creditAmount);\\n }\\n\\n _totalSupply = _totalSupply.sub(_amount);\\n\\n emit Transfer(_account, address(0), _amount);\\n }\\n\\n /**\\n * @dev Get the credits per token for an account. Returns a fixed amount\\n * if the account is non-rebasing.\\n * @param _account Address of the account.\\n */\\n function _creditsPerToken(address _account)\\n internal\\n view\\n returns (uint256)\\n {\\n if (nonRebasingCreditsPerToken[_account] != 0) {\\n return nonRebasingCreditsPerToken[_account];\\n } else {\\n return _rebasingCreditsPerToken;\\n }\\n }\\n\\n /**\\n * @dev Is an account using rebasing accounting or non-rebasing accounting?\\n * Also, ensure contracts are non-rebasing if they have not opted in.\\n * @param _account Address of the account.\\n */\\n function _isNonRebasingAccount(address _account) internal returns (bool) {\\n bool isContract = Address.isContract(_account);\\n if (isContract && rebaseState[_account] == RebaseOptions.NotSet) {\\n _ensureRebasingMigration(_account);\\n }\\n return nonRebasingCreditsPerToken[_account] > 0;\\n }\\n\\n /**\\n * @dev Ensures internal account for rebasing and non-rebasing credits and\\n * supply is updated following deployment of frozen yield change.\\n */\\n function _ensureRebasingMigration(address _account) internal {\\n if (nonRebasingCreditsPerToken[_account] == 0) {\\n emit AccountRebasingDisabled(_account);\\n if (_creditBalances[_account] == 0) {\\n // Since there is no existing balance, we can directly set to\\n // high resolution, and do not have to do any other bookkeeping\\n nonRebasingCreditsPerToken[_account] = 1e27;\\n } else {\\n // Migrate an existing account:\\n\\n // Set fixed credits per token for this account\\n nonRebasingCreditsPerToken[_account] = _rebasingCreditsPerToken;\\n // Update non rebasing supply\\n nonRebasingSupply = nonRebasingSupply.add(balanceOf(_account));\\n // Update credit tallies\\n _rebasingCredits = _rebasingCredits.sub(\\n _creditBalances[_account]\\n );\\n }\\n }\\n }\\n\\n /**\\n * @notice Enable rebasing for an account.\\n * @dev Add a contract address to the non-rebasing exception list. The\\n * address's balance will be part of rebases and the account will be exposed\\n * to upside and downside.\\n * @param _account Address of the account.\\n */\\n function governanceRebaseOptIn(address _account)\\n public\\n nonReentrant\\n onlyGovernor\\n {\\n _rebaseOptIn(_account);\\n }\\n\\n /**\\n * @dev Add a contract address to the non-rebasing exception list. The\\n * address's balance will be part of rebases and the account will be exposed\\n * to upside and downside.\\n */\\n function rebaseOptIn() public nonReentrant {\\n _rebaseOptIn(msg.sender);\\n }\\n\\n function _rebaseOptIn(address _account) internal {\\n require(_isNonRebasingAccount(_account), \\\"Account has not opted out\\\");\\n\\n // Convert balance into the same amount at the current exchange rate\\n uint256 newCreditBalance = _creditBalances[_account]\\n .mul(_rebasingCreditsPerToken)\\n .div(_creditsPerToken(_account));\\n\\n // Decreasing non rebasing supply\\n nonRebasingSupply = nonRebasingSupply.sub(balanceOf(_account));\\n\\n _creditBalances[_account] = newCreditBalance;\\n\\n // Increase rebasing credits, totalSupply remains unchanged so no\\n // adjustment necessary\\n _rebasingCredits = _rebasingCredits.add(_creditBalances[_account]);\\n\\n rebaseState[_account] = RebaseOptions.OptIn;\\n\\n // Delete any fixed credits per token\\n delete nonRebasingCreditsPerToken[_account];\\n emit AccountRebasingEnabled(_account);\\n }\\n\\n /**\\n * @dev Explicitly mark that an address is non-rebasing.\\n */\\n function rebaseOptOut() public nonReentrant {\\n require(!_isNonRebasingAccount(msg.sender), \\\"Account has not opted in\\\");\\n\\n // Increase non rebasing supply\\n nonRebasingSupply = nonRebasingSupply.add(balanceOf(msg.sender));\\n // Set fixed credits per token\\n nonRebasingCreditsPerToken[msg.sender] = _rebasingCreditsPerToken;\\n\\n // Decrease rebasing credits, total supply remains unchanged so no\\n // adjustment necessary\\n _rebasingCredits = _rebasingCredits.sub(_creditBalances[msg.sender]);\\n\\n // Mark explicitly opted out of rebasing\\n rebaseState[msg.sender] = RebaseOptions.OptOut;\\n emit AccountRebasingDisabled(msg.sender);\\n }\\n\\n /**\\n * @dev Modify the supply without minting new tokens. This uses a change in\\n * the exchange rate between \\\"credits\\\" and OUSD tokens to change balances.\\n * @param _newTotalSupply New total supply of OUSD.\\n */\\n function changeSupply(uint256 _newTotalSupply)\\n external\\n onlyVault\\n nonReentrant\\n {\\n require(_totalSupply > 0, \\\"Cannot increase 0 supply\\\");\\n\\n if (_totalSupply == _newTotalSupply) {\\n emit TotalSupplyUpdatedHighres(\\n _totalSupply,\\n _rebasingCredits,\\n _rebasingCreditsPerToken\\n );\\n return;\\n }\\n\\n _totalSupply = _newTotalSupply > MAX_SUPPLY\\n ? MAX_SUPPLY\\n : _newTotalSupply;\\n\\n _rebasingCreditsPerToken = _rebasingCredits.divPrecisely(\\n _totalSupply.sub(nonRebasingSupply)\\n );\\n\\n require(_rebasingCreditsPerToken > 0, \\\"Invalid change in supply\\\");\\n\\n _totalSupply = _rebasingCredits\\n .divPrecisely(_rebasingCreditsPerToken)\\n .add(nonRebasingSupply);\\n\\n emit TotalSupplyUpdatedHighres(\\n _totalSupply,\\n _rebasingCredits,\\n _rebasingCreditsPerToken\\n );\\n }\\n}\\n\",\"keccak256\":\"0x2dc66b1ba02716d64eb47dd9117fda62650d8b57669e6c351437e0ad29ad5f19\",\"license\":\"MIT\"},\"contracts/utils/Helpers.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport { IBasicToken } from \\\"../interfaces/IBasicToken.sol\\\";\\n\\nlibrary Helpers {\\n /**\\n * @notice Fetch the `symbol()` from an ERC20 token\\n * @dev Grabs the `symbol()` from a contract\\n * @param _token Address of the ERC20 token\\n * @return string Symbol of the ERC20 token\\n */\\n function getSymbol(address _token) internal view returns (string memory) {\\n string memory symbol = IBasicToken(_token).symbol();\\n return symbol;\\n }\\n\\n /**\\n * @notice Fetch the `decimals()` from an ERC20 token\\n * @dev Grabs the `decimals()` from a contract and fails if\\n * the decimal value does not live within a certain range\\n * @param _token Address of the ERC20 token\\n * @return uint256 Decimals of the ERC20 token\\n */\\n function getDecimals(address _token) internal view returns (uint256) {\\n uint256 decimals = IBasicToken(_token).decimals();\\n require(\\n decimals >= 4 && decimals <= 18,\\n \\\"Token must have sufficient decimal places\\\"\\n );\\n\\n return decimals;\\n }\\n}\\n\",\"keccak256\":\"0x108b7a69e0140da0072ca18f90a03a3340574400f81aa6076cd2cccdf13699c2\",\"license\":\"MIT\"},\"contracts/utils/Initializable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Base contract any contracts that need to initialize state after deployment.\\n * @author Origin Protocol Inc\\n */\\nabstract contract Initializable {\\n /**\\n * @dev Indicates that the contract has been initialized.\\n */\\n bool private initialized;\\n\\n /**\\n * @dev Indicates that the contract is in the process of being initialized.\\n */\\n bool private initializing;\\n\\n /**\\n * @dev Modifier to protect an initializer function from being invoked twice.\\n */\\n modifier initializer() {\\n require(\\n initializing || !initialized,\\n \\\"Initializable: contract is already initialized\\\"\\n );\\n\\n bool isTopLevelCall = !initializing;\\n if (isTopLevelCall) {\\n initializing = true;\\n initialized = true;\\n }\\n\\n _;\\n\\n if (isTopLevelCall) {\\n initializing = false;\\n }\\n }\\n\\n uint256[50] private ______gap;\\n}\\n\",\"keccak256\":\"0xaadbcc138114afed4af4f353c2ced2916e6ee14be91434789187f192caf0d786\",\"license\":\"MIT\"},\"contracts/utils/InitializableERC20Detailed.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport { IERC20 } from \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @dev Optional functions from the ERC20 standard.\\n * Converted from openzeppelin/contracts/token/ERC20/ERC20Detailed.sol\\n * @author Origin Protocol Inc\\n */\\nabstract contract InitializableERC20Detailed is IERC20 {\\n // Storage gap to skip storage from prior to OUSD reset\\n uint256[100] private _____gap;\\n\\n string private _name;\\n string private _symbol;\\n uint8 private _decimals;\\n\\n /**\\n * @dev Sets the values for `name`, `symbol`, and `decimals`. All three of\\n * these values are immutable: they can only be set once during\\n * construction.\\n * @notice To avoid variable shadowing appended `Arg` after arguments name.\\n */\\n function _initialize(\\n string memory nameArg,\\n string memory symbolArg,\\n uint8 decimalsArg\\n ) internal {\\n _name = nameArg;\\n _symbol = symbolArg;\\n _decimals = decimalsArg;\\n }\\n\\n /**\\n * @notice Returns the name of the token.\\n */\\n function name() public view returns (string memory) {\\n return _name;\\n }\\n\\n /**\\n * @notice Returns the symbol of the token, usually a shorter version of the\\n * name.\\n */\\n function symbol() public view returns (string memory) {\\n return _symbol;\\n }\\n\\n /**\\n * @notice Returns the number of decimals used to get its user representation.\\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\\n * be displayed to a user as `5,05` (`505 / 10 ** 2`).\\n *\\n * Tokens usually opt for a value of 18, imitating the relationship between\\n * Ether and Wei.\\n *\\n * NOTE: This information is only used for _display_ purposes: it in\\n * no way affects any of the arithmetic of the contract, including\\n * {IERC20-balanceOf} and {IERC20-transfer}.\\n */\\n function decimals() public view returns (uint8) {\\n return _decimals;\\n }\\n}\\n\",\"keccak256\":\"0xe35ac2d813a30d845a3b52bba72588d7e936c2b3f3373d15568c14db46aeed60\",\"license\":\"MIT\"},\"contracts/utils/StableMath.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport { SafeMath } from \\\"@openzeppelin/contracts/utils/math/SafeMath.sol\\\";\\n\\n// Based on StableMath from Stability Labs Pty. Ltd.\\n// https://github.com/mstable/mStable-contracts/blob/master/contracts/shared/StableMath.sol\\n\\nlibrary StableMath {\\n using SafeMath for uint256;\\n\\n /**\\n * @dev Scaling unit for use in specific calculations,\\n * where 1 * 10**18, or 1e18 represents a unit '1'\\n */\\n uint256 private constant FULL_SCALE = 1e18;\\n\\n /***************************************\\n Helpers\\n ****************************************/\\n\\n /**\\n * @dev Adjust the scale of an integer\\n * @param to Decimals to scale to\\n * @param from Decimals to scale from\\n */\\n function scaleBy(\\n uint256 x,\\n uint256 to,\\n uint256 from\\n ) internal pure returns (uint256) {\\n if (to > from) {\\n x = x.mul(10**(to - from));\\n } else if (to < from) {\\n // slither-disable-next-line divide-before-multiply\\n x = x.div(10**(from - to));\\n }\\n return x;\\n }\\n\\n /***************************************\\n Precise Arithmetic\\n ****************************************/\\n\\n /**\\n * @dev Multiplies two precise units, and then truncates by the full scale\\n * @param x Left hand input to multiplication\\n * @param y Right hand input to multiplication\\n * @return Result after multiplying the two inputs and then dividing by the shared\\n * scale unit\\n */\\n function mulTruncate(uint256 x, uint256 y) internal pure returns (uint256) {\\n return mulTruncateScale(x, y, FULL_SCALE);\\n }\\n\\n /**\\n * @dev Multiplies two precise units, and then truncates by the given scale. For example,\\n * when calculating 90% of 10e18, (10e18 * 9e17) / 1e18 = (9e36) / 1e18 = 9e18\\n * @param x Left hand input to multiplication\\n * @param y Right hand input to multiplication\\n * @param scale Scale unit\\n * @return Result after multiplying the two inputs and then dividing by the shared\\n * scale unit\\n */\\n function mulTruncateScale(\\n uint256 x,\\n uint256 y,\\n uint256 scale\\n ) internal pure returns (uint256) {\\n // e.g. assume scale = fullScale\\n // z = 10e18 * 9e17 = 9e36\\n uint256 z = x.mul(y);\\n // return 9e36 / 1e18 = 9e18\\n return z.div(scale);\\n }\\n\\n /**\\n * @dev Multiplies two precise units, and then truncates by the full scale, rounding up the result\\n * @param x Left hand input to multiplication\\n * @param y Right hand input to multiplication\\n * @return Result after multiplying the two inputs and then dividing by the shared\\n * scale unit, rounded up to the closest base unit.\\n */\\n function mulTruncateCeil(uint256 x, uint256 y)\\n internal\\n pure\\n returns (uint256)\\n {\\n // e.g. 8e17 * 17268172638 = 138145381104e17\\n uint256 scaled = x.mul(y);\\n // e.g. 138145381104e17 + 9.99...e17 = 138145381113.99...e17\\n uint256 ceil = scaled.add(FULL_SCALE.sub(1));\\n // e.g. 13814538111.399...e18 / 1e18 = 13814538111\\n return ceil.div(FULL_SCALE);\\n }\\n\\n /**\\n * @dev Precisely divides two units, by first scaling the left hand operand. Useful\\n * for finding percentage weightings, i.e. 8e18/10e18 = 80% (or 8e17)\\n * @param x Left hand input to division\\n * @param y Right hand input to division\\n * @return Result after multiplying the left operand by the scale, and\\n * executing the division on the right hand input.\\n */\\n function divPrecisely(uint256 x, uint256 y)\\n internal\\n pure\\n returns (uint256)\\n {\\n // e.g. 8e18 * 1e18 = 8e36\\n uint256 z = x.mul(FULL_SCALE);\\n // e.g. 8e36 / 10e18 = 8e17\\n return z.div(y);\\n }\\n}\\n\",\"keccak256\":\"0x1eb49f6f79045d9e0a8e1dced8e01d9e559e5fac554dcbb53e43140b601b04e7\",\"license\":\"MIT\"},\"contracts/vault/OETHVaultCore.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport { StableMath } from \\\"../utils/StableMath.sol\\\";\\nimport { VaultCore } from \\\"./VaultCore.sol\\\";\\n\\nimport { SafeERC20 } from \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\nimport { IERC20 } from \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport { IStrategy } from \\\"../interfaces/IStrategy.sol\\\";\\n\\n/**\\n * @title OETH VaultCore Contract\\n * @author Origin Protocol Inc\\n */\\ncontract OETHVaultCore is VaultCore {\\n using SafeERC20 for IERC20;\\n using StableMath for uint256;\\n\\n address public immutable weth;\\n uint256 public wethAssetIndex;\\n\\n constructor(address _weth) {\\n weth = _weth;\\n }\\n\\n /**\\n * @dev Caches WETH's index in `allAssets` variable.\\n * Reduces gas usage by redeem by caching that.\\n */\\n function cacheWETHAssetIndex() external onlyGovernor {\\n uint256 assetCount = allAssets.length;\\n for (uint256 i = 0; i < assetCount; ++i) {\\n if (allAssets[i] == weth) {\\n wethAssetIndex = i;\\n break;\\n }\\n }\\n\\n require(allAssets[wethAssetIndex] == weth, \\\"Invalid WETH Asset Index\\\");\\n }\\n\\n // @inheritdoc VaultCore\\n function _mint(\\n address _asset,\\n uint256 _amount,\\n uint256 _minimumOusdAmount\\n ) internal virtual override {\\n require(_asset == weth, \\\"Unsupported asset for minting\\\");\\n require(_amount > 0, \\\"Amount must be greater than 0\\\");\\n require(\\n _amount >= _minimumOusdAmount,\\n \\\"Mint amount lower than minimum\\\"\\n );\\n\\n emit Mint(msg.sender, _amount);\\n\\n // Rebase must happen before any transfers occur.\\n if (!rebasePaused && _amount >= rebaseThreshold) {\\n _rebase();\\n }\\n\\n // Mint oTokens\\n oUSD.mint(msg.sender, _amount);\\n\\n // Transfer the deposited coins to the vault\\n IERC20(_asset).safeTransferFrom(msg.sender, address(this), _amount);\\n\\n // Auto-allocate if necessary\\n if (_amount >= autoAllocateThreshold) {\\n _allocate();\\n }\\n }\\n\\n // @inheritdoc VaultCore\\n function _calculateRedeemOutputs(uint256 _amount)\\n internal\\n view\\n virtual\\n override\\n returns (uint256[] memory outputs)\\n {\\n // Overrides `VaultCore._calculateRedeemOutputs` to redeem with only\\n // WETH instead of LST-mix. Doesn't change the function signature\\n // for backward compatibility\\n\\n // Calculate redeem fee\\n if (redeemFeeBps > 0) {\\n uint256 redeemFee = _amount.mulTruncateScale(redeemFeeBps, 1e4);\\n _amount = _amount - redeemFee;\\n }\\n\\n // Ensure that the WETH index is cached\\n uint256 _wethAssetIndex = wethAssetIndex;\\n require(\\n allAssets[_wethAssetIndex] == weth,\\n \\\"WETH Asset index not cached\\\"\\n );\\n\\n outputs = new uint256[](allAssets.length);\\n outputs[_wethAssetIndex] = _amount;\\n }\\n\\n // @inheritdoc VaultCore\\n function _redeem(uint256 _amount, uint256 _minimumUnitAmount)\\n internal\\n virtual\\n override\\n {\\n // Override `VaultCore._redeem` to simplify it. Gets rid of oracle\\n // usage and looping through all assets for LST-mix redeem. Instead\\n // does a simple WETH-only redeem.\\n emit Redeem(msg.sender, _amount);\\n\\n if (_amount == 0) {\\n return;\\n }\\n\\n // Amount excluding fees\\n uint256 amountMinusFee = _calculateRedeemOutputs(_amount)[\\n wethAssetIndex\\n ];\\n\\n require(\\n amountMinusFee >= _minimumUnitAmount,\\n \\\"Redeem amount lower than minimum\\\"\\n );\\n\\n if (IERC20(weth).balanceOf(address(this)) >= amountMinusFee) {\\n // Use Vault funds first if sufficient\\n IERC20(weth).safeTransfer(msg.sender, amountMinusFee);\\n } else {\\n address strategyAddr = assetDefaultStrategies[weth];\\n if (strategyAddr != address(0)) {\\n // Nothing in Vault, but something in Strategy, send from there\\n IStrategy strategy = IStrategy(strategyAddr);\\n strategy.withdraw(msg.sender, weth, amountMinusFee);\\n } else {\\n // Cant find funds anywhere\\n revert(\\\"Liquidity error\\\");\\n }\\n }\\n\\n // Burn OETH from user (including fees)\\n oUSD.burn(msg.sender, _amount);\\n\\n _postRedeem(_amount);\\n }\\n}\\n\",\"keccak256\":\"0x8ae6aada28f768745991b7e6610e325e1331da8fd7e9de045d03f1bc12d65f1e\",\"license\":\"MIT\"},\"contracts/vault/VaultCore.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title OToken VaultCore contract\\n * @notice The Vault contract stores assets. On a deposit, OTokens will be minted\\n and sent to the depositor. On a withdrawal, OTokens will be burned and\\n assets will be sent to the withdrawer. The Vault accepts deposits of\\n interest from yield bearing strategies which will modify the supply\\n of OTokens.\\n * @author Origin Protocol Inc\\n */\\n\\nimport { SafeERC20 } from \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\n\\nimport { StableMath } from \\\"../utils/StableMath.sol\\\";\\nimport { IOracle } from \\\"../interfaces/IOracle.sol\\\";\\nimport { IGetExchangeRateToken } from \\\"../interfaces/IGetExchangeRateToken.sol\\\";\\n\\nimport \\\"./VaultInitializer.sol\\\";\\n\\ncontract VaultCore is VaultInitializer {\\n using SafeERC20 for IERC20;\\n using StableMath for uint256;\\n // max signed int\\n uint256 internal constant MAX_INT = 2**255 - 1;\\n // max un-signed int\\n uint256 internal constant MAX_UINT =\\n 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff;\\n\\n /**\\n * @dev Verifies that the rebasing is not paused.\\n */\\n modifier whenNotRebasePaused() {\\n require(!rebasePaused, \\\"Rebasing paused\\\");\\n _;\\n }\\n\\n /**\\n * @dev Verifies that the deposits are not paused.\\n */\\n modifier whenNotCapitalPaused() {\\n require(!capitalPaused, \\\"Capital paused\\\");\\n _;\\n }\\n\\n modifier onlyOusdMetaStrategy() {\\n require(\\n msg.sender == ousdMetaStrategy,\\n \\\"Caller is not the OUSD meta strategy\\\"\\n );\\n _;\\n }\\n\\n /**\\n * @notice Deposit a supported asset and mint OTokens.\\n * @param _asset Address of the asset being deposited\\n * @param _amount Amount of the asset being deposited\\n * @param _minimumOusdAmount Minimum OTokens to mint\\n */\\n function mint(\\n address _asset,\\n uint256 _amount,\\n uint256 _minimumOusdAmount\\n ) external whenNotCapitalPaused nonReentrant {\\n _mint(_asset, _amount, _minimumOusdAmount);\\n }\\n\\n function _mint(\\n address _asset,\\n uint256 _amount,\\n uint256 _minimumOusdAmount\\n ) internal virtual {\\n require(assets[_asset].isSupported, \\\"Asset is not supported\\\");\\n require(_amount > 0, \\\"Amount must be greater than 0\\\");\\n\\n uint256 units = _toUnits(_amount, _asset);\\n uint256 unitPrice = _toUnitPrice(_asset, true);\\n uint256 priceAdjustedDeposit = (units * unitPrice) / 1e18;\\n\\n if (_minimumOusdAmount > 0) {\\n require(\\n priceAdjustedDeposit >= _minimumOusdAmount,\\n \\\"Mint amount lower than minimum\\\"\\n );\\n }\\n\\n emit Mint(msg.sender, priceAdjustedDeposit);\\n\\n // Rebase must happen before any transfers occur.\\n if (priceAdjustedDeposit >= rebaseThreshold && !rebasePaused) {\\n _rebase();\\n }\\n\\n // Mint matching amount of OTokens\\n oUSD.mint(msg.sender, priceAdjustedDeposit);\\n\\n // Transfer the deposited coins to the vault\\n IERC20 asset = IERC20(_asset);\\n asset.safeTransferFrom(msg.sender, address(this), _amount);\\n\\n if (priceAdjustedDeposit >= autoAllocateThreshold) {\\n _allocate();\\n }\\n }\\n\\n /**\\n * @notice Mint OTokens for a Metapool Strategy\\n * @param _amount Amount of the asset being deposited\\n *\\n * Notice: can't use `nonReentrant` modifier since the `mint` function can\\n * call `allocate`, and that can trigger `ConvexOUSDMetaStrategy` to call this function\\n * while the execution of the `mint` has not yet completed -> causing a `nonReentrant` collision.\\n *\\n * Also important to understand is that this is a limitation imposed by the test suite.\\n * Production / mainnet contracts should never be configured in a way where mint/redeem functions\\n * that are moving funds between the Vault and end user wallets can influence strategies\\n * utilizing this function.\\n */\\n function mintForStrategy(uint256 _amount)\\n external\\n whenNotCapitalPaused\\n onlyOusdMetaStrategy\\n {\\n require(_amount < MAX_INT, \\\"Amount too high\\\");\\n\\n emit Mint(msg.sender, _amount);\\n\\n // safe to cast because of the require check at the beginning of the function\\n netOusdMintedForStrategy += int256(_amount);\\n\\n require(\\n abs(netOusdMintedForStrategy) < netOusdMintForStrategyThreshold,\\n \\\"Minted ousd surpassed netOusdMintForStrategyThreshold.\\\"\\n );\\n\\n // Mint matching amount of OTokens\\n oUSD.mint(msg.sender, _amount);\\n }\\n\\n // In memoriam\\n\\n /**\\n * @notice Withdraw a supported asset and burn OTokens.\\n * @param _amount Amount of OTokens to burn\\n * @param _minimumUnitAmount Minimum stablecoin units to receive in return\\n */\\n function redeem(uint256 _amount, uint256 _minimumUnitAmount)\\n external\\n whenNotCapitalPaused\\n nonReentrant\\n {\\n _redeem(_amount, _minimumUnitAmount);\\n }\\n\\n /**\\n * @notice Withdraw a supported asset and burn OTokens.\\n * @param _amount Amount of OTokens to burn\\n * @param _minimumUnitAmount Minimum stablecoin units to receive in return\\n */\\n function _redeem(uint256 _amount, uint256 _minimumUnitAmount)\\n internal\\n virtual\\n {\\n // Calculate redemption outputs\\n uint256[] memory outputs = _calculateRedeemOutputs(_amount);\\n\\n emit Redeem(msg.sender, _amount);\\n\\n // Send outputs\\n uint256 assetCount = allAssets.length;\\n for (uint256 i = 0; i < assetCount; ++i) {\\n if (outputs[i] == 0) continue;\\n\\n address assetAddr = allAssets[i];\\n\\n if (IERC20(assetAddr).balanceOf(address(this)) >= outputs[i]) {\\n // Use Vault funds first if sufficient\\n IERC20(assetAddr).safeTransfer(msg.sender, outputs[i]);\\n } else {\\n address strategyAddr = assetDefaultStrategies[assetAddr];\\n if (strategyAddr != address(0)) {\\n // Nothing in Vault, but something in Strategy, send from there\\n IStrategy strategy = IStrategy(strategyAddr);\\n strategy.withdraw(msg.sender, assetAddr, outputs[i]);\\n } else {\\n // Cant find funds anywhere\\n revert(\\\"Liquidity error\\\");\\n }\\n }\\n }\\n\\n if (_minimumUnitAmount > 0) {\\n uint256 unitTotal = 0;\\n for (uint256 i = 0; i < outputs.length; ++i) {\\n unitTotal += _toUnits(outputs[i], allAssets[i]);\\n }\\n require(\\n unitTotal >= _minimumUnitAmount,\\n \\\"Redeem amount lower than minimum\\\"\\n );\\n }\\n\\n oUSD.burn(msg.sender, _amount);\\n\\n _postRedeem(_amount);\\n }\\n\\n function _postRedeem(uint256 _amount) internal {\\n // Until we can prove that we won't affect the prices of our assets\\n // by withdrawing them, this should be here.\\n // It's possible that a strategy was off on its asset total, perhaps\\n // a reward token sold for more or for less than anticipated.\\n uint256 totalUnits = 0;\\n if (_amount >= rebaseThreshold && !rebasePaused) {\\n totalUnits = _rebase();\\n } else {\\n totalUnits = _totalValue();\\n }\\n\\n // Check that the OTokens are backed by enough assets\\n if (maxSupplyDiff > 0) {\\n // Allow a max difference of maxSupplyDiff% between\\n // backing assets value and OUSD total supply\\n uint256 diff = oUSD.totalSupply().divPrecisely(totalUnits);\\n require(\\n (diff > 1e18 ? diff - 1e18 : 1e18 - diff) <= maxSupplyDiff,\\n \\\"Backing supply liquidity error\\\"\\n );\\n }\\n }\\n\\n /**\\n * @notice Burn OTokens for Metapool Strategy\\n * @param _amount Amount of OUSD to burn\\n *\\n * @dev Notice: can't use `nonReentrant` modifier since the `redeem` function could\\n * require withdrawal on `ConvexOUSDMetaStrategy` and that one can call `burnForStrategy`\\n * while the execution of the `redeem` has not yet completed -> causing a `nonReentrant` collision.\\n *\\n * Also important to understand is that this is a limitation imposed by the test suite.\\n * Production / mainnet contracts should never be configured in a way where mint/redeem functions\\n * that are moving funds between the Vault and end user wallets can influence strategies\\n * utilizing this function.\\n */\\n function burnForStrategy(uint256 _amount)\\n external\\n whenNotCapitalPaused\\n onlyOusdMetaStrategy\\n {\\n require(_amount < MAX_INT, \\\"Amount too high\\\");\\n\\n emit Redeem(msg.sender, _amount);\\n\\n // safe to cast because of the require check at the beginning of the function\\n netOusdMintedForStrategy -= int256(_amount);\\n\\n require(\\n abs(netOusdMintedForStrategy) < netOusdMintForStrategyThreshold,\\n \\\"Attempting to burn too much OUSD.\\\"\\n );\\n\\n // Burn OTokens\\n oUSD.burn(msg.sender, _amount);\\n }\\n\\n /**\\n * @notice Withdraw a supported asset and burn all OTokens.\\n * @param _minimumUnitAmount Minimum stablecoin units to receive in return\\n */\\n function redeemAll(uint256 _minimumUnitAmount)\\n external\\n whenNotCapitalPaused\\n nonReentrant\\n {\\n _redeem(oUSD.balanceOf(msg.sender), _minimumUnitAmount);\\n }\\n\\n /**\\n * @notice Allocate unallocated funds on Vault to strategies.\\n **/\\n function allocate() external whenNotCapitalPaused nonReentrant {\\n _allocate();\\n }\\n\\n /**\\n * @dev Allocate unallocated funds on Vault to strategies.\\n **/\\n function _allocate() internal {\\n uint256 vaultValue = _totalValueInVault();\\n // Nothing in vault to allocate\\n if (vaultValue == 0) return;\\n uint256 strategiesValue = _totalValueInStrategies();\\n // We have a method that does the same as this, gas optimisation\\n uint256 calculatedTotalValue = vaultValue + strategiesValue;\\n\\n // We want to maintain a buffer on the Vault so calculate a percentage\\n // modifier to multiply each amount being allocated by to enforce the\\n // vault buffer\\n uint256 vaultBufferModifier;\\n if (strategiesValue == 0) {\\n // Nothing in Strategies, allocate 100% minus the vault buffer to\\n // strategies\\n vaultBufferModifier = uint256(1e18) - vaultBuffer;\\n } else {\\n vaultBufferModifier =\\n (vaultBuffer * calculatedTotalValue) /\\n vaultValue;\\n if (1e18 > vaultBufferModifier) {\\n // E.g. 1e18 - (1e17 * 10e18)/5e18 = 8e17\\n // (5e18 * 8e17) / 1e18 = 4e18 allocated from Vault\\n vaultBufferModifier = uint256(1e18) - vaultBufferModifier;\\n } else {\\n // We need to let the buffer fill\\n return;\\n }\\n }\\n if (vaultBufferModifier == 0) return;\\n\\n // Iterate over all assets in the Vault and allocate to the appropriate\\n // strategy\\n uint256 assetCount = allAssets.length;\\n for (uint256 i = 0; i < assetCount; ++i) {\\n IERC20 asset = IERC20(allAssets[i]);\\n uint256 assetBalance = asset.balanceOf(address(this));\\n // No balance, nothing to do here\\n if (assetBalance == 0) continue;\\n\\n // Multiply the balance by the vault buffer modifier and truncate\\n // to the scale of the asset decimals\\n uint256 allocateAmount = assetBalance.mulTruncate(\\n vaultBufferModifier\\n );\\n\\n address depositStrategyAddr = assetDefaultStrategies[\\n address(asset)\\n ];\\n\\n if (depositStrategyAddr != address(0) && allocateAmount > 0) {\\n IStrategy strategy = IStrategy(depositStrategyAddr);\\n // Transfer asset to Strategy and call deposit method to\\n // mint or take required action\\n asset.safeTransfer(address(strategy), allocateAmount);\\n strategy.deposit(address(asset), allocateAmount);\\n emit AssetAllocated(\\n address(asset),\\n depositStrategyAddr,\\n allocateAmount\\n );\\n }\\n }\\n }\\n\\n /**\\n * @notice Calculate the total value of assets held by the Vault and all\\n * strategies and update the supply of OTokens.\\n */\\n function rebase() external virtual nonReentrant {\\n _rebase();\\n }\\n\\n /**\\n * @dev Calculate the total value of assets held by the Vault and all\\n * strategies and update the supply of OTokens, optionally sending a\\n * portion of the yield to the trustee.\\n * @return totalUnits Total balance of Vault in units\\n */\\n function _rebase() internal whenNotRebasePaused returns (uint256) {\\n uint256 ousdSupply = oUSD.totalSupply();\\n uint256 vaultValue = _totalValue();\\n if (ousdSupply == 0) {\\n return vaultValue;\\n }\\n\\n // Yield fee collection\\n address _trusteeAddress = trusteeAddress; // gas savings\\n if (_trusteeAddress != address(0) && (vaultValue > ousdSupply)) {\\n uint256 yield = vaultValue - ousdSupply;\\n uint256 fee = yield.mulTruncateScale(trusteeFeeBps, 1e4);\\n require(yield > fee, \\\"Fee must not be greater than yield\\\");\\n if (fee > 0) {\\n oUSD.mint(_trusteeAddress, fee);\\n }\\n emit YieldDistribution(_trusteeAddress, yield, fee);\\n }\\n\\n // Only rachet OToken supply upwards\\n ousdSupply = oUSD.totalSupply(); // Final check should use latest value\\n if (vaultValue > ousdSupply) {\\n oUSD.changeSupply(vaultValue);\\n }\\n return vaultValue;\\n }\\n\\n /**\\n * @notice Determine the total value of assets held by the vault and its\\n * strategies.\\n * @return value Total value in USD/ETH (1e18)\\n */\\n function totalValue() external view virtual returns (uint256 value) {\\n value = _totalValue();\\n }\\n\\n /**\\n * @dev Internal Calculate the total value of the assets held by the\\n * vault and its strategies.\\n * @return value Total value in USD/ETH (1e18)\\n */\\n function _totalValue() internal view virtual returns (uint256 value) {\\n return _totalValueInVault() + _totalValueInStrategies();\\n }\\n\\n /**\\n * @dev Internal to calculate total value of all assets held in Vault.\\n * @return value Total value in USD/ETH (1e18)\\n */\\n function _totalValueInVault() internal view returns (uint256 value) {\\n uint256 assetCount = allAssets.length;\\n for (uint256 y = 0; y < assetCount; ++y) {\\n address assetAddr = allAssets[y];\\n uint256 balance = IERC20(assetAddr).balanceOf(address(this));\\n if (balance > 0) {\\n value += _toUnits(balance, assetAddr);\\n }\\n }\\n }\\n\\n /**\\n * @dev Internal to calculate total value of all assets held in Strategies.\\n * @return value Total value in USD/ETH (1e18)\\n */\\n function _totalValueInStrategies() internal view returns (uint256 value) {\\n uint256 stratCount = allStrategies.length;\\n for (uint256 i = 0; i < stratCount; ++i) {\\n value = value + _totalValueInStrategy(allStrategies[i]);\\n }\\n }\\n\\n /**\\n * @dev Internal to calculate total value of all assets held by strategy.\\n * @param _strategyAddr Address of the strategy\\n * @return value Total value in USD/ETH (1e18)\\n */\\n function _totalValueInStrategy(address _strategyAddr)\\n internal\\n view\\n returns (uint256 value)\\n {\\n IStrategy strategy = IStrategy(_strategyAddr);\\n uint256 assetCount = allAssets.length;\\n for (uint256 y = 0; y < assetCount; ++y) {\\n address assetAddr = allAssets[y];\\n if (strategy.supportsAsset(assetAddr)) {\\n uint256 balance = strategy.checkBalance(assetAddr);\\n if (balance > 0) {\\n value += _toUnits(balance, assetAddr);\\n }\\n }\\n }\\n }\\n\\n /**\\n * @notice Get the balance of an asset held in Vault and all strategies.\\n * @param _asset Address of asset\\n * @return uint256 Balance of asset in decimals of asset\\n */\\n function checkBalance(address _asset) external view returns (uint256) {\\n return _checkBalance(_asset);\\n }\\n\\n /**\\n * @notice Get the balance of an asset held in Vault and all strategies.\\n * @param _asset Address of asset\\n * @return balance Balance of asset in decimals of asset\\n */\\n function _checkBalance(address _asset)\\n internal\\n view\\n virtual\\n returns (uint256 balance)\\n {\\n IERC20 asset = IERC20(_asset);\\n balance = asset.balanceOf(address(this));\\n uint256 stratCount = allStrategies.length;\\n for (uint256 i = 0; i < stratCount; ++i) {\\n IStrategy strategy = IStrategy(allStrategies[i]);\\n if (strategy.supportsAsset(_asset)) {\\n balance = balance + strategy.checkBalance(_asset);\\n }\\n }\\n }\\n\\n /**\\n * @notice Calculate the outputs for a redeem function, i.e. the mix of\\n * coins that will be returned\\n */\\n function calculateRedeemOutputs(uint256 _amount)\\n external\\n view\\n returns (uint256[] memory)\\n {\\n return _calculateRedeemOutputs(_amount);\\n }\\n\\n /**\\n * @dev Calculate the outputs for a redeem function, i.e. the mix of\\n * coins that will be returned.\\n * @return outputs Array of amounts respective to the supported assets\\n */\\n function _calculateRedeemOutputs(uint256 _amount)\\n internal\\n view\\n virtual\\n returns (uint256[] memory outputs)\\n {\\n // We always give out coins in proportion to how many we have,\\n // Now if all coins were the same value, this math would easy,\\n // just take the percentage of each coin, and multiply by the\\n // value to be given out. But if coins are worth more than $1,\\n // then we would end up handing out too many coins. We need to\\n // adjust by the total value of coins.\\n //\\n // To do this, we total up the value of our coins, by their\\n // percentages. Then divide what we would otherwise give out by\\n // this number.\\n //\\n // Let say we have 100 DAI at $1.06 and 200 USDT at $1.00.\\n // So for every 1 DAI we give out, we'll be handing out 2 USDT\\n // Our total output ratio is: 33% * 1.06 + 66% * 1.00 = 1.02\\n //\\n // So when calculating the output, we take the percentage of\\n // each coin, times the desired output value, divided by the\\n // totalOutputRatio.\\n //\\n // For example, withdrawing: 30 OUSD:\\n // DAI 33% * 30 / 1.02 = 9.80 DAI\\n // USDT = 66 % * 30 / 1.02 = 19.60 USDT\\n //\\n // Checking these numbers:\\n // 9.80 DAI * 1.06 = $10.40\\n // 19.60 USDT * 1.00 = $19.60\\n //\\n // And so the user gets $10.40 + $19.60 = $30 worth of value.\\n\\n uint256 assetCount = allAssets.length;\\n uint256[] memory assetUnits = new uint256[](assetCount);\\n uint256[] memory assetBalances = new uint256[](assetCount);\\n outputs = new uint256[](assetCount);\\n\\n // Calculate redeem fee\\n if (redeemFeeBps > 0) {\\n uint256 redeemFee = _amount.mulTruncateScale(redeemFeeBps, 1e4);\\n _amount = _amount - redeemFee;\\n }\\n\\n // Calculate assets balances and decimals once,\\n // for a large gas savings.\\n uint256 totalUnits = 0;\\n for (uint256 i = 0; i < assetCount; ++i) {\\n address assetAddr = allAssets[i];\\n uint256 balance = _checkBalance(assetAddr);\\n assetBalances[i] = balance;\\n assetUnits[i] = _toUnits(balance, assetAddr);\\n totalUnits = totalUnits + assetUnits[i];\\n }\\n // Calculate totalOutputRatio\\n uint256 totalOutputRatio = 0;\\n for (uint256 i = 0; i < assetCount; ++i) {\\n uint256 unitPrice = _toUnitPrice(allAssets[i], false);\\n uint256 ratio = (assetUnits[i] * unitPrice) / totalUnits;\\n totalOutputRatio = totalOutputRatio + ratio;\\n }\\n // Calculate final outputs\\n uint256 factor = _amount.divPrecisely(totalOutputRatio);\\n for (uint256 i = 0; i < assetCount; ++i) {\\n outputs[i] = (assetBalances[i] * factor) / totalUnits;\\n }\\n }\\n\\n /***************************************\\n Pricing\\n ****************************************/\\n\\n /**\\n * @notice Returns the total price in 18 digit units for a given asset.\\n * Never goes above 1, since that is how we price mints.\\n * @param asset address of the asset\\n * @return price uint256: unit (USD / ETH) price for 1 unit of the asset, in 18 decimal fixed\\n */\\n function priceUnitMint(address asset)\\n external\\n view\\n returns (uint256 price)\\n {\\n /* need to supply 1 asset unit in asset's decimals and can not just hard-code\\n * to 1e18 and ignore calling `_toUnits` since we need to consider assets\\n * with the exchange rate\\n */\\n uint256 units = _toUnits(\\n uint256(1e18).scaleBy(_getDecimals(asset), 18),\\n asset\\n );\\n price = (_toUnitPrice(asset, true) * units) / 1e18;\\n }\\n\\n /**\\n * @notice Returns the total price in 18 digit unit for a given asset.\\n * Never goes below 1, since that is how we price redeems\\n * @param asset Address of the asset\\n * @return price uint256: unit (USD / ETH) price for 1 unit of the asset, in 18 decimal fixed\\n */\\n function priceUnitRedeem(address asset)\\n external\\n view\\n returns (uint256 price)\\n {\\n /* need to supply 1 asset unit in asset's decimals and can not just hard-code\\n * to 1e18 and ignore calling `_toUnits` since we need to consider assets\\n * with the exchange rate\\n */\\n uint256 units = _toUnits(\\n uint256(1e18).scaleBy(_getDecimals(asset), 18),\\n asset\\n );\\n price = (_toUnitPrice(asset, false) * units) / 1e18;\\n }\\n\\n /***************************************\\n Utils\\n ****************************************/\\n\\n /**\\n * @dev Convert a quantity of a token into 1e18 fixed decimal \\\"units\\\"\\n * in the underlying base (USD/ETH) used by the vault.\\n * Price is not taken into account, only quantity.\\n *\\n * Examples of this conversion:\\n *\\n * - 1e18 DAI becomes 1e18 units (same decimals)\\n * - 1e6 USDC becomes 1e18 units (decimal conversion)\\n * - 1e18 rETH becomes 1.2e18 units (exchange rate conversion)\\n *\\n * @param _raw Quantity of asset\\n * @param _asset Core Asset address\\n * @return value 1e18 normalized quantity of units\\n */\\n function _toUnits(uint256 _raw, address _asset)\\n internal\\n view\\n returns (uint256)\\n {\\n UnitConversion conversion = assets[_asset].unitConversion;\\n if (conversion == UnitConversion.DECIMALS) {\\n return _raw.scaleBy(18, _getDecimals(_asset));\\n } else if (conversion == UnitConversion.GETEXCHANGERATE) {\\n uint256 exchangeRate = IGetExchangeRateToken(_asset)\\n .getExchangeRate();\\n return (_raw * exchangeRate) / 1e18;\\n } else {\\n revert(\\\"Unsupported conversion type\\\");\\n }\\n }\\n\\n /**\\n * @dev Returns asset's unit price accounting for different asset types\\n * and takes into account the context in which that price exists -\\n * - mint or redeem.\\n *\\n * Note: since we are returning the price of the unit and not the one of the\\n * asset (see comment above how 1 rETH exchanges for 1.2 units) we need\\n * to make the Oracle price adjustment as well since we are pricing the\\n * units and not the assets.\\n *\\n * The price also snaps to a \\\"full unit price\\\" in case a mint or redeem\\n * action would be unfavourable to the protocol.\\n *\\n */\\n function _toUnitPrice(address _asset, bool isMint)\\n internal\\n view\\n returns (uint256 price)\\n {\\n UnitConversion conversion = assets[_asset].unitConversion;\\n price = IOracle(priceProvider).price(_asset);\\n\\n if (conversion == UnitConversion.GETEXCHANGERATE) {\\n uint256 exchangeRate = IGetExchangeRateToken(_asset)\\n .getExchangeRate();\\n price = (price * 1e18) / exchangeRate;\\n } else if (conversion != UnitConversion.DECIMALS) {\\n revert(\\\"Unsupported conversion type\\\");\\n }\\n\\n /* At this stage the price is already adjusted to the unit\\n * so the price checks are agnostic to underlying asset being\\n * pegged to a USD or to an ETH or having a custom exchange rate.\\n */\\n require(price <= MAX_UNIT_PRICE_DRIFT, \\\"Vault: Price exceeds max\\\");\\n require(price >= MIN_UNIT_PRICE_DRIFT, \\\"Vault: Price under min\\\");\\n\\n if (isMint) {\\n /* Never price a normalized unit price for more than one\\n * unit of OETH/OUSD when minting.\\n */\\n if (price > 1e18) {\\n price = 1e18;\\n }\\n require(price >= MINT_MINIMUM_UNIT_PRICE, \\\"Asset price below peg\\\");\\n } else {\\n /* Never give out more than 1 normalized unit amount of assets\\n * for one unit of OETH/OUSD when redeeming.\\n */\\n if (price < 1e18) {\\n price = 1e18;\\n }\\n }\\n }\\n\\n function _getDecimals(address _asset)\\n internal\\n view\\n returns (uint256 decimals)\\n {\\n decimals = assets[_asset].decimals;\\n require(decimals > 0, \\\"Decimals not cached\\\");\\n }\\n\\n /**\\n * @notice Return the number of assets supported by the Vault.\\n */\\n function getAssetCount() public view returns (uint256) {\\n return allAssets.length;\\n }\\n\\n /**\\n * @notice Gets the vault configuration of a supported asset.\\n */\\n function getAssetConfig(address _asset)\\n public\\n view\\n returns (Asset memory config)\\n {\\n config = assets[_asset];\\n }\\n\\n /**\\n * @notice Return all vault asset addresses in order\\n */\\n function getAllAssets() external view returns (address[] memory) {\\n return allAssets;\\n }\\n\\n /**\\n * @notice Return the number of strategies active on the Vault.\\n */\\n function getStrategyCount() external view returns (uint256) {\\n return allStrategies.length;\\n }\\n\\n /**\\n * @notice Return the array of all strategies\\n */\\n function getAllStrategies() external view returns (address[] memory) {\\n return allStrategies;\\n }\\n\\n /**\\n * @notice Returns whether the vault supports the asset\\n * @param _asset address of the asset\\n * @return true if supported\\n */\\n function isSupportedAsset(address _asset) external view returns (bool) {\\n return assets[_asset].isSupported;\\n }\\n\\n /**\\n * @dev Falldown to the admin implementation\\n * @notice This is a catch all for all functions not declared in core\\n */\\n // solhint-disable-next-line no-complex-fallback\\n fallback() external {\\n bytes32 slot = adminImplPosition;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n // Copy msg.data. We take full control of memory in this inline assembly\\n // block because it will not return to Solidity code. We overwrite the\\n // Solidity scratch pad at memory position 0.\\n calldatacopy(0, 0, calldatasize())\\n\\n // Call the implementation.\\n // out and outsize are 0 because we don't know the size yet.\\n let result := delegatecall(\\n gas(),\\n sload(slot),\\n 0,\\n calldatasize(),\\n 0,\\n 0\\n )\\n\\n // Copy the returned data.\\n returndatacopy(0, 0, returndatasize())\\n\\n switch result\\n // delegatecall returns 0 on error.\\n case 0 {\\n revert(0, returndatasize())\\n }\\n default {\\n return(0, returndatasize())\\n }\\n }\\n }\\n\\n function abs(int256 x) private pure returns (uint256) {\\n require(x < int256(MAX_INT), \\\"Amount too high\\\");\\n return x >= 0 ? uint256(x) : uint256(-x);\\n }\\n}\\n\",\"keccak256\":\"0x5af4c0464b3728750231edf3bec62181c9eb734b5a3b3f7379789c84c0411ef0\",\"license\":\"MIT\"},\"contracts/vault/VaultInitializer.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title OToken VaultInitializer contract\\n * @notice The Vault contract initializes the vault.\\n * @author Origin Protocol Inc\\n */\\n\\nimport \\\"./VaultStorage.sol\\\";\\n\\ncontract VaultInitializer is VaultStorage {\\n function initialize(address _priceProvider, address _oToken)\\n external\\n onlyGovernor\\n initializer\\n {\\n require(_priceProvider != address(0), \\\"PriceProvider address is zero\\\");\\n require(_oToken != address(0), \\\"oToken address is zero\\\");\\n\\n oUSD = OUSD(_oToken);\\n\\n priceProvider = _priceProvider;\\n\\n rebasePaused = false;\\n capitalPaused = true;\\n\\n // Initial redeem fee of 0 basis points\\n redeemFeeBps = 0;\\n // Initial Vault buffer of 0%\\n vaultBuffer = 0;\\n // Initial allocate threshold of 25,000 OUSD\\n autoAllocateThreshold = 25000e18;\\n // Threshold for rebasing\\n rebaseThreshold = 1000e18;\\n // Initialize all strategies\\n allStrategies = new address[](0);\\n }\\n}\\n\",\"keccak256\":\"0x5b9676307bbabe14b5278f00ec7edc557b84debbfa1391902d78100cb9cd467e\",\"license\":\"MIT\"},\"contracts/vault/VaultStorage.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title OToken VaultStorage contract\\n * @notice The VaultStorage contract defines the storage for the Vault contracts\\n * @author Origin Protocol Inc\\n */\\n\\nimport { IERC20 } from \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport { SafeERC20 } from \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\nimport { Address } from \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\n\\nimport { IStrategy } from \\\"../interfaces/IStrategy.sol\\\";\\nimport { Governable } from \\\"../governance/Governable.sol\\\";\\nimport { OUSD } from \\\"../token/OUSD.sol\\\";\\nimport { Initializable } from \\\"../utils/Initializable.sol\\\";\\nimport \\\"../utils/Helpers.sol\\\";\\n\\ncontract VaultStorage is Initializable, Governable {\\n using SafeERC20 for IERC20;\\n\\n event AssetSupported(address _asset);\\n event AssetDefaultStrategyUpdated(address _asset, address _strategy);\\n event AssetAllocated(address _asset, address _strategy, uint256 _amount);\\n event StrategyApproved(address _addr);\\n event StrategyRemoved(address _addr);\\n event Mint(address _addr, uint256 _value);\\n event Redeem(address _addr, uint256 _value);\\n event CapitalPaused();\\n event CapitalUnpaused();\\n event RebasePaused();\\n event RebaseUnpaused();\\n event VaultBufferUpdated(uint256 _vaultBuffer);\\n event OusdMetaStrategyUpdated(address _ousdMetaStrategy);\\n event RedeemFeeUpdated(uint256 _redeemFeeBps);\\n event PriceProviderUpdated(address _priceProvider);\\n event AllocateThresholdUpdated(uint256 _threshold);\\n event RebaseThresholdUpdated(uint256 _threshold);\\n event StrategistUpdated(address _address);\\n event MaxSupplyDiffChanged(uint256 maxSupplyDiff);\\n event YieldDistribution(address _to, uint256 _yield, uint256 _fee);\\n event TrusteeFeeBpsChanged(uint256 _basis);\\n event TrusteeAddressChanged(address _address);\\n event NetOusdMintForStrategyThresholdChanged(uint256 _threshold);\\n event SwapperChanged(address _address);\\n event SwapAllowedUndervalueChanged(uint256 _basis);\\n event SwapSlippageChanged(address _asset, uint256 _basis);\\n event Swapped(\\n address indexed _fromAsset,\\n address indexed _toAsset,\\n uint256 _fromAssetAmount,\\n uint256 _toAssetAmount\\n );\\n\\n // Assets supported by the Vault, i.e. Stablecoins\\n enum UnitConversion {\\n DECIMALS,\\n GETEXCHANGERATE\\n }\\n // Changed to fit into a single storage slot so the decimals needs to be recached\\n struct Asset {\\n // Note: OETHVaultCore doesn't use `isSupported` when minting,\\n // redeeming or checking balance of assets.\\n bool isSupported;\\n UnitConversion unitConversion;\\n uint8 decimals;\\n // Max allowed slippage from the Oracle price when swapping collateral assets in basis points.\\n // For example 40 == 0.4% slippage\\n uint16 allowedOracleSlippageBps;\\n }\\n\\n /// @dev mapping of supported vault assets to their configuration\\n // slither-disable-next-line uninitialized-state\\n mapping(address => Asset) internal assets;\\n /// @dev list of all assets supported by the vault.\\n // slither-disable-next-line uninitialized-state\\n address[] internal allAssets;\\n\\n // Strategies approved for use by the Vault\\n struct Strategy {\\n bool isSupported;\\n uint256 _deprecated; // Deprecated storage slot\\n }\\n /// @dev mapping of strategy contracts to their configiration\\n mapping(address => Strategy) internal strategies;\\n /// @dev list of all vault strategies\\n address[] internal allStrategies;\\n\\n /// @notice Address of the Oracle price provider contract\\n // slither-disable-next-line uninitialized-state\\n address public priceProvider;\\n /// @notice pause rebasing if true\\n bool public rebasePaused = false;\\n /// @notice pause operations that change the OToken supply.\\n /// eg mint, redeem, allocate, mint/burn for strategy\\n bool public capitalPaused = true;\\n /// @notice Redemption fee in basis points. eg 50 = 0.5%\\n uint256 public redeemFeeBps;\\n /// @notice Percentage of assets to keep in Vault to handle (most) withdrawals. 100% = 1e18.\\n uint256 public vaultBuffer;\\n /// @notice OToken mints over this amount automatically allocate funds. 18 decimals.\\n uint256 public autoAllocateThreshold;\\n /// @notice OToken mints over this amount automatically rebase. 18 decimals.\\n uint256 public rebaseThreshold;\\n\\n /// @dev Address of the OToken token. eg OUSD or OETH.\\n // slither-disable-next-line uninitialized-state\\n OUSD internal oUSD;\\n\\n //keccak256(\\\"OUSD.vault.governor.admin.impl\\\");\\n bytes32 constant adminImplPosition =\\n 0xa2bd3d3cf188a41358c8b401076eb59066b09dec5775650c0de4c55187d17bd9;\\n\\n // Address of the contract responsible for post rebase syncs with AMMs\\n address private _deprecated_rebaseHooksAddr = address(0);\\n\\n // Deprecated: Address of Uniswap\\n // slither-disable-next-line constable-states\\n address private _deprecated_uniswapAddr = address(0);\\n\\n /// @notice Address of the Strategist\\n address public strategistAddr = address(0);\\n\\n /// @notice Mapping of asset address to the Strategy that they should automatically\\n // be allocated to\\n // slither-disable-next-line uninitialized-state\\n mapping(address => address) public assetDefaultStrategies;\\n\\n /// @notice Max difference between total supply and total value of assets. 18 decimals.\\n // slither-disable-next-line uninitialized-state\\n uint256 public maxSupplyDiff;\\n\\n /// @notice Trustee contract that can collect a percentage of yield\\n address public trusteeAddress;\\n\\n /// @notice Amount of yield collected in basis points. eg 2000 = 20%\\n uint256 public trusteeFeeBps;\\n\\n /// @dev Deprecated: Tokens that should be swapped for stablecoins\\n address[] private _deprecated_swapTokens;\\n\\n uint256 constant MINT_MINIMUM_UNIT_PRICE = 0.998e18;\\n\\n /// @notice Metapool strategy that is allowed to mint/burn OTokens without changing collateral\\n address public ousdMetaStrategy = address(0);\\n\\n /// @notice How much OTokens are currently minted by the strategy\\n int256 public netOusdMintedForStrategy = 0;\\n\\n /// @notice How much net total OTokens are allowed to be minted by all strategies\\n uint256 public netOusdMintForStrategyThreshold = 0;\\n\\n uint256 constant MIN_UNIT_PRICE_DRIFT = 0.7e18;\\n uint256 constant MAX_UNIT_PRICE_DRIFT = 1.3e18;\\n\\n /// @notice Collateral swap configuration.\\n /// @dev is packed into a single storage slot to save gas.\\n struct SwapConfig {\\n // Contract that swaps the vault's collateral assets\\n address swapper;\\n // Max allowed percentage the total value can drop below the total supply in basis points.\\n // For example 100 == 1%\\n uint16 allowedUndervalueBps;\\n }\\n SwapConfig internal swapConfig = SwapConfig(address(0), 0);\\n\\n // For future use\\n uint256[50] private __gap;\\n\\n /**\\n * @notice set the implementation for the admin, this needs to be in a base class else we cannot set it\\n * @param newImpl address of the implementation\\n */\\n function setAdminImpl(address newImpl) external onlyGovernor {\\n require(\\n Address.isContract(newImpl),\\n \\\"new implementation is not a contract\\\"\\n );\\n bytes32 position = adminImplPosition;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n sstore(position, newImpl)\\n }\\n }\\n}\\n\",\"keccak256\":\"0xbcefeb5e2b88d99a54dbe6542dc25d0a68eeaf3adfe6e12fb70049cc024b1a79\",\"license\":\"MIT\"}},\"version\":1}", - "bytecode": "0x6037805461ffff60a01b1916600160a81b179055603d80546001600160a01b0319908116909155603e805482169055603f80548216905560458054909116905560006046819055604781905560e060405260a081905260c052604880546001600160b01b03191690553480156200007557600080fd5b50604051620036453803806200364583398101604081905262000098916200010e565b620000b0336000805160206200362583398151915255565b60008051602062003625833981519152546040516001600160a01b03909116906000907fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a908290a360601b6001600160601b03191660805262000140565b6000602082840312156200012157600080fd5b81516001600160a01b03811681146200013957600080fd5b9392505050565b60805160601c61348e620001976000396000818161034f0152818161072401528181610797015281816112d001528181611d0301528181611edd01528181611f7101528181611fa70152611ffb015261348e6000f3fe608060405234801561001057600080fd5b506004361061025e5760003560e01c806367bd7ba311610146578063ab80dafb116100c3578063c7af335211610087578063c7af335214610545578063d38bfff41461054d578063d4c3eea014610560578063e45cc9f014610568578063e6cc543214610571578063fc0cfeee146105855761025e565b8063ab80dafb14610507578063abaa99161461051a578063af14052c14610522578063b888879e1461052a578063c3b288641461053d5761025e565b80638e510b521161010a5780638e510b52146104985780639be918e6146104a15780639fa1826e146104cd578063a0aead4d146104d6578063a403e4d5146104de5761025e565b806367bd7ba3146104295780636ec3ab67146104495780637136a7a6146104695780637a2202f31461047c5780637cbc2373146104855761025e565b806344c54707116101df57806354c6d858116101a357806354c6d858146103cc578063570d8e1d146103d55780635b60f9fc146103e85780635d36b190146103fb5780635f515226146104035780636217f3ea146104165761025e565b806344c5470714610371578063485cc9551461037957806349c1d54d1461038c57806352d38e5d1461039f57806353ca9f24146103a85761025e565b8063207134b011610226578063207134b0146103115780632acada4d1461031a57806331e19cfa1461032f5780633b8fe28d146103375780633fc8cef31461034a5761025e565b806309f6442c146102a45780630c340a24146102c0578063156e29f6146102e057806318ce56bd146102f55780631edfe3da14610308575b7fa2bd3d3cf188a41358c8b401076eb59066b09dec5775650c0de4c55187d17bd9366000803760008036600084545af43d6000803e80801561029f573d6000f35b3d6000fd5b6102ad60385481565b6040519081526020015b60405180910390f35b6102c8610598565b6040516001600160a01b0390911681526020016102b7565b6102f36102ee366004612ea1565b6105b5565b005b6045546102c8906001600160a01b031681565b6102ad60395481565b6102ad60435481565b610322610633565b6040516102b79190612f7f565b6036546102ad565b6102ad610345366004612e53565b610695565b6102c87f000000000000000000000000000000000000000000000000000000000000000081565b6102f36106f0565b6102f3610387366004612e6e565b610839565b6042546102c8906001600160a01b031681565b6102ad603b5481565b6037546103bc90600160a01b900460ff1681565b60405190151581526020016102b7565b6102ad607b5481565b603f546102c8906001600160a01b031681565b6102ad6103f6366004612e53565b610a3b565b6102f3610a64565b6102ad610411366004612e53565b610b0a565b6102f3610424366004612ef6565b610b1b565b61043c610437366004612ef6565b610cb2565b6040516102b79190612fcc565b61045c610457366004612e53565b610cbd565b6040516102b7919061312b565b6102f3610477366004612ef6565b610d63565b6102ad60475481565b6102f3610493366004612f28565b610e4e565b6102ad60415481565b6103bc6104af366004612e53565b6001600160a01b031660009081526033602052604090205460ff1690565b6102ad603a5481565b6034546102ad565b6102c86104ec366004612e53565b6040602081905260009182529020546001600160a01b031681565b6102f3610515366004612ef6565b610ec1565b6102f3611038565b6102f36110a7565b6037546102c8906001600160a01b031681565b6103226110ed565b6103bc61114d565b6102f361055b366004612e53565b61117e565b6102ad611222565b6102ad60465481565b6037546103bc90600160a81b900460ff1681565b6102f3610593366004612e53565b61122c565b60006105b06000805160206134398339815191525490565b905090565b603754600160a81b900460ff16156105e85760405162461bcd60e51b81526004016105df906130db565b60405180910390fd5b6000805160206134198339815191528054600281141561061a5760405162461bcd60e51b81526004016105df90613103565b600282556106298585856112ce565b5060019055505050565b6060603480548060200260200160405190810160405280929190818152602001828054801561068b57602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161066d575b5050505050905090565b6000806106be6106b86106a7856114de565b670de0b6b3a7640000906012611548565b846115aa565b9050670de0b6b3a7640000816106d5856001611706565b6106df91906132e7565b6106e991906131da565b9392505050565b6106f861114d565b6107145760405162461bcd60e51b81526004016105df9061307b565b60345460005b81811015610794577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166034828154811061075f5761075f6133ec565b6000918252602090912001546001600160a01b0316141561078457607b819055610794565b61078d81613388565b905061071a565b507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166034607b54815481106107d4576107d46133ec565b6000918252602090912001546001600160a01b0316146108365760405162461bcd60e51b815260206004820152601860248201527f496e76616c6964205745544820417373657420496e646578000000000000000060448201526064016105df565b50565b61084161114d565b61085d5760405162461bcd60e51b81526004016105df9061307b565b600054610100900460ff1680610876575060005460ff16155b6108d95760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016105df565b600054610100900460ff161580156108fb576000805461ffff19166101011790555b6001600160a01b0383166109515760405162461bcd60e51b815260206004820152601d60248201527f507269636550726f76696465722061646472657373206973207a65726f00000060448201526064016105df565b6001600160a01b0382166109a05760405162461bcd60e51b81526020600482015260166024820152756f546f6b656e2061646472657373206973207a65726f60501b60448201526064016105df565b603c80546001600160a01b038481166001600160a01b031990921691909117909155603780546001600160b01b03191691851691909117600160a81b17905560006038819055603981905569054b40b1f852bda00000603a55683635c9adc5dea00000603b556040805191825260208201908190529051610a2391603691612dcb565b508015610a36576000805461ff00191690555b505050565b600080610a4d6106b86106a7856114de565b9050670de0b6b3a7640000816106d5856000611706565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b031614610aff5760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b60648201526084016105df565b610b08336119f8565b565b6000610b1582611ab9565b92915050565b603754600160a81b900460ff1615610b455760405162461bcd60e51b81526004016105df906130db565b6045546001600160a01b03163314610b6f5760405162461bcd60e51b81526004016105df90613037565b6001600160ff1b038110610b955760405162461bcd60e51b81526004016105df906130b2565b7f222838db2794d11532d940e8dec38ae307ed0b63cd97c233322e221f998767a63382604051610bc6929190612f66565b60405180910390a18060466000828254610be09190613306565b9091555050604754604654610bf490611c88565b10610c4b5760405162461bcd60e51b815260206004820152602160248201527f417474656d7074696e6720746f206275726e20746f6f206d756368204f5553446044820152601760f91b60648201526084016105df565b603c54604051632770a7eb60e21b81526001600160a01b0390911690639dc29fac90610c7d9033908590600401612f66565b600060405180830381600087803b158015610c9757600080fd5b505af1158015610cab573d6000803e3d6000fd5b5050505050565b6060610b1582611ccb565b604080516080808201835260008083526020808401829052838501829052606084018290526001600160a01b038616825260338152908490208451928301909452835460ff808216151584529394929391840191610100909104166001811115610d2957610d296133d6565b6001811115610d3a57610d3a6133d6565b8152905462010000810460ff1660208301526301000000900461ffff1660409091015292915050565b603754600160a81b900460ff1615610d8d5760405162461bcd60e51b81526004016105df906130db565b60008051602061341983398151915280546002811415610dbf5760405162461bcd60e51b81526004016105df90613103565b60028255603c546040516370a0823160e01b8152336004820152610e46916001600160a01b0316906370a082319060240160206040518083038186803b158015610e0857600080fd5b505afa158015610e1c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e409190612f0f565b84611e0c565b506001905550565b603754600160a81b900460ff1615610e785760405162461bcd60e51b81526004016105df906130db565b60008051602061341983398151915280546002811415610eaa5760405162461bcd60e51b81526004016105df90613103565b60028255610eb88484611e0c565b50600190555050565b603754600160a81b900460ff1615610eeb5760405162461bcd60e51b81526004016105df906130db565b6045546001600160a01b03163314610f155760405162461bcd60e51b81526004016105df90613037565b6001600160ff1b038110610f3b5760405162461bcd60e51b81526004016105df906130b2565b7f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d41213968853382604051610f6c929190612f66565b60405180910390a18060466000828254610f869190613181565b9091555050604754604654610f9a90611c88565b106110065760405162461bcd60e51b815260206004820152603660248201527f4d696e746564206f75736420737572706173736564206e65744f7573644d696e6044820152753a2337b929ba3930ba32b3bcaa343932b9b437b6321760511b60648201526084016105df565b603c546040516340c10f1960e01b81526001600160a01b03909116906340c10f1990610c7d9033908590600401612f66565b603754600160a81b900460ff16156110625760405162461bcd60e51b81526004016105df906130db565b600080516020613419833981519152805460028114156110945760405162461bcd60e51b81526004016105df90613103565b600282556110a0612118565b5060019055565b600080516020613419833981519152805460028114156110d95760405162461bcd60e51b81526004016105df90613103565b600282556110e561238c565b505060019055565b6060603680548060200260200160405190810160405280929190818152602001828054801561068b576020028201919060005260206000209081546001600160a01b0316815260019091019060200180831161066d575050505050905090565b60006111656000805160206134398339815191525490565b6001600160a01b0316336001600160a01b031614905090565b61118661114d565b6111a25760405162461bcd60e51b81526004016105df9061307b565b6111ca817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b03166111ea6000805160206134398339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b60006105b06126c7565b61123461114d565b6112505760405162461bcd60e51b81526004016105df9061307b565b803b6112aa5760405162461bcd60e51b8152602060048201526024808201527f6e657720696d706c656d656e746174696f6e206973206e6f74206120636f6e746044820152631c9858dd60e21b60648201526084016105df565b7fa2bd3d3cf188a41358c8b401076eb59066b09dec5775650c0de4c55187d17bd955565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316836001600160a01b03161461134f5760405162461bcd60e51b815260206004820152601d60248201527f556e737570706f7274656420617373657420666f72206d696e74696e6700000060448201526064016105df565b6000821161139f5760405162461bcd60e51b815260206004820152601d60248201527f416d6f756e74206d7573742062652067726561746572207468616e203000000060448201526064016105df565b808210156113ef5760405162461bcd60e51b815260206004820152601e60248201527f4d696e7420616d6f756e74206c6f776572207468616e206d696e696d756d000060448201526064016105df565b7f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d41213968853383604051611420929190612f66565b60405180910390a1603754600160a01b900460ff161580156114445750603b548210155b156114535761145161238c565b505b603c546040516340c10f1960e01b81526001600160a01b03909116906340c10f19906114859033908690600401612f66565b600060405180830381600087803b15801561149f57600080fd5b505af11580156114b3573d6000803e3d6000fd5b506114cd925050506001600160a01b0384163330856126e3565b603a548210610a3657610a36612118565b6001600160a01b03811660009081526033602052604090205462010000900460ff16806115435760405162461bcd60e51b8152602060048201526013602482015272111958da5b585b1cc81b9bdd0818d858da1959606a1b60448201526064016105df565b919050565b6000818311156115785761157161155f8385613345565b61156a90600a61323f565b859061274e565b93506115a2565b818310156115a25761159f61158d8484613345565b61159890600a61323f565b859061275a565b93505b509192915050565b6001600160a01b038116600090815260336020526040812054610100900460ff16818160018111156115de576115de6133d6565b1415611602576115fa60126115f2856114de565b869190611548565b915050610b15565b6001816001811115611616576116166133d6565b14156116b7576000836001600160a01b031663e6aa216c6040518163ffffffff1660e01b815260040160206040518083038186803b15801561165757600080fd5b505afa15801561166b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061168f9190612f0f565b9050670de0b6b3a76400006116a482876132e7565b6116ae91906131da565b92505050610b15565b60405162461bcd60e51b815260206004820152601b60248201527f556e737570706f7274656420636f6e76657273696f6e2074797065000000000060448201526064016105df565b5092915050565b6001600160a01b038281166000818152603360205260408082205460375491516315d5220f60e31b81526004810194909452919361010090920460ff169291169063aea910789060240160206040518083038186803b15801561176857600080fd5b505afa15801561177c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117a09190612f0f565b915060018160018111156117b6576117b66133d6565b1415611856576000846001600160a01b031663e6aa216c6040518163ffffffff1660e01b815260040160206040518083038186803b1580156117f757600080fd5b505afa15801561180b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061182f9190612f0f565b90508061184484670de0b6b3a76400006132e7565b61184e91906131da565b9250506118b7565b600081600181111561186a5761186a6133d6565b146118b75760405162461bcd60e51b815260206004820152601b60248201527f556e737570706f7274656420636f6e76657273696f6e2074797065000000000060448201526064016105df565b67120a871cc002000082111561190f5760405162461bcd60e51b815260206004820152601860248201527f5661756c743a2050726963652065786365656473206d6178000000000000000060448201526064016105df565b6709b6e64a8ec600008210156119605760405162461bcd60e51b81526020600482015260166024820152752b30bab63a1d10283934b1b2903ab73232b91036b4b760511b60448201526064016105df565b82156119d757670de0b6b3a764000082111561198257670de0b6b3a764000091505b670dd99bb65dd700008210156119d25760405162461bcd60e51b815260206004820152601560248201527441737365742070726963652062656c6f772070656760581b60448201526064016105df565b6116ff565b670de0b6b3a76400008210156116ff5750670de0b6b3a76400009392505050565b6001600160a01b038116611a4e5760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f72206973206164647265737328302900000000000060448201526064016105df565b806001600160a01b0316611a6e6000805160206134398339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a36108368160008051602061343983398151915255565b6040516370a0823160e01b815230600482015260009082906001600160a01b038216906370a082319060240160206040518083038186803b158015611afd57600080fd5b505afa158015611b11573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b359190612f0f565b60365490925060005b81811015611c8057600060368281548110611b5b57611b5b6133ec565b60009182526020909120015460405163551c457b60e11b81526001600160a01b0388811660048301529091169150819063aa388af69060240160206040518083038186803b158015611bac57600080fd5b505afa158015611bc0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611be49190612ed4565b15611c6f57604051632fa8a91360e11b81526001600160a01b038781166004830152821690635f5152269060240160206040518083038186803b158015611c2a57600080fd5b505afa158015611c3e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c629190612f0f565b611c6c90866131c2565b94505b50611c7981613388565b9050611b3e565b505050919050565b60006001600160ff1b038212611cb05760405162461bcd60e51b81526004016105df906130b2565b6000821215611cc757611cc2826133a3565b610b15565b5090565b60385460609015611cfa57603854600090611cea908490612710612766565b9050611cf68184613345565b9250505b6000607b5490507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031660348281548110611d3e57611d3e6133ec565b6000918252602090912001546001600160a01b031614611da05760405162461bcd60e51b815260206004820152601b60248201527f5745544820417373657420696e646578206e6f7420636163686564000000000060448201526064016105df565b60345467ffffffffffffffff811115611dbb57611dbb613402565b604051908082528060200260200182016040528015611de4578160200160208202803683370190505b50915082828281518110611dfa57611dfa6133ec565b60200260200101818152505050919050565b7f222838db2794d11532d940e8dec38ae307ed0b63cd97c233322e221f998767a63383604051611e3d929190612f66565b60405180910390a181611e4e575050565b6000611e5983611ccb565b607b5481518110611e6c57611e6c6133ec565b6020026020010151905081811015611ec65760405162461bcd60e51b815260206004820181905260248201527f52656465656d20616d6f756e74206c6f776572207468616e206d696e696d756d60448201526064016105df565b6040516370a0823160e01b815230600482015281907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b158015611f2757600080fd5b505afa158015611f3b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f5f9190612f0f565b10611f9d57611f986001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163383612788565b6120ab565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660009081526040602081905290205416801561206f57604051636ce5768960e11b81523360048201526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660248301526044820184905282919082169063d9caed1290606401600060405180830381600087803b15801561205157600080fd5b505af1158015612065573d6000803e3d6000fd5b50505050506120a9565b60405162461bcd60e51b815260206004820152600f60248201526e2634b8bab4b234ba3c9032b93937b960891b60448201526064016105df565b505b603c54604051632770a7eb60e21b81526001600160a01b0390911690639dc29fac906120dd9033908790600401612f66565b600060405180830381600087803b1580156120f757600080fd5b505af115801561210b573d6000803e3d6000fd5b50505050610a36836127a7565b600061212261290d565b90508061212c5750565b60006121366129ef565b9050600061214482846131c2565b90506000826121695760395461216290670de0b6b3a7640000613345565b90506121ac565b838260395461217891906132e7565b61218291906131da565b905080670de0b6b3a764000011156121a65761216281670de0b6b3a7640000613345565b50505050565b806121b75750505050565b60345460005b81811015612384576000603482815481106121da576121da6133ec565b60009182526020822001546040516370a0823160e01b81523060048201526001600160a01b03909116925082906370a082319060240160206040518083038186803b15801561222857600080fd5b505afa15801561223c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122609190612f0f565b90508061226e575050612374565b600061227a8287612a4b565b6001600160a01b038085166000908152604060208190529020549192501680158015906122a75750600082115b1561236f57806122c16001600160a01b0386168285612788565b6040516311f9fbc960e21b81526001600160a01b038216906347e7ef24906122ef9088908790600401612f66565b600060405180830381600087803b15801561230957600080fd5b505af115801561231d573d6000803e3d6000fd5b5050604080516001600160a01b03808a168252861660208201529081018690527f41b99659f6ba0803f444aff29e5bf6e26dd86a3219aff92119d69710a956ba8d9250606001905060405180910390a1505b505050505b61237d81613388565b90506121bd565b505050505050565b603754600090600160a01b900460ff16156123db5760405162461bcd60e51b815260206004820152600f60248201526e149958985cda5b99c81c185d5cd959608a1b60448201526064016105df565b603c54604080516318160ddd60e01b815290516000926001600160a01b0316916318160ddd916004808301926020929190829003018186803b15801561242057600080fd5b505afa158015612434573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124589190612f0f565b905060006124646126c7565b9050816124745791506126c49050565b6042546001600160a01b0316801580159061248e57508282115b156125d057600061249f8484613345565b905060006124bc604354612710846127669092919063ffffffff16565b90508082116125185760405162461bcd60e51b815260206004820152602260248201527f466565206d757374206e6f742062652067726561746572207468616e207969656044820152611b1960f21b60648201526084016105df565b801561258357603c546040516340c10f1960e01b81526001600160a01b03909116906340c10f19906125509086908590600401612f66565b600060405180830381600087803b15801561256a57600080fd5b505af115801561257e573d6000803e3d6000fd5b505050505b604080516001600160a01b0385168152602081018490529081018290527f09516ecf4a8a86e59780a9befc6dee948bc9e60a36e3be68d31ea817ee8d2c809060600160405180910390a150505b603c60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561261e57600080fd5b505afa158015612632573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126569190612f0f565b9250828211156126bf57603c546040516339a7919f60e01b8152600481018490526001600160a01b03909116906339a7919f90602401600060405180830381600087803b1580156126a657600080fd5b505af11580156126ba573d6000803e3d6000fd5b505050505b509150505b90565b60006126d16129ef565b6126d961290d565b6105b091906131c2565b6040516001600160a01b03808516602483015283166044820152606481018290526121a69085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152612a60565b60006106e982846132e7565b60006106e982846131da565b600080612773858561274e565b905061277f818461275a565b95945050505050565b610a368363a9059cbb60e01b8484604051602401612717929190612f66565b6000603b5482101580156127c55750603754600160a01b900460ff16155b156127d9576127d261238c565b90506127e4565b6127e16126c7565b90505b6041541561290957600061287e82603c60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561284057600080fd5b505afa158015612854573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128789190612f0f565b90612b32565b9050604154670de0b6b3a764000082116128a9576128a482670de0b6b3a7640000613345565b6128bb565b6128bb670de0b6b3a764000083613345565b1115610a365760405162461bcd60e51b815260206004820152601e60248201527f4261636b696e6720737570706c79206c6971756964697479206572726f72000060448201526064016105df565b5050565b603454600090815b818110156129ea57600060348281548110612932576129326133ec565b60009182526020822001546040516370a0823160e01b81523060048201526001600160a01b03909116925082906370a082319060240160206040518083038186803b15801561298057600080fd5b505afa158015612994573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129b89190612f0f565b905080156129d7576129ca81836115aa565b6129d490866131c2565b94505b5050806129e390613388565b9050612915565b505090565b603654600090815b818110156129ea57612a2f60368281548110612a1557612a156133ec565b6000918252602090912001546001600160a01b0316612b5b565b612a3990846131c2565b9250612a4481613388565b90506129f7565b60006106e98383670de0b6b3a7640000612766565b6000612ab5826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316612cc09092919063ffffffff16565b805190915015610a365780806020019051810190612ad39190612ed4565b610a365760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016105df565b600080612b4784670de0b6b3a764000061274e565b9050612b53818461275a565b949350505050565b6034546000908290825b81811015611c8057600060348281548110612b8257612b826133ec565b60009182526020909120015460405163551c457b60e11b81526001600160a01b039182166004820181905292509085169063aa388af69060240160206040518083038186803b158015612bd457600080fd5b505afa158015612be8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c0c9190612ed4565b15612caf57604051632fa8a91360e11b81526001600160a01b03828116600483015260009190861690635f5152269060240160206040518083038186803b158015612c5657600080fd5b505afa158015612c6a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c8e9190612f0f565b90508015612cad57612ca081836115aa565b612caa90876131c2565b95505b505b50612cb981613388565b9050612b65565b6060612b53848460008585843b612d195760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016105df565b600080866001600160a01b03168587604051612d359190612f4a565b60006040518083038185875af1925050503d8060008114612d72576040519150601f19603f3d011682016040523d82523d6000602084013e612d77565b606091505b5091509150612d87828286612d92565b979650505050505050565b60608315612da15750816106e9565b825115612db15782518084602001fd5b8160405162461bcd60e51b81526004016105df9190613004565b828054828255906000526020600020908101928215612e20579160200282015b82811115612e2057825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190612deb565b50611cc79291505b80821115611cc75760008155600101612e28565b80356001600160a01b038116811461154357600080fd5b600060208284031215612e6557600080fd5b6106e982612e3c565b60008060408385031215612e8157600080fd5b612e8a83612e3c565b9150612e9860208401612e3c565b90509250929050565b600080600060608486031215612eb657600080fd5b612ebf84612e3c565b95602085013595506040909401359392505050565b600060208284031215612ee657600080fd5b815180151581146106e957600080fd5b600060208284031215612f0857600080fd5b5035919050565b600060208284031215612f2157600080fd5b5051919050565b60008060408385031215612f3b57600080fd5b50508035926020909101359150565b60008251612f5c81846020870161335c565b9190910192915050565b6001600160a01b03929092168252602082015260400190565b6020808252825182820181905260009190848201906040850190845b81811015612fc05783516001600160a01b031683529284019291840191600101612f9b565b50909695505050505050565b6020808252825182820181905260009190848201906040850190845b81811015612fc057835183529284019291840191600101612fe8565b602081526000825180602084015261302381604085016020870161335c565b601f01601f19169190910160400192915050565b60208082526024908201527f43616c6c6572206973206e6f7420746865204f555344206d65746120737472616040820152637465677960e01b606082015260800190565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b6020808252600f908201526e082dadeeadce840e8dede40d0d2ced608b1b604082015260600190565b6020808252600e908201526d10d85c1a5d185b081c185d5cd95960921b604082015260600190565b6020808252600e908201526d1499595b9d1c985b9d0818d85b1b60921b604082015260600190565b815115158152602082015160808201906002811061315957634e487b7160e01b600052602160045260246000fd5b8060208401525060ff604084015116604083015261ffff606084015116606083015292915050565b600080821280156001600160ff1b03849003851316156131a3576131a36133c0565b600160ff1b83900384128116156131bc576131bc6133c0565b50500190565b600082198211156131d5576131d56133c0565b500190565b6000826131f757634e487b7160e01b600052601260045260246000fd5b500490565b600181815b8085111561323757816000190482111561321d5761321d6133c0565b8085161561322a57918102915b93841c9390800290613201565b509250929050565b60006106e9838360008261325557506001610b15565b8161326257506000610b15565b816001811461327857600281146132825761329e565b6001915050610b15565b60ff841115613293576132936133c0565b50506001821b610b15565b5060208310610133831016604e8410600b84101617156132c1575081810a610b15565b6132cb83836131fc565b80600019048211156132df576132df6133c0565b029392505050565b6000816000190483118215151615613301576133016133c0565b500290565b60008083128015600160ff1b850184121615613324576133246133c0565b6001600160ff1b038401831381161561333f5761333f6133c0565b50500390565b600082821015613357576133576133c0565b500390565b60005b8381101561337757818101518382015260200161335f565b838111156121a65750506000910152565b600060001982141561339c5761339c6133c0565b5060010190565b6000600160ff1b8214156133b9576133b96133c0565b5060000390565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fdfe53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac45357bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa26469706673582212204e8e456474cb6e24f080768f1c492c792431f05e2e92233405d5b9337a2458fb64736f6c634300080700337bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a", - "deployedBytecode": "0x608060405234801561001057600080fd5b506004361061025e5760003560e01c806367bd7ba311610146578063ab80dafb116100c3578063c7af335211610087578063c7af335214610545578063d38bfff41461054d578063d4c3eea014610560578063e45cc9f014610568578063e6cc543214610571578063fc0cfeee146105855761025e565b8063ab80dafb14610507578063abaa99161461051a578063af14052c14610522578063b888879e1461052a578063c3b288641461053d5761025e565b80638e510b521161010a5780638e510b52146104985780639be918e6146104a15780639fa1826e146104cd578063a0aead4d146104d6578063a403e4d5146104de5761025e565b806367bd7ba3146104295780636ec3ab67146104495780637136a7a6146104695780637a2202f31461047c5780637cbc2373146104855761025e565b806344c54707116101df57806354c6d858116101a357806354c6d858146103cc578063570d8e1d146103d55780635b60f9fc146103e85780635d36b190146103fb5780635f515226146104035780636217f3ea146104165761025e565b806344c5470714610371578063485cc9551461037957806349c1d54d1461038c57806352d38e5d1461039f57806353ca9f24146103a85761025e565b8063207134b011610226578063207134b0146103115780632acada4d1461031a57806331e19cfa1461032f5780633b8fe28d146103375780633fc8cef31461034a5761025e565b806309f6442c146102a45780630c340a24146102c0578063156e29f6146102e057806318ce56bd146102f55780631edfe3da14610308575b7fa2bd3d3cf188a41358c8b401076eb59066b09dec5775650c0de4c55187d17bd9366000803760008036600084545af43d6000803e80801561029f573d6000f35b3d6000fd5b6102ad60385481565b6040519081526020015b60405180910390f35b6102c8610598565b6040516001600160a01b0390911681526020016102b7565b6102f36102ee366004612ea1565b6105b5565b005b6045546102c8906001600160a01b031681565b6102ad60395481565b6102ad60435481565b610322610633565b6040516102b79190612f7f565b6036546102ad565b6102ad610345366004612e53565b610695565b6102c87f000000000000000000000000000000000000000000000000000000000000000081565b6102f36106f0565b6102f3610387366004612e6e565b610839565b6042546102c8906001600160a01b031681565b6102ad603b5481565b6037546103bc90600160a01b900460ff1681565b60405190151581526020016102b7565b6102ad607b5481565b603f546102c8906001600160a01b031681565b6102ad6103f6366004612e53565b610a3b565b6102f3610a64565b6102ad610411366004612e53565b610b0a565b6102f3610424366004612ef6565b610b1b565b61043c610437366004612ef6565b610cb2565b6040516102b79190612fcc565b61045c610457366004612e53565b610cbd565b6040516102b7919061312b565b6102f3610477366004612ef6565b610d63565b6102ad60475481565b6102f3610493366004612f28565b610e4e565b6102ad60415481565b6103bc6104af366004612e53565b6001600160a01b031660009081526033602052604090205460ff1690565b6102ad603a5481565b6034546102ad565b6102c86104ec366004612e53565b6040602081905260009182529020546001600160a01b031681565b6102f3610515366004612ef6565b610ec1565b6102f3611038565b6102f36110a7565b6037546102c8906001600160a01b031681565b6103226110ed565b6103bc61114d565b6102f361055b366004612e53565b61117e565b6102ad611222565b6102ad60465481565b6037546103bc90600160a81b900460ff1681565b6102f3610593366004612e53565b61122c565b60006105b06000805160206134398339815191525490565b905090565b603754600160a81b900460ff16156105e85760405162461bcd60e51b81526004016105df906130db565b60405180910390fd5b6000805160206134198339815191528054600281141561061a5760405162461bcd60e51b81526004016105df90613103565b600282556106298585856112ce565b5060019055505050565b6060603480548060200260200160405190810160405280929190818152602001828054801561068b57602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161066d575b5050505050905090565b6000806106be6106b86106a7856114de565b670de0b6b3a7640000906012611548565b846115aa565b9050670de0b6b3a7640000816106d5856001611706565b6106df91906132e7565b6106e991906131da565b9392505050565b6106f861114d565b6107145760405162461bcd60e51b81526004016105df9061307b565b60345460005b81811015610794577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166034828154811061075f5761075f6133ec565b6000918252602090912001546001600160a01b0316141561078457607b819055610794565b61078d81613388565b905061071a565b507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166034607b54815481106107d4576107d46133ec565b6000918252602090912001546001600160a01b0316146108365760405162461bcd60e51b815260206004820152601860248201527f496e76616c6964205745544820417373657420496e646578000000000000000060448201526064016105df565b50565b61084161114d565b61085d5760405162461bcd60e51b81526004016105df9061307b565b600054610100900460ff1680610876575060005460ff16155b6108d95760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016105df565b600054610100900460ff161580156108fb576000805461ffff19166101011790555b6001600160a01b0383166109515760405162461bcd60e51b815260206004820152601d60248201527f507269636550726f76696465722061646472657373206973207a65726f00000060448201526064016105df565b6001600160a01b0382166109a05760405162461bcd60e51b81526020600482015260166024820152756f546f6b656e2061646472657373206973207a65726f60501b60448201526064016105df565b603c80546001600160a01b038481166001600160a01b031990921691909117909155603780546001600160b01b03191691851691909117600160a81b17905560006038819055603981905569054b40b1f852bda00000603a55683635c9adc5dea00000603b556040805191825260208201908190529051610a2391603691612dcb565b508015610a36576000805461ff00191690555b505050565b600080610a4d6106b86106a7856114de565b9050670de0b6b3a7640000816106d5856000611706565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b031614610aff5760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b60648201526084016105df565b610b08336119f8565b565b6000610b1582611ab9565b92915050565b603754600160a81b900460ff1615610b455760405162461bcd60e51b81526004016105df906130db565b6045546001600160a01b03163314610b6f5760405162461bcd60e51b81526004016105df90613037565b6001600160ff1b038110610b955760405162461bcd60e51b81526004016105df906130b2565b7f222838db2794d11532d940e8dec38ae307ed0b63cd97c233322e221f998767a63382604051610bc6929190612f66565b60405180910390a18060466000828254610be09190613306565b9091555050604754604654610bf490611c88565b10610c4b5760405162461bcd60e51b815260206004820152602160248201527f417474656d7074696e6720746f206275726e20746f6f206d756368204f5553446044820152601760f91b60648201526084016105df565b603c54604051632770a7eb60e21b81526001600160a01b0390911690639dc29fac90610c7d9033908590600401612f66565b600060405180830381600087803b158015610c9757600080fd5b505af1158015610cab573d6000803e3d6000fd5b5050505050565b6060610b1582611ccb565b604080516080808201835260008083526020808401829052838501829052606084018290526001600160a01b038616825260338152908490208451928301909452835460ff808216151584529394929391840191610100909104166001811115610d2957610d296133d6565b6001811115610d3a57610d3a6133d6565b8152905462010000810460ff1660208301526301000000900461ffff1660409091015292915050565b603754600160a81b900460ff1615610d8d5760405162461bcd60e51b81526004016105df906130db565b60008051602061341983398151915280546002811415610dbf5760405162461bcd60e51b81526004016105df90613103565b60028255603c546040516370a0823160e01b8152336004820152610e46916001600160a01b0316906370a082319060240160206040518083038186803b158015610e0857600080fd5b505afa158015610e1c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e409190612f0f565b84611e0c565b506001905550565b603754600160a81b900460ff1615610e785760405162461bcd60e51b81526004016105df906130db565b60008051602061341983398151915280546002811415610eaa5760405162461bcd60e51b81526004016105df90613103565b60028255610eb88484611e0c565b50600190555050565b603754600160a81b900460ff1615610eeb5760405162461bcd60e51b81526004016105df906130db565b6045546001600160a01b03163314610f155760405162461bcd60e51b81526004016105df90613037565b6001600160ff1b038110610f3b5760405162461bcd60e51b81526004016105df906130b2565b7f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d41213968853382604051610f6c929190612f66565b60405180910390a18060466000828254610f869190613181565b9091555050604754604654610f9a90611c88565b106110065760405162461bcd60e51b815260206004820152603660248201527f4d696e746564206f75736420737572706173736564206e65744f7573644d696e6044820152753a2337b929ba3930ba32b3bcaa343932b9b437b6321760511b60648201526084016105df565b603c546040516340c10f1960e01b81526001600160a01b03909116906340c10f1990610c7d9033908590600401612f66565b603754600160a81b900460ff16156110625760405162461bcd60e51b81526004016105df906130db565b600080516020613419833981519152805460028114156110945760405162461bcd60e51b81526004016105df90613103565b600282556110a0612118565b5060019055565b600080516020613419833981519152805460028114156110d95760405162461bcd60e51b81526004016105df90613103565b600282556110e561238c565b505060019055565b6060603680548060200260200160405190810160405280929190818152602001828054801561068b576020028201919060005260206000209081546001600160a01b0316815260019091019060200180831161066d575050505050905090565b60006111656000805160206134398339815191525490565b6001600160a01b0316336001600160a01b031614905090565b61118661114d565b6111a25760405162461bcd60e51b81526004016105df9061307b565b6111ca817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b03166111ea6000805160206134398339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b60006105b06126c7565b61123461114d565b6112505760405162461bcd60e51b81526004016105df9061307b565b803b6112aa5760405162461bcd60e51b8152602060048201526024808201527f6e657720696d706c656d656e746174696f6e206973206e6f74206120636f6e746044820152631c9858dd60e21b60648201526084016105df565b7fa2bd3d3cf188a41358c8b401076eb59066b09dec5775650c0de4c55187d17bd955565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316836001600160a01b03161461134f5760405162461bcd60e51b815260206004820152601d60248201527f556e737570706f7274656420617373657420666f72206d696e74696e6700000060448201526064016105df565b6000821161139f5760405162461bcd60e51b815260206004820152601d60248201527f416d6f756e74206d7573742062652067726561746572207468616e203000000060448201526064016105df565b808210156113ef5760405162461bcd60e51b815260206004820152601e60248201527f4d696e7420616d6f756e74206c6f776572207468616e206d696e696d756d000060448201526064016105df565b7f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d41213968853383604051611420929190612f66565b60405180910390a1603754600160a01b900460ff161580156114445750603b548210155b156114535761145161238c565b505b603c546040516340c10f1960e01b81526001600160a01b03909116906340c10f19906114859033908690600401612f66565b600060405180830381600087803b15801561149f57600080fd5b505af11580156114b3573d6000803e3d6000fd5b506114cd925050506001600160a01b0384163330856126e3565b603a548210610a3657610a36612118565b6001600160a01b03811660009081526033602052604090205462010000900460ff16806115435760405162461bcd60e51b8152602060048201526013602482015272111958da5b585b1cc81b9bdd0818d858da1959606a1b60448201526064016105df565b919050565b6000818311156115785761157161155f8385613345565b61156a90600a61323f565b859061274e565b93506115a2565b818310156115a25761159f61158d8484613345565b61159890600a61323f565b859061275a565b93505b509192915050565b6001600160a01b038116600090815260336020526040812054610100900460ff16818160018111156115de576115de6133d6565b1415611602576115fa60126115f2856114de565b869190611548565b915050610b15565b6001816001811115611616576116166133d6565b14156116b7576000836001600160a01b031663e6aa216c6040518163ffffffff1660e01b815260040160206040518083038186803b15801561165757600080fd5b505afa15801561166b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061168f9190612f0f565b9050670de0b6b3a76400006116a482876132e7565b6116ae91906131da565b92505050610b15565b60405162461bcd60e51b815260206004820152601b60248201527f556e737570706f7274656420636f6e76657273696f6e2074797065000000000060448201526064016105df565b5092915050565b6001600160a01b038281166000818152603360205260408082205460375491516315d5220f60e31b81526004810194909452919361010090920460ff169291169063aea910789060240160206040518083038186803b15801561176857600080fd5b505afa15801561177c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117a09190612f0f565b915060018160018111156117b6576117b66133d6565b1415611856576000846001600160a01b031663e6aa216c6040518163ffffffff1660e01b815260040160206040518083038186803b1580156117f757600080fd5b505afa15801561180b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061182f9190612f0f565b90508061184484670de0b6b3a76400006132e7565b61184e91906131da565b9250506118b7565b600081600181111561186a5761186a6133d6565b146118b75760405162461bcd60e51b815260206004820152601b60248201527f556e737570706f7274656420636f6e76657273696f6e2074797065000000000060448201526064016105df565b67120a871cc002000082111561190f5760405162461bcd60e51b815260206004820152601860248201527f5661756c743a2050726963652065786365656473206d6178000000000000000060448201526064016105df565b6709b6e64a8ec600008210156119605760405162461bcd60e51b81526020600482015260166024820152752b30bab63a1d10283934b1b2903ab73232b91036b4b760511b60448201526064016105df565b82156119d757670de0b6b3a764000082111561198257670de0b6b3a764000091505b670dd99bb65dd700008210156119d25760405162461bcd60e51b815260206004820152601560248201527441737365742070726963652062656c6f772070656760581b60448201526064016105df565b6116ff565b670de0b6b3a76400008210156116ff5750670de0b6b3a76400009392505050565b6001600160a01b038116611a4e5760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f72206973206164647265737328302900000000000060448201526064016105df565b806001600160a01b0316611a6e6000805160206134398339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a36108368160008051602061343983398151915255565b6040516370a0823160e01b815230600482015260009082906001600160a01b038216906370a082319060240160206040518083038186803b158015611afd57600080fd5b505afa158015611b11573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b359190612f0f565b60365490925060005b81811015611c8057600060368281548110611b5b57611b5b6133ec565b60009182526020909120015460405163551c457b60e11b81526001600160a01b0388811660048301529091169150819063aa388af69060240160206040518083038186803b158015611bac57600080fd5b505afa158015611bc0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611be49190612ed4565b15611c6f57604051632fa8a91360e11b81526001600160a01b038781166004830152821690635f5152269060240160206040518083038186803b158015611c2a57600080fd5b505afa158015611c3e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c629190612f0f565b611c6c90866131c2565b94505b50611c7981613388565b9050611b3e565b505050919050565b60006001600160ff1b038212611cb05760405162461bcd60e51b81526004016105df906130b2565b6000821215611cc757611cc2826133a3565b610b15565b5090565b60385460609015611cfa57603854600090611cea908490612710612766565b9050611cf68184613345565b9250505b6000607b5490507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031660348281548110611d3e57611d3e6133ec565b6000918252602090912001546001600160a01b031614611da05760405162461bcd60e51b815260206004820152601b60248201527f5745544820417373657420696e646578206e6f7420636163686564000000000060448201526064016105df565b60345467ffffffffffffffff811115611dbb57611dbb613402565b604051908082528060200260200182016040528015611de4578160200160208202803683370190505b50915082828281518110611dfa57611dfa6133ec565b60200260200101818152505050919050565b7f222838db2794d11532d940e8dec38ae307ed0b63cd97c233322e221f998767a63383604051611e3d929190612f66565b60405180910390a181611e4e575050565b6000611e5983611ccb565b607b5481518110611e6c57611e6c6133ec565b6020026020010151905081811015611ec65760405162461bcd60e51b815260206004820181905260248201527f52656465656d20616d6f756e74206c6f776572207468616e206d696e696d756d60448201526064016105df565b6040516370a0823160e01b815230600482015281907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b158015611f2757600080fd5b505afa158015611f3b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f5f9190612f0f565b10611f9d57611f986001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163383612788565b6120ab565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660009081526040602081905290205416801561206f57604051636ce5768960e11b81523360048201526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660248301526044820184905282919082169063d9caed1290606401600060405180830381600087803b15801561205157600080fd5b505af1158015612065573d6000803e3d6000fd5b50505050506120a9565b60405162461bcd60e51b815260206004820152600f60248201526e2634b8bab4b234ba3c9032b93937b960891b60448201526064016105df565b505b603c54604051632770a7eb60e21b81526001600160a01b0390911690639dc29fac906120dd9033908790600401612f66565b600060405180830381600087803b1580156120f757600080fd5b505af115801561210b573d6000803e3d6000fd5b50505050610a36836127a7565b600061212261290d565b90508061212c5750565b60006121366129ef565b9050600061214482846131c2565b90506000826121695760395461216290670de0b6b3a7640000613345565b90506121ac565b838260395461217891906132e7565b61218291906131da565b905080670de0b6b3a764000011156121a65761216281670de0b6b3a7640000613345565b50505050565b806121b75750505050565b60345460005b81811015612384576000603482815481106121da576121da6133ec565b60009182526020822001546040516370a0823160e01b81523060048201526001600160a01b03909116925082906370a082319060240160206040518083038186803b15801561222857600080fd5b505afa15801561223c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122609190612f0f565b90508061226e575050612374565b600061227a8287612a4b565b6001600160a01b038085166000908152604060208190529020549192501680158015906122a75750600082115b1561236f57806122c16001600160a01b0386168285612788565b6040516311f9fbc960e21b81526001600160a01b038216906347e7ef24906122ef9088908790600401612f66565b600060405180830381600087803b15801561230957600080fd5b505af115801561231d573d6000803e3d6000fd5b5050604080516001600160a01b03808a168252861660208201529081018690527f41b99659f6ba0803f444aff29e5bf6e26dd86a3219aff92119d69710a956ba8d9250606001905060405180910390a1505b505050505b61237d81613388565b90506121bd565b505050505050565b603754600090600160a01b900460ff16156123db5760405162461bcd60e51b815260206004820152600f60248201526e149958985cda5b99c81c185d5cd959608a1b60448201526064016105df565b603c54604080516318160ddd60e01b815290516000926001600160a01b0316916318160ddd916004808301926020929190829003018186803b15801561242057600080fd5b505afa158015612434573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124589190612f0f565b905060006124646126c7565b9050816124745791506126c49050565b6042546001600160a01b0316801580159061248e57508282115b156125d057600061249f8484613345565b905060006124bc604354612710846127669092919063ffffffff16565b90508082116125185760405162461bcd60e51b815260206004820152602260248201527f466565206d757374206e6f742062652067726561746572207468616e207969656044820152611b1960f21b60648201526084016105df565b801561258357603c546040516340c10f1960e01b81526001600160a01b03909116906340c10f19906125509086908590600401612f66565b600060405180830381600087803b15801561256a57600080fd5b505af115801561257e573d6000803e3d6000fd5b505050505b604080516001600160a01b0385168152602081018490529081018290527f09516ecf4a8a86e59780a9befc6dee948bc9e60a36e3be68d31ea817ee8d2c809060600160405180910390a150505b603c60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561261e57600080fd5b505afa158015612632573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126569190612f0f565b9250828211156126bf57603c546040516339a7919f60e01b8152600481018490526001600160a01b03909116906339a7919f90602401600060405180830381600087803b1580156126a657600080fd5b505af11580156126ba573d6000803e3d6000fd5b505050505b509150505b90565b60006126d16129ef565b6126d961290d565b6105b091906131c2565b6040516001600160a01b03808516602483015283166044820152606481018290526121a69085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152612a60565b60006106e982846132e7565b60006106e982846131da565b600080612773858561274e565b905061277f818461275a565b95945050505050565b610a368363a9059cbb60e01b8484604051602401612717929190612f66565b6000603b5482101580156127c55750603754600160a01b900460ff16155b156127d9576127d261238c565b90506127e4565b6127e16126c7565b90505b6041541561290957600061287e82603c60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561284057600080fd5b505afa158015612854573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128789190612f0f565b90612b32565b9050604154670de0b6b3a764000082116128a9576128a482670de0b6b3a7640000613345565b6128bb565b6128bb670de0b6b3a764000083613345565b1115610a365760405162461bcd60e51b815260206004820152601e60248201527f4261636b696e6720737570706c79206c6971756964697479206572726f72000060448201526064016105df565b5050565b603454600090815b818110156129ea57600060348281548110612932576129326133ec565b60009182526020822001546040516370a0823160e01b81523060048201526001600160a01b03909116925082906370a082319060240160206040518083038186803b15801561298057600080fd5b505afa158015612994573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129b89190612f0f565b905080156129d7576129ca81836115aa565b6129d490866131c2565b94505b5050806129e390613388565b9050612915565b505090565b603654600090815b818110156129ea57612a2f60368281548110612a1557612a156133ec565b6000918252602090912001546001600160a01b0316612b5b565b612a3990846131c2565b9250612a4481613388565b90506129f7565b60006106e98383670de0b6b3a7640000612766565b6000612ab5826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316612cc09092919063ffffffff16565b805190915015610a365780806020019051810190612ad39190612ed4565b610a365760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016105df565b600080612b4784670de0b6b3a764000061274e565b9050612b53818461275a565b949350505050565b6034546000908290825b81811015611c8057600060348281548110612b8257612b826133ec565b60009182526020909120015460405163551c457b60e11b81526001600160a01b039182166004820181905292509085169063aa388af69060240160206040518083038186803b158015612bd457600080fd5b505afa158015612be8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c0c9190612ed4565b15612caf57604051632fa8a91360e11b81526001600160a01b03828116600483015260009190861690635f5152269060240160206040518083038186803b158015612c5657600080fd5b505afa158015612c6a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c8e9190612f0f565b90508015612cad57612ca081836115aa565b612caa90876131c2565b95505b505b50612cb981613388565b9050612b65565b6060612b53848460008585843b612d195760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016105df565b600080866001600160a01b03168587604051612d359190612f4a565b60006040518083038185875af1925050503d8060008114612d72576040519150601f19603f3d011682016040523d82523d6000602084013e612d77565b606091505b5091509150612d87828286612d92565b979650505050505050565b60608315612da15750816106e9565b825115612db15782518084602001fd5b8160405162461bcd60e51b81526004016105df9190613004565b828054828255906000526020600020908101928215612e20579160200282015b82811115612e2057825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190612deb565b50611cc79291505b80821115611cc75760008155600101612e28565b80356001600160a01b038116811461154357600080fd5b600060208284031215612e6557600080fd5b6106e982612e3c565b60008060408385031215612e8157600080fd5b612e8a83612e3c565b9150612e9860208401612e3c565b90509250929050565b600080600060608486031215612eb657600080fd5b612ebf84612e3c565b95602085013595506040909401359392505050565b600060208284031215612ee657600080fd5b815180151581146106e957600080fd5b600060208284031215612f0857600080fd5b5035919050565b600060208284031215612f2157600080fd5b5051919050565b60008060408385031215612f3b57600080fd5b50508035926020909101359150565b60008251612f5c81846020870161335c565b9190910192915050565b6001600160a01b03929092168252602082015260400190565b6020808252825182820181905260009190848201906040850190845b81811015612fc05783516001600160a01b031683529284019291840191600101612f9b565b50909695505050505050565b6020808252825182820181905260009190848201906040850190845b81811015612fc057835183529284019291840191600101612fe8565b602081526000825180602084015261302381604085016020870161335c565b601f01601f19169190910160400192915050565b60208082526024908201527f43616c6c6572206973206e6f7420746865204f555344206d65746120737472616040820152637465677960e01b606082015260800190565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b6020808252600f908201526e082dadeeadce840e8dede40d0d2ced608b1b604082015260600190565b6020808252600e908201526d10d85c1a5d185b081c185d5cd95960921b604082015260600190565b6020808252600e908201526d1499595b9d1c985b9d0818d85b1b60921b604082015260600190565b815115158152602082015160808201906002811061315957634e487b7160e01b600052602160045260246000fd5b8060208401525060ff604084015116604083015261ffff606084015116606083015292915050565b600080821280156001600160ff1b03849003851316156131a3576131a36133c0565b600160ff1b83900384128116156131bc576131bc6133c0565b50500190565b600082198211156131d5576131d56133c0565b500190565b6000826131f757634e487b7160e01b600052601260045260246000fd5b500490565b600181815b8085111561323757816000190482111561321d5761321d6133c0565b8085161561322a57918102915b93841c9390800290613201565b509250929050565b60006106e9838360008261325557506001610b15565b8161326257506000610b15565b816001811461327857600281146132825761329e565b6001915050610b15565b60ff841115613293576132936133c0565b50506001821b610b15565b5060208310610133831016604e8410600b84101617156132c1575081810a610b15565b6132cb83836131fc565b80600019048211156132df576132df6133c0565b029392505050565b6000816000190483118215151615613301576133016133c0565b500290565b60008083128015600160ff1b850184121615613324576133246133c0565b6001600160ff1b038401831381161561333f5761333f6133c0565b50500390565b600082821015613357576133576133c0565b500390565b60005b8381101561337757818101518382015260200161335f565b838111156121a65750506000910152565b600060001982141561339c5761339c6133c0565b5060010190565b6000600160ff1b8214156133b9576133b96133c0565b5060000390565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fdfe53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac45357bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa26469706673582212204e8e456474cb6e24f080768f1c492c792431f05e2e92233405d5b9337a2458fb64736f6c63430008070033", + "numDeployments": 2, + "solcInputHash": "9b811e7a632431f9f724307daee2b897", + "metadata": "{\"compiler\":{\"version\":\"0.8.7+commit.e28d00a7\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_weth\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_threshold\",\"type\":\"uint256\"}],\"name\":\"AllocateThresholdUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_strategy\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"AssetAllocated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_strategy\",\"type\":\"address\"}],\"name\":\"AssetDefaultStrategyUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"}],\"name\":\"AssetRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"}],\"name\":\"AssetSupported\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"CapitalPaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"CapitalUnpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_dripper\",\"type\":\"address\"}],\"name\":\"DripperChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousGovernor\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newGovernor\",\"type\":\"address\"}],\"name\":\"GovernorshipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"maxSupplyDiff\",\"type\":\"uint256\"}],\"name\":\"MaxSupplyDiffChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"Mint\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_threshold\",\"type\":\"uint256\"}],\"name\":\"NetOusdMintForStrategyThresholdChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_ousdMetaStrategy\",\"type\":\"address\"}],\"name\":\"OusdMetaStrategyUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousGovernor\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newGovernor\",\"type\":\"address\"}],\"name\":\"PendingGovernorshipTransfer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_priceProvider\",\"type\":\"address\"}],\"name\":\"PriceProviderUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"RebasePaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_threshold\",\"type\":\"uint256\"}],\"name\":\"RebaseThresholdUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"RebaseUnpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"Redeem\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_redeemFeeBps\",\"type\":\"uint256\"}],\"name\":\"RedeemFeeUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"StrategistUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"}],\"name\":\"StrategyApproved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"}],\"name\":\"StrategyRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_basis\",\"type\":\"uint256\"}],\"name\":\"SwapAllowedUndervalueChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_basis\",\"type\":\"uint256\"}],\"name\":\"SwapSlippageChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_fromAsset\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_toAsset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_fromAssetAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_toAssetAmount\",\"type\":\"uint256\"}],\"name\":\"Swapped\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"SwapperChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"}],\"name\":\"TrusteeAddressChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_basis\",\"type\":\"uint256\"}],\"name\":\"TrusteeFeeBpsChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_vaultBuffer\",\"type\":\"uint256\"}],\"name\":\"VaultBufferUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_claimable\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_newClaimable\",\"type\":\"uint256\"}],\"name\":\"WithdrawalClaimable\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_withdrawer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"WithdrawalClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_withdrawer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_queued\",\"type\":\"uint256\"}],\"name\":\"WithdrawalRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_yield\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_fee\",\"type\":\"uint256\"}],\"name\":\"YieldDistribution\",\"type\":\"event\"},{\"stateMutability\":\"nonpayable\",\"type\":\"fallback\"},{\"inputs\":[],\"name\":\"addWithdrawalQueueLiquidity\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"allocate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"assetDefaultStrategies\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"autoAllocateThreshold\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"burnForStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"cacheWETHAssetIndex\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"calculateRedeemOutputs\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"capitalPaused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"}],\"name\":\"checkBalance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"claimGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"}],\"name\":\"claimWithdrawal\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"requestIds\",\"type\":\"uint256[]\"}],\"name\":\"claimWithdrawals\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"amounts\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256\",\"name\":\"totalAmount\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"dripper\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllAssets\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllStrategies\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"}],\"name\":\"getAssetConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"isSupported\",\"type\":\"bool\"},{\"internalType\":\"enum VaultStorage.UnitConversion\",\"name\":\"unitConversion\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"decimals\",\"type\":\"uint8\"},{\"internalType\":\"uint16\",\"name\":\"allowedOracleSlippageBps\",\"type\":\"uint16\"}],\"internalType\":\"struct VaultStorage.Asset\",\"name\":\"config\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAssetCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getStrategyCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"governor\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_priceProvider\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_oToken\",\"type\":\"address\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isGovernor\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"}],\"name\":\"isSupportedAsset\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"maxSupplyDiff\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_minimumOusdAmount\",\"type\":\"uint256\"}],\"name\":\"mint\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"mintForStrategy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"netOusdMintForStrategyThreshold\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"netOusdMintedForStrategy\",\"outputs\":[{\"internalType\":\"int256\",\"name\":\"\",\"type\":\"int256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"ousdMetaStrategy\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"priceProvider\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"asset\",\"type\":\"address\"}],\"name\":\"priceUnitMint\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"price\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"asset\",\"type\":\"address\"}],\"name\":\"priceUnitRedeem\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"price\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rebase\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rebasePaused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rebaseThreshold\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_minimumUnitAmount\",\"type\":\"uint256\"}],\"name\":\"redeem\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_minimumUnitAmount\",\"type\":\"uint256\"}],\"name\":\"redeemAll\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"redeemFeeBps\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"requestWithdrawal\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"queued\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newImpl\",\"type\":\"address\"}],\"name\":\"setAdminImpl\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"strategistAddr\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalValue\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_newGovernor\",\"type\":\"address\"}],\"name\":\"transferGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"trusteeAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"trusteeFeeBps\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"vaultBuffer\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"weth\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"wethAssetIndex\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdrawalQueueMetadata\",\"outputs\":[{\"internalType\":\"uint128\",\"name\":\"queued\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"claimable\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"claimed\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"nextWithdrawalIndex\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"withdrawalRequests\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"withdrawer\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"claimed\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"amount\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"queued\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"author\":\"Origin Protocol Inc\",\"kind\":\"dev\",\"methods\":{\"addWithdrawalQueueLiquidity()\":{\"details\":\"is called from the Native Staking strategy when validator withdrawals are processed. It also called before any WETH is allocated to a strategy.\"},\"burnForStrategy(uint256)\":{\"details\":\"Notice: can't use `nonReentrant` modifier since the `redeem` function could require withdrawal on `ConvexOUSDMetaStrategy` and that one can call `burnForStrategy` while the execution of the `redeem` has not yet completed -> causing a `nonReentrant` collision. Also important to understand is that this is a limitation imposed by the test suite. Production / mainnet contracts should never be configured in a way where mint/redeem functions that are moving funds between the Vault and end user wallets can influence strategies utilizing this function.\",\"params\":{\"_amount\":\"Amount of OUSD to burn\"}},\"cacheWETHAssetIndex()\":{\"details\":\"Caches WETH's index in `allAssets` variable. Reduces gas usage by redeem by caching that.\"},\"checkBalance(address)\":{\"params\":{\"_asset\":\"Address of asset\"},\"returns\":{\"_0\":\"uint256 Balance of asset in decimals of asset\"}},\"claimWithdrawal(uint256)\":{\"params\":{\"requestId\":\"Unique ID for the withdrawal request\"},\"returns\":{\"amount\":\"Amount of WETH transferred to the withdrawer\"}},\"claimWithdrawals(uint256[])\":{\"params\":{\"requestIds\":\"Unique ID of each withdrawal request\"},\"returns\":{\"amounts\":\"Amount of WETH received for each request\"}},\"isSupportedAsset(address)\":{\"params\":{\"_asset\":\"address of the asset\"},\"returns\":{\"_0\":\"true if supported\"}},\"mint(address,uint256,uint256)\":{\"params\":{\"_amount\":\"Amount of the asset being deposited\",\"_asset\":\"Address of the asset being deposited\",\"_minimumOusdAmount\":\"Minimum OTokens to mint\"}},\"mintForStrategy(uint256)\":{\"params\":{\"_amount\":\"Amount of the asset being deposited Notice: can't use `nonReentrant` modifier since the `mint` function can call `allocate`, and that can trigger `ConvexOUSDMetaStrategy` to call this function while the execution of the `mint` has not yet completed -> causing a `nonReentrant` collision. Also important to understand is that this is a limitation imposed by the test suite. Production / mainnet contracts should never be configured in a way where mint/redeem functions that are moving funds between the Vault and end user wallets can influence strategies utilizing this function.\"}},\"priceUnitMint(address)\":{\"params\":{\"asset\":\"address of the asset\"},\"returns\":{\"price\":\"uint256: unit (USD / ETH) price for 1 unit of the asset, in 18 decimal fixed\"}},\"priceUnitRedeem(address)\":{\"params\":{\"asset\":\"Address of the asset\"},\"returns\":{\"price\":\"uint256: unit (USD / ETH) price for 1 unit of the asset, in 18 decimal fixed\"}},\"redeem(uint256,uint256)\":{\"params\":{\"_amount\":\"Amount of OTokens to burn\",\"_minimumUnitAmount\":\"Minimum stablecoin units to receive in return\"}},\"redeemAll(uint256)\":{\"params\":{\"_minimumUnitAmount\":\"Minimum stablecoin units to receive in return\"}},\"requestWithdrawal(uint256)\":{\"params\":{\"_amount\":\"Amount of oTokens to burn. eg OETH\",\"queued\":\"Cumulative total of all WETH queued including already claimed requests. This request can be claimed once the withdrawal queue's claimable amount is greater than or equal this request's queued amount.\",\"requestId\":\"Unique ID for the withdrawal request\"}},\"setAdminImpl(address)\":{\"params\":{\"newImpl\":\"address of the implementation\"}},\"totalValue()\":{\"returns\":{\"value\":\"Total value in USD/ETH (1e18)\"}},\"transferGovernance(address)\":{\"params\":{\"_newGovernor\":\"Address of the new Governor\"}}},\"title\":\"OETH VaultCore Contract\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"addWithdrawalQueueLiquidity()\":{\"notice\":\"Collects harvested rewards from the Dripper as WETH then adds WETH to the withdrawal queue if there is a funding shortfall.\"},\"allocate()\":{\"notice\":\"Allocate unallocated funds on Vault to strategies.*\"},\"assetDefaultStrategies(address)\":{\"notice\":\"Mapping of asset address to the Strategy that they should automatically\"},\"autoAllocateThreshold()\":{\"notice\":\"OToken mints over this amount automatically allocate funds. 18 decimals.\"},\"burnForStrategy(uint256)\":{\"notice\":\"Burn OTokens for Metapool Strategy\"},\"calculateRedeemOutputs(uint256)\":{\"notice\":\"Calculate the outputs for a redeem function, i.e. the mix of coins that will be returned\"},\"capitalPaused()\":{\"notice\":\"pause operations that change the OToken supply. eg mint, redeem, allocate, mint/burn for strategy\"},\"checkBalance(address)\":{\"notice\":\"Get the balance of an asset held in Vault and all strategies.\"},\"claimGovernance()\":{\"notice\":\"Claim Governance of the contract to a new account (`newGovernor`). Can only be called by the new Governor.\"},\"claimWithdrawal(uint256)\":{\"notice\":\"Claim a previously requested withdrawal once it is claimable.\"},\"claimWithdrawals(uint256[])\":{\"notice\":\"Claim a previously requested withdrawals once they are claimable.\"},\"dripper()\":{\"notice\":\"Address of the Dripper contract that streams harvested rewards to the Vault\"},\"getAllAssets()\":{\"notice\":\"Return all vault asset addresses in order\"},\"getAllStrategies()\":{\"notice\":\"Return the array of all strategies\"},\"getAssetConfig(address)\":{\"notice\":\"Gets the vault configuration of a supported asset.\"},\"getAssetCount()\":{\"notice\":\"Return the number of assets supported by the Vault.\"},\"getStrategyCount()\":{\"notice\":\"Return the number of strategies active on the Vault.\"},\"governor()\":{\"notice\":\"Returns the address of the current Governor.\"},\"isGovernor()\":{\"notice\":\"Returns true if the caller is the current Governor.\"},\"isSupportedAsset(address)\":{\"notice\":\"Returns whether the vault supports the asset\"},\"maxSupplyDiff()\":{\"notice\":\"Max difference between total supply and total value of assets. 18 decimals.\"},\"mint(address,uint256,uint256)\":{\"notice\":\"Deposit a supported asset and mint OTokens.\"},\"mintForStrategy(uint256)\":{\"notice\":\"Mint OTokens for a Metapool Strategy\"},\"netOusdMintForStrategyThreshold()\":{\"notice\":\"How much net total OTokens are allowed to be minted by all strategies\"},\"netOusdMintedForStrategy()\":{\"notice\":\"How much OTokens are currently minted by the strategy\"},\"ousdMetaStrategy()\":{\"notice\":\"Metapool strategy that is allowed to mint/burn OTokens without changing collateral\"},\"priceProvider()\":{\"notice\":\"Address of the Oracle price provider contract\"},\"priceUnitMint(address)\":{\"notice\":\"Returns the total price in 18 digit units for a given asset. Never goes above 1, since that is how we price mints.\"},\"priceUnitRedeem(address)\":{\"notice\":\"Returns the total price in 18 digit unit for a given asset. Never goes below 1, since that is how we price redeems\"},\"rebase()\":{\"notice\":\"Calculate the total value of assets held by the Vault and all strategies and update the supply of OTokens.\"},\"rebasePaused()\":{\"notice\":\"pause rebasing if true\"},\"rebaseThreshold()\":{\"notice\":\"OToken mints over this amount automatically rebase. 18 decimals.\"},\"redeem(uint256,uint256)\":{\"notice\":\"Withdraw a supported asset and burn OTokens.\"},\"redeemAll(uint256)\":{\"notice\":\"Withdraw a supported asset and burn all OTokens.\"},\"redeemFeeBps()\":{\"notice\":\"Redemption fee in basis points. eg 50 = 0.5%\"},\"requestWithdrawal(uint256)\":{\"notice\":\"Request an asynchronous withdrawal of the underlying asset. eg WETH\"},\"setAdminImpl(address)\":{\"notice\":\"set the implementation for the admin, this needs to be in a base class else we cannot set it\"},\"strategistAddr()\":{\"notice\":\"Address of the Strategist\"},\"totalValue()\":{\"notice\":\"Determine the total value of assets held by the vault and its strategies.\"},\"transferGovernance(address)\":{\"notice\":\"Transfers Governance of the contract to a new account (`newGovernor`). Can only be called by the current Governor. Must be claimed for this to complete\"},\"trusteeAddress()\":{\"notice\":\"Trustee contract that can collect a percentage of yield\"},\"trusteeFeeBps()\":{\"notice\":\"Amount of yield collected in basis points. eg 2000 = 20%\"},\"vaultBuffer()\":{\"notice\":\"Percentage of assets to keep in Vault to handle (most) withdrawals. 100% = 1e18.\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/vault/OETHVaultCore.sol\":\"OETHVaultCore\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `recipient`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address recipient, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `sender` to `recipient` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address sender,\\n address recipient,\\n uint256 amount\\n ) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0x61437cb513a887a1bbad006e7b1c8b414478427d33de47c5600af3c748f108da\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Address.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize, which returns 0 for contracts in\\n // construction, since the code is only stored at the end of the\\n // constructor execution.\\n\\n uint256 size;\\n assembly {\\n size := extcodesize(account)\\n }\\n return size > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x51b758a8815ecc9596c66c37d56b1d33883a444631a3f916b9fe65cb863ef7c4\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/math/SafeMath.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeMath.sol)\\n\\npragma solidity ^0.8.0;\\n\\n// CAUTION\\n// This version of SafeMath should only be used with Solidity 0.8 or later,\\n// because it relies on the compiler's built in overflow checks.\\n\\n/**\\n * @dev Wrappers over Solidity's arithmetic operations.\\n *\\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\\n * now has built in overflow checking.\\n */\\nlibrary SafeMath {\\n /**\\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n uint256 c = a + b;\\n if (c < a) return (false, 0);\\n return (true, c);\\n }\\n }\\n\\n /**\\n * @dev Returns the substraction of two unsigned integers, with an overflow flag.\\n *\\n * _Available since v3.4._\\n */\\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n if (b > a) return (false, 0);\\n return (true, a - b);\\n }\\n }\\n\\n /**\\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\\n // benefit is lost if 'b' is also tested.\\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\\n if (a == 0) return (true, 0);\\n uint256 c = a * b;\\n if (c / a != b) return (false, 0);\\n return (true, c);\\n }\\n }\\n\\n /**\\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n if (b == 0) return (false, 0);\\n return (true, a / b);\\n }\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n if (b == 0) return (false, 0);\\n return (true, a % b);\\n }\\n }\\n\\n /**\\n * @dev Returns the addition of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `+` operator.\\n *\\n * Requirements:\\n *\\n * - Addition cannot overflow.\\n */\\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a + b;\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting on\\n * overflow (when the result is negative).\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n *\\n * - Subtraction cannot overflow.\\n */\\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a - b;\\n }\\n\\n /**\\n * @dev Returns the multiplication of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `*` operator.\\n *\\n * Requirements:\\n *\\n * - Multiplication cannot overflow.\\n */\\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a * b;\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers, reverting on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator.\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a / b;\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * reverting when dividing by zero.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a % b;\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\\n * overflow (when the result is negative).\\n *\\n * CAUTION: This function is deprecated because it requires allocating memory for the error\\n * message unnecessarily. For custom revert reasons use {trySub}.\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n *\\n * - Subtraction cannot overflow.\\n */\\n function sub(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n unchecked {\\n require(b <= a, errorMessage);\\n return a - b;\\n }\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator. Note: this function uses a\\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\\n * uses an invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function div(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n unchecked {\\n require(b > 0, errorMessage);\\n return a / b;\\n }\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * reverting with custom message when dividing by zero.\\n *\\n * CAUTION: This function is deprecated because it requires allocating memory for the error\\n * message unnecessarily. For custom revert reasons use {tryMod}.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function mod(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n unchecked {\\n require(b > 0, errorMessage);\\n return a % b;\\n }\\n }\\n}\\n\",\"keccak256\":\"0xa2f576be637946f767aa56601c26d717f48a0aff44f82e46f13807eea1009a21\",\"license\":\"MIT\"},\"contracts/governance/Governable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Base for contracts that are managed by the Origin Protocol's Governor.\\n * @dev Copy of the openzeppelin Ownable.sol contract with nomenclature change\\n * from owner to governor and renounce methods removed. Does not use\\n * Context.sol like Ownable.sol does for simplification.\\n * @author Origin Protocol Inc\\n */\\ncontract Governable {\\n // Storage position of the owner and pendingOwner of the contract\\n // keccak256(\\\"OUSD.governor\\\");\\n bytes32 private constant governorPosition =\\n 0x7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a;\\n\\n // keccak256(\\\"OUSD.pending.governor\\\");\\n bytes32 private constant pendingGovernorPosition =\\n 0x44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db;\\n\\n // keccak256(\\\"OUSD.reentry.status\\\");\\n bytes32 private constant reentryStatusPosition =\\n 0x53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac4535;\\n\\n // See OpenZeppelin ReentrancyGuard implementation\\n uint256 constant _NOT_ENTERED = 1;\\n uint256 constant _ENTERED = 2;\\n\\n event PendingGovernorshipTransfer(\\n address indexed previousGovernor,\\n address indexed newGovernor\\n );\\n\\n event GovernorshipTransferred(\\n address indexed previousGovernor,\\n address indexed newGovernor\\n );\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial Governor.\\n */\\n constructor() {\\n _setGovernor(msg.sender);\\n emit GovernorshipTransferred(address(0), _governor());\\n }\\n\\n /**\\n * @notice Returns the address of the current Governor.\\n */\\n function governor() public view returns (address) {\\n return _governor();\\n }\\n\\n /**\\n * @dev Returns the address of the current Governor.\\n */\\n function _governor() internal view returns (address governorOut) {\\n bytes32 position = governorPosition;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n governorOut := sload(position)\\n }\\n }\\n\\n /**\\n * @dev Returns the address of the pending Governor.\\n */\\n function _pendingGovernor()\\n internal\\n view\\n returns (address pendingGovernor)\\n {\\n bytes32 position = pendingGovernorPosition;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n pendingGovernor := sload(position)\\n }\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the Governor.\\n */\\n modifier onlyGovernor() {\\n require(isGovernor(), \\\"Caller is not the Governor\\\");\\n _;\\n }\\n\\n /**\\n * @notice Returns true if the caller is the current Governor.\\n */\\n function isGovernor() public view returns (bool) {\\n return msg.sender == _governor();\\n }\\n\\n function _setGovernor(address newGovernor) internal {\\n bytes32 position = governorPosition;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n sstore(position, newGovernor)\\n }\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a `nonReentrant` function from another `nonReentrant`\\n * function is not supported. It is possible to prevent this from happening\\n * by making the `nonReentrant` function external, and make it call a\\n * `private` function that does the actual work.\\n */\\n modifier nonReentrant() {\\n bytes32 position = reentryStatusPosition;\\n uint256 _reentry_status;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n _reentry_status := sload(position)\\n }\\n\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_reentry_status != _ENTERED, \\\"Reentrant call\\\");\\n\\n // Any calls to nonReentrant after this point will fail\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n sstore(position, _ENTERED)\\n }\\n\\n _;\\n\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n sstore(position, _NOT_ENTERED)\\n }\\n }\\n\\n function _setPendingGovernor(address newGovernor) internal {\\n bytes32 position = pendingGovernorPosition;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n sstore(position, newGovernor)\\n }\\n }\\n\\n /**\\n * @notice Transfers Governance of the contract to a new account (`newGovernor`).\\n * Can only be called by the current Governor. Must be claimed for this to complete\\n * @param _newGovernor Address of the new Governor\\n */\\n function transferGovernance(address _newGovernor) external onlyGovernor {\\n _setPendingGovernor(_newGovernor);\\n emit PendingGovernorshipTransfer(_governor(), _newGovernor);\\n }\\n\\n /**\\n * @notice Claim Governance of the contract to a new account (`newGovernor`).\\n * Can only be called by the new Governor.\\n */\\n function claimGovernance() external {\\n require(\\n msg.sender == _pendingGovernor(),\\n \\\"Only the pending Governor can complete the claim\\\"\\n );\\n _changeGovernor(msg.sender);\\n }\\n\\n /**\\n * @dev Change Governance of the contract to a new account (`newGovernor`).\\n * @param _newGovernor Address of the new Governor\\n */\\n function _changeGovernor(address _newGovernor) internal {\\n require(_newGovernor != address(0), \\\"New Governor is address(0)\\\");\\n emit GovernorshipTransferred(_governor(), _newGovernor);\\n _setGovernor(_newGovernor);\\n }\\n}\\n\",\"keccak256\":\"0xb7133d6ce7a9e673ff79fcedb3fd41ae6e58e251f94915bb65731abe524270b4\",\"license\":\"MIT\"},\"contracts/interfaces/IBasicToken.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IBasicToken {\\n function symbol() external view returns (string memory);\\n\\n function decimals() external view returns (uint8);\\n}\\n\",\"keccak256\":\"0xa562062698aa12572123b36dfd2072f1a39e44fed2031cc19c2c9fd522f96ec2\",\"license\":\"MIT\"},\"contracts/interfaces/IDripper.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IDripper {\\n /// @notice How much funds have dripped out already and are currently\\n // available to be sent to the vault.\\n /// @return The amount that would be sent if a collect was called\\n function availableFunds() external view returns (uint256);\\n\\n /// @notice Collect all dripped funds and send to vault.\\n /// Recalculate new drip rate.\\n function collect() external;\\n\\n /// @notice Collect all dripped funds, send to vault, recalculate new drip\\n /// rate, and rebase mToken.\\n function collectAndRebase() external;\\n}\\n\",\"keccak256\":\"0xa2c33ae21a1331a27a17d550d2dd0774a959e17380bb55d6f6c1797d938b8e50\",\"license\":\"MIT\"},\"contracts/interfaces/IGetExchangeRateToken.sol\":{\"content\":\"pragma solidity ^0.8.0;\\n\\ninterface IGetExchangeRateToken {\\n function getExchangeRate() external view returns (uint256 _exchangeRate);\\n}\\n\",\"keccak256\":\"0x641d5892d570f3f9e256d39a9571e58b02c39368726b01c4cdf7d91f45e349d8\"},\"contracts/interfaces/IOracle.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IOracle {\\n /**\\n * @dev returns the asset price in USD, in 8 decimal digits.\\n *\\n * The version of priceProvider deployed for OETH has 18 decimal digits\\n */\\n function price(address asset) external view returns (uint256);\\n}\\n\",\"keccak256\":\"0x9eabf152389f145c9c23ed71972af73fb1708cbc4b26e524a9ba29a557b7cfe5\",\"license\":\"MIT\"},\"contracts/interfaces/IStrategy.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Platform interface to integrate with lending platform like Compound, AAVE etc.\\n */\\ninterface IStrategy {\\n /**\\n * @dev Deposit the given asset to platform\\n * @param _asset asset address\\n * @param _amount Amount to deposit\\n */\\n function deposit(address _asset, uint256 _amount) external;\\n\\n /**\\n * @dev Deposit the entire balance of all supported assets in the Strategy\\n * to the platform\\n */\\n function depositAll() external;\\n\\n /**\\n * @dev Withdraw given asset from Lending platform\\n */\\n function withdraw(\\n address _recipient,\\n address _asset,\\n uint256 _amount\\n ) external;\\n\\n /**\\n * @dev Liquidate all assets in strategy and return them to Vault.\\n */\\n function withdrawAll() external;\\n\\n /**\\n * @dev Returns the current balance of the given asset.\\n */\\n function checkBalance(address _asset)\\n external\\n view\\n returns (uint256 balance);\\n\\n /**\\n * @dev Returns bool indicating whether strategy supports asset.\\n */\\n function supportsAsset(address _asset) external view returns (bool);\\n\\n /**\\n * @dev Collect reward tokens from the Strategy.\\n */\\n function collectRewardTokens() external;\\n\\n /**\\n * @dev The address array of the reward tokens for the Strategy.\\n */\\n function getRewardTokenAddresses() external view returns (address[] memory);\\n}\\n\",\"keccak256\":\"0xb291e409a9b95527f9ed19cd6bff8eeb9921a21c1f5194a48c0bb9ce6613959a\",\"license\":\"MIT\"},\"contracts/token/OUSD.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title OUSD Token Contract\\n * @dev ERC20 compatible contract for OUSD\\n * @dev Implements an elastic supply\\n * @author Origin Protocol Inc\\n */\\nimport { SafeMath } from \\\"@openzeppelin/contracts/utils/math/SafeMath.sol\\\";\\nimport { Address } from \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\n\\nimport { Initializable } from \\\"../utils/Initializable.sol\\\";\\nimport { InitializableERC20Detailed } from \\\"../utils/InitializableERC20Detailed.sol\\\";\\nimport { StableMath } from \\\"../utils/StableMath.sol\\\";\\nimport { Governable } from \\\"../governance/Governable.sol\\\";\\n\\n/**\\n * NOTE that this is an ERC20 token but the invariant that the sum of\\n * balanceOf(x) for all x is not >= totalSupply(). This is a consequence of the\\n * rebasing design. Any integrations with OUSD should be aware.\\n */\\n\\ncontract OUSD is Initializable, InitializableERC20Detailed, Governable {\\n using SafeMath for uint256;\\n using StableMath for uint256;\\n\\n event TotalSupplyUpdatedHighres(\\n uint256 totalSupply,\\n uint256 rebasingCredits,\\n uint256 rebasingCreditsPerToken\\n );\\n event AccountRebasingEnabled(address account);\\n event AccountRebasingDisabled(address account);\\n\\n enum RebaseOptions {\\n NotSet,\\n OptOut,\\n OptIn\\n }\\n\\n uint256 private constant MAX_SUPPLY = ~uint128(0); // (2^128) - 1\\n uint256 public _totalSupply;\\n mapping(address => mapping(address => uint256)) private _allowances;\\n address public vaultAddress = address(0);\\n mapping(address => uint256) private _creditBalances;\\n uint256 private _rebasingCredits;\\n uint256 private _rebasingCreditsPerToken;\\n // Frozen address/credits are non rebasing (value is held in contracts which\\n // do not receive yield unless they explicitly opt in)\\n uint256 public nonRebasingSupply;\\n mapping(address => uint256) public nonRebasingCreditsPerToken;\\n mapping(address => RebaseOptions) public rebaseState;\\n mapping(address => uint256) public isUpgraded;\\n\\n uint256 private constant RESOLUTION_INCREASE = 1e9;\\n\\n function initialize(\\n string calldata _nameArg,\\n string calldata _symbolArg,\\n address _vaultAddress,\\n uint256 _initialCreditsPerToken\\n ) external onlyGovernor initializer {\\n InitializableERC20Detailed._initialize(_nameArg, _symbolArg, 18);\\n _rebasingCreditsPerToken = _initialCreditsPerToken;\\n vaultAddress = _vaultAddress;\\n }\\n\\n /**\\n * @dev Verifies that the caller is the Vault contract\\n */\\n modifier onlyVault() {\\n require(vaultAddress == msg.sender, \\\"Caller is not the Vault\\\");\\n _;\\n }\\n\\n /**\\n * @return The total supply of OUSD.\\n */\\n function totalSupply() public view override returns (uint256) {\\n return _totalSupply;\\n }\\n\\n /**\\n * @return Low resolution rebasingCreditsPerToken\\n */\\n function rebasingCreditsPerToken() public view returns (uint256) {\\n return _rebasingCreditsPerToken / RESOLUTION_INCREASE;\\n }\\n\\n /**\\n * @return Low resolution total number of rebasing credits\\n */\\n function rebasingCredits() public view returns (uint256) {\\n return _rebasingCredits / RESOLUTION_INCREASE;\\n }\\n\\n /**\\n * @return High resolution rebasingCreditsPerToken\\n */\\n function rebasingCreditsPerTokenHighres() public view returns (uint256) {\\n return _rebasingCreditsPerToken;\\n }\\n\\n /**\\n * @return High resolution total number of rebasing credits\\n */\\n function rebasingCreditsHighres() public view returns (uint256) {\\n return _rebasingCredits;\\n }\\n\\n /**\\n * @dev Gets the balance of the specified address.\\n * @param _account Address to query the balance of.\\n * @return A uint256 representing the amount of base units owned by the\\n * specified address.\\n */\\n function balanceOf(address _account)\\n public\\n view\\n override\\n returns (uint256)\\n {\\n if (_creditBalances[_account] == 0) return 0;\\n return\\n _creditBalances[_account].divPrecisely(_creditsPerToken(_account));\\n }\\n\\n /**\\n * @dev Gets the credits balance of the specified address.\\n * @dev Backwards compatible with old low res credits per token.\\n * @param _account The address to query the balance of.\\n * @return (uint256, uint256) Credit balance and credits per token of the\\n * address\\n */\\n function creditsBalanceOf(address _account)\\n public\\n view\\n returns (uint256, uint256)\\n {\\n uint256 cpt = _creditsPerToken(_account);\\n if (cpt == 1e27) {\\n // For a period before the resolution upgrade, we created all new\\n // contract accounts at high resolution. Since they are not changing\\n // as a result of this upgrade, we will return their true values\\n return (_creditBalances[_account], cpt);\\n } else {\\n return (\\n _creditBalances[_account] / RESOLUTION_INCREASE,\\n cpt / RESOLUTION_INCREASE\\n );\\n }\\n }\\n\\n /**\\n * @dev Gets the credits balance of the specified address.\\n * @param _account The address to query the balance of.\\n * @return (uint256, uint256, bool) Credit balance, credits per token of the\\n * address, and isUpgraded\\n */\\n function creditsBalanceOfHighres(address _account)\\n public\\n view\\n returns (\\n uint256,\\n uint256,\\n bool\\n )\\n {\\n return (\\n _creditBalances[_account],\\n _creditsPerToken(_account),\\n isUpgraded[_account] == 1\\n );\\n }\\n\\n /**\\n * @dev Transfer tokens to a specified address.\\n * @param _to the address to transfer to.\\n * @param _value the amount to be transferred.\\n * @return true on success.\\n */\\n function transfer(address _to, uint256 _value)\\n public\\n override\\n returns (bool)\\n {\\n require(_to != address(0), \\\"Transfer to zero address\\\");\\n require(\\n _value <= balanceOf(msg.sender),\\n \\\"Transfer greater than balance\\\"\\n );\\n\\n _executeTransfer(msg.sender, _to, _value);\\n\\n emit Transfer(msg.sender, _to, _value);\\n\\n return true;\\n }\\n\\n /**\\n * @dev Transfer tokens from one address to another.\\n * @param _from The address you want to send tokens from.\\n * @param _to The address you want to transfer to.\\n * @param _value The amount of tokens to be transferred.\\n */\\n function transferFrom(\\n address _from,\\n address _to,\\n uint256 _value\\n ) public override returns (bool) {\\n require(_to != address(0), \\\"Transfer to zero address\\\");\\n require(_value <= balanceOf(_from), \\\"Transfer greater than balance\\\");\\n\\n _allowances[_from][msg.sender] = _allowances[_from][msg.sender].sub(\\n _value\\n );\\n\\n _executeTransfer(_from, _to, _value);\\n\\n emit Transfer(_from, _to, _value);\\n\\n return true;\\n }\\n\\n /**\\n * @dev Update the count of non rebasing credits in response to a transfer\\n * @param _from The address you want to send tokens from.\\n * @param _to The address you want to transfer to.\\n * @param _value Amount of OUSD to transfer\\n */\\n function _executeTransfer(\\n address _from,\\n address _to,\\n uint256 _value\\n ) internal {\\n bool isNonRebasingTo = _isNonRebasingAccount(_to);\\n bool isNonRebasingFrom = _isNonRebasingAccount(_from);\\n\\n // Credits deducted and credited might be different due to the\\n // differing creditsPerToken used by each account\\n uint256 creditsCredited = _value.mulTruncate(_creditsPerToken(_to));\\n uint256 creditsDeducted = _value.mulTruncate(_creditsPerToken(_from));\\n\\n _creditBalances[_from] = _creditBalances[_from].sub(\\n creditsDeducted,\\n \\\"Transfer amount exceeds balance\\\"\\n );\\n _creditBalances[_to] = _creditBalances[_to].add(creditsCredited);\\n\\n if (isNonRebasingTo && !isNonRebasingFrom) {\\n // Transfer to non-rebasing account from rebasing account, credits\\n // are removed from the non rebasing tally\\n nonRebasingSupply = nonRebasingSupply.add(_value);\\n // Update rebasingCredits by subtracting the deducted amount\\n _rebasingCredits = _rebasingCredits.sub(creditsDeducted);\\n } else if (!isNonRebasingTo && isNonRebasingFrom) {\\n // Transfer to rebasing account from non-rebasing account\\n // Decreasing non-rebasing credits by the amount that was sent\\n nonRebasingSupply = nonRebasingSupply.sub(_value);\\n // Update rebasingCredits by adding the credited amount\\n _rebasingCredits = _rebasingCredits.add(creditsCredited);\\n }\\n }\\n\\n /**\\n * @dev Function to check the amount of tokens that _owner has allowed to\\n * `_spender`.\\n * @param _owner The address which owns the funds.\\n * @param _spender The address which will spend the funds.\\n * @return The number of tokens still available for the _spender.\\n */\\n function allowance(address _owner, address _spender)\\n public\\n view\\n override\\n returns (uint256)\\n {\\n return _allowances[_owner][_spender];\\n }\\n\\n /**\\n * @dev Approve the passed address to spend the specified amount of tokens\\n * on behalf of msg.sender. This method is included for ERC20\\n * compatibility. `increaseAllowance` and `decreaseAllowance` should be\\n * used instead.\\n *\\n * Changing an allowance with this method brings the risk that someone\\n * may transfer both the old and the new allowance - if they are both\\n * greater than zero - if a transfer transaction is mined before the\\n * later approve() call is mined.\\n * @param _spender The address which will spend the funds.\\n * @param _value The amount of tokens to be spent.\\n */\\n function approve(address _spender, uint256 _value)\\n public\\n override\\n returns (bool)\\n {\\n _allowances[msg.sender][_spender] = _value;\\n emit Approval(msg.sender, _spender, _value);\\n return true;\\n }\\n\\n /**\\n * @dev Increase the amount of tokens that an owner has allowed to\\n * `_spender`.\\n * This method should be used instead of approve() to avoid the double\\n * approval vulnerability described above.\\n * @param _spender The address which will spend the funds.\\n * @param _addedValue The amount of tokens to increase the allowance by.\\n */\\n function increaseAllowance(address _spender, uint256 _addedValue)\\n public\\n returns (bool)\\n {\\n _allowances[msg.sender][_spender] = _allowances[msg.sender][_spender]\\n .add(_addedValue);\\n emit Approval(msg.sender, _spender, _allowances[msg.sender][_spender]);\\n return true;\\n }\\n\\n /**\\n * @dev Decrease the amount of tokens that an owner has allowed to\\n `_spender`.\\n * @param _spender The address which will spend the funds.\\n * @param _subtractedValue The amount of tokens to decrease the allowance\\n * by.\\n */\\n function decreaseAllowance(address _spender, uint256 _subtractedValue)\\n public\\n returns (bool)\\n {\\n uint256 oldValue = _allowances[msg.sender][_spender];\\n if (_subtractedValue >= oldValue) {\\n _allowances[msg.sender][_spender] = 0;\\n } else {\\n _allowances[msg.sender][_spender] = oldValue.sub(_subtractedValue);\\n }\\n emit Approval(msg.sender, _spender, _allowances[msg.sender][_spender]);\\n return true;\\n }\\n\\n /**\\n * @dev Mints new tokens, increasing totalSupply.\\n */\\n function mint(address _account, uint256 _amount) external onlyVault {\\n _mint(_account, _amount);\\n }\\n\\n /**\\n * @dev Creates `_amount` tokens and assigns them to `_account`, increasing\\n * the total supply.\\n *\\n * Emits a {Transfer} event with `from` set to the zero address.\\n *\\n * Requirements\\n *\\n * - `to` cannot be the zero address.\\n */\\n function _mint(address _account, uint256 _amount) internal nonReentrant {\\n require(_account != address(0), \\\"Mint to the zero address\\\");\\n\\n bool isNonRebasingAccount = _isNonRebasingAccount(_account);\\n\\n uint256 creditAmount = _amount.mulTruncate(_creditsPerToken(_account));\\n _creditBalances[_account] = _creditBalances[_account].add(creditAmount);\\n\\n // If the account is non rebasing and doesn't have a set creditsPerToken\\n // then set it i.e. this is a mint from a fresh contract\\n if (isNonRebasingAccount) {\\n nonRebasingSupply = nonRebasingSupply.add(_amount);\\n } else {\\n _rebasingCredits = _rebasingCredits.add(creditAmount);\\n }\\n\\n _totalSupply = _totalSupply.add(_amount);\\n\\n require(_totalSupply < MAX_SUPPLY, \\\"Max supply\\\");\\n\\n emit Transfer(address(0), _account, _amount);\\n }\\n\\n /**\\n * @dev Burns tokens, decreasing totalSupply.\\n */\\n function burn(address account, uint256 amount) external onlyVault {\\n _burn(account, amount);\\n }\\n\\n /**\\n * @dev Destroys `_amount` tokens from `_account`, reducing the\\n * total supply.\\n *\\n * Emits a {Transfer} event with `to` set to the zero address.\\n *\\n * Requirements\\n *\\n * - `_account` cannot be the zero address.\\n * - `_account` must have at least `_amount` tokens.\\n */\\n function _burn(address _account, uint256 _amount) internal nonReentrant {\\n require(_account != address(0), \\\"Burn from the zero address\\\");\\n if (_amount == 0) {\\n return;\\n }\\n\\n bool isNonRebasingAccount = _isNonRebasingAccount(_account);\\n uint256 creditAmount = _amount.mulTruncate(_creditsPerToken(_account));\\n uint256 currentCredits = _creditBalances[_account];\\n\\n // Remove the credits, burning rounding errors\\n if (\\n currentCredits == creditAmount || currentCredits - 1 == creditAmount\\n ) {\\n // Handle dust from rounding\\n _creditBalances[_account] = 0;\\n } else if (currentCredits > creditAmount) {\\n _creditBalances[_account] = _creditBalances[_account].sub(\\n creditAmount\\n );\\n } else {\\n revert(\\\"Remove exceeds balance\\\");\\n }\\n\\n // Remove from the credit tallies and non-rebasing supply\\n if (isNonRebasingAccount) {\\n nonRebasingSupply = nonRebasingSupply.sub(_amount);\\n } else {\\n _rebasingCredits = _rebasingCredits.sub(creditAmount);\\n }\\n\\n _totalSupply = _totalSupply.sub(_amount);\\n\\n emit Transfer(_account, address(0), _amount);\\n }\\n\\n /**\\n * @dev Get the credits per token for an account. Returns a fixed amount\\n * if the account is non-rebasing.\\n * @param _account Address of the account.\\n */\\n function _creditsPerToken(address _account)\\n internal\\n view\\n returns (uint256)\\n {\\n if (nonRebasingCreditsPerToken[_account] != 0) {\\n return nonRebasingCreditsPerToken[_account];\\n } else {\\n return _rebasingCreditsPerToken;\\n }\\n }\\n\\n /**\\n * @dev Is an account using rebasing accounting or non-rebasing accounting?\\n * Also, ensure contracts are non-rebasing if they have not opted in.\\n * @param _account Address of the account.\\n */\\n function _isNonRebasingAccount(address _account) internal returns (bool) {\\n bool isContract = Address.isContract(_account);\\n if (isContract && rebaseState[_account] == RebaseOptions.NotSet) {\\n _ensureRebasingMigration(_account);\\n }\\n return nonRebasingCreditsPerToken[_account] > 0;\\n }\\n\\n /**\\n * @dev Ensures internal account for rebasing and non-rebasing credits and\\n * supply is updated following deployment of frozen yield change.\\n */\\n function _ensureRebasingMigration(address _account) internal {\\n if (nonRebasingCreditsPerToken[_account] == 0) {\\n emit AccountRebasingDisabled(_account);\\n if (_creditBalances[_account] == 0) {\\n // Since there is no existing balance, we can directly set to\\n // high resolution, and do not have to do any other bookkeeping\\n nonRebasingCreditsPerToken[_account] = 1e27;\\n } else {\\n // Migrate an existing account:\\n\\n // Set fixed credits per token for this account\\n nonRebasingCreditsPerToken[_account] = _rebasingCreditsPerToken;\\n // Update non rebasing supply\\n nonRebasingSupply = nonRebasingSupply.add(balanceOf(_account));\\n // Update credit tallies\\n _rebasingCredits = _rebasingCredits.sub(\\n _creditBalances[_account]\\n );\\n }\\n }\\n }\\n\\n /**\\n * @notice Enable rebasing for an account.\\n * @dev Add a contract address to the non-rebasing exception list. The\\n * address's balance will be part of rebases and the account will be exposed\\n * to upside and downside.\\n * @param _account Address of the account.\\n */\\n function governanceRebaseOptIn(address _account)\\n public\\n nonReentrant\\n onlyGovernor\\n {\\n _rebaseOptIn(_account);\\n }\\n\\n /**\\n * @dev Add a contract address to the non-rebasing exception list. The\\n * address's balance will be part of rebases and the account will be exposed\\n * to upside and downside.\\n */\\n function rebaseOptIn() public nonReentrant {\\n _rebaseOptIn(msg.sender);\\n }\\n\\n function _rebaseOptIn(address _account) internal {\\n require(_isNonRebasingAccount(_account), \\\"Account has not opted out\\\");\\n\\n // Convert balance into the same amount at the current exchange rate\\n uint256 newCreditBalance = _creditBalances[_account]\\n .mul(_rebasingCreditsPerToken)\\n .div(_creditsPerToken(_account));\\n\\n // Decreasing non rebasing supply\\n nonRebasingSupply = nonRebasingSupply.sub(balanceOf(_account));\\n\\n _creditBalances[_account] = newCreditBalance;\\n\\n // Increase rebasing credits, totalSupply remains unchanged so no\\n // adjustment necessary\\n _rebasingCredits = _rebasingCredits.add(_creditBalances[_account]);\\n\\n rebaseState[_account] = RebaseOptions.OptIn;\\n\\n // Delete any fixed credits per token\\n delete nonRebasingCreditsPerToken[_account];\\n emit AccountRebasingEnabled(_account);\\n }\\n\\n /**\\n * @dev Explicitly mark that an address is non-rebasing.\\n */\\n function rebaseOptOut() public nonReentrant {\\n require(!_isNonRebasingAccount(msg.sender), \\\"Account has not opted in\\\");\\n\\n // Increase non rebasing supply\\n nonRebasingSupply = nonRebasingSupply.add(balanceOf(msg.sender));\\n // Set fixed credits per token\\n nonRebasingCreditsPerToken[msg.sender] = _rebasingCreditsPerToken;\\n\\n // Decrease rebasing credits, total supply remains unchanged so no\\n // adjustment necessary\\n _rebasingCredits = _rebasingCredits.sub(_creditBalances[msg.sender]);\\n\\n // Mark explicitly opted out of rebasing\\n rebaseState[msg.sender] = RebaseOptions.OptOut;\\n emit AccountRebasingDisabled(msg.sender);\\n }\\n\\n /**\\n * @dev Modify the supply without minting new tokens. This uses a change in\\n * the exchange rate between \\\"credits\\\" and OUSD tokens to change balances.\\n * @param _newTotalSupply New total supply of OUSD.\\n */\\n function changeSupply(uint256 _newTotalSupply)\\n external\\n onlyVault\\n nonReentrant\\n {\\n require(_totalSupply > 0, \\\"Cannot increase 0 supply\\\");\\n\\n if (_totalSupply == _newTotalSupply) {\\n emit TotalSupplyUpdatedHighres(\\n _totalSupply,\\n _rebasingCredits,\\n _rebasingCreditsPerToken\\n );\\n return;\\n }\\n\\n _totalSupply = _newTotalSupply > MAX_SUPPLY\\n ? MAX_SUPPLY\\n : _newTotalSupply;\\n\\n _rebasingCreditsPerToken = _rebasingCredits.divPrecisely(\\n _totalSupply.sub(nonRebasingSupply)\\n );\\n\\n require(_rebasingCreditsPerToken > 0, \\\"Invalid change in supply\\\");\\n\\n _totalSupply = _rebasingCredits\\n .divPrecisely(_rebasingCreditsPerToken)\\n .add(nonRebasingSupply);\\n\\n emit TotalSupplyUpdatedHighres(\\n _totalSupply,\\n _rebasingCredits,\\n _rebasingCreditsPerToken\\n );\\n }\\n}\\n\",\"keccak256\":\"0x2dc66b1ba02716d64eb47dd9117fda62650d8b57669e6c351437e0ad29ad5f19\",\"license\":\"MIT\"},\"contracts/utils/Helpers.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport { IBasicToken } from \\\"../interfaces/IBasicToken.sol\\\";\\n\\nlibrary Helpers {\\n /**\\n * @notice Fetch the `symbol()` from an ERC20 token\\n * @dev Grabs the `symbol()` from a contract\\n * @param _token Address of the ERC20 token\\n * @return string Symbol of the ERC20 token\\n */\\n function getSymbol(address _token) internal view returns (string memory) {\\n string memory symbol = IBasicToken(_token).symbol();\\n return symbol;\\n }\\n\\n /**\\n * @notice Fetch the `decimals()` from an ERC20 token\\n * @dev Grabs the `decimals()` from a contract and fails if\\n * the decimal value does not live within a certain range\\n * @param _token Address of the ERC20 token\\n * @return uint256 Decimals of the ERC20 token\\n */\\n function getDecimals(address _token) internal view returns (uint256) {\\n uint256 decimals = IBasicToken(_token).decimals();\\n require(\\n decimals >= 4 && decimals <= 18,\\n \\\"Token must have sufficient decimal places\\\"\\n );\\n\\n return decimals;\\n }\\n}\\n\",\"keccak256\":\"0x108b7a69e0140da0072ca18f90a03a3340574400f81aa6076cd2cccdf13699c2\",\"license\":\"MIT\"},\"contracts/utils/Initializable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Base contract any contracts that need to initialize state after deployment.\\n * @author Origin Protocol Inc\\n */\\nabstract contract Initializable {\\n /**\\n * @dev Indicates that the contract has been initialized.\\n */\\n bool private initialized;\\n\\n /**\\n * @dev Indicates that the contract is in the process of being initialized.\\n */\\n bool private initializing;\\n\\n /**\\n * @dev Modifier to protect an initializer function from being invoked twice.\\n */\\n modifier initializer() {\\n require(\\n initializing || !initialized,\\n \\\"Initializable: contract is already initialized\\\"\\n );\\n\\n bool isTopLevelCall = !initializing;\\n if (isTopLevelCall) {\\n initializing = true;\\n initialized = true;\\n }\\n\\n _;\\n\\n if (isTopLevelCall) {\\n initializing = false;\\n }\\n }\\n\\n uint256[50] private ______gap;\\n}\\n\",\"keccak256\":\"0xaadbcc138114afed4af4f353c2ced2916e6ee14be91434789187f192caf0d786\",\"license\":\"MIT\"},\"contracts/utils/InitializableERC20Detailed.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport { IERC20 } from \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @dev Optional functions from the ERC20 standard.\\n * Converted from openzeppelin/contracts/token/ERC20/ERC20Detailed.sol\\n * @author Origin Protocol Inc\\n */\\nabstract contract InitializableERC20Detailed is IERC20 {\\n // Storage gap to skip storage from prior to OUSD reset\\n uint256[100] private _____gap;\\n\\n string private _name;\\n string private _symbol;\\n uint8 private _decimals;\\n\\n /**\\n * @dev Sets the values for `name`, `symbol`, and `decimals`. All three of\\n * these values are immutable: they can only be set once during\\n * construction.\\n * @notice To avoid variable shadowing appended `Arg` after arguments name.\\n */\\n function _initialize(\\n string memory nameArg,\\n string memory symbolArg,\\n uint8 decimalsArg\\n ) internal {\\n _name = nameArg;\\n _symbol = symbolArg;\\n _decimals = decimalsArg;\\n }\\n\\n /**\\n * @notice Returns the name of the token.\\n */\\n function name() public view returns (string memory) {\\n return _name;\\n }\\n\\n /**\\n * @notice Returns the symbol of the token, usually a shorter version of the\\n * name.\\n */\\n function symbol() public view returns (string memory) {\\n return _symbol;\\n }\\n\\n /**\\n * @notice Returns the number of decimals used to get its user representation.\\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\\n * be displayed to a user as `5,05` (`505 / 10 ** 2`).\\n *\\n * Tokens usually opt for a value of 18, imitating the relationship between\\n * Ether and Wei.\\n *\\n * NOTE: This information is only used for _display_ purposes: it in\\n * no way affects any of the arithmetic of the contract, including\\n * {IERC20-balanceOf} and {IERC20-transfer}.\\n */\\n function decimals() public view returns (uint8) {\\n return _decimals;\\n }\\n}\\n\",\"keccak256\":\"0xe35ac2d813a30d845a3b52bba72588d7e936c2b3f3373d15568c14db46aeed60\",\"license\":\"MIT\"},\"contracts/utils/StableMath.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport { SafeMath } from \\\"@openzeppelin/contracts/utils/math/SafeMath.sol\\\";\\n\\n// Based on StableMath from Stability Labs Pty. Ltd.\\n// https://github.com/mstable/mStable-contracts/blob/master/contracts/shared/StableMath.sol\\n\\nlibrary StableMath {\\n using SafeMath for uint256;\\n\\n /**\\n * @dev Scaling unit for use in specific calculations,\\n * where 1 * 10**18, or 1e18 represents a unit '1'\\n */\\n uint256 private constant FULL_SCALE = 1e18;\\n\\n /***************************************\\n Helpers\\n ****************************************/\\n\\n /**\\n * @dev Adjust the scale of an integer\\n * @param to Decimals to scale to\\n * @param from Decimals to scale from\\n */\\n function scaleBy(\\n uint256 x,\\n uint256 to,\\n uint256 from\\n ) internal pure returns (uint256) {\\n if (to > from) {\\n x = x.mul(10**(to - from));\\n } else if (to < from) {\\n // slither-disable-next-line divide-before-multiply\\n x = x.div(10**(from - to));\\n }\\n return x;\\n }\\n\\n /***************************************\\n Precise Arithmetic\\n ****************************************/\\n\\n /**\\n * @dev Multiplies two precise units, and then truncates by the full scale\\n * @param x Left hand input to multiplication\\n * @param y Right hand input to multiplication\\n * @return Result after multiplying the two inputs and then dividing by the shared\\n * scale unit\\n */\\n function mulTruncate(uint256 x, uint256 y) internal pure returns (uint256) {\\n return mulTruncateScale(x, y, FULL_SCALE);\\n }\\n\\n /**\\n * @dev Multiplies two precise units, and then truncates by the given scale. For example,\\n * when calculating 90% of 10e18, (10e18 * 9e17) / 1e18 = (9e36) / 1e18 = 9e18\\n * @param x Left hand input to multiplication\\n * @param y Right hand input to multiplication\\n * @param scale Scale unit\\n * @return Result after multiplying the two inputs and then dividing by the shared\\n * scale unit\\n */\\n function mulTruncateScale(\\n uint256 x,\\n uint256 y,\\n uint256 scale\\n ) internal pure returns (uint256) {\\n // e.g. assume scale = fullScale\\n // z = 10e18 * 9e17 = 9e36\\n uint256 z = x.mul(y);\\n // return 9e36 / 1e18 = 9e18\\n return z.div(scale);\\n }\\n\\n /**\\n * @dev Multiplies two precise units, and then truncates by the full scale, rounding up the result\\n * @param x Left hand input to multiplication\\n * @param y Right hand input to multiplication\\n * @return Result after multiplying the two inputs and then dividing by the shared\\n * scale unit, rounded up to the closest base unit.\\n */\\n function mulTruncateCeil(uint256 x, uint256 y)\\n internal\\n pure\\n returns (uint256)\\n {\\n // e.g. 8e17 * 17268172638 = 138145381104e17\\n uint256 scaled = x.mul(y);\\n // e.g. 138145381104e17 + 9.99...e17 = 138145381113.99...e17\\n uint256 ceil = scaled.add(FULL_SCALE.sub(1));\\n // e.g. 13814538111.399...e18 / 1e18 = 13814538111\\n return ceil.div(FULL_SCALE);\\n }\\n\\n /**\\n * @dev Precisely divides two units, by first scaling the left hand operand. Useful\\n * for finding percentage weightings, i.e. 8e18/10e18 = 80% (or 8e17)\\n * @param x Left hand input to division\\n * @param y Right hand input to division\\n * @return Result after multiplying the left operand by the scale, and\\n * executing the division on the right hand input.\\n */\\n function divPrecisely(uint256 x, uint256 y)\\n internal\\n pure\\n returns (uint256)\\n {\\n // e.g. 8e18 * 1e18 = 8e36\\n uint256 z = x.mul(FULL_SCALE);\\n // e.g. 8e36 / 10e18 = 8e17\\n return z.div(y);\\n }\\n}\\n\",\"keccak256\":\"0x1eb49f6f79045d9e0a8e1dced8e01d9e559e5fac554dcbb53e43140b601b04e7\",\"license\":\"MIT\"},\"contracts/vault/OETHVaultCore.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport { StableMath } from \\\"../utils/StableMath.sol\\\";\\nimport { VaultCore } from \\\"./VaultCore.sol\\\";\\n\\nimport { SafeERC20 } from \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\nimport { IERC20 } from \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport { IStrategy } from \\\"../interfaces/IStrategy.sol\\\";\\nimport { IDripper } from \\\"../interfaces/IDripper.sol\\\";\\n\\n/**\\n * @title OETH VaultCore Contract\\n * @author Origin Protocol Inc\\n */\\ncontract OETHVaultCore is VaultCore {\\n using SafeERC20 for IERC20;\\n using StableMath for uint256;\\n\\n address public immutable weth;\\n uint256 public wethAssetIndex;\\n\\n constructor(address _weth) {\\n weth = _weth;\\n }\\n\\n /**\\n * @dev Caches WETH's index in `allAssets` variable.\\n * Reduces gas usage by redeem by caching that.\\n */\\n function cacheWETHAssetIndex() external onlyGovernor {\\n uint256 assetCount = allAssets.length;\\n for (uint256 i = 0; i < assetCount; ++i) {\\n if (allAssets[i] == weth) {\\n wethAssetIndex = i;\\n break;\\n }\\n }\\n\\n require(allAssets[wethAssetIndex] == weth, \\\"Invalid WETH Asset Index\\\");\\n }\\n\\n // @inheritdoc VaultCore\\n // slither-disable-start reentrancy-no-eth\\n function _mint(\\n address _asset,\\n uint256 _amount,\\n uint256 _minimumOusdAmount\\n ) internal virtual override {\\n require(_asset == weth, \\\"Unsupported asset for minting\\\");\\n require(_amount > 0, \\\"Amount must be greater than 0\\\");\\n require(\\n _amount >= _minimumOusdAmount,\\n \\\"Mint amount lower than minimum\\\"\\n );\\n\\n emit Mint(msg.sender, _amount);\\n\\n // Rebase must happen before any transfers occur.\\n if (!rebasePaused && _amount >= rebaseThreshold) {\\n // Stream any harvested rewards (WETH) that are available to the Vault\\n IDripper(dripper).collect();\\n\\n _rebase();\\n }\\n\\n // Mint oTokens\\n oUSD.mint(msg.sender, _amount);\\n\\n // Transfer the deposited coins to the vault\\n IERC20(_asset).safeTransferFrom(msg.sender, address(this), _amount);\\n\\n // Give priority to the withdrawal queue for the new WETH liquidity\\n _addWithdrawalQueueLiquidity();\\n\\n // Auto-allocate if necessary\\n if (_amount >= autoAllocateThreshold) {\\n _allocate();\\n }\\n }\\n\\n // slither-disable-end reentrancy-no-eth\\n\\n // @inheritdoc VaultCore\\n function _calculateRedeemOutputs(uint256 _amount)\\n internal\\n view\\n virtual\\n override\\n returns (uint256[] memory outputs)\\n {\\n // Overrides `VaultCore._calculateRedeemOutputs` to redeem with only\\n // WETH instead of LST-mix. Doesn't change the function signature\\n // for backward compatibility\\n\\n // Calculate redeem fee\\n if (redeemFeeBps > 0) {\\n uint256 redeemFee = _amount.mulTruncateScale(redeemFeeBps, 1e4);\\n _amount = _amount - redeemFee;\\n }\\n\\n // Ensure that the WETH index is cached\\n uint256 _wethAssetIndex = wethAssetIndex;\\n require(\\n allAssets[_wethAssetIndex] == weth,\\n \\\"WETH Asset index not cached\\\"\\n );\\n\\n outputs = new uint256[](allAssets.length);\\n outputs[_wethAssetIndex] = _amount;\\n }\\n\\n // @inheritdoc VaultCore\\n function _redeem(uint256 _amount, uint256 _minimumUnitAmount)\\n internal\\n virtual\\n override\\n {\\n // Override `VaultCore._redeem` to simplify it. Gets rid of oracle\\n // usage and looping through all assets for LST-mix redeem. Instead\\n // does a simple WETH-only redeem.\\n emit Redeem(msg.sender, _amount);\\n\\n if (_amount == 0) {\\n return;\\n }\\n\\n // Amount excluding fees\\n uint256 amountMinusFee = _calculateRedeemOutputs(_amount)[\\n wethAssetIndex\\n ];\\n\\n require(\\n amountMinusFee >= _minimumUnitAmount,\\n \\\"Redeem amount lower than minimum\\\"\\n );\\n\\n // If there is any WETH in the Vault available after accounting for the withdrawal queue\\n if (_wethAvailable() >= amountMinusFee) {\\n // Use Vault funds first if sufficient\\n IERC20(weth).safeTransfer(msg.sender, amountMinusFee);\\n } else {\\n address strategyAddr = assetDefaultStrategies[weth];\\n if (strategyAddr != address(0)) {\\n // Nothing in Vault, but something in Strategy, send from there\\n IStrategy strategy = IStrategy(strategyAddr);\\n strategy.withdraw(msg.sender, weth, amountMinusFee);\\n } else {\\n // Cant find funds anywhere\\n revert(\\\"Liquidity error\\\");\\n }\\n }\\n\\n // Burn OETH from user (including fees)\\n oUSD.burn(msg.sender, _amount);\\n\\n _postRedeem(_amount);\\n }\\n\\n /**\\n * @notice Request an asynchronous withdrawal of the underlying asset. eg WETH\\n * @param _amount Amount of oTokens to burn. eg OETH\\n * @param requestId Unique ID for the withdrawal request\\n * @param queued Cumulative total of all WETH queued including already claimed requests.\\n * This request can be claimed once the withdrawal queue's claimable amount\\n * is greater than or equal this request's queued amount.\\n */\\n function requestWithdrawal(uint256 _amount)\\n external\\n whenNotCapitalPaused\\n nonReentrant\\n returns (uint256 requestId, uint256 queued)\\n {\\n // Burn the user's OETH\\n // This also checks the requester has enough OETH to burn\\n oUSD.burn(msg.sender, _amount);\\n\\n requestId = withdrawalQueueMetadata.nextWithdrawalIndex;\\n queued = withdrawalQueueMetadata.queued + _amount;\\n\\n // store the next withdrawal request\\n withdrawalQueueMetadata.nextWithdrawalIndex = uint128(requestId + 1);\\n withdrawalQueueMetadata.queued = uint128(queued);\\n\\n emit WithdrawalRequested(msg.sender, requestId, _amount, queued);\\n\\n withdrawalRequests[requestId] = WithdrawalRequest({\\n withdrawer: msg.sender,\\n claimed: false,\\n amount: uint128(_amount),\\n queued: uint128(queued)\\n });\\n }\\n\\n /**\\n * @notice Claim a previously requested withdrawal once it is claimable.\\n * @param requestId Unique ID for the withdrawal request\\n * @return amount Amount of WETH transferred to the withdrawer\\n */\\n function claimWithdrawal(uint256 requestId)\\n external\\n whenNotCapitalPaused\\n nonReentrant\\n returns (uint256 amount)\\n {\\n amount = _claimWithdrawal(requestId);\\n\\n // transfer WETH from the vault to the withdrawer\\n IERC20(weth).safeTransfer(msg.sender, amount);\\n }\\n\\n /**\\n * @notice Claim a previously requested withdrawals once they are claimable.\\n * @param requestIds Unique ID of each withdrawal request\\n * @return amounts Amount of WETH received for each request\\n */\\n function claimWithdrawals(uint256[] memory requestIds)\\n external\\n whenNotCapitalPaused\\n nonReentrant\\n returns (uint256[] memory amounts, uint256 totalAmount)\\n {\\n amounts = new uint256[](requestIds.length);\\n for (uint256 i = 0; i < requestIds.length; ++i) {\\n amounts[i] = _claimWithdrawal(requestIds[i]);\\n totalAmount += amounts[i];\\n }\\n\\n // transfer all the claimed WETH from the vault to the withdrawer\\n IERC20(weth).safeTransfer(msg.sender, totalAmount);\\n }\\n\\n // slither-disable-start reentrancy-no-eth\\n\\n function _claimWithdrawal(uint256 requestId)\\n internal\\n returns (uint256 amount)\\n {\\n // Check if there's enough liquidity to cover the withdrawal request\\n WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata;\\n WithdrawalRequest memory request = withdrawalRequests[requestId];\\n\\n require(request.claimed == false, \\\"already claimed\\\");\\n require(request.withdrawer == msg.sender, \\\"not requester\\\");\\n\\n // Try and get more liquidity in the withdrawal queue if there is not enough\\n if (request.queued > queue.claimable) {\\n // Stream any harvested rewards (WETH) that are available to the Vault\\n IDripper(dripper).collect();\\n\\n // Add any WETH from the Dripper to the withdrawal queue\\n uint256 addedClaimable = _addWithdrawalQueueLiquidity();\\n\\n // If there still isn't enough liquidity in the queue to claim, revert\\n require(\\n request.queued <= queue.claimable + addedClaimable,\\n \\\"queue pending liquidity\\\"\\n );\\n }\\n\\n // Store the updated claimed amount\\n withdrawalQueueMetadata.claimed = queue.claimed + request.amount;\\n // Store the request as claimed\\n withdrawalRequests[requestId].claimed = true;\\n\\n emit WithdrawalClaimed(msg.sender, requestId, request.amount);\\n\\n return request.amount;\\n }\\n\\n // slither-disable-end reentrancy-no-eth\\n\\n /// @notice Collects harvested rewards from the Dripper as WETH then\\n /// adds WETH to the withdrawal queue if there is a funding shortfall.\\n /// @dev is called from the Native Staking strategy when validator withdrawals are processed.\\n /// It also called before any WETH is allocated to a strategy.\\n function addWithdrawalQueueLiquidity() external {\\n // Stream any harvested rewards (WETH) that are available to the Vault\\n IDripper(dripper).collect();\\n\\n _addWithdrawalQueueLiquidity();\\n }\\n\\n /// @dev Adds WETH to the withdrawal queue if there is a funding shortfall.\\n function _addWithdrawalQueueLiquidity()\\n internal\\n returns (uint256 addedClaimable)\\n {\\n WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata;\\n\\n // Check if the claimable WETH is less than the queued amount\\n uint256 queueShortfall = queue.queued - queue.claimable;\\n\\n // No need to get WETH balance if all the withdrawal requests are claimable\\n if (queueShortfall > 0) {\\n uint256 wethBalance = IERC20(weth).balanceOf(address(this));\\n\\n // Of the claimable withdrawal requests, how much is unclaimed?\\n uint256 unclaimed = queue.claimable - queue.claimed;\\n if (wethBalance > unclaimed) {\\n uint256 unallocatedWeth = wethBalance - unclaimed;\\n\\n // the new claimable amount is the smaller of the queue shortfall or unallocated weth\\n addedClaimable = queueShortfall < unallocatedWeth\\n ? queueShortfall\\n : unallocatedWeth;\\n uint256 newClaimable = queue.claimable + addedClaimable;\\n\\n // Store the new claimable amount back to storage\\n withdrawalQueueMetadata.claimable = uint128(newClaimable);\\n\\n // emit a WithdrawalClaimable event\\n emit WithdrawalClaimable(newClaimable, addedClaimable);\\n }\\n }\\n }\\n\\n /***************************************\\n View Functions\\n ****************************************/\\n\\n function _wethAvailable() internal view returns (uint256 wethAvailable) {\\n WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata;\\n\\n // Check if the claimable WETH is less than the queued amount\\n uint256 queueShortfall = queue.queued - queue.claimable;\\n uint256 wethBalance = IERC20(weth).balanceOf(address(this));\\n // Of the claimable withdrawal requests, how much is unclaimed?\\n uint256 unclaimed = queue.claimable - queue.claimed;\\n\\n if (wethBalance > queueShortfall + unclaimed) {\\n wethAvailable = wethBalance - queueShortfall - unclaimed;\\n }\\n }\\n\\n function _checkBalance(address _asset)\\n internal\\n view\\n override\\n returns (uint256 balance)\\n {\\n balance = super._checkBalance(_asset);\\n\\n if (_asset == weth) {\\n WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata;\\n // Need to remove WETH that is reserved for the withdrawal queue\\n return balance + queue.claimed - queue.queued;\\n }\\n }\\n\\n function _allocate() internal override {\\n // Add any unallocated WETH to the withdrawal queue first\\n _addWithdrawalQueueLiquidity();\\n\\n super._allocate();\\n }\\n\\n function _totalValue() internal view override returns (uint256 value) {\\n value = super._totalValue();\\n\\n // Need to remove WETH that is reserved for the withdrawal queue.\\n // reserved for the withdrawal queue = cumulative queued total - total claimed\\n WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata;\\n value = value + queue.claimed - queue.queued;\\n }\\n}\\n\",\"keccak256\":\"0xe42502bef951bd6f7121f729c03399ec8af2e6c678007974552fe13f65ce4d1d\",\"license\":\"MIT\"},\"contracts/vault/VaultCore.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title OToken VaultCore contract\\n * @notice The Vault contract stores assets. On a deposit, OTokens will be minted\\n and sent to the depositor. On a withdrawal, OTokens will be burned and\\n assets will be sent to the withdrawer. The Vault accepts deposits of\\n interest from yield bearing strategies which will modify the supply\\n of OTokens.\\n * @author Origin Protocol Inc\\n */\\n\\nimport { SafeERC20 } from \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\n\\nimport { StableMath } from \\\"../utils/StableMath.sol\\\";\\nimport { IOracle } from \\\"../interfaces/IOracle.sol\\\";\\nimport { IGetExchangeRateToken } from \\\"../interfaces/IGetExchangeRateToken.sol\\\";\\nimport { IDripper } from \\\"../interfaces/IDripper.sol\\\";\\n\\nimport \\\"./VaultInitializer.sol\\\";\\n\\ncontract VaultCore is VaultInitializer {\\n using SafeERC20 for IERC20;\\n using StableMath for uint256;\\n // max signed int\\n uint256 internal constant MAX_INT = 2**255 - 1;\\n // max un-signed int\\n uint256 internal constant MAX_UINT =\\n 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff;\\n\\n /**\\n * @dev Verifies that the rebasing is not paused.\\n */\\n modifier whenNotRebasePaused() {\\n require(!rebasePaused, \\\"Rebasing paused\\\");\\n _;\\n }\\n\\n /**\\n * @dev Verifies that the deposits are not paused.\\n */\\n modifier whenNotCapitalPaused() {\\n require(!capitalPaused, \\\"Capital paused\\\");\\n _;\\n }\\n\\n modifier onlyOusdMetaStrategy() {\\n require(\\n msg.sender == ousdMetaStrategy,\\n \\\"Caller is not the OUSD meta strategy\\\"\\n );\\n _;\\n }\\n\\n /**\\n * @notice Deposit a supported asset and mint OTokens.\\n * @param _asset Address of the asset being deposited\\n * @param _amount Amount of the asset being deposited\\n * @param _minimumOusdAmount Minimum OTokens to mint\\n */\\n function mint(\\n address _asset,\\n uint256 _amount,\\n uint256 _minimumOusdAmount\\n ) external whenNotCapitalPaused nonReentrant {\\n _mint(_asset, _amount, _minimumOusdAmount);\\n }\\n\\n function _mint(\\n address _asset,\\n uint256 _amount,\\n uint256 _minimumOusdAmount\\n ) internal virtual {\\n require(assets[_asset].isSupported, \\\"Asset is not supported\\\");\\n require(_amount > 0, \\\"Amount must be greater than 0\\\");\\n\\n uint256 units = _toUnits(_amount, _asset);\\n uint256 unitPrice = _toUnitPrice(_asset, true);\\n uint256 priceAdjustedDeposit = (units * unitPrice) / 1e18;\\n\\n if (_minimumOusdAmount > 0) {\\n require(\\n priceAdjustedDeposit >= _minimumOusdAmount,\\n \\\"Mint amount lower than minimum\\\"\\n );\\n }\\n\\n emit Mint(msg.sender, priceAdjustedDeposit);\\n\\n // Rebase must happen before any transfers occur.\\n if (priceAdjustedDeposit >= rebaseThreshold && !rebasePaused) {\\n if (dripper != address(0)) {\\n // Stream any harvested rewards that are available\\n IDripper(dripper).collect();\\n }\\n _rebase();\\n }\\n\\n // Mint matching amount of OTokens\\n oUSD.mint(msg.sender, priceAdjustedDeposit);\\n\\n // Transfer the deposited coins to the vault\\n IERC20 asset = IERC20(_asset);\\n asset.safeTransferFrom(msg.sender, address(this), _amount);\\n\\n if (priceAdjustedDeposit >= autoAllocateThreshold) {\\n _allocate();\\n }\\n }\\n\\n /**\\n * @notice Mint OTokens for a Metapool Strategy\\n * @param _amount Amount of the asset being deposited\\n *\\n * Notice: can't use `nonReentrant` modifier since the `mint` function can\\n * call `allocate`, and that can trigger `ConvexOUSDMetaStrategy` to call this function\\n * while the execution of the `mint` has not yet completed -> causing a `nonReentrant` collision.\\n *\\n * Also important to understand is that this is a limitation imposed by the test suite.\\n * Production / mainnet contracts should never be configured in a way where mint/redeem functions\\n * that are moving funds between the Vault and end user wallets can influence strategies\\n * utilizing this function.\\n */\\n function mintForStrategy(uint256 _amount)\\n external\\n whenNotCapitalPaused\\n onlyOusdMetaStrategy\\n {\\n require(_amount < MAX_INT, \\\"Amount too high\\\");\\n\\n emit Mint(msg.sender, _amount);\\n\\n // safe to cast because of the require check at the beginning of the function\\n netOusdMintedForStrategy += int256(_amount);\\n\\n require(\\n abs(netOusdMintedForStrategy) < netOusdMintForStrategyThreshold,\\n \\\"Minted ousd surpassed netOusdMintForStrategyThreshold.\\\"\\n );\\n\\n // Mint matching amount of OTokens\\n oUSD.mint(msg.sender, _amount);\\n }\\n\\n // In memoriam\\n\\n /**\\n * @notice Withdraw a supported asset and burn OTokens.\\n * @param _amount Amount of OTokens to burn\\n * @param _minimumUnitAmount Minimum stablecoin units to receive in return\\n */\\n function redeem(uint256 _amount, uint256 _minimumUnitAmount)\\n external\\n whenNotCapitalPaused\\n nonReentrant\\n {\\n _redeem(_amount, _minimumUnitAmount);\\n }\\n\\n /**\\n * @notice Withdraw a supported asset and burn OTokens.\\n * @param _amount Amount of OTokens to burn\\n * @param _minimumUnitAmount Minimum stablecoin units to receive in return\\n */\\n function _redeem(uint256 _amount, uint256 _minimumUnitAmount)\\n internal\\n virtual\\n {\\n // Calculate redemption outputs\\n uint256[] memory outputs = _calculateRedeemOutputs(_amount);\\n\\n emit Redeem(msg.sender, _amount);\\n\\n // Send outputs\\n uint256 assetCount = allAssets.length;\\n for (uint256 i = 0; i < assetCount; ++i) {\\n if (outputs[i] == 0) continue;\\n\\n address assetAddr = allAssets[i];\\n\\n if (IERC20(assetAddr).balanceOf(address(this)) >= outputs[i]) {\\n // Use Vault funds first if sufficient\\n IERC20(assetAddr).safeTransfer(msg.sender, outputs[i]);\\n } else {\\n address strategyAddr = assetDefaultStrategies[assetAddr];\\n if (strategyAddr != address(0)) {\\n // Nothing in Vault, but something in Strategy, send from there\\n IStrategy strategy = IStrategy(strategyAddr);\\n strategy.withdraw(msg.sender, assetAddr, outputs[i]);\\n } else {\\n // Cant find funds anywhere\\n revert(\\\"Liquidity error\\\");\\n }\\n }\\n }\\n\\n if (_minimumUnitAmount > 0) {\\n uint256 unitTotal = 0;\\n for (uint256 i = 0; i < outputs.length; ++i) {\\n unitTotal += _toUnits(outputs[i], allAssets[i]);\\n }\\n require(\\n unitTotal >= _minimumUnitAmount,\\n \\\"Redeem amount lower than minimum\\\"\\n );\\n }\\n\\n oUSD.burn(msg.sender, _amount);\\n\\n _postRedeem(_amount);\\n }\\n\\n function _postRedeem(uint256 _amount) internal {\\n // Until we can prove that we won't affect the prices of our assets\\n // by withdrawing them, this should be here.\\n // It's possible that a strategy was off on its asset total, perhaps\\n // a reward token sold for more or for less than anticipated.\\n uint256 totalUnits = 0;\\n if (_amount >= rebaseThreshold && !rebasePaused) {\\n totalUnits = _rebase();\\n } else {\\n totalUnits = _totalValue();\\n }\\n\\n // Check that the OTokens are backed by enough assets\\n if (maxSupplyDiff > 0) {\\n // Allow a max difference of maxSupplyDiff% between\\n // backing assets value and OUSD total supply\\n uint256 diff = oUSD.totalSupply().divPrecisely(totalUnits);\\n require(\\n (diff > 1e18 ? diff - 1e18 : 1e18 - diff) <= maxSupplyDiff,\\n \\\"Backing supply liquidity error\\\"\\n );\\n }\\n }\\n\\n /**\\n * @notice Burn OTokens for Metapool Strategy\\n * @param _amount Amount of OUSD to burn\\n *\\n * @dev Notice: can't use `nonReentrant` modifier since the `redeem` function could\\n * require withdrawal on `ConvexOUSDMetaStrategy` and that one can call `burnForStrategy`\\n * while the execution of the `redeem` has not yet completed -> causing a `nonReentrant` collision.\\n *\\n * Also important to understand is that this is a limitation imposed by the test suite.\\n * Production / mainnet contracts should never be configured in a way where mint/redeem functions\\n * that are moving funds between the Vault and end user wallets can influence strategies\\n * utilizing this function.\\n */\\n function burnForStrategy(uint256 _amount)\\n external\\n whenNotCapitalPaused\\n onlyOusdMetaStrategy\\n {\\n require(_amount < MAX_INT, \\\"Amount too high\\\");\\n\\n emit Redeem(msg.sender, _amount);\\n\\n // safe to cast because of the require check at the beginning of the function\\n netOusdMintedForStrategy -= int256(_amount);\\n\\n require(\\n abs(netOusdMintedForStrategy) < netOusdMintForStrategyThreshold,\\n \\\"Attempting to burn too much OUSD.\\\"\\n );\\n\\n // Burn OTokens\\n oUSD.burn(msg.sender, _amount);\\n }\\n\\n /**\\n * @notice Withdraw a supported asset and burn all OTokens.\\n * @param _minimumUnitAmount Minimum stablecoin units to receive in return\\n */\\n function redeemAll(uint256 _minimumUnitAmount)\\n external\\n whenNotCapitalPaused\\n nonReentrant\\n {\\n _redeem(oUSD.balanceOf(msg.sender), _minimumUnitAmount);\\n }\\n\\n /**\\n * @notice Allocate unallocated funds on Vault to strategies.\\n **/\\n function allocate() external whenNotCapitalPaused nonReentrant {\\n _allocate();\\n }\\n\\n /**\\n * @dev Allocate unallocated funds on Vault to strategies.\\n **/\\n function _allocate() internal virtual {\\n uint256 vaultValue = _totalValueInVault();\\n // Nothing in vault to allocate\\n if (vaultValue == 0) return;\\n uint256 strategiesValue = _totalValueInStrategies();\\n // We have a method that does the same as this, gas optimisation\\n uint256 calculatedTotalValue = vaultValue + strategiesValue;\\n\\n // We want to maintain a buffer on the Vault so calculate a percentage\\n // modifier to multiply each amount being allocated by to enforce the\\n // vault buffer\\n uint256 vaultBufferModifier;\\n if (strategiesValue == 0) {\\n // Nothing in Strategies, allocate 100% minus the vault buffer to\\n // strategies\\n vaultBufferModifier = uint256(1e18) - vaultBuffer;\\n } else {\\n vaultBufferModifier =\\n (vaultBuffer * calculatedTotalValue) /\\n vaultValue;\\n if (1e18 > vaultBufferModifier) {\\n // E.g. 1e18 - (1e17 * 10e18)/5e18 = 8e17\\n // (5e18 * 8e17) / 1e18 = 4e18 allocated from Vault\\n vaultBufferModifier = uint256(1e18) - vaultBufferModifier;\\n } else {\\n // We need to let the buffer fill\\n return;\\n }\\n }\\n if (vaultBufferModifier == 0) return;\\n\\n // Iterate over all assets in the Vault and allocate to the appropriate\\n // strategy\\n uint256 assetCount = allAssets.length;\\n for (uint256 i = 0; i < assetCount; ++i) {\\n IERC20 asset = IERC20(allAssets[i]);\\n uint256 assetBalance = asset.balanceOf(address(this));\\n // No balance, nothing to do here\\n if (assetBalance == 0) continue;\\n\\n // Multiply the balance by the vault buffer modifier and truncate\\n // to the scale of the asset decimals\\n uint256 allocateAmount = assetBalance.mulTruncate(\\n vaultBufferModifier\\n );\\n\\n address depositStrategyAddr = assetDefaultStrategies[\\n address(asset)\\n ];\\n\\n if (depositStrategyAddr != address(0) && allocateAmount > 0) {\\n IStrategy strategy = IStrategy(depositStrategyAddr);\\n // Transfer asset to Strategy and call deposit method to\\n // mint or take required action\\n asset.safeTransfer(address(strategy), allocateAmount);\\n strategy.deposit(address(asset), allocateAmount);\\n emit AssetAllocated(\\n address(asset),\\n depositStrategyAddr,\\n allocateAmount\\n );\\n }\\n }\\n }\\n\\n /**\\n * @notice Calculate the total value of assets held by the Vault and all\\n * strategies and update the supply of OTokens.\\n */\\n function rebase() external virtual nonReentrant {\\n _rebase();\\n }\\n\\n /**\\n * @dev Calculate the total value of assets held by the Vault and all\\n * strategies and update the supply of OTokens, optionally sending a\\n * portion of the yield to the trustee.\\n * @return totalUnits Total balance of Vault in units\\n */\\n function _rebase() internal whenNotRebasePaused returns (uint256) {\\n uint256 ousdSupply = oUSD.totalSupply();\\n uint256 vaultValue = _totalValue();\\n if (ousdSupply == 0) {\\n return vaultValue;\\n }\\n\\n // Yield fee collection\\n address _trusteeAddress = trusteeAddress; // gas savings\\n if (_trusteeAddress != address(0) && (vaultValue > ousdSupply)) {\\n uint256 yield = vaultValue - ousdSupply;\\n uint256 fee = yield.mulTruncateScale(trusteeFeeBps, 1e4);\\n require(yield > fee, \\\"Fee must not be greater than yield\\\");\\n if (fee > 0) {\\n oUSD.mint(_trusteeAddress, fee);\\n }\\n emit YieldDistribution(_trusteeAddress, yield, fee);\\n }\\n\\n // Only rachet OToken supply upwards\\n ousdSupply = oUSD.totalSupply(); // Final check should use latest value\\n if (vaultValue > ousdSupply) {\\n oUSD.changeSupply(vaultValue);\\n }\\n return vaultValue;\\n }\\n\\n /**\\n * @notice Determine the total value of assets held by the vault and its\\n * strategies.\\n * @return value Total value in USD/ETH (1e18)\\n */\\n function totalValue() external view virtual returns (uint256 value) {\\n value = _totalValue();\\n }\\n\\n /**\\n * @dev Internal Calculate the total value of the assets held by the\\n * vault and its strategies.\\n * @return value Total value in USD/ETH (1e18)\\n */\\n function _totalValue() internal view virtual returns (uint256 value) {\\n return _totalValueInVault() + _totalValueInStrategies();\\n }\\n\\n /**\\n * @dev Internal to calculate total value of all assets held in Vault.\\n * @return value Total value in USD/ETH (1e18)\\n */\\n function _totalValueInVault()\\n internal\\n view\\n virtual\\n returns (uint256 value)\\n {\\n uint256 assetCount = allAssets.length;\\n for (uint256 y = 0; y < assetCount; ++y) {\\n address assetAddr = allAssets[y];\\n uint256 balance = IERC20(assetAddr).balanceOf(address(this));\\n if (balance > 0) {\\n value += _toUnits(balance, assetAddr);\\n }\\n }\\n }\\n\\n /**\\n * @dev Internal to calculate total value of all assets held in Strategies.\\n * @return value Total value in USD/ETH (1e18)\\n */\\n function _totalValueInStrategies() internal view returns (uint256 value) {\\n uint256 stratCount = allStrategies.length;\\n for (uint256 i = 0; i < stratCount; ++i) {\\n value = value + _totalValueInStrategy(allStrategies[i]);\\n }\\n }\\n\\n /**\\n * @dev Internal to calculate total value of all assets held by strategy.\\n * @param _strategyAddr Address of the strategy\\n * @return value Total value in USD/ETH (1e18)\\n */\\n function _totalValueInStrategy(address _strategyAddr)\\n internal\\n view\\n returns (uint256 value)\\n {\\n IStrategy strategy = IStrategy(_strategyAddr);\\n uint256 assetCount = allAssets.length;\\n for (uint256 y = 0; y < assetCount; ++y) {\\n address assetAddr = allAssets[y];\\n if (strategy.supportsAsset(assetAddr)) {\\n uint256 balance = strategy.checkBalance(assetAddr);\\n if (balance > 0) {\\n value += _toUnits(balance, assetAddr);\\n }\\n }\\n }\\n }\\n\\n /**\\n * @notice Get the balance of an asset held in Vault and all strategies.\\n * @param _asset Address of asset\\n * @return uint256 Balance of asset in decimals of asset\\n */\\n function checkBalance(address _asset) external view returns (uint256) {\\n return _checkBalance(_asset);\\n }\\n\\n /**\\n * @notice Get the balance of an asset held in Vault and all strategies.\\n * @param _asset Address of asset\\n * @return balance Balance of asset in decimals of asset\\n */\\n function _checkBalance(address _asset)\\n internal\\n view\\n virtual\\n returns (uint256 balance)\\n {\\n IERC20 asset = IERC20(_asset);\\n balance = asset.balanceOf(address(this));\\n uint256 stratCount = allStrategies.length;\\n for (uint256 i = 0; i < stratCount; ++i) {\\n IStrategy strategy = IStrategy(allStrategies[i]);\\n if (strategy.supportsAsset(_asset)) {\\n balance = balance + strategy.checkBalance(_asset);\\n }\\n }\\n }\\n\\n /**\\n * @notice Calculate the outputs for a redeem function, i.e. the mix of\\n * coins that will be returned\\n */\\n function calculateRedeemOutputs(uint256 _amount)\\n external\\n view\\n returns (uint256[] memory)\\n {\\n return _calculateRedeemOutputs(_amount);\\n }\\n\\n /**\\n * @dev Calculate the outputs for a redeem function, i.e. the mix of\\n * coins that will be returned.\\n * @return outputs Array of amounts respective to the supported assets\\n */\\n function _calculateRedeemOutputs(uint256 _amount)\\n internal\\n view\\n virtual\\n returns (uint256[] memory outputs)\\n {\\n // We always give out coins in proportion to how many we have,\\n // Now if all coins were the same value, this math would easy,\\n // just take the percentage of each coin, and multiply by the\\n // value to be given out. But if coins are worth more than $1,\\n // then we would end up handing out too many coins. We need to\\n // adjust by the total value of coins.\\n //\\n // To do this, we total up the value of our coins, by their\\n // percentages. Then divide what we would otherwise give out by\\n // this number.\\n //\\n // Let say we have 100 DAI at $1.06 and 200 USDT at $1.00.\\n // So for every 1 DAI we give out, we'll be handing out 2 USDT\\n // Our total output ratio is: 33% * 1.06 + 66% * 1.00 = 1.02\\n //\\n // So when calculating the output, we take the percentage of\\n // each coin, times the desired output value, divided by the\\n // totalOutputRatio.\\n //\\n // For example, withdrawing: 30 OUSD:\\n // DAI 33% * 30 / 1.02 = 9.80 DAI\\n // USDT = 66 % * 30 / 1.02 = 19.60 USDT\\n //\\n // Checking these numbers:\\n // 9.80 DAI * 1.06 = $10.40\\n // 19.60 USDT * 1.00 = $19.60\\n //\\n // And so the user gets $10.40 + $19.60 = $30 worth of value.\\n\\n uint256 assetCount = allAssets.length;\\n uint256[] memory assetUnits = new uint256[](assetCount);\\n uint256[] memory assetBalances = new uint256[](assetCount);\\n outputs = new uint256[](assetCount);\\n\\n // Calculate redeem fee\\n if (redeemFeeBps > 0) {\\n uint256 redeemFee = _amount.mulTruncateScale(redeemFeeBps, 1e4);\\n _amount = _amount - redeemFee;\\n }\\n\\n // Calculate assets balances and decimals once,\\n // for a large gas savings.\\n uint256 totalUnits = 0;\\n for (uint256 i = 0; i < assetCount; ++i) {\\n address assetAddr = allAssets[i];\\n uint256 balance = _checkBalance(assetAddr);\\n assetBalances[i] = balance;\\n assetUnits[i] = _toUnits(balance, assetAddr);\\n totalUnits = totalUnits + assetUnits[i];\\n }\\n // Calculate totalOutputRatio\\n uint256 totalOutputRatio = 0;\\n for (uint256 i = 0; i < assetCount; ++i) {\\n uint256 unitPrice = _toUnitPrice(allAssets[i], false);\\n uint256 ratio = (assetUnits[i] * unitPrice) / totalUnits;\\n totalOutputRatio = totalOutputRatio + ratio;\\n }\\n // Calculate final outputs\\n uint256 factor = _amount.divPrecisely(totalOutputRatio);\\n for (uint256 i = 0; i < assetCount; ++i) {\\n outputs[i] = (assetBalances[i] * factor) / totalUnits;\\n }\\n }\\n\\n /***************************************\\n Pricing\\n ****************************************/\\n\\n /**\\n * @notice Returns the total price in 18 digit units for a given asset.\\n * Never goes above 1, since that is how we price mints.\\n * @param asset address of the asset\\n * @return price uint256: unit (USD / ETH) price for 1 unit of the asset, in 18 decimal fixed\\n */\\n function priceUnitMint(address asset)\\n external\\n view\\n returns (uint256 price)\\n {\\n /* need to supply 1 asset unit in asset's decimals and can not just hard-code\\n * to 1e18 and ignore calling `_toUnits` since we need to consider assets\\n * with the exchange rate\\n */\\n uint256 units = _toUnits(\\n uint256(1e18).scaleBy(_getDecimals(asset), 18),\\n asset\\n );\\n price = (_toUnitPrice(asset, true) * units) / 1e18;\\n }\\n\\n /**\\n * @notice Returns the total price in 18 digit unit for a given asset.\\n * Never goes below 1, since that is how we price redeems\\n * @param asset Address of the asset\\n * @return price uint256: unit (USD / ETH) price for 1 unit of the asset, in 18 decimal fixed\\n */\\n function priceUnitRedeem(address asset)\\n external\\n view\\n returns (uint256 price)\\n {\\n /* need to supply 1 asset unit in asset's decimals and can not just hard-code\\n * to 1e18 and ignore calling `_toUnits` since we need to consider assets\\n * with the exchange rate\\n */\\n uint256 units = _toUnits(\\n uint256(1e18).scaleBy(_getDecimals(asset), 18),\\n asset\\n );\\n price = (_toUnitPrice(asset, false) * units) / 1e18;\\n }\\n\\n /***************************************\\n Utils\\n ****************************************/\\n\\n /**\\n * @dev Convert a quantity of a token into 1e18 fixed decimal \\\"units\\\"\\n * in the underlying base (USD/ETH) used by the vault.\\n * Price is not taken into account, only quantity.\\n *\\n * Examples of this conversion:\\n *\\n * - 1e18 DAI becomes 1e18 units (same decimals)\\n * - 1e6 USDC becomes 1e18 units (decimal conversion)\\n * - 1e18 rETH becomes 1.2e18 units (exchange rate conversion)\\n *\\n * @param _raw Quantity of asset\\n * @param _asset Core Asset address\\n * @return value 1e18 normalized quantity of units\\n */\\n function _toUnits(uint256 _raw, address _asset)\\n internal\\n view\\n returns (uint256)\\n {\\n UnitConversion conversion = assets[_asset].unitConversion;\\n if (conversion == UnitConversion.DECIMALS) {\\n return _raw.scaleBy(18, _getDecimals(_asset));\\n } else if (conversion == UnitConversion.GETEXCHANGERATE) {\\n uint256 exchangeRate = IGetExchangeRateToken(_asset)\\n .getExchangeRate();\\n return (_raw * exchangeRate) / 1e18;\\n } else {\\n revert(\\\"Unsupported conversion type\\\");\\n }\\n }\\n\\n /**\\n * @dev Returns asset's unit price accounting for different asset types\\n * and takes into account the context in which that price exists -\\n * - mint or redeem.\\n *\\n * Note: since we are returning the price of the unit and not the one of the\\n * asset (see comment above how 1 rETH exchanges for 1.2 units) we need\\n * to make the Oracle price adjustment as well since we are pricing the\\n * units and not the assets.\\n *\\n * The price also snaps to a \\\"full unit price\\\" in case a mint or redeem\\n * action would be unfavourable to the protocol.\\n *\\n */\\n function _toUnitPrice(address _asset, bool isMint)\\n internal\\n view\\n returns (uint256 price)\\n {\\n UnitConversion conversion = assets[_asset].unitConversion;\\n price = IOracle(priceProvider).price(_asset);\\n\\n if (conversion == UnitConversion.GETEXCHANGERATE) {\\n uint256 exchangeRate = IGetExchangeRateToken(_asset)\\n .getExchangeRate();\\n price = (price * 1e18) / exchangeRate;\\n } else if (conversion != UnitConversion.DECIMALS) {\\n revert(\\\"Unsupported conversion type\\\");\\n }\\n\\n /* At this stage the price is already adjusted to the unit\\n * so the price checks are agnostic to underlying asset being\\n * pegged to a USD or to an ETH or having a custom exchange rate.\\n */\\n require(price <= MAX_UNIT_PRICE_DRIFT, \\\"Vault: Price exceeds max\\\");\\n require(price >= MIN_UNIT_PRICE_DRIFT, \\\"Vault: Price under min\\\");\\n\\n if (isMint) {\\n /* Never price a normalized unit price for more than one\\n * unit of OETH/OUSD when minting.\\n */\\n if (price > 1e18) {\\n price = 1e18;\\n }\\n require(price >= MINT_MINIMUM_UNIT_PRICE, \\\"Asset price below peg\\\");\\n } else {\\n /* Never give out more than 1 normalized unit amount of assets\\n * for one unit of OETH/OUSD when redeeming.\\n */\\n if (price < 1e18) {\\n price = 1e18;\\n }\\n }\\n }\\n\\n function _getDecimals(address _asset)\\n internal\\n view\\n returns (uint256 decimals)\\n {\\n decimals = assets[_asset].decimals;\\n require(decimals > 0, \\\"Decimals not cached\\\");\\n }\\n\\n /**\\n * @notice Return the number of assets supported by the Vault.\\n */\\n function getAssetCount() public view returns (uint256) {\\n return allAssets.length;\\n }\\n\\n /**\\n * @notice Gets the vault configuration of a supported asset.\\n */\\n function getAssetConfig(address _asset)\\n public\\n view\\n returns (Asset memory config)\\n {\\n config = assets[_asset];\\n }\\n\\n /**\\n * @notice Return all vault asset addresses in order\\n */\\n function getAllAssets() external view returns (address[] memory) {\\n return allAssets;\\n }\\n\\n /**\\n * @notice Return the number of strategies active on the Vault.\\n */\\n function getStrategyCount() external view returns (uint256) {\\n return allStrategies.length;\\n }\\n\\n /**\\n * @notice Return the array of all strategies\\n */\\n function getAllStrategies() external view returns (address[] memory) {\\n return allStrategies;\\n }\\n\\n /**\\n * @notice Returns whether the vault supports the asset\\n * @param _asset address of the asset\\n * @return true if supported\\n */\\n function isSupportedAsset(address _asset) external view returns (bool) {\\n return assets[_asset].isSupported;\\n }\\n\\n /**\\n * @dev Falldown to the admin implementation\\n * @notice This is a catch all for all functions not declared in core\\n */\\n // solhint-disable-next-line no-complex-fallback\\n fallback() external {\\n bytes32 slot = adminImplPosition;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n // Copy msg.data. We take full control of memory in this inline assembly\\n // block because it will not return to Solidity code. We overwrite the\\n // Solidity scratch pad at memory position 0.\\n calldatacopy(0, 0, calldatasize())\\n\\n // Call the implementation.\\n // out and outsize are 0 because we don't know the size yet.\\n let result := delegatecall(\\n gas(),\\n sload(slot),\\n 0,\\n calldatasize(),\\n 0,\\n 0\\n )\\n\\n // Copy the returned data.\\n returndatacopy(0, 0, returndatasize())\\n\\n switch result\\n // delegatecall returns 0 on error.\\n case 0 {\\n revert(0, returndatasize())\\n }\\n default {\\n return(0, returndatasize())\\n }\\n }\\n }\\n\\n function abs(int256 x) private pure returns (uint256) {\\n require(x < int256(MAX_INT), \\\"Amount too high\\\");\\n return x >= 0 ? uint256(x) : uint256(-x);\\n }\\n}\\n\",\"keccak256\":\"0x53b63416345037aefda0c13b0d7b6480737fe5edc50a23fa7383720808a5399e\",\"license\":\"MIT\"},\"contracts/vault/VaultInitializer.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title OToken VaultInitializer contract\\n * @notice The Vault contract initializes the vault.\\n * @author Origin Protocol Inc\\n */\\n\\nimport \\\"./VaultStorage.sol\\\";\\n\\ncontract VaultInitializer is VaultStorage {\\n function initialize(address _priceProvider, address _oToken)\\n external\\n onlyGovernor\\n initializer\\n {\\n require(_priceProvider != address(0), \\\"PriceProvider address is zero\\\");\\n require(_oToken != address(0), \\\"oToken address is zero\\\");\\n\\n oUSD = OUSD(_oToken);\\n\\n priceProvider = _priceProvider;\\n\\n rebasePaused = false;\\n capitalPaused = true;\\n\\n // Initial redeem fee of 0 basis points\\n redeemFeeBps = 0;\\n // Initial Vault buffer of 0%\\n vaultBuffer = 0;\\n // Initial allocate threshold of 25,000 OUSD\\n autoAllocateThreshold = 25000e18;\\n // Threshold for rebasing\\n rebaseThreshold = 1000e18;\\n // Initialize all strategies\\n allStrategies = new address[](0);\\n }\\n}\\n\",\"keccak256\":\"0x5b9676307bbabe14b5278f00ec7edc557b84debbfa1391902d78100cb9cd467e\",\"license\":\"MIT\"},\"contracts/vault/VaultStorage.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title OToken VaultStorage contract\\n * @notice The VaultStorage contract defines the storage for the Vault contracts\\n * @author Origin Protocol Inc\\n */\\n\\nimport { IERC20 } from \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport { SafeERC20 } from \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\nimport { Address } from \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\n\\nimport { IStrategy } from \\\"../interfaces/IStrategy.sol\\\";\\nimport { Governable } from \\\"../governance/Governable.sol\\\";\\nimport { OUSD } from \\\"../token/OUSD.sol\\\";\\nimport { Initializable } from \\\"../utils/Initializable.sol\\\";\\nimport \\\"../utils/Helpers.sol\\\";\\n\\ncontract VaultStorage is Initializable, Governable {\\n using SafeERC20 for IERC20;\\n\\n event AssetSupported(address _asset);\\n event AssetRemoved(address _asset);\\n event AssetDefaultStrategyUpdated(address _asset, address _strategy);\\n event AssetAllocated(address _asset, address _strategy, uint256 _amount);\\n event StrategyApproved(address _addr);\\n event StrategyRemoved(address _addr);\\n event Mint(address _addr, uint256 _value);\\n event Redeem(address _addr, uint256 _value);\\n event CapitalPaused();\\n event CapitalUnpaused();\\n event RebasePaused();\\n event RebaseUnpaused();\\n event VaultBufferUpdated(uint256 _vaultBuffer);\\n event OusdMetaStrategyUpdated(address _ousdMetaStrategy);\\n event RedeemFeeUpdated(uint256 _redeemFeeBps);\\n event PriceProviderUpdated(address _priceProvider);\\n event AllocateThresholdUpdated(uint256 _threshold);\\n event RebaseThresholdUpdated(uint256 _threshold);\\n event StrategistUpdated(address _address);\\n event MaxSupplyDiffChanged(uint256 maxSupplyDiff);\\n event YieldDistribution(address _to, uint256 _yield, uint256 _fee);\\n event TrusteeFeeBpsChanged(uint256 _basis);\\n event TrusteeAddressChanged(address _address);\\n event NetOusdMintForStrategyThresholdChanged(uint256 _threshold);\\n event SwapperChanged(address _address);\\n event SwapAllowedUndervalueChanged(uint256 _basis);\\n event SwapSlippageChanged(address _asset, uint256 _basis);\\n event Swapped(\\n address indexed _fromAsset,\\n address indexed _toAsset,\\n uint256 _fromAssetAmount,\\n uint256 _toAssetAmount\\n );\\n event DripperChanged(address indexed _dripper);\\n event WithdrawalRequested(\\n address indexed _withdrawer,\\n uint256 indexed _requestId,\\n uint256 _amount,\\n uint256 _queued\\n );\\n event WithdrawalClaimed(\\n address indexed _withdrawer,\\n uint256 indexed _requestId,\\n uint256 _amount\\n );\\n event WithdrawalClaimable(uint256 _claimable, uint256 _newClaimable);\\n\\n // Assets supported by the Vault, i.e. Stablecoins\\n enum UnitConversion {\\n DECIMALS,\\n GETEXCHANGERATE\\n }\\n // Changed to fit into a single storage slot so the decimals needs to be recached\\n struct Asset {\\n // Note: OETHVaultCore doesn't use `isSupported` when minting,\\n // redeeming or checking balance of assets.\\n bool isSupported;\\n UnitConversion unitConversion;\\n uint8 decimals;\\n // Max allowed slippage from the Oracle price when swapping collateral assets in basis points.\\n // For example 40 == 0.4% slippage\\n uint16 allowedOracleSlippageBps;\\n }\\n\\n /// @dev mapping of supported vault assets to their configuration\\n // slither-disable-next-line uninitialized-state\\n mapping(address => Asset) internal assets;\\n /// @dev list of all assets supported by the vault.\\n // slither-disable-next-line uninitialized-state\\n address[] internal allAssets;\\n\\n // Strategies approved for use by the Vault\\n struct Strategy {\\n bool isSupported;\\n uint256 _deprecated; // Deprecated storage slot\\n }\\n /// @dev mapping of strategy contracts to their configuration\\n mapping(address => Strategy) internal strategies;\\n /// @dev list of all vault strategies\\n address[] internal allStrategies;\\n\\n /// @notice Address of the Oracle price provider contract\\n // slither-disable-next-line uninitialized-state\\n address public priceProvider;\\n /// @notice pause rebasing if true\\n bool public rebasePaused = false;\\n /// @notice pause operations that change the OToken supply.\\n /// eg mint, redeem, allocate, mint/burn for strategy\\n bool public capitalPaused = true;\\n /// @notice Redemption fee in basis points. eg 50 = 0.5%\\n uint256 public redeemFeeBps;\\n /// @notice Percentage of assets to keep in Vault to handle (most) withdrawals. 100% = 1e18.\\n uint256 public vaultBuffer;\\n /// @notice OToken mints over this amount automatically allocate funds. 18 decimals.\\n uint256 public autoAllocateThreshold;\\n /// @notice OToken mints over this amount automatically rebase. 18 decimals.\\n uint256 public rebaseThreshold;\\n\\n /// @dev Address of the OToken token. eg OUSD or OETH.\\n // slither-disable-next-line uninitialized-state\\n OUSD internal oUSD;\\n\\n //keccak256(\\\"OUSD.vault.governor.admin.impl\\\");\\n bytes32 constant adminImplPosition =\\n 0xa2bd3d3cf188a41358c8b401076eb59066b09dec5775650c0de4c55187d17bd9;\\n\\n // Address of the contract responsible for post rebase syncs with AMMs\\n address private _deprecated_rebaseHooksAddr = address(0);\\n\\n // Deprecated: Address of Uniswap\\n // slither-disable-next-line constable-states\\n address private _deprecated_uniswapAddr = address(0);\\n\\n /// @notice Address of the Strategist\\n address public strategistAddr = address(0);\\n\\n /// @notice Mapping of asset address to the Strategy that they should automatically\\n // be allocated to\\n // slither-disable-next-line uninitialized-state\\n mapping(address => address) public assetDefaultStrategies;\\n\\n /// @notice Max difference between total supply and total value of assets. 18 decimals.\\n // slither-disable-next-line uninitialized-state\\n uint256 public maxSupplyDiff;\\n\\n /// @notice Trustee contract that can collect a percentage of yield\\n address public trusteeAddress;\\n\\n /// @notice Amount of yield collected in basis points. eg 2000 = 20%\\n uint256 public trusteeFeeBps;\\n\\n /// @dev Deprecated: Tokens that should be swapped for stablecoins\\n address[] private _deprecated_swapTokens;\\n\\n uint256 constant MINT_MINIMUM_UNIT_PRICE = 0.998e18;\\n\\n /// @notice Metapool strategy that is allowed to mint/burn OTokens without changing collateral\\n address public ousdMetaStrategy = address(0);\\n\\n /// @notice How much OTokens are currently minted by the strategy\\n int256 public netOusdMintedForStrategy = 0;\\n\\n /// @notice How much net total OTokens are allowed to be minted by all strategies\\n uint256 public netOusdMintForStrategyThreshold = 0;\\n\\n uint256 constant MIN_UNIT_PRICE_DRIFT = 0.7e18;\\n uint256 constant MAX_UNIT_PRICE_DRIFT = 1.3e18;\\n\\n /// @notice Collateral swap configuration.\\n /// @dev is packed into a single storage slot to save gas.\\n struct SwapConfig {\\n // Contract that swaps the vault's collateral assets\\n address swapper;\\n // Max allowed percentage the total value can drop below the total supply in basis points.\\n // For example 100 == 1%\\n uint16 allowedUndervalueBps;\\n }\\n SwapConfig internal swapConfig = SwapConfig(address(0), 0);\\n\\n /// @notice Address of the Dripper contract that streams harvested rewards to the Vault\\n /// @dev The vault is proxied so needs to be set with setDripper against the proxy contract.\\n // slither-disable-start constable-states\\n // slither-disable-next-line uninitialized-state\\n address public dripper;\\n // slither-disable-end constable-states\\n\\n /// Withdrawal Queue Storage /////\\n\\n struct WithdrawalQueueMetadata {\\n // cumulative total of all withdrawal requests included the ones that have already been claimed\\n uint128 queued;\\n // cumulative total of all the requests that can be claimed included the ones that have already been claimed\\n uint128 claimable;\\n // total of all the requests that have been claimed\\n uint128 claimed;\\n // index of the next withdrawal request starting at 0\\n uint128 nextWithdrawalIndex;\\n }\\n\\n // slither-disable-next-line uninitialized-state\\n WithdrawalQueueMetadata public withdrawalQueueMetadata;\\n\\n struct WithdrawalRequest {\\n address withdrawer;\\n bool claimed;\\n // Amount of oTokens to redeem\\n uint128 amount;\\n // cumulative total of all withdrawal requests including this one.\\n // this request can be claimed when this queued amount is less than or equal to the queue's claimable amount.\\n uint128 queued;\\n }\\n\\n // Mapping of withdrawal requests indexes to the user withdrawal request data\\n mapping(uint256 => WithdrawalRequest) public withdrawalRequests;\\n\\n // For future use\\n uint256[46] private __gap;\\n\\n /**\\n * @notice set the implementation for the admin, this needs to be in a base class else we cannot set it\\n * @param newImpl address of the implementation\\n */\\n function setAdminImpl(address newImpl) external onlyGovernor {\\n require(\\n Address.isContract(newImpl),\\n \\\"new implementation is not a contract\\\"\\n );\\n bytes32 position = adminImplPosition;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n sstore(position, newImpl)\\n }\\n }\\n}\\n\",\"keccak256\":\"0xe13565f58d63805320aa4aac336b294fa6b6e55b028a6727510bf99764ebce14\",\"license\":\"MIT\"}},\"version\":1}", + "bytecode": "0x6037805461ffff60a01b1916600160a81b179055603d80546001600160a01b0319908116909155603e805482169055603f80548216905560458054909116905560006046819055604781905560e060405260a081905260c052604880546001600160b01b03191690553480156200007557600080fd5b50604051620045363803806200453683398101604081905262000098916200010e565b620000b0336000805160206200451683398151915255565b60008051602062004516833981519152546040516001600160a01b03909116906000907fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a908290a360601b6001600160601b03191660805262000140565b6000602082840312156200012157600080fd5b81516001600160a01b03811681146200013957600080fd5b9392505050565b60805160601c614363620001b36000396000818161040b015281816108e10152818161095401528181610d350152818161183a0152818161190f0152818161249d015281816125a701528181612785015281816127bb0152818161280f01528181612cf3015261324801526143636000f3fe608060405234801561001057600080fd5b50600436106102bb5760003560e01c806367bd7ba311610182578063ab80dafb116100e9578063c7af3352116100a2578063e45cc9f01161007c578063e45cc9f014610712578063e6cc54321461071b578063f84444361461072f578063fc0cfeee14610742576102bb565b8063c7af3352146106ef578063d38bfff4146106f7578063d4c3eea01461070a576102bb565b8063ab80dafb146106a9578063abaa9916146106bc578063af14052c146106c4578063b888879e146106cc578063b9b17f9f146106df578063c3b28864146106e7576102bb565b8063937b25811161013b578063937b2581146105915780639be918e61461061b5780639ee679e8146106475780639fa1826e1461066f578063a0aead4d14610678578063a403e4d514610680576102bb565b806367bd7ba3146105195780636ec3ab67146105395780637136a7a6146105595780637a2202f31461056c5780637cbc2373146105755780638e510b5214610588576102bb565b8063485cc95511610226578063570d8e1d116101df578063570d8e1d146104b25780635b60f9fc146104c55780635d36b190146104d85780635f515226146104e0578063603ea03b146104f35780636217f3ea14610506576102bb565b8063485cc9551461043557806348e30f541461044857806349c1d54d1461046957806352d38e5d1461047c57806353ca9f241461048557806354c6d858146104a9576102bb565b80632acada4d116102785780632acada4d1461037757806331e19cfa1461038c578063362bd1a3146103945780633b8fe28d146103f35780633fc8cef31461040657806344c547071461042d576102bb565b806309f6442c146103015780630c340a241461031d578063156e29f61461033d57806318ce56bd146103525780631edfe3da14610365578063207134b01461036e575b7fa2bd3d3cf188a41358c8b401076eb59066b09dec5775650c0de4c55187d17bd9366000803760008036600084545af43d6000803e8080156102fc573d6000f35b3d6000fd5b61030a60385481565b6040519081526020015b60405180910390f35b610325610755565b6040516001600160a01b039091168152602001610314565b61035061034b366004613c26565b610772565b005b604554610325906001600160a01b031681565b61030a60395481565b61030a60435481565b61037f6107f0565b6040516103149190613e04565b60365461030a565b604a54604b546103c0916001600160801b0380821692600160801b928390048216928183169291041684565b604080516001600160801b0395861681529385166020850152918416918301919091529091166060820152608001610314565b61030a610401366004613bd8565b610852565b6103257f000000000000000000000000000000000000000000000000000000000000000081565b6103506108ad565b610350610443366004613bf3565b6109f6565b61045b610456366004613c59565b610bf8565b604051610314929190613e64565b604254610325906001600160a01b031681565b61030a603b5481565b60375461049990600160a01b900460ff1681565b6040519015158152602001610314565b61030a607b5481565b603f54610325906001600160a01b031681565b61030a6104d3366004613bd8565b610d67565b610350610d90565b61030a6104ee366004613bd8565b610e36565b604954610325906001600160a01b031681565b610350610514366004613d40565b610e47565b61052c610527366004613d40565b610fde565b6040516103149190613e51565b61054c610547366004613bd8565b610fe9565b6040516103149190613fad565b610350610567366004613d40565b61108f565b61030a60475481565b610350610583366004613d72565b61117a565b61030a60415481565b6105e261059f366004613d40565b604c60205260009081526040902080546001909101546001600160a01b03821691600160a01b900460ff16906001600160801b0380821691600160801b90041684565b604080516001600160a01b03909516855292151560208501526001600160801b0391821692840192909252166060820152608001610314565b610499610629366004613bd8565b6001600160a01b031660009081526033602052604090205460ff1690565b61065a610655366004613d40565b6111ed565b60408051928352602083019190915201610314565b61030a603a5481565b60345461030a565b61032561068e366004613bd8565b6040602081905260009182529020546001600160a01b031681565b6103506106b7366004613d40565b6113e4565b61035061155b565b6103506115ca565b603754610325906001600160a01b031681565b610350611610565b61037f611680565b6104996116e0565b610350610705366004613bd8565b611711565b61030a6117b5565b61030a60465481565b60375461049990600160a81b900460ff1681565b61030a61073d366004613d40565b6117bf565b610350610750366004613bd8565b61186b565b600061076d60008051602061430e8339815191525490565b905090565b603754600160a81b900460ff16156107a55760405162461bcd60e51b815260040161079c90613f5d565b60405180910390fd5b6000805160206142ee833981519152805460028114156107d75760405162461bcd60e51b815260040161079c90613f85565b600282556107e685858561190d565b5060019055505050565b6060603480548060200260200160405190810160405280929190818152602001828054801561084857602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161082a575b5050505050905090565b60008061087b61087561086485611b8e565b670de0b6b3a7640000906012611bf8565b84611c5a565b9050670de0b6b3a764000081610892856001611db6565b61089c9190614194565b6108a69190614087565b9392505050565b6108b56116e0565b6108d15760405162461bcd60e51b815260040161079c90613efd565b60345460005b81811015610951577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166034828154811061091c5761091c6142c1565b6000918252602090912001546001600160a01b0316141561094157607b819055610951565b61094a8161425d565b90506108d7565b507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166034607b5481548110610991576109916142c1565b6000918252602090912001546001600160a01b0316146109f35760405162461bcd60e51b815260206004820152601860248201527f496e76616c6964205745544820417373657420496e6465780000000000000000604482015260640161079c565b50565b6109fe6116e0565b610a1a5760405162461bcd60e51b815260040161079c90613efd565b600054610100900460ff1680610a33575060005460ff16155b610a965760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840161079c565b600054610100900460ff16158015610ab8576000805461ffff19166101011790555b6001600160a01b038316610b0e5760405162461bcd60e51b815260206004820152601d60248201527f507269636550726f76696465722061646472657373206973207a65726f000000604482015260640161079c565b6001600160a01b038216610b5d5760405162461bcd60e51b81526020600482015260166024820152756f546f6b656e2061646472657373206973207a65726f60501b604482015260640161079c565b603c80546001600160a01b038481166001600160a01b031990921691909117909155603780546001600160b01b03191691851691909117600160a81b17905560006038819055603981905569054b40b1f852bda00000603a55683635c9adc5dea00000603b556040805191825260208201908190529051610be091603691613b50565b508015610bf3576000805461ff00191690555b505050565b603754606090600090600160a81b900460ff1615610c285760405162461bcd60e51b815260040161079c90613f5d565b6000805160206142ee83398151915280546002811415610c5a5760405162461bcd60e51b815260040161079c90613f85565b60028255845167ffffffffffffffff811115610c7857610c786142d7565b604051908082528060200260200182016040528015610ca1578160200160208202803683370190505b50935060005b8551811015610d2757610cd2868281518110610cc557610cc56142c1565b60200260200101516120a8565b858281518110610ce457610ce46142c1565b602002602001018181525050848181518110610d0257610d026142c1565b602002602001015184610d15919061406f565b9350610d208161425d565b9050610ca7565b50610d5c6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163385612377565b600182555050915091565b600080610d7961087561086485611b8e565b9050670de0b6b3a764000081610892856000611db6565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b031614610e2b5760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b606482015260840161079c565b610e34336123cd565b565b6000610e418261248e565b92915050565b603754600160a81b900460ff1615610e715760405162461bcd60e51b815260040161079c90613f5d565b6045546001600160a01b03163314610e9b5760405162461bcd60e51b815260040161079c90613eb9565b6001600160ff1b038110610ec15760405162461bcd60e51b815260040161079c90613f34565b7f222838db2794d11532d940e8dec38ae307ed0b63cd97c233322e221f998767a63382604051610ef2929190613deb565b60405180910390a18060466000828254610f0c91906141b3565b9091555050604754604654610f209061252c565b10610f775760405162461bcd60e51b815260206004820152602160248201527f417474656d7074696e6720746f206275726e20746f6f206d756368204f5553446044820152601760f91b606482015260840161079c565b603c54604051632770a7eb60e21b81526001600160a01b0390911690639dc29fac90610fa99033908590600401613deb565b600060405180830381600087803b158015610fc357600080fd5b505af1158015610fd7573d6000803e3d6000fd5b5050505050565b6060610e418261256f565b604080516080808201835260008083526020808401829052838501829052606084018290526001600160a01b038616825260338152908490208451928301909452835460ff808216151584529394929391840191610100909104166001811115611055576110556142ab565b6001811115611066576110666142ab565b8152905462010000810460ff1660208301526301000000900461ffff1660409091015292915050565b603754600160a81b900460ff16156110b95760405162461bcd60e51b815260040161079c90613f5d565b6000805160206142ee833981519152805460028114156110eb5760405162461bcd60e51b815260040161079c90613f85565b60028255603c546040516370a0823160e01b8152336004820152611172916001600160a01b0316906370a082319060240160206040518083038186803b15801561113457600080fd5b505afa158015611148573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061116c9190613d59565b846126b0565b506001905550565b603754600160a81b900460ff16156111a45760405162461bcd60e51b815260040161079c90613f5d565b6000805160206142ee833981519152805460028114156111d65760405162461bcd60e51b815260040161079c90613f85565b600282556111e484846126b0565b50600190555050565b6037546000908190600160a81b900460ff161561121c5760405162461bcd60e51b815260040161079c90613f5d565b6000805160206142ee8339815191528054600281141561124e5760405162461bcd60e51b815260040161079c90613f85565b60028255603c54604051632770a7eb60e21b81526001600160a01b0390911690639dc29fac906112849033908990600401613deb565b600060405180830381600087803b15801561129e57600080fd5b505af11580156112b2573d6000803e3d6000fd5b5050604b54604a546001600160801b03600160801b909204821697506112dc93508892501661406f565b92506112e984600161406f565b604b80546001600160801b03928316600160801b02908316179055604a80549185166001600160801b03199092169190911790556040805186815260208101859052859133917f38e3d972947cfef94205163d483d6287ef27eb312e20cb8e0b13a49989db232e910160405180910390a35060408051608081018252338152600060208083018281526001600160801b03988916848601908152878a1660608601908152898552604c909352949092209251835492511515600160a01b026001600160a81b03199093166001600160a01b039190911617919091178255915191518616600160801b0291909516176001948501559290925591565b603754600160a81b900460ff161561140e5760405162461bcd60e51b815260040161079c90613f5d565b6045546001600160a01b031633146114385760405162461bcd60e51b815260040161079c90613eb9565b6001600160ff1b03811061145e5760405162461bcd60e51b815260040161079c90613f34565b7f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d4121396885338260405161148f929190613deb565b60405180910390a180604660008282546114a99190614003565b90915550506047546046546114bd9061252c565b106115295760405162461bcd60e51b815260206004820152603660248201527f4d696e746564206f75736420737572706173736564206e65744f7573644d696e6044820152753a2337b929ba3930ba32b3bcaa343932b9b437b6321760511b606482015260840161079c565b603c546040516340c10f1960e01b81526001600160a01b03909116906340c10f1990610fa99033908590600401613deb565b603754600160a81b900460ff16156115855760405162461bcd60e51b815260040161079c90613f5d565b6000805160206142ee833981519152805460028114156115b75760405162461bcd60e51b815260040161079c90613f85565b600282556115c361292c565b5060019055565b6000805160206142ee833981519152805460028114156115fc5760405162461bcd60e51b815260040161079c90613f85565b6002825561160861293d565b505060019055565b604960009054906101000a90046001600160a01b03166001600160a01b031663e52253816040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561166057600080fd5b505af1158015611674573d6000803e3d6000fd5b505050506109f3612c78565b60606036805480602002602001604051908101604052809291908181526020018280548015610848576020028201919060005260206000209081546001600160a01b0316815260019091019060200180831161082a575050505050905090565b60006116f860008051602061430e8339815191525490565b6001600160a01b0316336001600160a01b031614905090565b6117196116e0565b6117355760405162461bcd60e51b815260040161079c90613efd565b61175d817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b031661177d60008051602061430e8339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b600061076d612e45565b603754600090600160a81b900460ff16156117ec5760405162461bcd60e51b815260040161079c90613f5d565b6000805160206142ee8339815191528054600281141561181e5760405162461bcd60e51b815260040161079c90613f85565b6002825561182b846120a8565b92506118616001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163385612377565b5060019055919050565b6118736116e0565b61188f5760405162461bcd60e51b815260040161079c90613efd565b803b6118e95760405162461bcd60e51b8152602060048201526024808201527f6e657720696d706c656d656e746174696f6e206973206e6f74206120636f6e746044820152631c9858dd60e21b606482015260840161079c565b7fa2bd3d3cf188a41358c8b401076eb59066b09dec5775650c0de4c55187d17bd955565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316836001600160a01b03161461198e5760405162461bcd60e51b815260206004820152601d60248201527f556e737570706f7274656420617373657420666f72206d696e74696e67000000604482015260640161079c565b600082116119de5760405162461bcd60e51b815260206004820152601d60248201527f416d6f756e74206d7573742062652067726561746572207468616e2030000000604482015260640161079c565b80821015611a2e5760405162461bcd60e51b815260206004820152601e60248201527f4d696e7420616d6f756e74206c6f776572207468616e206d696e696d756d0000604482015260640161079c565b7f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d41213968853383604051611a5f929190613deb565b60405180910390a1603754600160a01b900460ff16158015611a835750603b548210155b15611afa57604960009054906101000a90046001600160a01b03166001600160a01b031663e52253816040518163ffffffff1660e01b8152600401600060405180830381600087803b158015611ad857600080fd5b505af1158015611aec573d6000803e3d6000fd5b50505050611af861293d565b505b603c546040516340c10f1960e01b81526001600160a01b03909116906340c10f1990611b2c9033908690600401613deb565b600060405180830381600087803b158015611b4657600080fd5b505af1158015611b5a573d6000803e3d6000fd5b50611b74925050506001600160a01b038416333085612eaf565b611b7c612c78565b50603a548210610bf357610bf361292c565b6001600160a01b03811660009081526033602052604090205462010000900460ff1680611bf35760405162461bcd60e51b8152602060048201526013602482015272111958da5b585b1cc81b9bdd0818d858da1959606a1b604482015260640161079c565b919050565b600081831115611c2857611c21611c0f838561421a565b611c1a90600a6140ec565b8590612eed565b9350611c52565b81831015611c5257611c4f611c3d848461421a565b611c4890600a6140ec565b8590612ef9565b93505b509192915050565b6001600160a01b038116600090815260336020526040812054610100900460ff1681816001811115611c8e57611c8e6142ab565b1415611cb257611caa6012611ca285611b8e565b869190611bf8565b915050610e41565b6001816001811115611cc657611cc66142ab565b1415611d67576000836001600160a01b031663e6aa216c6040518163ffffffff1660e01b815260040160206040518083038186803b158015611d0757600080fd5b505afa158015611d1b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d3f9190613d59565b9050670de0b6b3a7640000611d548287614194565b611d5e9190614087565b92505050610e41565b60405162461bcd60e51b815260206004820152601b60248201527f556e737570706f7274656420636f6e76657273696f6e20747970650000000000604482015260640161079c565b5092915050565b6001600160a01b038281166000818152603360205260408082205460375491516315d5220f60e31b81526004810194909452919361010090920460ff169291169063aea910789060240160206040518083038186803b158015611e1857600080fd5b505afa158015611e2c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e509190613d59565b91506001816001811115611e6657611e666142ab565b1415611f06576000846001600160a01b031663e6aa216c6040518163ffffffff1660e01b815260040160206040518083038186803b158015611ea757600080fd5b505afa158015611ebb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611edf9190613d59565b905080611ef484670de0b6b3a7640000614194565b611efe9190614087565b925050611f67565b6000816001811115611f1a57611f1a6142ab565b14611f675760405162461bcd60e51b815260206004820152601b60248201527f556e737570706f7274656420636f6e76657273696f6e20747970650000000000604482015260640161079c565b67120a871cc0020000821115611fbf5760405162461bcd60e51b815260206004820152601860248201527f5661756c743a2050726963652065786365656473206d61780000000000000000604482015260640161079c565b6709b6e64a8ec600008210156120105760405162461bcd60e51b81526020600482015260166024820152752b30bab63a1d10283934b1b2903ab73232b91036b4b760511b604482015260640161079c565b821561208757670de0b6b3a764000082111561203257670de0b6b3a764000091505b670dd99bb65dd700008210156120825760405162461bcd60e51b815260206004820152601560248201527441737365742070726963652062656c6f772070656760581b604482015260640161079c565b611daf565b670de0b6b3a7640000821015611daf5750670de0b6b3a76400009392505050565b6040805160808082018352604a546001600160801b038082168452600160801b918290048116602080860191909152604b548083168688015283900482166060808701919091526000888152604c83528781208851968701895280546001600160a01b0381168852600160a01b900460ff1615801594880194909452600101548085169887019890985293909604909116948301949094529261217f5760405162461bcd60e51b815260206004820152600f60248201526e185b1c9958591e4818db185a5b5959608a1b604482015260640161079c565b80516001600160a01b031633146121c85760405162461bcd60e51b815260206004820152600d60248201526c3737ba103932b8bab2b9ba32b960991b604482015260640161079c565b81602001516001600160801b031681606001516001600160801b031611156122d557604960009054906101000a90046001600160a01b03166001600160a01b031663e52253816040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561223a57600080fd5b505af115801561224e573d6000803e3d6000fd5b50505050600061225c612c78565b90508083602001516001600160801b0316612277919061406f565b82606001516001600160801b031611156122d35760405162461bcd60e51b815260206004820152601760248201527f71756575652070656e64696e67206c6971756964697479000000000000000000604482015260640161079c565b505b806040015182604001516122e99190614044565b604b80546001600160801b039283166001600160801b03199091161790556000858152604c6020908152604091829020805460ff60a01b1916600160a01b179055838201518251931683529051869233927f2d43eb174787155132b52ddb6b346e2dca99302eac3df4466dbeff953d3c84d192918290030190a3604001516001600160801b03169392505050565b610bf38363a9059cbb60e01b8484604051602401612396929190613deb565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152612f05565b6001600160a01b0381166124235760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f722069732061646472657373283029000000000000604482015260640161079c565b806001600160a01b031661244360008051602061430e8339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a36109f38160008051602061430e83398151915255565b600061249982612fd7565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b03161415611bf35760408051608081018252604a546001600160801b03808216808452600160801b9283900482166020850152604b54808316958501869052929092041660608301529091612522908461406f565b6108a6919061421a565b60006001600160ff1b0382126125545760405162461bcd60e51b815260040161079c90613f34565b600082121561256b5761256682614278565b610e41565b5090565b6038546060901561259e5760385460009061258e9084906127106131a6565b905061259a818461421a565b9250505b6000607b5490507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316603482815481106125e2576125e26142c1565b6000918252602090912001546001600160a01b0316146126445760405162461bcd60e51b815260206004820152601b60248201527f5745544820417373657420696e646578206e6f74206361636865640000000000604482015260640161079c565b60345467ffffffffffffffff81111561265f5761265f6142d7565b604051908082528060200260200182016040528015612688578160200160208202803683370190505b5091508282828151811061269e5761269e6142c1565b60200260200101818152505050919050565b7f222838db2794d11532d940e8dec38ae307ed0b63cd97c233322e221f998767a633836040516126e1929190613deb565b60405180910390a1816126f2575050565b60006126fd8361256f565b607b5481518110612710576127106142c1565b602002602001015190508181101561276a5760405162461bcd60e51b815260206004820181905260248201527f52656465656d20616d6f756e74206c6f776572207468616e206d696e696d756d604482015260640161079c565b806127736131c8565b106127b1576127ac6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163383612377565b6128bf565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660009081526040602081905290205416801561288357604051636ce5768960e11b81523360048201526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660248301526044820184905282919082169063d9caed1290606401600060405180830381600087803b15801561286557600080fd5b505af1158015612879573d6000803e3d6000fd5b50505050506128bd565b60405162461bcd60e51b815260206004820152600f60248201526e2634b8bab4b234ba3c9032b93937b960891b604482015260640161079c565b505b603c54604051632770a7eb60e21b81526001600160a01b0390911690639dc29fac906128f19033908790600401613deb565b600060405180830381600087803b15801561290b57600080fd5b505af115801561291f573d6000803e3d6000fd5b50505050610bf383613314565b612934612c78565b50610e3461347a565b603754600090600160a01b900460ff161561298c5760405162461bcd60e51b815260206004820152600f60248201526e149958985cda5b99c81c185d5cd959608a1b604482015260640161079c565b603c54604080516318160ddd60e01b815290516000926001600160a01b0316916318160ddd916004808301926020929190829003018186803b1580156129d157600080fd5b505afa1580156129e5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a099190613d59565b90506000612a15612e45565b905081612a25579150612c759050565b6042546001600160a01b03168015801590612a3f57508282115b15612b81576000612a50848461421a565b90506000612a6d604354612710846131a69092919063ffffffff16565b9050808211612ac95760405162461bcd60e51b815260206004820152602260248201527f466565206d757374206e6f742062652067726561746572207468616e207969656044820152611b1960f21b606482015260840161079c565b8015612b3457603c546040516340c10f1960e01b81526001600160a01b03909116906340c10f1990612b019086908590600401613deb565b600060405180830381600087803b158015612b1b57600080fd5b505af1158015612b2f573d6000803e3d6000fd5b505050505b604080516001600160a01b0385168152602081018490529081018290527f09516ecf4a8a86e59780a9befc6dee948bc9e60a36e3be68d31ea817ee8d2c809060600160405180910390a150505b603c60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b158015612bcf57600080fd5b505afa158015612be3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c079190613d59565b925082821115612c7057603c546040516339a7919f60e01b8152600481018490526001600160a01b03909116906339a7919f90602401600060405180830381600087803b158015612c5757600080fd5b505af1158015612c6b573d6000803e3d6000fd5b505050505b509150505b90565b60408051608081018252604a546001600160801b03808216808452600160801b92839004821660208501819052604b5480841696860196909652929094041660608301526000928391612cca916141f2565b6001600160801b031690508015612e40576040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b158015612d3d57600080fd5b505afa158015612d51573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d759190613d59565b9050600083604001518460200151612d8d91906141f2565b6001600160801b0316905080821115612e3d576000612dac828461421a565b9050808410612dbb5780612dbd565b835b955060008686602001516001600160801b0316612dda919061406f565b604a80546001600160801b03808416600160801b0291161790556040519091507fee79a0c43d3993055690b54e074b5153e8bae8d1a872b656dedb64aa8f46333390612e329083908a90918252602082015260400190565b60405180910390a150505b50505b505090565b6000612e4f6136e8565b60408051608081018252604a546001600160801b03808216808452600160801b9283900482166020850152604b54808316958501869052929092041660608301529293509190612e9f908461406f565b612ea9919061421a565b91505090565b6040516001600160a01b0380851660248301528316604482015260648101829052612ee79085906323b872dd60e01b90608401612396565b50505050565b60006108a68284614194565b60006108a68284614087565b6000612f5a826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166137049092919063ffffffff16565b805190915015610bf35780806020019051810190612f789190613d1e565b610bf35760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840161079c565b6040516370a0823160e01b815230600482015260009082906001600160a01b038216906370a082319060240160206040518083038186803b15801561301b57600080fd5b505afa15801561302f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130539190613d59565b60365490925060005b8181101561319e57600060368281548110613079576130796142c1565b60009182526020909120015460405163551c457b60e11b81526001600160a01b0388811660048301529091169150819063aa388af69060240160206040518083038186803b1580156130ca57600080fd5b505afa1580156130de573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131029190613d1e565b1561318d57604051632fa8a91360e11b81526001600160a01b038781166004830152821690635f5152269060240160206040518083038186803b15801561314857600080fd5b505afa15801561315c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131809190613d59565b61318a908661406f565b94505b506131978161425d565b905061305c565b505050919050565b6000806131b38585612eed565b90506131bf8184612ef9565b95945050505050565b60408051608081018252604a546001600160801b03808216808452600160801b92839004821660208501819052604b548084169686019690965292909404166060830152600092839161321a916141f2565b6040516370a0823160e01b81523060048201526001600160801b039190911691506000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a082319060240160206040518083038186803b15801561328a57600080fd5b505afa15801561329e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132c29190613d59565b90506000836040015184602001516132da91906141f2565b6001600160801b031690506132ef818461406f565b821115612e3d5780613301848461421a565b61330b919061421a565b94505050505090565b6000603b5482101580156133325750603754600160a01b900460ff16155b156133465761333f61293d565b9050613351565b61334e612e45565b90505b604154156134765760006133eb82603c60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b1580156133ad57600080fd5b505afa1580156133c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133e59190613d59565b9061371b565b9050604154670de0b6b3a764000082116134165761341182670de0b6b3a764000061421a565b613428565b613428670de0b6b3a76400008361421a565b1115610bf35760405162461bcd60e51b815260206004820152601e60248201527f4261636b696e6720737570706c79206c6971756964697479206572726f720000604482015260640161079c565b5050565b600061348461373c565b90508061348e5750565b6000613498613819565b905060006134a6828461406f565b90506000826134cb576039546134c490670de0b6b3a764000061421a565b9050613508565b83826039546134da9190614194565b6134e49190614087565b905080670de0b6b3a76400001115612ee7576134c481670de0b6b3a764000061421a565b806135135750505050565b60345460005b818110156136e057600060348281548110613536576135366142c1565b60009182526020822001546040516370a0823160e01b81523060048201526001600160a01b03909116925082906370a082319060240160206040518083038186803b15801561358457600080fd5b505afa158015613598573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135bc9190613d59565b9050806135ca5750506136d0565b60006135d68287613875565b6001600160a01b038085166000908152604060208190529020549192501680158015906136035750600082115b156136cb578061361d6001600160a01b0386168285612377565b6040516311f9fbc960e21b81526001600160a01b038216906347e7ef249061364b9088908790600401613deb565b600060405180830381600087803b15801561366557600080fd5b505af1158015613679573d6000803e3d6000fd5b5050604080516001600160a01b03808a168252861660208201529081018690527f41b99659f6ba0803f444aff29e5bf6e26dd86a3219aff92119d69710a956ba8d9250606001905060405180910390a1505b505050505b6136d98161425d565b9050613519565b505050505050565b60006136f2613819565b6136fa61373c565b61076d919061406f565b6060613713848460008561388a565b949350505050565b60008061373084670de0b6b3a7640000612eed565b90506137138184612ef9565b603454600090815b81811015612e4057600060348281548110613761576137616142c1565b60009182526020822001546040516370a0823160e01b81523060048201526001600160a01b03909116925082906370a082319060240160206040518083038186803b1580156137af57600080fd5b505afa1580156137c3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137e79190613d59565b90508015613806576137f98183611c5a565b613803908661406f565b94505b5050806138129061425d565b9050613744565b603654600090815b81811015612e40576138596036828154811061383f5761383f6142c1565b6000918252602090912001546001600160a01b03166139b2565b613863908461406f565b925061386e8161425d565b9050613821565b60006108a68383670de0b6b3a76400006131a6565b6060824710156138eb5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840161079c565b843b6139395760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161079c565b600080866001600160a01b031685876040516139559190613dcf565b60006040518083038185875af1925050503d8060008114613992576040519150601f19603f3d011682016040523d82523d6000602084013e613997565b606091505b50915091506139a7828286613b17565b979650505050505050565b6034546000908290825b8181101561319e576000603482815481106139d9576139d96142c1565b60009182526020909120015460405163551c457b60e11b81526001600160a01b039182166004820181905292509085169063aa388af69060240160206040518083038186803b158015613a2b57600080fd5b505afa158015613a3f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a639190613d1e565b15613b0657604051632fa8a91360e11b81526001600160a01b03828116600483015260009190861690635f5152269060240160206040518083038186803b158015613aad57600080fd5b505afa158015613ac1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ae59190613d59565b90508015613b0457613af78183611c5a565b613b01908761406f565b95505b505b50613b108161425d565b90506139bc565b60608315613b265750816108a6565b825115613b365782518084602001fd5b8160405162461bcd60e51b815260040161079c9190613e86565b828054828255906000526020600020908101928215613ba5579160200282015b82811115613ba557825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190613b70565b5061256b9291505b8082111561256b5760008155600101613bad565b80356001600160a01b0381168114611bf357600080fd5b600060208284031215613bea57600080fd5b6108a682613bc1565b60008060408385031215613c0657600080fd5b613c0f83613bc1565b9150613c1d60208401613bc1565b90509250929050565b600080600060608486031215613c3b57600080fd5b613c4484613bc1565b95602085013595506040909401359392505050565b60006020808385031215613c6c57600080fd5b823567ffffffffffffffff80821115613c8457600080fd5b818501915085601f830112613c9857600080fd5b813581811115613caa57613caa6142d7565b8060051b604051601f19603f83011681018181108582111715613ccf57613ccf6142d7565b604052828152858101935084860182860187018a1015613cee57600080fd5b600095505b83861015613d11578035855260019590950194938601938601613cf3565b5098975050505050505050565b600060208284031215613d3057600080fd5b815180151581146108a657600080fd5b600060208284031215613d5257600080fd5b5035919050565b600060208284031215613d6b57600080fd5b5051919050565b60008060408385031215613d8557600080fd5b50508035926020909101359150565b600081518084526020808501945080840160005b83811015613dc457815187529582019590820190600101613da8565b509495945050505050565b60008251613de1818460208701614231565b9190910192915050565b6001600160a01b03929092168252602082015260400190565b6020808252825182820181905260009190848201906040850190845b81811015613e455783516001600160a01b031683529284019291840191600101613e20565b50909695505050505050565b6020815260006108a66020830184613d94565b604081526000613e776040830185613d94565b90508260208301529392505050565b6020815260008251806020840152613ea5816040850160208701614231565b601f01601f19169190910160400192915050565b60208082526024908201527f43616c6c6572206973206e6f7420746865204f555344206d65746120737472616040820152637465677960e01b606082015260800190565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b6020808252600f908201526e082dadeeadce840e8dede40d0d2ced608b1b604082015260600190565b6020808252600e908201526d10d85c1a5d185b081c185d5cd95960921b604082015260600190565b6020808252600e908201526d1499595b9d1c985b9d0818d85b1b60921b604082015260600190565b8151151581526020820151608082019060028110613fdb57634e487b7160e01b600052602160045260246000fd5b8060208401525060ff604084015116604083015261ffff606084015116606083015292915050565b600080821280156001600160ff1b038490038513161561402557614025614295565b600160ff1b839003841281161561403e5761403e614295565b50500190565b60006001600160801b0380831681851680830382111561406657614066614295565b01949350505050565b6000821982111561408257614082614295565b500190565b6000826140a457634e487b7160e01b600052601260045260246000fd5b500490565b600181815b808511156140e45781600019048211156140ca576140ca614295565b808516156140d757918102915b93841c93908002906140ae565b509250929050565b60006108a6838360008261410257506001610e41565b8161410f57506000610e41565b8160018114614125576002811461412f5761414b565b6001915050610e41565b60ff84111561414057614140614295565b50506001821b610e41565b5060208310610133831016604e8410600b841016171561416e575081810a610e41565b61417883836140a9565b806000190482111561418c5761418c614295565b029392505050565b60008160001904831182151516156141ae576141ae614295565b500290565b60008083128015600160ff1b8501841216156141d1576141d1614295565b6001600160ff1b03840183138116156141ec576141ec614295565b50500390565b60006001600160801b038381169083168181101561421257614212614295565b039392505050565b60008282101561422c5761422c614295565b500390565b60005b8381101561424c578181015183820152602001614234565b83811115612ee75750506000910152565b600060001982141561427157614271614295565b5060010190565b6000600160ff1b82141561428e5761428e614295565b5060000390565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fdfe53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac45357bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa2646970667358221220c50e1d5377ccd0e0207b1b93cdbe2de692420544f1c0bb67494ccf540d5cd0c864736f6c634300080700337bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a", + "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106102bb5760003560e01c806367bd7ba311610182578063ab80dafb116100e9578063c7af3352116100a2578063e45cc9f01161007c578063e45cc9f014610712578063e6cc54321461071b578063f84444361461072f578063fc0cfeee14610742576102bb565b8063c7af3352146106ef578063d38bfff4146106f7578063d4c3eea01461070a576102bb565b8063ab80dafb146106a9578063abaa9916146106bc578063af14052c146106c4578063b888879e146106cc578063b9b17f9f146106df578063c3b28864146106e7576102bb565b8063937b25811161013b578063937b2581146105915780639be918e61461061b5780639ee679e8146106475780639fa1826e1461066f578063a0aead4d14610678578063a403e4d514610680576102bb565b806367bd7ba3146105195780636ec3ab67146105395780637136a7a6146105595780637a2202f31461056c5780637cbc2373146105755780638e510b5214610588576102bb565b8063485cc95511610226578063570d8e1d116101df578063570d8e1d146104b25780635b60f9fc146104c55780635d36b190146104d85780635f515226146104e0578063603ea03b146104f35780636217f3ea14610506576102bb565b8063485cc9551461043557806348e30f541461044857806349c1d54d1461046957806352d38e5d1461047c57806353ca9f241461048557806354c6d858146104a9576102bb565b80632acada4d116102785780632acada4d1461037757806331e19cfa1461038c578063362bd1a3146103945780633b8fe28d146103f35780633fc8cef31461040657806344c547071461042d576102bb565b806309f6442c146103015780630c340a241461031d578063156e29f61461033d57806318ce56bd146103525780631edfe3da14610365578063207134b01461036e575b7fa2bd3d3cf188a41358c8b401076eb59066b09dec5775650c0de4c55187d17bd9366000803760008036600084545af43d6000803e8080156102fc573d6000f35b3d6000fd5b61030a60385481565b6040519081526020015b60405180910390f35b610325610755565b6040516001600160a01b039091168152602001610314565b61035061034b366004613c26565b610772565b005b604554610325906001600160a01b031681565b61030a60395481565b61030a60435481565b61037f6107f0565b6040516103149190613e04565b60365461030a565b604a54604b546103c0916001600160801b0380821692600160801b928390048216928183169291041684565b604080516001600160801b0395861681529385166020850152918416918301919091529091166060820152608001610314565b61030a610401366004613bd8565b610852565b6103257f000000000000000000000000000000000000000000000000000000000000000081565b6103506108ad565b610350610443366004613bf3565b6109f6565b61045b610456366004613c59565b610bf8565b604051610314929190613e64565b604254610325906001600160a01b031681565b61030a603b5481565b60375461049990600160a01b900460ff1681565b6040519015158152602001610314565b61030a607b5481565b603f54610325906001600160a01b031681565b61030a6104d3366004613bd8565b610d67565b610350610d90565b61030a6104ee366004613bd8565b610e36565b604954610325906001600160a01b031681565b610350610514366004613d40565b610e47565b61052c610527366004613d40565b610fde565b6040516103149190613e51565b61054c610547366004613bd8565b610fe9565b6040516103149190613fad565b610350610567366004613d40565b61108f565b61030a60475481565b610350610583366004613d72565b61117a565b61030a60415481565b6105e261059f366004613d40565b604c60205260009081526040902080546001909101546001600160a01b03821691600160a01b900460ff16906001600160801b0380821691600160801b90041684565b604080516001600160a01b03909516855292151560208501526001600160801b0391821692840192909252166060820152608001610314565b610499610629366004613bd8565b6001600160a01b031660009081526033602052604090205460ff1690565b61065a610655366004613d40565b6111ed565b60408051928352602083019190915201610314565b61030a603a5481565b60345461030a565b61032561068e366004613bd8565b6040602081905260009182529020546001600160a01b031681565b6103506106b7366004613d40565b6113e4565b61035061155b565b6103506115ca565b603754610325906001600160a01b031681565b610350611610565b61037f611680565b6104996116e0565b610350610705366004613bd8565b611711565b61030a6117b5565b61030a60465481565b60375461049990600160a81b900460ff1681565b61030a61073d366004613d40565b6117bf565b610350610750366004613bd8565b61186b565b600061076d60008051602061430e8339815191525490565b905090565b603754600160a81b900460ff16156107a55760405162461bcd60e51b815260040161079c90613f5d565b60405180910390fd5b6000805160206142ee833981519152805460028114156107d75760405162461bcd60e51b815260040161079c90613f85565b600282556107e685858561190d565b5060019055505050565b6060603480548060200260200160405190810160405280929190818152602001828054801561084857602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161082a575b5050505050905090565b60008061087b61087561086485611b8e565b670de0b6b3a7640000906012611bf8565b84611c5a565b9050670de0b6b3a764000081610892856001611db6565b61089c9190614194565b6108a69190614087565b9392505050565b6108b56116e0565b6108d15760405162461bcd60e51b815260040161079c90613efd565b60345460005b81811015610951577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166034828154811061091c5761091c6142c1565b6000918252602090912001546001600160a01b0316141561094157607b819055610951565b61094a8161425d565b90506108d7565b507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166034607b5481548110610991576109916142c1565b6000918252602090912001546001600160a01b0316146109f35760405162461bcd60e51b815260206004820152601860248201527f496e76616c6964205745544820417373657420496e6465780000000000000000604482015260640161079c565b50565b6109fe6116e0565b610a1a5760405162461bcd60e51b815260040161079c90613efd565b600054610100900460ff1680610a33575060005460ff16155b610a965760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840161079c565b600054610100900460ff16158015610ab8576000805461ffff19166101011790555b6001600160a01b038316610b0e5760405162461bcd60e51b815260206004820152601d60248201527f507269636550726f76696465722061646472657373206973207a65726f000000604482015260640161079c565b6001600160a01b038216610b5d5760405162461bcd60e51b81526020600482015260166024820152756f546f6b656e2061646472657373206973207a65726f60501b604482015260640161079c565b603c80546001600160a01b038481166001600160a01b031990921691909117909155603780546001600160b01b03191691851691909117600160a81b17905560006038819055603981905569054b40b1f852bda00000603a55683635c9adc5dea00000603b556040805191825260208201908190529051610be091603691613b50565b508015610bf3576000805461ff00191690555b505050565b603754606090600090600160a81b900460ff1615610c285760405162461bcd60e51b815260040161079c90613f5d565b6000805160206142ee83398151915280546002811415610c5a5760405162461bcd60e51b815260040161079c90613f85565b60028255845167ffffffffffffffff811115610c7857610c786142d7565b604051908082528060200260200182016040528015610ca1578160200160208202803683370190505b50935060005b8551811015610d2757610cd2868281518110610cc557610cc56142c1565b60200260200101516120a8565b858281518110610ce457610ce46142c1565b602002602001018181525050848181518110610d0257610d026142c1565b602002602001015184610d15919061406f565b9350610d208161425d565b9050610ca7565b50610d5c6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163385612377565b600182555050915091565b600080610d7961087561086485611b8e565b9050670de0b6b3a764000081610892856000611db6565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b031614610e2b5760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b606482015260840161079c565b610e34336123cd565b565b6000610e418261248e565b92915050565b603754600160a81b900460ff1615610e715760405162461bcd60e51b815260040161079c90613f5d565b6045546001600160a01b03163314610e9b5760405162461bcd60e51b815260040161079c90613eb9565b6001600160ff1b038110610ec15760405162461bcd60e51b815260040161079c90613f34565b7f222838db2794d11532d940e8dec38ae307ed0b63cd97c233322e221f998767a63382604051610ef2929190613deb565b60405180910390a18060466000828254610f0c91906141b3565b9091555050604754604654610f209061252c565b10610f775760405162461bcd60e51b815260206004820152602160248201527f417474656d7074696e6720746f206275726e20746f6f206d756368204f5553446044820152601760f91b606482015260840161079c565b603c54604051632770a7eb60e21b81526001600160a01b0390911690639dc29fac90610fa99033908590600401613deb565b600060405180830381600087803b158015610fc357600080fd5b505af1158015610fd7573d6000803e3d6000fd5b5050505050565b6060610e418261256f565b604080516080808201835260008083526020808401829052838501829052606084018290526001600160a01b038616825260338152908490208451928301909452835460ff808216151584529394929391840191610100909104166001811115611055576110556142ab565b6001811115611066576110666142ab565b8152905462010000810460ff1660208301526301000000900461ffff1660409091015292915050565b603754600160a81b900460ff16156110b95760405162461bcd60e51b815260040161079c90613f5d565b6000805160206142ee833981519152805460028114156110eb5760405162461bcd60e51b815260040161079c90613f85565b60028255603c546040516370a0823160e01b8152336004820152611172916001600160a01b0316906370a082319060240160206040518083038186803b15801561113457600080fd5b505afa158015611148573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061116c9190613d59565b846126b0565b506001905550565b603754600160a81b900460ff16156111a45760405162461bcd60e51b815260040161079c90613f5d565b6000805160206142ee833981519152805460028114156111d65760405162461bcd60e51b815260040161079c90613f85565b600282556111e484846126b0565b50600190555050565b6037546000908190600160a81b900460ff161561121c5760405162461bcd60e51b815260040161079c90613f5d565b6000805160206142ee8339815191528054600281141561124e5760405162461bcd60e51b815260040161079c90613f85565b60028255603c54604051632770a7eb60e21b81526001600160a01b0390911690639dc29fac906112849033908990600401613deb565b600060405180830381600087803b15801561129e57600080fd5b505af11580156112b2573d6000803e3d6000fd5b5050604b54604a546001600160801b03600160801b909204821697506112dc93508892501661406f565b92506112e984600161406f565b604b80546001600160801b03928316600160801b02908316179055604a80549185166001600160801b03199092169190911790556040805186815260208101859052859133917f38e3d972947cfef94205163d483d6287ef27eb312e20cb8e0b13a49989db232e910160405180910390a35060408051608081018252338152600060208083018281526001600160801b03988916848601908152878a1660608601908152898552604c909352949092209251835492511515600160a01b026001600160a81b03199093166001600160a01b039190911617919091178255915191518616600160801b0291909516176001948501559290925591565b603754600160a81b900460ff161561140e5760405162461bcd60e51b815260040161079c90613f5d565b6045546001600160a01b031633146114385760405162461bcd60e51b815260040161079c90613eb9565b6001600160ff1b03811061145e5760405162461bcd60e51b815260040161079c90613f34565b7f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d4121396885338260405161148f929190613deb565b60405180910390a180604660008282546114a99190614003565b90915550506047546046546114bd9061252c565b106115295760405162461bcd60e51b815260206004820152603660248201527f4d696e746564206f75736420737572706173736564206e65744f7573644d696e6044820152753a2337b929ba3930ba32b3bcaa343932b9b437b6321760511b606482015260840161079c565b603c546040516340c10f1960e01b81526001600160a01b03909116906340c10f1990610fa99033908590600401613deb565b603754600160a81b900460ff16156115855760405162461bcd60e51b815260040161079c90613f5d565b6000805160206142ee833981519152805460028114156115b75760405162461bcd60e51b815260040161079c90613f85565b600282556115c361292c565b5060019055565b6000805160206142ee833981519152805460028114156115fc5760405162461bcd60e51b815260040161079c90613f85565b6002825561160861293d565b505060019055565b604960009054906101000a90046001600160a01b03166001600160a01b031663e52253816040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561166057600080fd5b505af1158015611674573d6000803e3d6000fd5b505050506109f3612c78565b60606036805480602002602001604051908101604052809291908181526020018280548015610848576020028201919060005260206000209081546001600160a01b0316815260019091019060200180831161082a575050505050905090565b60006116f860008051602061430e8339815191525490565b6001600160a01b0316336001600160a01b031614905090565b6117196116e0565b6117355760405162461bcd60e51b815260040161079c90613efd565b61175d817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b031661177d60008051602061430e8339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b600061076d612e45565b603754600090600160a81b900460ff16156117ec5760405162461bcd60e51b815260040161079c90613f5d565b6000805160206142ee8339815191528054600281141561181e5760405162461bcd60e51b815260040161079c90613f85565b6002825561182b846120a8565b92506118616001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163385612377565b5060019055919050565b6118736116e0565b61188f5760405162461bcd60e51b815260040161079c90613efd565b803b6118e95760405162461bcd60e51b8152602060048201526024808201527f6e657720696d706c656d656e746174696f6e206973206e6f74206120636f6e746044820152631c9858dd60e21b606482015260840161079c565b7fa2bd3d3cf188a41358c8b401076eb59066b09dec5775650c0de4c55187d17bd955565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316836001600160a01b03161461198e5760405162461bcd60e51b815260206004820152601d60248201527f556e737570706f7274656420617373657420666f72206d696e74696e67000000604482015260640161079c565b600082116119de5760405162461bcd60e51b815260206004820152601d60248201527f416d6f756e74206d7573742062652067726561746572207468616e2030000000604482015260640161079c565b80821015611a2e5760405162461bcd60e51b815260206004820152601e60248201527f4d696e7420616d6f756e74206c6f776572207468616e206d696e696d756d0000604482015260640161079c565b7f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d41213968853383604051611a5f929190613deb565b60405180910390a1603754600160a01b900460ff16158015611a835750603b548210155b15611afa57604960009054906101000a90046001600160a01b03166001600160a01b031663e52253816040518163ffffffff1660e01b8152600401600060405180830381600087803b158015611ad857600080fd5b505af1158015611aec573d6000803e3d6000fd5b50505050611af861293d565b505b603c546040516340c10f1960e01b81526001600160a01b03909116906340c10f1990611b2c9033908690600401613deb565b600060405180830381600087803b158015611b4657600080fd5b505af1158015611b5a573d6000803e3d6000fd5b50611b74925050506001600160a01b038416333085612eaf565b611b7c612c78565b50603a548210610bf357610bf361292c565b6001600160a01b03811660009081526033602052604090205462010000900460ff1680611bf35760405162461bcd60e51b8152602060048201526013602482015272111958da5b585b1cc81b9bdd0818d858da1959606a1b604482015260640161079c565b919050565b600081831115611c2857611c21611c0f838561421a565b611c1a90600a6140ec565b8590612eed565b9350611c52565b81831015611c5257611c4f611c3d848461421a565b611c4890600a6140ec565b8590612ef9565b93505b509192915050565b6001600160a01b038116600090815260336020526040812054610100900460ff1681816001811115611c8e57611c8e6142ab565b1415611cb257611caa6012611ca285611b8e565b869190611bf8565b915050610e41565b6001816001811115611cc657611cc66142ab565b1415611d67576000836001600160a01b031663e6aa216c6040518163ffffffff1660e01b815260040160206040518083038186803b158015611d0757600080fd5b505afa158015611d1b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d3f9190613d59565b9050670de0b6b3a7640000611d548287614194565b611d5e9190614087565b92505050610e41565b60405162461bcd60e51b815260206004820152601b60248201527f556e737570706f7274656420636f6e76657273696f6e20747970650000000000604482015260640161079c565b5092915050565b6001600160a01b038281166000818152603360205260408082205460375491516315d5220f60e31b81526004810194909452919361010090920460ff169291169063aea910789060240160206040518083038186803b158015611e1857600080fd5b505afa158015611e2c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e509190613d59565b91506001816001811115611e6657611e666142ab565b1415611f06576000846001600160a01b031663e6aa216c6040518163ffffffff1660e01b815260040160206040518083038186803b158015611ea757600080fd5b505afa158015611ebb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611edf9190613d59565b905080611ef484670de0b6b3a7640000614194565b611efe9190614087565b925050611f67565b6000816001811115611f1a57611f1a6142ab565b14611f675760405162461bcd60e51b815260206004820152601b60248201527f556e737570706f7274656420636f6e76657273696f6e20747970650000000000604482015260640161079c565b67120a871cc0020000821115611fbf5760405162461bcd60e51b815260206004820152601860248201527f5661756c743a2050726963652065786365656473206d61780000000000000000604482015260640161079c565b6709b6e64a8ec600008210156120105760405162461bcd60e51b81526020600482015260166024820152752b30bab63a1d10283934b1b2903ab73232b91036b4b760511b604482015260640161079c565b821561208757670de0b6b3a764000082111561203257670de0b6b3a764000091505b670dd99bb65dd700008210156120825760405162461bcd60e51b815260206004820152601560248201527441737365742070726963652062656c6f772070656760581b604482015260640161079c565b611daf565b670de0b6b3a7640000821015611daf5750670de0b6b3a76400009392505050565b6040805160808082018352604a546001600160801b038082168452600160801b918290048116602080860191909152604b548083168688015283900482166060808701919091526000888152604c83528781208851968701895280546001600160a01b0381168852600160a01b900460ff1615801594880194909452600101548085169887019890985293909604909116948301949094529261217f5760405162461bcd60e51b815260206004820152600f60248201526e185b1c9958591e4818db185a5b5959608a1b604482015260640161079c565b80516001600160a01b031633146121c85760405162461bcd60e51b815260206004820152600d60248201526c3737ba103932b8bab2b9ba32b960991b604482015260640161079c565b81602001516001600160801b031681606001516001600160801b031611156122d557604960009054906101000a90046001600160a01b03166001600160a01b031663e52253816040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561223a57600080fd5b505af115801561224e573d6000803e3d6000fd5b50505050600061225c612c78565b90508083602001516001600160801b0316612277919061406f565b82606001516001600160801b031611156122d35760405162461bcd60e51b815260206004820152601760248201527f71756575652070656e64696e67206c6971756964697479000000000000000000604482015260640161079c565b505b806040015182604001516122e99190614044565b604b80546001600160801b039283166001600160801b03199091161790556000858152604c6020908152604091829020805460ff60a01b1916600160a01b179055838201518251931683529051869233927f2d43eb174787155132b52ddb6b346e2dca99302eac3df4466dbeff953d3c84d192918290030190a3604001516001600160801b03169392505050565b610bf38363a9059cbb60e01b8484604051602401612396929190613deb565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152612f05565b6001600160a01b0381166124235760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f722069732061646472657373283029000000000000604482015260640161079c565b806001600160a01b031661244360008051602061430e8339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a36109f38160008051602061430e83398151915255565b600061249982612fd7565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b03161415611bf35760408051608081018252604a546001600160801b03808216808452600160801b9283900482166020850152604b54808316958501869052929092041660608301529091612522908461406f565b6108a6919061421a565b60006001600160ff1b0382126125545760405162461bcd60e51b815260040161079c90613f34565b600082121561256b5761256682614278565b610e41565b5090565b6038546060901561259e5760385460009061258e9084906127106131a6565b905061259a818461421a565b9250505b6000607b5490507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316603482815481106125e2576125e26142c1565b6000918252602090912001546001600160a01b0316146126445760405162461bcd60e51b815260206004820152601b60248201527f5745544820417373657420696e646578206e6f74206361636865640000000000604482015260640161079c565b60345467ffffffffffffffff81111561265f5761265f6142d7565b604051908082528060200260200182016040528015612688578160200160208202803683370190505b5091508282828151811061269e5761269e6142c1565b60200260200101818152505050919050565b7f222838db2794d11532d940e8dec38ae307ed0b63cd97c233322e221f998767a633836040516126e1929190613deb565b60405180910390a1816126f2575050565b60006126fd8361256f565b607b5481518110612710576127106142c1565b602002602001015190508181101561276a5760405162461bcd60e51b815260206004820181905260248201527f52656465656d20616d6f756e74206c6f776572207468616e206d696e696d756d604482015260640161079c565b806127736131c8565b106127b1576127ac6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163383612377565b6128bf565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660009081526040602081905290205416801561288357604051636ce5768960e11b81523360048201526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660248301526044820184905282919082169063d9caed1290606401600060405180830381600087803b15801561286557600080fd5b505af1158015612879573d6000803e3d6000fd5b50505050506128bd565b60405162461bcd60e51b815260206004820152600f60248201526e2634b8bab4b234ba3c9032b93937b960891b604482015260640161079c565b505b603c54604051632770a7eb60e21b81526001600160a01b0390911690639dc29fac906128f19033908790600401613deb565b600060405180830381600087803b15801561290b57600080fd5b505af115801561291f573d6000803e3d6000fd5b50505050610bf383613314565b612934612c78565b50610e3461347a565b603754600090600160a01b900460ff161561298c5760405162461bcd60e51b815260206004820152600f60248201526e149958985cda5b99c81c185d5cd959608a1b604482015260640161079c565b603c54604080516318160ddd60e01b815290516000926001600160a01b0316916318160ddd916004808301926020929190829003018186803b1580156129d157600080fd5b505afa1580156129e5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a099190613d59565b90506000612a15612e45565b905081612a25579150612c759050565b6042546001600160a01b03168015801590612a3f57508282115b15612b81576000612a50848461421a565b90506000612a6d604354612710846131a69092919063ffffffff16565b9050808211612ac95760405162461bcd60e51b815260206004820152602260248201527f466565206d757374206e6f742062652067726561746572207468616e207969656044820152611b1960f21b606482015260840161079c565b8015612b3457603c546040516340c10f1960e01b81526001600160a01b03909116906340c10f1990612b019086908590600401613deb565b600060405180830381600087803b158015612b1b57600080fd5b505af1158015612b2f573d6000803e3d6000fd5b505050505b604080516001600160a01b0385168152602081018490529081018290527f09516ecf4a8a86e59780a9befc6dee948bc9e60a36e3be68d31ea817ee8d2c809060600160405180910390a150505b603c60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b158015612bcf57600080fd5b505afa158015612be3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c079190613d59565b925082821115612c7057603c546040516339a7919f60e01b8152600481018490526001600160a01b03909116906339a7919f90602401600060405180830381600087803b158015612c5757600080fd5b505af1158015612c6b573d6000803e3d6000fd5b505050505b509150505b90565b60408051608081018252604a546001600160801b03808216808452600160801b92839004821660208501819052604b5480841696860196909652929094041660608301526000928391612cca916141f2565b6001600160801b031690508015612e40576040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b158015612d3d57600080fd5b505afa158015612d51573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d759190613d59565b9050600083604001518460200151612d8d91906141f2565b6001600160801b0316905080821115612e3d576000612dac828461421a565b9050808410612dbb5780612dbd565b835b955060008686602001516001600160801b0316612dda919061406f565b604a80546001600160801b03808416600160801b0291161790556040519091507fee79a0c43d3993055690b54e074b5153e8bae8d1a872b656dedb64aa8f46333390612e329083908a90918252602082015260400190565b60405180910390a150505b50505b505090565b6000612e4f6136e8565b60408051608081018252604a546001600160801b03808216808452600160801b9283900482166020850152604b54808316958501869052929092041660608301529293509190612e9f908461406f565b612ea9919061421a565b91505090565b6040516001600160a01b0380851660248301528316604482015260648101829052612ee79085906323b872dd60e01b90608401612396565b50505050565b60006108a68284614194565b60006108a68284614087565b6000612f5a826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166137049092919063ffffffff16565b805190915015610bf35780806020019051810190612f789190613d1e565b610bf35760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840161079c565b6040516370a0823160e01b815230600482015260009082906001600160a01b038216906370a082319060240160206040518083038186803b15801561301b57600080fd5b505afa15801561302f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130539190613d59565b60365490925060005b8181101561319e57600060368281548110613079576130796142c1565b60009182526020909120015460405163551c457b60e11b81526001600160a01b0388811660048301529091169150819063aa388af69060240160206040518083038186803b1580156130ca57600080fd5b505afa1580156130de573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131029190613d1e565b1561318d57604051632fa8a91360e11b81526001600160a01b038781166004830152821690635f5152269060240160206040518083038186803b15801561314857600080fd5b505afa15801561315c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131809190613d59565b61318a908661406f565b94505b506131978161425d565b905061305c565b505050919050565b6000806131b38585612eed565b90506131bf8184612ef9565b95945050505050565b60408051608081018252604a546001600160801b03808216808452600160801b92839004821660208501819052604b548084169686019690965292909404166060830152600092839161321a916141f2565b6040516370a0823160e01b81523060048201526001600160801b039190911691506000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a082319060240160206040518083038186803b15801561328a57600080fd5b505afa15801561329e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132c29190613d59565b90506000836040015184602001516132da91906141f2565b6001600160801b031690506132ef818461406f565b821115612e3d5780613301848461421a565b61330b919061421a565b94505050505090565b6000603b5482101580156133325750603754600160a01b900460ff16155b156133465761333f61293d565b9050613351565b61334e612e45565b90505b604154156134765760006133eb82603c60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b1580156133ad57600080fd5b505afa1580156133c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133e59190613d59565b9061371b565b9050604154670de0b6b3a764000082116134165761341182670de0b6b3a764000061421a565b613428565b613428670de0b6b3a76400008361421a565b1115610bf35760405162461bcd60e51b815260206004820152601e60248201527f4261636b696e6720737570706c79206c6971756964697479206572726f720000604482015260640161079c565b5050565b600061348461373c565b90508061348e5750565b6000613498613819565b905060006134a6828461406f565b90506000826134cb576039546134c490670de0b6b3a764000061421a565b9050613508565b83826039546134da9190614194565b6134e49190614087565b905080670de0b6b3a76400001115612ee7576134c481670de0b6b3a764000061421a565b806135135750505050565b60345460005b818110156136e057600060348281548110613536576135366142c1565b60009182526020822001546040516370a0823160e01b81523060048201526001600160a01b03909116925082906370a082319060240160206040518083038186803b15801561358457600080fd5b505afa158015613598573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135bc9190613d59565b9050806135ca5750506136d0565b60006135d68287613875565b6001600160a01b038085166000908152604060208190529020549192501680158015906136035750600082115b156136cb578061361d6001600160a01b0386168285612377565b6040516311f9fbc960e21b81526001600160a01b038216906347e7ef249061364b9088908790600401613deb565b600060405180830381600087803b15801561366557600080fd5b505af1158015613679573d6000803e3d6000fd5b5050604080516001600160a01b03808a168252861660208201529081018690527f41b99659f6ba0803f444aff29e5bf6e26dd86a3219aff92119d69710a956ba8d9250606001905060405180910390a1505b505050505b6136d98161425d565b9050613519565b505050505050565b60006136f2613819565b6136fa61373c565b61076d919061406f565b6060613713848460008561388a565b949350505050565b60008061373084670de0b6b3a7640000612eed565b90506137138184612ef9565b603454600090815b81811015612e4057600060348281548110613761576137616142c1565b60009182526020822001546040516370a0823160e01b81523060048201526001600160a01b03909116925082906370a082319060240160206040518083038186803b1580156137af57600080fd5b505afa1580156137c3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137e79190613d59565b90508015613806576137f98183611c5a565b613803908661406f565b94505b5050806138129061425d565b9050613744565b603654600090815b81811015612e40576138596036828154811061383f5761383f6142c1565b6000918252602090912001546001600160a01b03166139b2565b613863908461406f565b925061386e8161425d565b9050613821565b60006108a68383670de0b6b3a76400006131a6565b6060824710156138eb5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840161079c565b843b6139395760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161079c565b600080866001600160a01b031685876040516139559190613dcf565b60006040518083038185875af1925050503d8060008114613992576040519150601f19603f3d011682016040523d82523d6000602084013e613997565b606091505b50915091506139a7828286613b17565b979650505050505050565b6034546000908290825b8181101561319e576000603482815481106139d9576139d96142c1565b60009182526020909120015460405163551c457b60e11b81526001600160a01b039182166004820181905292509085169063aa388af69060240160206040518083038186803b158015613a2b57600080fd5b505afa158015613a3f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a639190613d1e565b15613b0657604051632fa8a91360e11b81526001600160a01b03828116600483015260009190861690635f5152269060240160206040518083038186803b158015613aad57600080fd5b505afa158015613ac1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ae59190613d59565b90508015613b0457613af78183611c5a565b613b01908761406f565b95505b505b50613b108161425d565b90506139bc565b60608315613b265750816108a6565b825115613b365782518084602001fd5b8160405162461bcd60e51b815260040161079c9190613e86565b828054828255906000526020600020908101928215613ba5579160200282015b82811115613ba557825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190613b70565b5061256b9291505b8082111561256b5760008155600101613bad565b80356001600160a01b0381168114611bf357600080fd5b600060208284031215613bea57600080fd5b6108a682613bc1565b60008060408385031215613c0657600080fd5b613c0f83613bc1565b9150613c1d60208401613bc1565b90509250929050565b600080600060608486031215613c3b57600080fd5b613c4484613bc1565b95602085013595506040909401359392505050565b60006020808385031215613c6c57600080fd5b823567ffffffffffffffff80821115613c8457600080fd5b818501915085601f830112613c9857600080fd5b813581811115613caa57613caa6142d7565b8060051b604051601f19603f83011681018181108582111715613ccf57613ccf6142d7565b604052828152858101935084860182860187018a1015613cee57600080fd5b600095505b83861015613d11578035855260019590950194938601938601613cf3565b5098975050505050505050565b600060208284031215613d3057600080fd5b815180151581146108a657600080fd5b600060208284031215613d5257600080fd5b5035919050565b600060208284031215613d6b57600080fd5b5051919050565b60008060408385031215613d8557600080fd5b50508035926020909101359150565b600081518084526020808501945080840160005b83811015613dc457815187529582019590820190600101613da8565b509495945050505050565b60008251613de1818460208701614231565b9190910192915050565b6001600160a01b03929092168252602082015260400190565b6020808252825182820181905260009190848201906040850190845b81811015613e455783516001600160a01b031683529284019291840191600101613e20565b50909695505050505050565b6020815260006108a66020830184613d94565b604081526000613e776040830185613d94565b90508260208301529392505050565b6020815260008251806020840152613ea5816040850160208701614231565b601f01601f19169190910160400192915050565b60208082526024908201527f43616c6c6572206973206e6f7420746865204f555344206d65746120737472616040820152637465677960e01b606082015260800190565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b6020808252600f908201526e082dadeeadce840e8dede40d0d2ced608b1b604082015260600190565b6020808252600e908201526d10d85c1a5d185b081c185d5cd95960921b604082015260600190565b6020808252600e908201526d1499595b9d1c985b9d0818d85b1b60921b604082015260600190565b8151151581526020820151608082019060028110613fdb57634e487b7160e01b600052602160045260246000fd5b8060208401525060ff604084015116604083015261ffff606084015116606083015292915050565b600080821280156001600160ff1b038490038513161561402557614025614295565b600160ff1b839003841281161561403e5761403e614295565b50500190565b60006001600160801b0380831681851680830382111561406657614066614295565b01949350505050565b6000821982111561408257614082614295565b500190565b6000826140a457634e487b7160e01b600052601260045260246000fd5b500490565b600181815b808511156140e45781600019048211156140ca576140ca614295565b808516156140d757918102915b93841c93908002906140ae565b509250929050565b60006108a6838360008261410257506001610e41565b8161410f57506000610e41565b8160018114614125576002811461412f5761414b565b6001915050610e41565b60ff84111561414057614140614295565b50506001821b610e41565b5060208310610133831016604e8410600b841016171561416e575081810a610e41565b61417883836140a9565b806000190482111561418c5761418c614295565b029392505050565b60008160001904831182151516156141ae576141ae614295565b500290565b60008083128015600160ff1b8501841216156141d1576141d1614295565b6001600160ff1b03840183138116156141ec576141ec614295565b50500390565b60006001600160801b038381169083168181101561421257614212614295565b039392505050565b60008282101561422c5761422c614295565b500390565b60005b8381101561424c578181015183820152602001614234565b83811115612ee75750506000910152565b600060001982141561427157614271614295565b5060010190565b6000600160ff1b82141561428e5761428e614295565b5060000390565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fdfe53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac45357bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa2646970667358221220c50e1d5377ccd0e0207b1b93cdbe2de692420544f1c0bb67494ccf540d5cd0c864736f6c63430008070033", "libraries": {}, "devdoc": { "author": "Origin Protocol Inc", "kind": "dev", "methods": { + "addWithdrawalQueueLiquidity()": { + "details": "is called from the Native Staking strategy when validator withdrawals are processed. It also called before any WETH is allocated to a strategy." + }, "burnForStrategy(uint256)": { "details": "Notice: can't use `nonReentrant` modifier since the `redeem` function could require withdrawal on `ConvexOUSDMetaStrategy` and that one can call `burnForStrategy` while the execution of the `redeem` has not yet completed -> causing a `nonReentrant` collision. Also important to understand is that this is a limitation imposed by the test suite. Production / mainnet contracts should never be configured in a way where mint/redeem functions that are moving funds between the Vault and end user wallets can influence strategies utilizing this function.", "params": { @@ -1111,6 +1364,22 @@ "_0": "uint256 Balance of asset in decimals of asset" } }, + "claimWithdrawal(uint256)": { + "params": { + "requestId": "Unique ID for the withdrawal request" + }, + "returns": { + "amount": "Amount of WETH transferred to the withdrawer" + } + }, + "claimWithdrawals(uint256[])": { + "params": { + "requestIds": "Unique ID of each withdrawal request" + }, + "returns": { + "amounts": "Amount of WETH received for each request" + } + }, "isSupportedAsset(address)": { "params": { "_asset": "address of the asset" @@ -1158,6 +1427,13 @@ "_minimumUnitAmount": "Minimum stablecoin units to receive in return" } }, + "requestWithdrawal(uint256)": { + "params": { + "_amount": "Amount of oTokens to burn. eg OETH", + "queued": "Cumulative total of all WETH queued including already claimed requests. This request can be claimed once the withdrawal queue's claimable amount is greater than or equal this request's queued amount.", + "requestId": "Unique ID for the withdrawal request" + } + }, "setAdminImpl(address)": { "params": { "newImpl": "address of the implementation" @@ -1180,6 +1456,9 @@ "userdoc": { "kind": "user", "methods": { + "addWithdrawalQueueLiquidity()": { + "notice": "Collects harvested rewards from the Dripper as WETH then adds WETH to the withdrawal queue if there is a funding shortfall." + }, "allocate()": { "notice": "Allocate unallocated funds on Vault to strategies.*" }, @@ -1204,6 +1483,15 @@ "claimGovernance()": { "notice": "Claim Governance of the contract to a new account (`newGovernor`). Can only be called by the new Governor." }, + "claimWithdrawal(uint256)": { + "notice": "Claim a previously requested withdrawal once it is claimable." + }, + "claimWithdrawals(uint256[])": { + "notice": "Claim a previously requested withdrawals once they are claimable." + }, + "dripper()": { + "notice": "Address of the Dripper contract that streams harvested rewards to the Vault" + }, "getAllAssets()": { "notice": "Return all vault asset addresses in order" }, @@ -1273,6 +1561,9 @@ "redeemFeeBps()": { "notice": "Redemption fee in basis points. eg 50 = 0.5%" }, + "requestWithdrawal(uint256)": { + "notice": "Request an asynchronous withdrawal of the underlying asset. eg WETH" + }, "setAdminImpl(address)": { "notice": "set the implementation for the admin, this needs to be in a base class else we cannot set it" }, @@ -1300,7 +1591,7 @@ "storageLayout": { "storage": [ { - "astId": 41419, + "astId": 24111, "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", "label": "initialized", "offset": 0, @@ -1308,7 +1599,7 @@ "type": "t_bool" }, { - "astId": 41422, + "astId": 24114, "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", "label": "initializing", "offset": 1, @@ -1316,7 +1607,7 @@ "type": "t_bool" }, { - "astId": 41462, + "astId": 24154, "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", "label": "______gap", "offset": 0, @@ -1324,15 +1615,15 @@ "type": "t_array(t_uint256)50_storage" }, { - "astId": 46069, + "astId": 29745, "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", "label": "assets", "offset": 0, "slot": "51", - "type": "t_mapping(t_address,t_struct(Asset)46063_storage)" + "type": "t_mapping(t_address,t_struct(Asset)29739_storage)" }, { - "astId": 46073, + "astId": 29749, "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", "label": "allAssets", "offset": 0, @@ -1340,15 +1631,15 @@ "type": "t_array(t_address)dyn_storage" }, { - "astId": 46084, + "astId": 29760, "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", "label": "strategies", "offset": 0, "slot": "53", - "type": "t_mapping(t_address,t_struct(Strategy)46078_storage)" + "type": "t_mapping(t_address,t_struct(Strategy)29754_storage)" }, { - "astId": 46088, + "astId": 29764, "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", "label": "allStrategies", "offset": 0, @@ -1356,7 +1647,7 @@ "type": "t_array(t_address)dyn_storage" }, { - "astId": 46091, + "astId": 29767, "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", "label": "priceProvider", "offset": 0, @@ -1364,7 +1655,7 @@ "type": "t_address" }, { - "astId": 46095, + "astId": 29771, "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", "label": "rebasePaused", "offset": 20, @@ -1372,7 +1663,7 @@ "type": "t_bool" }, { - "astId": 46099, + "astId": 29775, "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", "label": "capitalPaused", "offset": 21, @@ -1380,7 +1671,7 @@ "type": "t_bool" }, { - "astId": 46102, + "astId": 29778, "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", "label": "redeemFeeBps", "offset": 0, @@ -1388,7 +1679,7 @@ "type": "t_uint256" }, { - "astId": 46105, + "astId": 29781, "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", "label": "vaultBuffer", "offset": 0, @@ -1396,7 +1687,7 @@ "type": "t_uint256" }, { - "astId": 46108, + "astId": 29784, "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", "label": "autoAllocateThreshold", "offset": 0, @@ -1404,7 +1695,7 @@ "type": "t_uint256" }, { - "astId": 46111, + "astId": 29787, "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", "label": "rebaseThreshold", "offset": 0, @@ -1412,15 +1703,15 @@ "type": "t_uint256" }, { - "astId": 46115, + "astId": 29791, "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", "label": "oUSD", "offset": 0, "slot": "60", - "type": "t_contract(OUSD)40245" + "type": "t_contract(OUSD)23477" }, { - "astId": 46124, + "astId": 29800, "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", "label": "_deprecated_rebaseHooksAddr", "offset": 0, @@ -1428,7 +1719,7 @@ "type": "t_address" }, { - "astId": 46130, + "astId": 29806, "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", "label": "_deprecated_uniswapAddr", "offset": 0, @@ -1436,7 +1727,7 @@ "type": "t_address" }, { - "astId": 46137, + "astId": 29813, "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", "label": "strategistAddr", "offset": 0, @@ -1444,7 +1735,7 @@ "type": "t_address" }, { - "astId": 46142, + "astId": 29818, "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", "label": "assetDefaultStrategies", "offset": 0, @@ -1452,7 +1743,7 @@ "type": "t_mapping(t_address,t_address)" }, { - "astId": 46145, + "astId": 29821, "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", "label": "maxSupplyDiff", "offset": 0, @@ -1460,7 +1751,7 @@ "type": "t_uint256" }, { - "astId": 46148, + "astId": 29824, "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", "label": "trusteeAddress", "offset": 0, @@ -1468,7 +1759,7 @@ "type": "t_address" }, { - "astId": 46151, + "astId": 29827, "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", "label": "trusteeFeeBps", "offset": 0, @@ -1476,7 +1767,7 @@ "type": "t_uint256" }, { - "astId": 46155, + "astId": 29831, "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", "label": "_deprecated_swapTokens", "offset": 0, @@ -1484,7 +1775,7 @@ "type": "t_array(t_address)dyn_storage" }, { - "astId": 46165, + "astId": 29841, "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", "label": "ousdMetaStrategy", "offset": 0, @@ -1492,7 +1783,7 @@ "type": "t_address" }, { - "astId": 46169, + "astId": 29845, "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", "label": "netOusdMintedForStrategy", "offset": 0, @@ -1500,7 +1791,7 @@ "type": "t_int256" }, { - "astId": 46173, + "astId": 29849, "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", "label": "netOusdMintForStrategyThreshold", "offset": 0, @@ -1508,23 +1799,47 @@ "type": "t_uint256" }, { - "astId": 46194, + "astId": 29870, "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", "label": "swapConfig", "offset": 0, "slot": "72", - "type": "t_struct(SwapConfig)46184_storage" + "type": "t_struct(SwapConfig)29860_storage" }, { - "astId": 46198, + "astId": 29873, "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", - "label": "__gap", + "label": "dripper", "offset": 0, "slot": "73", - "type": "t_array(t_uint256)50_storage" + "type": "t_address" + }, + { + "astId": 29885, + "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", + "label": "withdrawalQueueMetadata", + "offset": 0, + "slot": "74", + "type": "t_struct(WithdrawalQueueMetadata)29882_storage" }, { - "astId": 42360, + "astId": 29899, + "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", + "label": "withdrawalRequests", + "offset": 0, + "slot": "76", + "type": "t_mapping(t_uint256,t_struct(WithdrawalRequest)29894_storage)" + }, + { + "astId": 29903, + "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", + "label": "__gap", + "offset": 0, + "slot": "77", + "type": "t_array(t_uint256)46_storage" + }, + { + "astId": 25324, "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", "label": "wethAssetIndex", "offset": 0, @@ -1544,6 +1859,12 @@ "label": "address[]", "numberOfBytes": "32" }, + "t_array(t_uint256)46_storage": { + "base": "t_uint256", + "encoding": "inplace", + "label": "uint256[46]", + "numberOfBytes": "1472" + }, "t_array(t_uint256)50_storage": { "base": "t_uint256", "encoding": "inplace", @@ -1555,12 +1876,12 @@ "label": "bool", "numberOfBytes": "1" }, - "t_contract(OUSD)40245": { + "t_contract(OUSD)23477": { "encoding": "inplace", "label": "contract OUSD", "numberOfBytes": "20" }, - "t_enum(UnitConversion)46053": { + "t_enum(UnitConversion)29729": { "encoding": "inplace", "label": "enum VaultStorage.UnitConversion", "numberOfBytes": "1" @@ -1577,26 +1898,33 @@ "numberOfBytes": "32", "value": "t_address" }, - "t_mapping(t_address,t_struct(Asset)46063_storage)": { + "t_mapping(t_address,t_struct(Asset)29739_storage)": { "encoding": "mapping", "key": "t_address", "label": "mapping(address => struct VaultStorage.Asset)", "numberOfBytes": "32", - "value": "t_struct(Asset)46063_storage" + "value": "t_struct(Asset)29739_storage" }, - "t_mapping(t_address,t_struct(Strategy)46078_storage)": { + "t_mapping(t_address,t_struct(Strategy)29754_storage)": { "encoding": "mapping", "key": "t_address", "label": "mapping(address => struct VaultStorage.Strategy)", "numberOfBytes": "32", - "value": "t_struct(Strategy)46078_storage" + "value": "t_struct(Strategy)29754_storage" }, - "t_struct(Asset)46063_storage": { + "t_mapping(t_uint256,t_struct(WithdrawalRequest)29894_storage)": { + "encoding": "mapping", + "key": "t_uint256", + "label": "mapping(uint256 => struct VaultStorage.WithdrawalRequest)", + "numberOfBytes": "32", + "value": "t_struct(WithdrawalRequest)29894_storage" + }, + "t_struct(Asset)29739_storage": { "encoding": "inplace", "label": "struct VaultStorage.Asset", "members": [ { - "astId": 46055, + "astId": 29731, "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", "label": "isSupported", "offset": 0, @@ -1604,15 +1932,15 @@ "type": "t_bool" }, { - "astId": 46058, + "astId": 29734, "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", "label": "unitConversion", "offset": 1, "slot": "0", - "type": "t_enum(UnitConversion)46053" + "type": "t_enum(UnitConversion)29729" }, { - "astId": 46060, + "astId": 29736, "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", "label": "decimals", "offset": 2, @@ -1620,7 +1948,7 @@ "type": "t_uint8" }, { - "astId": 46062, + "astId": 29738, "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", "label": "allowedOracleSlippageBps", "offset": 3, @@ -1630,12 +1958,12 @@ ], "numberOfBytes": "32" }, - "t_struct(Strategy)46078_storage": { + "t_struct(Strategy)29754_storage": { "encoding": "inplace", "label": "struct VaultStorage.Strategy", "members": [ { - "astId": 46075, + "astId": 29751, "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", "label": "isSupported", "offset": 0, @@ -1643,7 +1971,7 @@ "type": "t_bool" }, { - "astId": 46077, + "astId": 29753, "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", "label": "_deprecated", "offset": 0, @@ -1653,12 +1981,12 @@ ], "numberOfBytes": "64" }, - "t_struct(SwapConfig)46184_storage": { + "t_struct(SwapConfig)29860_storage": { "encoding": "inplace", "label": "struct VaultStorage.SwapConfig", "members": [ { - "astId": 46181, + "astId": 29857, "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", "label": "swapper", "offset": 0, @@ -1666,7 +1994,7 @@ "type": "t_address" }, { - "astId": 46183, + "astId": 29859, "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", "label": "allowedUndervalueBps", "offset": 20, @@ -1676,6 +2004,89 @@ ], "numberOfBytes": "32" }, + "t_struct(WithdrawalQueueMetadata)29882_storage": { + "encoding": "inplace", + "label": "struct VaultStorage.WithdrawalQueueMetadata", + "members": [ + { + "astId": 29875, + "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", + "label": "queued", + "offset": 0, + "slot": "0", + "type": "t_uint128" + }, + { + "astId": 29877, + "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", + "label": "claimable", + "offset": 16, + "slot": "0", + "type": "t_uint128" + }, + { + "astId": 29879, + "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", + "label": "claimed", + "offset": 0, + "slot": "1", + "type": "t_uint128" + }, + { + "astId": 29881, + "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", + "label": "nextWithdrawalIndex", + "offset": 16, + "slot": "1", + "type": "t_uint128" + } + ], + "numberOfBytes": "64" + }, + "t_struct(WithdrawalRequest)29894_storage": { + "encoding": "inplace", + "label": "struct VaultStorage.WithdrawalRequest", + "members": [ + { + "astId": 29887, + "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", + "label": "withdrawer", + "offset": 0, + "slot": "0", + "type": "t_address" + }, + { + "astId": 29889, + "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", + "label": "claimed", + "offset": 20, + "slot": "0", + "type": "t_bool" + }, + { + "astId": 29891, + "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", + "label": "amount", + "offset": 0, + "slot": "1", + "type": "t_uint128" + }, + { + "astId": 29893, + "contract": "contracts/vault/OETHVaultCore.sol:OETHVaultCore", + "label": "queued", + "offset": 16, + "slot": "1", + "type": "t_uint128" + } + ], + "numberOfBytes": "64" + }, + "t_uint128": { + "encoding": "inplace", + "label": "uint128", + "numberOfBytes": "16" + }, "t_uint16": { "encoding": "inplace", "label": "uint16", diff --git a/contracts/deployments/holesky/solcInputs/9b811e7a632431f9f724307daee2b897.json b/contracts/deployments/holesky/solcInputs/9b811e7a632431f9f724307daee2b897.json new file mode 100644 index 0000000000..fcd56c8ae6 --- /dev/null +++ b/contracts/deployments/holesky/solcInputs/9b811e7a632431f9f724307daee2b897.json @@ -0,0 +1,344 @@ +{ + "language": "Solidity", + "sources": { + "@openzeppelin/contracts/security/Pausable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (security/Pausable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which allows children to implement an emergency stop\n * mechanism that can be triggered by an authorized account.\n *\n * This module is used through inheritance. It will make available the\n * modifiers `whenNotPaused` and `whenPaused`, which can be applied to\n * the functions of your contract. Note that they will not be pausable by\n * simply including this module, only once the modifiers are put in place.\n */\nabstract contract Pausable is Context {\n /**\n * @dev Emitted when the pause is triggered by `account`.\n */\n event Paused(address account);\n\n /**\n * @dev Emitted when the pause is lifted by `account`.\n */\n event Unpaused(address account);\n\n bool private _paused;\n\n /**\n * @dev Initializes the contract in unpaused state.\n */\n constructor() {\n _paused = false;\n }\n\n /**\n * @dev Returns true if the contract is paused, and false otherwise.\n */\n function paused() public view virtual returns (bool) {\n return _paused;\n }\n\n /**\n * @dev Modifier to make a function callable only when the contract is not paused.\n *\n * Requirements:\n *\n * - The contract must not be paused.\n */\n modifier whenNotPaused() {\n require(!paused(), \"Pausable: paused\");\n _;\n }\n\n /**\n * @dev Modifier to make a function callable only when the contract is paused.\n *\n * Requirements:\n *\n * - The contract must be paused.\n */\n modifier whenPaused() {\n require(paused(), \"Pausable: not paused\");\n _;\n }\n\n /**\n * @dev Triggers stopped state.\n *\n * Requirements:\n *\n * - The contract must not be paused.\n */\n function _pause() internal virtual whenNotPaused {\n _paused = true;\n emit Paused(_msgSender());\n }\n\n /**\n * @dev Returns to normal state.\n *\n * Requirements:\n *\n * - The contract must be paused.\n */\n function _unpause() internal virtual whenPaused {\n _paused = false;\n emit Unpaused(_msgSender());\n }\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/ERC20.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n string private _name;\n string private _symbol;\n\n /**\n * @dev Sets the values for {name} and {symbol}.\n *\n * The default value of {decimals} is 18. To select a different value for\n * {decimals} you should overload it.\n *\n * All two of these values are immutable: they can only be set once during\n * construction.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\n * overridden;\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view virtual override returns (uint8) {\n return 18;\n }\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view virtual override returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view virtual override returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `recipient` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address recipient, uint256 amount) public virtual override returns (bool) {\n _transfer(_msgSender(), recipient, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\n _approve(_msgSender(), spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20}.\n *\n * Requirements:\n *\n * - `sender` and `recipient` cannot be the zero address.\n * - `sender` must have a balance of at least `amount`.\n * - the caller must have allowance for ``sender``'s tokens of at least\n * `amount`.\n */\n function transferFrom(\n address sender,\n address recipient,\n uint256 amount\n ) public virtual override returns (bool) {\n _transfer(sender, recipient, amount);\n\n uint256 currentAllowance = _allowances[sender][_msgSender()];\n require(currentAllowance >= amount, \"ERC20: transfer amount exceeds allowance\");\n unchecked {\n _approve(sender, _msgSender(), currentAllowance - amount);\n }\n\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n _approve(_msgSender(), spender, _allowances[_msgSender()][spender] + addedValue);\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n uint256 currentAllowance = _allowances[_msgSender()][spender];\n require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n unchecked {\n _approve(_msgSender(), spender, currentAllowance - subtractedValue);\n }\n\n return true;\n }\n\n /**\n * @dev Moves `amount` of tokens from `sender` to `recipient`.\n *\n * This internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `sender` cannot be the zero address.\n * - `recipient` cannot be the zero address.\n * - `sender` must have a balance of at least `amount`.\n */\n function _transfer(\n address sender,\n address recipient,\n uint256 amount\n ) internal virtual {\n require(sender != address(0), \"ERC20: transfer from the zero address\");\n require(recipient != address(0), \"ERC20: transfer to the zero address\");\n\n _beforeTokenTransfer(sender, recipient, amount);\n\n uint256 senderBalance = _balances[sender];\n require(senderBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n unchecked {\n _balances[sender] = senderBalance - amount;\n }\n _balances[recipient] += amount;\n\n emit Transfer(sender, recipient, amount);\n\n _afterTokenTransfer(sender, recipient, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _beforeTokenTransfer(address(0), account, amount);\n\n _totalSupply += amount;\n _balances[account] += amount;\n emit Transfer(address(0), account, amount);\n\n _afterTokenTransfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _beforeTokenTransfer(account, address(0), amount);\n\n uint256 accountBalance = _balances[account];\n require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n unchecked {\n _balances[account] = accountBalance - amount;\n }\n _totalSupply -= amount;\n\n emit Transfer(account, address(0), amount);\n\n _afterTokenTransfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n *\n * This internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Hook that is called before any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * will be transferred to `to`.\n * - when `from` is zero, `amount` tokens will be minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * has been transferred to `to`.\n * - when `from` is zero, `amount` tokens have been minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/IERC20.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `recipient`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address recipient, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `sender` to `recipient` using the\n * allowance mechanism. `amount` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address sender,\n address recipient,\n uint256 amount\n ) external returns (bool);\n\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\nimport \"../../../utils/Address.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n function safeTransfer(\n IERC20 token,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n }\n\n function safeTransferFrom(\n IERC20 token,\n address from,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n }\n\n /**\n * @dev Deprecated. This function has issues similar to the ones found in\n * {IERC20-approve}, and its usage is discouraged.\n *\n * Whenever possible, use {safeIncreaseAllowance} and\n * {safeDecreaseAllowance} instead.\n */\n function safeApprove(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n // safeApprove should only be called when setting an initial allowance,\n // or when resetting it to zero. To increase and decrease it, use\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n require(\n (value == 0) || (token.allowance(address(this), spender) == 0),\n \"SafeERC20: approve from non-zero to non-zero allowance\"\n );\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n }\n\n function safeIncreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n uint256 newAllowance = token.allowance(address(this), spender) + value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n\n function safeDecreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n unchecked {\n uint256 oldAllowance = token.allowance(address(this), spender);\n require(oldAllowance >= value, \"SafeERC20: decreased allowance below zero\");\n uint256 newAllowance = oldAllowance - value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n if (returndata.length > 0) {\n // Return data is optional\n require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n }\n }\n}\n" + }, + "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721Receiver.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @title ERC721 token receiver interface\n * @dev Interface for any contract that wants to support safeTransfers\n * from ERC721 asset contracts.\n */\ninterface IERC721Receiver {\n /**\n * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}\n * by `operator` from `from`, this function is called.\n *\n * It must return its Solidity selector to confirm the token transfer.\n * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.\n *\n * The selector can be obtained in Solidity with `IERC721.onERC721Received.selector`.\n */\n function onERC721Received(\n address operator,\n address from,\n uint256 tokenId,\n bytes calldata data\n ) external returns (bytes4);\n}\n" + }, + "@openzeppelin/contracts/utils/Address.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Address.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev Returns true if `account` is a contract.\n *\n * [IMPORTANT]\n * ====\n * It is unsafe to assume that an address for which this function returns\n * false is an externally-owned account (EOA) and not a contract.\n *\n * Among others, `isContract` will return false for the following\n * types of addresses:\n *\n * - an externally-owned account\n * - a contract in construction\n * - an address where a contract will be created\n * - an address where a contract lived, but was destroyed\n * ====\n */\n function isContract(address account) internal view returns (bool) {\n // This method relies on extcodesize, which returns 0 for contracts in\n // construction, since the code is only stored at the end of the\n // constructor execution.\n\n uint256 size;\n assembly {\n size := extcodesize(account)\n }\n return size > 0;\n }\n\n /**\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n * `recipient`, forwarding all available gas and reverting on errors.\n *\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\n * imposed by `transfer`, making them unable to receive funds via\n * `transfer`. {sendValue} removes this limitation.\n *\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n *\n * IMPORTANT: because control is transferred to `recipient`, care must be\n * taken to not create reentrancy vulnerabilities. Consider using\n * {ReentrancyGuard} or the\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n require(success, \"Address: unable to send value, recipient may have reverted\");\n }\n\n /**\n * @dev Performs a Solidity function call using a low level `call`. A\n * plain `call` is an unsafe replacement for a function call: use this\n * function instead.\n *\n * If `target` reverts with a revert reason, it is bubbled up by this\n * function (like regular Solidity function calls).\n *\n * Returns the raw returned data. To convert to the expected return value,\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n *\n * Requirements:\n *\n * - `target` must be a contract.\n * - calling `target` with `data` must not revert.\n *\n * _Available since v3.1._\n */\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCall(target, data, \"Address: low-level call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n * `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but also transferring `value` wei to `target`.\n *\n * Requirements:\n *\n * - the calling contract must have an ETH balance of at least `value`.\n * - the called Solidity function must be `payable`.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n * with `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance >= value, \"Address: insufficient balance for call\");\n require(isContract(target), \"Address: call to non-contract\");\n\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n return functionStaticCall(target, data, \"Address: low-level static call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n require(isContract(target), \"Address: static call to non-contract\");\n\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(isContract(target), \"Address: delegate call to non-contract\");\n\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason using the provided one.\n *\n * _Available since v4.3._\n */\n function verifyCallResult(\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal pure returns (bytes memory) {\n if (success) {\n return returndata;\n } else {\n // Look for revert reason and bubble it up if present\n if (returndata.length > 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert(errorMessage);\n }\n }\n }\n}\n" + }, + "@openzeppelin/contracts/utils/Context.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n}\n" + }, + "@openzeppelin/contracts/utils/math/Math.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/Math.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Standard math utilities missing in the Solidity language.\n */\nlibrary Math {\n /**\n * @dev Returns the largest of two numbers.\n */\n function max(uint256 a, uint256 b) internal pure returns (uint256) {\n return a >= b ? a : b;\n }\n\n /**\n * @dev Returns the smallest of two numbers.\n */\n function min(uint256 a, uint256 b) internal pure returns (uint256) {\n return a < b ? a : b;\n }\n\n /**\n * @dev Returns the average of two numbers. The result is rounded towards\n * zero.\n */\n function average(uint256 a, uint256 b) internal pure returns (uint256) {\n // (a + b) / 2 can overflow.\n return (a & b) + (a ^ b) / 2;\n }\n\n /**\n * @dev Returns the ceiling of the division of two numbers.\n *\n * This differs from standard division with `/` in that it rounds up instead\n * of rounding down.\n */\n function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\n // (a + b - 1) / b can overflow on addition, so we distribute.\n return a / b + (a % b == 0 ? 0 : 1);\n }\n}\n" + }, + "@openzeppelin/contracts/utils/math/SafeMath.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeMath.sol)\n\npragma solidity ^0.8.0;\n\n// CAUTION\n// This version of SafeMath should only be used with Solidity 0.8 or later,\n// because it relies on the compiler's built in overflow checks.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\n * now has built in overflow checking.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n uint256 c = a + b;\n if (c < a) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the substraction of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b > a) return (false, 0);\n return (true, a - b);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) return (true, 0);\n uint256 c = a * b;\n if (c / a != b) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a / b);\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a % b);\n }\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n return a + b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return a - b;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return a / b;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return a % b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {trySub}.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b <= a, errorMessage);\n return a - b;\n }\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a / b;\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting with custom message when dividing by zero.\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {tryMod}.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a % b;\n }\n }\n}\n" + }, + "@openzeppelin/contracts/utils/Strings.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n // Inspired by OraclizeAPI's implementation - MIT licence\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n if (value == 0) {\n return \"0\";\n }\n uint256 temp = value;\n uint256 digits;\n while (temp != 0) {\n digits++;\n temp /= 10;\n }\n bytes memory buffer = new bytes(digits);\n while (value != 0) {\n digits -= 1;\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n value /= 10;\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n if (value == 0) {\n return \"0x00\";\n }\n uint256 temp = value;\n uint256 length = 0;\n while (temp != 0) {\n length++;\n temp >>= 8;\n }\n return toHexString(value, length);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n}\n" + }, + "contracts/governance/Governable.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @title Base for contracts that are managed by the Origin Protocol's Governor.\n * @dev Copy of the openzeppelin Ownable.sol contract with nomenclature change\n * from owner to governor and renounce methods removed. Does not use\n * Context.sol like Ownable.sol does for simplification.\n * @author Origin Protocol Inc\n */\ncontract Governable {\n // Storage position of the owner and pendingOwner of the contract\n // keccak256(\"OUSD.governor\");\n bytes32 private constant governorPosition =\n 0x7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a;\n\n // keccak256(\"OUSD.pending.governor\");\n bytes32 private constant pendingGovernorPosition =\n 0x44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db;\n\n // keccak256(\"OUSD.reentry.status\");\n bytes32 private constant reentryStatusPosition =\n 0x53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac4535;\n\n // See OpenZeppelin ReentrancyGuard implementation\n uint256 constant _NOT_ENTERED = 1;\n uint256 constant _ENTERED = 2;\n\n event PendingGovernorshipTransfer(\n address indexed previousGovernor,\n address indexed newGovernor\n );\n\n event GovernorshipTransferred(\n address indexed previousGovernor,\n address indexed newGovernor\n );\n\n /**\n * @dev Initializes the contract setting the deployer as the initial Governor.\n */\n constructor() {\n _setGovernor(msg.sender);\n emit GovernorshipTransferred(address(0), _governor());\n }\n\n /**\n * @notice Returns the address of the current Governor.\n */\n function governor() public view returns (address) {\n return _governor();\n }\n\n /**\n * @dev Returns the address of the current Governor.\n */\n function _governor() internal view returns (address governorOut) {\n bytes32 position = governorPosition;\n // solhint-disable-next-line no-inline-assembly\n assembly {\n governorOut := sload(position)\n }\n }\n\n /**\n * @dev Returns the address of the pending Governor.\n */\n function _pendingGovernor()\n internal\n view\n returns (address pendingGovernor)\n {\n bytes32 position = pendingGovernorPosition;\n // solhint-disable-next-line no-inline-assembly\n assembly {\n pendingGovernor := sload(position)\n }\n }\n\n /**\n * @dev Throws if called by any account other than the Governor.\n */\n modifier onlyGovernor() {\n require(isGovernor(), \"Caller is not the Governor\");\n _;\n }\n\n /**\n * @notice Returns true if the caller is the current Governor.\n */\n function isGovernor() public view returns (bool) {\n return msg.sender == _governor();\n }\n\n function _setGovernor(address newGovernor) internal {\n bytes32 position = governorPosition;\n // solhint-disable-next-line no-inline-assembly\n assembly {\n sstore(position, newGovernor)\n }\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a `nonReentrant` function from another `nonReentrant`\n * function is not supported. It is possible to prevent this from happening\n * by making the `nonReentrant` function external, and make it call a\n * `private` function that does the actual work.\n */\n modifier nonReentrant() {\n bytes32 position = reentryStatusPosition;\n uint256 _reentry_status;\n // solhint-disable-next-line no-inline-assembly\n assembly {\n _reentry_status := sload(position)\n }\n\n // On the first call to nonReentrant, _notEntered will be true\n require(_reentry_status != _ENTERED, \"Reentrant call\");\n\n // Any calls to nonReentrant after this point will fail\n // solhint-disable-next-line no-inline-assembly\n assembly {\n sstore(position, _ENTERED)\n }\n\n _;\n\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n // solhint-disable-next-line no-inline-assembly\n assembly {\n sstore(position, _NOT_ENTERED)\n }\n }\n\n function _setPendingGovernor(address newGovernor) internal {\n bytes32 position = pendingGovernorPosition;\n // solhint-disable-next-line no-inline-assembly\n assembly {\n sstore(position, newGovernor)\n }\n }\n\n /**\n * @notice Transfers Governance of the contract to a new account (`newGovernor`).\n * Can only be called by the current Governor. Must be claimed for this to complete\n * @param _newGovernor Address of the new Governor\n */\n function transferGovernance(address _newGovernor) external onlyGovernor {\n _setPendingGovernor(_newGovernor);\n emit PendingGovernorshipTransfer(_governor(), _newGovernor);\n }\n\n /**\n * @notice Claim Governance of the contract to a new account (`newGovernor`).\n * Can only be called by the new Governor.\n */\n function claimGovernance() external {\n require(\n msg.sender == _pendingGovernor(),\n \"Only the pending Governor can complete the claim\"\n );\n _changeGovernor(msg.sender);\n }\n\n /**\n * @dev Change Governance of the contract to a new account (`newGovernor`).\n * @param _newGovernor Address of the new Governor\n */\n function _changeGovernor(address _newGovernor) internal {\n require(_newGovernor != address(0), \"New Governor is address(0)\");\n emit GovernorshipTransferred(_governor(), _newGovernor);\n _setGovernor(_newGovernor);\n }\n}\n" + }, + "contracts/harvest/BaseHarvester.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { SafeMath } from \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/utils/math/Math.sol\";\n\nimport { StableMath } from \"../utils/StableMath.sol\";\nimport { Governable } from \"../governance/Governable.sol\";\nimport { IVault } from \"../interfaces/IVault.sol\";\nimport { IOracle } from \"../interfaces/IOracle.sol\";\nimport { IStrategy } from \"../interfaces/IStrategy.sol\";\nimport { IUniswapV2Router } from \"../interfaces/uniswap/IUniswapV2Router02.sol\";\nimport { IUniswapV3Router } from \"../interfaces/uniswap/IUniswapV3Router.sol\";\nimport { IBalancerVault } from \"../interfaces/balancer/IBalancerVault.sol\";\nimport { ICurvePool } from \"../strategies/ICurvePool.sol\";\nimport \"../utils/Helpers.sol\";\n\nabstract contract BaseHarvester is Governable {\n using SafeERC20 for IERC20;\n using SafeMath for uint256;\n using StableMath for uint256;\n\n enum SwapPlatform {\n UniswapV2Compatible,\n UniswapV3,\n Balancer,\n Curve\n }\n\n event SupportedStrategyUpdate(address strategyAddress, bool isSupported);\n event RewardTokenConfigUpdated(\n address tokenAddress,\n uint16 allowedSlippageBps,\n uint16 harvestRewardBps,\n SwapPlatform swapPlatform,\n address swapPlatformAddr,\n bytes swapData,\n uint256 liquidationLimit,\n bool doSwapRewardToken\n );\n event RewardTokenSwapped(\n address indexed rewardToken,\n address indexed swappedInto,\n SwapPlatform swapPlatform,\n uint256 amountIn,\n uint256 amountOut\n );\n event RewardProceedsTransferred(\n address indexed token,\n address farmer,\n uint256 protcolYield,\n uint256 farmerFee\n );\n event RewardProceedsAddressChanged(address newProceedsAddress);\n\n error EmptyAddress();\n error InvalidSlippageBps();\n error InvalidHarvestRewardBps();\n\n error InvalidSwapPlatform(SwapPlatform swapPlatform);\n\n error InvalidUniswapV2PathLength();\n error InvalidTokenInSwapPath(address token);\n error EmptyBalancerPoolId();\n error InvalidCurvePoolAssetIndex(address token);\n\n error UnsupportedStrategy(address strategyAddress);\n\n error SlippageError(uint256 actualBalance, uint256 minExpected);\n error BalanceMismatchAfterSwap(uint256 actualBalance, uint256 minExpected);\n\n // Configuration properties for harvesting logic of reward tokens\n struct RewardTokenConfig {\n // Max allowed slippage when swapping reward token for a stablecoin denominated in basis points.\n uint16 allowedSlippageBps;\n // Reward when calling a harvest function denominated in basis points.\n uint16 harvestRewardBps;\n // Address of compatible exchange protocol (Uniswap V2/V3, SushiSwap, Balancer and Curve).\n address swapPlatformAddr;\n /* When true the reward token is being swapped. In a need of (temporarily) disabling the swapping of\n * a reward token this needs to be set to false.\n */\n bool doSwapRewardToken;\n // Platform to use for Swapping\n SwapPlatform swapPlatform;\n /* How much token can be sold per one harvest call. If the balance of rewards tokens\n * exceeds that limit multiple harvest calls are required to harvest all of the tokens.\n * Set it to MAX_INT to effectively disable the limit.\n */\n uint256 liquidationLimit;\n }\n\n mapping(address => RewardTokenConfig) public rewardTokenConfigs;\n mapping(address => bool) public supportedStrategies;\n\n address public immutable vaultAddress;\n\n /**\n * Address receiving rewards proceeds. Initially the Vault contract later will possibly\n * be replaced by another contract that eases out rewards distribution.\n **/\n address public rewardProceedsAddress;\n\n /**\n * All tokens are swapped to this token before it gets transferred\n * to the `rewardProceedsAddress`. USDT for OUSD and WETH for OETH.\n **/\n address public immutable baseTokenAddress;\n // Cached decimals for `baseTokenAddress`\n uint256 public immutable baseTokenDecimals;\n\n // Uniswap V2 path for reward tokens using Uniswap V2 Router\n mapping(address => address[]) public uniswapV2Path;\n // Uniswap V3 path for reward tokens using Uniswap V3 Router\n mapping(address => bytes) public uniswapV3Path;\n // Pool ID to use for reward tokens on Balancer\n mapping(address => bytes32) public balancerPoolId;\n\n struct CurvePoolIndices {\n // Casted into uint128 and stored in a struct to save gas\n uint128 rewardTokenIndex;\n uint128 baseTokenIndex;\n }\n // Packed indices of assets on the Curve pool\n mapping(address => CurvePoolIndices) public curvePoolIndices;\n\n constructor(address _vaultAddress, address _baseTokenAddress) {\n require(_vaultAddress != address(0));\n require(_baseTokenAddress != address(0));\n\n vaultAddress = _vaultAddress;\n baseTokenAddress = _baseTokenAddress;\n\n // Cache decimals as well\n baseTokenDecimals = Helpers.getDecimals(_baseTokenAddress);\n }\n\n /***************************************\n Configuration\n ****************************************/\n\n /**\n * Set the Address receiving rewards proceeds.\n * @param _rewardProceedsAddress Address of the reward token\n */\n function setRewardProceedsAddress(address _rewardProceedsAddress)\n external\n onlyGovernor\n {\n if (_rewardProceedsAddress == address(0)) {\n revert EmptyAddress();\n }\n\n rewardProceedsAddress = _rewardProceedsAddress;\n emit RewardProceedsAddressChanged(_rewardProceedsAddress);\n }\n\n /**\n * @dev Add/update a reward token configuration that holds harvesting config variables\n * @param _tokenAddress Address of the reward token\n * @param tokenConfig.allowedSlippageBps uint16 maximum allowed slippage denominated in basis points.\n * Example: 300 == 3% slippage\n * @param tokenConfig.harvestRewardBps uint16 amount of reward tokens the caller of the function is rewarded.\n * Example: 100 == 1%\n * @param tokenConfig.swapPlatformAddr Address Address of a UniswapV2 compatible contract to perform\n * the exchange from reward tokens to stablecoin (currently hard-coded to USDT)\n * @param tokenConfig.liquidationLimit uint256 Maximum amount of token to be sold per one swap function call.\n * When value is 0 there is no limit.\n * @param tokenConfig.doSwapRewardToken bool Disables swapping of the token when set to true,\n * does not cause it to revert though.\n * @param tokenConfig.swapPlatform SwapPlatform to use for Swapping\n * @param swapData Additional data required for swapping\n */\n function setRewardTokenConfig(\n address _tokenAddress,\n RewardTokenConfig calldata tokenConfig,\n bytes calldata swapData\n ) external onlyGovernor {\n if (tokenConfig.allowedSlippageBps > 1000) {\n revert InvalidSlippageBps();\n }\n\n if (tokenConfig.harvestRewardBps > 1000) {\n revert InvalidHarvestRewardBps();\n }\n\n address newRouterAddress = tokenConfig.swapPlatformAddr;\n if (newRouterAddress == address(0)) {\n // Swap router address should be non zero address\n revert EmptyAddress();\n }\n\n address oldRouterAddress = rewardTokenConfigs[_tokenAddress]\n .swapPlatformAddr;\n rewardTokenConfigs[_tokenAddress] = tokenConfig;\n\n // Revert if feed does not exist\n // slither-disable-next-line unused-return\n IOracle(IVault(vaultAddress).priceProvider()).price(_tokenAddress);\n\n IERC20 token = IERC20(_tokenAddress);\n // if changing token swap provider cancel existing allowance\n if (\n /* oldRouterAddress == address(0) when there is no pre-existing\n * configuration for said rewards token\n */\n oldRouterAddress != address(0) &&\n oldRouterAddress != newRouterAddress\n ) {\n token.safeApprove(oldRouterAddress, 0);\n }\n\n // Give SwapRouter infinite approval when needed\n if (oldRouterAddress != newRouterAddress) {\n token.safeApprove(newRouterAddress, 0);\n token.safeApprove(newRouterAddress, type(uint256).max);\n }\n\n SwapPlatform _platform = tokenConfig.swapPlatform;\n if (_platform == SwapPlatform.UniswapV2Compatible) {\n uniswapV2Path[_tokenAddress] = _decodeUniswapV2Path(\n swapData,\n _tokenAddress\n );\n } else if (_platform == SwapPlatform.UniswapV3) {\n uniswapV3Path[_tokenAddress] = _decodeUniswapV3Path(\n swapData,\n _tokenAddress\n );\n } else if (_platform == SwapPlatform.Balancer) {\n balancerPoolId[_tokenAddress] = _decodeBalancerPoolId(\n swapData,\n newRouterAddress,\n _tokenAddress\n );\n } else if (_platform == SwapPlatform.Curve) {\n curvePoolIndices[_tokenAddress] = _decodeCurvePoolIndices(\n swapData,\n newRouterAddress,\n _tokenAddress\n );\n } else {\n // Note: This code is unreachable since Solidity reverts when\n // the value is outside the range of defined values of the enum\n // (even if it's under the max length of the base type)\n revert InvalidSwapPlatform(_platform);\n }\n\n emit RewardTokenConfigUpdated(\n _tokenAddress,\n tokenConfig.allowedSlippageBps,\n tokenConfig.harvestRewardBps,\n _platform,\n newRouterAddress,\n swapData,\n tokenConfig.liquidationLimit,\n tokenConfig.doSwapRewardToken\n );\n }\n\n /**\n * @dev Decodes the data passed into Uniswap V2 path and validates\n * it to make sure the path is for `token` to `baseToken`\n *\n * @param data Ecnoded data passed to the `setRewardTokenConfig`\n * @param token The address of the reward token\n * @return path The validated Uniswap V2 path\n */\n function _decodeUniswapV2Path(bytes calldata data, address token)\n internal\n view\n returns (address[] memory path)\n {\n (path) = abi.decode(data, (address[]));\n uint256 len = path.length;\n\n if (len < 2) {\n // Path should have at least two tokens\n revert InvalidUniswapV2PathLength();\n }\n\n // Do some validation\n if (path[0] != token) {\n revert InvalidTokenInSwapPath(path[0]);\n }\n\n if (path[len - 1] != baseTokenAddress) {\n revert InvalidTokenInSwapPath(path[len - 1]);\n }\n }\n\n /**\n * @dev Decodes the data passed into Uniswap V3 path and validates\n * it to make sure the path is for `token` to `baseToken`\n *\n * @param data Ecnoded data passed to the `setRewardTokenConfig`\n * @param token The address of the reward token\n * @return path The validated Uniswap V3 path\n */\n function _decodeUniswapV3Path(bytes calldata data, address token)\n internal\n view\n returns (bytes calldata path)\n {\n path = data;\n\n address decodedAddress = address(uint160(bytes20(data[0:20])));\n\n if (decodedAddress != token) {\n // Invalid Reward Token in swap path\n revert InvalidTokenInSwapPath(decodedAddress);\n }\n\n decodedAddress = address(uint160(bytes20(data[path.length - 20:])));\n if (decodedAddress != baseTokenAddress) {\n // Invalid Base Token in swap path\n revert InvalidTokenInSwapPath(decodedAddress);\n }\n }\n\n /**\n * @dev Decodes the data passed to Balancer Pool ID\n *\n * @param data Ecnoded data passed to the `setRewardTokenConfig`\n * @return poolId The pool ID\n */\n function _decodeBalancerPoolId(\n bytes calldata data,\n address balancerVault,\n address token\n ) internal view returns (bytes32 poolId) {\n (poolId) = abi.decode(data, (bytes32));\n\n if (poolId == bytes32(0)) {\n revert EmptyBalancerPoolId();\n }\n\n IBalancerVault bVault = IBalancerVault(balancerVault);\n\n // Note: this reverts if token is not a pool asset\n // slither-disable-next-line unused-return\n bVault.getPoolTokenInfo(poolId, token);\n\n // slither-disable-next-line unused-return\n bVault.getPoolTokenInfo(poolId, baseTokenAddress);\n }\n\n /**\n * @dev Decodes the data passed to get the pool indices and\n * checks it against the Curve Pool to make sure it's\n * not misconfigured. The indices are packed into a single\n * uint256 for gas savings\n *\n * @param data Ecnoded data passed to the `setRewardTokenConfig`\n * @param poolAddress Curve pool address\n * @param token The address of the reward token\n * @return indices Packed pool asset indices\n */\n function _decodeCurvePoolIndices(\n bytes calldata data,\n address poolAddress,\n address token\n ) internal view returns (CurvePoolIndices memory indices) {\n indices = abi.decode(data, (CurvePoolIndices));\n\n ICurvePool pool = ICurvePool(poolAddress);\n if (token != pool.coins(indices.rewardTokenIndex)) {\n revert InvalidCurvePoolAssetIndex(token);\n }\n if (baseTokenAddress != pool.coins(indices.baseTokenIndex)) {\n revert InvalidCurvePoolAssetIndex(baseTokenAddress);\n }\n }\n\n /**\n * @dev Flags a strategy as supported or not supported one\n * @param _strategyAddress Address of the strategy\n * @param _isSupported Bool marking strategy as supported or not supported\n */\n function setSupportedStrategy(address _strategyAddress, bool _isSupported)\n external\n onlyGovernor\n {\n supportedStrategies[_strategyAddress] = _isSupported;\n emit SupportedStrategyUpdate(_strategyAddress, _isSupported);\n }\n\n /***************************************\n Rewards\n ****************************************/\n\n /**\n * @dev Transfer token to governor. Intended for recovering tokens stuck in\n * contract, i.e. mistaken sends.\n * @param _asset Address for the asset\n * @param _amount Amount of the asset to transfer\n */\n function transferToken(address _asset, uint256 _amount)\n external\n onlyGovernor\n {\n IERC20(_asset).safeTransfer(governor(), _amount);\n }\n\n /**\n * @dev Collect reward tokens from a specific strategy and swap them for\n * base token on the configured swap platform. Can be called by anyone.\n * Rewards incentivizing the caller are sent to the caller of this function.\n * @param _strategyAddr Address of the strategy to collect rewards from\n */\n function harvestAndSwap(address _strategyAddr) external nonReentrant {\n // Remember _harvest function checks for the validity of _strategyAddr\n _harvestAndSwap(_strategyAddr, msg.sender);\n }\n\n /**\n * @dev Collect reward tokens from a specific strategy and swap them for\n * base token on the configured swap platform. Can be called by anyone\n * @param _strategyAddr Address of the strategy to collect rewards from\n * @param _rewardTo Address where to send a share of harvest rewards to as an incentive\n * for executing this function\n */\n function harvestAndSwap(address _strategyAddr, address _rewardTo)\n external\n nonReentrant\n {\n // Remember _harvest function checks for the validity of _strategyAddr\n _harvestAndSwap(_strategyAddr, _rewardTo);\n }\n\n /**\n * @dev Collect reward tokens from a specific strategy and swap them for\n * base token on the configured swap platform\n * @param _strategyAddr Address of the strategy to collect rewards from\n * @param _rewardTo Address where to send a share of harvest rewards to as an incentive\n * for executing this function\n */\n function _harvestAndSwap(address _strategyAddr, address _rewardTo)\n internal\n {\n _harvest(_strategyAddr);\n IStrategy strategy = IStrategy(_strategyAddr);\n address[] memory rewardTokens = strategy.getRewardTokenAddresses();\n IOracle priceProvider = IOracle(IVault(vaultAddress).priceProvider());\n uint256 len = rewardTokens.length;\n for (uint256 i = 0; i < len; ++i) {\n _swap(rewardTokens[i], _rewardTo, priceProvider);\n }\n }\n\n /**\n * @dev Collect reward tokens from a specific strategy and swap them for\n * base token on the configured swap platform\n * @param _strategyAddr Address of the strategy to collect rewards from.\n */\n function _harvest(address _strategyAddr) internal {\n if (!supportedStrategies[_strategyAddr]) {\n revert UnsupportedStrategy(_strategyAddr);\n }\n\n IStrategy strategy = IStrategy(_strategyAddr);\n strategy.collectRewardTokens();\n }\n\n /**\n * @dev Swap a reward token for the base token on the configured\n * swap platform. The token must have a registered price feed\n * with the price provider\n * @param _swapToken Address of the token to swap\n * @param _rewardTo Address where to send the share of harvest rewards to\n * @param _priceProvider Oracle to get prices of the swap token\n */\n function _swap(\n address _swapToken,\n address _rewardTo,\n IOracle _priceProvider\n ) internal virtual {\n uint256 balance = IERC20(_swapToken).balanceOf(address(this));\n\n // No need to swap if the reward token is the base token. eg USDT or WETH.\n // There is also no limit on the transfer. Everything in the harvester will be transferred\n // to the Dripper regardless of the liquidationLimit config.\n if (_swapToken == baseTokenAddress) {\n IERC20(_swapToken).safeTransfer(rewardProceedsAddress, balance);\n // currently not paying the farmer any rewards as there is no swap\n emit RewardProceedsTransferred(\n baseTokenAddress,\n address(0),\n balance,\n 0\n );\n return;\n }\n\n RewardTokenConfig memory tokenConfig = rewardTokenConfigs[_swapToken];\n\n /* This will trigger a return when reward token configuration has not yet been set\n * or we have temporarily disabled swapping of specific reward token via setting\n * doSwapRewardToken to false.\n */\n if (!tokenConfig.doSwapRewardToken) {\n return;\n }\n\n if (balance == 0) {\n return;\n }\n\n if (tokenConfig.liquidationLimit > 0) {\n balance = Math.min(balance, tokenConfig.liquidationLimit);\n }\n\n // This'll revert if there is no price feed\n uint256 oraclePrice = _priceProvider.price(_swapToken);\n\n // Oracle price is 1e18\n uint256 minExpected = (balance *\n (1e4 - tokenConfig.allowedSlippageBps) * // max allowed slippage\n oraclePrice).scaleBy(\n baseTokenDecimals,\n Helpers.getDecimals(_swapToken)\n ) /\n 1e4 / // fix the max slippage decimal position\n 1e18; // and oracle price decimals position\n\n // Do the swap\n uint256 amountReceived = _doSwap(\n tokenConfig.swapPlatform,\n tokenConfig.swapPlatformAddr,\n _swapToken,\n balance,\n minExpected\n );\n\n if (amountReceived < minExpected) {\n revert SlippageError(amountReceived, minExpected);\n }\n\n emit RewardTokenSwapped(\n _swapToken,\n baseTokenAddress,\n tokenConfig.swapPlatform,\n balance,\n amountReceived\n );\n\n IERC20 baseToken = IERC20(baseTokenAddress);\n uint256 baseTokenBalance = baseToken.balanceOf(address(this));\n if (baseTokenBalance < amountReceived) {\n // Note: It's possible to bypass this check by transferring `baseToken`\n // directly to Harvester before calling the `harvestAndSwap`. However,\n // there's no incentive for an attacker to do that. Doing a balance diff\n // will increase the gas cost significantly\n revert BalanceMismatchAfterSwap(baseTokenBalance, amountReceived);\n }\n\n // Farmer only gets fee from the base amount they helped farm,\n // They do not get anything from anything that already was there\n // on the Harvester\n uint256 farmerFee = amountReceived.mulTruncateScale(\n tokenConfig.harvestRewardBps,\n 1e4\n );\n uint256 protocolYield = baseTokenBalance - farmerFee;\n\n baseToken.safeTransfer(rewardProceedsAddress, protocolYield);\n baseToken.safeTransfer(_rewardTo, farmerFee);\n emit RewardProceedsTransferred(\n baseTokenAddress,\n _rewardTo,\n protocolYield,\n farmerFee\n );\n }\n\n function _doSwap(\n SwapPlatform swapPlatform,\n address routerAddress,\n address rewardTokenAddress,\n uint256 amountIn,\n uint256 minAmountOut\n ) internal returns (uint256 amountOut) {\n if (swapPlatform == SwapPlatform.UniswapV2Compatible) {\n return\n _swapWithUniswapV2(\n routerAddress,\n rewardTokenAddress,\n amountIn,\n minAmountOut\n );\n } else if (swapPlatform == SwapPlatform.UniswapV3) {\n return\n _swapWithUniswapV3(\n routerAddress,\n rewardTokenAddress,\n amountIn,\n minAmountOut\n );\n } else if (swapPlatform == SwapPlatform.Balancer) {\n return\n _swapWithBalancer(\n routerAddress,\n rewardTokenAddress,\n amountIn,\n minAmountOut\n );\n } else if (swapPlatform == SwapPlatform.Curve) {\n return\n _swapWithCurve(\n routerAddress,\n rewardTokenAddress,\n amountIn,\n minAmountOut\n );\n } else {\n // Should never be invoked since we catch invalid values\n // in the `setRewardTokenConfig` function before it's set\n revert InvalidSwapPlatform(swapPlatform);\n }\n }\n\n /**\n * @dev Swaps the token to `baseToken` with Uniswap V2\n *\n * @param routerAddress Uniswap V2 Router address\n * @param swapToken Address of the tokenIn\n * @param amountIn Amount of `swapToken` to swap\n * @param minAmountOut Minimum expected amount of `baseToken`\n *\n * @return amountOut Amount of `baseToken` received after the swap\n */\n function _swapWithUniswapV2(\n address routerAddress,\n address swapToken,\n uint256 amountIn,\n uint256 minAmountOut\n ) internal returns (uint256 amountOut) {\n address[] memory path = uniswapV2Path[swapToken];\n\n uint256[] memory amounts = IUniswapV2Router(routerAddress)\n .swapExactTokensForTokens(\n amountIn,\n minAmountOut,\n path,\n address(this),\n block.timestamp\n );\n\n amountOut = amounts[amounts.length - 1];\n }\n\n /**\n * @dev Swaps the token to `baseToken` with Uniswap V3\n *\n * @param routerAddress Uniswap V3 Router address\n * @param swapToken Address of the tokenIn\n * @param amountIn Amount of `swapToken` to swap\n * @param minAmountOut Minimum expected amount of `baseToken`\n *\n * @return amountOut Amount of `baseToken` received after the swap\n */\n function _swapWithUniswapV3(\n address routerAddress,\n address swapToken,\n uint256 amountIn,\n uint256 minAmountOut\n ) internal returns (uint256 amountOut) {\n bytes memory path = uniswapV3Path[swapToken];\n\n IUniswapV3Router.ExactInputParams memory params = IUniswapV3Router\n .ExactInputParams({\n path: path,\n recipient: address(this),\n deadline: block.timestamp,\n amountIn: amountIn,\n amountOutMinimum: minAmountOut\n });\n amountOut = IUniswapV3Router(routerAddress).exactInput(params);\n }\n\n /**\n * @dev Swaps the token to `baseToken` on Balancer\n *\n * @param balancerVaultAddress BalancerVaultAddress\n * @param swapToken Address of the tokenIn\n * @param amountIn Amount of `swapToken` to swap\n * @param minAmountOut Minimum expected amount of `baseToken`\n *\n * @return amountOut Amount of `baseToken` received after the swap\n */\n function _swapWithBalancer(\n address balancerVaultAddress,\n address swapToken,\n uint256 amountIn,\n uint256 minAmountOut\n ) internal returns (uint256 amountOut) {\n bytes32 poolId = balancerPoolId[swapToken];\n\n IBalancerVault.SingleSwap memory singleSwap = IBalancerVault\n .SingleSwap({\n poolId: poolId,\n kind: IBalancerVault.SwapKind.GIVEN_IN,\n assetIn: swapToken,\n assetOut: baseTokenAddress,\n amount: amountIn,\n userData: hex\"\"\n });\n\n IBalancerVault.FundManagement memory fundMgmt = IBalancerVault\n .FundManagement({\n sender: address(this),\n fromInternalBalance: false,\n recipient: payable(address(this)),\n toInternalBalance: false\n });\n\n amountOut = IBalancerVault(balancerVaultAddress).swap(\n singleSwap,\n fundMgmt,\n minAmountOut,\n block.timestamp\n );\n }\n\n /**\n * @dev Swaps the token to `baseToken` on Curve\n *\n * @param poolAddress Curve Pool Address\n * @param swapToken Address of the tokenIn\n * @param amountIn Amount of `swapToken` to swap\n * @param minAmountOut Minimum expected amount of `baseToken`\n *\n * @return amountOut Amount of `baseToken` received after the swap\n */\n function _swapWithCurve(\n address poolAddress,\n address swapToken,\n uint256 amountIn,\n uint256 minAmountOut\n ) internal returns (uint256 amountOut) {\n CurvePoolIndices memory indices = curvePoolIndices[swapToken];\n\n // Note: Not all CurvePools return the `amountOut`, make sure\n // to use only pool that do. Otherwise the swap would revert\n // always\n amountOut = ICurvePool(poolAddress).exchange(\n uint256(indices.rewardTokenIndex),\n uint256(indices.baseTokenIndex),\n amountIn,\n minAmountOut\n );\n }\n}\n" + }, + "contracts/harvest/Dripper.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { Governable } from \"../governance/Governable.sol\";\nimport { IVault } from \"../interfaces/IVault.sol\";\n\n/**\n * @title OUSD Dripper\n *\n * The dripper contract smooths out the yield from point-in-time yield events\n * and spreads the yield out over a configurable time period. This ensures a\n * continuous per block yield to makes users happy as their next rebase\n * amount is always moving up. Also, this makes historical day to day yields\n * smooth, rather than going from a near zero day, to a large APY day, then\n * back to a near zero day again.\n *\n *\n * Design notes\n * - USDT has a smaller resolution than the number of seconds\n * in a week, which can make per block payouts have a rounding error. However\n * the total effect is not large - cents per day, and this money is\n * not lost, just distributed in the future. While we could use a higher\n * decimal precision for the drip perBlock, we chose simpler code.\n * - By calculating the changing drip rates on collects only, harvests and yield\n * events don't have to call anything on this contract or pay any extra gas.\n * Collect() is already be paying for a single write, since it has to reset\n * the lastCollect time.\n * - By having a collectAndRebase method, and having our external systems call\n * that, the OUSD vault does not need any changes, not even to know the address\n * of the dripper.\n * - A rejected design was to retro-calculate the drip rate on each collect,\n * based on the balance at the time of the collect. While this would have\n * required less state, and would also have made the contract respond more quickly\n * to new income, it would break the predictability that is this contract's entire\n * purpose. If we did this, the amount of fundsAvailable() would make sharp increases\n * when funds were deposited.\n * - When the dripper recalculates the rate, it targets spending the balance over\n * the duration. This means that every time that collect is called, if no\n * new funds have been deposited the duration is being pushed back and the\n * rate decreases. This is expected, and ends up following a smoother but\n * longer curve the more collect() is called without incoming yield.\n *\n */\n\ncontract Dripper is Governable {\n using SafeERC20 for IERC20;\n\n struct Drip {\n uint64 lastCollect; // overflows 262 billion years after the sun dies\n uint192 perBlock; // drip rate per block\n }\n\n address immutable vault; // OUSD vault\n address immutable token; // token to drip out\n uint256 public dripDuration; // in seconds\n Drip public drip; // active drip parameters\n\n constructor(address _vault, address _token) {\n vault = _vault;\n token = _token;\n }\n\n /// @notice How much funds have dripped out already and are currently\n // available to be sent to the vault.\n /// @return The amount that would be sent if a collect was called\n function availableFunds() external view returns (uint256) {\n uint256 balance = IERC20(token).balanceOf(address(this));\n return _availableFunds(balance, drip);\n }\n\n /// @notice Collect all dripped funds and send to vault.\n /// Recalculate new drip rate.\n function collect() external {\n _collect();\n }\n\n /// @notice Collect all dripped funds, send to vault, recalculate new drip\n /// rate, and rebase OUSD.\n function collectAndRebase() external {\n _collect();\n IVault(vault).rebase();\n }\n\n /// @dev Change the drip duration. Governor only.\n /// @param _durationSeconds the number of seconds to drip out the entire\n /// balance over if no collects were called during that time.\n function setDripDuration(uint256 _durationSeconds) external onlyGovernor {\n require(_durationSeconds > 0, \"duration must be non-zero\");\n dripDuration = _durationSeconds;\n _collect(); // duration change take immediate effect\n }\n\n /// @dev Transfer out ERC20 tokens held by the contract. Governor only.\n /// @param _asset ERC20 token address\n /// @param _amount amount to transfer\n function transferToken(address _asset, uint256 _amount)\n external\n onlyGovernor\n {\n IERC20(_asset).safeTransfer(governor(), _amount);\n }\n\n /// @dev Calculate available funds by taking the lower of either the\n /// currently dripped out funds or the balance available.\n /// Uses passed in parameters to calculate with for gas savings.\n /// @param _balance current balance in contract\n /// @param _drip current drip parameters\n function _availableFunds(uint256 _balance, Drip memory _drip)\n internal\n view\n returns (uint256)\n {\n uint256 elapsed = block.timestamp - _drip.lastCollect;\n uint256 allowed = (elapsed * _drip.perBlock);\n return (allowed > _balance) ? _balance : allowed;\n }\n\n /// @dev Sends the currently dripped funds to be vault, and sets\n /// the new drip rate based on the new balance.\n function _collect() internal {\n // Calculate send\n uint256 balance = IERC20(token).balanceOf(address(this));\n uint256 amountToSend = _availableFunds(balance, drip);\n uint256 remaining = balance - amountToSend;\n // Calculate new drip perBlock\n // Gas savings by setting entire struct at one time\n drip = Drip({\n perBlock: uint192(remaining / dripDuration),\n lastCollect: uint64(block.timestamp)\n });\n // Send funds\n IERC20(token).safeTransfer(vault, amountToSend);\n }\n}\n" + }, + "contracts/harvest/Harvester.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { BaseHarvester } from \"./BaseHarvester.sol\";\n\ncontract Harvester is BaseHarvester {\n constructor(address _vault, address _usdtAddress)\n BaseHarvester(_vault, _usdtAddress)\n {}\n}\n" + }, + "contracts/harvest/OETHDripper.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { Dripper } from \"./Dripper.sol\";\n\n/**\n * @title OETH Dripper Contract\n * @author Origin Protocol Inc\n */\ncontract OETHDripper is Dripper {\n constructor(address _vault, address _token) Dripper(_vault, _token) {}\n}\n" + }, + "contracts/harvest/OETHHarvester.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { BaseHarvester } from \"./BaseHarvester.sol\";\n\ncontract OETHHarvester is BaseHarvester {\n constructor(address _vault, address _wethAddress)\n BaseHarvester(_vault, _wethAddress)\n {}\n}\n" + }, + "contracts/interfaces/balancer/IBalancerVault.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { IERC20 } from \"../../utils/InitializableAbstractStrategy.sol\";\n\ninterface IBalancerVault {\n enum WeightedPoolJoinKind {\n INIT,\n EXACT_TOKENS_IN_FOR_BPT_OUT,\n TOKEN_IN_FOR_EXACT_BPT_OUT,\n ALL_TOKENS_IN_FOR_EXACT_BPT_OUT,\n ADD_TOKEN\n }\n\n enum WeightedPoolExitKind {\n EXACT_BPT_IN_FOR_ONE_TOKEN_OUT,\n EXACT_BPT_IN_FOR_TOKENS_OUT,\n BPT_IN_FOR_EXACT_TOKENS_OUT,\n REMOVE_TOKEN\n }\n\n /**\n * @dev Called by users to join a Pool, which transfers tokens from `sender` into the Pool's balance. This will\n * trigger custom Pool behavior, which will typically grant something in return to `recipient` - often tokenized\n * Pool shares.\n *\n * If the caller is not `sender`, it must be an authorized relayer for them.\n *\n * The `assets` and `maxAmountsIn` arrays must have the same length, and each entry indicates the maximum amount\n * to send for each asset. The amounts to send are decided by the Pool and not the Vault: it just enforces\n * these maximums.\n *\n * If joining a Pool that holds WETH, it is possible to send ETH directly: the Vault will do the wrapping. To enable\n * this mechanism, the IAsset sentinel value (the zero address) must be passed in the `assets` array instead of the\n * WETH address. Note that it is not possible to combine ETH and WETH in the same join. Any excess ETH will be sent\n * back to the caller (not the sender, which is important for relayers).\n *\n * `assets` must have the same length and order as the array returned by `getPoolTokens`. This prevents issues when\n * interacting with Pools that register and deregister tokens frequently. If sending ETH however, the array must be\n * sorted *before* replacing the WETH address with the ETH sentinel value (the zero address), which means the final\n * `assets` array might not be sorted. Pools with no registered tokens cannot be joined.\n *\n * If `fromInternalBalance` is true, the caller's Internal Balance will be preferred: ERC20 transfers will only\n * be made for the difference between the requested amount and Internal Balance (if any). Note that ETH cannot be\n * withdrawn from Internal Balance: attempting to do so will trigger a revert.\n *\n * This causes the Vault to call the `IBasePool.onJoinPool` hook on the Pool's contract, where Pools implement\n * their own custom logic. This typically requires additional information from the user (such as the expected number\n * of Pool shares). This can be encoded in the `userData` argument, which is ignored by the Vault and passed\n * directly to the Pool's contract, as is `recipient`.\n *\n * Emits a `PoolBalanceChanged` event.\n */\n function joinPool(\n bytes32 poolId,\n address sender,\n address recipient,\n JoinPoolRequest memory request\n ) external payable;\n\n struct JoinPoolRequest {\n address[] assets;\n uint256[] maxAmountsIn;\n bytes userData;\n bool fromInternalBalance;\n }\n\n /**\n * @dev Called by users to exit a Pool, which transfers tokens from the Pool's balance to `recipient`. This will\n * trigger custom Pool behavior, which will typically ask for something in return from `sender` - often tokenized\n * Pool shares. The amount of tokens that can be withdrawn is limited by the Pool's `cash` balance (see\n * `getPoolTokenInfo`).\n *\n * If the caller is not `sender`, it must be an authorized relayer for them.\n *\n * The `tokens` and `minAmountsOut` arrays must have the same length, and each entry in these indicates the minimum\n * token amount to receive for each token contract. The amounts to send are decided by the Pool and not the Vault:\n * it just enforces these minimums.\n *\n * If exiting a Pool that holds WETH, it is possible to receive ETH directly: the Vault will do the unwrapping. To\n * enable this mechanism, the IAsset sentinel value (the zero address) must be passed in the `assets` array instead\n * of the WETH address. Note that it is not possible to combine ETH and WETH in the same exit.\n *\n * `assets` must have the same length and order as the array returned by `getPoolTokens`. This prevents issues when\n * interacting with Pools that register and deregister tokens frequently. If receiving ETH however, the array must\n * be sorted *before* replacing the WETH address with the ETH sentinel value (the zero address), which means the\n * final `assets` array might not be sorted. Pools with no registered tokens cannot be exited.\n *\n * If `toInternalBalance` is true, the tokens will be deposited to `recipient`'s Internal Balance. Otherwise,\n * an ERC20 transfer will be performed. Note that ETH cannot be deposited to Internal Balance: attempting to\n * do so will trigger a revert.\n *\n * `minAmountsOut` is the minimum amount of tokens the user expects to get out of the Pool, for each token in the\n * `tokens` array. This array must match the Pool's registered tokens.\n *\n * This causes the Vault to call the `IBasePool.onExitPool` hook on the Pool's contract, where Pools implement\n * their own custom logic. This typically requires additional information from the user (such as the expected number\n * of Pool shares to return). This can be encoded in the `userData` argument, which is ignored by the Vault and\n * passed directly to the Pool's contract.\n *\n * Emits a `PoolBalanceChanged` event.\n */\n function exitPool(\n bytes32 poolId,\n address sender,\n address payable recipient,\n ExitPoolRequest memory request\n ) external;\n\n struct ExitPoolRequest {\n address[] assets;\n uint256[] minAmountsOut;\n bytes userData;\n bool toInternalBalance;\n }\n\n /**\n * @dev Returns a Pool's registered tokens, the total balance for each, and the latest block when *any* of\n * the tokens' `balances` changed.\n *\n * The order of the `tokens` array is the same order that will be used in `joinPool`, `exitPool`, as well as in all\n * Pool hooks (where applicable). Calls to `registerTokens` and `deregisterTokens` may change this order.\n *\n * If a Pool only registers tokens once, and these are sorted in ascending order, they will be stored in the same\n * order as passed to `registerTokens`.\n *\n * Total balances include both tokens held by the Vault and those withdrawn by the Pool's Asset Managers. These are\n * the amounts used by joins, exits and swaps. For a detailed breakdown of token balances, use `getPoolTokenInfo`\n * instead.\n */\n function getPoolTokens(bytes32 poolId)\n external\n view\n returns (\n IERC20[] memory tokens,\n uint256[] memory balances,\n uint256 lastChangeBlock\n );\n\n /**\n * @dev Performs a set of user balance operations, which involve Internal Balance (deposit, withdraw or transfer)\n * and plain ERC20 transfers using the Vault's allowance. This last feature is particularly useful for relayers, as\n * it lets integrators reuse a user's Vault allowance.\n *\n * For each operation, if the caller is not `sender`, it must be an authorized relayer for them.\n */\n function manageUserBalance(UserBalanceOp[] memory ops) external payable;\n\n struct UserBalanceOp {\n UserBalanceOpKind kind;\n address asset;\n uint256 amount;\n address sender;\n address payable recipient;\n }\n\n enum UserBalanceOpKind {\n DEPOSIT_INTERNAL,\n WITHDRAW_INTERNAL,\n TRANSFER_INTERNAL,\n TRANSFER_EXTERNAL\n }\n\n enum SwapKind {\n GIVEN_IN,\n GIVEN_OUT\n }\n\n struct SingleSwap {\n bytes32 poolId;\n SwapKind kind;\n address assetIn;\n address assetOut;\n uint256 amount;\n bytes userData;\n }\n\n struct FundManagement {\n address sender;\n bool fromInternalBalance;\n address payable recipient;\n bool toInternalBalance;\n }\n\n function swap(\n SingleSwap calldata singleSwap,\n FundManagement calldata funds,\n uint256 limit,\n uint256 deadline\n ) external returns (uint256 amountCalculated);\n\n function getPoolTokenInfo(bytes32 poolId, address token)\n external\n view\n returns (\n uint256 cash,\n uint256 managed,\n uint256 lastChangeBlock,\n address assetManager\n );\n}\n" + }, + "contracts/interfaces/balancer/IMetaStablePool.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { IRateProvider } from \"./IRateProvider.sol\";\n\ninterface IMetaStablePool {\n function getRateProviders()\n external\n view\n returns (IRateProvider[] memory providers);\n}\n" + }, + "contracts/interfaces/balancer/IRateProvider.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n\n// You should have received a copy of the GNU General Public License\n// along with this program. If not, see .\n\npragma solidity ^0.8.0;\n\ninterface IRateProvider {\n function getRate() external view returns (uint256);\n}\n" + }, + "contracts/interfaces/IBasicToken.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IBasicToken {\n function symbol() external view returns (string memory);\n\n function decimals() external view returns (uint8);\n}\n" + }, + "contracts/interfaces/IComptroller.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IComptroller {\n // Claim all the COMP accrued by specific holders in specific markets for their supplies and/or borrows\n function claimComp(\n address[] memory holders,\n address[] memory cTokens,\n bool borrowers,\n bool suppliers\n ) external;\n\n function oracle() external view returns (address);\n}\n" + }, + "contracts/interfaces/IDepositContract.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IDepositContract {\n /// @notice A processed deposit event.\n event DepositEvent(\n bytes pubkey,\n bytes withdrawal_credentials,\n bytes amount,\n bytes signature,\n bytes index\n );\n\n /// @notice Submit a Phase 0 DepositData object.\n /// @param pubkey A BLS12-381 public key.\n /// @param withdrawal_credentials Commitment to a public key for withdrawals.\n /// @param signature A BLS12-381 signature.\n /// @param deposit_data_root The SHA-256 hash of the SSZ-encoded DepositData object.\n /// Used as a protection against malformed input.\n function deposit(\n bytes calldata pubkey,\n bytes calldata withdrawal_credentials,\n bytes calldata signature,\n bytes32 deposit_data_root\n ) external payable;\n\n /// @notice Query the current deposit root hash.\n /// @return The deposit root hash.\n function get_deposit_root() external view returns (bytes32);\n\n /// @notice Query the current deposit count.\n /// @return The deposit count encoded as a little endian 64-bit number.\n function get_deposit_count() external view returns (bytes memory);\n}\n" + }, + "contracts/interfaces/IDripper.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IDripper {\n /// @notice How much funds have dripped out already and are currently\n // available to be sent to the vault.\n /// @return The amount that would be sent if a collect was called\n function availableFunds() external view returns (uint256);\n\n /// @notice Collect all dripped funds and send to vault.\n /// Recalculate new drip rate.\n function collect() external;\n\n /// @notice Collect all dripped funds, send to vault, recalculate new drip\n /// rate, and rebase mToken.\n function collectAndRebase() external;\n}\n" + }, + "contracts/interfaces/IFraxETHMinter.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IFraxETHMinter {\n function submitAndDeposit(address recipient)\n external\n payable\n returns (uint256 shares);\n}\n" + }, + "contracts/interfaces/IGetExchangeRateToken.sol": { + "content": "pragma solidity ^0.8.0;\n\ninterface IGetExchangeRateToken {\n function getExchangeRate() external view returns (uint256 _exchangeRate);\n}\n" + }, + "contracts/interfaces/IOracle.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IOracle {\n /**\n * @dev returns the asset price in USD, in 8 decimal digits.\n *\n * The version of priceProvider deployed for OETH has 18 decimal digits\n */\n function price(address asset) external view returns (uint256);\n}\n" + }, + "contracts/interfaces/IOUSD.sol": { + "content": "pragma solidity ^0.8.0;\n\ninterface IOUSD {\n event Approval(\n address indexed owner,\n address indexed spender,\n uint256 value\n );\n event GovernorshipTransferred(\n address indexed previousGovernor,\n address indexed newGovernor\n );\n event PendingGovernorshipTransfer(\n address indexed previousGovernor,\n address indexed newGovernor\n );\n event TotalSupplyUpdatedHighres(\n uint256 totalSupply,\n uint256 rebasingCredits,\n uint256 rebasingCreditsPerToken\n );\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n function _totalSupply() external view returns (uint256);\n\n function allowance(address _owner, address _spender)\n external\n view\n returns (uint256);\n\n function approve(address _spender, uint256 _value) external returns (bool);\n\n function balanceOf(address _account) external view returns (uint256);\n\n function burn(address account, uint256 amount) external;\n\n function changeSupply(uint256 _newTotalSupply) external;\n\n function claimGovernance() external;\n\n function creditsBalanceOf(address _account)\n external\n view\n returns (uint256, uint256);\n\n function creditsBalanceOfHighres(address _account)\n external\n view\n returns (\n uint256,\n uint256,\n bool\n );\n\n function decimals() external view returns (uint8);\n\n function decreaseAllowance(address _spender, uint256 _subtractedValue)\n external\n returns (bool);\n\n function governor() external view returns (address);\n\n function increaseAllowance(address _spender, uint256 _addedValue)\n external\n returns (bool);\n\n function initialize(\n string memory _nameArg,\n string memory _symbolArg,\n address _vaultAddress\n ) external;\n\n function isGovernor() external view returns (bool);\n\n function isUpgraded(address) external view returns (uint256);\n\n function mint(address _account, uint256 _amount) external;\n\n function name() external view returns (string memory);\n\n function nonRebasingCreditsPerToken(address)\n external\n view\n returns (uint256);\n\n function nonRebasingSupply() external view returns (uint256);\n\n function rebaseOptIn() external;\n\n function rebaseOptOut() external;\n\n function rebaseState(address) external view returns (uint8);\n\n function rebasingCredits() external view returns (uint256);\n\n function rebasingCreditsHighres() external view returns (uint256);\n\n function rebasingCreditsPerToken() external view returns (uint256);\n\n function rebasingCreditsPerTokenHighres() external view returns (uint256);\n\n function symbol() external view returns (string memory);\n\n function totalSupply() external view returns (uint256);\n\n function transfer(address _to, uint256 _value) external returns (bool);\n\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n ) external returns (bool);\n\n function transferGovernance(address _newGovernor) external;\n\n function vaultAddress() external view returns (address);\n}\n" + }, + "contracts/interfaces/ISfrxETH.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface ISfrxETH {\n event Approval(\n address indexed owner,\n address indexed spender,\n uint256 amount\n );\n event Deposit(\n address indexed caller,\n address indexed owner,\n uint256 assets,\n uint256 shares\n );\n event NewRewardsCycle(uint32 indexed cycleEnd, uint256 rewardAmount);\n event Transfer(address indexed from, address indexed to, uint256 amount);\n event Withdraw(\n address indexed caller,\n address indexed receiver,\n address indexed owner,\n uint256 assets,\n uint256 shares\n );\n\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n\n function allowance(address, address) external view returns (uint256);\n\n function approve(address spender, uint256 amount) external returns (bool);\n\n function asset() external view returns (address);\n\n function balanceOf(address) external view returns (uint256);\n\n function convertToAssets(uint256 shares) external view returns (uint256);\n\n function convertToShares(uint256 assets) external view returns (uint256);\n\n function decimals() external view returns (uint8);\n\n function deposit(uint256 assets, address receiver)\n external\n returns (uint256 shares);\n\n function depositWithSignature(\n uint256 assets,\n address receiver,\n uint256 deadline,\n bool approveMax,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external returns (uint256 shares);\n\n function lastRewardAmount() external view returns (uint192);\n\n function lastSync() external view returns (uint32);\n\n function maxDeposit(address) external view returns (uint256);\n\n function maxMint(address) external view returns (uint256);\n\n function maxRedeem(address owner) external view returns (uint256);\n\n function maxWithdraw(address owner) external view returns (uint256);\n\n function mint(uint256 shares, address receiver)\n external\n returns (uint256 assets);\n\n function name() external view returns (string memory);\n\n function nonces(address) external view returns (uint256);\n\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n function previewDeposit(uint256 assets) external view returns (uint256);\n\n function previewMint(uint256 shares) external view returns (uint256);\n\n function previewRedeem(uint256 shares) external view returns (uint256);\n\n function previewWithdraw(uint256 assets) external view returns (uint256);\n\n function pricePerShare() external view returns (uint256);\n\n function redeem(\n uint256 shares,\n address receiver,\n address owner\n ) external returns (uint256 assets);\n\n function rewardsCycleEnd() external view returns (uint32);\n\n function rewardsCycleLength() external view returns (uint32);\n\n function symbol() external view returns (string memory);\n\n function syncRewards() external;\n\n function totalAssets() external view returns (uint256);\n\n function totalSupply() external view returns (uint256);\n\n function transfer(address to, uint256 amount) external returns (bool);\n\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) external returns (bool);\n\n function withdraw(\n uint256 assets,\n address receiver,\n address owner\n ) external returns (uint256 shares);\n}\n" + }, + "contracts/interfaces/ISSVNetwork.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nstruct Cluster {\n uint32 validatorCount;\n uint64 networkFeeIndex;\n uint64 index;\n bool active;\n uint256 balance;\n}\n\ninterface ISSVNetwork {\n /**********/\n /* Errors */\n /**********/\n\n error CallerNotOwner(); // 0x5cd83192\n error CallerNotWhitelisted(); // 0x8c6e5d71\n error FeeTooLow(); // 0x732f9413\n error FeeExceedsIncreaseLimit(); // 0x958065d9\n error NoFeeDeclared(); // 0x1d226c30\n error ApprovalNotWithinTimeframe(); // 0x97e4b518\n error OperatorDoesNotExist(); // 0x961e3e8c\n error InsufficientBalance(); // 0xf4d678b8\n error ValidatorDoesNotExist(); // 0xe51315d2\n error ClusterNotLiquidatable(); // 0x60300a8d\n error InvalidPublicKeyLength(); // 0x637297a4\n error InvalidOperatorIdsLength(); // 0x38186224\n error ClusterAlreadyEnabled(); // 0x3babafd2\n error ClusterIsLiquidated(); // 0x95a0cf33\n error ClusterDoesNotExists(); // 0x185e2b16\n error IncorrectClusterState(); // 0x12e04c87\n error UnsortedOperatorsList(); // 0xdd020e25\n error NewBlockPeriodIsBelowMinimum(); // 0x6e6c9cac\n error ExceedValidatorLimit(); // 0x6df5ab76\n error TokenTransferFailed(); // 0x045c4b02\n error SameFeeChangeNotAllowed(); // 0xc81272f8\n error FeeIncreaseNotAllowed(); // 0x410a2b6c\n error NotAuthorized(); // 0xea8e4eb5\n error OperatorsListNotUnique(); // 0xa5a1ff5d\n error OperatorAlreadyExists(); // 0x289c9494\n error TargetModuleDoesNotExist(); // 0x8f9195fb\n error MaxValueExceeded(); // 0x91aa3017\n error FeeTooHigh(); // 0xcd4e6167\n error PublicKeysSharesLengthMismatch(); // 0x9ad467b8\n error IncorrectValidatorStateWithData(bytes publicKey); // 0x89307938\n error ValidatorAlreadyExistsWithData(bytes publicKey); // 0x388e7999\n error EmptyPublicKeysList(); // df83e679\n\n // legacy errors\n error ValidatorAlreadyExists(); // 0x8d09a73e\n error IncorrectValidatorState(); // 0x2feda3c1\n\n event AdminChanged(address previousAdmin, address newAdmin);\n event BeaconUpgraded(address indexed beacon);\n event ClusterDeposited(\n address indexed owner,\n uint64[] operatorIds,\n uint256 value,\n Cluster cluster\n );\n event ClusterLiquidated(\n address indexed owner,\n uint64[] operatorIds,\n Cluster cluster\n );\n event ClusterReactivated(\n address indexed owner,\n uint64[] operatorIds,\n Cluster cluster\n );\n event ClusterWithdrawn(\n address indexed owner,\n uint64[] operatorIds,\n uint256 value,\n Cluster cluster\n );\n event DeclareOperatorFeePeriodUpdated(uint64 value);\n event ExecuteOperatorFeePeriodUpdated(uint64 value);\n event FeeRecipientAddressUpdated(\n address indexed owner,\n address recipientAddress\n );\n event Initialized(uint8 version);\n event LiquidationThresholdPeriodUpdated(uint64 value);\n event MinimumLiquidationCollateralUpdated(uint256 value);\n event NetworkEarningsWithdrawn(uint256 value, address recipient);\n event NetworkFeeUpdated(uint256 oldFee, uint256 newFee);\n event OperatorAdded(\n uint64 indexed operatorId,\n address indexed owner,\n bytes publicKey,\n uint256 fee\n );\n event OperatorFeeDeclarationCancelled(\n address indexed owner,\n uint64 indexed operatorId\n );\n event OperatorFeeDeclared(\n address indexed owner,\n uint64 indexed operatorId,\n uint256 blockNumber,\n uint256 fee\n );\n event OperatorFeeExecuted(\n address indexed owner,\n uint64 indexed operatorId,\n uint256 blockNumber,\n uint256 fee\n );\n event OperatorFeeIncreaseLimitUpdated(uint64 value);\n event OperatorMaximumFeeUpdated(uint64 maxFee);\n event OperatorRemoved(uint64 indexed operatorId);\n event OperatorWhitelistUpdated(\n uint64 indexed operatorId,\n address whitelisted\n );\n event OperatorWithdrawn(\n address indexed owner,\n uint64 indexed operatorId,\n uint256 value\n );\n event OwnershipTransferStarted(\n address indexed previousOwner,\n address indexed newOwner\n );\n event OwnershipTransferred(\n address indexed previousOwner,\n address indexed newOwner\n );\n event Upgraded(address indexed implementation);\n event ValidatorAdded(\n address indexed owner,\n uint64[] operatorIds,\n bytes publicKey,\n bytes shares,\n Cluster cluster\n );\n event ValidatorExited(\n address indexed owner,\n uint64[] operatorIds,\n bytes publicKey\n );\n event ValidatorRemoved(\n address indexed owner,\n uint64[] operatorIds,\n bytes publicKey,\n Cluster cluster\n );\n\n fallback() external;\n\n function acceptOwnership() external;\n\n function cancelDeclaredOperatorFee(uint64 operatorId) external;\n\n function declareOperatorFee(uint64 operatorId, uint256 fee) external;\n\n function deposit(\n address clusterOwner,\n uint64[] memory operatorIds,\n uint256 amount,\n Cluster memory cluster\n ) external;\n\n function executeOperatorFee(uint64 operatorId) external;\n\n function exitValidator(bytes memory publicKey, uint64[] memory operatorIds)\n external;\n\n function bulkExitValidator(\n bytes[] calldata publicKeys,\n uint64[] calldata operatorIds\n ) external;\n\n function getVersion() external pure returns (string memory version);\n\n function initialize(\n address token_,\n address ssvOperators_,\n address ssvClusters_,\n address ssvDAO_,\n address ssvViews_,\n uint64 minimumBlocksBeforeLiquidation_,\n uint256 minimumLiquidationCollateral_,\n uint32 validatorsPerOperatorLimit_,\n uint64 declareOperatorFeePeriod_,\n uint64 executeOperatorFeePeriod_,\n uint64 operatorMaxFeeIncrease_\n ) external;\n\n function liquidate(\n address clusterOwner,\n uint64[] memory operatorIds,\n Cluster memory cluster\n ) external;\n\n function owner() external view returns (address);\n\n function pendingOwner() external view returns (address);\n\n function proxiableUUID() external view returns (bytes32);\n\n function reactivate(\n uint64[] memory operatorIds,\n uint256 amount,\n Cluster memory cluster\n ) external;\n\n function reduceOperatorFee(uint64 operatorId, uint256 fee) external;\n\n function registerOperator(bytes memory publicKey, uint256 fee)\n external\n returns (uint64 id);\n\n function registerValidator(\n bytes memory publicKey,\n uint64[] memory operatorIds,\n bytes memory sharesData,\n uint256 amount,\n Cluster memory cluster\n ) external;\n\n function bulkRegisterValidator(\n bytes[] calldata publicKeys,\n uint64[] calldata operatorIds,\n bytes[] calldata sharesData,\n uint256 amount,\n Cluster memory cluster\n ) external;\n\n function removeOperator(uint64 operatorId) external;\n\n function removeValidator(\n bytes memory publicKey,\n uint64[] memory operatorIds,\n Cluster memory cluster\n ) external;\n\n function bulkRemoveValidator(\n bytes[] calldata publicKeys,\n uint64[] calldata operatorIds,\n Cluster memory cluster\n ) external;\n\n function renounceOwnership() external;\n\n function setFeeRecipientAddress(address recipientAddress) external;\n\n function setOperatorWhitelist(uint64 operatorId, address whitelisted)\n external;\n\n function transferOwnership(address newOwner) external;\n\n function updateDeclareOperatorFeePeriod(uint64 timeInSeconds) external;\n\n function updateExecuteOperatorFeePeriod(uint64 timeInSeconds) external;\n\n function updateLiquidationThresholdPeriod(uint64 blocks) external;\n\n function updateMaximumOperatorFee(uint64 maxFee) external;\n\n function updateMinimumLiquidationCollateral(uint256 amount) external;\n\n function updateModule(uint8 moduleId, address moduleAddress) external;\n\n function updateNetworkFee(uint256 fee) external;\n\n function updateOperatorFeeIncreaseLimit(uint64 percentage) external;\n\n function upgradeTo(address newImplementation) external;\n\n function upgradeToAndCall(address newImplementation, bytes memory data)\n external\n payable;\n\n function withdraw(\n uint64[] memory operatorIds,\n uint256 amount,\n Cluster memory cluster\n ) external;\n\n function withdrawAllOperatorEarnings(uint64 operatorId) external;\n\n function withdrawNetworkEarnings(uint256 amount) external;\n\n function withdrawOperatorEarnings(uint64 operatorId, uint256 amount)\n external;\n}\n" + }, + "contracts/interfaces/IStrategy.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @title Platform interface to integrate with lending platform like Compound, AAVE etc.\n */\ninterface IStrategy {\n /**\n * @dev Deposit the given asset to platform\n * @param _asset asset address\n * @param _amount Amount to deposit\n */\n function deposit(address _asset, uint256 _amount) external;\n\n /**\n * @dev Deposit the entire balance of all supported assets in the Strategy\n * to the platform\n */\n function depositAll() external;\n\n /**\n * @dev Withdraw given asset from Lending platform\n */\n function withdraw(\n address _recipient,\n address _asset,\n uint256 _amount\n ) external;\n\n /**\n * @dev Liquidate all assets in strategy and return them to Vault.\n */\n function withdrawAll() external;\n\n /**\n * @dev Returns the current balance of the given asset.\n */\n function checkBalance(address _asset)\n external\n view\n returns (uint256 balance);\n\n /**\n * @dev Returns bool indicating whether strategy supports asset.\n */\n function supportsAsset(address _asset) external view returns (bool);\n\n /**\n * @dev Collect reward tokens from the Strategy.\n */\n function collectRewardTokens() external;\n\n /**\n * @dev The address array of the reward tokens for the Strategy.\n */\n function getRewardTokenAddresses() external view returns (address[] memory);\n}\n" + }, + "contracts/interfaces/ISwapper.sol": { + "content": "pragma solidity ^0.8.0;\n\ninterface ISwapper {\n /**\n * @param fromAsset The token address of the asset being sold.\n * @param toAsset The token address of the asset being purchased.\n * @param fromAssetAmount The amount of assets being sold.\n * @param minToAssetAmmount The minimum amount of assets to be purchased.\n * @param data tx.data returned from 1Inch's /v5.0/1/swap API\n */\n function swap(\n address fromAsset,\n address toAsset,\n uint256 fromAssetAmount,\n uint256 minToAssetAmmount,\n bytes calldata data\n ) external returns (uint256 toAssetAmount);\n}\n" + }, + "contracts/interfaces/IVault.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { VaultStorage } from \"../vault/VaultStorage.sol\";\n\ninterface IVault {\n event AssetSupported(address _asset);\n event AssetDefaultStrategyUpdated(address _asset, address _strategy);\n event AssetAllocated(address _asset, address _strategy, uint256 _amount);\n event StrategyApproved(address _addr);\n event StrategyRemoved(address _addr);\n event Mint(address _addr, uint256 _value);\n event Redeem(address _addr, uint256 _value);\n event CapitalPaused();\n event CapitalUnpaused();\n event RebasePaused();\n event RebaseUnpaused();\n event VaultBufferUpdated(uint256 _vaultBuffer);\n event RedeemFeeUpdated(uint256 _redeemFeeBps);\n event PriceProviderUpdated(address _priceProvider);\n event AllocateThresholdUpdated(uint256 _threshold);\n event RebaseThresholdUpdated(uint256 _threshold);\n event StrategistUpdated(address _address);\n event MaxSupplyDiffChanged(uint256 maxSupplyDiff);\n event YieldDistribution(address _to, uint256 _yield, uint256 _fee);\n event TrusteeFeeBpsChanged(uint256 _basis);\n event TrusteeAddressChanged(address _address);\n event SwapperChanged(address _address);\n event SwapAllowedUndervalueChanged(uint256 _basis);\n event SwapSlippageChanged(address _asset, uint256 _basis);\n event Swapped(\n address indexed _fromAsset,\n address indexed _toAsset,\n uint256 _fromAssetAmount,\n uint256 _toAssetAmount\n );\n event DripperChanged(address indexed _dripper);\n event WithdrawalRequested(\n address indexed _withdrawer,\n uint256 indexed _requestId,\n uint256 _amount,\n uint256 _queued\n );\n event WithdrawalClaimed(\n address indexed _withdrawer,\n uint256 indexed _requestId,\n uint256 _amount\n );\n event WithdrawalClaimable(uint256 _claimable, uint256 _newClaimable);\n\n // Governable.sol\n function transferGovernance(address _newGovernor) external;\n\n function claimGovernance() external;\n\n function governor() external view returns (address);\n\n // VaultAdmin.sol\n function setPriceProvider(address _priceProvider) external;\n\n function priceProvider() external view returns (address);\n\n function setRedeemFeeBps(uint256 _redeemFeeBps) external;\n\n function redeemFeeBps() external view returns (uint256);\n\n function setVaultBuffer(uint256 _vaultBuffer) external;\n\n function vaultBuffer() external view returns (uint256);\n\n function setAutoAllocateThreshold(uint256 _threshold) external;\n\n function autoAllocateThreshold() external view returns (uint256);\n\n function setRebaseThreshold(uint256 _threshold) external;\n\n function rebaseThreshold() external view returns (uint256);\n\n function setStrategistAddr(address _address) external;\n\n function strategistAddr() external view returns (address);\n\n function setMaxSupplyDiff(uint256 _maxSupplyDiff) external;\n\n function maxSupplyDiff() external view returns (uint256);\n\n function setTrusteeAddress(address _address) external;\n\n function trusteeAddress() external view returns (address);\n\n function setTrusteeFeeBps(uint256 _basis) external;\n\n function trusteeFeeBps() external view returns (uint256);\n\n function ousdMetaStrategy() external view returns (address);\n\n function setSwapper(address _swapperAddr) external;\n\n function setSwapAllowedUndervalue(uint16 _percentageBps) external;\n\n function setOracleSlippage(address _asset, uint16 _allowedOracleSlippageBps)\n external;\n\n function supportAsset(address _asset, uint8 _supportsAsset) external;\n\n function approveStrategy(address _addr) external;\n\n function removeStrategy(address _addr) external;\n\n function setAssetDefaultStrategy(address _asset, address _strategy)\n external;\n\n function assetDefaultStrategies(address _asset)\n external\n view\n returns (address);\n\n function pauseRebase() external;\n\n function unpauseRebase() external;\n\n function rebasePaused() external view returns (bool);\n\n function pauseCapital() external;\n\n function unpauseCapital() external;\n\n function capitalPaused() external view returns (bool);\n\n function transferToken(address _asset, uint256 _amount) external;\n\n function priceUnitMint(address asset) external view returns (uint256);\n\n function priceUnitRedeem(address asset) external view returns (uint256);\n\n function withdrawAllFromStrategy(address _strategyAddr) external;\n\n function withdrawAllFromStrategies() external;\n\n function withdrawFromStrategy(\n address _strategyFromAddress,\n address[] calldata _assets,\n uint256[] calldata _amounts\n ) external;\n\n function depositToStrategy(\n address _strategyToAddress,\n address[] calldata _assets,\n uint256[] calldata _amounts\n ) external;\n\n // VaultCore.sol\n function mint(\n address _asset,\n uint256 _amount,\n uint256 _minimumOusdAmount\n ) external;\n\n function mintForStrategy(uint256 _amount) external;\n\n function redeem(uint256 _amount, uint256 _minimumUnitAmount) external;\n\n function burnForStrategy(uint256 _amount) external;\n\n function redeemAll(uint256 _minimumUnitAmount) external;\n\n function allocate() external;\n\n function rebase() external;\n\n function swapCollateral(\n address fromAsset,\n address toAsset,\n uint256 fromAssetAmount,\n uint256 minToAssetAmount,\n bytes calldata data\n ) external returns (uint256 toAssetAmount);\n\n function totalValue() external view returns (uint256 value);\n\n function checkBalance(address _asset) external view returns (uint256);\n\n function calculateRedeemOutputs(uint256 _amount)\n external\n view\n returns (uint256[] memory);\n\n function getAssetCount() external view returns (uint256);\n\n function getAssetConfig(address _asset)\n external\n view\n returns (VaultStorage.Asset memory config);\n\n function getAllAssets() external view returns (address[] memory);\n\n function getStrategyCount() external view returns (uint256);\n\n function swapper() external view returns (address);\n\n function allowedSwapUndervalue() external view returns (uint256);\n\n function getAllStrategies() external view returns (address[] memory);\n\n function isSupportedAsset(address _asset) external view returns (bool);\n\n function netOusdMintForStrategyThreshold() external view returns (uint256);\n\n function setOusdMetaStrategy(address _ousdMetaStrategy) external;\n\n function setNetOusdMintForStrategyThreshold(uint256 _threshold) external;\n\n function netOusdMintedForStrategy() external view returns (int256);\n\n function setDripper(address _dripper) external;\n\n function weth() external view returns (address);\n\n function cacheWETHAssetIndex() external;\n\n function wethAssetIndex() external view returns (uint256);\n\n function initialize(address, address) external;\n\n function setAdminImpl(address) external;\n\n function removeAsset(address _asset) external;\n\n // These are OETH specific functions\n function addWithdrawalQueueLiquidity() external;\n\n function requestWithdrawal(uint256 _amount)\n external\n returns (uint256 requestId, uint256 queued);\n\n function claimWithdrawal(uint256 requestId)\n external\n returns (uint256 amount);\n\n function claimWithdrawals(uint256[] memory requestIds)\n external\n returns (uint256[] memory amounts, uint256 totalAmount);\n\n function withdrawalQueueMetadata()\n external\n view\n returns (VaultStorage.WithdrawalQueueMetadata memory);\n\n function withdrawalRequests(uint256 requestId)\n external\n view\n returns (VaultStorage.WithdrawalRequest memory);\n}\n" + }, + "contracts/interfaces/IWETH9.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IWETH9 {\n event Approval(address indexed src, address indexed guy, uint256 wad);\n event Deposit(address indexed dst, uint256 wad);\n event Transfer(address indexed src, address indexed dst, uint256 wad);\n event Withdrawal(address indexed src, uint256 wad);\n\n function allowance(address, address) external view returns (uint256);\n\n function approve(address guy, uint256 wad) external returns (bool);\n\n function balanceOf(address) external view returns (uint256);\n\n function decimals() external view returns (uint8);\n\n function deposit() external payable;\n\n function name() external view returns (string memory);\n\n function symbol() external view returns (string memory);\n\n function totalSupply() external view returns (uint256);\n\n function transfer(address dst, uint256 wad) external returns (bool);\n\n function transferFrom(\n address src,\n address dst,\n uint256 wad\n ) external returns (bool);\n\n function withdraw(uint256 wad) external;\n}\n" + }, + "contracts/interfaces/IWstETH.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IWstETH {\n /**\n * @notice Get amount of wstETH for a given amount of stETH\n * @param _stETHAmount amount of stETH\n * @return Amount of wstETH for a given stETH amount\n */\n function getWstETHByStETH(uint256 _stETHAmount)\n external\n view\n returns (uint256);\n\n /**\n * @notice Get amount of stETH for a given amount of wstETH\n * @param _wstETHAmount amount of wstETH\n * @return Amount of stETH for a given wstETH amount\n */\n function getStETHByWstETH(uint256 _wstETHAmount)\n external\n view\n returns (uint256);\n\n /**\n * @notice Get amount of stETH for a one wstETH\n * @return Amount of stETH for 1 wstETH\n */\n function stEthPerToken() external view returns (uint256);\n\n /**\n * @notice Get amount of wstETH for a one stETH\n * @return Amount of wstETH for a 1 stETH\n */\n function tokensPerStEth() external view returns (uint256);\n\n /**\n * @notice Exchanges stETH to wstETH\n * @param _stETHAmount amount of stETH to wrap in exchange for wstETH\n * @dev Requirements:\n * - `_stETHAmount` must be non-zero\n * - msg.sender must approve at least `_stETHAmount` stETH to this\n * contract.\n * - msg.sender must have at least `_stETHAmount` of stETH.\n * User should first approve _stETHAmount to the WstETH contract\n * @return Amount of wstETH user receives after wrap\n */\n function wrap(uint256 _stETHAmount) external returns (uint256);\n\n /**\n * @notice Exchanges wstETH to stETH\n * @param _wstETHAmount amount of wstETH to uwrap in exchange for stETH\n * @dev Requirements:\n * - `_wstETHAmount` must be non-zero\n * - msg.sender must have at least `_wstETHAmount` wstETH.\n * @return Amount of stETH user receives after unwrap\n */\n function unwrap(uint256 _wstETHAmount) external returns (uint256);\n}\n" + }, + "contracts/interfaces/morpho/compound/ICompoundOracle.sol": { + "content": "// SPDX-License-Identifier: GNU AGPLv3\npragma solidity ^0.8.0;\n\ninterface ICompoundOracle {\n function getUnderlyingPrice(address) external view returns (uint256);\n}\n" + }, + "contracts/interfaces/morpho/ILens.sol": { + "content": "// SPDX-License-Identifier: GNU AGPLv3\npragma solidity ^0.8.0;\n\nimport \"./compound/ICompoundOracle.sol\";\nimport \"./IMorpho.sol\";\n\ninterface ILens {\n /// STORAGE ///\n\n function MAX_BASIS_POINTS() external view returns (uint256);\n\n function WAD() external view returns (uint256);\n\n function morpho() external view returns (IMorpho);\n\n function comptroller() external view returns (IComptroller);\n\n /// GENERAL ///\n\n function getTotalSupply()\n external\n view\n returns (\n uint256 p2pSupplyAmount,\n uint256 poolSupplyAmount,\n uint256 totalSupplyAmount\n );\n\n function getTotalBorrow()\n external\n view\n returns (\n uint256 p2pBorrowAmount,\n uint256 poolBorrowAmount,\n uint256 totalBorrowAmount\n );\n\n /// MARKETS ///\n\n function isMarketCreated(address _poolToken) external view returns (bool);\n\n function isMarketCreatedAndNotPaused(address _poolToken)\n external\n view\n returns (bool);\n\n function isMarketCreatedAndNotPausedNorPartiallyPaused(address _poolToken)\n external\n view\n returns (bool);\n\n function getAllMarkets()\n external\n view\n returns (address[] memory marketsCreated_);\n\n function getMainMarketData(address _poolToken)\n external\n view\n returns (\n uint256 avgSupplyRatePerBlock,\n uint256 avgBorrowRatePerBlock,\n uint256 p2pSupplyAmount,\n uint256 p2pBorrowAmount,\n uint256 poolSupplyAmount,\n uint256 poolBorrowAmount\n );\n\n function getAdvancedMarketData(address _poolToken)\n external\n view\n returns (\n uint256 p2pSupplyIndex,\n uint256 p2pBorrowIndex,\n uint256 poolSupplyIndex,\n uint256 poolBorrowIndex,\n uint32 lastUpdateBlockNumber,\n uint256 p2pSupplyDelta,\n uint256 p2pBorrowDelta\n );\n\n function getMarketConfiguration(address _poolToken)\n external\n view\n returns (\n address underlying,\n bool isCreated,\n bool p2pDisabled,\n bool isPaused,\n bool isPartiallyPaused,\n uint16 reserveFactor,\n uint16 p2pIndexCursor,\n uint256 collateralFactor\n );\n\n function getTotalMarketSupply(address _poolToken)\n external\n view\n returns (uint256 p2pSupplyAmount, uint256 poolSupplyAmount);\n\n function getTotalMarketBorrow(address _poolToken)\n external\n view\n returns (uint256 p2pBorrowAmount, uint256 poolBorrowAmount);\n\n /// INDEXES ///\n\n function getCurrentP2PSupplyIndex(address _poolToken)\n external\n view\n returns (uint256);\n\n function getCurrentP2PBorrowIndex(address _poolToken)\n external\n view\n returns (uint256);\n\n function getCurrentPoolIndexes(address _poolToken)\n external\n view\n returns (\n uint256 currentPoolSupplyIndex,\n uint256 currentPoolBorrowIndex\n );\n\n function getIndexes(address _poolToken, bool _computeUpdatedIndexes)\n external\n view\n returns (\n uint256 p2pSupplyIndex,\n uint256 p2pBorrowIndex,\n uint256 poolSupplyIndex,\n uint256 poolBorrowIndex\n );\n\n /// USERS ///\n\n function getEnteredMarkets(address _user)\n external\n view\n returns (address[] memory enteredMarkets);\n\n function getUserHealthFactor(\n address _user,\n address[] calldata _updatedMarkets\n ) external view returns (uint256);\n\n function getUserBalanceStates(\n address _user,\n address[] calldata _updatedMarkets\n )\n external\n view\n returns (\n uint256 collateralValue,\n uint256 debtValue,\n uint256 maxDebtValue\n );\n\n function getCurrentSupplyBalanceInOf(address _poolToken, address _user)\n external\n view\n returns (\n uint256 balanceOnPool,\n uint256 balanceInP2P,\n uint256 totalBalance\n );\n\n function getCurrentBorrowBalanceInOf(address _poolToken, address _user)\n external\n view\n returns (\n uint256 balanceOnPool,\n uint256 balanceInP2P,\n uint256 totalBalance\n );\n\n function getUserMaxCapacitiesForAsset(address _user, address _poolToken)\n external\n view\n returns (uint256 withdrawable, uint256 borrowable);\n\n function getUserHypotheticalBalanceStates(\n address _user,\n address _poolToken,\n uint256 _withdrawnAmount,\n uint256 _borrowedAmount\n ) external view returns (uint256 debtValue, uint256 maxDebtValue);\n\n function getUserLiquidityDataForAsset(\n address _user,\n address _poolToken,\n bool _computeUpdatedIndexes,\n ICompoundOracle _oracle\n ) external view returns (Types.AssetLiquidityData memory assetData);\n\n function isLiquidatable(address _user, address[] memory _updatedMarkets)\n external\n view\n returns (bool);\n\n function computeLiquidationRepayAmount(\n address _user,\n address _poolTokenBorrowed,\n address _poolTokenCollateral,\n address[] calldata _updatedMarkets\n ) external view returns (uint256 toRepay);\n\n /// RATES ///\n\n function getAverageSupplyRatePerBlock(address _poolToken)\n external\n view\n returns (\n uint256 avgSupplyRatePerBlock,\n uint256 p2pSupplyAmount,\n uint256 poolSupplyAmount\n );\n\n function getAverageBorrowRatePerBlock(address _poolToken)\n external\n view\n returns (\n uint256 avgBorrowRatePerBlock,\n uint256 p2pBorrowAmount,\n uint256 poolBorrowAmount\n );\n\n function getNextUserSupplyRatePerBlock(\n address _poolToken,\n address _user,\n uint256 _amount\n )\n external\n view\n returns (\n uint256 nextSupplyRatePerBlock,\n uint256 balanceOnPool,\n uint256 balanceInP2P,\n uint256 totalBalance\n );\n\n function getNextUserBorrowRatePerBlock(\n address _poolToken,\n address _user,\n uint256 _amount\n )\n external\n view\n returns (\n uint256 nextBorrowRatePerBlock,\n uint256 balanceOnPool,\n uint256 balanceInP2P,\n uint256 totalBalance\n );\n\n function getCurrentUserSupplyRatePerBlock(address _poolToken, address _user)\n external\n view\n returns (uint256);\n\n function getCurrentUserBorrowRatePerBlock(address _poolToken, address _user)\n external\n view\n returns (uint256);\n\n function getRatesPerBlock(address _poolToken)\n external\n view\n returns (\n uint256 p2pSupplyRate,\n uint256 p2pBorrowRate,\n uint256 poolSupplyRate,\n uint256 poolBorrowRate\n );\n\n /// REWARDS ///\n\n function getUserUnclaimedRewards(\n address[] calldata _poolTokens,\n address _user\n ) external view returns (uint256 unclaimedRewards);\n\n function getAccruedSupplierComp(\n address _supplier,\n address _poolToken,\n uint256 _balance\n ) external view returns (uint256);\n\n function getAccruedBorrowerComp(\n address _borrower,\n address _poolToken,\n uint256 _balance\n ) external view returns (uint256);\n\n function getCurrentCompSupplyIndex(address _poolToken)\n external\n view\n returns (uint256);\n\n function getCurrentCompBorrowIndex(address _poolToken)\n external\n view\n returns (uint256);\n}\n" + }, + "contracts/interfaces/morpho/IMorpho.sol": { + "content": "// SPDX-License-Identifier: GNU AGPLv3\npragma solidity ^0.8.0;\n\nimport \"./Types.sol\";\nimport \"../IComptroller.sol\";\nimport \"./compound/ICompoundOracle.sol\";\n\n// prettier-ignore\ninterface IMorpho {\n function comptroller() external view returns (IComptroller);\n function supply(address _poolTokenAddress, address _onBehalf, uint256 _amount) external;\n function supply(address _poolTokenAddress, address _onBehalf, uint256 _amount, uint256 _maxGasForMatching) external;\n function withdraw(address _poolTokenAddress, uint256 _amount) external;\n function claimRewards(\n address[] calldata _cTokenAddresses,\n bool _tradeForMorphoToken\n ) external returns (uint256 claimedAmount);\n}\n" + }, + "contracts/interfaces/morpho/Types.sol": { + "content": "// SPDX-License-Identifier: GNU AGPLv3\npragma solidity ^0.8.0;\n\n/// @title Types.\n/// @author Morpho Labs.\n/// @custom:contact security@morpho.xyz\n/// @dev Common types and structs used in Moprho contracts.\nlibrary Types {\n /// ENUMS ///\n\n enum PositionType {\n SUPPLIERS_IN_P2P,\n SUPPLIERS_ON_POOL,\n BORROWERS_IN_P2P,\n BORROWERS_ON_POOL\n }\n\n /// STRUCTS ///\n\n struct SupplyBalance {\n uint256 inP2P; // In supplier's peer-to-peer unit, a unit that grows in underlying value, to keep track of the interests earned by suppliers in peer-to-peer. Multiply by the peer-to-peer supply index to get the underlying amount.\n uint256 onPool; // In cToken. Multiply by the pool supply index to get the underlying amount.\n }\n\n struct BorrowBalance {\n uint256 inP2P; // In borrower's peer-to-peer unit, a unit that grows in underlying value, to keep track of the interests paid by borrowers in peer-to-peer. Multiply by the peer-to-peer borrow index to get the underlying amount.\n uint256 onPool; // In cdUnit, a unit that grows in value, to keep track of the debt increase when borrowers are on Compound. Multiply by the pool borrow index to get the underlying amount.\n }\n\n // Max gas to consume during the matching process for supply, borrow, withdraw and repay functions.\n struct MaxGasForMatching {\n uint64 supply;\n uint64 borrow;\n uint64 withdraw;\n uint64 repay;\n }\n\n struct Delta {\n uint256 p2pSupplyDelta; // Difference between the stored peer-to-peer supply amount and the real peer-to-peer supply amount (in pool supply unit).\n uint256 p2pBorrowDelta; // Difference between the stored peer-to-peer borrow amount and the real peer-to-peer borrow amount (in pool borrow unit).\n uint256 p2pSupplyAmount; // Sum of all stored peer-to-peer supply (in peer-to-peer supply unit).\n uint256 p2pBorrowAmount; // Sum of all stored peer-to-peer borrow (in peer-to-peer borrow unit).\n }\n\n struct AssetLiquidityData {\n uint256 collateralValue; // The collateral value of the asset.\n uint256 maxDebtValue; // The maximum possible debt value of the asset.\n uint256 debtValue; // The debt value of the asset.\n uint256 underlyingPrice; // The price of the token.\n uint256 collateralFactor; // The liquidation threshold applied on this token.\n }\n\n struct LiquidityData {\n uint256 collateralValue; // The collateral value.\n uint256 maxDebtValue; // The maximum debt value possible.\n uint256 debtValue; // The debt value.\n }\n\n // Variables are packed together to save gas (will not exceed their limit during Morpho's lifetime).\n struct LastPoolIndexes {\n uint32 lastUpdateBlockNumber; // The last time the peer-to-peer indexes were updated.\n uint112 lastSupplyPoolIndex; // Last pool supply index.\n uint112 lastBorrowPoolIndex; // Last pool borrow index.\n }\n\n struct MarketParameters {\n uint16 reserveFactor; // Proportion of the interest earned by users sent to the DAO for each market, in basis point (100% = 10 000). The value is set at market creation.\n uint16 p2pIndexCursor; // Position of the peer-to-peer rate in the pool's spread. Determine the weights of the weighted arithmetic average in the indexes computations ((1 - p2pIndexCursor) * r^S + p2pIndexCursor * r^B) (in basis point).\n }\n\n struct MarketStatus {\n bool isCreated; // Whether or not this market is created.\n bool isPaused; // Whether the market is paused or not (all entry points on Morpho are frozen; supply, borrow, withdraw, repay and liquidate).\n bool isPartiallyPaused; // Whether the market is partially paused or not (only supply and borrow are frozen).\n }\n}\n" + }, + "contracts/interfaces/uniswap/IUniswapV2Router02.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IUniswapV2Router {\n function WETH() external pure returns (address);\n\n function swapExactTokensForTokens(\n uint256 amountIn,\n uint256 amountOutMin,\n address[] calldata path,\n address to,\n uint256 deadline\n ) external returns (uint256[] memory amounts);\n\n function addLiquidity(\n address tokenA,\n address tokenB,\n uint256 amountADesired,\n uint256 amountBDesired,\n uint256 amountAMin,\n uint256 amountBMin,\n address to,\n uint256 deadline\n )\n external\n returns (\n uint256 amountA,\n uint256 amountB,\n uint256 liquidity\n );\n}\n" + }, + "contracts/interfaces/uniswap/IUniswapV3Router.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n// -- Solididy v0.5.x compatible interface\ninterface IUniswapV3Router {\n struct ExactInputParams {\n bytes path;\n address recipient;\n uint256 deadline;\n uint256 amountIn;\n uint256 amountOutMinimum;\n }\n\n /// @notice Swaps `amountIn` of one token for as much as possible of another along the specified path\n /// @param params The parameters necessary for the multi-hop swap, encoded as `ExactInputParams` in calldata\n /// @return amountOut The amount of the received token\n function exactInput(ExactInputParams calldata params)\n external\n payable\n returns (uint256 amountOut);\n}\n" + }, + "contracts/mocks/MintableERC20.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { ERC20 } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ninterface IMintableERC20 {\n function mint(uint256 value) external;\n\n function mintTo(address to, uint256 value) external;\n}\n\n/**\n * @title MintableERC20\n * @dev Exposes the mint function of ERC20 for tests\n */\nabstract contract MintableERC20 is IMintableERC20, ERC20 {\n /**\n * @dev Function to mint tokens\n * @param _value The amount of tokens to mint.\n */\n function mint(uint256 _value) public virtual override {\n _mint(msg.sender, _value);\n }\n\n /**\n * @dev Function to mint tokens\n * @param _to Address to mint to.\n * @param _value The amount of tokens to mint.\n */\n function mintTo(address _to, uint256 _value) public virtual override {\n _mint(_to, _value);\n }\n}\n" + }, + "contracts/mocks/MockBalancerVault.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { IBalancerVault } from \"../interfaces/balancer/IBalancerVault.sol\";\nimport { MintableERC20 } from \"./MintableERC20.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\n\n// import \"hardhat/console.sol\";\n\ncontract MockBalancerVault {\n using StableMath for uint256;\n uint256 public slippage = 1 ether;\n bool public transferDisabled = false;\n bool public slippageErrorDisabled = false;\n\n function swap(\n IBalancerVault.SingleSwap calldata singleSwap,\n IBalancerVault.FundManagement calldata funds,\n uint256 minAmountOut,\n uint256\n ) external returns (uint256 amountCalculated) {\n amountCalculated = (minAmountOut * slippage) / 1 ether;\n if (!slippageErrorDisabled) {\n require(amountCalculated >= minAmountOut, \"Slippage error\");\n }\n IERC20(singleSwap.assetIn).transferFrom(\n funds.sender,\n address(this),\n singleSwap.amount\n );\n if (!transferDisabled) {\n MintableERC20(singleSwap.assetOut).mintTo(\n funds.recipient,\n amountCalculated\n );\n }\n }\n\n function setSlippage(uint256 _slippage) external {\n slippage = _slippage;\n }\n\n function getPoolTokenInfo(bytes32 poolId, address token)\n external\n view\n returns (\n uint256,\n uint256,\n uint256,\n address\n )\n {}\n\n function disableTransfer() external {\n transferDisabled = true;\n }\n\n function disableSlippageError() external {\n slippageErrorDisabled = true;\n }\n}\n" + }, + "contracts/mocks/MockEvilDAI.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./MintableERC20.sol\";\nimport { IVault } from \"../interfaces/IVault.sol\";\n\ncontract MockEvilDAI is MintableERC20 {\n address host;\n address realCoin;\n\n constructor(address _host, address _realCoin) ERC20(\"DAI\", \"DAI\") {\n host = _host;\n realCoin = _realCoin;\n }\n\n function transferFrom(\n // solhint-disable-next-line no-unused-vars\n address _from,\n // solhint-disable-next-line no-unused-vars\n address _to,\n uint256 _amount\n ) public override returns (bool) {\n // call mint again!\n if (_amount != 69) {\n IVault(host).mint(address(this), 69, 0);\n }\n return true;\n }\n}\n" + }, + "contracts/mocks/MockEvilReentrantContract.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { IVault } from \"../interfaces/IVault.sol\";\nimport { IOracle } from \"../interfaces/IOracle.sol\";\nimport { IRateProvider } from \"../interfaces/balancer/IRateProvider.sol\";\n\nimport { IBalancerVault } from \"../interfaces/balancer/IBalancerVault.sol\";\nimport { IERC20 } from \"../utils/InitializableAbstractStrategy.sol\";\n\nimport { StableMath } from \"../utils/StableMath.sol\";\n\ncontract MockEvilReentrantContract {\n using StableMath for uint256;\n\n IBalancerVault public immutable balancerVault;\n IERC20 public immutable reth;\n IERC20 public immutable weth;\n IVault public immutable oethVault;\n address public immutable poolAddress;\n bytes32 public immutable balancerPoolId;\n\n constructor(\n address _balancerVault,\n address _oethVault,\n address _reth,\n address _weth,\n address _poolAddress,\n bytes32 _poolId\n ) {\n balancerVault = IBalancerVault(_balancerVault);\n oethVault = IVault(_oethVault);\n reth = IERC20(_reth);\n weth = IERC20(_weth);\n poolAddress = _poolAddress;\n balancerPoolId = _poolId;\n }\n\n function doEvilStuff() public {\n address priceProvider = oethVault.priceProvider();\n uint256 rethPrice = IOracle(priceProvider).price(address(reth));\n\n // 1. Join pool\n uint256[] memory amounts = new uint256[](2);\n amounts[0] = uint256(10 ether);\n amounts[1] = rethPrice * 10;\n\n address[] memory assets = new address[](2);\n assets[0] = address(reth);\n assets[1] = address(weth);\n\n uint256 minBPT = getBPTExpected(assets, amounts).mulTruncate(\n 0.99 ether\n );\n\n bytes memory joinUserData = abi.encode(\n IBalancerVault.WeightedPoolJoinKind.EXACT_TOKENS_IN_FOR_BPT_OUT,\n amounts,\n minBPT\n );\n\n IBalancerVault.JoinPoolRequest memory joinRequest = IBalancerVault\n .JoinPoolRequest(assets, amounts, joinUserData, false);\n\n balancerVault.joinPool(\n balancerPoolId,\n address(this),\n address(this),\n joinRequest\n );\n\n uint256 bptTokenBalance = IERC20(poolAddress).balanceOf(address(this));\n\n // 2. Redeem as ETH\n bytes memory exitUserData = abi.encode(\n IBalancerVault.WeightedPoolExitKind.EXACT_BPT_IN_FOR_ONE_TOKEN_OUT,\n bptTokenBalance,\n 1\n );\n\n assets[1] = address(0); // Receive ETH instead of WETH\n uint256[] memory exitAmounts = new uint256[](2);\n exitAmounts[1] = 15 ether;\n IBalancerVault.ExitPoolRequest memory exitRequest = IBalancerVault\n .ExitPoolRequest(assets, exitAmounts, exitUserData, false);\n\n balancerVault.exitPool(\n balancerPoolId,\n address(this),\n payable(address(this)),\n exitRequest\n );\n bptTokenBalance = IERC20(poolAddress).balanceOf(address(this));\n }\n\n function getBPTExpected(address[] memory _assets, uint256[] memory _amounts)\n internal\n view\n virtual\n returns (uint256 bptExpected)\n {\n // Get the oracle from the OETH Vault\n address priceProvider = oethVault.priceProvider();\n\n for (uint256 i = 0; i < _assets.length; ++i) {\n uint256 strategyAssetMarketPrice = IOracle(priceProvider).price(\n _assets[i]\n );\n // convert asset amount to ETH amount\n bptExpected =\n bptExpected +\n _amounts[i].mulTruncate(strategyAssetMarketPrice);\n }\n\n uint256 bptRate = IRateProvider(poolAddress).getRate();\n // Convert ETH amount to BPT amount\n bptExpected = bptExpected.divPrecisely(bptRate);\n }\n\n function approveAllTokens() public {\n // Approve all tokens\n weth.approve(address(oethVault), type(uint256).max);\n reth.approve(poolAddress, type(uint256).max);\n weth.approve(poolAddress, type(uint256).max);\n reth.approve(address(balancerVault), type(uint256).max);\n weth.approve(address(balancerVault), type(uint256).max);\n }\n\n receive() external payable {\n // 3. Try to mint OETH\n oethVault.mint(address(weth), 1 ether, 0.9 ether);\n }\n}\n" + }, + "contracts/mocks/MockNonRebasing.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\nimport { IVault } from \"../interfaces/IVault.sol\";\n\nimport { OUSD } from \"../token/OUSD.sol\";\n\ncontract MockNonRebasing {\n OUSD oUSD;\n\n function setOUSD(address _oUSDAddress) public {\n oUSD = OUSD(_oUSDAddress);\n }\n\n function rebaseOptIn() public {\n oUSD.rebaseOptIn();\n }\n\n function rebaseOptOut() public {\n oUSD.rebaseOptOut();\n }\n\n function transfer(address _to, uint256 _value) public {\n oUSD.transfer(_to, _value);\n }\n\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n ) public {\n oUSD.transferFrom(_from, _to, _value);\n }\n\n function increaseAllowance(address _spender, uint256 _addedValue) public {\n oUSD.increaseAllowance(_spender, _addedValue);\n }\n\n function mintOusd(\n address _vaultContract,\n address _asset,\n uint256 _amount\n ) public {\n IVault(_vaultContract).mint(_asset, _amount, 0);\n }\n\n function redeemOusd(address _vaultContract, uint256 _amount) public {\n IVault(_vaultContract).redeem(_amount, 0);\n }\n\n function approveFor(\n address _contract,\n address _spender,\n uint256 _addedValue\n ) public {\n IERC20(_contract).approve(_spender, _addedValue);\n }\n}\n" + }, + "contracts/mocks/MockOETHVault.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { OETHVaultCore } from \"../vault/OETHVaultCore.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\nimport \"../utils/Helpers.sol\";\n\ncontract MockOETHVault is OETHVaultCore {\n using StableMath for uint256;\n\n constructor(address _weth) OETHVaultCore(_weth) {}\n\n function supportAsset(address asset) external {\n assets[asset] = Asset({\n isSupported: true,\n unitConversion: UnitConversion(0),\n decimals: 18,\n allowedOracleSlippageBps: 0\n });\n\n allAssets.push(asset);\n }\n}\n" + }, + "contracts/mocks/MockRebornMinter.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { IVault } from \"../interfaces/IVault.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n// solhint-disable-next-line no-console\nimport \"hardhat/console.sol\";\n\ncontract Sanctum {\n address public asset;\n address public vault;\n address public reborner;\n bool public shouldAttack = false;\n uint256 public targetMethod;\n address public ousdContract;\n\n constructor(address _asset, address _vault) {\n asset = _asset;\n vault = _vault;\n }\n\n function deploy(uint256 salt, bytes memory bytecode)\n public\n returns (address addr)\n {\n // solhint-disable-next-line no-inline-assembly\n assembly {\n addr := create2(0, add(bytecode, 0x20), mload(bytecode), salt)\n }\n require(addr != address(0), \"Create2: Failed on deploy\");\n }\n\n function computeAddress(uint256 salt, bytes memory bytecode)\n public\n view\n returns (address)\n {\n bytes32 bytecodeHashHash = keccak256(bytecode);\n bytes32 _data = keccak256(\n abi.encodePacked(\n bytes1(0xff),\n address(this),\n salt,\n bytecodeHashHash\n )\n );\n return address(bytes20(_data << 96));\n }\n\n function setShouldAttack(bool _shouldAttack) public {\n shouldAttack = _shouldAttack;\n }\n\n function setTargetMethod(uint256 target) public {\n targetMethod = target;\n }\n\n function setOUSDAddress(address _ousdContract) public {\n ousdContract = _ousdContract;\n }\n}\n\ncontract Reborner {\n Sanctum sanctum;\n bool logging = false;\n\n constructor(address _sanctum) {\n log(\"We are created...\");\n sanctum = Sanctum(_sanctum);\n if (sanctum.shouldAttack()) {\n log(\"We are attacking now...\");\n\n uint256 target = sanctum.targetMethod();\n\n if (target == 1) {\n redeem();\n } else if (target == 2) {\n transfer();\n } else {\n mint();\n }\n }\n }\n\n function mint() public {\n log(\"We are attempting to mint..\");\n address asset = sanctum.asset();\n address vault = sanctum.vault();\n IERC20(asset).approve(vault, 1e18);\n IVault(vault).mint(asset, 1e18, 0);\n log(\"We are now minting..\");\n }\n\n function redeem() public {\n log(\"We are attempting to redeem..\");\n address vault = sanctum.vault();\n IVault(vault).redeem(1e18, 1e18);\n log(\"We are now redeeming..\");\n }\n\n function transfer() public {\n log(\"We are attempting to transfer..\");\n address ousd = sanctum.ousdContract();\n require(IERC20(ousd).transfer(address(1), 1e18), \"transfer failed\");\n log(\"We are now transfering..\");\n }\n\n function bye() public {\n log(\"We are now destructing..\");\n selfdestruct(payable(msg.sender));\n }\n\n function log(string memory message) internal view {\n if (logging) {\n // solhint-disable-next-line no-console\n console.log(message);\n }\n }\n}\n" + }, + "contracts/mocks/MockVault.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { VaultCore } from \"../vault/VaultCore.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\nimport { VaultInitializer } from \"../vault/VaultInitializer.sol\";\nimport \"../utils/Helpers.sol\";\n\ncontract MockVault is VaultCore {\n using StableMath for uint256;\n\n uint256 storedTotalValue;\n\n function setTotalValue(uint256 _value) public {\n storedTotalValue = _value;\n }\n\n function totalValue() external view override returns (uint256) {\n return storedTotalValue;\n }\n\n function _totalValue() internal view override returns (uint256) {\n return storedTotalValue;\n }\n\n function _checkBalance(address _asset)\n internal\n view\n override\n returns (uint256 balance)\n {\n // Avoids rounding errors by returning the total value\n // in a single currency\n if (allAssets[0] == _asset) {\n uint256 decimals = Helpers.getDecimals(_asset);\n return storedTotalValue.scaleBy(decimals, 18);\n } else {\n return 0;\n }\n }\n\n function setMaxSupplyDiff(uint256 _maxSupplyDiff) external onlyGovernor {\n maxSupplyDiff = _maxSupplyDiff;\n }\n}\n" + }, + "contracts/strategies/AaveStrategy.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @title OUSD Aave Strategy\n * @notice Investment strategy for investing stablecoins via Aave\n * @author Origin Protocol Inc\n */\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nimport \"./IAave.sol\";\nimport { IERC20, InitializableAbstractStrategy } from \"../utils/InitializableAbstractStrategy.sol\";\n\nimport { IAaveStakedToken } from \"./IAaveStakeToken.sol\";\nimport { IAaveIncentivesController } from \"./IAaveIncentivesController.sol\";\n\ncontract AaveStrategy is InitializableAbstractStrategy {\n using SafeERC20 for IERC20;\n\n uint16 constant referralCode = 92;\n\n IAaveIncentivesController public incentivesController;\n IAaveStakedToken public stkAave;\n\n /**\n * @param _stratConfig The platform and OToken vault addresses\n */\n constructor(BaseStrategyConfig memory _stratConfig)\n InitializableAbstractStrategy(_stratConfig)\n {}\n\n /**\n * Initializer for setting up strategy internal state. This overrides the\n * InitializableAbstractStrategy initializer as AAVE needs several extra\n * addresses for the rewards program.\n * @param _rewardTokenAddresses Address of the AAVE token\n * @param _assets Addresses of supported assets\n * @param _pTokens Platform Token corresponding addresses\n * @param _incentivesAddress Address of the AAVE incentives controller\n * @param _stkAaveAddress Address of the stkAave contract\n */\n function initialize(\n address[] calldata _rewardTokenAddresses, // AAVE\n address[] calldata _assets,\n address[] calldata _pTokens,\n address _incentivesAddress,\n address _stkAaveAddress\n ) external onlyGovernor initializer {\n incentivesController = IAaveIncentivesController(_incentivesAddress);\n stkAave = IAaveStakedToken(_stkAaveAddress);\n InitializableAbstractStrategy._initialize(\n _rewardTokenAddresses,\n _assets,\n _pTokens\n );\n }\n\n /**\n * @dev Deposit asset into Aave\n * @param _asset Address of asset to deposit\n * @param _amount Amount of asset to deposit\n */\n function deposit(address _asset, uint256 _amount)\n external\n override\n onlyVault\n nonReentrant\n {\n _deposit(_asset, _amount);\n }\n\n /**\n * @dev Deposit asset into Aave\n * @param _asset Address of asset to deposit\n * @param _amount Amount of asset to deposit\n */\n function _deposit(address _asset, uint256 _amount) internal {\n require(_amount > 0, \"Must deposit something\");\n // Following line also doubles as a check that we are depositing\n // an asset that we support.\n emit Deposit(_asset, _getATokenFor(_asset), _amount);\n _getLendingPool().deposit(_asset, _amount, address(this), referralCode);\n }\n\n /**\n * @dev Deposit the entire balance of any supported asset into Aave\n */\n function depositAll() external override onlyVault nonReentrant {\n for (uint256 i = 0; i < assetsMapped.length; i++) {\n uint256 balance = IERC20(assetsMapped[i]).balanceOf(address(this));\n if (balance > 0) {\n _deposit(assetsMapped[i], balance);\n }\n }\n }\n\n /**\n * @dev Withdraw asset from Aave\n * @param _recipient Address to receive withdrawn asset\n * @param _asset Address of asset to withdraw\n * @param _amount Amount of asset to withdraw\n */\n function withdraw(\n address _recipient,\n address _asset,\n uint256 _amount\n ) external override onlyVault nonReentrant {\n require(_amount > 0, \"Must withdraw something\");\n require(_recipient != address(0), \"Must specify recipient\");\n\n emit Withdrawal(_asset, _getATokenFor(_asset), _amount);\n uint256 actual = _getLendingPool().withdraw(\n _asset,\n _amount,\n address(this)\n );\n require(actual == _amount, \"Did not withdraw enough\");\n IERC20(_asset).safeTransfer(_recipient, _amount);\n }\n\n /**\n * @dev Remove all assets from platform and send them to Vault contract.\n */\n function withdrawAll() external override onlyVaultOrGovernor nonReentrant {\n for (uint256 i = 0; i < assetsMapped.length; i++) {\n // Redeem entire balance of aToken\n IERC20 asset = IERC20(assetsMapped[i]);\n address aToken = _getATokenFor(assetsMapped[i]);\n uint256 balance = IERC20(aToken).balanceOf(address(this));\n if (balance > 0) {\n uint256 actual = _getLendingPool().withdraw(\n address(asset),\n balance,\n address(this)\n );\n require(actual == balance, \"Did not withdraw enough\");\n\n uint256 assetBalance = asset.balanceOf(address(this));\n // Transfer entire balance to Vault\n asset.safeTransfer(vaultAddress, assetBalance);\n\n emit Withdrawal(address(asset), aToken, assetBalance);\n }\n }\n }\n\n /**\n * @dev Get the total asset value held in the platform\n * @param _asset Address of the asset\n * @return balance Total value of the asset in the platform\n */\n function checkBalance(address _asset)\n external\n view\n override\n returns (uint256 balance)\n {\n // Balance is always with token aToken decimals\n address aToken = _getATokenFor(_asset);\n balance = IERC20(aToken).balanceOf(address(this));\n }\n\n /**\n * @dev Returns bool indicating whether asset is supported by strategy\n * @param _asset Address of the asset\n */\n function supportsAsset(address _asset) public view override returns (bool) {\n return assetToPToken[_asset] != address(0);\n }\n\n /**\n * @dev Approve the spending of all assets by their corresponding aToken,\n * if for some reason is it necessary.\n */\n function safeApproveAllTokens()\n external\n override\n onlyGovernor\n nonReentrant\n {\n address lendingPool = address(_getLendingPool());\n // approve the pool to spend the Asset\n for (uint256 i = 0; i < assetsMapped.length; i++) {\n address asset = assetsMapped[i];\n // Safe approval\n IERC20(asset).safeApprove(lendingPool, 0);\n IERC20(asset).safeApprove(lendingPool, type(uint256).max);\n }\n }\n\n /**\n * @dev Internal method to respond to the addition of new asset / aTokens\n We need to give the AAVE lending pool approval to transfer the\n asset.\n * @param _asset Address of the asset to approve\n * @param _aToken Address of the aToken\n */\n // solhint-disable-next-line no-unused-vars\n function _abstractSetPToken(address _asset, address _aToken)\n internal\n override\n {\n address lendingPool = address(_getLendingPool());\n IERC20(_asset).safeApprove(lendingPool, 0);\n IERC20(_asset).safeApprove(lendingPool, type(uint256).max);\n }\n\n /**\n * @dev Get the aToken wrapped in the IERC20 interface for this asset.\n * Fails if the pToken doesn't exist in our mappings.\n * @param _asset Address of the asset\n * @return Corresponding aToken to this asset\n */\n function _getATokenFor(address _asset) internal view returns (address) {\n address aToken = assetToPToken[_asset];\n require(aToken != address(0), \"aToken does not exist\");\n return aToken;\n }\n\n /**\n * @dev Get the current address of the Aave lending pool, which is the gateway to\n * depositing.\n * @return Current lending pool implementation\n */\n function _getLendingPool() internal view returns (IAaveLendingPool) {\n address lendingPool = ILendingPoolAddressesProvider(platformAddress)\n .getLendingPool();\n require(lendingPool != address(0), \"Lending pool does not exist\");\n return IAaveLendingPool(lendingPool);\n }\n\n /**\n * @dev Collect stkAave, convert it to AAVE send to Vault.\n */\n function collectRewardTokens()\n external\n override\n onlyHarvester\n nonReentrant\n {\n if (address(stkAave) == address(0)) {\n return;\n }\n\n // Check staked AAVE cooldown timer\n uint256 cooldown = stkAave.stakersCooldowns(address(this));\n uint256 windowStart = cooldown + stkAave.COOLDOWN_SECONDS();\n uint256 windowEnd = windowStart + stkAave.UNSTAKE_WINDOW();\n\n // If inside the unlock window, then we can redeem stkAave\n // for AAVE and send it to the vault.\n if (block.timestamp > windowStart && block.timestamp <= windowEnd) {\n // Redeem to AAVE\n uint256 stkAaveBalance = stkAave.balanceOf(address(this));\n stkAave.redeem(address(this), stkAaveBalance);\n\n // Transfer AAVE to harvesterAddress\n uint256 aaveBalance = IERC20(rewardTokenAddresses[0]).balanceOf(\n address(this)\n );\n if (aaveBalance > 0) {\n IERC20(rewardTokenAddresses[0]).safeTransfer(\n harvesterAddress,\n aaveBalance\n );\n }\n }\n\n // Collect available rewards and restart the cooldown timer, if either of\n // those should be run.\n if (block.timestamp > windowStart || cooldown == 0) {\n uint256 assetsLen = assetsMapped.length;\n // aToken addresses for incentives controller\n address[] memory aTokens = new address[](assetsLen);\n for (uint256 i = 0; i < assetsLen; ++i) {\n aTokens[i] = _getATokenFor(assetsMapped[i]);\n }\n\n // 1. If we have rewards availabile, collect them\n uint256 pendingRewards = incentivesController.getRewardsBalance(\n aTokens,\n address(this)\n );\n if (pendingRewards > 0) {\n // Because getting more stkAAVE from the incentives controller\n // with claimRewards() may push the stkAAVE cooldown time\n // forward, it is called after stakedAAVE has been turned into\n // AAVE.\n uint256 collected = incentivesController.claimRewards(\n aTokens,\n pendingRewards,\n address(this)\n );\n require(collected == pendingRewards, \"AAVE reward difference\");\n }\n\n // 2. Start cooldown counting down.\n if (stkAave.balanceOf(address(this)) > 0) {\n // Protected with if since cooldown call would revert\n // if no stkAave balance.\n stkAave.cooldown();\n }\n }\n }\n}\n" + }, + "contracts/strategies/balancer/BalancerMetaPoolStrategy.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @title OETH Balancer MetaStablePool Strategy\n * @author Origin Protocol Inc\n */\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { BaseAuraStrategy, BaseBalancerStrategy } from \"./BaseAuraStrategy.sol\";\nimport { IBalancerVault } from \"../../interfaces/balancer/IBalancerVault.sol\";\nimport { IRateProvider } from \"../../interfaces/balancer/IRateProvider.sol\";\nimport { IMetaStablePool } from \"../../interfaces/balancer/IMetaStablePool.sol\";\nimport { IERC20, InitializableAbstractStrategy } from \"../../utils/InitializableAbstractStrategy.sol\";\nimport { StableMath } from \"../../utils/StableMath.sol\";\n\ncontract BalancerMetaPoolStrategy is BaseAuraStrategy {\n using SafeERC20 for IERC20;\n using StableMath for uint256;\n\n constructor(\n BaseStrategyConfig memory _stratConfig,\n BaseBalancerConfig memory _balancerConfig,\n address _auraRewardPoolAddress\n )\n InitializableAbstractStrategy(_stratConfig)\n BaseBalancerStrategy(_balancerConfig)\n BaseAuraStrategy(_auraRewardPoolAddress)\n {}\n\n /**\n * @notice There are no plans to configure BalancerMetaPool as a default\n * asset strategy. For that reason there is no need to support this\n * functionality.\n */\n function deposit(address, uint256)\n external\n override\n onlyVault\n nonReentrant\n {\n revert(\"Not supported\");\n }\n\n /**\n * @notice There are no plans to configure BalancerMetaPool as a default\n * asset strategy. For that reason there is no need to support this\n * functionality.\n */\n function deposit(address[] calldata, uint256[] calldata)\n external\n onlyVault\n nonReentrant\n {\n revert(\"Not supported\");\n }\n\n /**\n * @notice Deposits all supported assets in this strategy contract to the Balancer pool.\n */\n function depositAll() external override onlyVault nonReentrant {\n uint256 assetsLength = assetsMapped.length;\n address[] memory strategyAssets = new address[](assetsLength);\n uint256[] memory strategyAmounts = new uint256[](assetsLength);\n\n // For each vault collateral asset\n for (uint256 i = 0; i < assetsLength; ++i) {\n strategyAssets[i] = assetsMapped[i];\n // Get the asset balance in this strategy contract\n strategyAmounts[i] = IERC20(strategyAssets[i]).balanceOf(\n address(this)\n );\n }\n _deposit(strategyAssets, strategyAmounts);\n }\n\n /*\n * _deposit doesn't require a read-only re-entrancy protection since during the deposit\n * the function enters the Balancer Vault Context. If this function were called as part of\n * the attacking contract (while intercepting execution flow upon receiving ETH) the read-only\n * protection of the Balancer Vault would be triggered. Since the attacking contract would\n * already be in the Balancer Vault context and wouldn't be able to enter it again.\n */\n function _deposit(\n address[] memory _strategyAssets,\n uint256[] memory _strategyAmounts\n ) internal {\n require(\n _strategyAssets.length == _strategyAmounts.length,\n \"Array length missmatch\"\n );\n\n (IERC20[] memory tokens, , ) = balancerVault.getPoolTokens(\n balancerPoolId\n );\n\n uint256[] memory strategyAssetAmountsToPoolAssetAmounts = new uint256[](\n _strategyAssets.length\n );\n address[] memory strategyAssetsToPoolAssets = new address[](\n _strategyAssets.length\n );\n\n for (uint256 i = 0; i < _strategyAssets.length; ++i) {\n address strategyAsset = _strategyAssets[i];\n uint256 strategyAmount = _strategyAmounts[i];\n\n require(\n assetToPToken[strategyAsset] != address(0),\n \"Unsupported asset\"\n );\n strategyAssetsToPoolAssets[i] = _toPoolAsset(strategyAsset);\n\n if (strategyAmount > 0) {\n emit Deposit(strategyAsset, platformAddress, strategyAmount);\n\n // wrap rebasing assets like stETH and frxETH to wstETH and sfrxETH\n (, strategyAssetAmountsToPoolAssetAmounts[i]) = _wrapPoolAsset(\n strategyAsset,\n strategyAmount\n );\n }\n }\n\n uint256[] memory amountsIn = new uint256[](tokens.length);\n address[] memory poolAssets = new address[](tokens.length);\n for (uint256 i = 0; i < tokens.length; ++i) {\n // Convert IERC20 type to address\n poolAssets[i] = address(tokens[i]);\n\n // For each of the mapped assets\n for (uint256 j = 0; j < strategyAssetsToPoolAssets.length; ++j) {\n // If the pool asset is the same as the mapped asset\n if (poolAssets[i] == strategyAssetsToPoolAssets[j]) {\n amountsIn[i] = strategyAssetAmountsToPoolAssetAmounts[j];\n }\n }\n }\n\n uint256 minBPT = _getBPTExpected(\n strategyAssetsToPoolAssets,\n strategyAssetAmountsToPoolAssetAmounts\n );\n uint256 minBPTwDeviation = minBPT.mulTruncate(\n 1e18 - maxDepositDeviation\n );\n\n /* EXACT_TOKENS_IN_FOR_BPT_OUT:\n * User sends precise quantities of tokens, and receives an\n * estimated but unknown (computed at run time) quantity of BPT.\n *\n * ['uint256', 'uint256[]', 'uint256']\n * [EXACT_TOKENS_IN_FOR_BPT_OUT, amountsIn, minimumBPT]\n */\n bytes memory userData = abi.encode(\n IBalancerVault.WeightedPoolJoinKind.EXACT_TOKENS_IN_FOR_BPT_OUT,\n amountsIn,\n minBPTwDeviation\n );\n\n IBalancerVault.JoinPoolRequest memory request = IBalancerVault\n .JoinPoolRequest(poolAssets, amountsIn, userData, false);\n\n // Add the pool assets in this strategy to the balancer pool\n balancerVault.joinPool(\n balancerPoolId,\n address(this),\n address(this),\n request\n );\n\n // Deposit the Balancer Pool Tokens (BPT) into Aura\n _lpDepositAll();\n }\n\n /**\n * @notice Withdraw a Vault collateral asset from the Balancer pool.\n * @param _recipient Address to receive the Vault collateral assets. Typically is the Vault.\n * @param _strategyAsset Address of the Vault collateral asset\n * @param _strategyAmount The amount of Vault collateral assets to withdraw\n */\n function withdraw(\n address _recipient,\n address _strategyAsset,\n uint256 _strategyAmount\n ) external override onlyVault nonReentrant {\n address[] memory strategyAssets = new address[](1);\n uint256[] memory strategyAmounts = new uint256[](1);\n strategyAssets[0] = _strategyAsset;\n strategyAmounts[0] = _strategyAmount;\n\n _withdraw(_recipient, strategyAssets, strategyAmounts);\n }\n\n /**\n * @notice Withdraw multiple Vault collateral asset from the Balancer pool.\n * @param _recipient Address to receive the Vault collateral assets. Typically is the Vault.\n * @param _strategyAssets Addresses of the Vault collateral assets\n * @param _strategyAmounts The amounts of Vault collateral assets to withdraw\n */\n function withdraw(\n address _recipient,\n address[] calldata _strategyAssets,\n uint256[] calldata _strategyAmounts\n ) external onlyVault nonReentrant {\n _withdraw(_recipient, _strategyAssets, _strategyAmounts);\n }\n\n /**\n * @dev Withdraw multiple Vault collateral asset from the Balancer pool.\n * @param _recipient Address to receive the Vault collateral assets. Typically is the Vault.\n * @param _strategyAssets Addresses of the Vault collateral assets\n * @param _strategyAmounts The amounts of Vault collateral assets to withdraw\n *\n * _withdrawal doesn't require a read-only re-entrancy protection since during the withdrawal\n * the function enters the Balancer Vault Context. If this function were called as part of\n * the attacking contract (while intercepting execution flow upon receiving ETH) the read-only\n * protection of the Balancer Vault would be triggered. Since the attacking contract would\n * already be in the Balancer Vault context and wouldn't be able to enter it again.\n */\n function _withdraw(\n address _recipient,\n address[] memory _strategyAssets,\n uint256[] memory _strategyAmounts\n ) internal {\n require(\n _strategyAssets.length == _strategyAmounts.length,\n \"Invalid input arrays\"\n );\n\n for (uint256 i = 0; i < _strategyAssets.length; ++i) {\n require(\n assetToPToken[_strategyAssets[i]] != address(0),\n \"Unsupported asset\"\n );\n }\n\n // STEP 1 - Calculate the Balancer pool assets and amounts from the vault collateral assets\n\n // Get all the supported balancer pool assets\n (IERC20[] memory tokens, , ) = balancerVault.getPoolTokens(\n balancerPoolId\n );\n // Calculate the balancer pool assets and amounts to withdraw\n uint256[] memory poolAssetsAmountsOut = new uint256[](tokens.length);\n address[] memory poolAssets = new address[](tokens.length);\n // Is the wrapped asset amount indexed by the assets array, not the order of the Balancer pool tokens\n // eg wstETH and sfrxETH amounts, not the stETH and frxETH amounts\n uint256[] memory strategyAssetsToPoolAssetsAmounts = new uint256[](\n _strategyAssets.length\n );\n\n // For each of the Balancer pool assets\n for (uint256 i = 0; i < tokens.length; ++i) {\n poolAssets[i] = address(tokens[i]);\n\n // Convert the Balancer pool asset back to a vault collateral asset\n address strategyAsset = _fromPoolAsset(poolAssets[i]);\n\n // for each of the vault assets\n for (uint256 j = 0; j < _strategyAssets.length; ++j) {\n // If the vault asset equals the vault asset mapped from the Balancer pool asset\n if (_strategyAssets[j] == strategyAsset) {\n (, poolAssetsAmountsOut[i]) = _toPoolAsset(\n strategyAsset,\n _strategyAmounts[j]\n );\n strategyAssetsToPoolAssetsAmounts[j] = poolAssetsAmountsOut[\n i\n ];\n\n /* Because of the potential Balancer rounding error mentioned below\n * the contract might receive 1-2 WEI smaller amount than required\n * in the withdraw user data encoding. If slightly lesser token amount\n * is received the strategy can not unwrap the pool asset as it is\n * smaller than expected.\n *\n * For that reason we `overshoot` the required tokens expected to\n * circumvent the error\n */\n if (poolAssetsAmountsOut[i] > 0) {\n poolAssetsAmountsOut[i] += 2;\n }\n }\n }\n }\n\n // STEP 2 - Calculate the max about of Balancer Pool Tokens (BPT) to withdraw\n\n // Estimate the required amount of Balancer Pool Tokens (BPT) for the assets\n uint256 maxBPTtoWithdraw = _getBPTExpected(\n poolAssets,\n /* all non 0 values are overshot by 2 WEI and with the expected mainnet\n * ~1% withdrawal deviation, the 2 WEI aren't important\n */\n poolAssetsAmountsOut\n );\n // Increase BPTs by the max allowed deviation\n // Any excess BPTs will be left in this strategy contract\n maxBPTtoWithdraw = maxBPTtoWithdraw.mulTruncate(\n 1e18 + maxWithdrawalDeviation\n );\n\n // STEP 3 - Withdraw the Balancer Pool Tokens (BPT) from Aura to this strategy contract\n\n // Withdraw BPT from Aura allowing for BPTs left in this strategy contract from previous withdrawals\n _lpWithdraw(\n maxBPTtoWithdraw - IERC20(platformAddress).balanceOf(address(this))\n );\n\n // STEP 4 - Withdraw the balancer pool assets from the pool\n\n /* Custom asset exit: BPT_IN_FOR_EXACT_TOKENS_OUT:\n * User sends an estimated but unknown (computed at run time) quantity of BPT,\n * and receives precise quantities of specified tokens.\n *\n * ['uint256', 'uint256[]', 'uint256']\n * [BPT_IN_FOR_EXACT_TOKENS_OUT, amountsOut, maxBPTAmountIn]\n */\n bytes memory userData = abi.encode(\n IBalancerVault.WeightedPoolExitKind.BPT_IN_FOR_EXACT_TOKENS_OUT,\n poolAssetsAmountsOut,\n maxBPTtoWithdraw\n );\n\n IBalancerVault.ExitPoolRequest memory request = IBalancerVault\n .ExitPoolRequest(\n poolAssets,\n /* We specify the exact amount of a tokens we are expecting in the encoded\n * userData, for that reason we don't need to specify the amountsOut here.\n *\n * Also Balancer has a rounding issue that can make a transaction fail:\n * https://github.com/balancer/balancer-v2-monorepo/issues/2541\n * which is an extra reason why this field is empty.\n */\n new uint256[](tokens.length),\n userData,\n false\n );\n\n balancerVault.exitPool(\n balancerPoolId,\n address(this),\n /* Payable keyword is required because of the IBalancerVault interface even though\n * this strategy shall never be receiving native ETH\n */\n payable(address(this)),\n request\n );\n\n // STEP 5 - Re-deposit any left over BPT tokens back into Aura\n /* When concluding how much of BPT we need to withdraw from Aura we overshoot by\n * roughly around 1% (initial mainnet setting of maxWithdrawalDeviation). After exiting\n * the pool strategy could have left over BPT tokens that are not earning boosted yield.\n * We re-deploy those back in.\n */\n _lpDepositAll();\n\n // STEP 6 - Unswap balancer pool assets to vault collateral assets and send to the vault.\n\n // For each of the specified assets\n for (uint256 i = 0; i < _strategyAssets.length; ++i) {\n // Unwrap assets like wstETH and sfrxETH to rebasing assets stETH and frxETH\n if (strategyAssetsToPoolAssetsAmounts[i] > 0) {\n _unwrapPoolAsset(\n _strategyAssets[i],\n strategyAssetsToPoolAssetsAmounts[i]\n );\n }\n\n // Transfer the vault collateral assets to the recipient, which is typically the vault\n if (_strategyAmounts[i] > 0) {\n IERC20(_strategyAssets[i]).safeTransfer(\n _recipient,\n _strategyAmounts[i]\n );\n\n emit Withdrawal(\n _strategyAssets[i],\n platformAddress,\n _strategyAmounts[i]\n );\n }\n }\n }\n\n /**\n * @notice Withdraws all supported Vault collateral assets from the Balancer pool\n * and send to the OToken's Vault.\n *\n * Is only executable by the OToken's Vault or the Governor.\n */\n function withdrawAll() external override onlyVaultOrGovernor nonReentrant {\n // STEP 1 - Withdraw all Balancer Pool Tokens (BPT) from Aura to this strategy contract\n\n _lpWithdrawAll();\n // Get the BPTs withdrawn from Aura plus any that were already in this strategy contract\n uint256 BPTtoWithdraw = IERC20(platformAddress).balanceOf(\n address(this)\n );\n // Get the balancer pool assets and their total balances\n (IERC20[] memory tokens, , ) = balancerVault.getPoolTokens(\n balancerPoolId\n );\n uint256[] memory minAmountsOut = new uint256[](tokens.length);\n address[] memory poolAssets = new address[](tokens.length);\n for (uint256 i = 0; i < tokens.length; ++i) {\n poolAssets[i] = address(tokens[i]);\n }\n\n // STEP 2 - Withdraw the Balancer pool assets from the pool\n /* Proportional exit: EXACT_BPT_IN_FOR_TOKENS_OUT:\n * User sends a precise quantity of BPT, and receives an estimated but unknown\n * (computed at run time) quantity of a single token\n *\n * ['uint256', 'uint256']\n * [EXACT_BPT_IN_FOR_TOKENS_OUT, bptAmountIn]\n *\n * It is ok to pass an empty minAmountsOut since tilting the pool in any direction\n * when doing a proportional exit can only be beneficial to the strategy. Since\n * it will receive more of the underlying tokens for the BPT traded in.\n */\n bytes memory userData = abi.encode(\n IBalancerVault.WeightedPoolExitKind.EXACT_BPT_IN_FOR_TOKENS_OUT,\n BPTtoWithdraw\n );\n\n IBalancerVault.ExitPoolRequest memory request = IBalancerVault\n .ExitPoolRequest(poolAssets, minAmountsOut, userData, false);\n\n balancerVault.exitPool(\n balancerPoolId,\n address(this),\n /* Payable keyword is required because of the IBalancerVault interface even though\n * this strategy shall never be receiving native ETH\n */\n payable(address(this)),\n request\n );\n\n // STEP 3 - Convert the balancer pool assets to the vault collateral assets and send to the vault\n // For each of the Balancer pool assets\n for (uint256 i = 0; i < tokens.length; ++i) {\n address poolAsset = address(tokens[i]);\n // Convert the balancer pool asset to the strategy asset\n address strategyAsset = _fromPoolAsset(poolAsset);\n // Get the balancer pool assets withdraw from the pool plus any that were already in this strategy contract\n uint256 poolAssetAmount = IERC20(poolAsset).balanceOf(\n address(this)\n );\n\n // Unwrap assets like wstETH and sfrxETH to rebasing assets stETH and frxETH\n uint256 unwrappedAmount = 0;\n if (poolAssetAmount > 0) {\n unwrappedAmount = _unwrapPoolAsset(\n strategyAsset,\n poolAssetAmount\n );\n }\n\n // Transfer the vault collateral assets to the vault\n if (unwrappedAmount > 0) {\n IERC20(strategyAsset).safeTransfer(\n vaultAddress,\n unwrappedAmount\n );\n emit Withdrawal(\n strategyAsset,\n platformAddress,\n unwrappedAmount\n );\n }\n }\n }\n\n /**\n * @notice Approves the Balancer Vault to transfer poolAsset counterparts\n * of all of the supported assets from this strategy. E.g. stETH is a supported\n * strategy and Balancer Vault gets unlimited approval to transfer wstETH.\n *\n * If Balancer pool uses a wrapped version of a supported asset then also approve\n * unlimited usage of an asset to the contract responsible for wrapping.\n *\n * Approve unlimited spending by Balancer Vault and Aura reward pool of the\n * pool BPT tokens.\n *\n * Is only executable by the Governor.\n */\n function safeApproveAllTokens()\n external\n override\n onlyGovernor\n nonReentrant\n {\n uint256 assetCount = assetsMapped.length;\n for (uint256 i = 0; i < assetCount; ++i) {\n _abstractSetPToken(assetsMapped[i], platformAddress);\n }\n _approveBase();\n }\n\n // solhint-disable-next-line no-unused-vars\n function _abstractSetPToken(address _asset, address) internal override {\n address poolAsset = _toPoolAsset(_asset);\n if (_asset == stETH) {\n // slither-disable-next-line unused-return\n IERC20(stETH).approve(wstETH, type(uint256).max);\n } else if (_asset == frxETH) {\n // slither-disable-next-line unused-return\n IERC20(frxETH).approve(sfrxETH, type(uint256).max);\n }\n _approveAsset(poolAsset);\n }\n\n /**\n * @dev Approves the Balancer Vault to transfer an asset from\n * this strategy. The assets could be a Vault collateral asset\n * like WETH or rETH; or a Balancer pool asset that wraps the vault asset\n * like wstETH or sfrxETH.\n */\n function _approveAsset(address _asset) internal {\n IERC20 asset = IERC20(_asset);\n // slither-disable-next-line unused-return\n asset.approve(address(balancerVault), type(uint256).max);\n }\n\n /**\n * @notice Returns the rate supplied by the Balancer configured rate\n * provider. Rate is used to normalize the token to common underlying\n * pool denominator. (ETH for ETH Liquid staking derivatives)\n *\n * @param _asset Address of the Balancer pool asset\n * @return rate of the corresponding asset\n */\n function _getRateProviderRate(address _asset)\n internal\n view\n override\n returns (uint256)\n {\n IMetaStablePool pool = IMetaStablePool(platformAddress);\n IRateProvider[] memory providers = pool.getRateProviders();\n (IERC20[] memory tokens, , ) = balancerVault.getPoolTokens(\n balancerPoolId\n );\n\n uint256 providersLength = providers.length;\n for (uint256 i = 0; i < providersLength; ++i) {\n // _assets and corresponding rate providers are all in the same order\n if (address(tokens[i]) == _asset) {\n // rate provider doesn't exist, defaults to 1e18\n if (address(providers[i]) == address(0)) {\n return 1e18;\n }\n return providers[i].getRate();\n }\n }\n\n // should never happen\n assert(false);\n }\n}\n" + }, + "contracts/strategies/balancer/BaseAuraStrategy.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @title OETH Base Balancer Abstract Strategy\n * @author Origin Protocol Inc\n */\n\nimport { BaseBalancerStrategy } from \"./BaseBalancerStrategy.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { IERC20 } from \"../../utils/InitializableAbstractStrategy.sol\";\nimport { IERC4626 } from \"../../../lib/openzeppelin/interfaces/IERC4626.sol\";\nimport { StableMath } from \"../../utils/StableMath.sol\";\nimport { IRewardStaking } from \"../IRewardStaking.sol\";\n\nabstract contract BaseAuraStrategy is BaseBalancerStrategy {\n using SafeERC20 for IERC20;\n using StableMath for uint256;\n\n /// @notice Address of the Aura rewards pool\n address public immutable auraRewardPoolAddress;\n\n // renamed from __reserved to not shadow BaseBalancerStrategy.__reserved,\n int256[50] private __reserved_baseAuraStrategy;\n\n constructor(address _auraRewardPoolAddress) {\n auraRewardPoolAddress = _auraRewardPoolAddress;\n }\n\n /**\n * @dev Deposit all Balancer Pool Tokens (BPT) in this strategy contract\n * to the Aura rewards pool.\n */\n function _lpDepositAll() internal virtual override {\n uint256 bptBalance = IERC20(platformAddress).balanceOf(address(this));\n uint256 auraLp = IERC4626(auraRewardPoolAddress).deposit(\n bptBalance,\n address(this)\n );\n require(bptBalance == auraLp, \"Aura LP != BPT\");\n }\n\n /**\n * @dev Withdraw `numBPTTokens` Balancer Pool Tokens (BPT) from\n * the Aura rewards pool to this strategy contract.\n * @param numBPTTokens Number of Balancer Pool Tokens (BPT) to withdraw\n */\n function _lpWithdraw(uint256 numBPTTokens) internal virtual override {\n IRewardStaking(auraRewardPoolAddress).withdrawAndUnwrap(\n numBPTTokens,\n true // also claim reward tokens\n );\n }\n\n /**\n * @dev Withdraw all Balancer Pool Tokens (BPT) from\n * the Aura rewards pool to this strategy contract.\n */\n function _lpWithdrawAll() internal virtual override {\n // Get all the strategy's BPTs in Aura\n // maxRedeem is implemented as balanceOf(address) in Aura\n uint256 bptBalance = IERC4626(auraRewardPoolAddress).maxRedeem(\n address(this)\n );\n\n IRewardStaking(auraRewardPoolAddress).withdrawAndUnwrap(\n bptBalance,\n true // also claim reward tokens\n );\n }\n\n /**\n * @notice Collects BAL and AURA tokens from the rewards pool.\n */\n function collectRewardTokens()\n external\n virtual\n override\n onlyHarvester\n nonReentrant\n {\n /* Similar to Convex, calling this function collects both of the\n * accrued BAL and AURA tokens.\n */\n IRewardStaking(auraRewardPoolAddress).getReward();\n _collectRewardTokens();\n }\n\n /// @notice Balancer Pool Tokens (BPT) in the Balancer pool and the Aura rewards pool.\n function _getBalancerPoolTokens()\n internal\n view\n override\n returns (uint256 balancerPoolTokens)\n {\n balancerPoolTokens =\n IERC20(platformAddress).balanceOf(address(this)) +\n // maxRedeem is implemented as balanceOf(address) in Aura\n IERC4626(auraRewardPoolAddress).maxRedeem(address(this));\n }\n\n function _approveBase() internal virtual override {\n super._approveBase();\n\n IERC20 pToken = IERC20(platformAddress);\n pToken.safeApprove(auraRewardPoolAddress, type(uint256).max);\n }\n}\n" + }, + "contracts/strategies/balancer/BaseBalancerStrategy.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @title OETH Base Balancer Abstract Strategy\n * @author Origin Protocol Inc\n */\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { IERC20, InitializableAbstractStrategy } from \"../../utils/InitializableAbstractStrategy.sol\";\nimport { IBalancerVault } from \"../../interfaces/balancer/IBalancerVault.sol\";\nimport { IRateProvider } from \"../../interfaces/balancer/IRateProvider.sol\";\nimport { VaultReentrancyLib } from \"./VaultReentrancyLib.sol\";\nimport { IOracle } from \"../../interfaces/IOracle.sol\";\nimport { IWstETH } from \"../../interfaces/IWstETH.sol\";\nimport { IERC4626 } from \"../../../lib/openzeppelin/interfaces/IERC4626.sol\";\nimport { StableMath } from \"../../utils/StableMath.sol\";\n\nabstract contract BaseBalancerStrategy is InitializableAbstractStrategy {\n using SafeERC20 for IERC20;\n using StableMath for uint256;\n\n address public immutable rETH;\n address public immutable stETH;\n address public immutable wstETH;\n address public immutable frxETH;\n address public immutable sfrxETH;\n\n /// @notice Address of the Balancer vault\n IBalancerVault public immutable balancerVault;\n /// @notice Balancer pool identifier\n bytes32 public immutable balancerPoolId;\n\n // Max withdrawal deviation denominated in 1e18 (1e18 == 100%)\n uint256 public maxWithdrawalDeviation;\n // Max deposit deviation denominated in 1e18 (1e18 == 100%)\n uint256 public maxDepositDeviation;\n\n int256[48] private __reserved;\n\n struct BaseBalancerConfig {\n address rEthAddress; // Address of the rETH token\n address stEthAddress; // Address of the stETH token\n address wstEthAddress; // Address of the wstETH token\n address frxEthAddress; // Address of the frxEth token\n address sfrxEthAddress; // Address of the sfrxEth token\n address balancerVaultAddress; // Address of the Balancer vault\n bytes32 balancerPoolId; // Balancer pool identifier\n }\n\n event MaxWithdrawalDeviationUpdated(\n uint256 _prevMaxDeviationPercentage,\n uint256 _newMaxDeviationPercentage\n );\n event MaxDepositDeviationUpdated(\n uint256 _prevMaxDeviationPercentage,\n uint256 _newMaxDeviationPercentage\n );\n\n /**\n * @dev Ensure we are not in a Vault context when this function is called, by attempting a no-op internal\n * balance operation. If we are already in a Vault transaction (e.g., a swap, join, or exit), the Vault's\n * reentrancy protection will cause this function to revert.\n *\n * Use this modifier with any function that can cause a state change in a pool and is either public itself,\n * or called by a public function *outside* a Vault operation (e.g., join, exit, or swap).\n *\n * This is to protect against Balancer's read-only re-entrancy vulnerability:\n * https://www.notion.so/originprotocol/Balancer-read-only-reentrancy-c686e72c82414ef18fa34312bb02e11b\n */\n modifier whenNotInBalancerVaultContext() {\n VaultReentrancyLib.ensureNotInVaultContext(balancerVault);\n _;\n }\n\n constructor(BaseBalancerConfig memory _balancerConfig) {\n rETH = _balancerConfig.rEthAddress;\n stETH = _balancerConfig.stEthAddress;\n wstETH = _balancerConfig.wstEthAddress;\n frxETH = _balancerConfig.frxEthAddress;\n sfrxETH = _balancerConfig.sfrxEthAddress;\n\n balancerVault = IBalancerVault(_balancerConfig.balancerVaultAddress);\n balancerPoolId = _balancerConfig.balancerPoolId;\n }\n\n /**\n * Initializer for setting up strategy internal state. This overrides the\n * InitializableAbstractStrategy initializer as Balancer's strategies don't fit\n * well within that abstraction.\n * @param _rewardTokenAddresses Address of BAL & AURA\n * @param _assets Addresses of supported assets. MUST be passed in the same\n * order as returned by coins on the pool contract, i.e.\n * WETH, stETH\n * @param _pTokens Platform Token corresponding addresses\n */\n function initialize(\n address[] calldata _rewardTokenAddresses, // BAL & AURA\n address[] calldata _assets,\n address[] calldata _pTokens\n ) external onlyGovernor initializer {\n maxWithdrawalDeviation = 1e16;\n maxDepositDeviation = 1e16;\n\n emit MaxWithdrawalDeviationUpdated(0, maxWithdrawalDeviation);\n emit MaxDepositDeviationUpdated(0, maxDepositDeviation);\n\n IERC20[] memory poolAssets = _getPoolAssets();\n require(\n poolAssets.length == _assets.length,\n \"Pool assets length mismatch\"\n );\n for (uint256 i = 0; i < _assets.length; ++i) {\n address asset = _fromPoolAsset(address(poolAssets[i]));\n require(_assets[i] == asset, \"Pool assets mismatch\");\n }\n\n InitializableAbstractStrategy._initialize(\n _rewardTokenAddresses,\n _assets,\n _pTokens\n );\n _approveBase();\n }\n\n /**\n * @notice Returns bool indicating whether asset is supported by strategy\n * @param _asset Address of the asset\n */\n function supportsAsset(address _asset) public view override returns (bool) {\n return assetToPToken[_asset] != address(0);\n }\n\n /**\n * @notice Get strategy's share of an assets in the Balancer pool.\n * This is not denominated in OUSD/ETH value of the assets in the Balancer pool.\n * @param _asset Address of the Vault collateral asset\n * @return amount the amount of vault collateral assets\n *\n * IMPORTANT if this function is overridden it needs to have a whenNotInBalancerVaultContext\n * modifier on it or it is susceptible to read-only re-entrancy attack\n *\n * @dev it is important that this function is not affected by reporting inflated\n * values of assets in case of any pool manipulation. Such a manipulation could easily\n * exploit the protocol by:\n * - minting OETH\n * - tilting Balancer pool to report higher balances of assets\n * - rebasing() -> all that extra token balances get distributed to OETH holders\n * - tilting pool back\n * - redeeming OETH\n */\n function checkBalance(address _asset)\n external\n view\n virtual\n override\n whenNotInBalancerVaultContext\n returns (uint256 amount)\n {\n require(assetToPToken[_asset] != address(0), \"Unsupported asset\");\n\n uint256 bptBalance = _getBalancerPoolTokens();\n\n /* To calculate the worth of queried asset:\n * - assume that all tokens normalized to their ETH value have an equal split balance\n * in the pool when it is balanced\n * - multiply the BPT amount with the bpt rate to get the ETH denominated amount\n * of strategy's holdings\n * - divide that by the number of tokens we support in the pool to get ETH denominated\n * amount that is applicable to each supported token in the pool.\n *\n * It would be possible to support only 1 asset in the pool (and be exposed to all\n * the assets while holding BPT tokens) and deposit/withdraw/checkBalance using only\n * that asset. TBD: changes to other functions still required if we ever decide to\n * go with such configuration.\n */\n amount = (bptBalance.mulTruncate(\n IRateProvider(platformAddress).getRate()\n ) / assetsMapped.length);\n\n /* If the pool asset is equal to (strategy )_asset it means that a rate\n * provider for that asset exists and that asset is not necessarily\n * pegged to a unit (ETH).\n *\n * Because this function returns the balance of the asset and is not denominated in\n * ETH units we need to convert the ETH denominated amount to asset amount.\n */\n if (_toPoolAsset(_asset) == _asset) {\n amount = amount.divPrecisely(_getRateProviderRate(_asset));\n }\n }\n\n /**\n * @notice Returns the value of all assets managed by this strategy.\n * Uses the Balancer pool's rate (virtual price) to convert the strategy's\n * Balancer Pool Tokens (BPT) to ETH value.\n * @return value The ETH value\n *\n * IMPORTANT if this function is overridden it needs to have a whenNotInBalancerVaultContext\n * modifier on it or it is susceptible to read-only re-entrancy attack\n */\n function checkBalance()\n external\n view\n virtual\n whenNotInBalancerVaultContext\n returns (uint256 value)\n {\n uint256 bptBalance = _getBalancerPoolTokens();\n\n // Convert BPT to ETH value\n value = bptBalance.mulTruncate(\n IRateProvider(platformAddress).getRate()\n );\n }\n\n /// @notice Balancer Pool Tokens (BPT) in the Balancer pool.\n function _getBalancerPoolTokens()\n internal\n view\n virtual\n returns (uint256 balancerPoolTokens)\n {\n balancerPoolTokens = IERC20(platformAddress).balanceOf(address(this));\n }\n\n /* solhint-disable max-line-length */\n /**\n * @notice BPT price is calculated by taking the rate from the rateProvider of the asset in\n * question. If one does not exist it defaults to 1e18. To get the final BPT expected that\n * is multiplied by the underlying asset amount divided by BPT token rate. BPT token rate is\n * similar to Curve's virtual_price and expresses how much has the price of BPT appreciated\n * (e.g. due to swap fees) in relation to the underlying assets\n *\n * Using the above approach makes the strategy vulnerable to a possible MEV attack using\n * flash loan to manipulate the pool before a deposit/withdrawal since the function ignores\n * market values of the assets being priced in BPT.\n *\n * At the time of writing there is no safe on-chain approach to pricing BPT in a way that it\n * would make it invulnerable to MEV pool manipulation. See recent Balancer exploit:\n * https://www.notion.so/originprotocol/Balancer-OETH-strategy-9becdea132704e588782a919d7d471eb?pvs=4#1cf07de12fc64f1888072321e0644348\n *\n * To mitigate MEV possibilities during deposits and withdraws, the VaultValueChecker will use checkBalance before and after the move\n * to ensure the expected changes took place.\n *\n * @param _asset Address of the Balancer pool asset\n * @param _amount Amount of the Balancer pool asset\n * @return bptExpected of BPT expected in exchange for the asset\n *\n * @dev\n * bptAssetPrice = 1e18 (asset peg) * pool_asset_rate\n *\n * bptExpected = bptAssetPrice * asset_amount / BPT_token_rate\n *\n * bptExpected = 1e18 (asset peg) * pool_asset_rate * asset_amount / BPT_token_rate\n * bptExpected = asset_amount * pool_asset_rate / BPT_token_rate\n *\n * further information available here:\n * https://www.notion.so/originprotocol/Balancer-OETH-strategy-9becdea132704e588782a919d7d471eb?pvs=4#ce01495ae70346d8971f5dced809fb83\n */\n /* solhint-enable max-line-length */\n function _getBPTExpected(address _asset, uint256 _amount)\n internal\n view\n virtual\n returns (uint256 bptExpected)\n {\n uint256 bptRate = IRateProvider(platformAddress).getRate();\n uint256 poolAssetRate = _getRateProviderRate(_asset);\n bptExpected = _amount.mulTruncate(poolAssetRate).divPrecisely(bptRate);\n }\n\n function _getBPTExpected(\n address[] memory _assets,\n uint256[] memory _amounts\n ) internal view virtual returns (uint256 bptExpected) {\n require(_assets.length == _amounts.length, \"Assets & amounts mismatch\");\n\n for (uint256 i = 0; i < _assets.length; ++i) {\n uint256 poolAssetRate = _getRateProviderRate(_assets[i]);\n // convert asset amount to ETH amount\n bptExpected += _amounts[i].mulTruncate(poolAssetRate);\n }\n\n uint256 bptRate = IRateProvider(platformAddress).getRate();\n // Convert ETH amount to BPT amount\n bptExpected = bptExpected.divPrecisely(bptRate);\n }\n\n function _lpDepositAll() internal virtual;\n\n function _lpWithdraw(uint256 numBPTTokens) internal virtual;\n\n function _lpWithdrawAll() internal virtual;\n\n /**\n * @notice Balancer returns assets and rateProviders for corresponding assets ordered\n * by numerical order.\n */\n function _getPoolAssets() internal view returns (IERC20[] memory assets) {\n // slither-disable-next-line unused-return\n (assets, , ) = balancerVault.getPoolTokens(balancerPoolId);\n }\n\n /**\n * @dev If an asset is rebasing the Balancer pools have a wrapped versions of assets\n * that the strategy supports. This function converts the pool(wrapped) asset\n * and corresponding amount to strategy asset.\n */\n function _toPoolAsset(address asset, uint256 amount)\n internal\n view\n returns (address poolAsset, uint256 poolAmount)\n {\n if (asset == stETH) {\n poolAsset = wstETH;\n if (amount > 0) {\n poolAmount = IWstETH(wstETH).getWstETHByStETH(amount);\n }\n } else if (asset == frxETH) {\n poolAsset = sfrxETH;\n if (amount > 0) {\n poolAmount = IERC4626(sfrxETH).convertToShares(amount);\n }\n } else {\n poolAsset = asset;\n poolAmount = amount;\n }\n }\n\n /**\n * @dev Converts a Vault collateral asset to a Balancer pool asset.\n * stETH becomes wstETH, frxETH becomes sfrxETH and everything else stays the same.\n * @param asset Address of the Vault collateral asset.\n * @return Address of the Balancer pool asset.\n */\n function _toPoolAsset(address asset) internal view returns (address) {\n if (asset == stETH) {\n return wstETH;\n } else if (asset == frxETH) {\n return sfrxETH;\n }\n return asset;\n }\n\n /**\n * @dev Converts rebasing asset to its wrapped counterpart.\n */\n function _wrapPoolAsset(address asset, uint256 amount)\n internal\n returns (address wrappedAsset, uint256 wrappedAmount)\n {\n if (asset == stETH) {\n wrappedAsset = wstETH;\n if (amount > 0) {\n wrappedAmount = IWstETH(wstETH).wrap(amount);\n }\n } else if (asset == frxETH) {\n wrappedAsset = sfrxETH;\n if (amount > 0) {\n wrappedAmount = IERC4626(sfrxETH).deposit(\n amount,\n address(this)\n );\n }\n } else {\n wrappedAsset = asset;\n wrappedAmount = amount;\n }\n }\n\n /**\n * @dev Converts wrapped asset to its rebasing counterpart.\n */\n function _unwrapPoolAsset(address asset, uint256 amount)\n internal\n returns (uint256 unwrappedAmount)\n {\n if (asset == stETH) {\n unwrappedAmount = IWstETH(wstETH).unwrap(amount);\n } else if (asset == frxETH) {\n unwrappedAmount = IERC4626(sfrxETH).withdraw(\n amount,\n address(this),\n address(this)\n );\n } else {\n unwrappedAmount = amount;\n }\n }\n\n /**\n * @dev If an asset is rebasing the Balancer pools have a wrapped versions of assets\n * that the strategy supports. This function converts the rebasing strategy asset\n * and corresponding amount to wrapped(pool) asset.\n */\n function _fromPoolAsset(address poolAsset, uint256 poolAmount)\n internal\n view\n returns (address asset, uint256 amount)\n {\n if (poolAsset == wstETH) {\n asset = stETH;\n if (poolAmount > 0) {\n amount = IWstETH(wstETH).getStETHByWstETH(poolAmount);\n }\n } else if (poolAsset == sfrxETH) {\n asset = frxETH;\n if (poolAmount > 0) {\n amount = IERC4626(sfrxETH).convertToAssets(poolAmount);\n }\n } else {\n asset = poolAsset;\n amount = poolAmount;\n }\n }\n\n function _fromPoolAsset(address poolAsset)\n internal\n view\n returns (address asset)\n {\n if (poolAsset == wstETH) {\n asset = stETH;\n } else if (poolAsset == sfrxETH) {\n asset = frxETH;\n } else {\n asset = poolAsset;\n }\n }\n\n /**\n * @notice Sets max withdrawal deviation that is considered when removing\n * liquidity from Balancer pools.\n * @param _maxWithdrawalDeviation Max withdrawal deviation denominated in\n * wad (number with 18 decimals): 1e18 == 100%, 1e16 == 1%\n *\n * IMPORTANT Minimum maxWithdrawalDeviation will be 1% (1e16) for production\n * usage. Vault value checker in combination with checkBalance will\n * catch any unexpected manipulation.\n */\n function setMaxWithdrawalDeviation(uint256 _maxWithdrawalDeviation)\n external\n onlyVaultOrGovernorOrStrategist\n {\n require(\n _maxWithdrawalDeviation <= 1e18,\n \"Withdrawal dev. out of bounds\"\n );\n emit MaxWithdrawalDeviationUpdated(\n maxWithdrawalDeviation,\n _maxWithdrawalDeviation\n );\n maxWithdrawalDeviation = _maxWithdrawalDeviation;\n }\n\n /**\n * @notice Sets max deposit deviation that is considered when adding\n * liquidity to Balancer pools.\n * @param _maxDepositDeviation Max deposit deviation denominated in\n * wad (number with 18 decimals): 1e18 == 100%, 1e16 == 1%\n *\n * IMPORTANT Minimum maxDepositDeviation will default to 1% (1e16)\n * for production usage. Vault value checker in combination with\n * checkBalance will catch any unexpected manipulation.\n */\n function setMaxDepositDeviation(uint256 _maxDepositDeviation)\n external\n onlyVaultOrGovernorOrStrategist\n {\n require(_maxDepositDeviation <= 1e18, \"Deposit dev. out of bounds\");\n emit MaxDepositDeviationUpdated(\n maxDepositDeviation,\n _maxDepositDeviation\n );\n maxDepositDeviation = _maxDepositDeviation;\n }\n\n function _approveBase() internal virtual {\n IERC20 pToken = IERC20(platformAddress);\n // Balancer vault for BPT token (required for removing liquidity)\n pToken.safeApprove(address(balancerVault), type(uint256).max);\n }\n\n function _getRateProviderRate(address _asset)\n internal\n view\n virtual\n returns (uint256);\n}\n" + }, + "contracts/strategies/balancer/VaultReentrancyLib.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n\n// You should have received a copy of the GNU General Public License\n// along with this program. If not, see .\n\npragma solidity >=0.7.0 <0.9.0;\n\nimport \"../../utils/BalancerErrors.sol\";\nimport { IBalancerVault } from \"../../interfaces/balancer/IBalancerVault.sol\";\n\nlibrary VaultReentrancyLib {\n /**\n * @dev Ensure we are not in a Vault context when this function is called, by attempting a no-op internal\n * balance operation. If we are already in a Vault transaction (e.g., a swap, join, or exit), the Vault's\n * reentrancy protection will cause this function to revert.\n *\n * The exact function call doesn't really matter: we're just trying to trigger the Vault reentrancy check\n * (and not hurt anything in case it works). An empty operation array with no specific operation at all works\n * for that purpose, and is also the least expensive in terms of gas and bytecode size.\n *\n * Call this at the top of any function that can cause a state change in a pool and is either public itself,\n * or called by a public function *outside* a Vault operation (e.g., join, exit, or swap).\n *\n * If this is *not* called in functions that are vulnerable to the read-only reentrancy issue described\n * here (https://forum.balancer.fi/t/reentrancy-vulnerability-scope-expanded/4345), those functions are unsafe,\n * and subject to manipulation that may result in loss of funds.\n */\n function ensureNotInVaultContext(IBalancerVault vault) internal view {\n // Perform the following operation to trigger the Vault's reentrancy guard:\n //\n // IBalancerVault.UserBalanceOp[] memory noop = new IBalancerVault.UserBalanceOp[](0);\n // _vault.manageUserBalance(noop);\n //\n // However, use a static call so that it can be a view function (even though the function is non-view).\n // This allows the library to be used more widely, as some functions that need to be protected might be\n // view.\n //\n // This staticcall always reverts, but we need to make sure it doesn't fail due to a re-entrancy attack.\n // Staticcalls consume all gas forwarded to them on a revert caused by storage modification.\n // By default, almost the entire available gas is forwarded to the staticcall,\n // causing the entire call to revert with an 'out of gas' error.\n //\n // We set the gas limit to 10k for the staticcall to\n // avoid wasting gas when it reverts due to storage modification.\n // `manageUserBalance` is a non-reentrant function in the Vault, so calling it invokes `_enterNonReentrant`\n // in the `ReentrancyGuard` contract, reproduced here:\n //\n // function _enterNonReentrant() private {\n // // If the Vault is actually being reentered, it will revert in the first line, at the `_require` that\n // // checks the reentrancy flag, with \"BAL#400\" (corresponding to Errors.REENTRANCY) in the revertData.\n // // The full revertData will be: `abi.encodeWithSignature(\"Error(string)\", \"BAL#400\")`.\n // _require(_status != _ENTERED, Errors.REENTRANCY);\n //\n // // If the Vault is not being reentered, the check above will pass: but it will *still* revert,\n // // because the next line attempts to modify storage during a staticcall. However, this type of\n // // failure results in empty revertData.\n // _status = _ENTERED;\n // }\n //\n // So based on this analysis, there are only two possible revertData values: empty, or abi.encoded BAL#400.\n //\n // It is of course much more bytecode and gas efficient to check for zero-length revertData than to compare it\n // to the encoded REENTRANCY revertData.\n //\n // While it should be impossible for the call to fail in any other way (especially since it reverts before\n // `manageUserBalance` even gets called), any other error would generate non-zero revertData, so checking for\n // empty data guards against this case too.\n\n (, bytes memory revertData) = address(vault).staticcall{ gas: 10_000 }(\n abi.encodeWithSelector(vault.manageUserBalance.selector, 0)\n );\n\n _require(revertData.length == 0, Errors.REENTRANCY);\n }\n}\n" + }, + "contracts/strategies/BaseCompoundStrategy.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @title Base Compound Abstract Strategy\n * @author Origin Protocol Inc\n */\n\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { ICERC20 } from \"./ICompound.sol\";\nimport { IComptroller } from \"../interfaces/IComptroller.sol\";\nimport { IERC20, InitializableAbstractStrategy } from \"../utils/InitializableAbstractStrategy.sol\";\n\nabstract contract BaseCompoundStrategy is InitializableAbstractStrategy {\n using SafeERC20 for IERC20;\n\n int256[50] private __reserved;\n\n /**\n * @dev Retuns bool indicating whether asset is supported by strategy\n * @param _asset Address of the asset\n */\n function supportsAsset(address _asset) public view override returns (bool) {\n return assetToPToken[_asset] != address(0);\n }\n\n /**\n * @dev Get the cToken wrapped in the ICERC20 interface for this asset.\n * Fails if the pToken doesn't exist in our mappings.\n * @param _asset Address of the asset\n * @return Corresponding cToken to this asset\n */\n function _getCTokenFor(address _asset) internal view returns (ICERC20) {\n address cToken = assetToPToken[_asset];\n require(cToken != address(0), \"cToken does not exist\");\n return ICERC20(cToken);\n }\n\n /**\n * @dev Converts an underlying amount into cToken amount\n * cTokenAmt = (underlying * 1e18) / exchangeRate\n * @param _cToken cToken for which to change\n * @param _underlying Amount of underlying to convert\n * @return amount Equivalent amount of cTokens\n */\n function _convertUnderlyingToCToken(ICERC20 _cToken, uint256 _underlying)\n internal\n view\n returns (uint256 amount)\n {\n // e.g. 1e18*1e18 / 205316390724364402565641705 = 50e8\n // e.g. 1e8*1e18 / 205316390724364402565641705 = 0.45 or 0\n amount = (_underlying * 1e18) / _cToken.exchangeRateStored();\n }\n}\n" + }, + "contracts/strategies/BaseConvexMetaStrategy.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @title Curve Convex Strategy\n * @notice Investment strategy for investing stablecoins via Curve 3Pool\n * @author Origin Protocol Inc\n */\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nimport { IRewardStaking } from \"./IRewardStaking.sol\";\nimport { ICurvePool } from \"./ICurvePool.sol\";\nimport { ICurveMetaPool } from \"./ICurveMetaPool.sol\";\nimport { IERC20, BaseCurveStrategy, InitializableAbstractStrategy } from \"./BaseCurveStrategy.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\nimport { Helpers } from \"../utils/Helpers.sol\";\n\nabstract contract BaseConvexMetaStrategy is BaseCurveStrategy {\n using StableMath for uint256;\n using SafeERC20 for IERC20;\n\n event MaxWithdrawalSlippageUpdated(\n uint256 _prevMaxSlippagePercentage,\n uint256 _newMaxSlippagePercentage\n );\n\n // used to circumvent the stack too deep issue\n struct InitConfig {\n address cvxDepositorAddress; //Address of the Convex depositor(AKA booster) for this pool\n address metapoolAddress; //Address of the Curve MetaPool\n address metapoolMainToken; //Address of Main metapool token\n address cvxRewardStakerAddress; //Address of the CVX rewards staker\n address metapoolLPToken; //Address of metapool LP token\n uint256 cvxDepositorPTokenId; //Pid of the pool referred to by Depositor and staker\n }\n\n address internal cvxDepositorAddress;\n address internal cvxRewardStakerAddress;\n uint256 internal cvxDepositorPTokenId;\n ICurveMetaPool internal metapool;\n IERC20 internal metapoolMainToken;\n IERC20 internal metapoolLPToken;\n // Ordered list of metapool assets\n address[] internal metapoolAssets;\n // Max withdrawal slippage denominated in 1e18 (1e18 == 100%)\n uint256 public maxWithdrawalSlippage;\n uint128 internal crvCoinIndex;\n uint128 internal mainCoinIndex;\n\n int256[41] private ___reserved;\n\n /**\n * Initializer for setting up strategy internal state. This overrides the\n * InitializableAbstractStrategy initializer as Curve strategies don't fit\n * well within that abstraction.\n * @param _rewardTokenAddresses Address of CRV & CVX\n * @param _assets Addresses of supported assets. MUST be passed in the same\n * order as returned by coins on the pool contract, i.e.\n * DAI, USDC, USDT\n * @param _pTokens Platform Token corresponding addresses\n * @param initConfig Various addresses and info for initialization state\n */\n function initialize(\n address[] calldata _rewardTokenAddresses, // CRV + CVX\n address[] calldata _assets,\n address[] calldata _pTokens,\n InitConfig calldata initConfig\n ) external onlyGovernor initializer {\n require(_assets.length == 3, \"Must have exactly three assets\");\n // Should be set prior to abstract initialize call otherwise\n // abstractSetPToken calls will fail\n cvxDepositorAddress = initConfig.cvxDepositorAddress;\n pTokenAddress = _pTokens[0];\n metapool = ICurveMetaPool(initConfig.metapoolAddress);\n metapoolMainToken = IERC20(initConfig.metapoolMainToken);\n cvxRewardStakerAddress = initConfig.cvxRewardStakerAddress;\n metapoolLPToken = IERC20(initConfig.metapoolLPToken);\n cvxDepositorPTokenId = initConfig.cvxDepositorPTokenId;\n maxWithdrawalSlippage = 1e16;\n\n metapoolAssets = [metapool.coins(0), metapool.coins(1)];\n crvCoinIndex = _getMetapoolCoinIndex(pTokenAddress);\n mainCoinIndex = _getMetapoolCoinIndex(initConfig.metapoolMainToken);\n InitializableAbstractStrategy._initialize(\n _rewardTokenAddresses,\n _assets,\n _pTokens\n );\n _approveBase();\n }\n\n /**\n * @dev Get the total asset value held in the platform\n * @param _asset Address of the asset\n * @return balance Total value of the asset in the platform\n */\n function checkBalance(address _asset)\n public\n view\n virtual\n override\n returns (uint256 balance)\n {\n require(assetToPToken[_asset] != address(0), \"Unsupported asset\");\n balance = 0;\n\n // LP tokens in this contract. This should generally be nothing as we\n // should always stake the full balance in the Gauge, but include for\n // safety\n uint256 contractPTokens = IERC20(pTokenAddress).balanceOf(\n address(this)\n );\n ICurvePool curvePool = ICurvePool(platformAddress);\n if (contractPTokens > 0) {\n uint256 virtual_price = curvePool.get_virtual_price();\n uint256 value = contractPTokens.mulTruncate(virtual_price);\n balance += value;\n }\n\n /* We intentionally omit the metapoolLp tokens held by the metastrategyContract\n * since the contract should never (except in the middle of deposit/withdrawal\n * transaction) hold any amount of those tokens in normal operation. There\n * could be tokens sent to it by a 3rd party and we decide to actively ignore\n * those.\n */\n uint256 metapoolGaugePTokens = IRewardStaking(cvxRewardStakerAddress)\n .balanceOf(address(this));\n\n if (metapoolGaugePTokens > 0) {\n uint256 value = metapoolGaugePTokens.mulTruncate(\n metapool.get_virtual_price()\n );\n balance += value;\n }\n\n uint256 assetDecimals = Helpers.getDecimals(_asset);\n balance = balance.scaleBy(assetDecimals, 18) / THREEPOOL_ASSET_COUNT;\n }\n\n /**\n * @dev This function is completely analogous to _calcCurveTokenAmount[BaseCurveStrategy]\n * and just utilizes different Curve (meta)pool API\n */\n function _calcCurveMetaTokenAmount(uint128 _coinIndex, uint256 _amount)\n internal\n returns (uint256 requiredMetapoolLP)\n {\n uint256[2] memory _amounts = [uint256(0), uint256(0)];\n _amounts[uint256(_coinIndex)] = _amount;\n\n // LP required when removing required asset ignoring fees\n uint256 lpRequiredNoFees = metapool.calc_token_amount(_amounts, false);\n /* LP required if fees would apply to entirety of removed amount\n *\n * fee is 1e10 denominated number: https://curve.readthedocs.io/exchange-pools.html#StableSwap.fee\n */\n uint256 lpRequiredFullFees = lpRequiredNoFees.mulTruncateScale(\n 1e10 + metapool.fee(),\n 1e10\n );\n\n /* asset received when withdrawing full fee applicable LP accounting for\n * slippage and fees\n */\n uint256 assetReceivedForFullLPFees = metapool.calc_withdraw_one_coin(\n lpRequiredFullFees,\n int128(_coinIndex)\n );\n\n // exact amount of LP required\n requiredMetapoolLP =\n (lpRequiredFullFees * _amount) /\n assetReceivedForFullLPFees;\n }\n\n function _approveBase() internal override {\n IERC20 pToken = IERC20(pTokenAddress);\n // 3Pool for LP token (required for removing liquidity)\n pToken.safeApprove(platformAddress, 0);\n pToken.safeApprove(platformAddress, type(uint256).max);\n // Gauge for LP token\n metapoolLPToken.safeApprove(cvxDepositorAddress, 0);\n metapoolLPToken.safeApprove(cvxDepositorAddress, type(uint256).max);\n // Metapool for LP token\n pToken.safeApprove(address(metapool), 0);\n pToken.safeApprove(address(metapool), type(uint256).max);\n // Metapool for Metapool main token\n metapoolMainToken.safeApprove(address(metapool), 0);\n metapoolMainToken.safeApprove(address(metapool), type(uint256).max);\n }\n\n /**\n * @dev Get the index of the coin\n */\n function _getMetapoolCoinIndex(address _asset)\n internal\n view\n returns (uint128)\n {\n for (uint128 i = 0; i < 2; i++) {\n if (metapoolAssets[i] == _asset) return i;\n }\n revert(\"Invalid Metapool asset\");\n }\n\n /**\n * @dev Sets max withdrawal slippage that is considered when removing\n * liquidity from Metapools.\n * @param _maxWithdrawalSlippage Max withdrawal slippage denominated in\n * wad (number with 18 decimals): 1e18 == 100%, 1e16 == 1%\n *\n * IMPORTANT Minimum maxWithdrawalSlippage should actually be 0.1% (1e15)\n * for production usage. Contract allows as low value as 0% for confirming\n * correct behavior in test suite.\n */\n function setMaxWithdrawalSlippage(uint256 _maxWithdrawalSlippage)\n external\n onlyVaultOrGovernorOrStrategist\n {\n require(\n _maxWithdrawalSlippage <= 1e18,\n \"Max withdrawal slippage needs to be between 0% - 100%\"\n );\n emit MaxWithdrawalSlippageUpdated(\n maxWithdrawalSlippage,\n _maxWithdrawalSlippage\n );\n maxWithdrawalSlippage = _maxWithdrawalSlippage;\n }\n\n /**\n * @dev Collect accumulated CRV and CVX and send to Harvester.\n */\n function collectRewardTokens()\n external\n override\n onlyHarvester\n nonReentrant\n {\n // Collect CRV and CVX\n IRewardStaking(cvxRewardStakerAddress).getReward();\n _collectRewardTokens();\n }\n\n /**\n * @dev Returns the largest of two numbers int256 version\n */\n function _max(int256 a, int256 b) internal pure returns (int256) {\n return a >= b ? a : b;\n }\n}\n" + }, + "contracts/strategies/BaseCurveStrategy.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @title Curve 3Pool Strategy\n * @notice Investment strategy for investing stablecoins via Curve 3Pool\n * @author Origin Protocol Inc\n */\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nimport { ICurvePool } from \"./ICurvePool.sol\";\nimport { IERC20, InitializableAbstractStrategy } from \"../utils/InitializableAbstractStrategy.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\nimport { Helpers } from \"../utils/Helpers.sol\";\n\nabstract contract BaseCurveStrategy is InitializableAbstractStrategy {\n using StableMath for uint256;\n using SafeERC20 for IERC20;\n\n uint256 internal constant MAX_SLIPPAGE = 1e16; // 1%, same as the Curve UI\n // number of assets in Curve 3Pool (USDC, DAI, USDT)\n uint256 internal constant THREEPOOL_ASSET_COUNT = 3;\n address internal pTokenAddress;\n\n int256[49] private __reserved;\n\n /**\n * @dev Deposit asset into the Curve 3Pool\n * @param _asset Address of asset to deposit\n * @param _amount Amount of asset to deposit\n */\n function deposit(address _asset, uint256 _amount)\n external\n override\n onlyVault\n nonReentrant\n {\n require(_amount > 0, \"Must deposit something\");\n emit Deposit(_asset, pTokenAddress, _amount);\n\n // 3Pool requires passing deposit amounts for all 3 assets, set to 0 for\n // all\n uint256[3] memory _amounts;\n uint256 poolCoinIndex = _getCoinIndex(_asset);\n // Set the amount on the asset we want to deposit\n _amounts[poolCoinIndex] = _amount;\n ICurvePool curvePool = ICurvePool(platformAddress);\n uint256 assetDecimals = Helpers.getDecimals(_asset);\n uint256 depositValue = _amount.scaleBy(18, assetDecimals).divPrecisely(\n curvePool.get_virtual_price()\n );\n uint256 minMintAmount = depositValue.mulTruncate(\n uint256(1e18) - MAX_SLIPPAGE\n );\n // Do the deposit to 3pool\n curvePool.add_liquidity(_amounts, minMintAmount);\n _lpDepositAll();\n }\n\n function _lpDepositAll() internal virtual;\n\n /**\n * @dev Deposit the entire balance of any supported asset into the Curve 3pool\n */\n function depositAll() external override onlyVault nonReentrant {\n uint256[3] memory _amounts = [uint256(0), uint256(0), uint256(0)];\n uint256 depositValue = 0;\n ICurvePool curvePool = ICurvePool(platformAddress);\n uint256 curveVirtualPrice = curvePool.get_virtual_price();\n\n for (uint256 i = 0; i < assetsMapped.length; i++) {\n address assetAddress = assetsMapped[i];\n uint256 balance = IERC20(assetAddress).balanceOf(address(this));\n if (balance > 0) {\n uint256 poolCoinIndex = _getCoinIndex(assetAddress);\n // Set the amount on the asset we want to deposit\n _amounts[poolCoinIndex] = balance;\n uint256 assetDecimals = Helpers.getDecimals(assetAddress);\n // Get value of deposit in Curve LP token to later determine\n // the minMintAmount argument for add_liquidity\n depositValue =\n depositValue +\n balance.scaleBy(18, assetDecimals).divPrecisely(\n curveVirtualPrice\n );\n emit Deposit(assetAddress, pTokenAddress, balance);\n }\n }\n\n uint256 minMintAmount = depositValue.mulTruncate(\n uint256(1e18) - MAX_SLIPPAGE\n );\n // Do the deposit to 3pool\n curvePool.add_liquidity(_amounts, minMintAmount);\n\n /* In case of Curve Strategy all assets are mapped to the same pToken (3CrvLP). Let\n * descendants further handle the pToken. By either deploying it to the metapool and\n * resulting tokens in Gauge. Or deploying pTokens directly to the Gauge.\n */\n _lpDepositAll();\n }\n\n function _lpWithdraw(uint256 numCrvTokens) internal virtual;\n\n function _lpWithdrawAll() internal virtual;\n\n /**\n * @dev Withdraw asset from Curve 3Pool\n * @param _recipient Address to receive withdrawn asset\n * @param _asset Address of asset to withdraw\n * @param _amount Amount of asset to withdraw\n */\n function withdraw(\n address _recipient,\n address _asset,\n uint256 _amount\n ) external override onlyVault nonReentrant {\n require(_amount > 0, \"Invalid amount\");\n\n emit Withdrawal(_asset, pTokenAddress, _amount);\n\n uint256 contractCrv3Tokens = IERC20(pTokenAddress).balanceOf(\n address(this)\n );\n\n uint256 coinIndex = _getCoinIndex(_asset);\n ICurvePool curvePool = ICurvePool(platformAddress);\n\n uint256 requiredCrv3Tokens = _calcCurveTokenAmount(coinIndex, _amount);\n\n // We have enough LP tokens, make sure they are all on this contract\n if (contractCrv3Tokens < requiredCrv3Tokens) {\n _lpWithdraw(requiredCrv3Tokens - contractCrv3Tokens);\n }\n\n uint256[3] memory _amounts = [uint256(0), uint256(0), uint256(0)];\n _amounts[coinIndex] = _amount;\n\n curvePool.remove_liquidity_imbalance(_amounts, requiredCrv3Tokens);\n IERC20(_asset).safeTransfer(_recipient, _amount);\n }\n\n /**\n * @dev Calculate amount of LP required when withdrawing specific amount of one\n * of the underlying assets accounting for fees and slippage.\n *\n * Curve pools unfortunately do not contain a calculation function for\n * amount of LP required when withdrawing a specific amount of one of the\n * underlying tokens and also accounting for fees (Curve's calc_token_amount\n * does account for slippage but not fees).\n *\n * Steps taken to calculate the metric:\n * - get amount of LP required if fees wouldn't apply\n * - increase the LP amount as if fees would apply to the entirety of the underlying\n * asset withdrawal. (when withdrawing only one coin fees apply only to amounts\n * of other assets pool would return in case of balanced removal - since those need\n * to be swapped for the single underlying asset being withdrawn)\n * - get amount of underlying asset withdrawn (this Curve function does consider slippage\n * and fees) when using the increased LP amount. As LP amount is slightly over-increased\n * so is amount of underlying assets returned.\n * - since we know exactly how much asset we require take the rate of LP required for asset\n * withdrawn to get the exact amount of LP.\n */\n function _calcCurveTokenAmount(uint256 _coinIndex, uint256 _amount)\n internal\n returns (uint256 required3Crv)\n {\n ICurvePool curvePool = ICurvePool(platformAddress);\n\n uint256[3] memory _amounts = [uint256(0), uint256(0), uint256(0)];\n _amounts[_coinIndex] = _amount;\n\n // LP required when removing required asset ignoring fees\n uint256 lpRequiredNoFees = curvePool.calc_token_amount(_amounts, false);\n /* LP required if fees would apply to entirety of removed amount\n *\n * fee is 1e10 denominated number: https://curve.readthedocs.io/exchange-pools.html#StableSwap.fee\n */\n uint256 lpRequiredFullFees = lpRequiredNoFees.mulTruncateScale(\n 1e10 + curvePool.fee(),\n 1e10\n );\n\n /* asset received when withdrawing full fee applicable LP accounting for\n * slippage and fees\n */\n uint256 assetReceivedForFullLPFees = curvePool.calc_withdraw_one_coin(\n lpRequiredFullFees,\n int128(uint128(_coinIndex))\n );\n\n // exact amount of LP required\n required3Crv =\n (lpRequiredFullFees * _amount) /\n assetReceivedForFullLPFees;\n }\n\n /**\n * @dev Remove all assets from platform and send them to Vault contract.\n */\n function withdrawAll() external override onlyVaultOrGovernor nonReentrant {\n _lpWithdrawAll();\n // Withdraws are proportional to assets held by 3Pool\n uint256[3] memory minWithdrawAmounts = [\n uint256(0),\n uint256(0),\n uint256(0)\n ];\n\n // Remove liquidity\n ICurvePool threePool = ICurvePool(platformAddress);\n threePool.remove_liquidity(\n IERC20(pTokenAddress).balanceOf(address(this)),\n minWithdrawAmounts\n );\n // Transfer assets out of Vault\n // Note that Curve will provide all 3 of the assets in 3pool even if\n // we have not set PToken addresses for all of them in this strategy\n for (uint256 i = 0; i < assetsMapped.length; i++) {\n IERC20 asset = IERC20(threePool.coins(i));\n asset.safeTransfer(vaultAddress, asset.balanceOf(address(this)));\n }\n }\n\n /**\n * @dev Get the total asset value held in the platform\n * @param _asset Address of the asset\n * @return balance Total value of the asset in the platform\n */\n function checkBalance(address _asset)\n public\n view\n virtual\n override\n returns (uint256 balance)\n {\n require(assetToPToken[_asset] != address(0), \"Unsupported asset\");\n // LP tokens in this contract. This should generally be nothing as we\n // should always stake the full balance in the Gauge, but include for\n // safety\n uint256 totalPTokens = IERC20(pTokenAddress).balanceOf(address(this));\n ICurvePool curvePool = ICurvePool(platformAddress);\n if (totalPTokens > 0) {\n uint256 virtual_price = curvePool.get_virtual_price();\n uint256 value = (totalPTokens * virtual_price) / 1e18;\n uint256 assetDecimals = Helpers.getDecimals(_asset);\n balance = value.scaleBy(assetDecimals, 18) / THREEPOOL_ASSET_COUNT;\n }\n }\n\n /**\n * @dev Retuns bool indicating whether asset is supported by strategy\n * @param _asset Address of the asset\n */\n function supportsAsset(address _asset) public view override returns (bool) {\n return assetToPToken[_asset] != address(0);\n }\n\n /**\n * @dev Approve the spending of all assets by their corresponding pool tokens,\n * if for some reason is it necessary.\n */\n function safeApproveAllTokens()\n external\n override\n onlyGovernor\n nonReentrant\n {\n _approveBase();\n // This strategy is a special case since it only supports one asset\n for (uint256 i = 0; i < assetsMapped.length; i++) {\n _approveAsset(assetsMapped[i]);\n }\n }\n\n /**\n * @dev Call the necessary approvals for the Curve pool and gauge\n * @param _asset Address of the asset\n */\n function _abstractSetPToken(address _asset, address) internal override {\n _approveAsset(_asset);\n }\n\n function _approveAsset(address _asset) internal {\n IERC20 asset = IERC20(_asset);\n // 3Pool for asset (required for adding liquidity)\n asset.safeApprove(platformAddress, 0);\n asset.safeApprove(platformAddress, type(uint256).max);\n }\n\n function _approveBase() internal virtual;\n\n /**\n * @dev Get the index of the coin\n */\n function _getCoinIndex(address _asset) internal view returns (uint256) {\n for (uint256 i = 0; i < 3; i++) {\n if (assetsMapped[i] == _asset) return i;\n }\n revert(\"Invalid 3pool asset\");\n }\n}\n" + }, + "contracts/strategies/CompoundStrategy.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @title Compound Strategy\n * @notice Investment strategy for Compound like lending platforms. eg Compound and Flux\n * @author Origin Protocol Inc\n */\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nimport { ICERC20 } from \"./ICompound.sol\";\nimport { BaseCompoundStrategy, InitializableAbstractStrategy } from \"./BaseCompoundStrategy.sol\";\nimport { IComptroller } from \"../interfaces/IComptroller.sol\";\nimport { IERC20 } from \"../utils/InitializableAbstractStrategy.sol\";\n\ncontract CompoundStrategy is BaseCompoundStrategy {\n using SafeERC20 for IERC20;\n event SkippedWithdrawal(address asset, uint256 amount);\n\n constructor(BaseStrategyConfig memory _stratConfig)\n InitializableAbstractStrategy(_stratConfig)\n {}\n\n /**\n * @notice initialize function, to set up initial internal state\n * @param _rewardTokenAddresses Address of reward token for platform\n * @param _assets Addresses of initial supported assets\n * @param _pTokens Platform Token corresponding addresses\n */\n function initialize(\n address[] memory _rewardTokenAddresses,\n address[] memory _assets,\n address[] memory _pTokens\n ) external onlyGovernor initializer {\n InitializableAbstractStrategy._initialize(\n _rewardTokenAddresses,\n _assets,\n _pTokens\n );\n }\n\n /**\n * @notice Collect accumulated COMP and send to Harvester.\n */\n function collectRewardTokens()\n external\n virtual\n override\n onlyHarvester\n nonReentrant\n {\n // Claim COMP from Comptroller\n ICERC20 cToken = _getCTokenFor(assetsMapped[0]);\n IComptroller comptroller = IComptroller(cToken.comptroller());\n // Only collect from active cTokens, saves gas\n address[] memory ctokensToCollect = new address[](assetsMapped.length);\n uint256 assetCount = assetsMapped.length;\n for (uint256 i = 0; i < assetCount; ++i) {\n ctokensToCollect[i] = address(_getCTokenFor(assetsMapped[i]));\n }\n // Claim only for this strategy\n address[] memory claimers = new address[](1);\n claimers[0] = address(this);\n // Claim COMP from Comptroller. Only collect for supply, saves gas\n comptroller.claimComp(claimers, ctokensToCollect, false, true);\n // Transfer COMP to Harvester\n IERC20 rewardToken = IERC20(rewardTokenAddresses[0]);\n uint256 balance = rewardToken.balanceOf(address(this));\n emit RewardTokenCollected(\n harvesterAddress,\n rewardTokenAddresses[0],\n balance\n );\n rewardToken.safeTransfer(harvesterAddress, balance);\n }\n\n /**\n * @notice Deposit asset into the underlying platform\n * @param _asset Address of asset to deposit\n * @param _amount Amount of assets to deposit\n */\n function deposit(address _asset, uint256 _amount)\n external\n override\n onlyVault\n nonReentrant\n {\n _deposit(_asset, _amount);\n }\n\n /**\n * @dev Deposit an asset into the underlying platform\n * @param _asset Address of the asset to deposit\n * @param _amount Amount of assets to deposit\n */\n function _deposit(address _asset, uint256 _amount) internal {\n require(_amount > 0, \"Must deposit something\");\n ICERC20 cToken = _getCTokenFor(_asset);\n emit Deposit(_asset, address(cToken), _amount);\n require(cToken.mint(_amount) == 0, \"cToken mint failed\");\n }\n\n /**\n * @notice Deposit the entire balance of any supported asset in the strategy into the underlying platform\n */\n function depositAll() external override onlyVault nonReentrant {\n uint256 assetCount = assetsMapped.length;\n for (uint256 i = 0; i < assetCount; ++i) {\n IERC20 asset = IERC20(assetsMapped[i]);\n uint256 assetBalance = asset.balanceOf(address(this));\n if (assetBalance > 0) {\n _deposit(address(asset), assetBalance);\n }\n }\n }\n\n /**\n * @notice Withdraw an asset from the underlying platform\n * @param _recipient Address to receive withdrawn assets\n * @param _asset Address of the asset to withdraw\n * @param _amount Amount of assets to withdraw\n */\n function withdraw(\n address _recipient,\n address _asset,\n uint256 _amount\n ) external override onlyVault nonReentrant {\n require(_amount > 0, \"Must withdraw something\");\n require(_recipient != address(0), \"Must specify recipient\");\n\n ICERC20 cToken = _getCTokenFor(_asset);\n // If redeeming 0 cTokens, just skip, else COMP will revert\n uint256 cTokensToRedeem = _convertUnderlyingToCToken(cToken, _amount);\n if (cTokensToRedeem == 0) {\n emit SkippedWithdrawal(_asset, _amount);\n return;\n }\n\n emit Withdrawal(_asset, address(cToken), _amount);\n require(cToken.redeemUnderlying(_amount) == 0, \"Redeem failed\");\n IERC20(_asset).safeTransfer(_recipient, _amount);\n }\n\n /**\n * @dev Internal method to respond to the addition of new asset / cTokens\n * We need to approve the cToken and give it permission to spend the asset\n * @param _asset Address of the asset to approve. eg DAI\n * @param _pToken The pToken for the approval. eg cDAI or fDAI\n */\n function _abstractSetPToken(address _asset, address _pToken)\n internal\n override\n {\n // Safe approval\n IERC20(_asset).safeApprove(_pToken, 0);\n IERC20(_asset).safeApprove(_pToken, type(uint256).max);\n }\n\n /**\n * @notice Remove all supported assets from the underlying platform and send them to Vault contract.\n */\n function withdrawAll() external override onlyVaultOrGovernor nonReentrant {\n uint256 assetCount = assetsMapped.length;\n for (uint256 i = 0; i < assetCount; ++i) {\n IERC20 asset = IERC20(assetsMapped[i]);\n // Redeem entire balance of cToken\n ICERC20 cToken = _getCTokenFor(address(asset));\n uint256 cTokenBalance = cToken.balanceOf(address(this));\n if (cTokenBalance > 0) {\n require(cToken.redeem(cTokenBalance) == 0, \"Redeem failed\");\n uint256 assetBalance = asset.balanceOf(address(this));\n // Transfer entire balance to Vault\n asset.safeTransfer(vaultAddress, assetBalance);\n\n emit Withdrawal(address(asset), address(cToken), assetBalance);\n }\n }\n }\n\n /**\n * @notice Get the total asset value held in the underlying platform\n * This includes any interest that was generated since depositing.\n * The exchange rate between the cToken and asset gradually increases,\n * causing the cToken to be worth more corresponding asset.\n * @param _asset Address of the asset\n * @return balance Total value of the asset in the platform\n */\n function checkBalance(address _asset)\n external\n view\n override\n returns (uint256 balance)\n {\n // Balance is always with token cToken decimals\n ICERC20 cToken = _getCTokenFor(_asset);\n balance = _checkBalance(cToken);\n }\n\n /**\n * @dev Get the total asset value held in the platform\n * underlying = (cTokenAmt * exchangeRate) / 1e18\n * @param _cToken cToken for which to check balance\n * @return balance Total value of the asset in the platform\n */\n function _checkBalance(ICERC20 _cToken)\n internal\n view\n returns (uint256 balance)\n {\n // e.g. 50e8*205316390724364402565641705 / 1e18 = 1.0265..e18\n balance =\n (_cToken.balanceOf(address(this)) * _cToken.exchangeRateStored()) /\n 1e18;\n }\n\n /**\n * @notice Approve the spending of all assets by their corresponding cToken,\n * if for some reason is it necessary.\n */\n function safeApproveAllTokens() external override {\n uint256 assetCount = assetsMapped.length;\n for (uint256 i = 0; i < assetCount; ++i) {\n IERC20 asset = IERC20(assetsMapped[i]);\n address cToken = assetToPToken[address(asset)];\n // Safe approval\n asset.safeApprove(cToken, 0);\n asset.safeApprove(cToken, type(uint256).max);\n }\n }\n}\n" + }, + "contracts/strategies/ConvexEthMetaStrategy.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @title Convex Automated Market Maker (AMO) Strategy\n * @notice AMO strategy for the Curve OETH/ETH pool\n * @author Origin Protocol Inc\n */\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/utils/math/Math.sol\";\n\nimport { ICurveETHPoolV1 } from \"./ICurveETHPoolV1.sol\";\nimport { IERC20, InitializableAbstractStrategy } from \"../utils/InitializableAbstractStrategy.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\nimport { IVault } from \"../interfaces/IVault.sol\";\nimport { IWETH9 } from \"../interfaces/IWETH9.sol\";\nimport { IConvexDeposits } from \"./IConvexDeposits.sol\";\nimport { IRewardStaking } from \"./IRewardStaking.sol\";\n\ncontract ConvexEthMetaStrategy is InitializableAbstractStrategy {\n using StableMath for uint256;\n using SafeERC20 for IERC20;\n\n uint256 public constant MAX_SLIPPAGE = 1e16; // 1%, same as the Curve UI\n address public constant ETH_ADDRESS =\n 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n // The following slots have been deprecated with immutable variables\n // slither-disable-next-line constable-states\n address private _deprecated_cvxDepositorAddress;\n // slither-disable-next-line constable-states\n address private _deprecated_cvxRewardStaker;\n // slither-disable-next-line constable-states\n uint256 private _deprecated_cvxDepositorPTokenId;\n // slither-disable-next-line constable-states\n address private _deprecated_curvePool;\n // slither-disable-next-line constable-states\n address private _deprecated_lpToken;\n // slither-disable-next-line constable-states\n address private _deprecated_oeth;\n // slither-disable-next-line constable-states\n address private _deprecated_weth;\n\n // Ordered list of pool assets\n // slither-disable-next-line constable-states\n uint128 private _deprecated_oethCoinIndex;\n // slither-disable-next-line constable-states\n uint128 private _deprecated_ethCoinIndex;\n\n // New immutable variables that must be set in the constructor\n address public immutable cvxDepositorAddress;\n IRewardStaking public immutable cvxRewardStaker;\n uint256 public immutable cvxDepositorPTokenId;\n ICurveETHPoolV1 public immutable curvePool;\n IERC20 public immutable lpToken;\n IERC20 public immutable oeth;\n IWETH9 public immutable weth;\n\n // Ordered list of pool assets\n uint128 public constant oethCoinIndex = 1;\n uint128 public constant ethCoinIndex = 0;\n\n /**\n * @dev Verifies that the caller is the Strategist.\n */\n modifier onlyStrategist() {\n require(\n msg.sender == IVault(vaultAddress).strategistAddr(),\n \"Caller is not the Strategist\"\n );\n _;\n }\n\n /**\n * @dev Checks the Curve pool's balances have improved and the balances\n * have not tipped to the other side.\n * This modifier only works on functions that do a single sided add or remove.\n * The standard deposit function adds to both sides of the pool in a way that\n * the pool's balance is not worsened.\n * Withdrawals are proportional so doesn't change the pools asset balance.\n */\n modifier improvePoolBalance() {\n // Get the asset and OToken balances in the Curve pool\n uint256[2] memory balancesBefore = curvePool.get_balances();\n // diff = ETH balance - OETH balance\n int256 diffBefore = int256(balancesBefore[ethCoinIndex]) -\n int256(balancesBefore[oethCoinIndex]);\n\n _;\n\n // Get the asset and OToken balances in the Curve pool\n uint256[2] memory balancesAfter = curvePool.get_balances();\n // diff = ETH balance - OETH balance\n int256 diffAfter = int256(balancesAfter[ethCoinIndex]) -\n int256(balancesAfter[oethCoinIndex]);\n\n if (diffBefore <= 0) {\n // If the pool was originally imbalanced in favor of OETH, then\n // we want to check that the pool is now more balanced\n require(diffAfter <= 0, \"OTokens overshot peg\");\n require(diffBefore < diffAfter, \"OTokens balance worse\");\n }\n if (diffBefore >= 0) {\n // If the pool was originally imbalanced in favor of ETH, then\n // we want to check that the pool is now more balanced\n require(diffAfter >= 0, \"Assets overshot peg\");\n require(diffAfter < diffBefore, \"Assets balance worse\");\n }\n }\n\n // Used to circumvent the stack too deep issue\n struct ConvexEthMetaConfig {\n address cvxDepositorAddress; //Address of the Convex depositor(AKA booster) for this pool\n address cvxRewardStakerAddress; //Address of the CVX rewards staker\n uint256 cvxDepositorPTokenId; //Pid of the pool referred to by Depositor and staker\n address oethAddress; //Address of OETH token\n address wethAddress; //Address of WETH\n }\n\n constructor(\n BaseStrategyConfig memory _baseConfig,\n ConvexEthMetaConfig memory _convexConfig\n ) InitializableAbstractStrategy(_baseConfig) {\n lpToken = IERC20(_baseConfig.platformAddress);\n curvePool = ICurveETHPoolV1(_baseConfig.platformAddress);\n\n cvxDepositorAddress = _convexConfig.cvxDepositorAddress;\n cvxRewardStaker = IRewardStaking(_convexConfig.cvxRewardStakerAddress);\n cvxDepositorPTokenId = _convexConfig.cvxDepositorPTokenId;\n oeth = IERC20(_convexConfig.oethAddress);\n weth = IWETH9(_convexConfig.wethAddress);\n }\n\n /**\n * Initializer for setting up strategy internal state. This overrides the\n * InitializableAbstractStrategy initializer as Curve strategies don't fit\n * well within that abstraction.\n * @param _rewardTokenAddresses Address of CRV & CVX\n * @param _assets Addresses of supported assets. eg WETH\n */\n function initialize(\n address[] calldata _rewardTokenAddresses, // CRV + CVX\n address[] calldata _assets // WETH\n ) external onlyGovernor initializer {\n require(_assets.length == 1, \"Must have exactly one asset\");\n require(_assets[0] == address(weth), \"Asset not WETH\");\n\n address[] memory pTokens = new address[](1);\n pTokens[0] = address(curvePool);\n\n InitializableAbstractStrategy._initialize(\n _rewardTokenAddresses,\n _assets,\n pTokens\n );\n\n _approveBase();\n }\n\n /***************************************\n Deposit\n ****************************************/\n\n /**\n * @notice Deposit WETH into the Curve pool\n * @param _weth Address of Wrapped ETH (WETH) contract.\n * @param _amount Amount of WETH to deposit.\n */\n function deposit(address _weth, uint256 _amount)\n external\n override\n onlyVault\n nonReentrant\n {\n _deposit(_weth, _amount);\n }\n\n function _deposit(address _weth, uint256 _wethAmount) internal {\n require(_wethAmount > 0, \"Must deposit something\");\n require(_weth == address(weth), \"Can only deposit WETH\");\n weth.withdraw(_wethAmount);\n\n emit Deposit(_weth, address(lpToken), _wethAmount);\n\n // Get the asset and OToken balances in the Curve pool\n uint256[2] memory balances = curvePool.get_balances();\n // safe to cast since min value is at least 0\n uint256 oethToAdd = uint256(\n _max(\n 0,\n int256(balances[ethCoinIndex]) +\n int256(_wethAmount) -\n int256(balances[oethCoinIndex])\n )\n );\n\n /* Add so much OETH so that the pool ends up being balanced. And at minimum\n * add as much OETH as WETH and at maximum twice as much OETH.\n */\n oethToAdd = Math.max(oethToAdd, _wethAmount);\n oethToAdd = Math.min(oethToAdd, _wethAmount * 2);\n\n /* Mint OETH with a strategy that attempts to contribute to stability of OETH/WETH pool. Try\n * to mint so much OETH that after deployment of liquidity pool ends up being balanced.\n *\n * To manage unpredictability minimal OETH minted will always be at least equal or greater\n * to WETH amount deployed. And never larger than twice the WETH amount deployed even if\n * it would have a further beneficial effect on pool stability.\n */\n IVault(vaultAddress).mintForStrategy(oethToAdd);\n\n emit Deposit(address(oeth), address(lpToken), oethToAdd);\n\n uint256[2] memory _amounts;\n _amounts[ethCoinIndex] = _wethAmount;\n _amounts[oethCoinIndex] = oethToAdd;\n\n uint256 valueInLpTokens = (_wethAmount + oethToAdd).divPrecisely(\n curvePool.get_virtual_price()\n );\n uint256 minMintAmount = valueInLpTokens.mulTruncate(\n uint256(1e18) - MAX_SLIPPAGE\n );\n\n // Do the deposit to the Curve pool\n // slither-disable-next-line arbitrary-send\n uint256 lpDeposited = curvePool.add_liquidity{ value: _wethAmount }(\n _amounts,\n minMintAmount\n );\n\n // Deposit the Curve pool's LP tokens into the Convex rewards pool\n require(\n IConvexDeposits(cvxDepositorAddress).deposit(\n cvxDepositorPTokenId,\n lpDeposited,\n true // Deposit with staking\n ),\n \"Depositing LP to Convex not successful\"\n );\n }\n\n /**\n * @notice Deposit the strategy's entire balance of WETH into the Curve pool\n */\n function depositAll() external override onlyVault nonReentrant {\n uint256 balance = weth.balanceOf(address(this));\n if (balance > 0) {\n _deposit(address(weth), balance);\n }\n }\n\n /***************************************\n Withdraw\n ****************************************/\n\n /**\n * @notice Withdraw ETH and OETH from the Curve pool, burn the OETH,\n * convert the ETH to WETH and transfer to the recipient.\n * @param _recipient Address to receive withdrawn asset which is normally the Vault.\n * @param _weth Address of the Wrapped ETH (WETH) contract.\n * @param _amount Amount of WETH to withdraw.\n */\n function withdraw(\n address _recipient,\n address _weth,\n uint256 _amount\n ) external override onlyVault nonReentrant {\n require(_amount > 0, \"Invalid amount\");\n require(_weth == address(weth), \"Can only withdraw WETH\");\n\n emit Withdrawal(_weth, address(lpToken), _amount);\n\n uint256 requiredLpTokens = calcTokenToBurn(_amount);\n\n _lpWithdraw(requiredLpTokens);\n\n /* math in requiredLpTokens should correctly calculate the amount of LP to remove\n * in that the strategy receives enough WETH on balanced removal\n */\n uint256[2] memory _minWithdrawalAmounts = [uint256(0), uint256(0)];\n _minWithdrawalAmounts[ethCoinIndex] = _amount;\n // slither-disable-next-line unused-return\n curvePool.remove_liquidity(requiredLpTokens, _minWithdrawalAmounts);\n\n // Burn all the removed OETH and any that was left in the strategy\n uint256 oethToBurn = oeth.balanceOf(address(this));\n IVault(vaultAddress).burnForStrategy(oethToBurn);\n\n emit Withdrawal(address(oeth), address(lpToken), oethToBurn);\n\n // Transfer WETH to the recipient\n weth.deposit{ value: _amount }();\n require(\n weth.transfer(_recipient, _amount),\n \"Transfer of WETH not successful\"\n );\n }\n\n function calcTokenToBurn(uint256 _wethAmount)\n internal\n view\n returns (uint256 lpToBurn)\n {\n /* The rate between coins in the pool determines the rate at which pool returns\n * tokens when doing balanced removal (remove_liquidity call). And by knowing how much WETH\n * we want we can determine how much of OETH we receive by removing liquidity.\n *\n * Because we are doing balanced removal we should be making profit when removing liquidity in a\n * pool tilted to either side.\n *\n * Important: A downside is that the Strategist / Governor needs to be\n * cognisant of not removing too much liquidity. And while the proposal to remove liquidity\n * is being voted on the pool tilt might change so much that the proposal that has been valid while\n * created is no longer valid.\n */\n\n uint256 poolWETHBalance = curvePool.balances(ethCoinIndex);\n /* K is multiplied by 1e36 which is used for higher precision calculation of required\n * pool LP tokens. Without it the end value can have rounding errors up to precision of\n * 10 digits. This way we move the decimal point by 36 places when doing the calculation\n * and again by 36 places when we are done with it.\n */\n uint256 k = (1e36 * lpToken.totalSupply()) / poolWETHBalance;\n // prettier-ignore\n // slither-disable-next-line divide-before-multiply\n uint256 diff = (_wethAmount + 1) * k;\n lpToBurn = diff / 1e36;\n }\n\n /**\n * @notice Remove all ETH and OETH from the Curve pool, burn the OETH,\n * convert the ETH to WETH and transfer to the Vault contract.\n */\n function withdrawAll() external override onlyVaultOrGovernor nonReentrant {\n uint256 gaugeTokens = cvxRewardStaker.balanceOf(address(this));\n _lpWithdraw(gaugeTokens);\n\n // Withdraws are proportional to assets held by 3Pool\n uint256[2] memory minWithdrawAmounts = [uint256(0), uint256(0)];\n\n // Remove liquidity\n // slither-disable-next-line unused-return\n curvePool.remove_liquidity(\n lpToken.balanceOf(address(this)),\n minWithdrawAmounts\n );\n\n // Burn all OETH\n uint256 oethToBurn = oeth.balanceOf(address(this));\n IVault(vaultAddress).burnForStrategy(oethToBurn);\n\n // Get the strategy contract's ether balance.\n // This includes all that was removed from the Curve pool and\n // any ether that was sitting in the strategy contract before the removal.\n uint256 ethBalance = address(this).balance;\n // Convert all the strategy contract's ether to WETH and transfer to the vault.\n weth.deposit{ value: ethBalance }();\n require(\n weth.transfer(vaultAddress, ethBalance),\n \"Transfer of WETH not successful\"\n );\n\n emit Withdrawal(address(weth), address(lpToken), ethBalance);\n emit Withdrawal(address(oeth), address(lpToken), oethToBurn);\n }\n\n /***************************************\n Curve pool Rebalancing\n ****************************************/\n\n /**\n * @notice Mint OTokens and one-sided add to the Curve pool.\n * This is used when the Curve pool does not have enough OTokens and too many ETH.\n * The OToken/Asset, eg OETH/ETH, price with increase.\n * The amount of assets in the vault is unchanged.\n * The total supply of OTokens is increased.\n * The asset value of the strategy and vault is increased.\n * @param _oTokens The amount of OTokens to be minted and added to the pool.\n */\n function mintAndAddOTokens(uint256 _oTokens)\n external\n onlyStrategist\n nonReentrant\n improvePoolBalance\n {\n IVault(vaultAddress).mintForStrategy(_oTokens);\n\n uint256[2] memory amounts = [uint256(0), uint256(0)];\n amounts[oethCoinIndex] = _oTokens;\n\n // Convert OETH to Curve pool LP tokens\n uint256 valueInLpTokens = (_oTokens).divPrecisely(\n curvePool.get_virtual_price()\n );\n // Apply slippage to LP tokens\n uint256 minMintAmount = valueInLpTokens.mulTruncate(\n uint256(1e18) - MAX_SLIPPAGE\n );\n\n // Add the minted OTokens to the Curve pool\n uint256 lpDeposited = curvePool.add_liquidity(amounts, minMintAmount);\n\n // Deposit the Curve pool LP tokens to the Convex rewards pool\n require(\n IConvexDeposits(cvxDepositorAddress).deposit(\n cvxDepositorPTokenId,\n lpDeposited,\n true // Deposit with staking\n ),\n \"Failed to Deposit LP to Convex\"\n );\n\n emit Deposit(address(oeth), address(lpToken), _oTokens);\n }\n\n /**\n * @notice One-sided remove of OTokens from the Curve pool which are then burned.\n * This is used when the Curve pool has too many OTokens and not enough ETH.\n * The amount of assets in the vault is unchanged.\n * The total supply of OTokens is reduced.\n * The asset value of the strategy and vault is reduced.\n * @param _lpTokens The amount of Curve pool LP tokens to be burned for OTokens.\n */\n function removeAndBurnOTokens(uint256 _lpTokens)\n external\n onlyStrategist\n nonReentrant\n improvePoolBalance\n {\n // Withdraw Curve pool LP tokens from Convex and remove OTokens from the Curve pool\n uint256 oethToBurn = _withdrawAndRemoveFromPool(\n _lpTokens,\n oethCoinIndex\n );\n\n // The vault burns the OTokens from this strategy\n IVault(vaultAddress).burnForStrategy(oethToBurn);\n\n emit Withdrawal(address(oeth), address(lpToken), oethToBurn);\n }\n\n /**\n * @notice One-sided remove of ETH from the Curve pool, convert to WETH\n * and transfer to the vault.\n * This is used when the Curve pool does not have enough OTokens and too many ETH.\n * The OToken/Asset, eg OETH/ETH, price with decrease.\n * The amount of assets in the vault increases.\n * The total supply of OTokens does not change.\n * The asset value of the strategy reduces.\n * The asset value of the vault should be close to the same.\n * @param _lpTokens The amount of Curve pool LP tokens to be burned for ETH.\n * @dev Curve pool LP tokens is used rather than WETH assets as Curve does not\n * have a way to accurately calculate the amount of LP tokens for a required\n * amount of ETH. Curve's `calc_token_amount` functioun does not include fees.\n * A 3rd party libary can be used that takes into account the fees, but this\n * is a gas intensive process. It's easier for the trusted strategist to\n * caclulate the amount of Curve pool LP tokens required off-chain.\n */\n function removeOnlyAssets(uint256 _lpTokens)\n external\n onlyStrategist\n nonReentrant\n improvePoolBalance\n {\n // Withdraw Curve pool LP tokens from Convex and remove ETH from the Curve pool\n uint256 ethAmount = _withdrawAndRemoveFromPool(_lpTokens, ethCoinIndex);\n\n // Convert ETH to WETH and transfer to the vault\n weth.deposit{ value: ethAmount }();\n require(\n weth.transfer(vaultAddress, ethAmount),\n \"Transfer of WETH not successful\"\n );\n\n emit Withdrawal(address(weth), address(lpToken), ethAmount);\n }\n\n /**\n * @dev Remove Curve pool LP tokens from the Convex pool and\n * do a one-sided remove of ETH or OETH from the Curve pool.\n * @param _lpTokens The amount of Curve pool LP tokens to be removed from the Convex pool.\n * @param coinIndex The index of the coin to be removed from the Curve pool. 0 = ETH, 1 = OETH.\n * @return coinsRemoved The amount of ETH or OETH removed from the Curve pool.\n */\n function _withdrawAndRemoveFromPool(uint256 _lpTokens, uint128 coinIndex)\n internal\n returns (uint256 coinsRemoved)\n {\n // Withdraw Curve pool LP tokens from Convex pool\n _lpWithdraw(_lpTokens);\n\n // Convert Curve pool LP tokens to ETH value\n uint256 valueInEth = _lpTokens.mulTruncate(\n curvePool.get_virtual_price()\n );\n // Apply slippage to ETH value\n uint256 minAmount = valueInEth.mulTruncate(\n uint256(1e18) - MAX_SLIPPAGE\n );\n\n // Remove just the ETH from the Curve pool\n coinsRemoved = curvePool.remove_liquidity_one_coin(\n _lpTokens,\n int128(coinIndex),\n minAmount,\n address(this)\n );\n }\n\n /***************************************\n Assets and Rewards\n ****************************************/\n\n /**\n * @notice Collect accumulated CRV and CVX rewards and send to the Harvester.\n */\n function collectRewardTokens()\n external\n override\n onlyHarvester\n nonReentrant\n {\n // Collect CRV and CVX\n cvxRewardStaker.getReward();\n _collectRewardTokens();\n }\n\n function _lpWithdraw(uint256 _wethAmount) internal {\n // withdraw and unwrap with claim takes back the lpTokens\n // and also collects the rewards for deposit\n cvxRewardStaker.withdrawAndUnwrap(_wethAmount, true);\n }\n\n /**\n * @notice Get the total asset value held in the platform\n * @param _asset Address of the asset\n * @return balance Total value of the asset in the platform\n */\n function checkBalance(address _asset)\n public\n view\n override\n returns (uint256 balance)\n {\n require(_asset == address(weth), \"Unsupported asset\");\n\n // Eth balance needed here for the balance check that happens from vault during depositing.\n balance = address(this).balance;\n uint256 lpTokens = cvxRewardStaker.balanceOf(address(this));\n if (lpTokens > 0) {\n balance += (lpTokens * curvePool.get_virtual_price()) / 1e18;\n }\n }\n\n /**\n * @notice Returns bool indicating whether asset is supported by strategy\n * @param _asset Address of the asset\n */\n function supportsAsset(address _asset) public view override returns (bool) {\n return _asset == address(weth);\n }\n\n /***************************************\n Approvals\n ****************************************/\n\n /**\n * @notice Approve the spending of all assets by their corresponding pool tokens,\n * if for some reason is it necessary.\n */\n function safeApproveAllTokens()\n external\n override\n onlyGovernor\n nonReentrant\n {\n _approveBase();\n }\n\n /**\n * @notice Accept unwrapped WETH\n */\n receive() external payable {}\n\n /**\n * @dev Since we are unwrapping WETH before depositing it to Curve\n * there is no need to set an approval for WETH on the Curve\n * pool\n * @param _asset Address of the asset\n * @param _pToken Address of the Curve LP token\n */\n // solhint-disable-next-line no-unused-vars\n function _abstractSetPToken(address _asset, address _pToken)\n internal\n override\n {}\n\n function _approveBase() internal {\n // Approve Curve pool for OETH (required for adding liquidity)\n // No approval is needed for ETH\n // slither-disable-next-line unused-return\n oeth.approve(platformAddress, type(uint256).max);\n\n // Approve Convex deposit contract to transfer Curve pool LP tokens\n // This is needed for deposits if Curve pool LP tokens into the Convex rewards pool\n // slither-disable-next-line unused-return\n lpToken.approve(cvxDepositorAddress, type(uint256).max);\n }\n\n /**\n * @dev Returns the largest of two numbers int256 version\n */\n function _max(int256 a, int256 b) internal pure returns (int256) {\n return a >= b ? a : b;\n }\n}\n" + }, + "contracts/strategies/ConvexGeneralizedMetaStrategy.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @title Curve Convex Strategy\n * @notice Investment strategy for investing stablecoins via Curve 3Pool\n * @author Origin Protocol Inc\n */\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/utils/Strings.sol\";\n\nimport { IRewardStaking } from \"./IRewardStaking.sol\";\nimport { IConvexDeposits } from \"./IConvexDeposits.sol\";\nimport { ICurvePool } from \"./ICurvePool.sol\";\nimport { IERC20, InitializableAbstractStrategy } from \"./BaseCurveStrategy.sol\";\nimport { BaseConvexMetaStrategy } from \"./BaseConvexMetaStrategy.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\n\ncontract ConvexGeneralizedMetaStrategy is BaseConvexMetaStrategy {\n using StableMath for uint256;\n using SafeERC20 for IERC20;\n\n constructor(BaseStrategyConfig memory _stratConfig)\n InitializableAbstractStrategy(_stratConfig)\n {}\n\n /* Take 3pool LP and deposit it to metapool. Take the LP from metapool\n * and deposit them to Convex.\n */\n function _lpDepositAll() internal override {\n IERC20 threePoolLp = IERC20(pTokenAddress);\n ICurvePool curvePool = ICurvePool(platformAddress);\n\n uint256 threePoolLpBalance = threePoolLp.balanceOf(address(this));\n uint256 curve3PoolVirtualPrice = curvePool.get_virtual_price();\n uint256 threePoolLpDollarValue = threePoolLpBalance.mulTruncate(\n curve3PoolVirtualPrice\n );\n\n uint256[2] memory _amounts = [0, threePoolLpBalance];\n\n uint256 metapoolVirtualPrice = metapool.get_virtual_price();\n /**\n * First convert all the deposited tokens to dollar values,\n * then divide by virtual price to convert to metapool LP tokens\n * and apply the max slippage\n */\n uint256 minReceived = threePoolLpDollarValue\n .divPrecisely(metapoolVirtualPrice)\n .mulTruncate(uint256(1e18) - MAX_SLIPPAGE);\n\n uint256 metapoolLp = metapool.add_liquidity(_amounts, minReceived);\n\n bool success = IConvexDeposits(cvxDepositorAddress).deposit(\n cvxDepositorPTokenId,\n metapoolLp,\n true // Deposit with staking\n );\n\n require(success, \"Failed to deposit to Convex\");\n }\n\n /**\n * Withdraw the specified amount of tokens from the gauge. And use all the resulting tokens\n * to remove liquidity from metapool\n * @param num3CrvTokens Number of Convex 3pool LP tokens to withdraw from metapool\n */\n function _lpWithdraw(uint256 num3CrvTokens) internal override {\n uint256 gaugeTokens = IRewardStaking(cvxRewardStakerAddress).balanceOf(\n address(this)\n );\n\n uint256 requiredMetapoolLpTokens = _calcCurveMetaTokenAmount(\n crvCoinIndex,\n num3CrvTokens\n );\n\n require(\n requiredMetapoolLpTokens <= gaugeTokens,\n string(\n bytes.concat(\n bytes(\"Attempting to withdraw \"),\n bytes(Strings.toString(requiredMetapoolLpTokens)),\n bytes(\", metapoolLP but only \"),\n bytes(Strings.toString(gaugeTokens)),\n bytes(\" available.\")\n )\n )\n );\n\n // withdraw and unwrap with claim takes back the lpTokens and also collects the rewards for deposit\n IRewardStaking(cvxRewardStakerAddress).withdrawAndUnwrap(\n requiredMetapoolLpTokens,\n true\n );\n\n if (requiredMetapoolLpTokens > 0) {\n // slither-disable-next-line unused-return\n metapool.remove_liquidity_one_coin(\n requiredMetapoolLpTokens,\n int128(crvCoinIndex),\n num3CrvTokens\n );\n }\n }\n\n function _lpWithdrawAll() internal override {\n uint256 gaugeTokens = IRewardStaking(cvxRewardStakerAddress).balanceOf(\n address(this)\n );\n IRewardStaking(cvxRewardStakerAddress).withdrawAndUnwrap(\n gaugeTokens,\n true\n );\n\n if (gaugeTokens > 0) {\n uint256 burnDollarAmount = gaugeTokens.mulTruncate(\n metapool.get_virtual_price()\n );\n uint256 curve3PoolExpected = burnDollarAmount.divPrecisely(\n ICurvePool(platformAddress).get_virtual_price()\n );\n\n // Always withdraw all of the available metapool LP tokens (similar to how we always deposit all)\n // slither-disable-next-line unused-return\n metapool.remove_liquidity_one_coin(\n gaugeTokens,\n int128(crvCoinIndex),\n curve3PoolExpected -\n curve3PoolExpected.mulTruncate(maxWithdrawalSlippage)\n );\n }\n }\n}\n" + }, + "contracts/strategies/ConvexOUSDMetaStrategy.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @title Curve Convex Strategy\n * @notice Investment strategy for investing stablecoins via Curve 3Pool\n * @author Origin Protocol Inc\n */\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/utils/Strings.sol\";\nimport \"@openzeppelin/contracts/utils/math/Math.sol\";\n\nimport { IRewardStaking } from \"./IRewardStaking.sol\";\nimport { IConvexDeposits } from \"./IConvexDeposits.sol\";\nimport { ICurvePool } from \"./ICurvePool.sol\";\nimport { IERC20, InitializableAbstractStrategy } from \"./BaseCurveStrategy.sol\";\nimport { BaseConvexMetaStrategy } from \"./BaseConvexMetaStrategy.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\nimport { IVault } from \"../interfaces/IVault.sol\";\n\ncontract ConvexOUSDMetaStrategy is BaseConvexMetaStrategy {\n using StableMath for uint256;\n using SafeERC20 for IERC20;\n\n constructor(BaseStrategyConfig memory _stratConfig)\n InitializableAbstractStrategy(_stratConfig)\n {}\n\n /* Take 3pool LP and mint the corresponding amount of ousd. Deposit and stake that to\n * ousd Curve Metapool. Take the LP from metapool and deposit them to Convex.\n */\n function _lpDepositAll() internal override {\n ICurvePool curvePool = ICurvePool(platformAddress);\n\n uint256 threePoolLpBalance = IERC20(pTokenAddress).balanceOf(\n address(this)\n );\n uint256 curve3PoolVirtualPrice = curvePool.get_virtual_price();\n uint256 threePoolLpDollarValue = threePoolLpBalance.mulTruncate(\n curve3PoolVirtualPrice\n );\n\n // safe to cast since min value is at least 0\n uint256 ousdToAdd = uint256(\n _max(\n 0,\n int256(\n metapool.balances(crvCoinIndex).mulTruncate(\n curve3PoolVirtualPrice\n )\n ) -\n int256(metapool.balances(mainCoinIndex)) +\n int256(threePoolLpDollarValue)\n )\n );\n\n /* Add so much OUSD so that the pool ends up being balanced. And at minimum\n * add twice as much OUSD as 3poolLP and at maximum at twice as\n * much OUSD.\n */\n ousdToAdd = Math.max(ousdToAdd, threePoolLpDollarValue);\n ousdToAdd = Math.min(ousdToAdd, threePoolLpDollarValue * 2);\n\n /* Mint OUSD with a strategy that attempts to contribute to stability of OUSD metapool. Try\n * to mint so much OUSD that after deployment of liquidity pool ends up being balanced.\n *\n * To manage unpredictability minimal OUSD minted will always be at least equal or greater\n * to stablecoin(DAI, USDC, USDT) amount of 3CRVLP deployed. And never larger than twice the\n * stablecoin amount of 3CRVLP deployed even if it would have a further beneficial effect\n * on pool stability.\n */\n if (ousdToAdd > 0) {\n IVault(vaultAddress).mintForStrategy(ousdToAdd);\n }\n\n uint256[2] memory _amounts = [ousdToAdd, threePoolLpBalance];\n\n uint256 metapoolVirtualPrice = metapool.get_virtual_price();\n /**\n * First convert all the deposited tokens to dollar values,\n * then divide by virtual price to convert to metapool LP tokens\n * and apply the max slippage\n */\n uint256 minReceived = (ousdToAdd + threePoolLpDollarValue)\n .divPrecisely(metapoolVirtualPrice)\n .mulTruncate(uint256(1e18) - MAX_SLIPPAGE);\n\n uint256 metapoolLp = metapool.add_liquidity(_amounts, minReceived);\n\n bool success = IConvexDeposits(cvxDepositorAddress).deposit(\n cvxDepositorPTokenId,\n metapoolLp,\n true // Deposit with staking\n );\n\n require(success, \"Failed to deposit to Convex\");\n }\n\n /**\n * Withdraw the specified amount of tokens from the gauge. And use all the resulting tokens\n * to remove liquidity from metapool\n * @param num3CrvTokens Number of 3CRV tokens to withdraw from metapool\n */\n function _lpWithdraw(uint256 num3CrvTokens) internal override {\n ICurvePool curvePool = ICurvePool(platformAddress);\n /* The rate between coins in the metapool determines the rate at which metapool returns\n * tokens when doing balanced removal (remove_liquidity call). And by knowing how much 3crvLp\n * we want we can determine how much of OUSD we receive by removing liquidity.\n *\n * Because we are doing balanced removal we should be making profit when removing liquidity in a\n * pool tilted to either side.\n *\n * Important: A downside is that the Strategist / Governor needs to be\n * cognisant of not removing too much liquidity. And while the proposal to remove liquidity\n * is being voted on the pool tilt might change so much that the proposal that has been valid while\n * created is no longer valid.\n */\n\n uint256 crvPoolBalance = metapool.balances(crvCoinIndex);\n /* K is multiplied by 1e36 which is used for higher precision calculation of required\n * metapool LP tokens. Without it the end value can have rounding errors up to precision of\n * 10 digits. This way we move the decimal point by 36 places when doing the calculation\n * and again by 36 places when we are done with it.\n */\n uint256 k = (1e36 * metapoolLPToken.totalSupply()) / crvPoolBalance;\n // simplifying below to: `uint256 diff = (num3CrvTokens - 1) * k` causes loss of precision\n // prettier-ignore\n // slither-disable-next-line divide-before-multiply\n uint256 diff = crvPoolBalance * k -\n (crvPoolBalance - num3CrvTokens - 1) * k;\n uint256 lpToBurn = diff / 1e36;\n\n uint256 gaugeTokens = IRewardStaking(cvxRewardStakerAddress).balanceOf(\n address(this)\n );\n\n require(\n lpToBurn <= gaugeTokens,\n string(\n bytes.concat(\n bytes(\"Attempting to withdraw \"),\n bytes(Strings.toString(lpToBurn)),\n bytes(\", metapoolLP but only \"),\n bytes(Strings.toString(gaugeTokens)),\n bytes(\" available.\")\n )\n )\n );\n\n // withdraw and unwrap with claim takes back the lpTokens and also collects the rewards for deposit\n IRewardStaking(cvxRewardStakerAddress).withdrawAndUnwrap(\n lpToBurn,\n true\n );\n\n // calculate the min amount of OUSD expected for the specified amount of LP tokens\n uint256 minOUSDAmount = lpToBurn.mulTruncate(\n metapool.get_virtual_price()\n ) -\n num3CrvTokens.mulTruncate(curvePool.get_virtual_price()) -\n 1;\n\n // withdraw the liquidity from metapool\n uint256[2] memory _removedAmounts = metapool.remove_liquidity(\n lpToBurn,\n [minOUSDAmount, num3CrvTokens]\n );\n\n IVault(vaultAddress).burnForStrategy(_removedAmounts[mainCoinIndex]);\n }\n\n function _lpWithdrawAll() internal override {\n IERC20 metapoolErc20 = IERC20(address(metapool));\n uint256 gaugeTokens = IRewardStaking(cvxRewardStakerAddress).balanceOf(\n address(this)\n );\n IRewardStaking(cvxRewardStakerAddress).withdrawAndUnwrap(\n gaugeTokens,\n true\n );\n\n uint256[2] memory _minAmounts = [uint256(0), uint256(0)];\n uint256[2] memory _removedAmounts = metapool.remove_liquidity(\n metapoolErc20.balanceOf(address(this)),\n _minAmounts\n );\n\n IVault(vaultAddress).burnForStrategy(_removedAmounts[mainCoinIndex]);\n }\n}\n" + }, + "contracts/strategies/ConvexStrategy.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @title Curve Convex Strategy\n * @notice Investment strategy for investing stablecoins via Curve 3Pool\n * @author Origin Protocol Inc\n */\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nimport { ICurvePool } from \"./ICurvePool.sol\";\nimport { IRewardStaking } from \"./IRewardStaking.sol\";\nimport { IConvexDeposits } from \"./IConvexDeposits.sol\";\nimport { IERC20, BaseCurveStrategy, InitializableAbstractStrategy } from \"./BaseCurveStrategy.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\nimport { Helpers } from \"../utils/Helpers.sol\";\n\n/*\n * IMPORTANT(!) If ConvexStrategy needs to be re-deployed, it requires new\n * proxy contract with fresh storage slots. Changes in `BaseCurveStrategy`\n * storage slots would break existing implementation.\n *\n * Remove this notice if ConvexStrategy is re-deployed\n */\ncontract ConvexStrategy is BaseCurveStrategy {\n using StableMath for uint256;\n using SafeERC20 for IERC20;\n\n address internal cvxDepositorAddress;\n address internal cvxRewardStakerAddress;\n // slither-disable-next-line constable-states\n address private _deprecated_cvxRewardTokenAddress;\n uint256 internal cvxDepositorPTokenId;\n\n constructor(BaseStrategyConfig memory _stratConfig)\n InitializableAbstractStrategy(_stratConfig)\n {}\n\n /**\n * Initializer for setting up strategy internal state. This overrides the\n * InitializableAbstractStrategy initializer as Curve strategies don't fit\n * well within that abstraction.\n * @param _rewardTokenAddresses Address of CRV & CVX\n * @param _assets Addresses of supported assets. MUST be passed in the same\n * order as returned by coins on the pool contract, i.e.\n * DAI, USDC, USDT\n * @param _pTokens Platform Token corresponding addresses\n * @param _cvxDepositorAddress Address of the Convex depositor(AKA booster) for this pool\n * @param _cvxRewardStakerAddress Address of the CVX rewards staker\n * @param _cvxDepositorPTokenId Pid of the pool referred to by Depositor and staker\n */\n function initialize(\n address[] calldata _rewardTokenAddresses, // CRV + CVX\n address[] calldata _assets,\n address[] calldata _pTokens,\n address _cvxDepositorAddress,\n address _cvxRewardStakerAddress,\n uint256 _cvxDepositorPTokenId\n ) external onlyGovernor initializer {\n require(_assets.length == 3, \"Must have exactly three assets\");\n // Should be set prior to abstract initialize call otherwise\n // abstractSetPToken calls will fail\n cvxDepositorAddress = _cvxDepositorAddress;\n cvxRewardStakerAddress = _cvxRewardStakerAddress;\n cvxDepositorPTokenId = _cvxDepositorPTokenId;\n pTokenAddress = _pTokens[0];\n\n InitializableAbstractStrategy._initialize(\n _rewardTokenAddresses,\n _assets,\n _pTokens\n );\n _approveBase();\n }\n\n function _lpDepositAll() internal override {\n IERC20 pToken = IERC20(pTokenAddress);\n // Deposit with staking\n bool success = IConvexDeposits(cvxDepositorAddress).deposit(\n cvxDepositorPTokenId,\n pToken.balanceOf(address(this)),\n true\n );\n require(success, \"Failed to deposit to Convex\");\n }\n\n function _lpWithdraw(uint256 numCrvTokens) internal override {\n uint256 gaugePTokens = IRewardStaking(cvxRewardStakerAddress).balanceOf(\n address(this)\n );\n\n // Not enough in this contract or in the Gauge, can't proceed\n require(numCrvTokens > gaugePTokens, \"Insufficient 3CRV balance\");\n\n // withdraw and unwrap with claim takes back the lpTokens and also collects the rewards to this\n IRewardStaking(cvxRewardStakerAddress).withdrawAndUnwrap(\n numCrvTokens,\n true\n );\n }\n\n function _lpWithdrawAll() internal override {\n // withdraw and unwrap with claim takes back the lpTokens and also collects the rewards to this\n IRewardStaking(cvxRewardStakerAddress).withdrawAndUnwrap(\n IRewardStaking(cvxRewardStakerAddress).balanceOf(address(this)),\n true\n );\n }\n\n function _approveBase() internal override {\n IERC20 pToken = IERC20(pTokenAddress);\n // 3Pool for LP token (required for removing liquidity)\n pToken.safeApprove(platformAddress, 0);\n pToken.safeApprove(platformAddress, type(uint256).max);\n // Gauge for LP token\n pToken.safeApprove(cvxDepositorAddress, 0);\n pToken.safeApprove(cvxDepositorAddress, type(uint256).max);\n }\n\n /**\n * @dev Get the total asset value held in the platform\n * @param _asset Address of the asset\n * @return balance Total value of the asset in the platform\n */\n function checkBalance(address _asset)\n public\n view\n override\n returns (uint256 balance)\n {\n require(assetToPToken[_asset] != address(0), \"Unsupported asset\");\n // LP tokens in this contract. This should generally be nothing as we\n // should always stake the full balance in the Gauge, but include for\n // safety\n uint256 contractPTokens = IERC20(pTokenAddress).balanceOf(\n address(this)\n );\n uint256 gaugePTokens = IRewardStaking(cvxRewardStakerAddress).balanceOf(\n address(this)\n );\n uint256 totalPTokens = contractPTokens + gaugePTokens;\n\n ICurvePool curvePool = ICurvePool(platformAddress);\n if (totalPTokens > 0) {\n uint256 virtual_price = curvePool.get_virtual_price();\n uint256 value = (totalPTokens * virtual_price) / 1e18;\n uint256 assetDecimals = Helpers.getDecimals(_asset);\n balance = value.scaleBy(assetDecimals, 18) / 3;\n }\n }\n\n /**\n * @dev Collect accumulated CRV and CVX and send to Vault.\n */\n function collectRewardTokens()\n external\n override\n onlyHarvester\n nonReentrant\n {\n // Collect CRV and CVX\n IRewardStaking(cvxRewardStakerAddress).getReward();\n _collectRewardTokens();\n }\n}\n" + }, + "contracts/strategies/FluxStrategy.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @title Flux Strategy\n * @notice Investment strategy for investing stablecoins via Flux\n * @author Origin Protocol Inc\n */\n\nimport { CompoundStrategy } from \"./CompoundStrategy.sol\";\n\ncontract FluxStrategy is CompoundStrategy {\n constructor(BaseStrategyConfig memory _stratConfig)\n CompoundStrategy(_stratConfig)\n {}\n\n /**\n * @inheritdoc CompoundStrategy\n */\n function collectRewardTokens() external override {\n // Intentionally not adding any modifiers to not increase contract size\n // Flux strategy has no reward tokens\n }\n}\n" + }, + "contracts/strategies/FraxETHStrategy.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @title OETH FraxETH Strategy\n * @notice Investment WETH and FraxETH into the sFraxETH staking contract\n * @author Origin Protocol Inc\n */\nimport { IERC4626 } from \"../../lib/openzeppelin/interfaces/IERC4626.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { IWETH9 } from \"../interfaces/IWETH9.sol\";\nimport { IFraxETHMinter } from \"../interfaces/IFraxETHMinter.sol\";\nimport { Generalized4626Strategy, IERC20, InitializableAbstractStrategy } from \"./Generalized4626Strategy.sol\";\n\ncontract FraxETHStrategy is Generalized4626Strategy {\n using SafeERC20 for IERC20;\n\n address public constant weth = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;\n\n IFraxETHMinter public constant fraxETHMinter =\n IFraxETHMinter(0xbAFA44EFE7901E04E39Dad13167D089C559c1138);\n\n /**\n * @param _baseConfig Base strategy config with platformAddress (sfrxETH) and vaultAddress (OETHVaultProxy)\n * @param _assetToken Address of the ERC-4626 asset token (frxETH)\n */\n constructor(BaseStrategyConfig memory _baseConfig, address _assetToken)\n Generalized4626Strategy(_baseConfig, _assetToken)\n {}\n\n function initialize() external override onlyGovernor initializer {\n address[] memory rewardTokens = new address[](0);\n address[] memory assets = new address[](2);\n address[] memory pTokens = new address[](2);\n\n assets[0] = address(assetToken);\n assets[1] = address(weth);\n pTokens[0] = address(platformAddress);\n pTokens[1] = address(platformAddress);\n\n InitializableAbstractStrategy._initialize(\n rewardTokens,\n assets,\n pTokens\n );\n }\n\n function _deposit(address _asset, uint256 _amount) internal override {\n require(_amount > 0, \"Must deposit something\");\n\n if (_asset == weth) {\n // Unwrap WETH\n IWETH9(weth).withdraw(_amount);\n\n // Deposit ETH for frxETH and stake it\n // slither-disable-next-line unused-return\n fraxETHMinter.submitAndDeposit{ value: _amount }(address(this));\n } else if (_asset == address(assetToken)) {\n // Stake frxETH\n // slither-disable-next-line unused-return\n IERC4626(platformAddress).deposit(_amount, address(this));\n } else {\n revert(\"Unexpected asset address\");\n }\n\n emit Deposit(_asset, address(shareToken), _amount);\n }\n\n /**\n * @dev Retuns bool indicating whether asset is supported by strategy\n * @param _asset Address of the asset\n */\n function supportsAsset(address _asset) public view override returns (bool) {\n return _asset == address(assetToken) || _asset == weth;\n }\n\n /**\n * @dev Get the total asset value held in the platform\n * @param _asset Address of the asset\n * @return balance Total value of the asset in the platform\n */\n function checkBalance(address _asset)\n external\n view\n virtual\n override\n returns (uint256 balance)\n {\n if (_asset == weth) {\n // For WETH, it's always 0\n return 0;\n }\n\n // If it's not WETH, it has to be frxETH\n require(_asset == address(assetToken), \"Unexpected asset address\");\n\n /* We are intentionally not counting the amount of assetToken parked on the\n * contract toward the checkBalance. The deposit and withdraw functions\n * should not result in assetToken being unused and owned by this strategy\n * contract.\n */\n return IERC4626(platformAddress).maxWithdraw(address(this));\n }\n\n /**\n * @dev Deposit the entire balance of assetToken to gain shareToken\n */\n function depositAll() external virtual override onlyVault nonReentrant {\n uint256 balance = assetToken.balanceOf(address(this));\n if (balance > 0) {\n _deposit(address(assetToken), balance);\n }\n\n uint256 wethBalance = IWETH9(weth).balanceOf(address(this));\n if (wethBalance > 0) {\n _deposit(weth, wethBalance);\n }\n }\n\n /**\n * @dev Accept ETH\n */\n receive() external payable {}\n}\n" + }, + "contracts/strategies/FrxEthRedeemStrategy.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { IERC721Receiver } from \"@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol\";\n\nimport { IERC20, InitializableAbstractStrategy } from \"../utils/InitializableAbstractStrategy.sol\";\nimport { IWETH9 } from \"../interfaces/IWETH9.sol\";\nimport { IVault } from \"../interfaces/IVault.sol\";\n\ninterface IFraxEtherRedemptionQueue {\n function burnRedemptionTicketNft(uint256 _nftId, address payable _recipient)\n external;\n\n function enterRedemptionQueue(address _recipient, uint120 _amountToRedeem)\n external\n returns (uint256 _nftId);\n}\n\n/**\n * @title Frax ETH Redeem Strategy\n * @notice This strategy redeems Frax ETH for ETH via the Frax Eth Redemption Queue contract\n * @author Origin Protocol Inc\n */\ncontract FrxEthRedeemStrategy is InitializableAbstractStrategy {\n IWETH9 private constant weth =\n IWETH9(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);\n IERC20 private constant frxETH =\n IERC20(0x5E8422345238F34275888049021821E8E08CAa1f);\n IFraxEtherRedemptionQueue private constant redemptionQueue =\n IFraxEtherRedemptionQueue(0x82bA8da44Cd5261762e629dd5c605b17715727bd);\n uint256 public constant maxRedeemTicket = 250e18;\n uint256 public outstandingRedeems;\n\n event RedeemNFTMinted(uint256 _nftId, uint256 _amount);\n event RedeemNFTBurned(uint256 _nftId);\n\n constructor(BaseStrategyConfig memory _stratConfig)\n InitializableAbstractStrategy(_stratConfig)\n {\n require(maxRedeemTicket < type(uint120).max);\n }\n\n /**\n * @notice initialize function, to set up initial internal state\n * @param _rewardTokenAddresses Address of reward token for platform\n * @param _assets Addresses of initial supported assets\n * @param _pTokens Platform Token corresponding addresses\n */\n function initialize(\n address[] memory _rewardTokenAddresses,\n address[] memory _assets,\n address[] memory _pTokens\n ) external onlyGovernor initializer {\n InitializableAbstractStrategy._initialize(\n _rewardTokenAddresses,\n _assets,\n _pTokens\n );\n safeApproveAllTokens();\n }\n\n /**\n * @notice deposit() function not used for this strategy. Use depositAll() instead.\n */\n function deposit(address, uint256) public override onlyVault nonReentrant {\n // This method no longer used by the VaultAdmin, and we don't want it\n // to be used by VaultCore.\n require(false, \"use depositAll() instead\");\n }\n\n /**\n * @notice Takes all given frxETH and creates new redeem tickets\n */\n function depositAll() external override onlyVault nonReentrant {\n uint256 frxETHStart = frxETH.balanceOf(address(this));\n require(frxETHStart > 0, \"No frxETH to redeem\");\n uint256 frxETHRemaining = frxETHStart;\n\n while (frxETHRemaining > 0) {\n uint256 amount = frxETHRemaining > maxRedeemTicket\n ? maxRedeemTicket\n : frxETHRemaining;\n uint256 nftId = redemptionQueue.enterRedemptionQueue(\n address(this),\n uint120(amount)\n );\n frxETHRemaining -= amount;\n emit RedeemNFTMinted(nftId, amount);\n }\n\n require(\n frxETH.balanceOf(address(this)) == 0,\n \"Not all FraxEth sent to redemption queue\"\n );\n outstandingRedeems += frxETHStart; // Single set for gas reasons\n\n // This strategy claims to support WETH, so it is posible for\n // the vault to transfer WETH to it. This returns any deposited WETH\n // to the vault so that it is not lost for balance tracking purposes.\n uint256 wethBalance = weth.balanceOf(address(this));\n if (wethBalance > 0) {\n // slither-disable-next-line unchecked-transfer\n weth.transfer(vaultAddress, wethBalance);\n }\n\n emit Deposit(address(frxETH), address(redemptionQueue), frxETHStart);\n }\n\n /**\n * @notice Withdraw an asset from the underlying platform\n * @param _recipient Address to receive withdrawn assets\n * @param _asset Address of the asset to withdraw\n * @param _amount Amount of assets to withdraw\n */\n function withdraw(\n // solhint-disable-next-line no-unused-vars\n address _recipient,\n // solhint-disable-next-line no-unused-vars\n address _asset,\n // solhint-disable-next-line no-unused-vars\n uint256 _amount\n ) external override onlyVault nonReentrant {\n // Does nothing - all redeems need to be called manually by the\n // strategist via redeemTickets\n require(false, \"use redeemTickets() instead\");\n }\n\n /**\n * @notice Redeem specific tickets from the Queue.\n * Called by the strategist.\n * @param _nftIds Array of NFT IDs to redeem\n */\n function redeemTickets(uint256[] memory _nftIds, uint256 expectedAmount)\n external\n nonReentrant\n {\n require(\n msg.sender == IVault(vaultAddress).strategistAddr(),\n \"Caller is not the Strategist\"\n );\n uint256 startingBalance = payable(address(this)).balance;\n for (uint256 i = 0; i < _nftIds.length; i++) {\n uint256 nftId = _nftIds[i];\n redemptionQueue.burnRedemptionTicketNft(\n nftId,\n payable(address(this))\n );\n emit RedeemNFTBurned(nftId);\n }\n\n uint256 currentBalance = payable(address(this)).balance;\n uint256 redeemedAmount = currentBalance - startingBalance;\n require(\n expectedAmount == redeemedAmount,\n \"Redeemed amount does not match expected amount\"\n );\n outstandingRedeems -= redeemedAmount;\n weth.deposit{ value: currentBalance }();\n // slither-disable-next-line unchecked-transfer\n weth.transfer(vaultAddress, currentBalance);\n emit Withdrawal(\n address(weth),\n address(redemptionQueue),\n currentBalance\n );\n }\n\n function _abstractSetPToken(address, address) internal override {\n revert(\"No pTokens are used\");\n }\n\n /**\n * @notice Withdraw all assets from this strategy, and transfer to the Vault.\n * In correct operation, this strategy should never hold any assets.\n */\n function withdrawAll() external override onlyVaultOrGovernor nonReentrant {\n if (payable(address(this)).balance > 0) {\n weth.deposit{ value: payable(address(this)).balance }();\n }\n uint256 wethBalance = weth.balanceOf(address(this));\n if (wethBalance > 0) {\n // slither-disable-next-line unchecked-transfer\n weth.transfer(vaultAddress, wethBalance);\n emit Withdrawal(address(weth), address(0), wethBalance);\n }\n uint256 fraxEthBalance = frxETH.balanceOf(address(this));\n if (fraxEthBalance > 0) {\n // slither-disable-next-line unchecked-transfer\n frxETH.transfer(vaultAddress, fraxEthBalance);\n emit Withdrawal(address(frxETH), address(0), fraxEthBalance);\n }\n }\n\n /**\n * @notice Returns the amount of queued FraxEth that will be returned as WETH.\n * We return this as a WETH asset, since that is what it will eventually be returned as.\n * We only return the outstandingRedeems, because the contract itself should never hold any funds.\n * @param _asset Address of the asset\n * @return balance Total value of the asset in the platform\n */\n function checkBalance(address _asset)\n external\n view\n override\n returns (uint256 balance)\n {\n if (_asset == address(weth)) {\n return outstandingRedeems;\n } else if (_asset == address(frxETH)) {\n return 0;\n } else {\n revert(\"Unexpected asset address\");\n }\n }\n\n /**\n * @notice Approve the spending of all assets by their corresponding cToken,\n * if for some reason is it necessary.\n */\n function safeApproveAllTokens() public override {\n // slither-disable-next-line unused-return\n frxETH.approve(address(redemptionQueue), type(uint256).max);\n }\n\n /**\n * @notice Check if an asset is supported.\n * @param _asset Address of the asset\n * @return bool Whether asset is supported\n */\n function supportsAsset(address _asset) public pure override returns (bool) {\n // frxETH can be deposited by the vault and balances are reported in weth\n return _asset == address(frxETH) || _asset == address(weth);\n }\n\n function onERC721Received(\n // solhint-disable-next-line no-unused-vars\n address operator,\n // solhint-disable-next-line no-unused-vars\n address from,\n // solhint-disable-next-line no-unused-vars\n uint256 tokenId,\n // solhint-disable-next-line no-unused-vars\n bytes calldata data\n ) external returns (bytes4) {\n return IERC721Receiver.onERC721Received.selector;\n }\n\n receive() external payable {}\n}\n" + }, + "contracts/strategies/Generalized4626Strategy.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @title Generalized 4626 Strategy\n * @notice Investment strategy for ERC-4626 Tokenized Vaults\n * @author Origin Protocol Inc\n */\nimport { IERC4626 } from \"../../lib/openzeppelin/interfaces/IERC4626.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { IERC20, InitializableAbstractStrategy } from \"../utils/InitializableAbstractStrategy.sol\";\n\ncontract Generalized4626Strategy is InitializableAbstractStrategy {\n using SafeERC20 for IERC20;\n\n /// @dev Replaced with an immutable variable\n // slither-disable-next-line constable-states\n address private _deprecate_shareToken;\n /// @dev Replaced with an immutable variable\n // slither-disable-next-line constable-states\n address private _deprecate_assetToken;\n\n IERC20 public immutable shareToken;\n IERC20 public immutable assetToken;\n\n // For future use\n uint256[50] private __gap;\n\n /**\n * @param _baseConfig Base strategy config with platformAddress (ERC-4626 Vault contract), eg sfrxETH or sDAI,\n * and vaultAddress (OToken Vault contract), eg VaultProxy or OETHVaultProxy\n * @param _assetToken Address of the ERC-4626 asset token. eg frxETH or DAI\n */\n constructor(BaseStrategyConfig memory _baseConfig, address _assetToken)\n InitializableAbstractStrategy(_baseConfig)\n {\n shareToken = IERC20(_baseConfig.platformAddress);\n assetToken = IERC20(_assetToken);\n }\n\n function initialize() external virtual onlyGovernor initializer {\n address[] memory rewardTokens = new address[](0);\n address[] memory assets = new address[](1);\n address[] memory pTokens = new address[](1);\n\n assets[0] = address(assetToken);\n pTokens[0] = address(platformAddress);\n\n InitializableAbstractStrategy._initialize(\n rewardTokens,\n assets,\n pTokens\n );\n }\n\n /**\n * @dev Deposit assets by converting them to shares\n * @param _asset Address of asset to deposit\n * @param _amount Amount of asset to deposit\n */\n function deposit(address _asset, uint256 _amount)\n external\n override\n onlyVault\n nonReentrant\n {\n _deposit(_asset, _amount);\n }\n\n /**\n * @dev Deposit assets by converting them to shares\n * @param _asset Address of asset to deposit\n * @param _amount Amount of asset to deposit\n */\n function _deposit(address _asset, uint256 _amount) internal virtual {\n require(_amount > 0, \"Must deposit something\");\n require(_asset == address(assetToken), \"Unexpected asset address\");\n\n // slither-disable-next-line unused-return\n IERC4626(platformAddress).deposit(_amount, address(this));\n emit Deposit(_asset, address(shareToken), _amount);\n }\n\n /**\n * @dev Deposit the entire balance of assetToken to gain shareToken\n */\n function depositAll() external virtual override onlyVault nonReentrant {\n uint256 balance = assetToken.balanceOf(address(this));\n if (balance > 0) {\n _deposit(address(assetToken), balance);\n }\n }\n\n /**\n * @dev Withdraw asset by burning shares\n * @param _recipient Address to receive withdrawn asset\n * @param _asset Address of asset to withdraw\n * @param _amount Amount of asset to withdraw\n */\n function withdraw(\n address _recipient,\n address _asset,\n uint256 _amount\n ) external virtual override onlyVault nonReentrant {\n require(_amount > 0, \"Must withdraw something\");\n require(_recipient != address(0), \"Must specify recipient\");\n require(_asset == address(assetToken), \"Unexpected asset address\");\n\n // slither-disable-next-line unused-return\n IERC4626(platformAddress).withdraw(_amount, _recipient, address(this));\n emit Withdrawal(_asset, address(shareToken), _amount);\n }\n\n /**\n * @dev Internal method to respond to the addition of new asset / share tokens\n */\n function _abstractSetPToken(address, address) internal virtual override {\n _approveBase();\n }\n\n /**\n * @dev Remove all assets from platform and send them to Vault contract.\n */\n function withdrawAll()\n external\n virtual\n override\n onlyVaultOrGovernor\n nonReentrant\n {\n uint256 shareBalance = shareToken.balanceOf(address(this));\n uint256 assetAmount = 0;\n if (shareBalance > 0) {\n assetAmount = IERC4626(platformAddress).redeem(\n shareBalance,\n vaultAddress,\n address(this)\n );\n emit Withdrawal(\n address(assetToken),\n address(shareToken),\n assetAmount\n );\n }\n }\n\n /**\n * @dev Get the total asset value held in the platform\n * @param _asset Address of the asset\n * @return balance Total value of the asset in the platform\n */\n function checkBalance(address _asset)\n external\n view\n virtual\n override\n returns (uint256 balance)\n {\n require(_asset == address(assetToken), \"Unexpected asset address\");\n /* We are intentionally not counting the amount of assetToken parked on the\n * contract toward the checkBalance. The deposit and withdraw functions\n * should not result in assetToken being unused and owned by this strategy\n * contract.\n */\n return IERC4626(platformAddress).maxWithdraw(address(this));\n }\n\n /**\n * @notice Governor approves the the ERC-4626 Tokenized Vault to spend the asset.\n */\n function safeApproveAllTokens() external override onlyGovernor {\n _approveBase();\n }\n\n function _approveBase() internal virtual {\n // Approval the asset to be trasferred to the ERC-4626 Tokenized Vualt.\n // Used by the ERC-4626 deposit() and mint() functions\n // slither-disable-next-line unused-return\n assetToken.approve(platformAddress, type(uint256).max);\n }\n\n /**\n * @dev Retuns bool indicating whether asset is supported by strategy\n * @param _asset Address of the asset\n */\n function supportsAsset(address _asset)\n public\n view\n virtual\n override\n returns (bool)\n {\n return _asset == address(assetToken);\n }\n\n /**\n * @notice is not supported for this strategy as the asset and\n * ERC-4626 Tokenized Vault are set at deploy time.\n * @dev If the ERC-4626 Tokenized Vault needed to be changed, a new\n * contract would need to be deployed and the proxy updated.\n */\n function setPTokenAddress(address, address) external override onlyGovernor {\n revert(\"unsupported function\");\n }\n\n /**\n * @notice is not supported for this strategy as the asset and\n * ERC-4626 Tokenized Vault are set at deploy time.\n * @dev If the ERC-4626 Tokenized Vault needed to be changed, a new\n * contract would need to be deployed and the proxy updated.\n */\n function removePToken(uint256) external override onlyGovernor {\n revert(\"unsupported function\");\n }\n}\n" + }, + "contracts/strategies/IAave.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface for Aaves Lending Pool\n * Documentation: https://developers.aave.com/#lendingpool\n */\ninterface IAaveLendingPool {\n /**\n * @dev Deposits an `amount` of underlying asset into the reserve, receiving in return overlying aTokens.\n * - E.g. User deposits 100 USDC and gets in return 100 aUSDC\n * @param asset The address of the underlying asset to deposit\n * @param amount The amount to be deposited\n * @param onBehalfOf The address that will receive the aTokens, same as msg.sender if the user\n * wants to receive them on his own wallet, or a different address if the beneficiary of aTokens\n * is a different wallet\n * @param referralCode Code used to register the integrator originating the operation, for potential rewards.\n * 0 if the action is executed directly by the user, without any middle-man\n **/\n function deposit(\n address asset,\n uint256 amount,\n address onBehalfOf,\n uint16 referralCode\n ) external;\n\n /**\n * @dev Withdraws an `amount` of underlying asset from the reserve, burning the equivalent aTokens owned\n * E.g. User has 100 aUSDC, calls withdraw() and receives 100 USDC, burning the 100 aUSDC\n * @param asset The address of the underlying asset to withdraw\n * @param amount The underlying amount to be withdrawn\n * - Send the value type(uint256).max in order to withdraw the whole aToken balance\n * @param to Address that will receive the underlying, same as msg.sender if the user\n * wants to receive it on his own wallet, or a different address if the beneficiary is a\n * different wallet\n * @return The final amount withdrawn\n **/\n function withdraw(\n address asset,\n uint256 amount,\n address to\n ) external returns (uint256);\n}\n\n/**\n * @dev Interface for Aaves Lending Pool\n * Documentation: https://developers.aave.com/#lendingpooladdressesprovider\n */\ninterface ILendingPoolAddressesProvider {\n /**\n * @notice Get the current address for Aave LendingPool\n * @dev Lending pool is the core contract on which to call deposit\n */\n function getLendingPool() external view returns (address);\n}\n" + }, + "contracts/strategies/IAaveIncentivesController.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IAaveIncentivesController {\n event RewardsAccrued(address indexed user, uint256 amount);\n\n event RewardsClaimed(\n address indexed user,\n address indexed to,\n uint256 amount\n );\n\n event RewardsClaimed(\n address indexed user,\n address indexed to,\n address indexed claimer,\n uint256 amount\n );\n\n event ClaimerSet(address indexed user, address indexed claimer);\n\n /*\n * @dev Returns the configuration of the distribution for a certain asset\n * @param asset The address of the reference asset of the distribution\n * @return The asset index, the emission per second and the last updated timestamp\n **/\n function getAssetData(address asset)\n external\n view\n returns (\n uint256,\n uint256,\n uint256\n );\n\n /**\n * @dev Whitelists an address to claim the rewards on behalf of another address\n * @param user The address of the user\n * @param claimer The address of the claimer\n */\n function setClaimer(address user, address claimer) external;\n\n /**\n * @dev Returns the whitelisted claimer for a certain address (0x0 if not set)\n * @param user The address of the user\n * @return The claimer address\n */\n function getClaimer(address user) external view returns (address);\n\n /**\n * @dev Configure assets for a certain rewards emission\n * @param assets The assets to incentivize\n * @param emissionsPerSecond The emission for each asset\n */\n function configureAssets(\n address[] calldata assets,\n uint256[] calldata emissionsPerSecond\n ) external;\n\n /**\n * @dev Called by the corresponding asset on any update that affects the rewards distribution\n * @param asset The address of the user\n * @param userBalance The balance of the user of the asset in the lending pool\n * @param totalSupply The total supply of the asset in the lending pool\n **/\n function handleAction(\n address asset,\n uint256 userBalance,\n uint256 totalSupply\n ) external;\n\n /**\n * @dev Returns the total of rewards of an user, already accrued + not yet accrued\n * @param user The address of the user\n * @return The rewards\n **/\n function getRewardsBalance(address[] calldata assets, address user)\n external\n view\n returns (uint256);\n\n /**\n * @dev Claims reward for an user, on all the assets of the lending pool,\n * accumulating the pending rewards\n * @param amount Amount of rewards to claim\n * @param to Address that will be receiving the rewards\n * @return Rewards claimed\n **/\n function claimRewards(\n address[] calldata assets,\n uint256 amount,\n address to\n ) external returns (uint256);\n\n /**\n * @dev Claims reward for an user on behalf, on all the assets of the\n * lending pool, accumulating the pending rewards. The caller must\n * be whitelisted via \"allowClaimOnBehalf\" function by the RewardsAdmin role manager\n * @param amount Amount of rewards to claim\n * @param user Address to check and claim rewards\n * @param to Address that will be receiving the rewards\n * @return Rewards claimed\n **/\n function claimRewardsOnBehalf(\n address[] calldata assets,\n uint256 amount,\n address user,\n address to\n ) external returns (uint256);\n\n /**\n * @dev returns the unclaimed rewards of the user\n * @param user the address of the user\n * @return the unclaimed user rewards\n */\n function getUserUnclaimedRewards(address user)\n external\n view\n returns (uint256);\n\n /**\n * @dev returns the unclaimed rewards of the user\n * @param user the address of the user\n * @param asset The asset to incentivize\n * @return the user index for the asset\n */\n function getUserAssetData(address user, address asset)\n external\n view\n returns (uint256);\n\n /**\n * @dev for backward compatibility with previous implementation of the Incentives controller\n */\n function REWARD_TOKEN() external view returns (address);\n\n /**\n * @dev for backward compatibility with previous implementation of the Incentives controller\n */\n function PRECISION() external view returns (uint8);\n\n /**\n * @dev Gets the distribution end timestamp of the emissions\n */\n function DISTRIBUTION_END() external view returns (uint256);\n}\n" + }, + "contracts/strategies/IAaveStakeToken.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IAaveStakedToken {\n function COOLDOWN_SECONDS() external returns (uint256);\n\n function UNSTAKE_WINDOW() external returns (uint256);\n\n function balanceOf(address addr) external returns (uint256);\n\n function redeem(address to, uint256 amount) external;\n\n function stakersCooldowns(address addr) external returns (uint256);\n\n function cooldown() external;\n}\n" + }, + "contracts/strategies/ICompound.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @dev Compound C Token interface\n * Documentation: https://compound.finance/developers/ctokens\n */\ninterface ICERC20 {\n /**\n * @notice The mint function transfers an asset into the protocol, which begins accumulating\n * interest based on the current Supply Rate for the asset. The user receives a quantity of\n * cTokens equal to the underlying tokens supplied, divided by the current Exchange Rate.\n * @param mintAmount The amount of the asset to be supplied, in units of the underlying asset.\n * @return 0 on success, otherwise an Error codes\n */\n function mint(uint256 mintAmount) external returns (uint256);\n\n /**\n * @notice Sender redeems cTokens in exchange for the underlying asset\n * @dev Accrues interest whether or not the operation succeeds, unless reverted\n * @param redeemTokens The number of cTokens to redeem into underlying\n * @return uint 0=success, otherwise an error code.\n */\n function redeem(uint256 redeemTokens) external returns (uint256);\n\n /**\n * @notice The redeem underlying function converts cTokens into a specified quantity of the underlying\n * asset, and returns them to the user. The amount of cTokens redeemed is equal to the quantity of\n * underlying tokens received, divided by the current Exchange Rate. The amount redeemed must be less\n * than the user's Account Liquidity and the market's available liquidity.\n * @param redeemAmount The amount of underlying to be redeemed.\n * @return 0 on success, otherwise an error code.\n */\n function redeemUnderlying(uint256 redeemAmount) external returns (uint256);\n\n /**\n * @notice The user's underlying balance, representing their assets in the protocol, is equal to\n * the user's cToken balance multiplied by the Exchange Rate.\n * @param owner The account to get the underlying balance of.\n * @return The amount of underlying currently owned by the account.\n */\n function balanceOfUnderlying(address owner) external returns (uint256);\n\n /**\n * @notice Calculates the exchange rate from the underlying to the CToken\n * @dev This function does not accrue interest before calculating the exchange rate\n * @return Calculated exchange rate scaled by 1e18\n */\n function exchangeRateStored() external view returns (uint256);\n\n /**\n * @notice Get the token balance of the `owner`\n * @param owner The address of the account to query\n * @return The number of tokens owned by `owner`\n */\n function balanceOf(address owner) external view returns (uint256);\n\n /**\n * @notice Get the supply rate per block for supplying the token to Compound.\n */\n function supplyRatePerBlock() external view returns (uint256);\n\n /**\n * @notice Address of the Compound Comptroller.\n */\n function comptroller() external view returns (address);\n}\n" + }, + "contracts/strategies/IConvexDeposits.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IConvexDeposits {\n function deposit(\n uint256 _pid,\n uint256 _amount,\n bool _stake\n ) external returns (bool);\n\n function deposit(\n uint256 _amount,\n bool _lock,\n address _stakeAddress\n ) external;\n}\n" + }, + "contracts/strategies/ICRVMinter.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface ICRVMinter {\n function mint(address gaugeAddress) external;\n}\n" + }, + "contracts/strategies/ICurveETHPoolV1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface ICurveETHPoolV1 {\n event AddLiquidity(\n address indexed provider,\n uint256[2] token_amounts,\n uint256[2] fees,\n uint256 invariant,\n uint256 token_supply\n );\n event ApplyNewFee(uint256 fee);\n event Approval(\n address indexed owner,\n address indexed spender,\n uint256 value\n );\n event CommitNewFee(uint256 new_fee);\n event RampA(\n uint256 old_A,\n uint256 new_A,\n uint256 initial_time,\n uint256 future_time\n );\n event RemoveLiquidity(\n address indexed provider,\n uint256[2] token_amounts,\n uint256[2] fees,\n uint256 token_supply\n );\n event RemoveLiquidityImbalance(\n address indexed provider,\n uint256[2] token_amounts,\n uint256[2] fees,\n uint256 invariant,\n uint256 token_supply\n );\n event RemoveLiquidityOne(\n address indexed provider,\n uint256 token_amount,\n uint256 coin_amount,\n uint256 token_supply\n );\n event StopRampA(uint256 A, uint256 t);\n event TokenExchange(\n address indexed buyer,\n int128 sold_id,\n uint256 tokens_sold,\n int128 bought_id,\n uint256 tokens_bought\n );\n event Transfer(\n address indexed sender,\n address indexed receiver,\n uint256 value\n );\n\n function A() external view returns (uint256);\n\n function A_precise() external view returns (uint256);\n\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n\n function add_liquidity(uint256[2] memory _amounts, uint256 _min_mint_amount)\n external\n payable\n returns (uint256);\n\n function add_liquidity(\n uint256[2] memory _amounts,\n uint256 _min_mint_amount,\n address _receiver\n ) external payable returns (uint256);\n\n function admin_action_deadline() external view returns (uint256);\n\n function admin_balances(uint256 i) external view returns (uint256);\n\n function admin_fee() external view returns (uint256);\n\n function allowance(address arg0, address arg1)\n external\n view\n returns (uint256);\n\n function apply_new_fee() external;\n\n function approve(address _spender, uint256 _value) external returns (bool);\n\n function balanceOf(address arg0) external view returns (uint256);\n\n function balances(uint256 arg0) external view returns (uint256);\n\n function calc_token_amount(uint256[2] memory _amounts, bool _is_deposit)\n external\n view\n returns (uint256);\n\n function calc_withdraw_one_coin(uint256 _burn_amount, int128 i)\n external\n view\n returns (uint256);\n\n function coins(uint256 arg0) external view returns (address);\n\n function commit_new_fee(uint256 _new_fee) external;\n\n function decimals() external view returns (uint256);\n\n function ema_price() external view returns (uint256);\n\n function exchange(\n int128 i,\n int128 j,\n uint256 _dx,\n uint256 _min_dy\n ) external payable returns (uint256);\n\n function exchange(\n int128 i,\n int128 j,\n uint256 _dx,\n uint256 _min_dy,\n address _receiver\n ) external payable returns (uint256);\n\n function fee() external view returns (uint256);\n\n function future_A() external view returns (uint256);\n\n function future_A_time() external view returns (uint256);\n\n function future_fee() external view returns (uint256);\n\n function get_balances() external view returns (uint256[2] memory);\n\n function get_dy(\n int128 i,\n int128 j,\n uint256 dx\n ) external view returns (uint256);\n\n function get_p() external view returns (uint256);\n\n function get_virtual_price() external view returns (uint256);\n\n function initial_A() external view returns (uint256);\n\n function initial_A_time() external view returns (uint256);\n\n function initialize(\n string memory _name,\n string memory _symbol,\n address[4] memory _coins,\n uint256[4] memory _rate_multipliers,\n uint256 _A,\n uint256 _fee\n ) external;\n\n function last_price() external view returns (uint256);\n\n function ma_exp_time() external view returns (uint256);\n\n function ma_last_time() external view returns (uint256);\n\n function name() external view returns (string memory);\n\n function nonces(address arg0) external view returns (uint256);\n\n function permit(\n address _owner,\n address _spender,\n uint256 _value,\n uint256 _deadline,\n uint8 _v,\n bytes32 _r,\n bytes32 _s\n ) external returns (bool);\n\n function price_oracle() external view returns (uint256);\n\n function ramp_A(uint256 _future_A, uint256 _future_time) external;\n\n function remove_liquidity(\n uint256 _burn_amount,\n uint256[2] memory _min_amounts\n ) external returns (uint256[2] memory);\n\n function remove_liquidity(\n uint256 _burn_amount,\n uint256[2] memory _min_amounts,\n address _receiver\n ) external returns (uint256[2] memory);\n\n function remove_liquidity_imbalance(\n uint256[2] memory _amounts,\n uint256 _max_burn_amount\n ) external returns (uint256);\n\n function remove_liquidity_imbalance(\n uint256[2] memory _amounts,\n uint256 _max_burn_amount,\n address _receiver\n ) external returns (uint256);\n\n function remove_liquidity_one_coin(\n uint256 _burn_amount,\n int128 i,\n uint256 _min_received\n ) external returns (uint256);\n\n function remove_liquidity_one_coin(\n uint256 _burn_amount,\n int128 i,\n uint256 _min_received,\n address _receiver\n ) external returns (uint256);\n\n function set_ma_exp_time(uint256 _ma_exp_time) external;\n\n function stop_ramp_A() external;\n\n function symbol() external view returns (string memory);\n\n function totalSupply() external view returns (uint256);\n\n function transfer(address _to, uint256 _value) external returns (bool);\n\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n ) external returns (bool);\n\n function version() external view returns (string memory);\n\n function withdraw_admin_fees() external;\n}\n" + }, + "contracts/strategies/ICurveGauge.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface ICurveGauge {\n function balanceOf(address account) external view returns (uint256);\n\n function deposit(uint256 value, address account) external;\n\n function withdraw(uint256 value) external;\n}\n" + }, + "contracts/strategies/ICurveMetaPool.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\ninterface ICurveMetaPool {\n function add_liquidity(uint256[2] calldata amounts, uint256 min_mint_amount)\n external\n returns (uint256);\n\n function get_virtual_price() external view returns (uint256);\n\n function remove_liquidity(uint256 _amount, uint256[2] calldata min_amounts)\n external\n returns (uint256[2] calldata);\n\n function remove_liquidity_one_coin(\n uint256 _token_amount,\n int128 i,\n uint256 min_amount\n ) external returns (uint256);\n\n function remove_liquidity_imbalance(\n uint256[2] calldata amounts,\n uint256 max_burn_amount\n ) external returns (uint256);\n\n function calc_withdraw_one_coin(uint256 _token_amount, int128 i)\n external\n view\n returns (uint256);\n\n function balances(uint256 i) external view returns (uint256);\n\n function calc_token_amount(uint256[2] calldata amounts, bool deposit)\n external\n view\n returns (uint256);\n\n function base_pool() external view returns (address);\n\n function fee() external view returns (uint256);\n\n function coins(uint256 i) external view returns (address);\n\n function exchange(\n int128 i,\n int128 j,\n uint256 dx,\n uint256 min_dy\n ) external returns (uint256);\n\n function get_dy(\n int128 i,\n int128 j,\n uint256 dx\n ) external view returns (uint256);\n}\n" + }, + "contracts/strategies/ICurvePool.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface ICurvePool {\n function get_virtual_price() external view returns (uint256);\n\n function add_liquidity(uint256[3] calldata _amounts, uint256 _min) external;\n\n function balances(uint256) external view returns (uint256);\n\n function calc_token_amount(uint256[3] calldata _amounts, bool _deposit)\n external\n returns (uint256);\n\n function fee() external view returns (uint256);\n\n function remove_liquidity_one_coin(\n uint256 _amount,\n int128 _index,\n uint256 _minAmount\n ) external;\n\n function remove_liquidity(\n uint256 _amount,\n uint256[3] calldata _minWithdrawAmounts\n ) external;\n\n function calc_withdraw_one_coin(uint256 _amount, int128 _index)\n external\n view\n returns (uint256);\n\n function exchange(\n uint256 i,\n uint256 j,\n uint256 dx,\n uint256 min_dy\n ) external returns (uint256);\n\n function coins(uint256 _index) external view returns (address);\n\n function remove_liquidity_imbalance(\n uint256[3] calldata _amounts,\n uint256 maxBurnAmount\n ) external;\n}\n" + }, + "contracts/strategies/IRewardStaking.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IRewardStaking {\n function stakeFor(address, uint256) external;\n\n function stake(uint256) external;\n\n function withdraw(uint256 amount, bool claim) external;\n\n function withdrawAndUnwrap(uint256 amount, bool claim) external;\n\n function earned(address account) external view returns (uint256);\n\n function getReward() external;\n\n function getReward(address _account, bool _claimExtras) external;\n\n function extraRewardsLength() external returns (uint256);\n\n function extraRewards(uint256 _pid) external returns (address);\n\n function rewardToken() external returns (address);\n\n function balanceOf(address account) external view returns (uint256);\n}\n" + }, + "contracts/strategies/LidoWithdrawalStrategy.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { IERC20, InitializableAbstractStrategy } from \"../utils/InitializableAbstractStrategy.sol\";\nimport { IWETH9 } from \"../interfaces/IWETH9.sol\";\nimport { IVault } from \"../interfaces/IVault.sol\";\n\ninterface IStETHWithdrawal {\n event WithdrawalRequested(\n uint256 indexed requestId,\n address indexed requestor,\n address indexed owner,\n uint256 amountOfStETH,\n uint256 amountOfShares\n );\n event WithdrawalsFinalized(\n uint256 indexed from,\n uint256 indexed to,\n uint256 amountOfETHLocked,\n uint256 sharesToBurn,\n uint256 timestamp\n );\n event WithdrawalClaimed(\n uint256 indexed requestId,\n address indexed owner,\n address indexed receiver,\n uint256 amountOfETH\n );\n\n struct WithdrawalRequestStatus {\n /// @notice stETH token amount that was locked on withdrawal queue for this request\n uint256 amountOfStETH;\n /// @notice amount of stETH shares locked on withdrawal queue for this request\n uint256 amountOfShares;\n /// @notice address that can claim or transfer this request\n address owner;\n /// @notice timestamp of when the request was created, in seconds\n uint256 timestamp;\n /// @notice true, if request is finalized\n bool isFinalized;\n /// @notice true, if request is claimed. Request is claimable if (isFinalized && !isClaimed)\n bool isClaimed;\n }\n\n function requestWithdrawals(uint256[] calldata _amounts, address _owner)\n external\n returns (uint256[] memory requestIds);\n\n function getLastCheckpointIndex() external view returns (uint256);\n\n function findCheckpointHints(\n uint256[] calldata _requestIds,\n uint256 _firstIndex,\n uint256 _lastIndex\n ) external view returns (uint256[] memory hintIds);\n\n function claimWithdrawals(\n uint256[] calldata _requestIds,\n uint256[] calldata _hints\n ) external;\n\n function getWithdrawalStatus(uint256[] calldata _requestIds)\n external\n view\n returns (WithdrawalRequestStatus[] memory statuses);\n\n function getWithdrawalRequests(address _owner)\n external\n view\n returns (uint256[] memory requestsIds);\n\n function finalize(\n uint256 _lastRequestIdToBeFinalized,\n uint256 _maxShareRate\n ) external payable;\n}\n\n/**\n * @title Lido Withdrawal Strategy\n * @notice This strategy withdraws ETH from stETH via the Lido Withdrawal Queue contract\n * @author Origin Protocol Inc\n */\ncontract LidoWithdrawalStrategy is InitializableAbstractStrategy {\n /// @notice Address of the WETH token\n IWETH9 private constant weth =\n IWETH9(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);\n /// @notice Address of the stETH token\n IERC20 private constant stETH =\n IERC20(0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84);\n /// @notice Address of the Lido Withdrawal Queue contract\n IStETHWithdrawal private constant withdrawalQueue =\n IStETHWithdrawal(0x889edC2eDab5f40e902b864aD4d7AdE8E412F9B1);\n /// @notice Maximum amount of stETH that can be withdrawn in a single request\n uint256 public constant MaxWithdrawalAmount = 1000 ether;\n /// @notice Total amount of stETH that has been requested to be withdrawn for ETH\n uint256 public outstandingWithdrawals;\n\n event WithdrawalRequests(uint256[] requestIds, uint256[] amounts);\n event WithdrawalClaims(uint256[] requestIds, uint256 amount);\n\n constructor(BaseStrategyConfig memory _stratConfig)\n InitializableAbstractStrategy(_stratConfig)\n {}\n\n /**\n * @notice initialize function, to set up initial internal state\n * @param _rewardTokenAddresses Address of reward token for platform\n * @param _assets Addresses of initial supported assets\n * @param _pTokens Platform Token corresponding addresses\n */\n function initialize(\n address[] memory _rewardTokenAddresses,\n address[] memory _assets,\n address[] memory _pTokens\n ) external onlyGovernor initializer {\n InitializableAbstractStrategy._initialize(\n _rewardTokenAddresses,\n _assets,\n _pTokens\n );\n safeApproveAllTokens();\n }\n\n /**\n * @notice deposit() function not used for this strategy. Use depositAll() instead.\n */\n function deposit(address, uint256) public override onlyVault nonReentrant {\n // This method no longer used by the VaultAdmin, and we don't want it\n // to be used by VaultCore.\n require(false, \"use depositAll() instead\");\n }\n\n /**\n * @notice Takes all given stETH and creates Lido withdrawal request\n */\n function depositAll() external override onlyVault nonReentrant {\n uint256 stETHStart = stETH.balanceOf(address(this));\n require(stETHStart > 0, \"No stETH to withdraw\");\n\n uint256 withdrawalLength = (stETHStart / MaxWithdrawalAmount) + 1;\n uint256[] memory amounts = new uint256[](withdrawalLength);\n\n uint256 stETHRemaining = stETHStart;\n uint256 i = 0;\n while (stETHRemaining > MaxWithdrawalAmount) {\n amounts[i++] = MaxWithdrawalAmount;\n stETHRemaining -= MaxWithdrawalAmount;\n }\n amounts[i] = stETHRemaining;\n\n uint256[] memory requestIds = withdrawalQueue.requestWithdrawals(\n amounts,\n address(this)\n );\n\n emit WithdrawalRequests(requestIds, amounts);\n\n // Is there any stETH left except 1 wei from each request?\n // This is because stETH does not transfer all the transfer amount.\n uint256 stEthDust = stETH.balanceOf(address(this));\n require(\n stEthDust <= withdrawalLength,\n \"Not all stEth in withdraw queue\"\n );\n outstandingWithdrawals += stETHStart;\n\n // This strategy claims to support WETH, so it is possible for\n // the vault to transfer WETH to it. This returns any deposited WETH\n // to the vault so that it is not lost for balance tracking purposes.\n uint256 wethBalance = weth.balanceOf(address(this));\n if (wethBalance > 0) {\n // slither-disable-next-line unchecked-transfer\n weth.transfer(vaultAddress, wethBalance);\n }\n\n emit Deposit(address(stETH), address(withdrawalQueue), stETHStart);\n }\n\n /**\n * @notice Withdraw an asset from the underlying platform\n * @param _recipient Address to receive withdrawn assets\n * @param _asset Address of the asset to withdraw\n * @param _amount Amount of assets to withdraw\n */\n function withdraw(\n // solhint-disable-next-line no-unused-vars\n address _recipient,\n // solhint-disable-next-line no-unused-vars\n address _asset,\n // solhint-disable-next-line no-unused-vars\n uint256 _amount\n ) external override onlyVault nonReentrant {\n // Does nothing - all withdrawals need to be called manually using the\n // Strategist calling claimWithdrawals\n revert(\"use claimWithdrawals()\");\n }\n\n /**\n * @notice Claim previously requested withdrawals that have now finalized.\n * Called by the Strategist.\n * @param _requestIds Array of withdrawal request identifiers\n * @param _expectedAmount Total amount of ETH expect to be withdrawn\n */\n function claimWithdrawals(\n uint256[] memory _requestIds,\n uint256 _expectedAmount\n ) external nonReentrant {\n require(\n msg.sender == IVault(vaultAddress).strategistAddr(),\n \"Caller is not the Strategist\"\n );\n uint256 startingBalance = payable(address(this)).balance;\n uint256 lastIndex = withdrawalQueue.getLastCheckpointIndex();\n uint256[] memory hintIds = withdrawalQueue.findCheckpointHints(\n _requestIds,\n 1,\n lastIndex\n );\n withdrawalQueue.claimWithdrawals(_requestIds, hintIds);\n\n uint256 currentBalance = payable(address(this)).balance;\n uint256 withdrawalAmount = currentBalance - startingBalance;\n // Withdrawal amount should be within 2 wei of expected amount\n require(\n withdrawalAmount + 2 >= _expectedAmount &&\n withdrawalAmount <= _expectedAmount,\n \"Withdrawal amount not expected\"\n );\n\n emit WithdrawalClaims(_requestIds, withdrawalAmount);\n\n outstandingWithdrawals -= withdrawalAmount;\n weth.deposit{ value: currentBalance }();\n // slither-disable-next-line unchecked-transfer\n weth.transfer(vaultAddress, currentBalance);\n emit Withdrawal(\n address(weth),\n address(withdrawalQueue),\n currentBalance\n );\n }\n\n /**\n * @notice Withdraw all assets from this strategy, and transfer to the Vault.\n * In correct operation, this strategy should never hold any assets.\n */\n function withdrawAll() external override onlyVaultOrGovernor nonReentrant {\n if (payable(address(this)).balance > 0) {\n weth.deposit{ value: payable(address(this)).balance }();\n }\n uint256 wethBalance = weth.balanceOf(address(this));\n if (wethBalance > 0) {\n // slither-disable-next-line unchecked-transfer\n weth.transfer(vaultAddress, wethBalance);\n emit Withdrawal(address(weth), address(0), wethBalance);\n }\n uint256 stEthBalance = stETH.balanceOf(address(this));\n if (stEthBalance > 0) {\n // slither-disable-next-line unchecked-transfer\n stETH.transfer(vaultAddress, stEthBalance);\n emit Withdrawal(address(stETH), address(0), stEthBalance);\n }\n }\n\n /**\n * @notice Returns the amount of queued stETH that will be returned as WETH.\n * We return this as a WETH asset, since that is what it will eventually be returned as.\n * We only return the outstandingWithdrawals, because the contract itself should never hold any funds.\n * @param _asset Address of the asset\n * @return balance Total value of the asset in the platform\n */\n function checkBalance(address _asset)\n external\n view\n override\n returns (uint256 balance)\n {\n if (_asset == address(weth)) {\n return outstandingWithdrawals;\n } else if (_asset == address(stETH)) {\n return 0;\n } else {\n revert(\"Unexpected asset address\");\n }\n }\n\n /**\n * @notice Approve the spending of all assets by their corresponding cToken,\n * if for some reason is it necessary.\n */\n function safeApproveAllTokens() public override {\n // slither-disable-next-line unused-return\n stETH.approve(address(withdrawalQueue), type(uint256).max);\n }\n\n /**\n * @notice Check if an asset is supported.\n * @param _asset Address of the asset\n * @return bool Whether asset is supported\n */\n function supportsAsset(address _asset) public pure override returns (bool) {\n // stETH can be deposited by the vault and balances are reported in WETH\n return _asset == address(stETH) || _asset == address(weth);\n }\n\n /// @notice Needed to receive ETH when withdrawal requests are claimed\n receive() external payable {}\n\n function _abstractSetPToken(address, address) internal pure override {\n revert(\"No pTokens are used\");\n }\n}\n" + }, + "contracts/strategies/MorphoAaveStrategy.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @title OUSD Morpho Aave Strategy\n * @notice Investment strategy for investing stablecoins via Morpho (Aave)\n * @author Origin Protocol Inc\n */\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { IERC20, InitializableAbstractStrategy } from \"../utils/InitializableAbstractStrategy.sol\";\nimport { IMorpho } from \"../interfaces/morpho/IMorpho.sol\";\nimport { ILens } from \"../interfaces/morpho/ILens.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\n\ncontract MorphoAaveStrategy is InitializableAbstractStrategy {\n address public constant MORPHO = 0x777777c9898D384F785Ee44Acfe945efDFf5f3E0;\n address public constant LENS = 0x507fA343d0A90786d86C7cd885f5C49263A91FF4;\n\n using SafeERC20 for IERC20;\n using StableMath for uint256;\n\n constructor(BaseStrategyConfig memory _stratConfig)\n InitializableAbstractStrategy(_stratConfig)\n {}\n\n /**\n * @dev Initialize function, to set up initial internal state\n * @param _rewardTokenAddresses Address of reward token for platform\n * @param _assets Addresses of initial supported assets\n * @param _pTokens Platform Token corresponding addresses\n */\n function initialize(\n address[] calldata _rewardTokenAddresses,\n address[] calldata _assets,\n address[] calldata _pTokens\n ) external onlyGovernor initializer {\n InitializableAbstractStrategy._initialize(\n _rewardTokenAddresses,\n _assets,\n _pTokens\n );\n }\n\n /**\n * @dev Approve the spending of all assets by main Morpho contract,\n * if for some reason is it necessary.\n */\n function safeApproveAllTokens()\n external\n override\n onlyGovernor\n nonReentrant\n {\n uint256 assetCount = assetsMapped.length;\n for (uint256 i = 0; i < assetCount; i++) {\n address asset = assetsMapped[i];\n\n // Safe approval\n IERC20(asset).safeApprove(MORPHO, 0);\n IERC20(asset).safeApprove(MORPHO, type(uint256).max);\n }\n }\n\n /**\n * @dev Internal method to respond to the addition of new asset\n * We need to approve and allow Morpho to move them\n * @param _asset Address of the asset to approve\n * @param _pToken The pToken for the approval\n */\n // solhint-disable-next-line no-unused-vars\n function _abstractSetPToken(address _asset, address _pToken)\n internal\n override\n {\n IERC20(_asset).safeApprove(MORPHO, 0);\n IERC20(_asset).safeApprove(MORPHO, type(uint256).max);\n }\n\n /**\n * @dev Collect accumulated rewards and send them to Harvester.\n */\n function collectRewardTokens()\n external\n override\n onlyHarvester\n nonReentrant\n {\n // Morpho Aave-v2 doesn't distribute reward tokens\n // solhint-disable-next-line max-line-length\n // Ref: https://developers.morpho.xyz/interact-with-morpho/get-started/interact-with-morpho/claim-rewards#morpho-aave-v2\n }\n\n /**\n * @dev Get the amount of rewards pending to be collected from the protocol\n */\n function getPendingRewards() external view returns (uint256 balance) {\n // Morpho Aave-v2 doesn't distribute reward tokens\n // solhint-disable-next-line max-line-length\n // Ref: https://developers.morpho.xyz/interact-with-morpho/get-started/interact-with-morpho/claim-rewards#morpho-aave-v2\n return 0;\n }\n\n /**\n * @dev Deposit asset into Morpho\n * @param _asset Address of asset to deposit\n * @param _amount Amount of asset to deposit\n */\n function deposit(address _asset, uint256 _amount)\n external\n override\n onlyVault\n nonReentrant\n {\n _deposit(_asset, _amount);\n }\n\n /**\n * @dev Deposit asset into Morpho\n * @param _asset Address of asset to deposit\n * @param _amount Amount of asset to deposit\n */\n function _deposit(address _asset, uint256 _amount) internal {\n require(_amount > 0, \"Must deposit something\");\n\n address pToken = address(_getPTokenFor(_asset));\n\n IMorpho(MORPHO).supply(\n pToken,\n address(this), // the address of the user you want to supply on behalf of\n _amount\n );\n emit Deposit(_asset, pToken, _amount);\n }\n\n /**\n * @dev Deposit the entire balance of any supported asset into Morpho\n */\n function depositAll() external override onlyVault nonReentrant {\n for (uint256 i = 0; i < assetsMapped.length; i++) {\n uint256 balance = IERC20(assetsMapped[i]).balanceOf(address(this));\n if (balance > 0) {\n _deposit(assetsMapped[i], balance);\n }\n }\n }\n\n /**\n * @dev Withdraw asset from Morpho\n * @param _recipient Address to receive withdrawn asset\n * @param _asset Address of asset to withdraw\n * @param _amount Amount of asset to withdraw\n */\n function withdraw(\n address _recipient,\n address _asset,\n uint256 _amount\n ) external override onlyVault nonReentrant {\n _withdraw(_recipient, _asset, _amount);\n }\n\n function _withdraw(\n address _recipient,\n address _asset,\n uint256 _amount\n ) internal {\n require(_amount > 0, \"Must withdraw something\");\n require(_recipient != address(0), \"Must specify recipient\");\n\n address pToken = address(_getPTokenFor(_asset));\n\n IMorpho(MORPHO).withdraw(pToken, _amount);\n emit Withdrawal(_asset, pToken, _amount);\n IERC20(_asset).safeTransfer(_recipient, _amount);\n }\n\n /**\n * @dev Remove all assets from platform and send them to Vault contract.\n */\n function withdrawAll() external override onlyVaultOrGovernor nonReentrant {\n for (uint256 i = 0; i < assetsMapped.length; i++) {\n uint256 balance = _checkBalance(assetsMapped[i]);\n if (balance > 0) {\n _withdraw(vaultAddress, assetsMapped[i], balance);\n }\n }\n }\n\n /**\n * @dev Return total value of an asset held in the platform\n * @param _asset Address of the asset\n * @return balance Total value of the asset in the platform\n */\n function checkBalance(address _asset)\n external\n view\n override\n returns (uint256 balance)\n {\n return _checkBalance(_asset);\n }\n\n function _checkBalance(address _asset)\n internal\n view\n returns (uint256 balance)\n {\n address pToken = address(_getPTokenFor(_asset));\n\n // Total value represented by decimal position of underlying token\n (, , balance) = ILens(LENS).getCurrentSupplyBalanceInOf(\n pToken,\n address(this)\n );\n }\n\n /**\n * @dev Retuns bool indicating whether asset is supported by strategy\n * @param _asset Address of the asset\n */\n function supportsAsset(address _asset) public view override returns (bool) {\n return assetToPToken[_asset] != address(0);\n }\n\n /**\n * @dev Get the pToken wrapped in the IERC20 interface for this asset.\n * Fails if the pToken doesn't exist in our mappings.\n * @param _asset Address of the asset\n * @return pToken Corresponding pToken to this asset\n */\n function _getPTokenFor(address _asset) internal view returns (IERC20) {\n address pToken = assetToPToken[_asset];\n require(pToken != address(0), \"pToken does not exist\");\n return IERC20(pToken);\n }\n}\n" + }, + "contracts/strategies/MorphoCompoundStrategy.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @title OUSD Morpho Compound Strategy\n * @notice Investment strategy for investing stablecoins via Morpho (Compound)\n * @author Origin Protocol Inc\n */\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { IERC20, BaseCompoundStrategy, InitializableAbstractStrategy } from \"./BaseCompoundStrategy.sol\";\nimport { IMorpho } from \"../interfaces/morpho/IMorpho.sol\";\nimport { ILens } from \"../interfaces/morpho/ILens.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\nimport \"../utils/Helpers.sol\";\n\ncontract MorphoCompoundStrategy is BaseCompoundStrategy {\n address public constant MORPHO = 0x8888882f8f843896699869179fB6E4f7e3B58888;\n address public constant LENS = 0x930f1b46e1D081Ec1524efD95752bE3eCe51EF67;\n using SafeERC20 for IERC20;\n using StableMath for uint256;\n\n constructor(BaseStrategyConfig memory _stratConfig)\n InitializableAbstractStrategy(_stratConfig)\n {}\n\n /**\n * @dev Initialize function, to set up initial internal state\n * @param _rewardTokenAddresses Address of reward token for platform\n * @param _assets Addresses of initial supported assets\n * @param _pTokens Platform Token corresponding addresses\n */\n function initialize(\n address[] calldata _rewardTokenAddresses,\n address[] calldata _assets,\n address[] calldata _pTokens\n ) external onlyGovernor initializer {\n InitializableAbstractStrategy._initialize(\n _rewardTokenAddresses,\n _assets,\n _pTokens\n );\n }\n\n /**\n * @dev Approve the spending of all assets by main Morpho contract,\n * if for some reason is it necessary.\n */\n function safeApproveAllTokens()\n external\n override\n onlyGovernor\n nonReentrant\n {\n uint256 assetCount = assetsMapped.length;\n for (uint256 i = 0; i < assetCount; i++) {\n address asset = assetsMapped[i];\n\n // Safe approval\n IERC20(asset).safeApprove(MORPHO, 0);\n IERC20(asset).safeApprove(MORPHO, type(uint256).max);\n }\n }\n\n /**\n * @dev Internal method to respond to the addition of new asset\n * We need to approve and allow Morpho to move them\n * @param _asset Address of the asset to approve\n * @param _pToken The pToken for the approval\n */\n // solhint-disable-next-line no-unused-vars\n function _abstractSetPToken(address _asset, address _pToken)\n internal\n override\n {\n IERC20(_asset).safeApprove(MORPHO, 0);\n IERC20(_asset).safeApprove(MORPHO, type(uint256).max);\n }\n\n /**\n * @dev Collect accumulated rewards and send them to Harvester.\n */\n function collectRewardTokens()\n external\n override\n onlyHarvester\n nonReentrant\n {\n /**\n * Gas considerations. We could query Morpho LENS's `getUserUnclaimedRewards` for each\n * cToken separately and only claimRewards where it is economically feasible. Each call\n * (out of 3) costs ~60k gas extra.\n *\n * Each extra cToken in the `poolTokens` of `claimRewards` function makes that call\n * 89-120k more expensive gas wise.\n *\n * With Lens query in case where:\n * - there is only 1 reward token to collect. Net gas usage in best case would be\n * 3*60 - 2*120 = -60k -> saving 60k gas\n * - there are 2 reward tokens to collect. Net gas usage in best case would be\n * 3*60 - 120 = 60k -> more expensive for 60k gas\n * - there are 3 reward tokens to collect. Net gas usage in best case would be\n * 3*60 = 180k -> more expensive for 180k gas\n *\n * For the above reasoning such \"optimization\" is not implemented\n */\n\n address[] memory poolTokens = new address[](assetsMapped.length);\n for (uint256 i = 0; i < assetsMapped.length; i++) {\n poolTokens[i] = assetToPToken[assetsMapped[i]];\n }\n\n // slither-disable-next-line unused-return\n IMorpho(MORPHO).claimRewards(\n poolTokens, // The addresses of the underlying protocol's pools to claim rewards from\n false // Whether to trade the accrued rewards for MORPHO token, with a premium\n );\n\n // Transfer COMP to Harvester\n IERC20 rewardToken = IERC20(rewardTokenAddresses[0]);\n uint256 balance = rewardToken.balanceOf(address(this));\n emit RewardTokenCollected(\n harvesterAddress,\n rewardTokenAddresses[0],\n balance\n );\n rewardToken.safeTransfer(harvesterAddress, balance);\n }\n\n /**\n * @dev Get the amount of rewards pending to be collected from the protocol\n */\n function getPendingRewards() external view returns (uint256 balance) {\n address[] memory poolTokens = new address[](assetsMapped.length);\n for (uint256 i = 0; i < assetsMapped.length; i++) {\n poolTokens[i] = assetToPToken[assetsMapped[i]];\n }\n\n return ILens(LENS).getUserUnclaimedRewards(poolTokens, address(this));\n }\n\n /**\n * @dev Deposit asset into Morpho\n * @param _asset Address of asset to deposit\n * @param _amount Amount of asset to deposit\n */\n function deposit(address _asset, uint256 _amount)\n external\n override\n onlyVault\n nonReentrant\n {\n _deposit(_asset, _amount);\n }\n\n /**\n * @dev Deposit asset into Morpho\n * @param _asset Address of asset to deposit\n * @param _amount Amount of asset to deposit\n */\n function _deposit(address _asset, uint256 _amount) internal {\n require(_amount > 0, \"Must deposit something\");\n\n IMorpho(MORPHO).supply(\n address(_getCTokenFor(_asset)),\n address(this), // the address of the user you want to supply on behalf of\n _amount\n );\n emit Deposit(_asset, address(_getCTokenFor(_asset)), _amount);\n }\n\n /**\n * @dev Deposit the entire balance of any supported asset into Morpho\n */\n function depositAll() external override onlyVault nonReentrant {\n for (uint256 i = 0; i < assetsMapped.length; i++) {\n uint256 balance = IERC20(assetsMapped[i]).balanceOf(address(this));\n if (balance > 0) {\n _deposit(assetsMapped[i], balance);\n }\n }\n }\n\n /**\n * @dev Withdraw asset from Morpho\n * @param _recipient Address to receive withdrawn asset\n * @param _asset Address of asset to withdraw\n * @param _amount Amount of asset to withdraw\n */\n function withdraw(\n address _recipient,\n address _asset,\n uint256 _amount\n ) external override onlyVault nonReentrant {\n _withdraw(_recipient, _asset, _amount);\n }\n\n function _withdraw(\n address _recipient,\n address _asset,\n uint256 _amount\n ) internal {\n require(_amount > 0, \"Must withdraw something\");\n require(_recipient != address(0), \"Must specify recipient\");\n\n address pToken = assetToPToken[_asset];\n\n IMorpho(MORPHO).withdraw(pToken, _amount);\n emit Withdrawal(_asset, address(_getCTokenFor(_asset)), _amount);\n IERC20(_asset).safeTransfer(_recipient, _amount);\n }\n\n /**\n * @dev Remove all assets from platform and send them to Vault contract.\n */\n function withdrawAll() external override onlyVaultOrGovernor nonReentrant {\n for (uint256 i = 0; i < assetsMapped.length; i++) {\n uint256 balance = _checkBalance(assetsMapped[i]);\n if (balance > 0) {\n _withdraw(vaultAddress, assetsMapped[i], balance);\n }\n }\n }\n\n /**\n * @dev Return total value of an asset held in the platform\n * @param _asset Address of the asset\n * @return balance Total value of the asset in the platform\n */\n function checkBalance(address _asset)\n external\n view\n override\n returns (uint256 balance)\n {\n return _checkBalance(_asset);\n }\n\n function _checkBalance(address _asset)\n internal\n view\n returns (uint256 balance)\n {\n address pToken = assetToPToken[_asset];\n\n // Total value represented by decimal position of underlying token\n (, , balance) = ILens(LENS).getCurrentSupplyBalanceInOf(\n pToken,\n address(this)\n );\n }\n}\n" + }, + "contracts/strategies/NativeStaking/FeeAccumulator.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { Address } from \"@openzeppelin/contracts/utils/Address.sol\";\n\n/**\n * @title Fee Accumulator for Native Staking SSV Strategy\n * @notice Receives execution rewards which includes tx fees and\n * MEV rewards like tx priority and tx ordering.\n * It does NOT include swept ETH from beacon chain consensus rewards or full validator withdrawals.\n * @author Origin Protocol Inc\n */\ncontract FeeAccumulator {\n /// @notice The address of the Native Staking Strategy\n address public immutable STRATEGY;\n\n event ExecutionRewardsCollected(address indexed strategy, uint256 amount);\n\n /**\n * @param _strategy Address of the Native Staking Strategy\n */\n constructor(address _strategy) {\n STRATEGY = _strategy;\n }\n\n /**\n * @notice sends all ETH in this FeeAccumulator contract to the Native Staking Strategy.\n * @return eth The amount of execution rewards that were sent to the Native Staking Strategy\n */\n function collect() external returns (uint256 eth) {\n require(msg.sender == STRATEGY, \"Caller is not the Strategy\");\n\n eth = address(this).balance;\n if (eth > 0) {\n // Send the ETH to the Native Staking Strategy\n Address.sendValue(payable(STRATEGY), eth);\n\n emit ExecutionRewardsCollected(STRATEGY, eth);\n }\n }\n\n /**\n * @dev Accept ETH\n */\n receive() external payable {}\n}\n" + }, + "contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/utils/math/Math.sol\";\n\nimport { InitializableAbstractStrategy } from \"../../utils/InitializableAbstractStrategy.sol\";\nimport { IWETH9 } from \"../../interfaces/IWETH9.sol\";\nimport { FeeAccumulator } from \"./FeeAccumulator.sol\";\nimport { ValidatorAccountant } from \"./ValidatorAccountant.sol\";\n\nstruct ValidatorStakeData {\n bytes pubkey;\n bytes signature;\n bytes32 depositDataRoot;\n}\n\n/// @title Native Staking SSV Strategy\n/// @notice Strategy to deploy funds into DVT validators powered by the SSV Network\n/// @author Origin Protocol Inc\n/// @dev This contract handles WETH and ETH and in some operations interchanges between the two. Any WETH that\n/// is on the contract across multiple blocks (and not just transitory within a transaction) is considered an\n/// asset. Meaning deposits increase the balance of the asset and withdrawal decrease it. As opposed to all\n/// our other strategies the WETH doesn't immediately get deposited into an underlying strategy and can be present\n/// across multiple blocks waiting to be unwrapped to ETH and staked to validators. This separation of WETH and ETH is\n/// required since the rewards (reward token) is also in ETH.\n///\n/// To simplify the accounting of WETH there is another difference in behavior compared to the other strategies.\n/// To withdraw WETH asset - exit message is posted to validators and the ETH hits this contract with multiple days\n/// delay. In order to simplify the WETH accounting upon detection of such an event the ValidatorAccountant\n/// immediately wraps ETH to WETH and sends it to the Vault.\n///\n/// On the other hand any ETH on the contract (across multiple blocks) is there either:\n/// - as a result of already accounted for consensus rewards\n/// - as a result of not yet accounted for consensus rewards\n/// - as a results of not yet accounted for full validator withdrawals (or validator slashes)\n///\n/// Even though the strategy assets and rewards are a very similar asset the consensus layer rewards and the\n/// execution layer rewards are considered rewards and those are dripped to the Vault over a configurable time\n/// interval and not immediately.\ncontract NativeStakingSSVStrategy is\n ValidatorAccountant,\n InitializableAbstractStrategy\n{\n using SafeERC20 for IERC20;\n\n /// @notice SSV ERC20 token that serves as a payment for operating SSV validators\n address public immutable SSV_TOKEN;\n /// @notice Fee collector address\n /// @dev this address will receive Execution layer rewards - These are rewards earned for\n /// executing transactions on the Ethereum network as part of block proposals. They include\n /// priority fees (fees paid by users for their transactions to be included) and MEV rewards\n /// (rewards for arranging transactions in a way that benefits the validator).\n address payable public immutable FEE_ACCUMULATOR_ADDRESS;\n\n /// @dev This contract receives WETH as the deposit asset, but unlike other strategies doesn't immediately\n /// deposit it to an underlying platform. Rather a special privilege account stakes it to the validators.\n /// For that reason calling WETH.balanceOf(this) in a deposit function can contain WETH that has just been\n /// deposited and also WETH that has previously been deposited. To keep a correct count we need to keep track\n /// of WETH that has already been accounted for.\n /// This value represents the amount of WETH balance of this contract that has already been accounted for by the\n /// deposit events.\n /// It is important to note that this variable is not concerned with WETH that is a result of full/partial\n /// withdrawal of the validators. It is strictly concerned with WETH that has been deposited and is waiting to\n /// be staked.\n uint256 public depositedWethAccountedFor;\n\n // For future use\n uint256[49] private __gap;\n\n /// @param _baseConfig Base strategy config with platformAddress (ERC-4626 Vault contract), eg sfrxETH or sDAI,\n /// and vaultAddress (OToken Vault contract), eg VaultProxy or OETHVaultProxy\n /// @param _wethAddress Address of the Erc20 WETH Token contract\n /// @param _ssvToken Address of the Erc20 SSV Token contract\n /// @param _ssvNetwork Address of the SSV Network contract\n /// @param _maxValidators Maximum number of validators that can be registered in the strategy\n /// @param _feeAccumulator Address of the fee accumulator receiving execution layer validator rewards\n /// @param _beaconChainDepositContract Address of the beacon chain deposit contract\n constructor(\n BaseStrategyConfig memory _baseConfig,\n address _wethAddress,\n address _ssvToken,\n address _ssvNetwork,\n uint256 _maxValidators,\n address _feeAccumulator,\n address _beaconChainDepositContract\n )\n InitializableAbstractStrategy(_baseConfig)\n ValidatorAccountant(\n _wethAddress,\n _baseConfig.vaultAddress,\n _beaconChainDepositContract,\n _ssvNetwork,\n _maxValidators\n )\n {\n SSV_TOKEN = _ssvToken;\n FEE_ACCUMULATOR_ADDRESS = payable(_feeAccumulator);\n }\n\n /// @notice initialize function, to set up initial internal state\n /// @param _rewardTokenAddresses Address of reward token for platform\n /// @param _assets Addresses of initial supported assets\n /// @param _pTokens Platform Token corresponding addresses\n function initialize(\n address[] memory _rewardTokenAddresses,\n address[] memory _assets,\n address[] memory _pTokens\n ) external onlyGovernor initializer {\n InitializableAbstractStrategy._initialize(\n _rewardTokenAddresses,\n _assets,\n _pTokens\n );\n }\n\n /// @notice Unlike other strategies, this does not deposit assets into the underlying platform.\n /// It just checks the asset is WETH and emits the Deposit event.\n /// To deposit WETH into validators `registerSsvValidator` and `stakeEth` must be used.\n /// Will NOT revert if the strategy is paused from an accounting failure.\n /// @param _asset Address of asset to deposit. Has to be WETH.\n /// @param _amount Amount of assets that were transferred to the strategy by the vault.\n function deposit(address _asset, uint256 _amount)\n external\n override\n onlyVault\n nonReentrant\n {\n require(_asset == WETH, \"Unsupported asset\");\n depositedWethAccountedFor += _amount;\n _deposit(_asset, _amount);\n }\n\n /// @dev Deposit WETH to this strategy so it can later be staked into a validator.\n /// @param _asset Address of WETH\n /// @param _amount Amount of WETH to deposit\n function _deposit(address _asset, uint256 _amount) internal {\n require(_amount > 0, \"Must deposit something\");\n /*\n * We could do a check here that would revert when \"_amount % 32 ether != 0\". With the idea of\n * not allowing deposits that will result in WETH sitting on the strategy after all the possible batches\n * of 32ETH have been staked.\n * But someone could mess with our strategy by sending some WETH to it. And we might want to deposit just\n * enough WETH to add it up to 32 so it can be staked. For that reason the check is left out.\n *\n * WETH sitting on the strategy won't interfere with the accounting since accounting only operates on ETH.\n */\n emit Deposit(_asset, address(0), _amount);\n }\n\n /// @notice Unlike other strategies, this does not deposit assets into the underlying platform.\n /// It just emits the Deposit event.\n /// To deposit WETH into validators `registerSsvValidator` and `stakeEth` must be used.\n /// Will NOT revert if the strategy is paused from an accounting failure.\n function depositAll() external override onlyVault nonReentrant {\n uint256 wethBalance = IERC20(WETH).balanceOf(address(this));\n uint256 newWeth = wethBalance - depositedWethAccountedFor;\n\n if (newWeth > 0) {\n depositedWethAccountedFor = wethBalance;\n\n _deposit(WETH, newWeth);\n }\n }\n\n /// @notice Withdraw WETH from this contract. Used only if some WETH for is lingering on the contract.\n /// That can happen when:\n /// - after mints if the strategy is the default\n /// - time between depositToStrategy and stakeEth\n /// - the deposit was not a multiple of 32 WETH\n /// - someone sent WETH directly to this contract\n /// Will NOT revert if the strategy is paused from an accounting failure.\n /// @param _recipient Address to receive withdrawn assets\n /// @param _asset WETH to withdraw\n /// @param _amount Amount of WETH to withdraw\n function withdraw(\n address _recipient,\n address _asset,\n uint256 _amount\n ) external override onlyVault nonReentrant {\n require(_asset == WETH, \"Unsupported asset\");\n _withdraw(_recipient, _asset, _amount);\n }\n\n function _withdraw(\n address _recipient,\n address _asset,\n uint256 _amount\n ) internal {\n require(_amount > 0, \"Must withdraw something\");\n require(_recipient != address(0), \"Must specify recipient\");\n\n _wethWithdrawn(_amount);\n\n IERC20(_asset).safeTransfer(_recipient, _amount);\n emit Withdrawal(_asset, address(0), _amount);\n }\n\n /// @notice transfer all WETH deposits back to the vault.\n /// This does not withdraw from the validators. That has to be done separately with the\n /// `exitSsvValidator` and `removeSsvValidator` operations.\n /// This does not withdraw any execution rewards from the FeeAccumulator or\n /// consensus rewards in this strategy.\n /// Any ETH in this strategy that was swept from a full validator withdrawal will not be withdrawn.\n /// ETH from full validator withdrawals is sent to the Vault using `doAccounting`.\n /// Will NOT revert if the strategy is paused from an accounting failure.\n function withdrawAll() external override onlyVaultOrGovernor nonReentrant {\n uint256 wethBalance = IERC20(WETH).balanceOf(address(this));\n if (wethBalance > 0) {\n _withdraw(vaultAddress, WETH, wethBalance);\n }\n }\n\n /// @notice Returns the total value of (W)ETH that is staked to the validators\n /// and WETH deposits that are still to be staked.\n /// This does not include ETH from consensus rewards sitting in this strategy\n /// or ETH from MEV rewards in the FeeAccumulator. These rewards are harvested\n /// and sent to the Dripper so will eventually be sent to the Vault as WETH.\n /// @param _asset Address of weth asset\n /// @return balance Total value of (W)ETH\n function checkBalance(address _asset)\n external\n view\n override\n returns (uint256 balance)\n {\n require(_asset == WETH, \"Unsupported asset\");\n\n balance =\n // add the ETH that has been staked in validators\n activeDepositedValidators *\n FULL_STAKE +\n // add the WETH in the strategy from deposits that are still to be staked\n IERC20(WETH).balanceOf(address(this));\n }\n\n function pause() external onlyStrategist {\n _pause();\n }\n\n /// @notice Returns bool indicating whether asset is supported by strategy.\n /// @param _asset The address of the asset token.\n function supportsAsset(address _asset) public view override returns (bool) {\n return _asset == WETH;\n }\n\n /// @notice Approves the SSV Network contract to transfer SSV tokens for deposits\n function safeApproveAllTokens() external override {\n /// @dev Approves the SSV Network contract to transfer SSV tokens for deposits\n IERC20(SSV_TOKEN).approve(SSV_NETWORK, type(uint256).max);\n }\n\n /**\n * @notice Only accept ETH from the FeeAccumulator and the WETH contract - required when\n * unwrapping WETH just before staking it to the validator\n * @dev don't want to receive donations from anyone else as this will\n * mess with the accounting of the consensus rewards and validator full withdrawals\n */\n receive() external payable {\n require(\n msg.sender == FEE_ACCUMULATOR_ADDRESS || msg.sender == WETH,\n \"Eth not from allowed contracts\"\n );\n }\n\n /***************************************\n Internal functions\n ****************************************/\n\n function _abstractSetPToken(address _asset, address) internal override {}\n\n /// @dev Convert accumulated ETH to WETH and send to the Harvester.\n /// Will revert if the strategy is paused for accounting.\n function _collectRewardTokens() internal override whenNotPaused {\n // collect ETH from execution rewards from the fee accumulator\n uint256 executionRewards = FeeAccumulator(FEE_ACCUMULATOR_ADDRESS)\n .collect();\n\n // total ETH rewards to be harvested = execution rewards + consensus rewards\n uint256 ethRewards = executionRewards + consensusRewards;\n\n require(\n address(this).balance >= ethRewards,\n \"Insufficient eth balance\"\n );\n\n if (ethRewards > 0) {\n // reset the counter keeping track of beacon chain consensus rewards\n consensusRewards = 0;\n\n // Convert ETH rewards to WETH\n IWETH9(WETH).deposit{ value: ethRewards }();\n\n IERC20(WETH).safeTransfer(harvesterAddress, ethRewards);\n emit RewardTokenCollected(harvesterAddress, WETH, ethRewards);\n }\n }\n\n /// @dev emits Withdrawal event from NativeStakingSSVStrategy\n function _wethWithdrawnToVault(uint256 _amount) internal override {\n emit Withdrawal(WETH, address(0), _amount);\n }\n\n /// @dev Called when WETH is withdrawn from the strategy or staked to a validator so\n /// the strategy knows how much WETH it has on deposit.\n /// This is so it can emit the correct amount in the Deposit event in depositAll().\n function _wethWithdrawn(uint256 _amount) internal override {\n /* In an ideal world we wouldn't need to reduce the deduction amount when the\n * depositedWethAccountedFor is smaller than the _amount.\n *\n * The reason this is required is that a malicious actor could sent WETH directly\n * to this contract and that would circumvent the increase of depositedWethAccountedFor\n * property. When the ETH would be staked the depositedWethAccountedFor amount could\n * be deducted so much that it would be negative.\n */\n uint256 deductAmount = Math.min(_amount, depositedWethAccountedFor);\n depositedWethAccountedFor -= deductAmount;\n }\n}\n" + }, + "contracts/strategies/NativeStaking/ValidatorAccountant.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { ValidatorRegistrator } from \"./ValidatorRegistrator.sol\";\nimport { IWETH9 } from \"../../interfaces/IWETH9.sol\";\n\n/// @title Validator Accountant\n/// @notice Attributes the ETH swept from beacon chain validators to this strategy contract\n/// as either full or partial withdrawals. Partial withdrawals being consensus rewards.\n/// Full withdrawals are from exited validators.\n/// @author Origin Protocol Inc\nabstract contract ValidatorAccountant is ValidatorRegistrator {\n /// @notice The minimum amount of blocks that need to pass between two calls to manuallyFixAccounting\n uint256 public constant MIN_FIX_ACCOUNTING_CADENCE = 7200; // 1 day\n\n /// @notice Keeps track of the total consensus rewards swept from the beacon chain\n uint256 public consensusRewards;\n\n /// @notice start of fuse interval\n uint256 public fuseIntervalStart;\n /// @notice end of fuse interval\n uint256 public fuseIntervalEnd;\n /// @notice last block number manuallyFixAccounting has been called\n uint256 public lastFixAccountingBlockNumber;\n\n uint256[49] private __gap;\n\n event FuseIntervalUpdated(uint256 start, uint256 end);\n event AccountingFullyWithdrawnValidator(\n uint256 noOfValidators,\n uint256 remainingValidators,\n uint256 wethSentToVault\n );\n event AccountingValidatorSlashed(\n uint256 remainingValidators,\n uint256 wethSentToVault\n );\n event AccountingConsensusRewards(uint256 amount);\n\n event AccountingManuallyFixed(\n int256 validatorsDelta,\n int256 consensusRewardsDelta,\n uint256 wethToVault\n );\n\n /// @param _wethAddress Address of the Erc20 WETH Token contract\n /// @param _vaultAddress Address of the Vault\n /// @param _beaconChainDepositContract Address of the beacon chain deposit contract\n /// @param _ssvNetwork Address of the SSV Network contract\n /// @param _maxValidators Maximum number of validators that can be registered in the strategy\n constructor(\n address _wethAddress,\n address _vaultAddress,\n address _beaconChainDepositContract,\n address _ssvNetwork,\n uint256 _maxValidators\n )\n ValidatorRegistrator(\n _wethAddress,\n _vaultAddress,\n _beaconChainDepositContract,\n _ssvNetwork,\n _maxValidators\n )\n {}\n\n /// @notice set fuse interval values\n function setFuseInterval(\n uint256 _fuseIntervalStart,\n uint256 _fuseIntervalEnd\n ) external onlyGovernor {\n require(\n _fuseIntervalStart < _fuseIntervalEnd &&\n _fuseIntervalEnd < 32 ether &&\n _fuseIntervalEnd - _fuseIntervalStart >= 4 ether,\n \"Incorrect fuse interval\"\n );\n\n fuseIntervalStart = _fuseIntervalStart;\n fuseIntervalEnd = _fuseIntervalEnd;\n\n emit FuseIntervalUpdated(_fuseIntervalStart, _fuseIntervalEnd);\n }\n\n /* solhint-disable max-line-length */\n /// This notion page offers a good explanation of how the accounting functions\n /// https://www.notion.so/originprotocol/Limited-simplified-native-staking-accounting-67a217c8420d40678eb943b9da0ee77d\n /// In short, after dividing by 32, if the ETH remaining on the contract falls between 0 and fuseIntervalStart,\n /// the accounting function will treat that ETH as Beacon chain consensus rewards.\n /// On the contrary, if after dividing by 32, the ETH remaining on the contract falls between fuseIntervalEnd and 32,\n /// the accounting function will treat that as a validator slashing.\n /// @notice Perform the accounting attributing beacon chain ETH to either full or partial withdrawals. Returns true when\n /// accounting is valid and fuse isn't \"blown\". Returns false when fuse is blown.\n /// @dev This function could in theory be permission-less but lets allow only the Registrator (Defender Action) to call it\n /// for now.\n /// @return accountingValid true if accounting was successful, false if fuse is blown\n /* solhint-enable max-line-length */\n function doAccounting()\n external\n onlyRegistrator\n whenNotPaused\n nonReentrant\n returns (bool accountingValid)\n {\n // pause the accounting on failure\n accountingValid = _doAccounting(true);\n }\n\n // slither-disable-start reentrancy-eth\n function _doAccounting(bool pauseOnFail)\n internal\n returns (bool accountingValid)\n {\n if (address(this).balance < consensusRewards) {\n return _failAccounting(pauseOnFail);\n }\n\n // Calculate all the new ETH that has been swept to the contract since the last accounting\n uint256 newSweptETH = address(this).balance - consensusRewards;\n accountingValid = true;\n\n // send the ETH that is from fully withdrawn validators to the Vault\n if (newSweptETH >= FULL_STAKE) {\n uint256 fullyWithdrawnValidators;\n // explicitly cast to uint256 as we want to round to a whole number of validators\n fullyWithdrawnValidators = uint256(newSweptETH / FULL_STAKE);\n activeDepositedValidators -= fullyWithdrawnValidators;\n\n uint256 wethToVault = FULL_STAKE * fullyWithdrawnValidators;\n IWETH9(WETH).deposit{ value: wethToVault }();\n // slither-disable-next-line unchecked-transfer\n IWETH9(WETH).transfer(VAULT_ADDRESS, wethToVault);\n _wethWithdrawnToVault(wethToVault);\n\n emit AccountingFullyWithdrawnValidator(\n fullyWithdrawnValidators,\n activeDepositedValidators,\n wethToVault\n );\n }\n\n uint256 ethRemaining = address(this).balance - consensusRewards;\n // should be less than a whole validator stake\n require(ethRemaining < FULL_STAKE, \"Unexpected accounting\");\n\n // If no Beacon chain consensus rewards swept\n if (ethRemaining == 0) {\n // do nothing\n return accountingValid;\n } else if (ethRemaining < fuseIntervalStart) {\n // Beacon chain consensus rewards swept (partial validator withdrawals)\n // solhint-disable-next-line reentrancy\n consensusRewards += ethRemaining;\n emit AccountingConsensusRewards(ethRemaining);\n } else if (ethRemaining > fuseIntervalEnd) {\n // Beacon chain consensus rewards swept but also a slashed validator fully exited\n IWETH9(WETH).deposit{ value: ethRemaining }();\n // slither-disable-next-line unchecked-transfer\n IWETH9(WETH).transfer(VAULT_ADDRESS, ethRemaining);\n activeDepositedValidators -= 1;\n\n _wethWithdrawnToVault(ethRemaining);\n\n emit AccountingValidatorSlashed(\n activeDepositedValidators,\n ethRemaining\n );\n }\n // Oh no... Fuse is blown. The Strategist needs to adjust the accounting values.\n else {\n return _failAccounting(pauseOnFail);\n }\n }\n\n // slither-disable-end reentrancy-eth\n\n /// @dev pause any further accounting if required and return false\n function _failAccounting(bool pauseOnFail)\n internal\n returns (bool accountingValid)\n {\n // pause if not already\n if (pauseOnFail) {\n _pause();\n }\n // fail the accounting\n accountingValid = false;\n }\n\n /// @notice Allow the Strategist to fix the accounting of this strategy and unpause.\n /// @param _validatorsDelta adjust the active validators by up to plus three or minus three\n /// @param _consensusRewardsDelta adjust the accounted for consensus rewards up or down\n /// @param _ethToVaultAmount the amount of ETH that gets wrapped into WETH and sent to the Vault\n /// @dev There is a case when a validator(s) gets slashed so much that the eth swept from\n /// the beacon chain enters the fuse area and there are no consensus rewards on the contract\n /// to \"dip into\"/use. To increase the amount of unaccounted ETH over the fuse end interval\n /// we need to reduce the amount of active deposited validators and immediately send WETH\n /// to the vault, so it doesn't interfere with further accounting.\n function manuallyFixAccounting(\n int256 _validatorsDelta,\n int256 _consensusRewardsDelta,\n uint256 _ethToVaultAmount\n ) external onlyStrategist whenPaused nonReentrant {\n require(\n lastFixAccountingBlockNumber + MIN_FIX_ACCOUNTING_CADENCE <\n block.number,\n \"Fix accounting called too soon\"\n );\n require(\n _validatorsDelta >= -3 &&\n _validatorsDelta <= 3 &&\n // new value must be positive\n int256(activeDepositedValidators) + _validatorsDelta >= 0,\n \"Invalid validatorsDelta\"\n );\n require(\n _consensusRewardsDelta >= -332 ether &&\n _consensusRewardsDelta <= 332 ether &&\n // new value must be positive\n int256(consensusRewards) + _consensusRewardsDelta >= 0,\n \"Invalid consensusRewardsDelta\"\n );\n require(_ethToVaultAmount <= 32 ether * 3, \"Invalid wethToVaultAmount\");\n\n activeDepositedValidators = uint256(\n int256(activeDepositedValidators) + _validatorsDelta\n );\n consensusRewards = uint256(\n int256(consensusRewards) + _consensusRewardsDelta\n );\n lastFixAccountingBlockNumber = block.number;\n if (_ethToVaultAmount > 0) {\n IWETH9(WETH).deposit{ value: _ethToVaultAmount }();\n // slither-disable-next-line unchecked-transfer\n IWETH9(WETH).transfer(VAULT_ADDRESS, _ethToVaultAmount);\n _wethWithdrawnToVault(_ethToVaultAmount);\n }\n\n emit AccountingManuallyFixed(\n _validatorsDelta,\n _consensusRewardsDelta,\n _ethToVaultAmount\n );\n\n // rerun the accounting to see if it has now been fixed.\n // Do not pause the accounting on failure as it is already paused\n require(_doAccounting(false), \"Fuse still blown\");\n\n // unpause since doAccounting was successful\n _unpause();\n }\n\n /***************************************\n Abstract\n ****************************************/\n\n /// @dev allows for NativeStakingSSVStrategy contract to emit the Withdrawal event\n function _wethWithdrawnToVault(uint256 _amount) internal virtual;\n}\n" + }, + "contracts/strategies/NativeStaking/ValidatorRegistrator.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { Pausable } from \"@openzeppelin/contracts/security/Pausable.sol\";\nimport { Governable } from \"../../governance/Governable.sol\";\nimport { IDepositContract } from \"../../interfaces/IDepositContract.sol\";\nimport { IVault } from \"../../interfaces/IVault.sol\";\nimport { IWETH9 } from \"../../interfaces/IWETH9.sol\";\nimport { ISSVNetwork, Cluster } from \"../../interfaces/ISSVNetwork.sol\";\n\nstruct ValidatorStakeData {\n bytes pubkey;\n bytes signature;\n bytes32 depositDataRoot;\n}\n\n/**\n * @title Registrator of the validators\n * @notice This contract implements all the required functionality to register, exit and remove validators.\n * @author Origin Protocol Inc\n */\nabstract contract ValidatorRegistrator is Governable, Pausable {\n /// @notice The maximum amount of ETH that can be staked by a validator\n /// @dev this can change in the future with EIP-7251, Increase the MAX_EFFECTIVE_BALANCE\n uint256 public constant FULL_STAKE = 32 ether;\n\n /// @notice The address of the Wrapped ETH (WETH) token contract\n address public immutable WETH;\n /// @notice The address of the beacon chain deposit contract\n address public immutable BEACON_CHAIN_DEPOSIT_CONTRACT;\n /// @notice The address of the SSV Network contract used to interface with\n address public immutable SSV_NETWORK;\n /// @notice Address of the OETH Vault proxy contract\n address public immutable VAULT_ADDRESS;\n /// @notice Maximum number of validators that can be registered in this strategy\n uint256 public immutable MAX_VALIDATORS;\n\n /// @notice Address of the registrator - allowed to register, exit and remove validators\n address public validatorRegistrator;\n /// @notice The number of validators that have 32 (!) ETH actively deposited. When a new deposit\n /// to a validator happens this number increases, when a validator exit is detected this number\n /// decreases.\n uint256 public activeDepositedValidators;\n /// @notice State of the validators keccak256(pubKey) => state\n mapping(bytes32 => VALIDATOR_STATE) public validatorsStates;\n /// @notice The account that is allowed to modify stakeETHThreshold and reset stakeETHTally\n address public stakingMonitor;\n /// @notice Amount of ETH that can be staked before staking on the contract is suspended\n /// and the `stakingMonitor` needs to approve further staking by calling `resetStakeETHTally`\n uint256 public stakeETHThreshold;\n /// @notice Amount of ETH that has been staked since the `stakingMonitor` last called `resetStakeETHTally`.\n /// This can not go above `stakeETHThreshold`.\n uint256 public stakeETHTally;\n // For future use\n uint256[47] private __gap;\n\n enum VALIDATOR_STATE {\n NON_REGISTERED, // validator is not registered on the SSV network\n REGISTERED, // validator is registered on the SSV network\n STAKED, // validator has funds staked\n EXITING, // exit message has been posted and validator is in the process of exiting\n EXIT_COMPLETE // validator has funds withdrawn to the EigenPod and is removed from the SSV\n }\n\n event RegistratorChanged(address indexed newAddress);\n event StakingMonitorChanged(address indexed newAddress);\n event ETHStaked(bytes32 indexed pubKeyHash, bytes pubKey, uint256 amount);\n event SSVValidatorRegistered(\n bytes32 indexed pubKeyHash,\n bytes pubKey,\n uint64[] operatorIds\n );\n event SSVValidatorExitInitiated(\n bytes32 indexed pubKeyHash,\n bytes pubKey,\n uint64[] operatorIds\n );\n event SSVValidatorExitCompleted(\n bytes32 indexed pubKeyHash,\n bytes pubKey,\n uint64[] operatorIds\n );\n event StakeETHThresholdChanged(uint256 amount);\n event StakeETHTallyReset();\n\n /// @dev Throws if called by any account other than the Registrator\n modifier onlyRegistrator() {\n require(\n msg.sender == validatorRegistrator,\n \"Caller is not the Registrator\"\n );\n _;\n }\n\n /// @dev Throws if called by any account other than the Staking monitor\n modifier onlyStakingMonitor() {\n require(msg.sender == stakingMonitor, \"Caller is not the Monitor\");\n _;\n }\n\n /// @dev Throws if called by any account other than the Strategist\n modifier onlyStrategist() {\n require(\n msg.sender == IVault(VAULT_ADDRESS).strategistAddr(),\n \"Caller is not the Strategist\"\n );\n _;\n }\n\n /// @param _wethAddress Address of the Erc20 WETH Token contract\n /// @param _vaultAddress Address of the Vault\n /// @param _beaconChainDepositContract Address of the beacon chain deposit contract\n /// @param _ssvNetwork Address of the SSV Network contract\n /// @param _maxValidators Maximum number of validators that can be registered in the strategy\n constructor(\n address _wethAddress,\n address _vaultAddress,\n address _beaconChainDepositContract,\n address _ssvNetwork,\n uint256 _maxValidators\n ) {\n WETH = _wethAddress;\n BEACON_CHAIN_DEPOSIT_CONTRACT = _beaconChainDepositContract;\n SSV_NETWORK = _ssvNetwork;\n VAULT_ADDRESS = _vaultAddress;\n MAX_VALIDATORS = _maxValidators;\n }\n\n /// @notice Set the address of the registrator which can register, exit and remove validators\n function setRegistrator(address _address) external onlyGovernor {\n validatorRegistrator = _address;\n emit RegistratorChanged(_address);\n }\n\n /// @notice Set the address of the staking monitor that is allowed to reset stakeETHTally\n function setStakingMonitor(address _address) external onlyGovernor {\n stakingMonitor = _address;\n emit StakingMonitorChanged(_address);\n }\n\n /// @notice Set the amount of ETH that can be staked before staking monitor\n // needs to a approve further staking by resetting the stake ETH tally\n function setStakeETHThreshold(uint256 _amount) external onlyGovernor {\n stakeETHThreshold = _amount;\n emit StakeETHThresholdChanged(_amount);\n }\n\n /// @notice Reset the stakeETHTally\n function resetStakeETHTally() external onlyStakingMonitor {\n stakeETHTally = 0;\n emit StakeETHTallyReset();\n }\n\n /// @notice Stakes WETH to the node validators\n /// @param validators A list of validator data needed to stake.\n /// The `ValidatorStakeData` struct contains the pubkey, signature and depositDataRoot.\n /// Only the registrator can call this function.\n // slither-disable-start reentrancy-eth\n function stakeEth(ValidatorStakeData[] calldata validators)\n external\n onlyRegistrator\n whenNotPaused\n nonReentrant\n {\n uint256 requiredETH = validators.length * FULL_STAKE;\n\n // Check there is enough WETH from the deposits sitting in this strategy contract\n require(\n requiredETH <= IWETH9(WETH).balanceOf(address(this)),\n \"Insufficient WETH\"\n );\n require(\n activeDepositedValidators + validators.length <= MAX_VALIDATORS,\n \"Max validators reached\"\n );\n\n require(\n stakeETHTally + requiredETH <= stakeETHThreshold,\n \"Staking ETH over threshold\"\n );\n stakeETHTally += requiredETH;\n\n // Convert required ETH from WETH\n IWETH9(WETH).withdraw(requiredETH);\n _wethWithdrawn(requiredETH);\n\n /* 0x01 to indicate that withdrawal credentials will contain an EOA address that the sweeping function\n * can sweep funds to.\n * bytes11(0) to fill up the required zeros\n * remaining bytes20 are for the address\n */\n bytes memory withdrawalCredentials = abi.encodePacked(\n bytes1(0x01),\n bytes11(0),\n address(this)\n );\n\n // For each validator\n for (uint256 i = 0; i < validators.length; ++i) {\n bytes32 pubKeyHash = keccak256(validators[i].pubkey);\n\n require(\n validatorsStates[pubKeyHash] == VALIDATOR_STATE.REGISTERED,\n \"Validator not registered\"\n );\n\n IDepositContract(BEACON_CHAIN_DEPOSIT_CONTRACT).deposit{\n value: FULL_STAKE\n }(\n validators[i].pubkey,\n withdrawalCredentials,\n validators[i].signature,\n validators[i].depositDataRoot\n );\n\n validatorsStates[pubKeyHash] = VALIDATOR_STATE.STAKED;\n\n emit ETHStaked(pubKeyHash, validators[i].pubkey, FULL_STAKE);\n }\n // save gas by changing this storage variable only once rather each time in the loop.\n activeDepositedValidators += validators.length;\n }\n\n // slither-disable-end reentrancy-eth\n\n /// @notice Registers a new validator in the SSV Cluster.\n /// Only the registrator can call this function.\n /// @param publicKeys The public keys of the validators\n /// @param operatorIds The operator IDs of the SSV Cluster\n /// @param sharesData The shares data for each validator\n /// @param ssvAmount The amount of SSV tokens to be deposited to the SSV cluster\n /// @param cluster The SSV cluster details including the validator count and SSV balance\n // slither-disable-start reentrancy-no-eth\n function registerSsvValidators(\n bytes[] calldata publicKeys,\n uint64[] calldata operatorIds,\n bytes[] calldata sharesData,\n uint256 ssvAmount,\n Cluster calldata cluster\n ) external onlyRegistrator whenNotPaused {\n require(\n publicKeys.length == sharesData.length,\n \"Pubkey sharesData mismatch\"\n );\n // Check each public key has not already been used\n bytes32 pubKeyHash;\n VALIDATOR_STATE currentState;\n for (uint256 i = 0; i < publicKeys.length; ++i) {\n pubKeyHash = keccak256(publicKeys[i]);\n currentState = validatorsStates[pubKeyHash];\n require(\n currentState == VALIDATOR_STATE.NON_REGISTERED,\n \"Validator already registered\"\n );\n\n validatorsStates[pubKeyHash] = VALIDATOR_STATE.REGISTERED;\n\n emit SSVValidatorRegistered(pubKeyHash, publicKeys[i], operatorIds);\n }\n\n ISSVNetwork(SSV_NETWORK).bulkRegisterValidator(\n publicKeys,\n operatorIds,\n sharesData,\n ssvAmount,\n cluster\n );\n }\n\n // slither-disable-end reentrancy-no-eth\n\n /// @notice Exit a validator from the Beacon chain.\n /// The staked ETH will eventually swept to this native staking strategy.\n /// Only the registrator can call this function.\n /// @param publicKey The public key of the validator\n /// @param operatorIds The operator IDs of the SSV Cluster\n // slither-disable-start reentrancy-no-eth\n function exitSsvValidator(\n bytes calldata publicKey,\n uint64[] calldata operatorIds\n ) external onlyRegistrator whenNotPaused {\n bytes32 pubKeyHash = keccak256(publicKey);\n VALIDATOR_STATE currentState = validatorsStates[pubKeyHash];\n require(currentState == VALIDATOR_STATE.STAKED, \"Validator not staked\");\n\n ISSVNetwork(SSV_NETWORK).exitValidator(publicKey, operatorIds);\n\n validatorsStates[pubKeyHash] = VALIDATOR_STATE.EXITING;\n\n emit SSVValidatorExitInitiated(pubKeyHash, publicKey, operatorIds);\n }\n\n // slither-disable-end reentrancy-no-eth\n\n /// @notice Remove a validator from the SSV Cluster.\n /// Make sure `exitSsvValidator` is called before and the validate has exited the Beacon chain.\n /// If removed before the validator has exited the beacon chain will result in the validator being slashed.\n /// Only the registrator can call this function.\n /// @param publicKey The public key of the validator\n /// @param operatorIds The operator IDs of the SSV Cluster\n /// @param cluster The SSV cluster details including the validator count and SSV balance\n // slither-disable-start reentrancy-no-eth\n function removeSsvValidator(\n bytes calldata publicKey,\n uint64[] calldata operatorIds,\n Cluster calldata cluster\n ) external onlyRegistrator whenNotPaused {\n bytes32 pubKeyHash = keccak256(publicKey);\n VALIDATOR_STATE currentState = validatorsStates[pubKeyHash];\n require(\n currentState == VALIDATOR_STATE.EXITING,\n \"Validator not exiting\"\n );\n\n ISSVNetwork(SSV_NETWORK).removeValidator(\n publicKey,\n operatorIds,\n cluster\n );\n\n validatorsStates[pubKeyHash] = VALIDATOR_STATE.EXIT_COMPLETE;\n\n emit SSVValidatorExitCompleted(pubKeyHash, publicKey, operatorIds);\n }\n\n // slither-disable-end reentrancy-no-eth\n\n /// @notice Deposits more SSV Tokens to the SSV Network contract which is used to pay the SSV Operators.\n /// @dev A SSV cluster is defined by the SSVOwnerAddress and the set of operatorIds.\n /// uses \"onlyStrategist\" modifier so continuous front-running can't DOS our maintenance service\n /// that tries to top up SSV tokens.\n /// @param operatorIds The operator IDs of the SSV Cluster\n /// @param ssvAmount The amount of SSV tokens to be deposited to the SSV cluster\n /// @param cluster The SSV cluster details including the validator count and SSV balance\n function depositSSV(\n uint64[] memory operatorIds,\n uint256 ssvAmount,\n Cluster memory cluster\n ) external onlyStrategist {\n ISSVNetwork(SSV_NETWORK).deposit(\n address(this),\n operatorIds,\n ssvAmount,\n cluster\n );\n }\n\n /***************************************\n Abstract\n ****************************************/\n\n /// @dev Called when WETH is withdrawn from the strategy or staked to a validator so\n /// the strategy knows how much WETH it has on deposit.\n /// This is so it can emit the correct amount in the Deposit event in depositAll().\n function _wethWithdrawn(uint256 _amount) internal virtual;\n}\n" + }, + "contracts/strategies/ThreePoolStrategy.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @title Curve 3Pool Strategy\n * @notice Investment strategy for investing stablecoins via Curve 3Pool\n * @author Origin Protocol Inc\n */\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nimport { ICurveGauge } from \"./ICurveGauge.sol\";\nimport { ICurvePool } from \"./ICurvePool.sol\";\nimport { ICRVMinter } from \"./ICRVMinter.sol\";\nimport { IERC20, BaseCurveStrategy, InitializableAbstractStrategy } from \"./BaseCurveStrategy.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\nimport { Helpers } from \"../utils/Helpers.sol\";\n\n/*\n * IMPORTANT(!) If ThreePoolStrategy needs to be re-deployed, it requires new\n * proxy contract with fresh storage slots. Changes in `BaseCurveStrategy`\n * storage slots would break existing implementation.\n *\n * Remove this notice if ThreePoolStrategy is re-deployed\n */\ncontract ThreePoolStrategy is BaseCurveStrategy {\n using StableMath for uint256;\n using SafeERC20 for IERC20;\n\n address internal crvGaugeAddress;\n address internal crvMinterAddress;\n\n constructor(BaseStrategyConfig memory _stratConfig)\n InitializableAbstractStrategy(_stratConfig)\n {}\n\n /**\n * Initializer for setting up strategy internal state. This overrides the\n * InitializableAbstractStrategy initializer as Curve strategies don't fit\n * well within that abstraction.\n * @param _rewardTokenAddress Address of CRV\n * @param _assets Addresses of supported assets. MUST be passed in the same\n * order as returned by coins on the pool contract, i.e.\n * DAI, USDC, USDT\n * @param _pTokens Platform Token corresponding addresses\n * @param _crvGaugeAddress Address of the Curve DAO gauge for this pool\n * @param _crvMinterAddress Address of the CRV minter for rewards\n */\n function initialize(\n address[] calldata _rewardTokenAddress, // CRV\n address[] calldata _assets,\n address[] calldata _pTokens,\n address _crvGaugeAddress,\n address _crvMinterAddress\n ) external onlyGovernor initializer {\n require(_assets.length == 3, \"Must have exactly three assets\");\n // Should be set prior to abstract initialize call otherwise\n // abstractSetPToken calls will fail\n crvGaugeAddress = _crvGaugeAddress;\n crvMinterAddress = _crvMinterAddress;\n pTokenAddress = _pTokens[0];\n InitializableAbstractStrategy._initialize(\n _rewardTokenAddress,\n _assets,\n _pTokens\n );\n _approveBase();\n }\n\n function _lpDepositAll() internal override {\n IERC20 pToken = IERC20(pTokenAddress);\n // Deposit into Gauge\n ICurveGauge(crvGaugeAddress).deposit(\n pToken.balanceOf(address(this)),\n address(this)\n );\n }\n\n function _lpWithdraw(uint256 numPTokens) internal override {\n // Not enough of pool token exists on this contract, some must be\n // staked in Gauge, unstake difference\n ICurveGauge(crvGaugeAddress).withdraw(numPTokens);\n }\n\n function _lpWithdrawAll() internal override {\n ICurveGauge gauge = ICurveGauge(crvGaugeAddress);\n gauge.withdraw(gauge.balanceOf(address(this)));\n }\n\n /**\n * @dev Get the total asset value held in the platform\n * @param _asset Address of the asset\n * @return balance Total value of the asset in the platform\n */\n function checkBalance(address _asset)\n public\n view\n override\n returns (uint256 balance)\n {\n require(assetToPToken[_asset] != address(0), \"Unsupported asset\");\n // LP tokens in this contract. This should generally be nothing as we\n // should always stake the full balance in the Gauge, but include for\n // safety\n\n uint256 contractPTokens = IERC20(pTokenAddress).balanceOf(\n address(this)\n );\n ICurveGauge gauge = ICurveGauge(crvGaugeAddress);\n uint256 gaugePTokens = gauge.balanceOf(address(this));\n uint256 totalPTokens = contractPTokens + gaugePTokens;\n\n ICurvePool curvePool = ICurvePool(platformAddress);\n if (totalPTokens > 0) {\n uint256 virtual_price = curvePool.get_virtual_price();\n uint256 value = (totalPTokens * virtual_price) / 1e18;\n uint256 assetDecimals = Helpers.getDecimals(_asset);\n balance = value.scaleBy(assetDecimals, 18) / 3;\n }\n }\n\n function _approveBase() internal override {\n IERC20 pToken = IERC20(pTokenAddress);\n // 3Pool for LP token (required for removing liquidity)\n pToken.safeApprove(platformAddress, 0);\n pToken.safeApprove(platformAddress, type(uint256).max);\n // Gauge for LP token\n pToken.safeApprove(crvGaugeAddress, 0);\n pToken.safeApprove(crvGaugeAddress, type(uint256).max);\n }\n\n /**\n * @dev Collect accumulated CRV and send to Vault.\n */\n function collectRewardTokens() public override onlyHarvester nonReentrant {\n // Collect\n ICRVMinter(crvMinterAddress).mint(crvGaugeAddress);\n // Send\n IERC20 crvToken = IERC20(rewardTokenAddresses[0]);\n uint256 balance = crvToken.balanceOf(address(this));\n emit RewardTokenCollected(\n harvesterAddress,\n rewardTokenAddresses[0],\n balance\n );\n crvToken.safeTransfer(harvesterAddress, balance);\n }\n}\n" + }, + "contracts/strategies/VaultValueChecker.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { IOUSD } from \"../interfaces/IOUSD.sol\";\nimport { IVault } from \"../interfaces/IVault.sol\";\n\ncontract VaultValueChecker {\n IVault public immutable vault;\n IOUSD public immutable ousd;\n // Snapshot expiration time in seconds.\n // Used to prevent accidental use of an old snapshot, but\n // is not zero to allow easy testing of strategist actions in fork testing\n uint256 constant SNAPSHOT_EXPIRES = 5 * 60;\n\n struct Snapshot {\n uint256 vaultValue;\n uint256 totalSupply;\n uint256 time;\n }\n // By doing per user snapshots, we prevent a reentrancy attack\n // from a third party that updates the snapshot in the middle\n // of an allocation process\n\n mapping(address => Snapshot) public snapshots;\n\n constructor(address _vault, address _ousd) {\n vault = IVault(_vault);\n ousd = IOUSD(_ousd);\n }\n\n function takeSnapshot() external {\n snapshots[msg.sender] = Snapshot({\n vaultValue: vault.totalValue(),\n totalSupply: ousd.totalSupply(),\n time: block.timestamp\n });\n }\n\n function checkDelta(\n int256 expectedProfit,\n int256 profitVariance,\n int256 expectedVaultChange,\n int256 vaultChangeVariance\n ) external {\n // Intentionaly not view so that this method shows up in TX builders\n Snapshot memory snapshot = snapshots[msg.sender];\n int256 vaultChange = toInt256(vault.totalValue()) -\n toInt256(snapshot.vaultValue);\n int256 supplyChange = toInt256(ousd.totalSupply()) -\n toInt256(snapshot.totalSupply);\n int256 profit = vaultChange - supplyChange;\n\n require(\n snapshot.time >= block.timestamp - SNAPSHOT_EXPIRES,\n \"Snapshot too old\"\n );\n require(snapshot.time <= block.timestamp, \"Snapshot too new\");\n require(profit >= expectedProfit - profitVariance, \"Profit too low\");\n require(profit <= expectedProfit + profitVariance, \"Profit too high\");\n require(\n vaultChange >= expectedVaultChange - vaultChangeVariance,\n \"Vault value change too low\"\n );\n require(\n vaultChange <= expectedVaultChange + vaultChangeVariance,\n \"Vault value change too high\"\n );\n }\n\n function toInt256(uint256 value) internal pure returns (int256) {\n // From openzeppelin math/SafeCast.sol\n // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive\n require(\n value <= uint256(type(int256).max),\n \"SafeCast: value doesn't fit in an int256\"\n );\n return int256(value);\n }\n}\n\ncontract OETHVaultValueChecker is VaultValueChecker {\n constructor(address _vault, address _ousd)\n VaultValueChecker(_vault, _ousd)\n {}\n}\n" + }, + "contracts/token/OUSD.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @title OUSD Token Contract\n * @dev ERC20 compatible contract for OUSD\n * @dev Implements an elastic supply\n * @author Origin Protocol Inc\n */\nimport { SafeMath } from \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport { Address } from \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport { Initializable } from \"../utils/Initializable.sol\";\nimport { InitializableERC20Detailed } from \"../utils/InitializableERC20Detailed.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\nimport { Governable } from \"../governance/Governable.sol\";\n\n/**\n * NOTE that this is an ERC20 token but the invariant that the sum of\n * balanceOf(x) for all x is not >= totalSupply(). This is a consequence of the\n * rebasing design. Any integrations with OUSD should be aware.\n */\n\ncontract OUSD is Initializable, InitializableERC20Detailed, Governable {\n using SafeMath for uint256;\n using StableMath for uint256;\n\n event TotalSupplyUpdatedHighres(\n uint256 totalSupply,\n uint256 rebasingCredits,\n uint256 rebasingCreditsPerToken\n );\n event AccountRebasingEnabled(address account);\n event AccountRebasingDisabled(address account);\n\n enum RebaseOptions {\n NotSet,\n OptOut,\n OptIn\n }\n\n uint256 private constant MAX_SUPPLY = ~uint128(0); // (2^128) - 1\n uint256 public _totalSupply;\n mapping(address => mapping(address => uint256)) private _allowances;\n address public vaultAddress = address(0);\n mapping(address => uint256) private _creditBalances;\n uint256 private _rebasingCredits;\n uint256 private _rebasingCreditsPerToken;\n // Frozen address/credits are non rebasing (value is held in contracts which\n // do not receive yield unless they explicitly opt in)\n uint256 public nonRebasingSupply;\n mapping(address => uint256) public nonRebasingCreditsPerToken;\n mapping(address => RebaseOptions) public rebaseState;\n mapping(address => uint256) public isUpgraded;\n\n uint256 private constant RESOLUTION_INCREASE = 1e9;\n\n function initialize(\n string calldata _nameArg,\n string calldata _symbolArg,\n address _vaultAddress,\n uint256 _initialCreditsPerToken\n ) external onlyGovernor initializer {\n InitializableERC20Detailed._initialize(_nameArg, _symbolArg, 18);\n _rebasingCreditsPerToken = _initialCreditsPerToken;\n vaultAddress = _vaultAddress;\n }\n\n /**\n * @dev Verifies that the caller is the Vault contract\n */\n modifier onlyVault() {\n require(vaultAddress == msg.sender, \"Caller is not the Vault\");\n _;\n }\n\n /**\n * @return The total supply of OUSD.\n */\n function totalSupply() public view override returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @return Low resolution rebasingCreditsPerToken\n */\n function rebasingCreditsPerToken() public view returns (uint256) {\n return _rebasingCreditsPerToken / RESOLUTION_INCREASE;\n }\n\n /**\n * @return Low resolution total number of rebasing credits\n */\n function rebasingCredits() public view returns (uint256) {\n return _rebasingCredits / RESOLUTION_INCREASE;\n }\n\n /**\n * @return High resolution rebasingCreditsPerToken\n */\n function rebasingCreditsPerTokenHighres() public view returns (uint256) {\n return _rebasingCreditsPerToken;\n }\n\n /**\n * @return High resolution total number of rebasing credits\n */\n function rebasingCreditsHighres() public view returns (uint256) {\n return _rebasingCredits;\n }\n\n /**\n * @dev Gets the balance of the specified address.\n * @param _account Address to query the balance of.\n * @return A uint256 representing the amount of base units owned by the\n * specified address.\n */\n function balanceOf(address _account)\n public\n view\n override\n returns (uint256)\n {\n if (_creditBalances[_account] == 0) return 0;\n return\n _creditBalances[_account].divPrecisely(_creditsPerToken(_account));\n }\n\n /**\n * @dev Gets the credits balance of the specified address.\n * @dev Backwards compatible with old low res credits per token.\n * @param _account The address to query the balance of.\n * @return (uint256, uint256) Credit balance and credits per token of the\n * address\n */\n function creditsBalanceOf(address _account)\n public\n view\n returns (uint256, uint256)\n {\n uint256 cpt = _creditsPerToken(_account);\n if (cpt == 1e27) {\n // For a period before the resolution upgrade, we created all new\n // contract accounts at high resolution. Since they are not changing\n // as a result of this upgrade, we will return their true values\n return (_creditBalances[_account], cpt);\n } else {\n return (\n _creditBalances[_account] / RESOLUTION_INCREASE,\n cpt / RESOLUTION_INCREASE\n );\n }\n }\n\n /**\n * @dev Gets the credits balance of the specified address.\n * @param _account The address to query the balance of.\n * @return (uint256, uint256, bool) Credit balance, credits per token of the\n * address, and isUpgraded\n */\n function creditsBalanceOfHighres(address _account)\n public\n view\n returns (\n uint256,\n uint256,\n bool\n )\n {\n return (\n _creditBalances[_account],\n _creditsPerToken(_account),\n isUpgraded[_account] == 1\n );\n }\n\n /**\n * @dev Transfer tokens to a specified address.\n * @param _to the address to transfer to.\n * @param _value the amount to be transferred.\n * @return true on success.\n */\n function transfer(address _to, uint256 _value)\n public\n override\n returns (bool)\n {\n require(_to != address(0), \"Transfer to zero address\");\n require(\n _value <= balanceOf(msg.sender),\n \"Transfer greater than balance\"\n );\n\n _executeTransfer(msg.sender, _to, _value);\n\n emit Transfer(msg.sender, _to, _value);\n\n return true;\n }\n\n /**\n * @dev Transfer tokens from one address to another.\n * @param _from The address you want to send tokens from.\n * @param _to The address you want to transfer to.\n * @param _value The amount of tokens to be transferred.\n */\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n ) public override returns (bool) {\n require(_to != address(0), \"Transfer to zero address\");\n require(_value <= balanceOf(_from), \"Transfer greater than balance\");\n\n _allowances[_from][msg.sender] = _allowances[_from][msg.sender].sub(\n _value\n );\n\n _executeTransfer(_from, _to, _value);\n\n emit Transfer(_from, _to, _value);\n\n return true;\n }\n\n /**\n * @dev Update the count of non rebasing credits in response to a transfer\n * @param _from The address you want to send tokens from.\n * @param _to The address you want to transfer to.\n * @param _value Amount of OUSD to transfer\n */\n function _executeTransfer(\n address _from,\n address _to,\n uint256 _value\n ) internal {\n bool isNonRebasingTo = _isNonRebasingAccount(_to);\n bool isNonRebasingFrom = _isNonRebasingAccount(_from);\n\n // Credits deducted and credited might be different due to the\n // differing creditsPerToken used by each account\n uint256 creditsCredited = _value.mulTruncate(_creditsPerToken(_to));\n uint256 creditsDeducted = _value.mulTruncate(_creditsPerToken(_from));\n\n _creditBalances[_from] = _creditBalances[_from].sub(\n creditsDeducted,\n \"Transfer amount exceeds balance\"\n );\n _creditBalances[_to] = _creditBalances[_to].add(creditsCredited);\n\n if (isNonRebasingTo && !isNonRebasingFrom) {\n // Transfer to non-rebasing account from rebasing account, credits\n // are removed from the non rebasing tally\n nonRebasingSupply = nonRebasingSupply.add(_value);\n // Update rebasingCredits by subtracting the deducted amount\n _rebasingCredits = _rebasingCredits.sub(creditsDeducted);\n } else if (!isNonRebasingTo && isNonRebasingFrom) {\n // Transfer to rebasing account from non-rebasing account\n // Decreasing non-rebasing credits by the amount that was sent\n nonRebasingSupply = nonRebasingSupply.sub(_value);\n // Update rebasingCredits by adding the credited amount\n _rebasingCredits = _rebasingCredits.add(creditsCredited);\n }\n }\n\n /**\n * @dev Function to check the amount of tokens that _owner has allowed to\n * `_spender`.\n * @param _owner The address which owns the funds.\n * @param _spender The address which will spend the funds.\n * @return The number of tokens still available for the _spender.\n */\n function allowance(address _owner, address _spender)\n public\n view\n override\n returns (uint256)\n {\n return _allowances[_owner][_spender];\n }\n\n /**\n * @dev Approve the passed address to spend the specified amount of tokens\n * on behalf of msg.sender. This method is included for ERC20\n * compatibility. `increaseAllowance` and `decreaseAllowance` should be\n * used instead.\n *\n * Changing an allowance with this method brings the risk that someone\n * may transfer both the old and the new allowance - if they are both\n * greater than zero - if a transfer transaction is mined before the\n * later approve() call is mined.\n * @param _spender The address which will spend the funds.\n * @param _value The amount of tokens to be spent.\n */\n function approve(address _spender, uint256 _value)\n public\n override\n returns (bool)\n {\n _allowances[msg.sender][_spender] = _value;\n emit Approval(msg.sender, _spender, _value);\n return true;\n }\n\n /**\n * @dev Increase the amount of tokens that an owner has allowed to\n * `_spender`.\n * This method should be used instead of approve() to avoid the double\n * approval vulnerability described above.\n * @param _spender The address which will spend the funds.\n * @param _addedValue The amount of tokens to increase the allowance by.\n */\n function increaseAllowance(address _spender, uint256 _addedValue)\n public\n returns (bool)\n {\n _allowances[msg.sender][_spender] = _allowances[msg.sender][_spender]\n .add(_addedValue);\n emit Approval(msg.sender, _spender, _allowances[msg.sender][_spender]);\n return true;\n }\n\n /**\n * @dev Decrease the amount of tokens that an owner has allowed to\n `_spender`.\n * @param _spender The address which will spend the funds.\n * @param _subtractedValue The amount of tokens to decrease the allowance\n * by.\n */\n function decreaseAllowance(address _spender, uint256 _subtractedValue)\n public\n returns (bool)\n {\n uint256 oldValue = _allowances[msg.sender][_spender];\n if (_subtractedValue >= oldValue) {\n _allowances[msg.sender][_spender] = 0;\n } else {\n _allowances[msg.sender][_spender] = oldValue.sub(_subtractedValue);\n }\n emit Approval(msg.sender, _spender, _allowances[msg.sender][_spender]);\n return true;\n }\n\n /**\n * @dev Mints new tokens, increasing totalSupply.\n */\n function mint(address _account, uint256 _amount) external onlyVault {\n _mint(_account, _amount);\n }\n\n /**\n * @dev Creates `_amount` tokens and assigns them to `_account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements\n *\n * - `to` cannot be the zero address.\n */\n function _mint(address _account, uint256 _amount) internal nonReentrant {\n require(_account != address(0), \"Mint to the zero address\");\n\n bool isNonRebasingAccount = _isNonRebasingAccount(_account);\n\n uint256 creditAmount = _amount.mulTruncate(_creditsPerToken(_account));\n _creditBalances[_account] = _creditBalances[_account].add(creditAmount);\n\n // If the account is non rebasing and doesn't have a set creditsPerToken\n // then set it i.e. this is a mint from a fresh contract\n if (isNonRebasingAccount) {\n nonRebasingSupply = nonRebasingSupply.add(_amount);\n } else {\n _rebasingCredits = _rebasingCredits.add(creditAmount);\n }\n\n _totalSupply = _totalSupply.add(_amount);\n\n require(_totalSupply < MAX_SUPPLY, \"Max supply\");\n\n emit Transfer(address(0), _account, _amount);\n }\n\n /**\n * @dev Burns tokens, decreasing totalSupply.\n */\n function burn(address account, uint256 amount) external onlyVault {\n _burn(account, amount);\n }\n\n /**\n * @dev Destroys `_amount` tokens from `_account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements\n *\n * - `_account` cannot be the zero address.\n * - `_account` must have at least `_amount` tokens.\n */\n function _burn(address _account, uint256 _amount) internal nonReentrant {\n require(_account != address(0), \"Burn from the zero address\");\n if (_amount == 0) {\n return;\n }\n\n bool isNonRebasingAccount = _isNonRebasingAccount(_account);\n uint256 creditAmount = _amount.mulTruncate(_creditsPerToken(_account));\n uint256 currentCredits = _creditBalances[_account];\n\n // Remove the credits, burning rounding errors\n if (\n currentCredits == creditAmount || currentCredits - 1 == creditAmount\n ) {\n // Handle dust from rounding\n _creditBalances[_account] = 0;\n } else if (currentCredits > creditAmount) {\n _creditBalances[_account] = _creditBalances[_account].sub(\n creditAmount\n );\n } else {\n revert(\"Remove exceeds balance\");\n }\n\n // Remove from the credit tallies and non-rebasing supply\n if (isNonRebasingAccount) {\n nonRebasingSupply = nonRebasingSupply.sub(_amount);\n } else {\n _rebasingCredits = _rebasingCredits.sub(creditAmount);\n }\n\n _totalSupply = _totalSupply.sub(_amount);\n\n emit Transfer(_account, address(0), _amount);\n }\n\n /**\n * @dev Get the credits per token for an account. Returns a fixed amount\n * if the account is non-rebasing.\n * @param _account Address of the account.\n */\n function _creditsPerToken(address _account)\n internal\n view\n returns (uint256)\n {\n if (nonRebasingCreditsPerToken[_account] != 0) {\n return nonRebasingCreditsPerToken[_account];\n } else {\n return _rebasingCreditsPerToken;\n }\n }\n\n /**\n * @dev Is an account using rebasing accounting or non-rebasing accounting?\n * Also, ensure contracts are non-rebasing if they have not opted in.\n * @param _account Address of the account.\n */\n function _isNonRebasingAccount(address _account) internal returns (bool) {\n bool isContract = Address.isContract(_account);\n if (isContract && rebaseState[_account] == RebaseOptions.NotSet) {\n _ensureRebasingMigration(_account);\n }\n return nonRebasingCreditsPerToken[_account] > 0;\n }\n\n /**\n * @dev Ensures internal account for rebasing and non-rebasing credits and\n * supply is updated following deployment of frozen yield change.\n */\n function _ensureRebasingMigration(address _account) internal {\n if (nonRebasingCreditsPerToken[_account] == 0) {\n emit AccountRebasingDisabled(_account);\n if (_creditBalances[_account] == 0) {\n // Since there is no existing balance, we can directly set to\n // high resolution, and do not have to do any other bookkeeping\n nonRebasingCreditsPerToken[_account] = 1e27;\n } else {\n // Migrate an existing account:\n\n // Set fixed credits per token for this account\n nonRebasingCreditsPerToken[_account] = _rebasingCreditsPerToken;\n // Update non rebasing supply\n nonRebasingSupply = nonRebasingSupply.add(balanceOf(_account));\n // Update credit tallies\n _rebasingCredits = _rebasingCredits.sub(\n _creditBalances[_account]\n );\n }\n }\n }\n\n /**\n * @notice Enable rebasing for an account.\n * @dev Add a contract address to the non-rebasing exception list. The\n * address's balance will be part of rebases and the account will be exposed\n * to upside and downside.\n * @param _account Address of the account.\n */\n function governanceRebaseOptIn(address _account)\n public\n nonReentrant\n onlyGovernor\n {\n _rebaseOptIn(_account);\n }\n\n /**\n * @dev Add a contract address to the non-rebasing exception list. The\n * address's balance will be part of rebases and the account will be exposed\n * to upside and downside.\n */\n function rebaseOptIn() public nonReentrant {\n _rebaseOptIn(msg.sender);\n }\n\n function _rebaseOptIn(address _account) internal {\n require(_isNonRebasingAccount(_account), \"Account has not opted out\");\n\n // Convert balance into the same amount at the current exchange rate\n uint256 newCreditBalance = _creditBalances[_account]\n .mul(_rebasingCreditsPerToken)\n .div(_creditsPerToken(_account));\n\n // Decreasing non rebasing supply\n nonRebasingSupply = nonRebasingSupply.sub(balanceOf(_account));\n\n _creditBalances[_account] = newCreditBalance;\n\n // Increase rebasing credits, totalSupply remains unchanged so no\n // adjustment necessary\n _rebasingCredits = _rebasingCredits.add(_creditBalances[_account]);\n\n rebaseState[_account] = RebaseOptions.OptIn;\n\n // Delete any fixed credits per token\n delete nonRebasingCreditsPerToken[_account];\n emit AccountRebasingEnabled(_account);\n }\n\n /**\n * @dev Explicitly mark that an address is non-rebasing.\n */\n function rebaseOptOut() public nonReentrant {\n require(!_isNonRebasingAccount(msg.sender), \"Account has not opted in\");\n\n // Increase non rebasing supply\n nonRebasingSupply = nonRebasingSupply.add(balanceOf(msg.sender));\n // Set fixed credits per token\n nonRebasingCreditsPerToken[msg.sender] = _rebasingCreditsPerToken;\n\n // Decrease rebasing credits, total supply remains unchanged so no\n // adjustment necessary\n _rebasingCredits = _rebasingCredits.sub(_creditBalances[msg.sender]);\n\n // Mark explicitly opted out of rebasing\n rebaseState[msg.sender] = RebaseOptions.OptOut;\n emit AccountRebasingDisabled(msg.sender);\n }\n\n /**\n * @dev Modify the supply without minting new tokens. This uses a change in\n * the exchange rate between \"credits\" and OUSD tokens to change balances.\n * @param _newTotalSupply New total supply of OUSD.\n */\n function changeSupply(uint256 _newTotalSupply)\n external\n onlyVault\n nonReentrant\n {\n require(_totalSupply > 0, \"Cannot increase 0 supply\");\n\n if (_totalSupply == _newTotalSupply) {\n emit TotalSupplyUpdatedHighres(\n _totalSupply,\n _rebasingCredits,\n _rebasingCreditsPerToken\n );\n return;\n }\n\n _totalSupply = _newTotalSupply > MAX_SUPPLY\n ? MAX_SUPPLY\n : _newTotalSupply;\n\n _rebasingCreditsPerToken = _rebasingCredits.divPrecisely(\n _totalSupply.sub(nonRebasingSupply)\n );\n\n require(_rebasingCreditsPerToken > 0, \"Invalid change in supply\");\n\n _totalSupply = _rebasingCredits\n .divPrecisely(_rebasingCreditsPerToken)\n .add(nonRebasingSupply);\n\n emit TotalSupplyUpdatedHighres(\n _totalSupply,\n _rebasingCredits,\n _rebasingCreditsPerToken\n );\n }\n}\n" + }, + "contracts/utils/BalancerErrors.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n\n// You should have received a copy of the GNU General Public License\n// along with this program. If not, see .\n\npragma solidity >=0.7.4 <0.9.0;\n\n// solhint-disable\n\n/**\n * @dev Reverts if `condition` is false, with a revert reason containing `errorCode`. Only codes up to 999 are\n * supported.\n * Uses the default 'BAL' prefix for the error code\n */\nfunction _require(bool condition, uint256 errorCode) pure {\n if (!condition) _revert(errorCode);\n}\n\n/**\n * @dev Reverts if `condition` is false, with a revert reason containing `errorCode`. Only codes up to 999 are\n * supported.\n */\nfunction _require(\n bool condition,\n uint256 errorCode,\n bytes3 prefix\n) pure {\n if (!condition) _revert(errorCode, prefix);\n}\n\n/**\n * @dev Reverts with a revert reason containing `errorCode`. Only codes up to 999 are supported.\n * Uses the default 'BAL' prefix for the error code\n */\nfunction _revert(uint256 errorCode) pure {\n _revert(errorCode, 0x42414c); // This is the raw byte representation of \"BAL\"\n}\n\n/**\n * @dev Reverts with a revert reason containing `errorCode`. Only codes up to 999 are supported.\n */\nfunction _revert(uint256 errorCode, bytes3 prefix) pure {\n uint256 prefixUint = uint256(uint24(prefix));\n // We're going to dynamically create a revert string based on the error code, with the following format:\n // 'BAL#{errorCode}'\n // where the code is left-padded with zeroes to three digits (so they range from 000 to 999).\n //\n // We don't have revert strings embedded in the contract to save bytecode size: it takes much less space to store a\n // number (8 to 16 bits) than the individual string characters.\n //\n // The dynamic string creation algorithm that follows could be implemented in Solidity, but assembly allows for a\n // much denser implementation, again saving bytecode size. Given this function unconditionally reverts, this is a\n // safe place to rely on it without worrying about how its usage might affect e.g. memory contents.\n assembly {\n // First, we need to compute the ASCII representation of the error code. We assume that it is in the 0-999\n // range, so we only need to convert three digits. To convert the digits to ASCII, we add 0x30, the value for\n // the '0' character.\n\n let units := add(mod(errorCode, 10), 0x30)\n\n errorCode := div(errorCode, 10)\n let tenths := add(mod(errorCode, 10), 0x30)\n\n errorCode := div(errorCode, 10)\n let hundreds := add(mod(errorCode, 10), 0x30)\n\n // With the individual characters, we can now construct the full string.\n // We first append the '#' character (0x23) to the prefix. In the case of 'BAL', it results in 0x42414c23 ('BAL#')\n // Then, we shift this by 24 (to provide space for the 3 bytes of the error code), and add the\n // characters to it, each shifted by a multiple of 8.\n // The revert reason is then shifted left by 200 bits (256 minus the length of the string, 7 characters * 8 bits\n // per character = 56) to locate it in the most significant part of the 256 slot (the beginning of a byte\n // array).\n let formattedPrefix := shl(24, add(0x23, shl(8, prefixUint)))\n\n let revertReason := shl(\n 200,\n add(\n formattedPrefix,\n add(add(units, shl(8, tenths)), shl(16, hundreds))\n )\n )\n\n // We can now encode the reason in memory, which can be safely overwritten as we're about to revert. The encoded\n // message will have the following layout:\n // [ revert reason identifier ] [ string location offset ] [ string length ] [ string contents ]\n\n // The Solidity revert reason identifier is 0x08c739a0, the function selector of the Error(string) function. We\n // also write zeroes to the next 28 bytes of memory, but those are about to be overwritten.\n mstore(\n 0x0,\n 0x08c379a000000000000000000000000000000000000000000000000000000000\n )\n // Next is the offset to the location of the string, which will be placed immediately after (20 bytes away).\n mstore(\n 0x04,\n 0x0000000000000000000000000000000000000000000000000000000000000020\n )\n // The string length is fixed: 7 characters.\n mstore(0x24, 7)\n // Finally, the string itself is stored.\n mstore(0x44, revertReason)\n\n // Even if the string is only 7 bytes long, we need to return a full 32 byte slot containing it. The length of\n // the encoded message is therefore 4 + 32 + 32 + 32 = 100.\n revert(0, 100)\n }\n}\n\nlibrary Errors {\n // Math\n uint256 internal constant ADD_OVERFLOW = 0;\n uint256 internal constant SUB_OVERFLOW = 1;\n uint256 internal constant SUB_UNDERFLOW = 2;\n uint256 internal constant MUL_OVERFLOW = 3;\n uint256 internal constant ZERO_DIVISION = 4;\n uint256 internal constant DIV_INTERNAL = 5;\n uint256 internal constant X_OUT_OF_BOUNDS = 6;\n uint256 internal constant Y_OUT_OF_BOUNDS = 7;\n uint256 internal constant PRODUCT_OUT_OF_BOUNDS = 8;\n uint256 internal constant INVALID_EXPONENT = 9;\n\n // Input\n uint256 internal constant OUT_OF_BOUNDS = 100;\n uint256 internal constant UNSORTED_ARRAY = 101;\n uint256 internal constant UNSORTED_TOKENS = 102;\n uint256 internal constant INPUT_LENGTH_MISMATCH = 103;\n uint256 internal constant ZERO_TOKEN = 104;\n uint256 internal constant INSUFFICIENT_DATA = 105;\n\n // Shared pools\n uint256 internal constant MIN_TOKENS = 200;\n uint256 internal constant MAX_TOKENS = 201;\n uint256 internal constant MAX_SWAP_FEE_PERCENTAGE = 202;\n uint256 internal constant MIN_SWAP_FEE_PERCENTAGE = 203;\n uint256 internal constant MINIMUM_BPT = 204;\n uint256 internal constant CALLER_NOT_VAULT = 205;\n uint256 internal constant UNINITIALIZED = 206;\n uint256 internal constant BPT_IN_MAX_AMOUNT = 207;\n uint256 internal constant BPT_OUT_MIN_AMOUNT = 208;\n uint256 internal constant EXPIRED_PERMIT = 209;\n uint256 internal constant NOT_TWO_TOKENS = 210;\n uint256 internal constant DISABLED = 211;\n\n // Pools\n uint256 internal constant MIN_AMP = 300;\n uint256 internal constant MAX_AMP = 301;\n uint256 internal constant MIN_WEIGHT = 302;\n uint256 internal constant MAX_STABLE_TOKENS = 303;\n uint256 internal constant MAX_IN_RATIO = 304;\n uint256 internal constant MAX_OUT_RATIO = 305;\n uint256 internal constant MIN_BPT_IN_FOR_TOKEN_OUT = 306;\n uint256 internal constant MAX_OUT_BPT_FOR_TOKEN_IN = 307;\n uint256 internal constant NORMALIZED_WEIGHT_INVARIANT = 308;\n uint256 internal constant INVALID_TOKEN = 309;\n uint256 internal constant UNHANDLED_JOIN_KIND = 310;\n uint256 internal constant ZERO_INVARIANT = 311;\n uint256 internal constant ORACLE_INVALID_SECONDS_QUERY = 312;\n uint256 internal constant ORACLE_NOT_INITIALIZED = 313;\n uint256 internal constant ORACLE_QUERY_TOO_OLD = 314;\n uint256 internal constant ORACLE_INVALID_INDEX = 315;\n uint256 internal constant ORACLE_BAD_SECS = 316;\n uint256 internal constant AMP_END_TIME_TOO_CLOSE = 317;\n uint256 internal constant AMP_ONGOING_UPDATE = 318;\n uint256 internal constant AMP_RATE_TOO_HIGH = 319;\n uint256 internal constant AMP_NO_ONGOING_UPDATE = 320;\n uint256 internal constant STABLE_INVARIANT_DIDNT_CONVERGE = 321;\n uint256 internal constant STABLE_GET_BALANCE_DIDNT_CONVERGE = 322;\n uint256 internal constant RELAYER_NOT_CONTRACT = 323;\n uint256 internal constant BASE_POOL_RELAYER_NOT_CALLED = 324;\n uint256 internal constant REBALANCING_RELAYER_REENTERED = 325;\n uint256 internal constant GRADUAL_UPDATE_TIME_TRAVEL = 326;\n uint256 internal constant SWAPS_DISABLED = 327;\n uint256 internal constant CALLER_IS_NOT_LBP_OWNER = 328;\n uint256 internal constant PRICE_RATE_OVERFLOW = 329;\n uint256 internal constant INVALID_JOIN_EXIT_KIND_WHILE_SWAPS_DISABLED = 330;\n uint256 internal constant WEIGHT_CHANGE_TOO_FAST = 331;\n uint256 internal constant LOWER_GREATER_THAN_UPPER_TARGET = 332;\n uint256 internal constant UPPER_TARGET_TOO_HIGH = 333;\n uint256 internal constant UNHANDLED_BY_LINEAR_POOL = 334;\n uint256 internal constant OUT_OF_TARGET_RANGE = 335;\n uint256 internal constant UNHANDLED_EXIT_KIND = 336;\n uint256 internal constant UNAUTHORIZED_EXIT = 337;\n uint256 internal constant MAX_MANAGEMENT_SWAP_FEE_PERCENTAGE = 338;\n uint256 internal constant UNHANDLED_BY_MANAGED_POOL = 339;\n uint256 internal constant UNHANDLED_BY_PHANTOM_POOL = 340;\n uint256 internal constant TOKEN_DOES_NOT_HAVE_RATE_PROVIDER = 341;\n uint256 internal constant INVALID_INITIALIZATION = 342;\n uint256 internal constant OUT_OF_NEW_TARGET_RANGE = 343;\n uint256 internal constant FEATURE_DISABLED = 344;\n uint256 internal constant UNINITIALIZED_POOL_CONTROLLER = 345;\n uint256 internal constant SET_SWAP_FEE_DURING_FEE_CHANGE = 346;\n uint256 internal constant SET_SWAP_FEE_PENDING_FEE_CHANGE = 347;\n uint256 internal constant CHANGE_TOKENS_DURING_WEIGHT_CHANGE = 348;\n uint256 internal constant CHANGE_TOKENS_PENDING_WEIGHT_CHANGE = 349;\n uint256 internal constant MAX_WEIGHT = 350;\n uint256 internal constant UNAUTHORIZED_JOIN = 351;\n uint256 internal constant MAX_MANAGEMENT_AUM_FEE_PERCENTAGE = 352;\n uint256 internal constant FRACTIONAL_TARGET = 353;\n uint256 internal constant ADD_OR_REMOVE_BPT = 354;\n uint256 internal constant INVALID_CIRCUIT_BREAKER_BOUNDS = 355;\n uint256 internal constant CIRCUIT_BREAKER_TRIPPED = 356;\n uint256 internal constant MALICIOUS_QUERY_REVERT = 357;\n uint256 internal constant JOINS_EXITS_DISABLED = 358;\n\n // Lib\n uint256 internal constant REENTRANCY = 400;\n uint256 internal constant SENDER_NOT_ALLOWED = 401;\n uint256 internal constant PAUSED = 402;\n uint256 internal constant PAUSE_WINDOW_EXPIRED = 403;\n uint256 internal constant MAX_PAUSE_WINDOW_DURATION = 404;\n uint256 internal constant MAX_BUFFER_PERIOD_DURATION = 405;\n uint256 internal constant INSUFFICIENT_BALANCE = 406;\n uint256 internal constant INSUFFICIENT_ALLOWANCE = 407;\n uint256 internal constant ERC20_TRANSFER_FROM_ZERO_ADDRESS = 408;\n uint256 internal constant ERC20_TRANSFER_TO_ZERO_ADDRESS = 409;\n uint256 internal constant ERC20_MINT_TO_ZERO_ADDRESS = 410;\n uint256 internal constant ERC20_BURN_FROM_ZERO_ADDRESS = 411;\n uint256 internal constant ERC20_APPROVE_FROM_ZERO_ADDRESS = 412;\n uint256 internal constant ERC20_APPROVE_TO_ZERO_ADDRESS = 413;\n uint256 internal constant ERC20_TRANSFER_EXCEEDS_ALLOWANCE = 414;\n uint256 internal constant ERC20_DECREASED_ALLOWANCE_BELOW_ZERO = 415;\n uint256 internal constant ERC20_TRANSFER_EXCEEDS_BALANCE = 416;\n uint256 internal constant ERC20_BURN_EXCEEDS_ALLOWANCE = 417;\n uint256 internal constant SAFE_ERC20_CALL_FAILED = 418;\n uint256 internal constant ADDRESS_INSUFFICIENT_BALANCE = 419;\n uint256 internal constant ADDRESS_CANNOT_SEND_VALUE = 420;\n uint256 internal constant SAFE_CAST_VALUE_CANT_FIT_INT256 = 421;\n uint256 internal constant GRANT_SENDER_NOT_ADMIN = 422;\n uint256 internal constant REVOKE_SENDER_NOT_ADMIN = 423;\n uint256 internal constant RENOUNCE_SENDER_NOT_ALLOWED = 424;\n uint256 internal constant BUFFER_PERIOD_EXPIRED = 425;\n uint256 internal constant CALLER_IS_NOT_OWNER = 426;\n uint256 internal constant NEW_OWNER_IS_ZERO = 427;\n uint256 internal constant CODE_DEPLOYMENT_FAILED = 428;\n uint256 internal constant CALL_TO_NON_CONTRACT = 429;\n uint256 internal constant LOW_LEVEL_CALL_FAILED = 430;\n uint256 internal constant NOT_PAUSED = 431;\n uint256 internal constant ADDRESS_ALREADY_ALLOWLISTED = 432;\n uint256 internal constant ADDRESS_NOT_ALLOWLISTED = 433;\n uint256 internal constant ERC20_BURN_EXCEEDS_BALANCE = 434;\n uint256 internal constant INVALID_OPERATION = 435;\n uint256 internal constant CODEC_OVERFLOW = 436;\n uint256 internal constant IN_RECOVERY_MODE = 437;\n uint256 internal constant NOT_IN_RECOVERY_MODE = 438;\n uint256 internal constant INDUCED_FAILURE = 439;\n uint256 internal constant EXPIRED_SIGNATURE = 440;\n uint256 internal constant MALFORMED_SIGNATURE = 441;\n uint256 internal constant SAFE_CAST_VALUE_CANT_FIT_UINT64 = 442;\n uint256 internal constant UNHANDLED_FEE_TYPE = 443;\n uint256 internal constant BURN_FROM_ZERO = 444;\n\n // Vault\n uint256 internal constant INVALID_POOL_ID = 500;\n uint256 internal constant CALLER_NOT_POOL = 501;\n uint256 internal constant SENDER_NOT_ASSET_MANAGER = 502;\n uint256 internal constant USER_DOESNT_ALLOW_RELAYER = 503;\n uint256 internal constant INVALID_SIGNATURE = 504;\n uint256 internal constant EXIT_BELOW_MIN = 505;\n uint256 internal constant JOIN_ABOVE_MAX = 506;\n uint256 internal constant SWAP_LIMIT = 507;\n uint256 internal constant SWAP_DEADLINE = 508;\n uint256 internal constant CANNOT_SWAP_SAME_TOKEN = 509;\n uint256 internal constant UNKNOWN_AMOUNT_IN_FIRST_SWAP = 510;\n uint256 internal constant MALCONSTRUCTED_MULTIHOP_SWAP = 511;\n uint256 internal constant INTERNAL_BALANCE_OVERFLOW = 512;\n uint256 internal constant INSUFFICIENT_INTERNAL_BALANCE = 513;\n uint256 internal constant INVALID_ETH_INTERNAL_BALANCE = 514;\n uint256 internal constant INVALID_POST_LOAN_BALANCE = 515;\n uint256 internal constant INSUFFICIENT_ETH = 516;\n uint256 internal constant UNALLOCATED_ETH = 517;\n uint256 internal constant ETH_TRANSFER = 518;\n uint256 internal constant CANNOT_USE_ETH_SENTINEL = 519;\n uint256 internal constant TOKENS_MISMATCH = 520;\n uint256 internal constant TOKEN_NOT_REGISTERED = 521;\n uint256 internal constant TOKEN_ALREADY_REGISTERED = 522;\n uint256 internal constant TOKENS_ALREADY_SET = 523;\n uint256 internal constant TOKENS_LENGTH_MUST_BE_2 = 524;\n uint256 internal constant NONZERO_TOKEN_BALANCE = 525;\n uint256 internal constant BALANCE_TOTAL_OVERFLOW = 526;\n uint256 internal constant POOL_NO_TOKENS = 527;\n uint256 internal constant INSUFFICIENT_FLASH_LOAN_BALANCE = 528;\n\n // Fees\n uint256 internal constant SWAP_FEE_PERCENTAGE_TOO_HIGH = 600;\n uint256 internal constant FLASH_LOAN_FEE_PERCENTAGE_TOO_HIGH = 601;\n uint256 internal constant INSUFFICIENT_FLASH_LOAN_FEE_AMOUNT = 602;\n uint256 internal constant AUM_FEE_PERCENTAGE_TOO_HIGH = 603;\n\n // FeeSplitter\n uint256 internal constant SPLITTER_FEE_PERCENTAGE_TOO_HIGH = 700;\n\n // Misc\n uint256 internal constant UNIMPLEMENTED = 998;\n uint256 internal constant SHOULD_NOT_HAPPEN = 999;\n}\n" + }, + "contracts/utils/Helpers.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { IBasicToken } from \"../interfaces/IBasicToken.sol\";\n\nlibrary Helpers {\n /**\n * @notice Fetch the `symbol()` from an ERC20 token\n * @dev Grabs the `symbol()` from a contract\n * @param _token Address of the ERC20 token\n * @return string Symbol of the ERC20 token\n */\n function getSymbol(address _token) internal view returns (string memory) {\n string memory symbol = IBasicToken(_token).symbol();\n return symbol;\n }\n\n /**\n * @notice Fetch the `decimals()` from an ERC20 token\n * @dev Grabs the `decimals()` from a contract and fails if\n * the decimal value does not live within a certain range\n * @param _token Address of the ERC20 token\n * @return uint256 Decimals of the ERC20 token\n */\n function getDecimals(address _token) internal view returns (uint256) {\n uint256 decimals = IBasicToken(_token).decimals();\n require(\n decimals >= 4 && decimals <= 18,\n \"Token must have sufficient decimal places\"\n );\n\n return decimals;\n }\n}\n" + }, + "contracts/utils/Initializable.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @title Base contract any contracts that need to initialize state after deployment.\n * @author Origin Protocol Inc\n */\nabstract contract Initializable {\n /**\n * @dev Indicates that the contract has been initialized.\n */\n bool private initialized;\n\n /**\n * @dev Indicates that the contract is in the process of being initialized.\n */\n bool private initializing;\n\n /**\n * @dev Modifier to protect an initializer function from being invoked twice.\n */\n modifier initializer() {\n require(\n initializing || !initialized,\n \"Initializable: contract is already initialized\"\n );\n\n bool isTopLevelCall = !initializing;\n if (isTopLevelCall) {\n initializing = true;\n initialized = true;\n }\n\n _;\n\n if (isTopLevelCall) {\n initializing = false;\n }\n }\n\n uint256[50] private ______gap;\n}\n" + }, + "contracts/utils/InitializableAbstractStrategy.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @title Base contract for vault strategies.\n * @author Origin Protocol Inc\n */\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nimport { Initializable } from \"../utils/Initializable.sol\";\nimport { Governable } from \"../governance/Governable.sol\";\nimport { IVault } from \"../interfaces/IVault.sol\";\n\nabstract contract InitializableAbstractStrategy is Initializable, Governable {\n using SafeERC20 for IERC20;\n\n event PTokenAdded(address indexed _asset, address _pToken);\n event PTokenRemoved(address indexed _asset, address _pToken);\n event Deposit(address indexed _asset, address _pToken, uint256 _amount);\n event Withdrawal(address indexed _asset, address _pToken, uint256 _amount);\n event RewardTokenCollected(\n address recipient,\n address rewardToken,\n uint256 amount\n );\n event RewardTokenAddressesUpdated(\n address[] _oldAddresses,\n address[] _newAddresses\n );\n event HarvesterAddressesUpdated(\n address _oldHarvesterAddress,\n address _newHarvesterAddress\n );\n\n /// @notice Address of the underlying platform\n address public immutable platformAddress;\n /// @notice Address of the OToken vault\n address public immutable vaultAddress;\n\n /// @dev Replaced with an immutable variable\n // slither-disable-next-line constable-states\n address private _deprecated_platformAddress;\n\n /// @dev Replaced with an immutable\n // slither-disable-next-line constable-states\n address private _deprecated_vaultAddress;\n\n /// @notice asset => pToken (Platform Specific Token Address)\n mapping(address => address) public assetToPToken;\n\n /// @notice Full list of all assets supported by the strategy\n address[] internal assetsMapped;\n\n // Deprecated: Reward token address\n // slither-disable-next-line constable-states\n address private _deprecated_rewardTokenAddress;\n\n // Deprecated: now resides in Harvester's rewardTokenConfigs\n // slither-disable-next-line constable-states\n uint256 private _deprecated_rewardLiquidationThreshold;\n\n /// @notice Address of the Harvester contract allowed to collect reward tokens\n address public harvesterAddress;\n\n /// @notice Address of the reward tokens. eg CRV, BAL, CVX, AURA\n address[] public rewardTokenAddresses;\n\n /* Reserved for future expansion. Used to be 100 storage slots\n * and has decreased to accommodate:\n * - harvesterAddress\n * - rewardTokenAddresses\n */\n int256[98] private _reserved;\n\n struct BaseStrategyConfig {\n address platformAddress; // Address of the underlying platform\n address vaultAddress; // Address of the OToken's Vault\n }\n\n /**\n * @param _config The platform and OToken vault addresses\n */\n constructor(BaseStrategyConfig memory _config) {\n platformAddress = _config.platformAddress;\n vaultAddress = _config.vaultAddress;\n }\n\n /**\n * @dev Internal initialize function, to set up initial internal state\n * @param _rewardTokenAddresses Address of reward token for platform\n * @param _assets Addresses of initial supported assets\n * @param _pTokens Platform Token corresponding addresses\n */\n function _initialize(\n address[] memory _rewardTokenAddresses,\n address[] memory _assets,\n address[] memory _pTokens\n ) internal {\n rewardTokenAddresses = _rewardTokenAddresses;\n\n uint256 assetCount = _assets.length;\n require(assetCount == _pTokens.length, \"Invalid input arrays\");\n for (uint256 i = 0; i < assetCount; ++i) {\n _setPTokenAddress(_assets[i], _pTokens[i]);\n }\n }\n\n /**\n * @notice Collect accumulated reward token and send to Vault.\n */\n function collectRewardTokens() external virtual onlyHarvester nonReentrant {\n _collectRewardTokens();\n }\n\n /**\n * @dev Default implementation that transfers reward tokens to the Harvester\n * Implementing strategies need to add custom logic to collect the rewards.\n */\n function _collectRewardTokens() internal virtual {\n uint256 rewardTokenCount = rewardTokenAddresses.length;\n for (uint256 i = 0; i < rewardTokenCount; ++i) {\n IERC20 rewardToken = IERC20(rewardTokenAddresses[i]);\n uint256 balance = rewardToken.balanceOf(address(this));\n if (balance > 0) {\n emit RewardTokenCollected(\n harvesterAddress,\n address(rewardToken),\n balance\n );\n rewardToken.safeTransfer(harvesterAddress, balance);\n }\n }\n }\n\n /**\n * @dev Verifies that the caller is the Vault.\n */\n modifier onlyVault() {\n require(msg.sender == vaultAddress, \"Caller is not the Vault\");\n _;\n }\n\n /**\n * @dev Verifies that the caller is the Harvester.\n */\n modifier onlyHarvester() {\n require(msg.sender == harvesterAddress, \"Caller is not the Harvester\");\n _;\n }\n\n /**\n * @dev Verifies that the caller is the Vault or Governor.\n */\n modifier onlyVaultOrGovernor() {\n require(\n msg.sender == vaultAddress || msg.sender == governor(),\n \"Caller is not the Vault or Governor\"\n );\n _;\n }\n\n /**\n * @dev Verifies that the caller is the Vault, Governor, or Strategist.\n */\n modifier onlyVaultOrGovernorOrStrategist() {\n require(\n msg.sender == vaultAddress ||\n msg.sender == governor() ||\n msg.sender == IVault(vaultAddress).strategistAddr(),\n \"Caller is not the Vault, Governor, or Strategist\"\n );\n _;\n }\n\n /**\n * @notice Set the reward token addresses. Any old addresses will be overwritten.\n * @param _rewardTokenAddresses Array of reward token addresses\n */\n function setRewardTokenAddresses(address[] calldata _rewardTokenAddresses)\n external\n onlyGovernor\n {\n uint256 rewardTokenCount = _rewardTokenAddresses.length;\n for (uint256 i = 0; i < rewardTokenCount; ++i) {\n require(\n _rewardTokenAddresses[i] != address(0),\n \"Can not set an empty address as a reward token\"\n );\n }\n\n emit RewardTokenAddressesUpdated(\n rewardTokenAddresses,\n _rewardTokenAddresses\n );\n rewardTokenAddresses = _rewardTokenAddresses;\n }\n\n /**\n * @notice Get the reward token addresses.\n * @return address[] the reward token addresses.\n */\n function getRewardTokenAddresses()\n external\n view\n returns (address[] memory)\n {\n return rewardTokenAddresses;\n }\n\n /**\n * @notice Provide support for asset by passing its pToken address.\n * This method can only be called by the system Governor\n * @param _asset Address for the asset\n * @param _pToken Address for the corresponding platform token\n */\n function setPTokenAddress(address _asset, address _pToken)\n external\n virtual\n onlyGovernor\n {\n _setPTokenAddress(_asset, _pToken);\n }\n\n /**\n * @notice Remove a supported asset by passing its index.\n * This method can only be called by the system Governor\n * @param _assetIndex Index of the asset to be removed\n */\n function removePToken(uint256 _assetIndex) external virtual onlyGovernor {\n require(_assetIndex < assetsMapped.length, \"Invalid index\");\n address asset = assetsMapped[_assetIndex];\n address pToken = assetToPToken[asset];\n\n if (_assetIndex < assetsMapped.length - 1) {\n assetsMapped[_assetIndex] = assetsMapped[assetsMapped.length - 1];\n }\n assetsMapped.pop();\n assetToPToken[asset] = address(0);\n\n emit PTokenRemoved(asset, pToken);\n }\n\n /**\n * @notice Provide support for asset by passing its pToken address.\n * Add to internal mappings and execute the platform specific,\n * abstract method `_abstractSetPToken`\n * @param _asset Address for the asset\n * @param _pToken Address for the corresponding platform token\n */\n function _setPTokenAddress(address _asset, address _pToken) internal {\n require(assetToPToken[_asset] == address(0), \"pToken already set\");\n require(\n _asset != address(0) && _pToken != address(0),\n \"Invalid addresses\"\n );\n\n assetToPToken[_asset] = _pToken;\n assetsMapped.push(_asset);\n\n emit PTokenAdded(_asset, _pToken);\n\n _abstractSetPToken(_asset, _pToken);\n }\n\n /**\n * @notice Transfer token to governor. Intended for recovering tokens stuck in\n * strategy contracts, i.e. mistaken sends.\n * @param _asset Address for the asset\n * @param _amount Amount of the asset to transfer\n */\n function transferToken(address _asset, uint256 _amount)\n public\n onlyGovernor\n {\n require(!supportsAsset(_asset), \"Cannot transfer supported asset\");\n IERC20(_asset).safeTransfer(governor(), _amount);\n }\n\n /**\n * @notice Set the Harvester contract that can collect rewards.\n * @param _harvesterAddress Address of the harvester contract.\n */\n function setHarvesterAddress(address _harvesterAddress)\n external\n onlyGovernor\n {\n emit HarvesterAddressesUpdated(harvesterAddress, _harvesterAddress);\n harvesterAddress = _harvesterAddress;\n }\n\n /***************************************\n Abstract\n ****************************************/\n\n function _abstractSetPToken(address _asset, address _pToken)\n internal\n virtual;\n\n function safeApproveAllTokens() external virtual;\n\n /**\n * @notice Deposit an amount of assets into the platform\n * @param _asset Address for the asset\n * @param _amount Units of asset to deposit\n */\n function deposit(address _asset, uint256 _amount) external virtual;\n\n /**\n * @notice Deposit all supported assets in this strategy contract to the platform\n */\n function depositAll() external virtual;\n\n /**\n * @notice Withdraw an `amount` of assets from the platform and\n * send to the `_recipient`.\n * @param _recipient Address to which the asset should be sent\n * @param _asset Address of the asset\n * @param _amount Units of asset to withdraw\n */\n function withdraw(\n address _recipient,\n address _asset,\n uint256 _amount\n ) external virtual;\n\n /**\n * @notice Withdraw all supported assets from platform and\n * sends to the OToken's Vault.\n */\n function withdrawAll() external virtual;\n\n /**\n * @notice Get the total asset value held in the platform.\n * This includes any interest that was generated since depositing.\n * @param _asset Address of the asset\n * @return balance Total value of the asset in the platform\n */\n function checkBalance(address _asset)\n external\n view\n virtual\n returns (uint256 balance);\n\n /**\n * @notice Check if an asset is supported.\n * @param _asset Address of the asset\n * @return bool Whether asset is supported\n */\n function supportsAsset(address _asset) public view virtual returns (bool);\n}\n" + }, + "contracts/utils/InitializableERC20Detailed.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @dev Optional functions from the ERC20 standard.\n * Converted from openzeppelin/contracts/token/ERC20/ERC20Detailed.sol\n * @author Origin Protocol Inc\n */\nabstract contract InitializableERC20Detailed is IERC20 {\n // Storage gap to skip storage from prior to OUSD reset\n uint256[100] private _____gap;\n\n string private _name;\n string private _symbol;\n uint8 private _decimals;\n\n /**\n * @dev Sets the values for `name`, `symbol`, and `decimals`. All three of\n * these values are immutable: they can only be set once during\n * construction.\n * @notice To avoid variable shadowing appended `Arg` after arguments name.\n */\n function _initialize(\n string memory nameArg,\n string memory symbolArg,\n uint8 decimalsArg\n ) internal {\n _name = nameArg;\n _symbol = symbolArg;\n _decimals = decimalsArg;\n }\n\n /**\n * @notice Returns the name of the token.\n */\n function name() public view returns (string memory) {\n return _name;\n }\n\n /**\n * @notice Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view returns (string memory) {\n return _symbol;\n }\n\n /**\n * @notice Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5,05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei.\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view returns (uint8) {\n return _decimals;\n }\n}\n" + }, + "contracts/utils/StableMath.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { SafeMath } from \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\n\n// Based on StableMath from Stability Labs Pty. Ltd.\n// https://github.com/mstable/mStable-contracts/blob/master/contracts/shared/StableMath.sol\n\nlibrary StableMath {\n using SafeMath for uint256;\n\n /**\n * @dev Scaling unit for use in specific calculations,\n * where 1 * 10**18, or 1e18 represents a unit '1'\n */\n uint256 private constant FULL_SCALE = 1e18;\n\n /***************************************\n Helpers\n ****************************************/\n\n /**\n * @dev Adjust the scale of an integer\n * @param to Decimals to scale to\n * @param from Decimals to scale from\n */\n function scaleBy(\n uint256 x,\n uint256 to,\n uint256 from\n ) internal pure returns (uint256) {\n if (to > from) {\n x = x.mul(10**(to - from));\n } else if (to < from) {\n // slither-disable-next-line divide-before-multiply\n x = x.div(10**(from - to));\n }\n return x;\n }\n\n /***************************************\n Precise Arithmetic\n ****************************************/\n\n /**\n * @dev Multiplies two precise units, and then truncates by the full scale\n * @param x Left hand input to multiplication\n * @param y Right hand input to multiplication\n * @return Result after multiplying the two inputs and then dividing by the shared\n * scale unit\n */\n function mulTruncate(uint256 x, uint256 y) internal pure returns (uint256) {\n return mulTruncateScale(x, y, FULL_SCALE);\n }\n\n /**\n * @dev Multiplies two precise units, and then truncates by the given scale. For example,\n * when calculating 90% of 10e18, (10e18 * 9e17) / 1e18 = (9e36) / 1e18 = 9e18\n * @param x Left hand input to multiplication\n * @param y Right hand input to multiplication\n * @param scale Scale unit\n * @return Result after multiplying the two inputs and then dividing by the shared\n * scale unit\n */\n function mulTruncateScale(\n uint256 x,\n uint256 y,\n uint256 scale\n ) internal pure returns (uint256) {\n // e.g. assume scale = fullScale\n // z = 10e18 * 9e17 = 9e36\n uint256 z = x.mul(y);\n // return 9e36 / 1e18 = 9e18\n return z.div(scale);\n }\n\n /**\n * @dev Multiplies two precise units, and then truncates by the full scale, rounding up the result\n * @param x Left hand input to multiplication\n * @param y Right hand input to multiplication\n * @return Result after multiplying the two inputs and then dividing by the shared\n * scale unit, rounded up to the closest base unit.\n */\n function mulTruncateCeil(uint256 x, uint256 y)\n internal\n pure\n returns (uint256)\n {\n // e.g. 8e17 * 17268172638 = 138145381104e17\n uint256 scaled = x.mul(y);\n // e.g. 138145381104e17 + 9.99...e17 = 138145381113.99...e17\n uint256 ceil = scaled.add(FULL_SCALE.sub(1));\n // e.g. 13814538111.399...e18 / 1e18 = 13814538111\n return ceil.div(FULL_SCALE);\n }\n\n /**\n * @dev Precisely divides two units, by first scaling the left hand operand. Useful\n * for finding percentage weightings, i.e. 8e18/10e18 = 80% (or 8e17)\n * @param x Left hand input to division\n * @param y Right hand input to division\n * @return Result after multiplying the left operand by the scale, and\n * executing the division on the right hand input.\n */\n function divPrecisely(uint256 x, uint256 y)\n internal\n pure\n returns (uint256)\n {\n // e.g. 8e18 * 1e18 = 8e36\n uint256 z = x.mul(FULL_SCALE);\n // e.g. 8e36 / 10e18 = 8e17\n return z.div(y);\n }\n}\n" + }, + "contracts/vault/OETHVault.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { Vault } from \"./Vault.sol\";\n\n/**\n * @title OETH Vault Contract\n * @author Origin Protocol Inc\n */\ncontract OETHVault is Vault {\n\n}\n" + }, + "contracts/vault/OETHVaultAdmin.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\nimport { IStrategy } from \"../interfaces/IStrategy.sol\";\nimport { IVault } from \"../interfaces/IVault.sol\";\nimport { VaultAdmin } from \"./VaultAdmin.sol\";\n\n/**\n * @title OETH VaultAdmin Contract\n * @author Origin Protocol Inc\n */\ncontract OETHVaultAdmin is VaultAdmin {\n using SafeERC20 for IERC20;\n\n address public immutable weth;\n\n constructor(address _weth) {\n weth = _weth;\n }\n\n /// @dev Simplified version of the deposit function as WETH is the only supported asset.\n function _depositToStrategy(\n address _strategyToAddress,\n address[] calldata _assets,\n uint256[] calldata _amounts\n ) internal override {\n require(\n strategies[_strategyToAddress].isSupported,\n \"Invalid to Strategy\"\n );\n require(\n _assets.length == 1 && _amounts.length == 1 && _assets[0] == weth,\n \"Only WETH is supported\"\n );\n\n // Check the there is enough WETH to transfer once the WETH reserved for the withdrawal queue is accounted for\n require(_amounts[0] <= _wethAvailable(), \"Not enough WETH available\");\n\n // Send required amount of funds to the strategy\n IERC20(weth).safeTransfer(_strategyToAddress, _amounts[0]);\n\n // Deposit all the funds that have been sent to the strategy\n IStrategy(_strategyToAddress).depositAll();\n }\n\n function _withdrawFromStrategy(\n address _recipient,\n address _strategyFromAddress,\n address[] calldata _assets,\n uint256[] calldata _amounts\n ) internal override {\n super._withdrawFromStrategy(\n _recipient,\n _strategyFromAddress,\n _assets,\n _amounts\n );\n\n IVault(address(this)).addWithdrawalQueueLiquidity();\n }\n\n function _withdrawAllFromStrategy(address _strategyAddr) internal override {\n super._withdrawAllFromStrategy(_strategyAddr);\n\n IVault(address(this)).addWithdrawalQueueLiquidity();\n }\n\n function _withdrawAllFromStrategies() internal override {\n super._withdrawAllFromStrategies();\n\n IVault(address(this)).addWithdrawalQueueLiquidity();\n }\n\n // TODO move to a library?\n function _wethAvailable() internal view returns (uint256 wethAvailable) {\n WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata;\n\n // Check if the claimable WETH is less than the queued amount\n uint256 queueShortfall = queue.queued - queue.claimable;\n uint256 wethBalance = IERC20(weth).balanceOf(address(this));\n // Of the claimable withdrawal requests, how much is unclaimed?\n uint256 unclaimed = queue.claimable - queue.claimed;\n\n if (wethBalance > queueShortfall + unclaimed) {\n wethAvailable = wethBalance - queueShortfall - unclaimed;\n }\n }\n\n function _swapCollateral(\n address _fromAsset,\n address _toAsset,\n uint256 _fromAssetAmount,\n uint256 _minToAssetAmount,\n bytes calldata _data\n ) internal override returns (uint256 toAssetAmount) {\n require(_fromAsset != weth, \"swap from WETH not supported\");\n require(_toAsset == weth, \"only swap to WETH\");\n toAssetAmount = super._swapCollateral(\n _fromAsset,\n _toAsset,\n _fromAssetAmount,\n _minToAssetAmount,\n _data\n );\n\n // Add any new WETH to the withdrawal queue first\n IVault(address(this)).addWithdrawalQueueLiquidity();\n }\n}\n" + }, + "contracts/vault/OETHVaultCore.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { StableMath } from \"../utils/StableMath.sol\";\nimport { VaultCore } from \"./VaultCore.sol\";\n\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { IStrategy } from \"../interfaces/IStrategy.sol\";\nimport { IDripper } from \"../interfaces/IDripper.sol\";\n\n/**\n * @title OETH VaultCore Contract\n * @author Origin Protocol Inc\n */\ncontract OETHVaultCore is VaultCore {\n using SafeERC20 for IERC20;\n using StableMath for uint256;\n\n address public immutable weth;\n uint256 public wethAssetIndex;\n\n constructor(address _weth) {\n weth = _weth;\n }\n\n /**\n * @dev Caches WETH's index in `allAssets` variable.\n * Reduces gas usage by redeem by caching that.\n */\n function cacheWETHAssetIndex() external onlyGovernor {\n uint256 assetCount = allAssets.length;\n for (uint256 i = 0; i < assetCount; ++i) {\n if (allAssets[i] == weth) {\n wethAssetIndex = i;\n break;\n }\n }\n\n require(allAssets[wethAssetIndex] == weth, \"Invalid WETH Asset Index\");\n }\n\n // @inheritdoc VaultCore\n // slither-disable-start reentrancy-no-eth\n function _mint(\n address _asset,\n uint256 _amount,\n uint256 _minimumOusdAmount\n ) internal virtual override {\n require(_asset == weth, \"Unsupported asset for minting\");\n require(_amount > 0, \"Amount must be greater than 0\");\n require(\n _amount >= _minimumOusdAmount,\n \"Mint amount lower than minimum\"\n );\n\n emit Mint(msg.sender, _amount);\n\n // Rebase must happen before any transfers occur.\n if (!rebasePaused && _amount >= rebaseThreshold) {\n // Stream any harvested rewards (WETH) that are available to the Vault\n IDripper(dripper).collect();\n\n _rebase();\n }\n\n // Mint oTokens\n oUSD.mint(msg.sender, _amount);\n\n // Transfer the deposited coins to the vault\n IERC20(_asset).safeTransferFrom(msg.sender, address(this), _amount);\n\n // Give priority to the withdrawal queue for the new WETH liquidity\n _addWithdrawalQueueLiquidity();\n\n // Auto-allocate if necessary\n if (_amount >= autoAllocateThreshold) {\n _allocate();\n }\n }\n\n // slither-disable-end reentrancy-no-eth\n\n // @inheritdoc VaultCore\n function _calculateRedeemOutputs(uint256 _amount)\n internal\n view\n virtual\n override\n returns (uint256[] memory outputs)\n {\n // Overrides `VaultCore._calculateRedeemOutputs` to redeem with only\n // WETH instead of LST-mix. Doesn't change the function signature\n // for backward compatibility\n\n // Calculate redeem fee\n if (redeemFeeBps > 0) {\n uint256 redeemFee = _amount.mulTruncateScale(redeemFeeBps, 1e4);\n _amount = _amount - redeemFee;\n }\n\n // Ensure that the WETH index is cached\n uint256 _wethAssetIndex = wethAssetIndex;\n require(\n allAssets[_wethAssetIndex] == weth,\n \"WETH Asset index not cached\"\n );\n\n outputs = new uint256[](allAssets.length);\n outputs[_wethAssetIndex] = _amount;\n }\n\n // @inheritdoc VaultCore\n function _redeem(uint256 _amount, uint256 _minimumUnitAmount)\n internal\n virtual\n override\n {\n // Override `VaultCore._redeem` to simplify it. Gets rid of oracle\n // usage and looping through all assets for LST-mix redeem. Instead\n // does a simple WETH-only redeem.\n emit Redeem(msg.sender, _amount);\n\n if (_amount == 0) {\n return;\n }\n\n // Amount excluding fees\n uint256 amountMinusFee = _calculateRedeemOutputs(_amount)[\n wethAssetIndex\n ];\n\n require(\n amountMinusFee >= _minimumUnitAmount,\n \"Redeem amount lower than minimum\"\n );\n\n // If there is any WETH in the Vault available after accounting for the withdrawal queue\n if (_wethAvailable() >= amountMinusFee) {\n // Use Vault funds first if sufficient\n IERC20(weth).safeTransfer(msg.sender, amountMinusFee);\n } else {\n address strategyAddr = assetDefaultStrategies[weth];\n if (strategyAddr != address(0)) {\n // Nothing in Vault, but something in Strategy, send from there\n IStrategy strategy = IStrategy(strategyAddr);\n strategy.withdraw(msg.sender, weth, amountMinusFee);\n } else {\n // Cant find funds anywhere\n revert(\"Liquidity error\");\n }\n }\n\n // Burn OETH from user (including fees)\n oUSD.burn(msg.sender, _amount);\n\n _postRedeem(_amount);\n }\n\n /**\n * @notice Request an asynchronous withdrawal of the underlying asset. eg WETH\n * @param _amount Amount of oTokens to burn. eg OETH\n * @param requestId Unique ID for the withdrawal request\n * @param queued Cumulative total of all WETH queued including already claimed requests.\n * This request can be claimed once the withdrawal queue's claimable amount\n * is greater than or equal this request's queued amount.\n */\n function requestWithdrawal(uint256 _amount)\n external\n whenNotCapitalPaused\n nonReentrant\n returns (uint256 requestId, uint256 queued)\n {\n // Burn the user's OETH\n // This also checks the requester has enough OETH to burn\n oUSD.burn(msg.sender, _amount);\n\n requestId = withdrawalQueueMetadata.nextWithdrawalIndex;\n queued = withdrawalQueueMetadata.queued + _amount;\n\n // store the next withdrawal request\n withdrawalQueueMetadata.nextWithdrawalIndex = uint128(requestId + 1);\n withdrawalQueueMetadata.queued = uint128(queued);\n\n emit WithdrawalRequested(msg.sender, requestId, _amount, queued);\n\n withdrawalRequests[requestId] = WithdrawalRequest({\n withdrawer: msg.sender,\n claimed: false,\n amount: uint128(_amount),\n queued: uint128(queued)\n });\n }\n\n /**\n * @notice Claim a previously requested withdrawal once it is claimable.\n * @param requestId Unique ID for the withdrawal request\n * @return amount Amount of WETH transferred to the withdrawer\n */\n function claimWithdrawal(uint256 requestId)\n external\n whenNotCapitalPaused\n nonReentrant\n returns (uint256 amount)\n {\n amount = _claimWithdrawal(requestId);\n\n // transfer WETH from the vault to the withdrawer\n IERC20(weth).safeTransfer(msg.sender, amount);\n }\n\n /**\n * @notice Claim a previously requested withdrawals once they are claimable.\n * @param requestIds Unique ID of each withdrawal request\n * @return amounts Amount of WETH received for each request\n */\n function claimWithdrawals(uint256[] memory requestIds)\n external\n whenNotCapitalPaused\n nonReentrant\n returns (uint256[] memory amounts, uint256 totalAmount)\n {\n amounts = new uint256[](requestIds.length);\n for (uint256 i = 0; i < requestIds.length; ++i) {\n amounts[i] = _claimWithdrawal(requestIds[i]);\n totalAmount += amounts[i];\n }\n\n // transfer all the claimed WETH from the vault to the withdrawer\n IERC20(weth).safeTransfer(msg.sender, totalAmount);\n }\n\n // slither-disable-start reentrancy-no-eth\n\n function _claimWithdrawal(uint256 requestId)\n internal\n returns (uint256 amount)\n {\n // Check if there's enough liquidity to cover the withdrawal request\n WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata;\n WithdrawalRequest memory request = withdrawalRequests[requestId];\n\n require(request.claimed == false, \"already claimed\");\n require(request.withdrawer == msg.sender, \"not requester\");\n\n // Try and get more liquidity in the withdrawal queue if there is not enough\n if (request.queued > queue.claimable) {\n // Stream any harvested rewards (WETH) that are available to the Vault\n IDripper(dripper).collect();\n\n // Add any WETH from the Dripper to the withdrawal queue\n uint256 addedClaimable = _addWithdrawalQueueLiquidity();\n\n // If there still isn't enough liquidity in the queue to claim, revert\n require(\n request.queued <= queue.claimable + addedClaimable,\n \"queue pending liquidity\"\n );\n }\n\n // Store the updated claimed amount\n withdrawalQueueMetadata.claimed = queue.claimed + request.amount;\n // Store the request as claimed\n withdrawalRequests[requestId].claimed = true;\n\n emit WithdrawalClaimed(msg.sender, requestId, request.amount);\n\n return request.amount;\n }\n\n // slither-disable-end reentrancy-no-eth\n\n /// @notice Collects harvested rewards from the Dripper as WETH then\n /// adds WETH to the withdrawal queue if there is a funding shortfall.\n /// @dev is called from the Native Staking strategy when validator withdrawals are processed.\n /// It also called before any WETH is allocated to a strategy.\n function addWithdrawalQueueLiquidity() external {\n // Stream any harvested rewards (WETH) that are available to the Vault\n IDripper(dripper).collect();\n\n _addWithdrawalQueueLiquidity();\n }\n\n /// @dev Adds WETH to the withdrawal queue if there is a funding shortfall.\n function _addWithdrawalQueueLiquidity()\n internal\n returns (uint256 addedClaimable)\n {\n WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata;\n\n // Check if the claimable WETH is less than the queued amount\n uint256 queueShortfall = queue.queued - queue.claimable;\n\n // No need to get WETH balance if all the withdrawal requests are claimable\n if (queueShortfall > 0) {\n uint256 wethBalance = IERC20(weth).balanceOf(address(this));\n\n // Of the claimable withdrawal requests, how much is unclaimed?\n uint256 unclaimed = queue.claimable - queue.claimed;\n if (wethBalance > unclaimed) {\n uint256 unallocatedWeth = wethBalance - unclaimed;\n\n // the new claimable amount is the smaller of the queue shortfall or unallocated weth\n addedClaimable = queueShortfall < unallocatedWeth\n ? queueShortfall\n : unallocatedWeth;\n uint256 newClaimable = queue.claimable + addedClaimable;\n\n // Store the new claimable amount back to storage\n withdrawalQueueMetadata.claimable = uint128(newClaimable);\n\n // emit a WithdrawalClaimable event\n emit WithdrawalClaimable(newClaimable, addedClaimable);\n }\n }\n }\n\n /***************************************\n View Functions\n ****************************************/\n\n function _wethAvailable() internal view returns (uint256 wethAvailable) {\n WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata;\n\n // Check if the claimable WETH is less than the queued amount\n uint256 queueShortfall = queue.queued - queue.claimable;\n uint256 wethBalance = IERC20(weth).balanceOf(address(this));\n // Of the claimable withdrawal requests, how much is unclaimed?\n uint256 unclaimed = queue.claimable - queue.claimed;\n\n if (wethBalance > queueShortfall + unclaimed) {\n wethAvailable = wethBalance - queueShortfall - unclaimed;\n }\n }\n\n function _checkBalance(address _asset)\n internal\n view\n override\n returns (uint256 balance)\n {\n balance = super._checkBalance(_asset);\n\n if (_asset == weth) {\n WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata;\n // Need to remove WETH that is reserved for the withdrawal queue\n return balance + queue.claimed - queue.queued;\n }\n }\n\n function _allocate() internal override {\n // Add any unallocated WETH to the withdrawal queue first\n _addWithdrawalQueueLiquidity();\n\n super._allocate();\n }\n\n function _totalValue() internal view override returns (uint256 value) {\n value = super._totalValue();\n\n // Need to remove WETH that is reserved for the withdrawal queue.\n // reserved for the withdrawal queue = cumulative queued total - total claimed\n WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata;\n value = value + queue.claimed - queue.queued;\n }\n}\n" + }, + "contracts/vault/OETHZapper.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { IVault } from \"../interfaces/IVault.sol\";\nimport { IWETH9 } from \"../interfaces/IWETH9.sol\";\nimport { ISfrxETH } from \"../interfaces/ISfrxETH.sol\";\n\ncontract OETHZapper {\n IERC20 public immutable oeth;\n IVault public immutable vault;\n\n IWETH9 public constant weth =\n IWETH9(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);\n IERC20 public constant frxeth =\n IERC20(0x5E8422345238F34275888049021821E8E08CAa1f);\n ISfrxETH public constant sfrxeth =\n ISfrxETH(0xac3E018457B222d93114458476f3E3416Abbe38F);\n address private constant ETH_MARKER =\n 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n event Zap(address indexed minter, address indexed asset, uint256 amount);\n\n constructor(address _oeth, address _vault) {\n oeth = IERC20(_oeth);\n vault = IVault(_vault);\n\n weth.approve(address(_vault), type(uint256).max);\n frxeth.approve(address(_vault), type(uint256).max);\n }\n\n /**\n * @dev Deposit ETH and receive OETH in return.\n * Will verify that the user is sent 1:1 for ETH.\n */\n receive() external payable {\n deposit();\n }\n\n /**\n * @dev Deposit ETH and receive OETH in return\n * Will verify that the user is sent 1:1 for ETH.\n * @return Amount of OETH sent to user\n */\n function deposit() public payable returns (uint256) {\n uint256 balance = address(this).balance;\n weth.deposit{ value: balance }();\n emit Zap(msg.sender, ETH_MARKER, balance);\n return _mint(address(weth), balance);\n }\n\n /**\n * @dev Deposit SFRXETH to the vault and receive OETH in return\n * @param amount Amount of SFRXETH to deposit\n * @param minOETH Minimum amount of OETH to receive\n * @return Amount of OETH sent to user\n */\n function depositSFRXETH(uint256 amount, uint256 minOETH)\n external\n returns (uint256)\n {\n sfrxeth.redeem(amount, address(this), msg.sender);\n emit Zap(msg.sender, address(sfrxeth), amount);\n return _mint(address(frxeth), minOETH);\n }\n\n /**\n * @dev Internal function to mint OETH from an asset\n * @param asset Address of asset for the vault to mint from\n * @param minOETH Minimum amount of OETH to for user to receive\n * @return Amount of OETH sent to user\n */\n function _mint(address asset, uint256 minOETH) internal returns (uint256) {\n uint256 toMint = IERC20(asset).balanceOf(address(this));\n vault.mint(asset, toMint, minOETH);\n uint256 mintedAmount = oeth.balanceOf(address(this));\n require(mintedAmount >= minOETH, \"Zapper: not enough minted\");\n require(oeth.transfer(msg.sender, mintedAmount));\n return mintedAmount;\n }\n}\n" + }, + "contracts/vault/Vault.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @title OUSD VaultInitializer Contract\n * @notice The VaultInitializer sets up the initial contract.\n * @author Origin Protocol Inc\n */\nimport { VaultInitializer } from \"./VaultInitializer.sol\";\nimport { VaultAdmin } from \"./VaultAdmin.sol\";\n\ncontract Vault is VaultInitializer, VaultAdmin {}\n" + }, + "contracts/vault/VaultAdmin.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @title OToken VaultAdmin contract\n * @notice The VaultAdmin contract makes configuration and admin calls on the vault.\n * @author Origin Protocol Inc\n */\n\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nimport { IOracle } from \"../interfaces/IOracle.sol\";\nimport { ISwapper } from \"../interfaces/ISwapper.sol\";\nimport { IVault } from \"../interfaces/IVault.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\n\nimport \"./VaultStorage.sol\";\n\ncontract VaultAdmin is VaultStorage {\n using SafeERC20 for IERC20;\n using StableMath for uint256;\n\n /**\n * @dev Verifies that the caller is the Governor or Strategist.\n */\n modifier onlyGovernorOrStrategist() {\n require(\n msg.sender == strategistAddr || isGovernor(),\n \"Caller is not the Strategist or Governor\"\n );\n _;\n }\n\n /***************************************\n Configuration\n ****************************************/\n\n /**\n * @notice Set address of price provider.\n * @param _priceProvider Address of price provider\n */\n function setPriceProvider(address _priceProvider) external onlyGovernor {\n priceProvider = _priceProvider;\n emit PriceProviderUpdated(_priceProvider);\n }\n\n /**\n * @notice Set a fee in basis points to be charged for a redeem.\n * @param _redeemFeeBps Basis point fee to be charged\n */\n function setRedeemFeeBps(uint256 _redeemFeeBps) external onlyGovernor {\n require(_redeemFeeBps <= 1000, \"Redeem fee should not be over 10%\");\n redeemFeeBps = _redeemFeeBps;\n emit RedeemFeeUpdated(_redeemFeeBps);\n }\n\n /**\n * @notice Set a buffer of assets to keep in the Vault to handle most\n * redemptions without needing to spend gas unwinding assets from a Strategy.\n * @param _vaultBuffer Percentage using 18 decimals. 100% = 1e18.\n */\n function setVaultBuffer(uint256 _vaultBuffer)\n external\n onlyGovernorOrStrategist\n {\n require(_vaultBuffer <= 1e18, \"Invalid value\");\n vaultBuffer = _vaultBuffer;\n emit VaultBufferUpdated(_vaultBuffer);\n }\n\n /**\n * @notice Sets the minimum amount of OTokens in a mint to trigger an\n * automatic allocation of funds afterwords.\n * @param _threshold OToken amount with 18 fixed decimals.\n */\n function setAutoAllocateThreshold(uint256 _threshold)\n external\n onlyGovernor\n {\n autoAllocateThreshold = _threshold;\n emit AllocateThresholdUpdated(_threshold);\n }\n\n /**\n * @notice Set a minimum amount of OTokens in a mint or redeem that triggers a\n * rebase\n * @param _threshold OToken amount with 18 fixed decimals.\n */\n function setRebaseThreshold(uint256 _threshold) external onlyGovernor {\n rebaseThreshold = _threshold;\n emit RebaseThresholdUpdated(_threshold);\n }\n\n /**\n * @notice Set address of Strategist\n * @param _address Address of Strategist\n */\n function setStrategistAddr(address _address) external onlyGovernor {\n strategistAddr = _address;\n emit StrategistUpdated(_address);\n }\n\n /**\n * @notice Set the default Strategy for an asset, i.e. the one which the asset\n will be automatically allocated to and withdrawn from\n * @param _asset Address of the asset\n * @param _strategy Address of the Strategy\n */\n function setAssetDefaultStrategy(address _asset, address _strategy)\n external\n onlyGovernorOrStrategist\n {\n emit AssetDefaultStrategyUpdated(_asset, _strategy);\n // If its a zero address being passed for the strategy we are removing\n // the default strategy\n if (_strategy != address(0)) {\n // Make sure the strategy meets some criteria\n require(strategies[_strategy].isSupported, \"Strategy not approved\");\n IStrategy strategy = IStrategy(_strategy);\n require(assets[_asset].isSupported, \"Asset is not supported\");\n require(\n strategy.supportsAsset(_asset),\n \"Asset not supported by Strategy\"\n );\n }\n assetDefaultStrategies[_asset] = _strategy;\n }\n\n /**\n * @notice Set maximum amount of OTokens that can at any point be minted and deployed\n * to strategy (used only by ConvexOUSDMetaStrategy for now).\n * @param _threshold OToken amount with 18 fixed decimals.\n */\n function setNetOusdMintForStrategyThreshold(uint256 _threshold)\n external\n onlyGovernor\n {\n /**\n * Because `netOusdMintedForStrategy` check in vault core works both ways\n * (positive and negative) the actual impact of the amount of OToken minted\n * could be double the threshold. E.g.:\n * - contract has threshold set to 100\n * - state of netOusdMinted is -90\n * - in effect it can mint 190 OToken and still be within limits\n *\n * We are somewhat mitigating this behaviour by resetting the netOusdMinted\n * counter whenever new threshold is set. So it can only move one threshold\n * amount in each direction. This also enables us to reduce the threshold\n * amount and not have problems with current netOusdMinted being near\n * limits on either side.\n */\n netOusdMintedForStrategy = 0;\n netOusdMintForStrategyThreshold = _threshold;\n emit NetOusdMintForStrategyThresholdChanged(_threshold);\n }\n\n /**\n * @notice Set the Dripper contract that streams harvested rewards to the vault.\n * @param _dripper Address of the Dripper contract.\n */\n function setDripper(address _dripper) external onlyGovernor {\n dripper = _dripper;\n emit DripperChanged(_dripper);\n }\n\n /***************************************\n Swaps\n ****************************************/\n\n /**\n * @notice Strategist swaps collateral assets sitting in the vault.\n * @param _fromAsset The token address of the asset being sold by the vault.\n * @param _toAsset The token address of the asset being purchased by the vault.\n * @param _fromAssetAmount The amount of assets being sold by the vault.\n * @param _minToAssetAmount The minimum amount of assets to be purchased.\n * @param _data implementation specific data. eg 1Inch swap data\n * @return toAssetAmount The amount of toAssets that was received from the swap\n */\n function swapCollateral(\n address _fromAsset,\n address _toAsset,\n uint256 _fromAssetAmount,\n uint256 _minToAssetAmount,\n bytes calldata _data\n )\n external\n nonReentrant\n onlyGovernorOrStrategist\n returns (uint256 toAssetAmount)\n {\n toAssetAmount = _swapCollateral(\n _fromAsset,\n _toAsset,\n _fromAssetAmount,\n _minToAssetAmount,\n _data\n );\n }\n\n function _swapCollateral(\n address _fromAsset,\n address _toAsset,\n uint256 _fromAssetAmount,\n uint256 _minToAssetAmount,\n bytes calldata _data\n ) internal virtual returns (uint256 toAssetAmount) {\n // Check fromAsset and toAsset are valid\n Asset memory fromAssetConfig = assets[address(_fromAsset)];\n Asset memory toAssetConfig = assets[_toAsset];\n require(fromAssetConfig.isSupported, \"From asset is not supported\");\n require(toAssetConfig.isSupported, \"To asset is not supported\");\n\n // Load swap config into memory to avoid separate SLOADs\n SwapConfig memory config = swapConfig;\n\n // Scope a new block to remove toAssetBalBefore from the scope of swapCollateral.\n // This avoids a stack too deep error.\n {\n uint256 toAssetBalBefore = IERC20(_toAsset).balanceOf(\n address(this)\n );\n\n // Transfer from assets to the swapper contract\n IERC20(_fromAsset).safeTransfer(config.swapper, _fromAssetAmount);\n\n // Call to the Swapper contract to do the actual swap\n // The -1 is required for stETH which sometimes transfers 1 wei less than what was specified.\n // slither-disable-next-line unused-return\n ISwapper(config.swapper).swap(\n _fromAsset,\n _toAsset,\n _fromAssetAmount - 1,\n _minToAssetAmount,\n _data\n );\n\n // Compute the change in asset balance held by the Vault\n toAssetAmount =\n IERC20(_toAsset).balanceOf(address(this)) -\n toAssetBalBefore;\n }\n\n // Check the to assets returned is above slippage amount specified by the strategist\n require(\n toAssetAmount >= _minToAssetAmount,\n \"Strategist slippage limit\"\n );\n\n // Scope a new block to remove minOracleToAssetAmount from the scope of swapCollateral.\n // This avoids a stack too deep error.\n {\n // Check the slippage against the Oracle in case the strategist made a mistake or has become malicious.\n // to asset amount = from asset amount * from asset price / to asset price\n uint256 minOracleToAssetAmount = (_fromAssetAmount *\n (1e4 - fromAssetConfig.allowedOracleSlippageBps) *\n IOracle(priceProvider).price(_fromAsset)) /\n (IOracle(priceProvider).price(_toAsset) *\n (1e4 + toAssetConfig.allowedOracleSlippageBps));\n\n // Scale both sides up to 18 decimals to compare\n require(\n toAssetAmount.scaleBy(18, toAssetConfig.decimals) >=\n minOracleToAssetAmount.scaleBy(\n 18,\n fromAssetConfig.decimals\n ),\n \"Oracle slippage limit exceeded\"\n );\n }\n\n // Check the vault's total value hasn't gone below the OToken total supply\n // by more than the allowed percentage.\n require(\n IVault(address(this)).totalValue() >=\n (oUSD.totalSupply() * ((1e4 - config.allowedUndervalueBps))) /\n 1e4,\n \"Allowed value < supply\"\n );\n\n emit Swapped(_fromAsset, _toAsset, _fromAssetAmount, toAssetAmount);\n }\n\n /***************************************\n Swap Config\n ****************************************/\n\n /**\n * @notice Set the contract the performs swaps of collateral assets.\n * @param _swapperAddr Address of the Swapper contract that implements the ISwapper interface.\n */\n function setSwapper(address _swapperAddr) external onlyGovernor {\n swapConfig.swapper = _swapperAddr;\n emit SwapperChanged(_swapperAddr);\n }\n\n /// @notice Contract that swaps the vault's collateral assets\n function swapper() external view returns (address swapper_) {\n swapper_ = swapConfig.swapper;\n }\n\n /**\n * @notice Set max allowed percentage the vault total value can drop below the OToken total supply in basis points\n * when executing collateral swaps.\n * @param _basis Percentage in basis points. eg 100 == 1%\n */\n function setSwapAllowedUndervalue(uint16 _basis) external onlyGovernor {\n require(_basis < 10001, \"Invalid basis points\");\n swapConfig.allowedUndervalueBps = _basis;\n emit SwapAllowedUndervalueChanged(_basis);\n }\n\n /**\n * @notice Max allowed percentage the vault total value can drop below the OToken total supply in basis points\n * when executing a collateral swap.\n * For example 100 == 1%\n * @return value Percentage in basis points.\n */\n function allowedSwapUndervalue() external view returns (uint256 value) {\n value = swapConfig.allowedUndervalueBps;\n }\n\n /**\n * @notice Set the allowed slippage from the Oracle price for collateral asset swaps.\n * @param _asset Address of the asset token.\n * @param _allowedOracleSlippageBps allowed slippage from Oracle in basis points. eg 20 = 0.2%. Max 10%.\n */\n function setOracleSlippage(address _asset, uint16 _allowedOracleSlippageBps)\n external\n onlyGovernor\n {\n require(assets[_asset].isSupported, \"Asset not supported\");\n require(_allowedOracleSlippageBps < 1000, \"Slippage too high\");\n\n assets[_asset].allowedOracleSlippageBps = _allowedOracleSlippageBps;\n\n emit SwapSlippageChanged(_asset, _allowedOracleSlippageBps);\n }\n\n /***************************************\n Asset Config\n ****************************************/\n\n /**\n * @notice Add a supported asset to the contract, i.e. one that can be\n * to mint OTokens.\n * @param _asset Address of asset\n */\n function supportAsset(address _asset, uint8 _unitConversion)\n external\n onlyGovernor\n {\n require(!assets[_asset].isSupported, \"Asset already supported\");\n\n assets[_asset] = Asset({\n isSupported: true,\n unitConversion: UnitConversion(_unitConversion),\n decimals: 0, // will be overridden in _cacheDecimals\n allowedOracleSlippageBps: 0 // 0% by default\n });\n\n _cacheDecimals(_asset);\n allAssets.push(_asset);\n\n // Verify that our oracle supports the asset\n // slither-disable-next-line unused-return\n IOracle(priceProvider).price(_asset);\n\n emit AssetSupported(_asset);\n }\n\n /**\n * @notice Remove a supported asset from the Vault\n * @param _asset Address of asset\n */\n function removeAsset(address _asset) external onlyGovernor {\n require(assets[_asset].isSupported, \"Asset not supported\");\n require(\n IVault(address(this)).checkBalance(_asset) <= 1e13,\n \"Vault still holds asset\"\n );\n\n uint256 assetsCount = allAssets.length;\n uint256 assetIndex = assetsCount; // initialize at invaid index\n for (uint256 i = 0; i < assetsCount; ++i) {\n if (allAssets[i] == _asset) {\n assetIndex = i;\n break;\n }\n }\n\n // Note: If asset is not found in `allAssets`, the following line\n // will revert with an out-of-bound error. However, there's no\n // reason why an asset would have `Asset.isSupported = true` but\n // not exist in `allAssets`.\n\n // Update allAssets array\n allAssets[assetIndex] = allAssets[assetsCount - 1];\n allAssets.pop();\n\n // Reset default strategy\n assetDefaultStrategies[_asset] = address(0);\n emit AssetDefaultStrategyUpdated(_asset, address(0));\n\n // Remove asset from storage\n delete assets[_asset];\n\n emit AssetRemoved(_asset);\n }\n\n /**\n * @notice Cache decimals on OracleRouter for a particular asset. This action\n * is required before that asset's price can be accessed.\n * @param _asset Address of asset token\n */\n function cacheDecimals(address _asset) external onlyGovernor {\n _cacheDecimals(_asset);\n }\n\n /***************************************\n Strategy Config\n ****************************************/\n\n /**\n * @notice Add a strategy to the Vault.\n * @param _addr Address of the strategy to add\n */\n function approveStrategy(address _addr) external onlyGovernor {\n require(!strategies[_addr].isSupported, \"Strategy already approved\");\n strategies[_addr] = Strategy({ isSupported: true, _deprecated: 0 });\n allStrategies.push(_addr);\n emit StrategyApproved(_addr);\n }\n\n /**\n * @notice Remove a strategy from the Vault.\n * @param _addr Address of the strategy to remove\n */\n\n function removeStrategy(address _addr) external onlyGovernor {\n require(strategies[_addr].isSupported, \"Strategy not approved\");\n\n uint256 assetCount = allAssets.length;\n for (uint256 i = 0; i < assetCount; ++i) {\n require(\n assetDefaultStrategies[allAssets[i]] != _addr,\n \"Strategy is default for an asset\"\n );\n }\n\n // Initialize strategyIndex with out of bounds result so function will\n // revert if no valid index found\n uint256 stratCount = allStrategies.length;\n uint256 strategyIndex = stratCount;\n for (uint256 i = 0; i < stratCount; ++i) {\n if (allStrategies[i] == _addr) {\n strategyIndex = i;\n break;\n }\n }\n\n if (strategyIndex < stratCount) {\n allStrategies[strategyIndex] = allStrategies[stratCount - 1];\n allStrategies.pop();\n\n // Mark the strategy as not supported\n strategies[_addr].isSupported = false;\n\n // Withdraw all assets\n IStrategy strategy = IStrategy(_addr);\n strategy.withdrawAll();\n\n emit StrategyRemoved(_addr);\n }\n }\n\n /***************************************\n Strategies\n ****************************************/\n\n /**\n * @notice Deposit multiple assets from the vault into the strategy.\n * @param _strategyToAddress Address of the Strategy to deposit assets into.\n * @param _assets Array of asset address that will be deposited into the strategy.\n * @param _amounts Array of amounts of each corresponding asset to deposit.\n */\n function depositToStrategy(\n address _strategyToAddress,\n address[] calldata _assets,\n uint256[] calldata _amounts\n ) external onlyGovernorOrStrategist nonReentrant {\n _depositToStrategy(_strategyToAddress, _assets, _amounts);\n }\n\n function _depositToStrategy(\n address _strategyToAddress,\n address[] calldata _assets,\n uint256[] calldata _amounts\n ) internal virtual {\n require(\n strategies[_strategyToAddress].isSupported,\n \"Invalid to Strategy\"\n );\n require(_assets.length == _amounts.length, \"Parameter length mismatch\");\n\n uint256 assetCount = _assets.length;\n for (uint256 i = 0; i < assetCount; ++i) {\n address assetAddr = _assets[i];\n require(\n IStrategy(_strategyToAddress).supportsAsset(assetAddr),\n \"Asset unsupported\"\n );\n // Send required amount of funds to the strategy\n IERC20(assetAddr).safeTransfer(_strategyToAddress, _amounts[i]);\n }\n\n // Deposit all the funds that have been sent to the strategy\n IStrategy(_strategyToAddress).depositAll();\n }\n\n /**\n * @notice Withdraw multiple assets from the strategy to the vault.\n * @param _strategyFromAddress Address of the Strategy to withdraw assets from.\n * @param _assets Array of asset address that will be withdrawn from the strategy.\n * @param _amounts Array of amounts of each corresponding asset to withdraw.\n */\n function withdrawFromStrategy(\n address _strategyFromAddress,\n address[] calldata _assets,\n uint256[] calldata _amounts\n ) external onlyGovernorOrStrategist nonReentrant {\n _withdrawFromStrategy(\n address(this),\n _strategyFromAddress,\n _assets,\n _amounts\n );\n }\n\n /**\n * @param _recipient can either be a strategy or the Vault\n */\n function _withdrawFromStrategy(\n address _recipient,\n address _strategyFromAddress,\n address[] calldata _assets,\n uint256[] calldata _amounts\n ) internal virtual {\n require(\n strategies[_strategyFromAddress].isSupported,\n \"Invalid from Strategy\"\n );\n require(_assets.length == _amounts.length, \"Parameter length mismatch\");\n\n uint256 assetCount = _assets.length;\n for (uint256 i = 0; i < assetCount; ++i) {\n // Withdraw from Strategy to the recipient\n IStrategy(_strategyFromAddress).withdraw(\n _recipient,\n _assets[i],\n _amounts[i]\n );\n }\n }\n\n /**\n * @notice Sets the maximum allowable difference between\n * total supply and backing assets' value.\n */\n function setMaxSupplyDiff(uint256 _maxSupplyDiff) external onlyGovernor {\n maxSupplyDiff = _maxSupplyDiff;\n emit MaxSupplyDiffChanged(_maxSupplyDiff);\n }\n\n /**\n * @notice Sets the trusteeAddress that can receive a portion of yield.\n * Setting to the zero address disables this feature.\n */\n function setTrusteeAddress(address _address) external onlyGovernor {\n trusteeAddress = _address;\n emit TrusteeAddressChanged(_address);\n }\n\n /**\n * @notice Sets the TrusteeFeeBps to the percentage of yield that should be\n * received in basis points.\n */\n function setTrusteeFeeBps(uint256 _basis) external onlyGovernor {\n require(_basis <= 5000, \"basis cannot exceed 50%\");\n trusteeFeeBps = _basis;\n emit TrusteeFeeBpsChanged(_basis);\n }\n\n /**\n * @notice Set OToken Metapool strategy\n * @param _ousdMetaStrategy Address of OToken metapool strategy\n */\n function setOusdMetaStrategy(address _ousdMetaStrategy)\n external\n onlyGovernor\n {\n ousdMetaStrategy = _ousdMetaStrategy;\n emit OusdMetaStrategyUpdated(_ousdMetaStrategy);\n }\n\n /***************************************\n Pause\n ****************************************/\n\n /**\n * @notice Set the deposit paused flag to true to prevent rebasing.\n */\n function pauseRebase() external onlyGovernorOrStrategist {\n rebasePaused = true;\n emit RebasePaused();\n }\n\n /**\n * @notice Set the deposit paused flag to true to allow rebasing.\n */\n function unpauseRebase() external onlyGovernorOrStrategist {\n rebasePaused = false;\n emit RebaseUnpaused();\n }\n\n /**\n * @notice Set the deposit paused flag to true to prevent capital movement.\n */\n function pauseCapital() external onlyGovernorOrStrategist {\n capitalPaused = true;\n emit CapitalPaused();\n }\n\n /**\n * @notice Set the deposit paused flag to false to enable capital movement.\n */\n function unpauseCapital() external onlyGovernorOrStrategist {\n capitalPaused = false;\n emit CapitalUnpaused();\n }\n\n /***************************************\n Utils\n ****************************************/\n\n /**\n * @notice Transfer token to governor. Intended for recovering tokens stuck in\n * contract, i.e. mistaken sends.\n * @param _asset Address for the asset\n * @param _amount Amount of the asset to transfer\n */\n function transferToken(address _asset, uint256 _amount)\n external\n onlyGovernor\n {\n require(!assets[_asset].isSupported, \"Only unsupported assets\");\n IERC20(_asset).safeTransfer(governor(), _amount);\n }\n\n /***************************************\n Strategies Admin\n ****************************************/\n\n /**\n * @notice Withdraws all assets from the strategy and sends assets to the Vault.\n * @param _strategyAddr Strategy address.\n */\n function withdrawAllFromStrategy(address _strategyAddr)\n external\n onlyGovernorOrStrategist\n {\n _withdrawAllFromStrategy(_strategyAddr);\n }\n\n function _withdrawAllFromStrategy(address _strategyAddr) internal virtual {\n require(\n strategies[_strategyAddr].isSupported,\n \"Strategy is not supported\"\n );\n IStrategy strategy = IStrategy(_strategyAddr);\n strategy.withdrawAll();\n }\n\n /**\n * @notice Withdraws all assets from all the strategies and sends assets to the Vault.\n */\n function withdrawAllFromStrategies() external onlyGovernorOrStrategist {\n _withdrawAllFromStrategies();\n }\n\n function _withdrawAllFromStrategies() internal virtual {\n uint256 stratCount = allStrategies.length;\n for (uint256 i = 0; i < stratCount; ++i) {\n IStrategy(allStrategies[i]).withdrawAll();\n }\n }\n\n /***************************************\n Utils\n ****************************************/\n\n function _cacheDecimals(address token) internal {\n Asset storage tokenAsset = assets[token];\n if (tokenAsset.decimals != 0) {\n return;\n }\n uint8 decimals = IBasicToken(token).decimals();\n require(decimals >= 6 && decimals <= 18, \"Unexpected precision\");\n tokenAsset.decimals = decimals;\n }\n}\n" + }, + "contracts/vault/VaultCore.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @title OToken VaultCore contract\n * @notice The Vault contract stores assets. On a deposit, OTokens will be minted\n and sent to the depositor. On a withdrawal, OTokens will be burned and\n assets will be sent to the withdrawer. The Vault accepts deposits of\n interest from yield bearing strategies which will modify the supply\n of OTokens.\n * @author Origin Protocol Inc\n */\n\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nimport { StableMath } from \"../utils/StableMath.sol\";\nimport { IOracle } from \"../interfaces/IOracle.sol\";\nimport { IGetExchangeRateToken } from \"../interfaces/IGetExchangeRateToken.sol\";\nimport { IDripper } from \"../interfaces/IDripper.sol\";\n\nimport \"./VaultInitializer.sol\";\n\ncontract VaultCore is VaultInitializer {\n using SafeERC20 for IERC20;\n using StableMath for uint256;\n // max signed int\n uint256 internal constant MAX_INT = 2**255 - 1;\n // max un-signed int\n uint256 internal constant MAX_UINT =\n 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff;\n\n /**\n * @dev Verifies that the rebasing is not paused.\n */\n modifier whenNotRebasePaused() {\n require(!rebasePaused, \"Rebasing paused\");\n _;\n }\n\n /**\n * @dev Verifies that the deposits are not paused.\n */\n modifier whenNotCapitalPaused() {\n require(!capitalPaused, \"Capital paused\");\n _;\n }\n\n modifier onlyOusdMetaStrategy() {\n require(\n msg.sender == ousdMetaStrategy,\n \"Caller is not the OUSD meta strategy\"\n );\n _;\n }\n\n /**\n * @notice Deposit a supported asset and mint OTokens.\n * @param _asset Address of the asset being deposited\n * @param _amount Amount of the asset being deposited\n * @param _minimumOusdAmount Minimum OTokens to mint\n */\n function mint(\n address _asset,\n uint256 _amount,\n uint256 _minimumOusdAmount\n ) external whenNotCapitalPaused nonReentrant {\n _mint(_asset, _amount, _minimumOusdAmount);\n }\n\n function _mint(\n address _asset,\n uint256 _amount,\n uint256 _minimumOusdAmount\n ) internal virtual {\n require(assets[_asset].isSupported, \"Asset is not supported\");\n require(_amount > 0, \"Amount must be greater than 0\");\n\n uint256 units = _toUnits(_amount, _asset);\n uint256 unitPrice = _toUnitPrice(_asset, true);\n uint256 priceAdjustedDeposit = (units * unitPrice) / 1e18;\n\n if (_minimumOusdAmount > 0) {\n require(\n priceAdjustedDeposit >= _minimumOusdAmount,\n \"Mint amount lower than minimum\"\n );\n }\n\n emit Mint(msg.sender, priceAdjustedDeposit);\n\n // Rebase must happen before any transfers occur.\n if (priceAdjustedDeposit >= rebaseThreshold && !rebasePaused) {\n if (dripper != address(0)) {\n // Stream any harvested rewards that are available\n IDripper(dripper).collect();\n }\n _rebase();\n }\n\n // Mint matching amount of OTokens\n oUSD.mint(msg.sender, priceAdjustedDeposit);\n\n // Transfer the deposited coins to the vault\n IERC20 asset = IERC20(_asset);\n asset.safeTransferFrom(msg.sender, address(this), _amount);\n\n if (priceAdjustedDeposit >= autoAllocateThreshold) {\n _allocate();\n }\n }\n\n /**\n * @notice Mint OTokens for a Metapool Strategy\n * @param _amount Amount of the asset being deposited\n *\n * Notice: can't use `nonReentrant` modifier since the `mint` function can\n * call `allocate`, and that can trigger `ConvexOUSDMetaStrategy` to call this function\n * while the execution of the `mint` has not yet completed -> causing a `nonReentrant` collision.\n *\n * Also important to understand is that this is a limitation imposed by the test suite.\n * Production / mainnet contracts should never be configured in a way where mint/redeem functions\n * that are moving funds between the Vault and end user wallets can influence strategies\n * utilizing this function.\n */\n function mintForStrategy(uint256 _amount)\n external\n whenNotCapitalPaused\n onlyOusdMetaStrategy\n {\n require(_amount < MAX_INT, \"Amount too high\");\n\n emit Mint(msg.sender, _amount);\n\n // safe to cast because of the require check at the beginning of the function\n netOusdMintedForStrategy += int256(_amount);\n\n require(\n abs(netOusdMintedForStrategy) < netOusdMintForStrategyThreshold,\n \"Minted ousd surpassed netOusdMintForStrategyThreshold.\"\n );\n\n // Mint matching amount of OTokens\n oUSD.mint(msg.sender, _amount);\n }\n\n // In memoriam\n\n /**\n * @notice Withdraw a supported asset and burn OTokens.\n * @param _amount Amount of OTokens to burn\n * @param _minimumUnitAmount Minimum stablecoin units to receive in return\n */\n function redeem(uint256 _amount, uint256 _minimumUnitAmount)\n external\n whenNotCapitalPaused\n nonReentrant\n {\n _redeem(_amount, _minimumUnitAmount);\n }\n\n /**\n * @notice Withdraw a supported asset and burn OTokens.\n * @param _amount Amount of OTokens to burn\n * @param _minimumUnitAmount Minimum stablecoin units to receive in return\n */\n function _redeem(uint256 _amount, uint256 _minimumUnitAmount)\n internal\n virtual\n {\n // Calculate redemption outputs\n uint256[] memory outputs = _calculateRedeemOutputs(_amount);\n\n emit Redeem(msg.sender, _amount);\n\n // Send outputs\n uint256 assetCount = allAssets.length;\n for (uint256 i = 0; i < assetCount; ++i) {\n if (outputs[i] == 0) continue;\n\n address assetAddr = allAssets[i];\n\n if (IERC20(assetAddr).balanceOf(address(this)) >= outputs[i]) {\n // Use Vault funds first if sufficient\n IERC20(assetAddr).safeTransfer(msg.sender, outputs[i]);\n } else {\n address strategyAddr = assetDefaultStrategies[assetAddr];\n if (strategyAddr != address(0)) {\n // Nothing in Vault, but something in Strategy, send from there\n IStrategy strategy = IStrategy(strategyAddr);\n strategy.withdraw(msg.sender, assetAddr, outputs[i]);\n } else {\n // Cant find funds anywhere\n revert(\"Liquidity error\");\n }\n }\n }\n\n if (_minimumUnitAmount > 0) {\n uint256 unitTotal = 0;\n for (uint256 i = 0; i < outputs.length; ++i) {\n unitTotal += _toUnits(outputs[i], allAssets[i]);\n }\n require(\n unitTotal >= _minimumUnitAmount,\n \"Redeem amount lower than minimum\"\n );\n }\n\n oUSD.burn(msg.sender, _amount);\n\n _postRedeem(_amount);\n }\n\n function _postRedeem(uint256 _amount) internal {\n // Until we can prove that we won't affect the prices of our assets\n // by withdrawing them, this should be here.\n // It's possible that a strategy was off on its asset total, perhaps\n // a reward token sold for more or for less than anticipated.\n uint256 totalUnits = 0;\n if (_amount >= rebaseThreshold && !rebasePaused) {\n totalUnits = _rebase();\n } else {\n totalUnits = _totalValue();\n }\n\n // Check that the OTokens are backed by enough assets\n if (maxSupplyDiff > 0) {\n // Allow a max difference of maxSupplyDiff% between\n // backing assets value and OUSD total supply\n uint256 diff = oUSD.totalSupply().divPrecisely(totalUnits);\n require(\n (diff > 1e18 ? diff - 1e18 : 1e18 - diff) <= maxSupplyDiff,\n \"Backing supply liquidity error\"\n );\n }\n }\n\n /**\n * @notice Burn OTokens for Metapool Strategy\n * @param _amount Amount of OUSD to burn\n *\n * @dev Notice: can't use `nonReentrant` modifier since the `redeem` function could\n * require withdrawal on `ConvexOUSDMetaStrategy` and that one can call `burnForStrategy`\n * while the execution of the `redeem` has not yet completed -> causing a `nonReentrant` collision.\n *\n * Also important to understand is that this is a limitation imposed by the test suite.\n * Production / mainnet contracts should never be configured in a way where mint/redeem functions\n * that are moving funds between the Vault and end user wallets can influence strategies\n * utilizing this function.\n */\n function burnForStrategy(uint256 _amount)\n external\n whenNotCapitalPaused\n onlyOusdMetaStrategy\n {\n require(_amount < MAX_INT, \"Amount too high\");\n\n emit Redeem(msg.sender, _amount);\n\n // safe to cast because of the require check at the beginning of the function\n netOusdMintedForStrategy -= int256(_amount);\n\n require(\n abs(netOusdMintedForStrategy) < netOusdMintForStrategyThreshold,\n \"Attempting to burn too much OUSD.\"\n );\n\n // Burn OTokens\n oUSD.burn(msg.sender, _amount);\n }\n\n /**\n * @notice Withdraw a supported asset and burn all OTokens.\n * @param _minimumUnitAmount Minimum stablecoin units to receive in return\n */\n function redeemAll(uint256 _minimumUnitAmount)\n external\n whenNotCapitalPaused\n nonReentrant\n {\n _redeem(oUSD.balanceOf(msg.sender), _minimumUnitAmount);\n }\n\n /**\n * @notice Allocate unallocated funds on Vault to strategies.\n **/\n function allocate() external whenNotCapitalPaused nonReentrant {\n _allocate();\n }\n\n /**\n * @dev Allocate unallocated funds on Vault to strategies.\n **/\n function _allocate() internal virtual {\n uint256 vaultValue = _totalValueInVault();\n // Nothing in vault to allocate\n if (vaultValue == 0) return;\n uint256 strategiesValue = _totalValueInStrategies();\n // We have a method that does the same as this, gas optimisation\n uint256 calculatedTotalValue = vaultValue + strategiesValue;\n\n // We want to maintain a buffer on the Vault so calculate a percentage\n // modifier to multiply each amount being allocated by to enforce the\n // vault buffer\n uint256 vaultBufferModifier;\n if (strategiesValue == 0) {\n // Nothing in Strategies, allocate 100% minus the vault buffer to\n // strategies\n vaultBufferModifier = uint256(1e18) - vaultBuffer;\n } else {\n vaultBufferModifier =\n (vaultBuffer * calculatedTotalValue) /\n vaultValue;\n if (1e18 > vaultBufferModifier) {\n // E.g. 1e18 - (1e17 * 10e18)/5e18 = 8e17\n // (5e18 * 8e17) / 1e18 = 4e18 allocated from Vault\n vaultBufferModifier = uint256(1e18) - vaultBufferModifier;\n } else {\n // We need to let the buffer fill\n return;\n }\n }\n if (vaultBufferModifier == 0) return;\n\n // Iterate over all assets in the Vault and allocate to the appropriate\n // strategy\n uint256 assetCount = allAssets.length;\n for (uint256 i = 0; i < assetCount; ++i) {\n IERC20 asset = IERC20(allAssets[i]);\n uint256 assetBalance = asset.balanceOf(address(this));\n // No balance, nothing to do here\n if (assetBalance == 0) continue;\n\n // Multiply the balance by the vault buffer modifier and truncate\n // to the scale of the asset decimals\n uint256 allocateAmount = assetBalance.mulTruncate(\n vaultBufferModifier\n );\n\n address depositStrategyAddr = assetDefaultStrategies[\n address(asset)\n ];\n\n if (depositStrategyAddr != address(0) && allocateAmount > 0) {\n IStrategy strategy = IStrategy(depositStrategyAddr);\n // Transfer asset to Strategy and call deposit method to\n // mint or take required action\n asset.safeTransfer(address(strategy), allocateAmount);\n strategy.deposit(address(asset), allocateAmount);\n emit AssetAllocated(\n address(asset),\n depositStrategyAddr,\n allocateAmount\n );\n }\n }\n }\n\n /**\n * @notice Calculate the total value of assets held by the Vault and all\n * strategies and update the supply of OTokens.\n */\n function rebase() external virtual nonReentrant {\n _rebase();\n }\n\n /**\n * @dev Calculate the total value of assets held by the Vault and all\n * strategies and update the supply of OTokens, optionally sending a\n * portion of the yield to the trustee.\n * @return totalUnits Total balance of Vault in units\n */\n function _rebase() internal whenNotRebasePaused returns (uint256) {\n uint256 ousdSupply = oUSD.totalSupply();\n uint256 vaultValue = _totalValue();\n if (ousdSupply == 0) {\n return vaultValue;\n }\n\n // Yield fee collection\n address _trusteeAddress = trusteeAddress; // gas savings\n if (_trusteeAddress != address(0) && (vaultValue > ousdSupply)) {\n uint256 yield = vaultValue - ousdSupply;\n uint256 fee = yield.mulTruncateScale(trusteeFeeBps, 1e4);\n require(yield > fee, \"Fee must not be greater than yield\");\n if (fee > 0) {\n oUSD.mint(_trusteeAddress, fee);\n }\n emit YieldDistribution(_trusteeAddress, yield, fee);\n }\n\n // Only rachet OToken supply upwards\n ousdSupply = oUSD.totalSupply(); // Final check should use latest value\n if (vaultValue > ousdSupply) {\n oUSD.changeSupply(vaultValue);\n }\n return vaultValue;\n }\n\n /**\n * @notice Determine the total value of assets held by the vault and its\n * strategies.\n * @return value Total value in USD/ETH (1e18)\n */\n function totalValue() external view virtual returns (uint256 value) {\n value = _totalValue();\n }\n\n /**\n * @dev Internal Calculate the total value of the assets held by the\n * vault and its strategies.\n * @return value Total value in USD/ETH (1e18)\n */\n function _totalValue() internal view virtual returns (uint256 value) {\n return _totalValueInVault() + _totalValueInStrategies();\n }\n\n /**\n * @dev Internal to calculate total value of all assets held in Vault.\n * @return value Total value in USD/ETH (1e18)\n */\n function _totalValueInVault()\n internal\n view\n virtual\n returns (uint256 value)\n {\n uint256 assetCount = allAssets.length;\n for (uint256 y = 0; y < assetCount; ++y) {\n address assetAddr = allAssets[y];\n uint256 balance = IERC20(assetAddr).balanceOf(address(this));\n if (balance > 0) {\n value += _toUnits(balance, assetAddr);\n }\n }\n }\n\n /**\n * @dev Internal to calculate total value of all assets held in Strategies.\n * @return value Total value in USD/ETH (1e18)\n */\n function _totalValueInStrategies() internal view returns (uint256 value) {\n uint256 stratCount = allStrategies.length;\n for (uint256 i = 0; i < stratCount; ++i) {\n value = value + _totalValueInStrategy(allStrategies[i]);\n }\n }\n\n /**\n * @dev Internal to calculate total value of all assets held by strategy.\n * @param _strategyAddr Address of the strategy\n * @return value Total value in USD/ETH (1e18)\n */\n function _totalValueInStrategy(address _strategyAddr)\n internal\n view\n returns (uint256 value)\n {\n IStrategy strategy = IStrategy(_strategyAddr);\n uint256 assetCount = allAssets.length;\n for (uint256 y = 0; y < assetCount; ++y) {\n address assetAddr = allAssets[y];\n if (strategy.supportsAsset(assetAddr)) {\n uint256 balance = strategy.checkBalance(assetAddr);\n if (balance > 0) {\n value += _toUnits(balance, assetAddr);\n }\n }\n }\n }\n\n /**\n * @notice Get the balance of an asset held in Vault and all strategies.\n * @param _asset Address of asset\n * @return uint256 Balance of asset in decimals of asset\n */\n function checkBalance(address _asset) external view returns (uint256) {\n return _checkBalance(_asset);\n }\n\n /**\n * @notice Get the balance of an asset held in Vault and all strategies.\n * @param _asset Address of asset\n * @return balance Balance of asset in decimals of asset\n */\n function _checkBalance(address _asset)\n internal\n view\n virtual\n returns (uint256 balance)\n {\n IERC20 asset = IERC20(_asset);\n balance = asset.balanceOf(address(this));\n uint256 stratCount = allStrategies.length;\n for (uint256 i = 0; i < stratCount; ++i) {\n IStrategy strategy = IStrategy(allStrategies[i]);\n if (strategy.supportsAsset(_asset)) {\n balance = balance + strategy.checkBalance(_asset);\n }\n }\n }\n\n /**\n * @notice Calculate the outputs for a redeem function, i.e. the mix of\n * coins that will be returned\n */\n function calculateRedeemOutputs(uint256 _amount)\n external\n view\n returns (uint256[] memory)\n {\n return _calculateRedeemOutputs(_amount);\n }\n\n /**\n * @dev Calculate the outputs for a redeem function, i.e. the mix of\n * coins that will be returned.\n * @return outputs Array of amounts respective to the supported assets\n */\n function _calculateRedeemOutputs(uint256 _amount)\n internal\n view\n virtual\n returns (uint256[] memory outputs)\n {\n // We always give out coins in proportion to how many we have,\n // Now if all coins were the same value, this math would easy,\n // just take the percentage of each coin, and multiply by the\n // value to be given out. But if coins are worth more than $1,\n // then we would end up handing out too many coins. We need to\n // adjust by the total value of coins.\n //\n // To do this, we total up the value of our coins, by their\n // percentages. Then divide what we would otherwise give out by\n // this number.\n //\n // Let say we have 100 DAI at $1.06 and 200 USDT at $1.00.\n // So for every 1 DAI we give out, we'll be handing out 2 USDT\n // Our total output ratio is: 33% * 1.06 + 66% * 1.00 = 1.02\n //\n // So when calculating the output, we take the percentage of\n // each coin, times the desired output value, divided by the\n // totalOutputRatio.\n //\n // For example, withdrawing: 30 OUSD:\n // DAI 33% * 30 / 1.02 = 9.80 DAI\n // USDT = 66 % * 30 / 1.02 = 19.60 USDT\n //\n // Checking these numbers:\n // 9.80 DAI * 1.06 = $10.40\n // 19.60 USDT * 1.00 = $19.60\n //\n // And so the user gets $10.40 + $19.60 = $30 worth of value.\n\n uint256 assetCount = allAssets.length;\n uint256[] memory assetUnits = new uint256[](assetCount);\n uint256[] memory assetBalances = new uint256[](assetCount);\n outputs = new uint256[](assetCount);\n\n // Calculate redeem fee\n if (redeemFeeBps > 0) {\n uint256 redeemFee = _amount.mulTruncateScale(redeemFeeBps, 1e4);\n _amount = _amount - redeemFee;\n }\n\n // Calculate assets balances and decimals once,\n // for a large gas savings.\n uint256 totalUnits = 0;\n for (uint256 i = 0; i < assetCount; ++i) {\n address assetAddr = allAssets[i];\n uint256 balance = _checkBalance(assetAddr);\n assetBalances[i] = balance;\n assetUnits[i] = _toUnits(balance, assetAddr);\n totalUnits = totalUnits + assetUnits[i];\n }\n // Calculate totalOutputRatio\n uint256 totalOutputRatio = 0;\n for (uint256 i = 0; i < assetCount; ++i) {\n uint256 unitPrice = _toUnitPrice(allAssets[i], false);\n uint256 ratio = (assetUnits[i] * unitPrice) / totalUnits;\n totalOutputRatio = totalOutputRatio + ratio;\n }\n // Calculate final outputs\n uint256 factor = _amount.divPrecisely(totalOutputRatio);\n for (uint256 i = 0; i < assetCount; ++i) {\n outputs[i] = (assetBalances[i] * factor) / totalUnits;\n }\n }\n\n /***************************************\n Pricing\n ****************************************/\n\n /**\n * @notice Returns the total price in 18 digit units for a given asset.\n * Never goes above 1, since that is how we price mints.\n * @param asset address of the asset\n * @return price uint256: unit (USD / ETH) price for 1 unit of the asset, in 18 decimal fixed\n */\n function priceUnitMint(address asset)\n external\n view\n returns (uint256 price)\n {\n /* need to supply 1 asset unit in asset's decimals and can not just hard-code\n * to 1e18 and ignore calling `_toUnits` since we need to consider assets\n * with the exchange rate\n */\n uint256 units = _toUnits(\n uint256(1e18).scaleBy(_getDecimals(asset), 18),\n asset\n );\n price = (_toUnitPrice(asset, true) * units) / 1e18;\n }\n\n /**\n * @notice Returns the total price in 18 digit unit for a given asset.\n * Never goes below 1, since that is how we price redeems\n * @param asset Address of the asset\n * @return price uint256: unit (USD / ETH) price for 1 unit of the asset, in 18 decimal fixed\n */\n function priceUnitRedeem(address asset)\n external\n view\n returns (uint256 price)\n {\n /* need to supply 1 asset unit in asset's decimals and can not just hard-code\n * to 1e18 and ignore calling `_toUnits` since we need to consider assets\n * with the exchange rate\n */\n uint256 units = _toUnits(\n uint256(1e18).scaleBy(_getDecimals(asset), 18),\n asset\n );\n price = (_toUnitPrice(asset, false) * units) / 1e18;\n }\n\n /***************************************\n Utils\n ****************************************/\n\n /**\n * @dev Convert a quantity of a token into 1e18 fixed decimal \"units\"\n * in the underlying base (USD/ETH) used by the vault.\n * Price is not taken into account, only quantity.\n *\n * Examples of this conversion:\n *\n * - 1e18 DAI becomes 1e18 units (same decimals)\n * - 1e6 USDC becomes 1e18 units (decimal conversion)\n * - 1e18 rETH becomes 1.2e18 units (exchange rate conversion)\n *\n * @param _raw Quantity of asset\n * @param _asset Core Asset address\n * @return value 1e18 normalized quantity of units\n */\n function _toUnits(uint256 _raw, address _asset)\n internal\n view\n returns (uint256)\n {\n UnitConversion conversion = assets[_asset].unitConversion;\n if (conversion == UnitConversion.DECIMALS) {\n return _raw.scaleBy(18, _getDecimals(_asset));\n } else if (conversion == UnitConversion.GETEXCHANGERATE) {\n uint256 exchangeRate = IGetExchangeRateToken(_asset)\n .getExchangeRate();\n return (_raw * exchangeRate) / 1e18;\n } else {\n revert(\"Unsupported conversion type\");\n }\n }\n\n /**\n * @dev Returns asset's unit price accounting for different asset types\n * and takes into account the context in which that price exists -\n * - mint or redeem.\n *\n * Note: since we are returning the price of the unit and not the one of the\n * asset (see comment above how 1 rETH exchanges for 1.2 units) we need\n * to make the Oracle price adjustment as well since we are pricing the\n * units and not the assets.\n *\n * The price also snaps to a \"full unit price\" in case a mint or redeem\n * action would be unfavourable to the protocol.\n *\n */\n function _toUnitPrice(address _asset, bool isMint)\n internal\n view\n returns (uint256 price)\n {\n UnitConversion conversion = assets[_asset].unitConversion;\n price = IOracle(priceProvider).price(_asset);\n\n if (conversion == UnitConversion.GETEXCHANGERATE) {\n uint256 exchangeRate = IGetExchangeRateToken(_asset)\n .getExchangeRate();\n price = (price * 1e18) / exchangeRate;\n } else if (conversion != UnitConversion.DECIMALS) {\n revert(\"Unsupported conversion type\");\n }\n\n /* At this stage the price is already adjusted to the unit\n * so the price checks are agnostic to underlying asset being\n * pegged to a USD or to an ETH or having a custom exchange rate.\n */\n require(price <= MAX_UNIT_PRICE_DRIFT, \"Vault: Price exceeds max\");\n require(price >= MIN_UNIT_PRICE_DRIFT, \"Vault: Price under min\");\n\n if (isMint) {\n /* Never price a normalized unit price for more than one\n * unit of OETH/OUSD when minting.\n */\n if (price > 1e18) {\n price = 1e18;\n }\n require(price >= MINT_MINIMUM_UNIT_PRICE, \"Asset price below peg\");\n } else {\n /* Never give out more than 1 normalized unit amount of assets\n * for one unit of OETH/OUSD when redeeming.\n */\n if (price < 1e18) {\n price = 1e18;\n }\n }\n }\n\n function _getDecimals(address _asset)\n internal\n view\n returns (uint256 decimals)\n {\n decimals = assets[_asset].decimals;\n require(decimals > 0, \"Decimals not cached\");\n }\n\n /**\n * @notice Return the number of assets supported by the Vault.\n */\n function getAssetCount() public view returns (uint256) {\n return allAssets.length;\n }\n\n /**\n * @notice Gets the vault configuration of a supported asset.\n */\n function getAssetConfig(address _asset)\n public\n view\n returns (Asset memory config)\n {\n config = assets[_asset];\n }\n\n /**\n * @notice Return all vault asset addresses in order\n */\n function getAllAssets() external view returns (address[] memory) {\n return allAssets;\n }\n\n /**\n * @notice Return the number of strategies active on the Vault.\n */\n function getStrategyCount() external view returns (uint256) {\n return allStrategies.length;\n }\n\n /**\n * @notice Return the array of all strategies\n */\n function getAllStrategies() external view returns (address[] memory) {\n return allStrategies;\n }\n\n /**\n * @notice Returns whether the vault supports the asset\n * @param _asset address of the asset\n * @return true if supported\n */\n function isSupportedAsset(address _asset) external view returns (bool) {\n return assets[_asset].isSupported;\n }\n\n /**\n * @dev Falldown to the admin implementation\n * @notice This is a catch all for all functions not declared in core\n */\n // solhint-disable-next-line no-complex-fallback\n fallback() external {\n bytes32 slot = adminImplPosition;\n // solhint-disable-next-line no-inline-assembly\n assembly {\n // Copy msg.data. We take full control of memory in this inline assembly\n // block because it will not return to Solidity code. We overwrite the\n // Solidity scratch pad at memory position 0.\n calldatacopy(0, 0, calldatasize())\n\n // Call the implementation.\n // out and outsize are 0 because we don't know the size yet.\n let result := delegatecall(\n gas(),\n sload(slot),\n 0,\n calldatasize(),\n 0,\n 0\n )\n\n // Copy the returned data.\n returndatacopy(0, 0, returndatasize())\n\n switch result\n // delegatecall returns 0 on error.\n case 0 {\n revert(0, returndatasize())\n }\n default {\n return(0, returndatasize())\n }\n }\n }\n\n function abs(int256 x) private pure returns (uint256) {\n require(x < int256(MAX_INT), \"Amount too high\");\n return x >= 0 ? uint256(x) : uint256(-x);\n }\n}\n" + }, + "contracts/vault/VaultInitializer.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @title OToken VaultInitializer contract\n * @notice The Vault contract initializes the vault.\n * @author Origin Protocol Inc\n */\n\nimport \"./VaultStorage.sol\";\n\ncontract VaultInitializer is VaultStorage {\n function initialize(address _priceProvider, address _oToken)\n external\n onlyGovernor\n initializer\n {\n require(_priceProvider != address(0), \"PriceProvider address is zero\");\n require(_oToken != address(0), \"oToken address is zero\");\n\n oUSD = OUSD(_oToken);\n\n priceProvider = _priceProvider;\n\n rebasePaused = false;\n capitalPaused = true;\n\n // Initial redeem fee of 0 basis points\n redeemFeeBps = 0;\n // Initial Vault buffer of 0%\n vaultBuffer = 0;\n // Initial allocate threshold of 25,000 OUSD\n autoAllocateThreshold = 25000e18;\n // Threshold for rebasing\n rebaseThreshold = 1000e18;\n // Initialize all strategies\n allStrategies = new address[](0);\n }\n}\n" + }, + "contracts/vault/VaultStorage.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @title OToken VaultStorage contract\n * @notice The VaultStorage contract defines the storage for the Vault contracts\n * @author Origin Protocol Inc\n */\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { Address } from \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport { IStrategy } from \"../interfaces/IStrategy.sol\";\nimport { Governable } from \"../governance/Governable.sol\";\nimport { OUSD } from \"../token/OUSD.sol\";\nimport { Initializable } from \"../utils/Initializable.sol\";\nimport \"../utils/Helpers.sol\";\n\ncontract VaultStorage is Initializable, Governable {\n using SafeERC20 for IERC20;\n\n event AssetSupported(address _asset);\n event AssetRemoved(address _asset);\n event AssetDefaultStrategyUpdated(address _asset, address _strategy);\n event AssetAllocated(address _asset, address _strategy, uint256 _amount);\n event StrategyApproved(address _addr);\n event StrategyRemoved(address _addr);\n event Mint(address _addr, uint256 _value);\n event Redeem(address _addr, uint256 _value);\n event CapitalPaused();\n event CapitalUnpaused();\n event RebasePaused();\n event RebaseUnpaused();\n event VaultBufferUpdated(uint256 _vaultBuffer);\n event OusdMetaStrategyUpdated(address _ousdMetaStrategy);\n event RedeemFeeUpdated(uint256 _redeemFeeBps);\n event PriceProviderUpdated(address _priceProvider);\n event AllocateThresholdUpdated(uint256 _threshold);\n event RebaseThresholdUpdated(uint256 _threshold);\n event StrategistUpdated(address _address);\n event MaxSupplyDiffChanged(uint256 maxSupplyDiff);\n event YieldDistribution(address _to, uint256 _yield, uint256 _fee);\n event TrusteeFeeBpsChanged(uint256 _basis);\n event TrusteeAddressChanged(address _address);\n event NetOusdMintForStrategyThresholdChanged(uint256 _threshold);\n event SwapperChanged(address _address);\n event SwapAllowedUndervalueChanged(uint256 _basis);\n event SwapSlippageChanged(address _asset, uint256 _basis);\n event Swapped(\n address indexed _fromAsset,\n address indexed _toAsset,\n uint256 _fromAssetAmount,\n uint256 _toAssetAmount\n );\n event DripperChanged(address indexed _dripper);\n event WithdrawalRequested(\n address indexed _withdrawer,\n uint256 indexed _requestId,\n uint256 _amount,\n uint256 _queued\n );\n event WithdrawalClaimed(\n address indexed _withdrawer,\n uint256 indexed _requestId,\n uint256 _amount\n );\n event WithdrawalClaimable(uint256 _claimable, uint256 _newClaimable);\n\n // Assets supported by the Vault, i.e. Stablecoins\n enum UnitConversion {\n DECIMALS,\n GETEXCHANGERATE\n }\n // Changed to fit into a single storage slot so the decimals needs to be recached\n struct Asset {\n // Note: OETHVaultCore doesn't use `isSupported` when minting,\n // redeeming or checking balance of assets.\n bool isSupported;\n UnitConversion unitConversion;\n uint8 decimals;\n // Max allowed slippage from the Oracle price when swapping collateral assets in basis points.\n // For example 40 == 0.4% slippage\n uint16 allowedOracleSlippageBps;\n }\n\n /// @dev mapping of supported vault assets to their configuration\n // slither-disable-next-line uninitialized-state\n mapping(address => Asset) internal assets;\n /// @dev list of all assets supported by the vault.\n // slither-disable-next-line uninitialized-state\n address[] internal allAssets;\n\n // Strategies approved for use by the Vault\n struct Strategy {\n bool isSupported;\n uint256 _deprecated; // Deprecated storage slot\n }\n /// @dev mapping of strategy contracts to their configuration\n mapping(address => Strategy) internal strategies;\n /// @dev list of all vault strategies\n address[] internal allStrategies;\n\n /// @notice Address of the Oracle price provider contract\n // slither-disable-next-line uninitialized-state\n address public priceProvider;\n /// @notice pause rebasing if true\n bool public rebasePaused = false;\n /// @notice pause operations that change the OToken supply.\n /// eg mint, redeem, allocate, mint/burn for strategy\n bool public capitalPaused = true;\n /// @notice Redemption fee in basis points. eg 50 = 0.5%\n uint256 public redeemFeeBps;\n /// @notice Percentage of assets to keep in Vault to handle (most) withdrawals. 100% = 1e18.\n uint256 public vaultBuffer;\n /// @notice OToken mints over this amount automatically allocate funds. 18 decimals.\n uint256 public autoAllocateThreshold;\n /// @notice OToken mints over this amount automatically rebase. 18 decimals.\n uint256 public rebaseThreshold;\n\n /// @dev Address of the OToken token. eg OUSD or OETH.\n // slither-disable-next-line uninitialized-state\n OUSD internal oUSD;\n\n //keccak256(\"OUSD.vault.governor.admin.impl\");\n bytes32 constant adminImplPosition =\n 0xa2bd3d3cf188a41358c8b401076eb59066b09dec5775650c0de4c55187d17bd9;\n\n // Address of the contract responsible for post rebase syncs with AMMs\n address private _deprecated_rebaseHooksAddr = address(0);\n\n // Deprecated: Address of Uniswap\n // slither-disable-next-line constable-states\n address private _deprecated_uniswapAddr = address(0);\n\n /// @notice Address of the Strategist\n address public strategistAddr = address(0);\n\n /// @notice Mapping of asset address to the Strategy that they should automatically\n // be allocated to\n // slither-disable-next-line uninitialized-state\n mapping(address => address) public assetDefaultStrategies;\n\n /// @notice Max difference between total supply and total value of assets. 18 decimals.\n // slither-disable-next-line uninitialized-state\n uint256 public maxSupplyDiff;\n\n /// @notice Trustee contract that can collect a percentage of yield\n address public trusteeAddress;\n\n /// @notice Amount of yield collected in basis points. eg 2000 = 20%\n uint256 public trusteeFeeBps;\n\n /// @dev Deprecated: Tokens that should be swapped for stablecoins\n address[] private _deprecated_swapTokens;\n\n uint256 constant MINT_MINIMUM_UNIT_PRICE = 0.998e18;\n\n /// @notice Metapool strategy that is allowed to mint/burn OTokens without changing collateral\n address public ousdMetaStrategy = address(0);\n\n /// @notice How much OTokens are currently minted by the strategy\n int256 public netOusdMintedForStrategy = 0;\n\n /// @notice How much net total OTokens are allowed to be minted by all strategies\n uint256 public netOusdMintForStrategyThreshold = 0;\n\n uint256 constant MIN_UNIT_PRICE_DRIFT = 0.7e18;\n uint256 constant MAX_UNIT_PRICE_DRIFT = 1.3e18;\n\n /// @notice Collateral swap configuration.\n /// @dev is packed into a single storage slot to save gas.\n struct SwapConfig {\n // Contract that swaps the vault's collateral assets\n address swapper;\n // Max allowed percentage the total value can drop below the total supply in basis points.\n // For example 100 == 1%\n uint16 allowedUndervalueBps;\n }\n SwapConfig internal swapConfig = SwapConfig(address(0), 0);\n\n /// @notice Address of the Dripper contract that streams harvested rewards to the Vault\n /// @dev The vault is proxied so needs to be set with setDripper against the proxy contract.\n // slither-disable-start constable-states\n // slither-disable-next-line uninitialized-state\n address public dripper;\n // slither-disable-end constable-states\n\n /// Withdrawal Queue Storage /////\n\n struct WithdrawalQueueMetadata {\n // cumulative total of all withdrawal requests included the ones that have already been claimed\n uint128 queued;\n // cumulative total of all the requests that can be claimed included the ones that have already been claimed\n uint128 claimable;\n // total of all the requests that have been claimed\n uint128 claimed;\n // index of the next withdrawal request starting at 0\n uint128 nextWithdrawalIndex;\n }\n\n // slither-disable-next-line uninitialized-state\n WithdrawalQueueMetadata public withdrawalQueueMetadata;\n\n struct WithdrawalRequest {\n address withdrawer;\n bool claimed;\n // Amount of oTokens to redeem\n uint128 amount;\n // cumulative total of all withdrawal requests including this one.\n // this request can be claimed when this queued amount is less than or equal to the queue's claimable amount.\n uint128 queued;\n }\n\n // Mapping of withdrawal requests indexes to the user withdrawal request data\n mapping(uint256 => WithdrawalRequest) public withdrawalRequests;\n\n // For future use\n uint256[46] private __gap;\n\n /**\n * @notice set the implementation for the admin, this needs to be in a base class else we cannot set it\n * @param newImpl address of the implementation\n */\n function setAdminImpl(address newImpl) external onlyGovernor {\n require(\n Address.isContract(newImpl),\n \"new implementation is not a contract\"\n );\n bytes32 position = adminImplPosition;\n // solhint-disable-next-line no-inline-assembly\n assembly {\n sstore(position, newImpl)\n }\n }\n}\n" + }, + "hardhat/console.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity >= 0.4.22 <0.9.0;\n\nlibrary console {\n\taddress constant CONSOLE_ADDRESS = address(0x000000000000000000636F6e736F6c652e6c6f67);\n\n\tfunction _sendLogPayload(bytes memory payload) private view {\n\t\tuint256 payloadLength = payload.length;\n\t\taddress consoleAddress = CONSOLE_ADDRESS;\n\t\tassembly {\n\t\t\tlet payloadStart := add(payload, 32)\n\t\t\tlet r := staticcall(gas(), consoleAddress, payloadStart, payloadLength, 0, 0)\n\t\t}\n\t}\n\n\tfunction log() internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log()\"));\n\t}\n\n\tfunction logInt(int256 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(int256)\", p0));\n\t}\n\n\tfunction logUint(uint256 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256)\", p0));\n\t}\n\n\tfunction logString(string memory p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string)\", p0));\n\t}\n\n\tfunction logBool(bool p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool)\", p0));\n\t}\n\n\tfunction logAddress(address p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address)\", p0));\n\t}\n\n\tfunction logBytes(bytes memory p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes)\", p0));\n\t}\n\n\tfunction logBytes1(bytes1 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes1)\", p0));\n\t}\n\n\tfunction logBytes2(bytes2 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes2)\", p0));\n\t}\n\n\tfunction logBytes3(bytes3 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes3)\", p0));\n\t}\n\n\tfunction logBytes4(bytes4 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes4)\", p0));\n\t}\n\n\tfunction logBytes5(bytes5 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes5)\", p0));\n\t}\n\n\tfunction logBytes6(bytes6 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes6)\", p0));\n\t}\n\n\tfunction logBytes7(bytes7 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes7)\", p0));\n\t}\n\n\tfunction logBytes8(bytes8 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes8)\", p0));\n\t}\n\n\tfunction logBytes9(bytes9 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes9)\", p0));\n\t}\n\n\tfunction logBytes10(bytes10 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes10)\", p0));\n\t}\n\n\tfunction logBytes11(bytes11 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes11)\", p0));\n\t}\n\n\tfunction logBytes12(bytes12 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes12)\", p0));\n\t}\n\n\tfunction logBytes13(bytes13 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes13)\", p0));\n\t}\n\n\tfunction logBytes14(bytes14 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes14)\", p0));\n\t}\n\n\tfunction logBytes15(bytes15 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes15)\", p0));\n\t}\n\n\tfunction logBytes16(bytes16 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes16)\", p0));\n\t}\n\n\tfunction logBytes17(bytes17 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes17)\", p0));\n\t}\n\n\tfunction logBytes18(bytes18 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes18)\", p0));\n\t}\n\n\tfunction logBytes19(bytes19 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes19)\", p0));\n\t}\n\n\tfunction logBytes20(bytes20 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes20)\", p0));\n\t}\n\n\tfunction logBytes21(bytes21 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes21)\", p0));\n\t}\n\n\tfunction logBytes22(bytes22 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes22)\", p0));\n\t}\n\n\tfunction logBytes23(bytes23 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes23)\", p0));\n\t}\n\n\tfunction logBytes24(bytes24 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes24)\", p0));\n\t}\n\n\tfunction logBytes25(bytes25 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes25)\", p0));\n\t}\n\n\tfunction logBytes26(bytes26 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes26)\", p0));\n\t}\n\n\tfunction logBytes27(bytes27 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes27)\", p0));\n\t}\n\n\tfunction logBytes28(bytes28 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes28)\", p0));\n\t}\n\n\tfunction logBytes29(bytes29 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes29)\", p0));\n\t}\n\n\tfunction logBytes30(bytes30 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes30)\", p0));\n\t}\n\n\tfunction logBytes31(bytes31 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes31)\", p0));\n\t}\n\n\tfunction logBytes32(bytes32 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes32)\", p0));\n\t}\n\n\tfunction log(uint256 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256)\", p0));\n\t}\n\n\tfunction log(string memory p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string)\", p0));\n\t}\n\n\tfunction log(bool p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool)\", p0));\n\t}\n\n\tfunction log(address p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address)\", p0));\n\t}\n\n\tfunction log(uint256 p0, uint256 p1) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256)\", p0, p1));\n\t}\n\n\tfunction log(uint256 p0, string memory p1) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,string)\", p0, p1));\n\t}\n\n\tfunction log(uint256 p0, bool p1) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool)\", p0, p1));\n\t}\n\n\tfunction log(uint256 p0, address p1) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,address)\", p0, p1));\n\t}\n\n\tfunction log(string memory p0, uint256 p1) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,uint256)\", p0, p1));\n\t}\n\n\tfunction log(string memory p0, string memory p1) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,string)\", p0, p1));\n\t}\n\n\tfunction log(string memory p0, bool p1) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,bool)\", p0, p1));\n\t}\n\n\tfunction log(string memory p0, address p1) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,address)\", p0, p1));\n\t}\n\n\tfunction log(bool p0, uint256 p1) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256)\", p0, p1));\n\t}\n\n\tfunction log(bool p0, string memory p1) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,string)\", p0, p1));\n\t}\n\n\tfunction log(bool p0, bool p1) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,bool)\", p0, p1));\n\t}\n\n\tfunction log(bool p0, address p1) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,address)\", p0, p1));\n\t}\n\n\tfunction log(address p0, uint256 p1) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,uint256)\", p0, p1));\n\t}\n\n\tfunction log(address p0, string memory p1) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,string)\", p0, p1));\n\t}\n\n\tfunction log(address p0, bool p1) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,bool)\", p0, p1));\n\t}\n\n\tfunction log(address p0, address p1) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,address)\", p0, p1));\n\t}\n\n\tfunction log(uint256 p0, uint256 p1, uint256 p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,uint256)\", p0, p1, p2));\n\t}\n\n\tfunction log(uint256 p0, uint256 p1, string memory p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,string)\", p0, p1, p2));\n\t}\n\n\tfunction log(uint256 p0, uint256 p1, bool p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,bool)\", p0, p1, p2));\n\t}\n\n\tfunction log(uint256 p0, uint256 p1, address p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,address)\", p0, p1, p2));\n\t}\n\n\tfunction log(uint256 p0, string memory p1, uint256 p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,uint256)\", p0, p1, p2));\n\t}\n\n\tfunction log(uint256 p0, string memory p1, string memory p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,string)\", p0, p1, p2));\n\t}\n\n\tfunction log(uint256 p0, string memory p1, bool p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,bool)\", p0, p1, p2));\n\t}\n\n\tfunction log(uint256 p0, string memory p1, address p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,address)\", p0, p1, p2));\n\t}\n\n\tfunction log(uint256 p0, bool p1, uint256 p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,uint256)\", p0, p1, p2));\n\t}\n\n\tfunction log(uint256 p0, bool p1, string memory p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,string)\", p0, p1, p2));\n\t}\n\n\tfunction log(uint256 p0, bool p1, bool p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,bool)\", p0, p1, p2));\n\t}\n\n\tfunction log(uint256 p0, bool p1, address p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,address)\", p0, p1, p2));\n\t}\n\n\tfunction log(uint256 p0, address p1, uint256 p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,uint256)\", p0, p1, p2));\n\t}\n\n\tfunction log(uint256 p0, address p1, string memory p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,string)\", p0, p1, p2));\n\t}\n\n\tfunction log(uint256 p0, address p1, bool p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,bool)\", p0, p1, p2));\n\t}\n\n\tfunction log(uint256 p0, address p1, address p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,address)\", p0, p1, p2));\n\t}\n\n\tfunction log(string memory p0, uint256 p1, uint256 p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,uint256)\", p0, p1, p2));\n\t}\n\n\tfunction log(string memory p0, uint256 p1, string memory p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,string)\", p0, p1, p2));\n\t}\n\n\tfunction log(string memory p0, uint256 p1, bool p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,bool)\", p0, p1, p2));\n\t}\n\n\tfunction log(string memory p0, uint256 p1, address p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,address)\", p0, p1, p2));\n\t}\n\n\tfunction log(string memory p0, string memory p1, uint256 p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,string,uint256)\", p0, p1, p2));\n\t}\n\n\tfunction log(string memory p0, string memory p1, string memory p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,string,string)\", p0, p1, p2));\n\t}\n\n\tfunction log(string memory p0, string memory p1, bool p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,string,bool)\", p0, p1, p2));\n\t}\n\n\tfunction log(string memory p0, string memory p1, address p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,string,address)\", p0, p1, p2));\n\t}\n\n\tfunction log(string memory p0, bool p1, uint256 p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,bool,uint256)\", p0, p1, p2));\n\t}\n\n\tfunction log(string memory p0, bool p1, string memory p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,bool,string)\", p0, p1, p2));\n\t}\n\n\tfunction log(string memory p0, bool p1, bool p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,bool,bool)\", p0, p1, p2));\n\t}\n\n\tfunction log(string memory p0, bool p1, address p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,bool,address)\", p0, p1, p2));\n\t}\n\n\tfunction log(string memory p0, address p1, uint256 p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,address,uint256)\", p0, p1, p2));\n\t}\n\n\tfunction log(string memory p0, address p1, string memory p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,address,string)\", p0, p1, p2));\n\t}\n\n\tfunction log(string memory p0, address p1, bool p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,address,bool)\", p0, p1, p2));\n\t}\n\n\tfunction log(string memory p0, address p1, address p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,address,address)\", p0, p1, p2));\n\t}\n\n\tfunction log(bool p0, uint256 p1, uint256 p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,uint256)\", p0, p1, p2));\n\t}\n\n\tfunction log(bool p0, uint256 p1, string memory p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,string)\", p0, p1, p2));\n\t}\n\n\tfunction log(bool p0, uint256 p1, bool p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,bool)\", p0, p1, p2));\n\t}\n\n\tfunction log(bool p0, uint256 p1, address p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,address)\", p0, p1, p2));\n\t}\n\n\tfunction log(bool p0, string memory p1, uint256 p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,string,uint256)\", p0, p1, p2));\n\t}\n\n\tfunction log(bool p0, string memory p1, string memory p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,string,string)\", p0, p1, p2));\n\t}\n\n\tfunction log(bool p0, string memory p1, bool p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,string,bool)\", p0, p1, p2));\n\t}\n\n\tfunction log(bool p0, string memory p1, address p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,string,address)\", p0, p1, p2));\n\t}\n\n\tfunction log(bool p0, bool p1, uint256 p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,uint256)\", p0, p1, p2));\n\t}\n\n\tfunction log(bool p0, bool p1, string memory p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,string)\", p0, p1, p2));\n\t}\n\n\tfunction log(bool p0, bool p1, bool p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,bool)\", p0, p1, p2));\n\t}\n\n\tfunction log(bool p0, bool p1, address p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,address)\", p0, p1, p2));\n\t}\n\n\tfunction log(bool p0, address p1, uint256 p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,address,uint256)\", p0, p1, p2));\n\t}\n\n\tfunction log(bool p0, address p1, string memory p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,address,string)\", p0, p1, p2));\n\t}\n\n\tfunction log(bool p0, address p1, bool p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,address,bool)\", p0, p1, p2));\n\t}\n\n\tfunction log(bool p0, address p1, address p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,address,address)\", p0, p1, p2));\n\t}\n\n\tfunction log(address p0, uint256 p1, uint256 p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,uint256)\", p0, p1, p2));\n\t}\n\n\tfunction log(address p0, uint256 p1, string memory p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,string)\", p0, p1, p2));\n\t}\n\n\tfunction log(address p0, uint256 p1, bool p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,bool)\", p0, p1, p2));\n\t}\n\n\tfunction log(address p0, uint256 p1, address p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,address)\", p0, p1, p2));\n\t}\n\n\tfunction log(address p0, string memory p1, uint256 p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,string,uint256)\", p0, p1, p2));\n\t}\n\n\tfunction log(address p0, string memory p1, string memory p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,string,string)\", p0, p1, p2));\n\t}\n\n\tfunction log(address p0, string memory p1, bool p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,string,bool)\", p0, p1, p2));\n\t}\n\n\tfunction log(address p0, string memory p1, address p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,string,address)\", p0, p1, p2));\n\t}\n\n\tfunction log(address p0, bool p1, uint256 p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,bool,uint256)\", p0, p1, p2));\n\t}\n\n\tfunction log(address p0, bool p1, string memory p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,bool,string)\", p0, p1, p2));\n\t}\n\n\tfunction log(address p0, bool p1, bool p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,bool,bool)\", p0, p1, p2));\n\t}\n\n\tfunction log(address p0, bool p1, address p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,bool,address)\", p0, p1, p2));\n\t}\n\n\tfunction log(address p0, address p1, uint256 p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,address,uint256)\", p0, p1, p2));\n\t}\n\n\tfunction log(address p0, address p1, string memory p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,address,string)\", p0, p1, p2));\n\t}\n\n\tfunction log(address p0, address p1, bool p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,address,bool)\", p0, p1, p2));\n\t}\n\n\tfunction log(address p0, address p1, address p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,address,address)\", p0, p1, p2));\n\t}\n\n\tfunction log(uint256 p0, uint256 p1, uint256 p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,uint256,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, uint256 p1, uint256 p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,uint256,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, uint256 p1, uint256 p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,uint256,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, uint256 p1, uint256 p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,uint256,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, uint256 p1, string memory p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,string,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, uint256 p1, string memory p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,string,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, uint256 p1, string memory p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,string,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, uint256 p1, string memory p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,string,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, uint256 p1, bool p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,bool,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, uint256 p1, bool p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,bool,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, uint256 p1, bool p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,bool,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, uint256 p1, bool p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,bool,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, uint256 p1, address p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,address,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, uint256 p1, address p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,address,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, uint256 p1, address p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,address,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, uint256 p1, address p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,address,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, string memory p1, uint256 p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,uint256,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, string memory p1, uint256 p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,uint256,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, string memory p1, uint256 p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,uint256,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, string memory p1, uint256 p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,uint256,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, string memory p1, string memory p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,string,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, string memory p1, string memory p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,string,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, string memory p1, string memory p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,string,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, string memory p1, string memory p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,string,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, string memory p1, bool p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,bool,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, string memory p1, bool p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,bool,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, string memory p1, bool p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,bool,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, string memory p1, bool p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,bool,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, string memory p1, address p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,address,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, string memory p1, address p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,address,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, string memory p1, address p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,address,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, string memory p1, address p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,address,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, bool p1, uint256 p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,uint256,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, bool p1, uint256 p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,uint256,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, bool p1, uint256 p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,uint256,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, bool p1, uint256 p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,uint256,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, bool p1, string memory p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,string,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, bool p1, string memory p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,string,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, bool p1, string memory p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,string,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, bool p1, string memory p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,string,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, bool p1, bool p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,bool,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, bool p1, bool p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,bool,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, bool p1, bool p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,bool,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, bool p1, bool p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,bool,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, bool p1, address p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,address,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, bool p1, address p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,address,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, bool p1, address p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,address,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, bool p1, address p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,address,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, address p1, uint256 p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,uint256,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, address p1, uint256 p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,uint256,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, address p1, uint256 p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,uint256,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, address p1, uint256 p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,uint256,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, address p1, string memory p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,string,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, address p1, string memory p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,string,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, address p1, string memory p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,string,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, address p1, string memory p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,string,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, address p1, bool p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,bool,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, address p1, bool p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,bool,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, address p1, bool p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,bool,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, address p1, bool p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,bool,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, address p1, address p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,address,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, address p1, address p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,address,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, address p1, address p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,address,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint256 p0, address p1, address p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,address,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, uint256 p1, uint256 p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,uint256,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, uint256 p1, uint256 p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,uint256,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, uint256 p1, uint256 p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,uint256,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, uint256 p1, uint256 p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,uint256,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, uint256 p1, string memory p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,string,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, uint256 p1, string memory p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,string,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, uint256 p1, string memory p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,string,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, uint256 p1, string memory p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,string,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, uint256 p1, bool p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,bool,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, uint256 p1, bool p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,bool,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, uint256 p1, bool p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,bool,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, uint256 p1, bool p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,bool,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, uint256 p1, address p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,address,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, uint256 p1, address p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,address,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, uint256 p1, address p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,address,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, uint256 p1, address p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,address,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, string memory p1, uint256 p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,string,uint256,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, string memory p1, uint256 p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,string,uint256,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, string memory p1, uint256 p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,string,uint256,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, string memory p1, uint256 p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,string,uint256,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, string memory p1, string memory p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,string,string,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, string memory p1, string memory p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,string,string,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, string memory p1, string memory p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,string,string,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, string memory p1, string memory p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,string,string,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, string memory p1, bool p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,string,bool,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, string memory p1, bool p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,string,bool,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, string memory p1, bool p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,string,bool,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, string memory p1, bool p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,string,bool,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, string memory p1, address p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,string,address,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, string memory p1, address p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,string,address,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, string memory p1, address p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,string,address,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, string memory p1, address p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,string,address,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, bool p1, uint256 p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,bool,uint256,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, bool p1, uint256 p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,bool,uint256,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, bool p1, uint256 p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,bool,uint256,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, bool p1, uint256 p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,bool,uint256,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, bool p1, string memory p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,bool,string,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, bool p1, string memory p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,bool,string,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, bool p1, string memory p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,bool,string,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, bool p1, string memory p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,bool,string,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, bool p1, bool p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,bool,bool,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, bool p1, bool p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,bool,bool,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, bool p1, bool p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,bool,bool,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, bool p1, bool p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,bool,bool,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, bool p1, address p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,bool,address,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, bool p1, address p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,bool,address,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, bool p1, address p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,bool,address,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, bool p1, address p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,bool,address,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, address p1, uint256 p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,address,uint256,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, address p1, uint256 p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,address,uint256,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, address p1, uint256 p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,address,uint256,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, address p1, uint256 p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,address,uint256,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, address p1, string memory p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,address,string,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, address p1, string memory p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,address,string,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, address p1, string memory p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,address,string,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, address p1, string memory p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,address,string,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, address p1, bool p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,address,bool,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, address p1, bool p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,address,bool,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, address p1, bool p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,address,bool,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, address p1, bool p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,address,bool,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, address p1, address p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,address,address,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, address p1, address p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,address,address,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, address p1, address p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,address,address,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, address p1, address p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,address,address,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, uint256 p1, uint256 p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,uint256,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, uint256 p1, uint256 p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,uint256,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, uint256 p1, uint256 p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,uint256,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, uint256 p1, uint256 p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,uint256,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, uint256 p1, string memory p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,string,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, uint256 p1, string memory p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,string,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, uint256 p1, string memory p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,string,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, uint256 p1, string memory p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,string,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, uint256 p1, bool p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,bool,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, uint256 p1, bool p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,bool,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, uint256 p1, bool p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,bool,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, uint256 p1, bool p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,bool,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, uint256 p1, address p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,address,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, uint256 p1, address p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,address,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, uint256 p1, address p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,address,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, uint256 p1, address p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,address,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, string memory p1, uint256 p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,string,uint256,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, string memory p1, uint256 p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,string,uint256,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, string memory p1, uint256 p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,string,uint256,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, string memory p1, uint256 p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,string,uint256,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, string memory p1, string memory p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,string,string,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, string memory p1, string memory p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,string,string,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, string memory p1, string memory p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,string,string,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, string memory p1, string memory p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,string,string,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, string memory p1, bool p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,string,bool,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, string memory p1, bool p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,string,bool,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, string memory p1, bool p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,string,bool,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, string memory p1, bool p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,string,bool,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, string memory p1, address p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,string,address,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, string memory p1, address p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,string,address,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, string memory p1, address p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,string,address,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, string memory p1, address p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,string,address,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, bool p1, uint256 p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,uint256,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, bool p1, uint256 p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,uint256,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, bool p1, uint256 p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,uint256,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, bool p1, uint256 p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,uint256,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, bool p1, string memory p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,string,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, bool p1, string memory p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,string,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, bool p1, string memory p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,string,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, bool p1, string memory p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,string,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, bool p1, bool p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,bool,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, bool p1, bool p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,bool,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, bool p1, bool p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,bool,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, bool p1, bool p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,bool,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, bool p1, address p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,address,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, bool p1, address p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,address,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, bool p1, address p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,address,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, bool p1, address p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,address,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, address p1, uint256 p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,address,uint256,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, address p1, uint256 p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,address,uint256,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, address p1, uint256 p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,address,uint256,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, address p1, uint256 p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,address,uint256,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, address p1, string memory p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,address,string,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, address p1, string memory p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,address,string,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, address p1, string memory p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,address,string,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, address p1, string memory p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,address,string,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, address p1, bool p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,address,bool,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, address p1, bool p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,address,bool,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, address p1, bool p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,address,bool,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, address p1, bool p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,address,bool,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, address p1, address p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,address,address,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, address p1, address p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,address,address,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, address p1, address p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,address,address,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, address p1, address p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,address,address,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, uint256 p1, uint256 p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,uint256,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, uint256 p1, uint256 p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,uint256,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, uint256 p1, uint256 p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,uint256,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, uint256 p1, uint256 p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,uint256,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, uint256 p1, string memory p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,string,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, uint256 p1, string memory p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,string,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, uint256 p1, string memory p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,string,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, uint256 p1, string memory p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,string,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, uint256 p1, bool p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,bool,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, uint256 p1, bool p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,bool,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, uint256 p1, bool p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,bool,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, uint256 p1, bool p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,bool,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, uint256 p1, address p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,address,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, uint256 p1, address p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,address,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, uint256 p1, address p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,address,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, uint256 p1, address p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,address,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, string memory p1, uint256 p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,string,uint256,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, string memory p1, uint256 p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,string,uint256,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, string memory p1, uint256 p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,string,uint256,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, string memory p1, uint256 p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,string,uint256,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, string memory p1, string memory p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,string,string,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, string memory p1, string memory p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,string,string,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, string memory p1, string memory p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,string,string,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, string memory p1, string memory p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,string,string,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, string memory p1, bool p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,string,bool,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, string memory p1, bool p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,string,bool,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, string memory p1, bool p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,string,bool,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, string memory p1, bool p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,string,bool,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, string memory p1, address p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,string,address,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, string memory p1, address p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,string,address,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, string memory p1, address p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,string,address,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, string memory p1, address p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,string,address,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, bool p1, uint256 p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,bool,uint256,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, bool p1, uint256 p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,bool,uint256,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, bool p1, uint256 p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,bool,uint256,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, bool p1, uint256 p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,bool,uint256,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, bool p1, string memory p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,bool,string,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, bool p1, string memory p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,bool,string,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, bool p1, string memory p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,bool,string,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, bool p1, string memory p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,bool,string,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, bool p1, bool p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,bool,bool,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, bool p1, bool p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,bool,bool,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, bool p1, bool p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,bool,bool,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, bool p1, bool p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,bool,bool,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, bool p1, address p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,bool,address,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, bool p1, address p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,bool,address,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, bool p1, address p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,bool,address,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, bool p1, address p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,bool,address,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, address p1, uint256 p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,address,uint256,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, address p1, uint256 p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,address,uint256,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, address p1, uint256 p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,address,uint256,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, address p1, uint256 p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,address,uint256,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, address p1, string memory p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,address,string,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, address p1, string memory p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,address,string,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, address p1, string memory p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,address,string,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, address p1, string memory p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,address,string,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, address p1, bool p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,address,bool,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, address p1, bool p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,address,bool,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, address p1, bool p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,address,bool,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, address p1, bool p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,address,bool,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, address p1, address p2, uint256 p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,address,address,uint256)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, address p1, address p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,address,address,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, address p1, address p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,address,address,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, address p1, address p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,address,address,address)\", p0, p1, p2, p3));\n\t}\n\n}\n" + }, + "lib/openzeppelin/interfaces/IERC4626.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\nimport { IERC20Metadata } from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\ninterface IERC4626 is IERC20, IERC20Metadata {\n event Deposit(address indexed caller, address indexed owner, uint256 assets, uint256 shares);\n\n event Withdraw(\n address indexed caller,\n address indexed receiver,\n address indexed owner,\n uint256 assets,\n uint256 shares\n );\n\n /**\n * @dev Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing.\n *\n * - MUST be an ERC-20 token contract.\n * - MUST NOT revert.\n */\n function asset() external view returns (address assetTokenAddress);\n\n /**\n * @dev Returns the total amount of the underlying asset that is “managed” by Vault.\n *\n * - SHOULD include any compounding that occurs from yield.\n * - MUST be inclusive of any fees that are charged against assets in the Vault.\n * - MUST NOT revert.\n */\n function totalAssets() external view returns (uint256 totalManagedAssets);\n\n /**\n * @dev Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal\n * scenario where all the conditions are met.\n *\n * - MUST NOT be inclusive of any fees that are charged against assets in the Vault.\n * - MUST NOT show any variations depending on the caller.\n * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.\n * - MUST NOT revert.\n *\n * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the\n * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and\n * from.\n */\n function convertToShares(uint256 assets) external view returns (uint256 shares);\n\n /**\n * @dev Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal\n * scenario where all the conditions are met.\n *\n * - MUST NOT be inclusive of any fees that are charged against assets in the Vault.\n * - MUST NOT show any variations depending on the caller.\n * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.\n * - MUST NOT revert.\n *\n * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the\n * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and\n * from.\n */\n function convertToAssets(uint256 shares) external view returns (uint256 assets);\n\n /**\n * @dev Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver,\n * through a deposit call.\n *\n * - MUST return a limited value if receiver is subject to some deposit limit.\n * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited.\n * - MUST NOT revert.\n */\n function maxDeposit(address receiver) external view returns (uint256 maxAssets);\n\n /**\n * @dev Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given\n * current on-chain conditions.\n *\n * - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit\n * call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called\n * in the same transaction.\n * - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the\n * deposit would be accepted, regardless if the user has enough tokens approved, etc.\n * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.\n * - MUST NOT revert.\n *\n * NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in\n * share price or some other type of condition, meaning the depositor will lose assets by depositing.\n */\n function previewDeposit(uint256 assets) external view returns (uint256 shares);\n\n /**\n * @dev Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens.\n *\n * - MUST emit the Deposit event.\n * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n * deposit execution, and are accounted for during deposit.\n * - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not\n * approving enough underlying tokens to the Vault contract, etc).\n *\n * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.\n */\n function deposit(uint256 assets, address receiver) external returns (uint256 shares);\n\n /**\n * @dev Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call.\n * - MUST return a limited value if receiver is subject to some mint limit.\n * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted.\n * - MUST NOT revert.\n */\n function maxMint(address receiver) external view returns (uint256 maxShares);\n\n /**\n * @dev Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given\n * current on-chain conditions.\n *\n * - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call\n * in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the\n * same transaction.\n * - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint\n * would be accepted, regardless if the user has enough tokens approved, etc.\n * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.\n * - MUST NOT revert.\n *\n * NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in\n * share price or some other type of condition, meaning the depositor will lose assets by minting.\n */\n function previewMint(uint256 shares) external view returns (uint256 assets);\n\n /**\n * @dev Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens.\n *\n * - MUST emit the Deposit event.\n * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint\n * execution, and are accounted for during mint.\n * - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not\n * approving enough underlying tokens to the Vault contract, etc).\n *\n * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.\n */\n function mint(uint256 shares, address receiver) external returns (uint256 assets);\n\n /**\n * @dev Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the\n * Vault, through a withdraw call.\n *\n * - MUST return a limited value if owner is subject to some withdrawal limit or timelock.\n * - MUST NOT revert.\n */\n function maxWithdraw(address owner) external view returns (uint256 maxAssets);\n\n /**\n * @dev Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block,\n * given current on-chain conditions.\n *\n * - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw\n * call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if\n * called\n * in the same transaction.\n * - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though\n * the withdrawal would be accepted, regardless if the user has enough shares, etc.\n * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.\n * - MUST NOT revert.\n *\n * NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in\n * share price or some other type of condition, meaning the depositor will lose assets by depositing.\n */\n function previewWithdraw(uint256 assets) external view returns (uint256 shares);\n\n /**\n * @dev Burns shares from owner and sends exactly assets of underlying tokens to receiver.\n *\n * - MUST emit the Withdraw event.\n * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n * withdraw execution, and are accounted for during withdraw.\n * - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner\n * not having enough shares, etc).\n *\n * Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed.\n * Those methods should be performed separately.\n */\n function withdraw(\n uint256 assets,\n address receiver,\n address owner\n ) external returns (uint256 shares);\n\n /**\n * @dev Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault,\n * through a redeem call.\n *\n * - MUST return a limited value if owner is subject to some withdrawal limit or timelock.\n * - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock.\n * - MUST NOT revert.\n */\n function maxRedeem(address owner) external view returns (uint256 maxShares);\n\n /**\n * @dev Allows an on-chain or off-chain user to simulate the effects of their redeemption at the current block,\n * given current on-chain conditions.\n *\n * - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call\n * in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the\n * same transaction.\n * - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the\n * redemption would be accepted, regardless if the user has enough shares, etc.\n * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.\n * - MUST NOT revert.\n *\n * NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in\n * share price or some other type of condition, meaning the depositor will lose assets by redeeming.\n */\n function previewRedeem(uint256 shares) external view returns (uint256 assets);\n\n /**\n * @dev Burns exactly shares from owner and sends assets of underlying tokens to receiver.\n *\n * - MUST emit the Withdraw event.\n * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n * redeem execution, and are accounted for during redeem.\n * - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner\n * not having enough shares, etc).\n *\n * NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed.\n * Those methods should be performed separately.\n */\n function redeem(\n uint256 shares,\n address receiver,\n address owner\n ) external returns (uint256 assets);\n}" + } + }, + "settings": { + "optimizer": { + "enabled": true, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata", + "devdoc", + "userdoc", + "storageLayout", + "evm.gasEstimates" + ], + "": [ + "ast" + ] + } + }, + "metadata": { + "useLiteralContent": true + } + } +} \ No newline at end of file From ba3c28cf9856f3813a48d28ee1cbcf408729ade8 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Thu, 4 Jul 2024 15:04:06 +1000 Subject: [PATCH 138/273] Added Vault requestWithdrawal andclaimWithdrawal Hardhat tasks Added Dripper collect and setDripDuration Hardhat tasks --- contracts/contracts/interfaces/IDripper.sol | 10 +++ contracts/tasks/dripper.js | 40 +++++++++++ contracts/tasks/tasks.js | 74 +++++++++++++++++++++ contracts/tasks/vault.js | 33 +++++++++ 4 files changed, 157 insertions(+) create mode 100644 contracts/tasks/dripper.js diff --git a/contracts/contracts/interfaces/IDripper.sol b/contracts/contracts/interfaces/IDripper.sol index c5d68bcee1..ff1b52cae7 100644 --- a/contracts/contracts/interfaces/IDripper.sol +++ b/contracts/contracts/interfaces/IDripper.sol @@ -14,4 +14,14 @@ interface IDripper { /// @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/tasks/dripper.js b/contracts/tasks/dripper.js new file mode 100644 index 0000000000..c6a7859db8 --- /dev/null +++ b/contracts/tasks/dripper.js @@ -0,0 +1,40 @@ +const { resolveContract } = require("../utils/resolvers"); +const { getSigner } = require("../utils/signers"); +const { logTxDetails } = require("../utils/txLogger"); + +const log = require("../utils/logger")("task:vault"); + +async function getContract(symbol) { + const contractPrefix = symbol === "OUSD" ? "" : symbol; + const dripper = await resolveContract( + `${contractPrefix}DripperProxy`, + "IDripper" + ); + + return dripper; +} + +async function setDripDuration({ symbol, duration }) { + const signer = await getSigner(); + + const dripper = await getContract(symbol); + + log(`About setDripDuration to ${duration} seconds on the ${symbol} Dripper`); + const tx = await dripper.connect(signer).setDripDuration(duration); + await logTxDetails(tx, "setDripDuration"); +} + +async function collect({ symbol }) { + const signer = await getSigner(); + + const dripper = await getContract(symbol); + + log(`About collect from the ${symbol} Dripper`); + const tx = await dripper.connect(signer).collect(); + await logTxDetails(tx, "collect"); +} + +module.exports = { + collect, + setDripDuration, +}; diff --git a/contracts/tasks/tasks.js b/contracts/tasks/tasks.js index af04bd69a9..ed76629c25 100644 --- a/contracts/tasks/tasks.js +++ b/contracts/tasks/tasks.js @@ -17,6 +17,7 @@ const { encryptMasterPrivateKey, decryptMasterPrivateKey, } = require("./amazon"); +const { collect, setDripDuration } = require("./dripper"); const { getSigner } = require("../utils/signers"); const { @@ -49,6 +50,8 @@ const { rebase, redeem, redeemAll, + requestWithdrawal, + claimWithdrawal, withdrawFromStrategy, withdrawAllFromStrategy, withdrawAllFromStrategies, @@ -478,6 +481,77 @@ task("withdrawAllFromStrategies").setAction(async (_, __, runSuper) => { return runSuper(); }); +subtask("requestWithdrawal", "Request a withdrawal from a vault") + .addParam( + "amount", + "The amount of oTokens to withdraw", + undefined, + types.float + ) + .addOptionalParam( + "symbol", + "Symbol of the OToken. eg OETH or OUSD", + "OETH", + types.string + ) + .setAction(requestWithdrawal); +task("requestWithdrawal").setAction(async (_, __, runSuper) => { + return runSuper(); +}); + +subtask( + "claimWithdrawal", + "Claim a previously requested withdrawal from a vault" +) + .addParam( + "requestId", + "The id from the previous withdrawal request", + undefined, + types.int + ) + .addOptionalParam( + "symbol", + "Symbol of the OToken. eg OETH or OUSD", + "OETH", + types.string + ) + .setAction(claimWithdrawal); +task("claimWithdrawal").setAction(async (_, __, runSuper) => { + return runSuper(); +}); + +// Dripper + +subtask("collect", "Collect harvested rewards from the Dripper to the Vault") + .addOptionalParam( + "symbol", + "Symbol of the OToken. eg OETH or OUSD", + "OETH", + types.string + ) + .setAction(collect); +task("collect").setAction(async (_, __, runSuper) => { + return runSuper(); +}); + +subtask("setDripDuration", "Set the Dripper duration") + .addParam( + "duration", + "The number of seconds to drip harvested rewards", + undefined, + types.int + ) + .addOptionalParam( + "symbol", + "Symbol of the OToken. eg OETH or OUSD", + "OETH", + types.string + ) + .setAction(setDripDuration); +task("setDripDuration").setAction(async (_, __, runSuper) => { + return runSuper(); +}); + // Governance tasks subtask("execute", "Execute a governance proposal") .addParam("id", "Proposal ID") diff --git a/contracts/tasks/vault.js b/contracts/tasks/vault.js index ba49d4259b..75cc75da1f 100644 --- a/contracts/tasks/vault.js +++ b/contracts/tasks/vault.js @@ -294,6 +294,37 @@ async function withdrawAllFromStrategies({ symbol }, hre) { await logTxDetails(tx, "withdrawAllFromStrategies"); } +async function requestWithdrawal({ amount, symbol }, hre) { + const signer = await getSigner(); + + const oTokenUnits = parseUnits(amount.toString()); + + const { vault } = await getContract(hre, symbol); + + // Get the withdrawal request ID by statically calling requestWithdrawal + const { requestId } = await vault + .connect(signer) + .callStatic.requestWithdrawal(oTokenUnits); + + log(`About to request withdrawal from the ${symbol} vault`); + const tx = await vault.connect(signer).requestWithdrawal(oTokenUnits); + await logTxDetails(tx, "requestWithdrawal"); + + console.log(`Withdrawal request id: ${requestId}`); +} + +async function claimWithdrawal({ requestId, symbol }, hre) { + const signer = await getSigner(); + + const { vault } = await getContract(hre, symbol); + + log( + `About to claim withdrawal from the ${symbol} vault for request ${requestId}` + ); + const tx = await vault.connect(signer).claimWithdrawal(requestId); + await logTxDetails(tx, "claimWithdrawal"); +} + module.exports = { allocate, capital, @@ -302,6 +333,8 @@ module.exports = { rebase, redeem, redeemAll, + requestWithdrawal, + claimWithdrawal, withdrawFromStrategy, withdrawAllFromStrategy, withdrawAllFromStrategies, From 39d9a86d55a37eb7ba7b7469828206da577bd4cb Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Thu, 4 Jul 2024 17:57:01 +1000 Subject: [PATCH 139/273] OETHVaultCore Natspec updates OETHVaultCore params with an underscore --- contracts/contracts/vault/OETHVaultCore.sol | 38 ++++++++++++++------- contracts/contracts/vault/VaultStorage.sol | 11 ++++-- contracts/docs/OETHVaultCoreSquashed.svg | 20 +++++------ 3 files changed, 44 insertions(+), 25 deletions(-) diff --git a/contracts/contracts/vault/OETHVaultCore.sol b/contracts/contracts/vault/OETHVaultCore.sol index 4539daeb4f..fc60262ab3 100644 --- a/contracts/contracts/vault/OETHVaultCore.sol +++ b/contracts/contracts/vault/OETHVaultCore.sol @@ -158,12 +158,16 @@ contract OETHVaultCore is VaultCore { } /** - * @notice Request an asynchronous withdrawal of the underlying asset. eg WETH - * @param _amount Amount of oTokens to burn. eg OETH + * @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. - * This request can be claimed once the withdrawal queue's claimable amount - * is greater than or equal this request's queued amount. */ function requestWithdrawal(uint256 _amount) external @@ -194,16 +198,21 @@ contract OETHVaultCore is VaultCore { /** * @notice Claim a previously requested withdrawal once it is claimable. - * @param requestId Unique ID for the withdrawal request + * 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 _requestId Unique ID for the withdrawal request * @return amount Amount of WETH transferred to the withdrawer */ - function claimWithdrawal(uint256 requestId) + function claimWithdrawal(uint256 _requestId) external whenNotCapitalPaused nonReentrant returns (uint256 amount) { - amount = _claimWithdrawal(requestId); + amount = _claimWithdrawal(_requestId); // transfer WETH from the vault to the withdrawer IERC20(weth).safeTransfer(msg.sender, amount); @@ -211,18 +220,22 @@ contract OETHVaultCore is VaultCore { /** * @notice Claim a previously requested withdrawals once they are claimable. - * @param requestIds Unique ID of each withdrawal request + * This requests can be claimed once the withdrawal queue's `claimable` amount + * is greater than or equal each request's `queued` amount. + * If one of the requests is not claimable, the whole transaction will revert with `queue pending liquidity`. + * @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) + function claimWithdrawals(uint256[] memory _requestIds) external whenNotCapitalPaused nonReentrant returns (uint256[] memory amounts, uint256 totalAmount) { - amounts = new uint256[](requestIds.length); - for (uint256 i = 0; i < requestIds.length; ++i) { - amounts[i] = _claimWithdrawal(requestIds[i]); + amounts = new uint256[](_requestIds.length); + for (uint256 i = 0; i < _requestIds.length; ++i) { + amounts[i] = _claimWithdrawal(_requestIds[i]); totalAmount += amounts[i]; } @@ -282,6 +295,7 @@ contract OETHVaultCore is VaultCore { } /// @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) diff --git a/contracts/contracts/vault/VaultStorage.sol b/contracts/contracts/vault/VaultStorage.sol index 7824e44489..04e74b2259 100644 --- a/contracts/contracts/vault/VaultStorage.sol +++ b/contracts/contracts/vault/VaultStorage.sol @@ -191,7 +191,7 @@ contract VaultStorage is Initializable, Governable { 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 included the ones that have already been claimed + // 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; @@ -199,20 +199,25 @@ contract VaultStorage is Initializable, Governable { 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; - // Amount of oTokens to redeem + // 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; } - // Mapping of withdrawal requests indexes to the user withdrawal request data + /// @notice Mapping of withdrawal request indices to the user withdrawal request data mapping(uint256 => WithdrawalRequest) public withdrawalRequests; // For future use diff --git a/contracts/docs/OETHVaultCoreSquashed.svg b/contracts/docs/OETHVaultCoreSquashed.svg index 31d93ff5a9..d49658abd7 100644 --- a/contracts/docs/OETHVaultCoreSquashed.svg +++ b/contracts/docs/OETHVaultCoreSquashed.svg @@ -4,18 +4,18 @@ - + UmlClassDiagram - + 224 - -OETHVaultCore -../contracts/vault/OETHVaultCore.sol - + +OETHVaultCore +../contracts/vault/OETHVaultCore.sol + Private:   initialized: bool <<Initializable>>   initializing: bool <<Initializable>> @@ -63,7 +63,7 @@   withdrawalRequests: mapping(uint256=>WithdrawalRequest) <<VaultStorage>>   weth: address <<OETHVaultCore>>   wethAssetIndex: uint256 <<OETHVaultCore>> - + Private:    abs(x: int256): uint256 <<VaultCore>> Internal: @@ -113,8 +113,8 @@    null() <<VaultCore>>    cacheWETHAssetIndex() <<onlyGovernor>> <<OETHVaultCore>>    requestWithdrawal(_amount: uint256): (requestId: uint256, queued: uint256) <<whenNotCapitalPaused, nonReentrant>> <<OETHVaultCore>> -    claimWithdrawal(requestId: uint256): (amount: uint256) <<whenNotCapitalPaused, nonReentrant>> <<OETHVaultCore>> -    claimWithdrawals(requestIds: uint256[]): (amounts: uint256[], totalAmount: uint256) <<whenNotCapitalPaused, nonReentrant>> <<OETHVaultCore>> +    claimWithdrawal(_requestId: uint256): (amount: uint256) <<whenNotCapitalPaused, nonReentrant>> <<OETHVaultCore>> +    claimWithdrawals(_requestIds: uint256[]): (amounts: uint256[], totalAmount: uint256) <<whenNotCapitalPaused, nonReentrant>> <<OETHVaultCore>>    addWithdrawalQueueLiquidity() <<OETHVaultCore>> Public:    <<event>> PendingGovernorshipTransfer(previousGovernor: address, newGovernor: address) <<Governable>> From f8d49749f16127e0cb8101e72c8a009444d48847 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment?= <55331875+clement-ux@users.noreply.github.com> Date: Fri, 12 Jul 2024 12:12:22 +0200 Subject: [PATCH 140/273] Add 30 minute time delay between request and claim from the OETH Withdrawal Queue. (#2127) * feat: add delay between request and claim. * test: update test with delay. * fix: move `CLAIM_DELAY` from `VaultStorage.sol` to `OETHVaultCore.sol`. * style: require error message start with capital letter. --------- Co-authored-by: Nicholas Addison --- contracts/contracts/vault/OETHVaultAdmin.sol | 4 +-- contracts/contracts/vault/OETHVaultCore.sol | 12 +++++-- contracts/contracts/vault/VaultStorage.sol | 1 + contracts/test/vault/oeth-vault.js | 35 +++++++++++++++++++- 4 files changed, 46 insertions(+), 6 deletions(-) diff --git a/contracts/contracts/vault/OETHVaultAdmin.sol b/contracts/contracts/vault/OETHVaultAdmin.sol index f78cc38bca..a329b9fbef 100644 --- a/contracts/contracts/vault/OETHVaultAdmin.sol +++ b/contracts/contracts/vault/OETHVaultAdmin.sol @@ -96,8 +96,8 @@ contract OETHVaultAdmin is VaultAdmin { uint256 _minToAssetAmount, bytes calldata _data ) internal override returns (uint256 toAssetAmount) { - require(_fromAsset != weth, "swap from WETH not supported"); - require(_toAsset == weth, "only swap to WETH"); + require(_fromAsset != weth, "Swap from WETH not supported"); + require(_toAsset == weth, "Only swap to WETH"); toAssetAmount = super._swapCollateral( _fromAsset, _toAsset, diff --git a/contracts/contracts/vault/OETHVaultCore.sol b/contracts/contracts/vault/OETHVaultCore.sol index fc60262ab3..527a6feaef 100644 --- a/contracts/contracts/vault/OETHVaultCore.sol +++ b/contracts/contracts/vault/OETHVaultCore.sol @@ -17,6 +17,7 @@ contract OETHVaultCore is VaultCore { using SafeERC20 for IERC20; using StableMath for uint256; + uint256 constant CLAIM_DELAY = 30 minutes; address public immutable weth; uint256 public wethAssetIndex; @@ -191,6 +192,7 @@ contract OETHVaultCore is VaultCore { withdrawalRequests[requestId] = WithdrawalRequest({ withdrawer: msg.sender, claimed: false, + timestamp: uint40(block.timestamp), amount: uint128(_amount), queued: uint128(queued) }); @@ -253,8 +255,12 @@ contract OETHVaultCore is VaultCore { WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata; WithdrawalRequest memory request = withdrawalRequests[requestId]; - require(request.claimed == false, "already claimed"); - require(request.withdrawer == msg.sender, "not requester"); + require(request.claimed == false, "Already claimed"); + require(request.withdrawer == msg.sender, "Not requester"); + require( + request.timestamp + CLAIM_DELAY <= block.timestamp, + "Claim delay not met" + ); // Try and get more liquidity in the withdrawal queue if there is not enough if (request.queued > queue.claimable) { @@ -267,7 +273,7 @@ contract OETHVaultCore is VaultCore { // If there still isn't enough liquidity in the queue to claim, revert require( request.queued <= queue.claimable + addedClaimable, - "queue pending liquidity" + "Queue pending liquidity" ); } diff --git a/contracts/contracts/vault/VaultStorage.sol b/contracts/contracts/vault/VaultStorage.sol index 04e74b2259..e93ca9a548 100644 --- a/contracts/contracts/vault/VaultStorage.sol +++ b/contracts/contracts/vault/VaultStorage.sol @@ -210,6 +210,7 @@ contract VaultStorage is Initializable, Governable { 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. diff --git a/contracts/test/vault/oeth-vault.js b/contracts/test/vault/oeth-vault.js index 59299c8602..ba37c16b14 100644 --- a/contracts/test/vault/oeth-vault.js +++ b/contracts/test/vault/oeth-vault.js @@ -4,7 +4,7 @@ const hre = require("hardhat"); const { createFixtureLoader, oethDefaultFixture } = require("../_fixture"); const { parseUnits } = require("ethers/lib/utils"); const { deployWithConfirmation } = require("../../utils/deploy"); -const { oethUnits } = require("../helpers"); +const { oethUnits, advanceTime } = require("../helpers"); const addresses = require("../../utils/addresses"); const oethFixture = createFixtureLoader(oethDefaultFixture); @@ -377,6 +377,7 @@ describe("OETH Vault", function () { }); const firstRequestAmount = oethUnits("5"); const secondRequestAmount = oethUnits("18"); + const delayPeriod = 30 * 60; // 30 minutes it("should request first withdrawal by Daniel", async () => { const { oethVault, daniel } = fixture; const fixtureWithUser = { ...fixture, user: daniel }; @@ -552,6 +553,8 @@ describe("OETH Vault", function () { const requestId = 1; // ids start at 0 so the second request is at index 1 const dataBefore = await snapData(fixtureWithUser); + await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. + const tx = await oethVault.connect(josh).claimWithdrawal(requestId); await expect(tx) @@ -586,6 +589,8 @@ describe("OETH Vault", function () { await oethVault.connect(matt).requestWithdrawal(secondRequestAmount); const dataBefore = await snapData(fixtureWithUser); + await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. + const tx = await oethVault.connect(matt).claimWithdrawals([0, 1]); await expect(tx) @@ -616,6 +621,18 @@ describe("OETH Vault", function () { fixtureWithUser ); }); + it("Should fail claim request because of not enough time passed", async () => { + const { oethVault, daniel } = fixture; + + // Daniel requests 5 OETH to be withdrawn + await oethVault.connect(daniel).requestWithdrawal(firstRequestAmount); + const requestId = 0; + + // Daniel claimWithdraw request in the same block as the request + const tx = oethVault.connect(daniel).claimWithdrawal(requestId); + + await expect(tx).to.revertedWith("claim delay not met"); + }); describe("when deposit some WETH to a strategy", () => { let mockStrategy; @@ -679,6 +696,8 @@ describe("OETH Vault", function () { const fixtureWithUser = { ...fixture, user: daniel }; const dataBefore = await snapData(fixtureWithUser); + await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. + const tx = await oethVault.connect(daniel).claimWithdrawal(0); await expect(tx) @@ -715,6 +734,8 @@ describe("OETH Vault", function () { const dataBefore = await snapData(fixtureWithUser); + await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. + const tx = await oethVault.connect(matt).claimWithdrawal(2); await expect(tx) @@ -743,6 +764,8 @@ describe("OETH Vault", function () { const requestAmount = oethUnits("23"); await oethVault.connect(matt).requestWithdrawal(requestAmount); + await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. + const tx = oethVault.connect(matt).claimWithdrawal(2); await expect(tx).to.be.revertedWith("queue pending liquidity"); }); @@ -786,6 +809,8 @@ describe("OETH Vault", function () { fixtureWithUser ); + await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. + await oethVault.connect(matt).claimWithdrawal(2); }); it("Should claim a new request after withdrawAllFromStrategy adds enough liquidity", async () => { @@ -826,6 +851,8 @@ describe("OETH Vault", function () { fixtureWithUser ); + await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. + await oethVault.connect(matt).claimWithdrawal(2); }); it("Should claim a new request after withdrawAll from strategies adds enough liquidity", async () => { @@ -864,6 +891,8 @@ describe("OETH Vault", function () { fixtureWithUser ); + await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. + await oethVault.connect(matt).claimWithdrawal(2); }); it("Should fail to claim a new request after mint with NOT enough liquidity", async () => { @@ -878,6 +907,8 @@ describe("OETH Vault", function () { // Add another 6 WETH so the unallocated WETH is 22 + 6 = 28 WETH await oethVault.connect(daniel).mint(weth.address, oethUnits("6"), 0); + await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. + const tx = oethVault.connect(matt).claimWithdrawal(2); await expect(tx).to.be.revertedWith("queue pending liquidity"); }); @@ -915,6 +946,8 @@ describe("OETH Vault", function () { fixtureWithUser ); + await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. + await oethVault.connect(matt).claimWithdrawal(2); }); }); From 937a084fcc29b25a76a3f461354000be76acd9a1 Mon Sep 17 00:00:00 2001 From: clement-ux Date: Fri, 12 Jul 2024 12:39:32 +0200 Subject: [PATCH 141/273] fix: test expectRevert with new error message --- contracts/test/vault/oeth-vault.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/contracts/test/vault/oeth-vault.js b/contracts/test/vault/oeth-vault.js index ba37c16b14..9639cdbcf7 100644 --- a/contracts/test/vault/oeth-vault.js +++ b/contracts/test/vault/oeth-vault.js @@ -631,7 +631,7 @@ describe("OETH Vault", function () { // Daniel claimWithdraw request in the same block as the request const tx = oethVault.connect(daniel).claimWithdrawal(requestId); - await expect(tx).to.revertedWith("claim delay not met"); + await expect(tx).to.revertedWith("Claim delay not met"); }); describe("when deposit some WETH to a strategy", () => { @@ -767,7 +767,7 @@ describe("OETH Vault", function () { await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. const tx = oethVault.connect(matt).claimWithdrawal(2); - await expect(tx).to.be.revertedWith("queue pending liquidity"); + await expect(tx).to.be.revertedWith("Queue pending liquidity"); }); it("Should claim a new request after withdraw from strategy adds enough liquidity", async () => { const { oethVault, daniel, matt, strategist, weth } = fixture; @@ -910,7 +910,7 @@ describe("OETH Vault", function () { await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. const tx = oethVault.connect(matt).claimWithdrawal(2); - await expect(tx).to.be.revertedWith("queue pending liquidity"); + await expect(tx).to.be.revertedWith("Queue pending liquidity"); }); it("Should claim a new request after mint adds enough liquidity", async () => { const { oethVault, daniel, matt, weth } = fixture; From b07ce571489ed9de2024e1c3c645cdb79cbe3bcd Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Fri, 12 Jul 2024 21:17:18 +1000 Subject: [PATCH 142/273] Fixed unit tests --- contracts/test/vault/oneinch-swapper.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/test/vault/oneinch-swapper.js b/contracts/test/vault/oneinch-swapper.js index cdc09fafac..60842e35ce 100644 --- a/contracts/test/vault/oneinch-swapper.js +++ b/contracts/test/vault/oneinch-swapper.js @@ -286,7 +286,7 @@ describe("1Inch Swapper", () => { .connect(strategist) .swapCollateral(stETH.address, dai.address, fromAmount, toAmount, []); - await expect(tx).to.be.revertedWith("only swap to WETH"); + await expect(tx).to.be.revertedWith("Only swap to WETH"); }); it("Should swap if capital is paused", async () => { From bdeb1de0d8ab8d5c99bf85faf910cf494e2d6a35 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Sun, 14 Jul 2024 19:29:40 +1000 Subject: [PATCH 143/273] Remove stETH and rETH asset from OETH Vault Remove legacy strategies from the Vault --- .../deploy/mainnet/101_oeth_withdraw_queue.js | 60 +++++++++++-------- 1 file changed, 34 insertions(+), 26 deletions(-) diff --git a/contracts/deploy/mainnet/101_oeth_withdraw_queue.js b/contracts/deploy/mainnet/101_oeth_withdraw_queue.js index 24d8f82f96..aa216605e3 100644 --- a/contracts/deploy/mainnet/101_oeth_withdraw_queue.js +++ b/contracts/deploy/mainnet/101_oeth_withdraw_queue.js @@ -40,6 +40,9 @@ module.exports = deploymentWithGovernanceProposal( 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); @@ -47,48 +50,53 @@ module.exports = deploymentWithGovernanceProposal( `There is ${formatUnits(stEthInVault)} stETH in the OETH Vault` ); - // If there is more than 1 wei of stETH in the Vault, we need to remove it using the Lido Withdrawal Strategy - const removeStEthActions = stEthInVault.gt(1) - ? [ - // 1. Deposit all stETH in the Vault to the Lido Withdrawal Strategy - { - contract: cVault, - signature: "depositToStrategy(address,address[],uint256[])", - args: [ - cLidoWithdrawStrategyProxy.address, - [stETH.address], - [stEthInVault], - ], - }, - // 2. Remove stETH from the OETH Vault - { - contract: cVault, - signature: "removeAsset(address)", - args: [stETH.address], - }, - ] - : []; + 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`); // Governance Actions // ---------------- return { name: "Upgrade OETH Vault to support queued withdrawals", actions: [ - // Remove stETH if not done already - ...removeStEthActions, - // 3. Upgrade the OETH Vault proxy to the new core vault implementation + // 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], + }, + // TODO add after all rETH has been swapped out of the Vault + // // 4. Remove rETH from the OETH Vault + // { + // contract: cVault, + // signature: "removeAsset(address)", + // args: [rETH.address], + // }, + // 5. Upgrade the OETH Vault proxy to the new core vault implementation { contract: cVaultProxy, signature: "upgradeTo(address)", args: [dVaultCore.address], }, - // 4. set OETH Vault proxy to the new admin vault implementation + // 6. set OETH Vault proxy to the new admin vault implementation { contract: cVault, signature: "setAdminImpl(address)", args: [dVaultAdmin.address], }, - // 5. Set the Dripper contract + // 7. Set the Dripper contract { contract: cVault, signature: "setDripper(address)", From 25f1b53fc18ee807aef9e77ce2b501cfb0b41e04 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Sun, 14 Jul 2024 19:30:10 +1000 Subject: [PATCH 144/273] Skip legacy strategy tests --- contracts/test/strategies/fraxeth.js | 2 +- contracts/test/strategies/oeth-morpho-aave.mainnet.fork-test.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/test/strategies/fraxeth.js b/contracts/test/strategies/fraxeth.js index 307253b7b4..6817d69002 100644 --- a/contracts/test/strategies/fraxeth.js +++ b/contracts/test/strategies/fraxeth.js @@ -11,7 +11,7 @@ const { } = require("./../_fixture"); const { impersonateAndFund } = require("../../utils/signers"); -describe("FraxETH Strategy", function () { +describe.skip("FraxETH Strategy", function () { let fixture; const loadFixture = createFixtureLoader(fraxETHStrategyFixture); beforeEach(async () => { diff --git a/contracts/test/strategies/oeth-morpho-aave.mainnet.fork-test.js b/contracts/test/strategies/oeth-morpho-aave.mainnet.fork-test.js index 0ad076add8..3ad0e5660f 100644 --- a/contracts/test/strategies/oeth-morpho-aave.mainnet.fork-test.js +++ b/contracts/test/strategies/oeth-morpho-aave.mainnet.fork-test.js @@ -10,7 +10,7 @@ const { const { createFixtureLoader, oethMorphoAaveFixture } = require("../_fixture"); const { impersonateAndFund } = require("../../utils/signers"); -describe("ForkTest: Morpho Aave OETH Strategy", function () { +describe.skip("ForkTest: Morpho Aave OETH Strategy", function () { this.timeout(0); // Retry up to 3 times on CI From 3049effccb7cf42d8f3ad7eb2b896d8484ec28d7 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Sun, 14 Jul 2024 19:46:07 +1000 Subject: [PATCH 145/273] Skiped legacy Oracle prices --- .../test/oracle/oracle.mainnet.fork-test.js | 40 +++++++++---------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/contracts/test/oracle/oracle.mainnet.fork-test.js b/contracts/test/oracle/oracle.mainnet.fork-test.js index 46e3233736..9b84a68bc5 100644 --- a/contracts/test/oracle/oracle.mainnet.fork-test.js +++ b/contracts/test/oracle/oracle.mainnet.fork-test.js @@ -16,7 +16,23 @@ describe("ForkTest: OETH Oracle Routers", function () { oethOracleRouter = await ethers.getContract("OETHOracleRouter"); }); - it("should get rETH price", async () => { + it("should get WETH price", async () => { + const { weth } = fixture; + + const price = await oethOracleRouter.price(weth.address); + expect(price).to.eq(parseUnits("1", 18)); + }); + + it("should get gas costs of weth", async () => { + const { weth, josh } = fixture; + + const tx = await oethOracleRouter + .connect(josh) + .populateTransaction.price(weth.address); + await josh.sendTransaction(tx); + }); + + it.skip("should get rETH price", async () => { const { reth } = fixture; const price = await oethOracleRouter.price(reth.address); @@ -24,35 +40,17 @@ describe("ForkTest: OETH Oracle Routers", function () { expect(price).to.lt(parseUnits("112", 16)); }); - it("should get frxETH price", async () => { + it.skip("should get frxETH price", async () => { const { frxETH } = fixture; const price = await oethOracleRouter.price(frxETH.address); expect(price).to.lt(parseUnits("1", 18)); }); - it("should get WETH price", async () => { - const { weth } = fixture; - - const price = await oethOracleRouter.price(weth.address); - expect(price).to.eq(parseUnits("1", 18)); - }); - - it("should get stETH price", async () => { + it.skip("should get stETH price", async () => { const { stETH } = fixture; const price = await oethOracleRouter.price(stETH.address); expect(price).to.approxEqualTolerance(parseUnits("1", 18), 1); }); - - it("should get gas costs of assets", async () => { - const { reth, frxETH, stETH, weth, josh } = fixture; - - for (const asset of [frxETH, reth, stETH, weth]) { - const tx = await oethOracleRouter - .connect(josh) - .populateTransaction.price(asset.address); - await josh.sendTransaction(tx); - } - }); }); From 3c9c9ec4ff406a7a10b5e43d076f5bf765d03180 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Sun, 14 Jul 2024 19:58:28 +1000 Subject: [PATCH 146/273] Skipped Aura price tests --- contracts/test/oracle/aura-feed.js | 2 +- contracts/test/oracle/aura-feed.mainnet.fork-test.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/test/oracle/aura-feed.js b/contracts/test/oracle/aura-feed.js index 8ab2d0949a..6c189a05bd 100644 --- a/contracts/test/oracle/aura-feed.js +++ b/contracts/test/oracle/aura-feed.js @@ -2,7 +2,7 @@ const { expect } = require("chai"); const { loadDefaultFixture } = require("../_fixture"); const { oethUnits } = require("../helpers"); -describe("ForkTest: Aura/WETH Price Feed", function () { +describe.skip("ForkTest: Aura/WETH Price Feed", function () { this.timeout(0); let fixture; diff --git a/contracts/test/oracle/aura-feed.mainnet.fork-test.js b/contracts/test/oracle/aura-feed.mainnet.fork-test.js index 58c2466c8f..cd61fd3237 100644 --- a/contracts/test/oracle/aura-feed.mainnet.fork-test.js +++ b/contracts/test/oracle/aura-feed.mainnet.fork-test.js @@ -4,7 +4,7 @@ const { oethUnits } = require("../helpers"); const addresses = require("../../utils/addresses"); const { hotDeployOption } = require("../_hot-deploy"); -describe("ForkTest: Aura/WETH Price Feed", function () { +describe.skip("ForkTest: Aura/WETH Price Feed", function () { this.timeout(0); let fixture; From dc58a1cda572a58b643b0a5e1456d68133260c86 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Mon, 15 Jul 2024 17:14:12 +1000 Subject: [PATCH 147/273] Remove rETH as an asset from the Vault --- contracts/deploy/mainnet/101_oeth_withdraw_queue.js | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/contracts/deploy/mainnet/101_oeth_withdraw_queue.js b/contracts/deploy/mainnet/101_oeth_withdraw_queue.js index aa216605e3..766bf9c2ff 100644 --- a/contracts/deploy/mainnet/101_oeth_withdraw_queue.js +++ b/contracts/deploy/mainnet/101_oeth_withdraw_queue.js @@ -77,13 +77,12 @@ module.exports = deploymentWithGovernanceProposal( signature: "removeAsset(address)", args: [stETH.address], }, - // TODO add after all rETH has been swapped out of the Vault - // // 4. Remove rETH from the OETH Vault - // { - // contract: cVault, - // signature: "removeAsset(address)", - // args: [rETH.address], - // }, + // 4. Remove rETH from the OETH Vault + { + contract: cVault, + signature: "removeAsset(address)", + args: [rETH.address], + }, // 5. Upgrade the OETH Vault proxy to the new core vault implementation { contract: cVaultProxy, From c607bc78f5de619130ae8be99743ee2dfc520ce3 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Mon, 15 Jul 2024 19:24:14 +1000 Subject: [PATCH 148/273] Added call to cacheWETHAssetIndex after stETH is removed from the Vault --- .../deploy/mainnet/101_oeth_withdraw_queue.js | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/contracts/deploy/mainnet/101_oeth_withdraw_queue.js b/contracts/deploy/mainnet/101_oeth_withdraw_queue.js index 766bf9c2ff..057ae31a46 100644 --- a/contracts/deploy/mainnet/101_oeth_withdraw_queue.js +++ b/contracts/deploy/mainnet/101_oeth_withdraw_queue.js @@ -34,7 +34,7 @@ module.exports = deploymentWithGovernanceProposal( // 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 cVault = await ethers.getContractAt("IVault", cVaultProxy.address); const cDripperProxy = await ethers.getContract("OETHDripperProxy"); const cLidoWithdrawStrategyProxy = await ethers.getContract( @@ -83,19 +83,26 @@ module.exports = deploymentWithGovernanceProposal( signature: "removeAsset(address)", args: [rETH.address], }, - // 5. Upgrade the OETH Vault proxy to the new core vault implementation + // 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], }, - // 6. set OETH Vault proxy to the new admin vault implementation + // 7. set OETH Vault proxy to the new admin vault implementation { contract: cVault, signature: "setAdminImpl(address)", args: [dVaultAdmin.address], }, - // 7. Set the Dripper contract + // 8. Set the Dripper contract { contract: cVault, signature: "setDripper(address)", From 33a5678ff3ff487bfd1414efb1c18c82af7a3106 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Mon, 15 Jul 2024 20:29:00 +1000 Subject: [PATCH 149/273] Updated vault storage diagrams --- contracts/docs/OETHVaultStorage.svg | 622 +++++++++++++--------------- contracts/docs/VaultStorage.svg | 614 +++++++++++++-------------- contracts/docs/generate.sh | 4 +- 3 files changed, 586 insertions(+), 654 deletions(-) diff --git a/contracts/docs/OETHVaultStorage.svg b/contracts/docs/OETHVaultStorage.svg index 6b7fb8f27f..5c2084d795 100644 --- a/contracts/docs/OETHVaultStorage.svg +++ b/contracts/docs/OETHVaultStorage.svg @@ -4,378 +4,344 @@ - - + + StorageDiagram - - + + -9 - -OETHVaultCore <<Contract>> - -slot - -0 - -1-50 - -51 - -52 - -53 - -54 - -55 - -56 - -57 - -58 - -59 - -60 - -61 - -62 - -63 - -64 - -65 - -66 - -67 - -68 - -69 - -70 - -71 - -72 - -73 - -74-75 - -76 - -77-122 - -123 - -type: <inherited contract>.variable (bytes) - -unallocated (30) - -bool: Initializable.initializing (1) - -bool: Initializable.initialized (1) - -uint256[50]: Initializable.______gap (1600) - -mapping(address=>Asset): VaultStorage.assets (32) - -address[]: VaultStorage.allAssets (32) - -mapping(address=>Strategy): VaultStorage.strategies (32) - -address[]: VaultStorage.allStrategies (32) - -unallocated (10) - -bool: VaultStorage.capitalPaused (1) - -bool: VaultStorage.rebasePaused (1) - -address: VaultStorage.priceProvider (20) - -uint256: VaultStorage.redeemFeeBps (32) - -uint256: VaultStorage.vaultBuffer (32) - -uint256: VaultStorage.autoAllocateThreshold (32) - -uint256: VaultStorage.rebaseThreshold (32) - -unallocated (12) - -OUSD: VaultStorage.oUSD (20) - -unallocated (12) - -address: VaultStorage._deprecated_rebaseHooksAddr (20) - -unallocated (12) - -address: VaultStorage._deprecated_uniswapAddr (20) - -unallocated (12) - -address: VaultStorage.strategistAddr (20) - -mapping(address=>address): VaultStorage.assetDefaultStrategies (32) - -uint256: VaultStorage.maxSupplyDiff (32) - -unallocated (12) - -address: VaultStorage.trusteeAddress (20) - -uint256: VaultStorage.trusteeFeeBps (32) - -address[]: VaultStorage._deprecated_swapTokens (32) - -unallocated (12) - -address: VaultStorage.ousdMetaStrategy (20) - -int256: VaultStorage.netOusdMintedForStrategy (32) - -uint256: VaultStorage.netOusdMintForStrategyThreshold (32) - -SwapConfig: VaultStorage.swapConfig (32) - -unallocated (12) - -address: VaultStorage.dripper (20) - -WithdrawalQueueMetadata: VaultStorage.withdrawalQueueMetadata (64) - -mapping(uint256=>WithdrawalRequest): VaultStorage.withdrawalRequests (32) - -uint256[46]: VaultStorage.__gap (1472) - -uint256: wethAssetIndex (32) +8 + +OETHVaultCore <<Contract>> + +slot + +0 + +1-50 + +51 + +52 + +53 + +54 + +55 + +56 + +57 + +58 + +59 + +60 + +61 + +62 + +63 + +64 + +65 + +66 + +67 + +68 + +69 + +70 + +71 + +72 + +73 + +74-75 + +76 + +77-122 + +123 + +type: <inherited contract>.variable (bytes) + +unallocated (30) + +bool: Initializable.initializing (1) + +bool: Initializable.initialized (1) + +uint256[50]: Initializable.______gap (1600) + +mapping(address=>Asset): VaultStorage.assets (32) + +address[]: VaultStorage.allAssets (32) + +mapping(address=>Strategy): VaultStorage.strategies (32) + +address[]: VaultStorage.allStrategies (32) + +unallocated (10) + +bool: VaultStorage.capitalPaused (1) + +bool: VaultStorage.rebasePaused (1) + +address: VaultStorage.priceProvider (20) + +uint256: VaultStorage.redeemFeeBps (32) + +uint256: VaultStorage.vaultBuffer (32) + +uint256: VaultStorage.autoAllocateThreshold (32) + +uint256: VaultStorage.rebaseThreshold (32) + +unallocated (12) + +OUSD: VaultStorage.oUSD (20) + +unallocated (12) + +address: VaultStorage._deprecated_rebaseHooksAddr (20) + +unallocated (12) + +address: VaultStorage._deprecated_uniswapAddr (20) + +unallocated (12) + +address: VaultStorage.strategistAddr (20) + +mapping(address=>address): VaultStorage.assetDefaultStrategies (32) + +uint256: VaultStorage.maxSupplyDiff (32) + +unallocated (12) + +address: VaultStorage.trusteeAddress (20) + +uint256: VaultStorage.trusteeFeeBps (32) + +address[]: VaultStorage._deprecated_swapTokens (32) + +unallocated (12) + +address: VaultStorage.ousdMetaStrategy (20) + +int256: VaultStorage.netOusdMintedForStrategy (32) + +uint256: VaultStorage.netOusdMintForStrategyThreshold (32) + +SwapConfig: VaultStorage.swapConfig (32) + +unallocated (12) + +address: VaultStorage.dripper (20) + +WithdrawalQueueMetadata: VaultStorage.withdrawalQueueMetadata (64) + +mapping(uint256=>WithdrawalRequest): VaultStorage.withdrawalRequests (32) + +uint256[46]: VaultStorage.__gap (1472) + +uint256: wethAssetIndex (32) 1 - -Asset <<Struct>> - -offset - -0 - -type: variable (bytes) - -unallocated (27) - -uint16: allowedOracleSlippageBps (2) - -uint8: decimals (1) - -UnitConversion: unitConversion (1) - -bool: isSupported (1) + +Asset <<Struct>> + +offset + +0 + +type: variable (bytes) + +unallocated (27) + +uint16: allowedOracleSlippageBps (2) + +uint8: decimals (1) + +UnitConversion: unitConversion (1) + +bool: isSupported (1) - + -9:8->1 - - +8:8->1 + + 2 - -address[]: allAssets <<Array>> -0x46bddb1178e94d7f2892ff5f366840eb658911794f2c3a44c450aa2c505186c1 - -offset - -0 - -type: variable (bytes) - -unallocated (12) - -address (20) + +address[]: allAssets <<Array>> +0x46bddb1178e94d7f2892ff5f366840eb658911794f2c3a44c450aa2c505186c1 + +offset + +0 + +type: variable (bytes) + +unallocated (12) + +address (20) - + -9:10->2 - - +8:10->2 + + 3 - -Strategy <<Struct>> - -offset - -0 - -1 - -type: variable (bytes) - -unallocated (31) - -bool: isSupported (1) - -uint256: _deprecated (32) + +Strategy <<Struct>> + +offset + +0 + +1 + +type: variable (bytes) + +unallocated (31) + +bool: isSupported (1) + +uint256: _deprecated (32) - + -9:13->3 - - +8:13->3 + + 4 - -address[]: allStrategies <<Array>> -0x4a11f94e20a93c79f6ec743a1954ec4fc2c08429ae2122118bf234b2185c81b8 - -offset - -0 - -type: variable (bytes) - -unallocated (12) - -address (20) + +address[]: allStrategies <<Array>> +0x4a11f94e20a93c79f6ec743a1954ec4fc2c08429ae2122118bf234b2185c81b8 + +offset + +0 + +type: variable (bytes) + +unallocated (12) + +address (20) - + -9:15->4 - - +8:15->4 + + 5 - -SwapConfig <<Struct>> - -slot - -72 - -type: variable (bytes) - -unallocated (10) - -uint16: allowedUndervalueBps (2) - -address: swapper (20) + +SwapConfig <<Struct>> + +slot + +72 + +type: variable (bytes) + +unallocated (10) + +uint16: allowedUndervalueBps (2) + +address: swapper (20) - + -9:37->5 - - +8:37->5 + + 6 - -WithdrawalQueueMetadata <<Struct>> - -slot - -74 - -75 - -type: variable (bytes) - -uint128: claimable (16) - -uint128: queued (16) - -uint128: nextWithdrawalIndex (16) - -uint128: claimed (16) + +WithdrawalQueueMetadata <<Struct>> + +slot + +74 + +75 + +type: variable (bytes) + +uint128: claimable (16) + +uint128: queued (16) + +uint128: nextWithdrawalIndex (16) + +uint128: claimed (16) - + -9:43->6 - - +8:43->6 + + 7 - -WithdrawalRequest <<Struct>> - -offset - -0 - -1 - -type: variable (bytes) - -unallocated (11) - -bool: claimed (1) - -address: withdrawer (20) - -uint128: queued (16) - -uint128: amount (16) + +WithdrawalRequest <<Struct>> + +offset + +0 + +1 + +type: variable (bytes) + +unallocated (6) + +uint40: timestamp (5) + +bool: claimed (1) + +address: withdrawer (20) + +uint128: queued (16) + +uint128: amount (16) - + -9:48->7 - - - - - -8 - -uint256[46]: __gap <<Array>> - -slot - -77 - -78 - -79-120 - -121 - -122 - -type: variable (bytes) - -uint256 (32) - -uint256 (32) - ----- (1344) - -uint256 (32) - -uint256 (32) - - - -9:54->8 - - +8:49->7 + + diff --git a/contracts/docs/VaultStorage.svg b/contracts/docs/VaultStorage.svg index b30a623ee0..af65b4197f 100644 --- a/contracts/docs/VaultStorage.svg +++ b/contracts/docs/VaultStorage.svg @@ -4,374 +4,340 @@ - - + + StorageDiagram - - + + -9 - -VaultCore <<Contract>> - -slot - -0 - -1-50 - -51 - -52 - -53 - -54 - -55 - -56 - -57 - -58 - -59 - -60 - -61 - -62 - -63 - -64 - -65 - -66 - -67 - -68 - -69 - -70 - -71 - -72 - -73 - -74-75 - -76 - -77-122 - -type: <inherited contract>.variable (bytes) - -unallocated (30) - -bool: Initializable.initializing (1) - -bool: Initializable.initialized (1) - -uint256[50]: Initializable.______gap (1600) - -mapping(address=>Asset): VaultStorage.assets (32) - -address[]: VaultStorage.allAssets (32) - -mapping(address=>Strategy): VaultStorage.strategies (32) - -address[]: VaultStorage.allStrategies (32) - -unallocated (10) - -bool: VaultStorage.capitalPaused (1) - -bool: VaultStorage.rebasePaused (1) - -address: VaultStorage.priceProvider (20) - -uint256: VaultStorage.redeemFeeBps (32) - -uint256: VaultStorage.vaultBuffer (32) - -uint256: VaultStorage.autoAllocateThreshold (32) - -uint256: VaultStorage.rebaseThreshold (32) - -unallocated (12) - -OUSD: VaultStorage.oUSD (20) - -unallocated (12) - -address: VaultStorage._deprecated_rebaseHooksAddr (20) - -unallocated (12) - -address: VaultStorage._deprecated_uniswapAddr (20) - -unallocated (12) - -address: VaultStorage.strategistAddr (20) - -mapping(address=>address): VaultStorage.assetDefaultStrategies (32) - -uint256: VaultStorage.maxSupplyDiff (32) - -unallocated (12) - -address: VaultStorage.trusteeAddress (20) - -uint256: VaultStorage.trusteeFeeBps (32) - -address[]: VaultStorage._deprecated_swapTokens (32) - -unallocated (12) - -address: VaultStorage.ousdMetaStrategy (20) - -int256: VaultStorage.netOusdMintedForStrategy (32) - -uint256: VaultStorage.netOusdMintForStrategyThreshold (32) - -SwapConfig: VaultStorage.swapConfig (32) - -unallocated (12) - -address: VaultStorage.dripper (20) - -WithdrawalQueueMetadata: VaultStorage.withdrawalQueueMetadata (64) - -mapping(uint256=>WithdrawalRequest): VaultStorage.withdrawalRequests (32) - -uint256[46]: VaultStorage.__gap (1472) +8 + +VaultCore <<Contract>> + +slot + +0 + +1-50 + +51 + +52 + +53 + +54 + +55 + +56 + +57 + +58 + +59 + +60 + +61 + +62 + +63 + +64 + +65 + +66 + +67 + +68 + +69 + +70 + +71 + +72 + +73 + +74-75 + +76 + +77-122 + +type: <inherited contract>.variable (bytes) + +unallocated (30) + +bool: Initializable.initializing (1) + +bool: Initializable.initialized (1) + +uint256[50]: Initializable.______gap (1600) + +mapping(address=>Asset): VaultStorage.assets (32) + +address[]: VaultStorage.allAssets (32) + +mapping(address=>Strategy): VaultStorage.strategies (32) + +address[]: VaultStorage.allStrategies (32) + +unallocated (10) + +bool: VaultStorage.capitalPaused (1) + +bool: VaultStorage.rebasePaused (1) + +address: VaultStorage.priceProvider (20) + +uint256: VaultStorage.redeemFeeBps (32) + +uint256: VaultStorage.vaultBuffer (32) + +uint256: VaultStorage.autoAllocateThreshold (32) + +uint256: VaultStorage.rebaseThreshold (32) + +unallocated (12) + +OUSD: VaultStorage.oUSD (20) + +unallocated (12) + +address: VaultStorage._deprecated_rebaseHooksAddr (20) + +unallocated (12) + +address: VaultStorage._deprecated_uniswapAddr (20) + +unallocated (12) + +address: VaultStorage.strategistAddr (20) + +mapping(address=>address): VaultStorage.assetDefaultStrategies (32) + +uint256: VaultStorage.maxSupplyDiff (32) + +unallocated (12) + +address: VaultStorage.trusteeAddress (20) + +uint256: VaultStorage.trusteeFeeBps (32) + +address[]: VaultStorage._deprecated_swapTokens (32) + +unallocated (12) + +address: VaultStorage.ousdMetaStrategy (20) + +int256: VaultStorage.netOusdMintedForStrategy (32) + +uint256: VaultStorage.netOusdMintForStrategyThreshold (32) + +SwapConfig: VaultStorage.swapConfig (32) + +unallocated (12) + +address: VaultStorage.dripper (20) + +WithdrawalQueueMetadata: VaultStorage.withdrawalQueueMetadata (64) + +mapping(uint256=>WithdrawalRequest): VaultStorage.withdrawalRequests (32) + +uint256[46]: VaultStorage.__gap (1472) 1 - -Asset <<Struct>> - -offset - -0 - -type: variable (bytes) - -unallocated (27) - -uint16: allowedOracleSlippageBps (2) - -uint8: decimals (1) - -UnitConversion: unitConversion (1) - -bool: isSupported (1) + +Asset <<Struct>> + +offset + +0 + +type: variable (bytes) + +unallocated (27) + +uint16: allowedOracleSlippageBps (2) + +uint8: decimals (1) + +UnitConversion: unitConversion (1) + +bool: isSupported (1) - + -9:8->1 - - +8:8->1 + + 2 - -address[]: allAssets <<Array>> -0x46bddb1178e94d7f2892ff5f366840eb658911794f2c3a44c450aa2c505186c1 - -offset - -0 - -type: variable (bytes) - -unallocated (12) - -address (20) + +address[]: allAssets <<Array>> +0x46bddb1178e94d7f2892ff5f366840eb658911794f2c3a44c450aa2c505186c1 + +offset + +0 + +type: variable (bytes) + +unallocated (12) + +address (20) - + -9:10->2 - - +8:10->2 + + 3 - -Strategy <<Struct>> - -offset - -0 - -1 - -type: variable (bytes) - -unallocated (31) - -bool: isSupported (1) - -uint256: _deprecated (32) + +Strategy <<Struct>> + +offset + +0 + +1 + +type: variable (bytes) + +unallocated (31) + +bool: isSupported (1) + +uint256: _deprecated (32) - + -9:13->3 - - +8:13->3 + + 4 - -address[]: allStrategies <<Array>> -0x4a11f94e20a93c79f6ec743a1954ec4fc2c08429ae2122118bf234b2185c81b8 - -offset - -0 - -type: variable (bytes) - -unallocated (12) - -address (20) + +address[]: allStrategies <<Array>> +0x4a11f94e20a93c79f6ec743a1954ec4fc2c08429ae2122118bf234b2185c81b8 + +offset + +0 + +type: variable (bytes) + +unallocated (12) + +address (20) - + -9:15->4 - - +8:15->4 + + 5 - -SwapConfig <<Struct>> - -slot - -72 - -type: variable (bytes) - -unallocated (10) - -uint16: allowedUndervalueBps (2) - -address: swapper (20) + +SwapConfig <<Struct>> + +slot + +72 + +type: variable (bytes) + +unallocated (10) + +uint16: allowedUndervalueBps (2) + +address: swapper (20) - + -9:37->5 - - +8:37->5 + + 6 - -WithdrawalQueueMetadata <<Struct>> - -slot - -74 - -75 - -type: variable (bytes) - -uint128: claimable (16) - -uint128: queued (16) - -uint128: nextWithdrawalIndex (16) - -uint128: claimed (16) + +WithdrawalQueueMetadata <<Struct>> + +slot + +74 + +75 + +type: variable (bytes) + +uint128: claimable (16) + +uint128: queued (16) + +uint128: nextWithdrawalIndex (16) + +uint128: claimed (16) - + -9:43->6 - - +8:43->6 + + 7 - -WithdrawalRequest <<Struct>> - -offset - -0 - -1 - -type: variable (bytes) - -unallocated (11) - -bool: claimed (1) - -address: withdrawer (20) - -uint128: queued (16) - -uint128: amount (16) + +WithdrawalRequest <<Struct>> + +offset + +0 + +1 + +type: variable (bytes) + +unallocated (6) + +uint40: timestamp (5) + +bool: claimed (1) + +address: withdrawer (20) + +uint128: queued (16) + +uint128: amount (16) - + -9:48->7 - - - - - -8 - -uint256[46]: __gap <<Array>> - -slot - -77 - -78 - -79-120 - -121 - -122 - -type: variable (bytes) - -uint256 (32) - -uint256 (32) - ----- (1344) - -uint256 (32) - -uint256 (32) - - - -9:54->8 - - +8:49->7 + + diff --git a/contracts/docs/generate.sh b/contracts/docs/generate.sh index ecd15f8c69..c8bc5867eb 100644 --- a/contracts/docs/generate.sh +++ b/contracts/docs/generate.sh @@ -132,12 +132,12 @@ sol2uml storage .. -c WOETH -o WOETHStorage.svg sol2uml .. -v -hv -hf -he -hs -hl -hi -b VaultCore,VaultAdmin -o VaultHierarchy.svg sol2uml .. -s -d 0 -b VaultCore -o VaultCoreSquashed.svg sol2uml .. -s -d 0 -b VaultAdmin -o VaultAdminSquashed.svg -sol2uml storage .. -c VaultCore -o VaultStorage.svg --hideExpand ______gap,_deprecated_swapTokens +sol2uml storage .. -c VaultCore -o VaultStorage.svg --hideExpand __gap,______gap,_deprecated_swapTokens sol2uml .. -v -hv -hf -he -hs -hl -hi -b OETHVaultCore,OETHVaultAdmin -o OETHVaultHierarchy.svg sol2uml .. -s -d 0 -b OETHVaultCore -o OETHVaultCoreSquashed.svg sol2uml .. -s -d 0 -b OETHVaultAdmin -o OETHVaultAdminSquashed.svg -sol2uml storage .. -c OETHVaultCore -o OETHVaultStorage.svg --hideExpand ______gap,_deprecated_swapTokens +sol2uml storage .. -c OETHVaultCore -o OETHVaultStorage.svg --hideExpand __gap,______gap,_deprecated_swapTokens # contracts/utils sol2uml .. -v -hv -hf -he -hs -hl -b InitializableAbstractStrategy -o InitializableAbstractStrategyHierarchy.svg From cbd6764a5416600d0286191658f85535d81da302 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Mon, 15 Jul 2024 21:39:54 +1000 Subject: [PATCH 150/273] Added second native staking strategy as the default for WETH --- ..._withdraw_queue.js => 103_oeth_withdraw_queue.js} | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) rename contracts/deploy/mainnet/{101_oeth_withdraw_queue.js => 103_oeth_withdraw_queue.js} (89%) diff --git a/contracts/deploy/mainnet/101_oeth_withdraw_queue.js b/contracts/deploy/mainnet/103_oeth_withdraw_queue.js similarity index 89% rename from contracts/deploy/mainnet/101_oeth_withdraw_queue.js rename to contracts/deploy/mainnet/103_oeth_withdraw_queue.js index 057ae31a46..b46e5e84ba 100644 --- a/contracts/deploy/mainnet/101_oeth_withdraw_queue.js +++ b/contracts/deploy/mainnet/103_oeth_withdraw_queue.js @@ -5,7 +5,7 @@ const { deploymentWithGovernanceProposal } = require("../../utils/deploy"); module.exports = deploymentWithGovernanceProposal( { - deployName: "101_oeth_withdraw_queue", + deployName: "103_oeth_withdraw_queue", forceDeploy: false, //forceSkip: true, reduceQueueTime: true, @@ -54,6 +54,10 @@ module.exports = deploymentWithGovernanceProposal( 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 { @@ -108,6 +112,12 @@ module.exports = deploymentWithGovernanceProposal( 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], + }, ], }; } From f93f6ab2f1e50e0f2698f6b7fa1e77dc18e9ea12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment?= <55331875+clement-ux@users.noreply.github.com> Date: Mon, 15 Jul 2024 15:16:14 +0200 Subject: [PATCH 151/273] Add solvency check. (#2131) * feat: add solvency check. * test: add test for solvency check. * docs: add comments * test: add more assertions. * style: run prettier * test: redeem with fees. * test: increase coverage. * test: increase coverage again. * fix: failing test. --- contracts/contracts/vault/OETHVaultCore.sol | 10 ++ contracts/test/vault/oeth-vault.js | 185 +++++++++++++++++++- 2 files changed, 194 insertions(+), 1 deletion(-) diff --git a/contracts/contracts/vault/OETHVaultCore.sol b/contracts/contracts/vault/OETHVaultCore.sol index 527a6feaef..dc658ab8c9 100644 --- a/contracts/contracts/vault/OETHVaultCore.sol +++ b/contracts/contracts/vault/OETHVaultCore.sol @@ -155,6 +155,7 @@ contract OETHVaultCore is VaultCore { // Burn OETH from user (including fees) oUSD.burn(msg.sender, _amount); + // Prevent insolvency _postRedeem(_amount); } @@ -196,6 +197,9 @@ contract OETHVaultCore is VaultCore { amount: uint128(_amount), queued: uint128(queued) }); + + // Prevent insolvency + _postRedeem(_amount); } /** @@ -218,6 +222,9 @@ contract OETHVaultCore is VaultCore { // transfer WETH from the vault to the withdrawer IERC20(weth).safeTransfer(msg.sender, amount); + + // Prevent insolvency + _postRedeem(amount); } /** @@ -243,6 +250,9 @@ contract OETHVaultCore is VaultCore { // transfer all the claimed WETH from the vault to the withdrawer IERC20(weth).safeTransfer(msg.sender, totalAmount); + + // Prevent insolvency + _postRedeem(totalAmount); } // slither-disable-start reentrancy-no-eth diff --git a/contracts/test/vault/oeth-vault.js b/contracts/test/vault/oeth-vault.js index 9639cdbcf7..7ec3691bba 100644 --- a/contracts/test/vault/oeth-vault.js +++ b/contracts/test/vault/oeth-vault.js @@ -5,6 +5,7 @@ const { createFixtureLoader, oethDefaultFixture } = require("../_fixture"); const { parseUnits } = require("ethers/lib/utils"); const { deployWithConfirmation } = require("../../utils/deploy"); const { oethUnits, advanceTime } = require("../helpers"); +const { impersonateAndFund } = require("../../utils/signers"); const addresses = require("../../utils/addresses"); const oethFixture = createFixtureLoader(oethDefaultFixture); @@ -187,7 +188,7 @@ describe("OETH Vault", function () { await expect(tx).to.be.revertedWith("WETH Asset index not cached"); }); - it("should update total supply correctly", async () => { + it("should update total supply correctly without redeem fee", async () => { const { oethVault, oeth, weth, daniel } = fixture; await oethVault.connect(daniel).mint(weth.address, oethUnits("10"), "0"); @@ -207,6 +208,34 @@ describe("OETH Vault", function () { expect(supplyBefore.sub(supplyAfter)).to.eq(oethUnits("10")); }); + it("should update total supply correctly with redeem fee", async () => { + const { oethVault, oeth, weth, daniel } = fixture; + await oethVault.connect(daniel).mint(weth.address, oethUnits("10"), "0"); + + await oethVault + .connect(await impersonateAndFund(await oethVault.governor())) + .setRedeemFeeBps(100); + + const userBalanceBefore = await weth.balanceOf(daniel.address); + const vaultBalanceBefore = await weth.balanceOf(oethVault.address); + const supplyBefore = await oeth.totalSupply(); + + await oethVault.connect(daniel).redeem(oethUnits("10"), "0"); + + const userBalanceAfter = await weth.balanceOf(daniel.address); + const vaultBalanceAfter = await weth.balanceOf(oethVault.address); + const supplyAfter = await oeth.totalSupply(); + + // Make sure the total supply went down + expect(userBalanceAfter.sub(userBalanceBefore)).to.eq( + oethUnits("10").sub(oethUnits("0.1")) + ); + expect(vaultBalanceBefore.sub(vaultBalanceAfter)).to.eq( + oethUnits("10").sub(oethUnits("0.1")) + ); + expect(supplyBefore.sub(supplyAfter)).to.eq(oethUnits("10")); + }); + it("Should withdraw from strategy if necessary", async () => { const { oethVault, weth, domen, governor } = fixture; @@ -291,6 +320,23 @@ describe("OETH Vault", function () { const tx = mockVault.connect(sDeployer).cacheWETHAssetIndex(); await expect(tx).to.be.revertedWith("Invalid WETH Asset Index"); }); + + it("should return all strategies", async () => { + // Mostly to increase coverage + + const { oethVault, weth, governor } = fixture; + + // Empty list + await expect((await oethVault.getAllStrategies()).length).to.equal(0); + + // Add a strategy + await oethVault.connect(governor).approveStrategy(weth.address); + + // Check the strategy list + await expect(await oethVault.getAllStrategies()).to.deep.equal([ + weth.address, + ]); + }); }); describe("Remove Asset", () => { @@ -365,6 +411,53 @@ describe("OETH Vault", function () { await expect(tx).to.not.be.revertedWith("Vault still holds asset"); }); + + it("should allow strategy to burnForStrategy", async () => { + const { oethVault, oeth, weth, governor, daniel } = fixture; + + await oethVault.connect(governor).setOusdMetaStrategy(daniel.address); + + // First increase netOusdMintForStrategyThreshold + await oethVault + .connect(governor) + .setNetOusdMintForStrategyThreshold(oethUnits("100")); + + // Then mint for strategy + await oethVault.connect(daniel).mint(weth.address, oethUnits("10"), "0"); + + await expect(await oeth.balanceOf(daniel.address)).to.equal( + oethUnits("10") + ); + + // Then burn for strategy + await oethVault.connect(daniel).burnForStrategy(oethUnits("10")); + + await expect(await oeth.balanceOf(daniel.address)).to.equal( + oethUnits("0") + ); + }); + + it("should fail when burnForStrategy because Amoount too high", async () => { + const { oethVault, governor, daniel } = fixture; + + await oethVault.connect(governor).setOusdMetaStrategy(daniel.address); + const tx = oethVault + .connect(daniel) + .burnForStrategy(parseUnits("10", 76)); + + await expect(tx).to.be.revertedWith("Amount too high"); + }); + + it("should fail when burnForStrategy because Attempting to burn too much OUSD.", async () => { + const { oethVault, governor, daniel } = fixture; + + await oethVault.connect(governor).setOusdMetaStrategy(daniel.address); + + // Then try to burn more than authorized + const tx = oethVault.connect(daniel).burnForStrategy(oethUnits("0")); + + await expect(tx).to.be.revertedWith("Attempting to burn too much OUSD."); + }); }); describe("with withdrawal queue", () => { @@ -374,6 +467,9 @@ describe("OETH Vault", function () { await oethVault.connect(daniel).mint(weth.address, oethUnits("10"), "0"); await oethVault.connect(josh).mint(weth.address, oethUnits("20"), "0"); await oethVault.connect(matt).mint(weth.address, oethUnits("30"), "0"); + await oethVault + .connect(await impersonateAndFund(await oethVault.governor())) + .setMaxSupplyDiff(oethUnits("0.03")); }); const firstRequestAmount = oethUnits("5"); const secondRequestAmount = oethUnits("18"); @@ -621,6 +717,34 @@ describe("OETH Vault", function () { fixtureWithUser ); }); + it("Should claim single big request as a whale", async () => { + const { oethVault, oeth, matt } = fixture; + + const oethBalanceBefore = await oeth.balanceOf(matt.address); + const totalValueBefore = await oethVault.totalValue(); + + await oethVault.connect(matt).requestWithdrawal(oethUnits("30")); + + const oethBalanceAfter = await oeth.balanceOf(matt.address); + const totalValueAfter = await oethVault.totalValue(); + await expect(oethBalanceBefore).to.equal(oethUnits("30")); + await expect(oethBalanceAfter).to.equal(oethUnits("0")); + await expect(totalValueBefore.sub(totalValueAfter)).to.equal( + oethUnits("30") + ); + + const oethTotalSupply = await oeth.totalSupply(); + await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. + const tx = await oethVault.connect(matt).claimWithdrawal(0); // Claim withdrawal for 50% of the supply + + await expect(tx) + .to.emit(oethVault, "WithdrawalClaimed") + .withArgs(matt.address, 0, oethUnits("30")); + + await expect(oethTotalSupply).to.equal(await oeth.totalSupply()); + await expect(totalValueAfter).to.equal(await oethVault.totalValue()); + }); + it("Should fail claim request because of not enough time passed", async () => { const { oethVault, daniel } = fixture; @@ -633,6 +757,65 @@ describe("OETH Vault", function () { await expect(tx).to.revertedWith("Claim delay not met"); }); + it("Should fail request withdrawal because of solvency check too high", async () => { + const { oethVault, daniel, weth } = fixture; + + await weth.connect(daniel).transfer(oethVault.address, oethUnits("10")); + + const tx = oethVault + .connect(daniel) + .requestWithdrawal(firstRequestAmount); + + await expect(tx).to.revertedWith("Backing supply liquidity error"); + }); + it("Should fail claim request because of solvency check too high", async () => { + const { oethVault, daniel, weth } = fixture; + + // Request withdrawal of 5 OETH + await oethVault.connect(daniel).requestWithdrawal(firstRequestAmount); + + // Transfer 10 WETH to the vault + await weth.connect(daniel).transfer(oethVault.address, oethUnits("10")); + + await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. + + // Claim the withdrawal + const tx = oethVault.connect(daniel).claimWithdrawal(0); + + await expect(tx).to.revertedWith("Backing supply liquidity error"); + }); + it("Should fail multiple claim requests because of solvency check too high", async () => { + const { oethVault, matt, weth } = fixture; + + // Request withdrawal of 5 OETH + await oethVault.connect(matt).requestWithdrawal(firstRequestAmount); + await oethVault.connect(matt).requestWithdrawal(secondRequestAmount); + + // Transfer 10 WETH to the vault + await weth.connect(matt).transfer(oethVault.address, oethUnits("10")); + + await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. + + // Claim the withdrawal + const tx = oethVault.connect(matt).claimWithdrawals([0, 1]); + + await expect(tx).to.revertedWith("Backing supply liquidity error"); + }); + + it("Should fail request withdrawal because of solvency check too low", async () => { + const { oethVault, daniel, weth } = fixture; + + // Simulate a loss of funds from the vault + await weth + .connect(await impersonateAndFund(oethVault.address)) + .transfer(daniel.address, oethUnits("10")); + + const tx = oethVault + .connect(daniel) + .requestWithdrawal(firstRequestAmount); + + await expect(tx).to.revertedWith("Backing supply liquidity error"); + }); describe("when deposit some WETH to a strategy", () => { let mockStrategy; From d3de400cad740edde51ecc84573d8c072c47faab Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Tue, 16 Jul 2024 11:10:18 +1000 Subject: [PATCH 152/273] Fixed claim Natspec now the delay is in place --- contracts/contracts/vault/OETHVaultCore.sol | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/contracts/contracts/vault/OETHVaultCore.sol b/contracts/contracts/vault/OETHVaultCore.sol index 527a6feaef..8f5c9b3236 100644 --- a/contracts/contracts/vault/OETHVaultCore.sol +++ b/contracts/contracts/vault/OETHVaultCore.sol @@ -201,9 +201,9 @@ contract OETHVaultCore is VaultCore { /** * @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. - * 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. + * is greater than or equal this request's `queued` amount and 30 minutes has passed. + * If the requests is not claimable, the transaction will revert with `Queue pending liquidity`. + * If the request is not older than 30 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 @@ -223,8 +223,9 @@ contract OETHVaultCore is VaultCore { /** * @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. - * If one of the requests is not claimable, the whole transaction will revert with `queue pending liquidity`. + * is greater than or equal each request's `queued` amount and 30 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 30 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 From ecc27734a4c94bceb2bad4555b22e8639c27fe8b Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Tue, 16 Jul 2024 11:49:47 +1000 Subject: [PATCH 153/273] Changed console debug in assertUpgradeIsSafe to use logger --- contracts/tasks/storageSlots.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/contracts/tasks/storageSlots.js b/contracts/tasks/storageSlots.js index 9a5f507dc6..0ff0f45239 100644 --- a/contracts/tasks/storageSlots.js +++ b/contracts/tasks/storageSlots.js @@ -9,6 +9,9 @@ const { isCurrentValidationData, assertStorageUpgradeSafe, } = require("@openzeppelin/upgrades-core"); + +const log = require("../utils/logger")("task:storage"); + const isFork = process.env.FORK === "true"; const getStorageFileLocation = (hre, contractName) => { @@ -124,7 +127,7 @@ const showStorageLayout = async (taskArguments, hre) => { const assertUpgradeIsSafe = async (hre, contractName) => { if (!isContractEligible(contractName)) { - console.debug(`Skipping storage slot validation of ${contractName}.`); + log(`Skipping storage slot validation of ${contractName}.`); return true; } @@ -135,7 +138,7 @@ const assertUpgradeIsSafe = async (hre, contractName) => { contractName ); if (!oldLayout) { - console.debug( + log( `Previous storage layout for ${contractName} not found. Treating ${contractName} as a new contract.` ); } else { From 74875cd3cc54417ef294e64b6c1cc1e52d7fe7ba Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Tue, 16 Jul 2024 11:50:07 +1000 Subject: [PATCH 154/273] Updated Natspec --- contracts/contracts/vault/OETHVaultAdmin.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/contracts/vault/OETHVaultAdmin.sol b/contracts/contracts/vault/OETHVaultAdmin.sol index a329b9fbef..5c067f9475 100644 --- a/contracts/contracts/vault/OETHVaultAdmin.sol +++ b/contracts/contracts/vault/OETHVaultAdmin.sol @@ -74,7 +74,7 @@ contract OETHVaultAdmin is VaultAdmin { IVault(address(this)).addWithdrawalQueueLiquidity(); } - // TODO move to a library? + /// @dev Calculates the amount of WETH in the Vault that is not reserved for the withdrawal queue. function _wethAvailable() internal view returns (uint256 wethAvailable) { WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata; From 5c2ab55c1700c5a5e6574b9bd491b03254755b64 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Tue, 16 Jul 2024 11:51:32 +1000 Subject: [PATCH 155/273] Assert totalValue in withdrawal queue unit tests --- contracts/test/vault/oeth-vault.js | 54 ++++++++++++++++++++---------- 1 file changed, 37 insertions(+), 17 deletions(-) diff --git a/contracts/test/vault/oeth-vault.js b/contracts/test/vault/oeth-vault.js index 9639cdbcf7..943789e883 100644 --- a/contracts/test/vault/oeth-vault.js +++ b/contracts/test/vault/oeth-vault.js @@ -18,14 +18,16 @@ describe("OETH Vault", function () { const snapData = async (fixture) => { const { oeth, oethVault, weth, user } = fixture; - const oethTotal = await oeth.totalSupply(); + const oethTotalSupply = await oeth.totalSupply(); + const oethTotalValue = await oethVault.totalValue(); const userOeth = await oeth.balanceOf(user.address); const userWeth = await weth.balanceOf(user.address); const vaultWeth = await weth.balanceOf(oethVault.address); const queue = await oethVault.withdrawalQueueMetadata(); return { - oethTotal, + oethTotalSupply, + oethTotalValue, userOeth, userWeth, vaultWeth, @@ -37,9 +39,13 @@ describe("OETH Vault", function () { const { oeth, oethVault, weth, user } = fixture; expect(await oeth.totalSupply()).to.equal( - dataBefore.oethTotal.add(delta.oethTotal), + dataBefore.oethTotalSupply.add(delta.oethTotalSupply), "OETH Total Supply" ); + expect(await oethVault.totalValue()).to.equal( + dataBefore.oethTotalValue.add(delta.oethTotalValue), + "OETH Total Value" + ); expect(await oeth.balanceOf(user.address)).to.equal( dataBefore.userOeth.add(delta.userOeth), "user's OETH balance" @@ -91,7 +97,8 @@ describe("OETH Vault", function () { await assertChangedData( dataBefore, { - oethTotal: amount, + oethTotalSupply: amount, + oethTotalValue: amount, userOeth: amount, userWeth: amount.mul(-1), vaultWeth: amount, @@ -394,7 +401,8 @@ describe("OETH Vault", function () { await assertChangedData( dataBefore, { - oethTotal: firstRequestAmount.mul(-1), + oethTotalSupply: firstRequestAmount.mul(-1), + oethTotalValue: firstRequestAmount.mul(-1), userOeth: firstRequestAmount.mul(-1), userWeth: 0, vaultWeth: 0, @@ -421,7 +429,8 @@ describe("OETH Vault", function () { await assertChangedData( dataBefore, { - oethTotal: 0, + oethTotalSupply: 0, + oethTotalValue: 0, userOeth: 0, userWeth: 0, vaultWeth: 0, @@ -468,7 +477,8 @@ describe("OETH Vault", function () { await assertChangedData( dataBefore, { - oethTotal: firstRequestAmount.add(secondRequestAmount).mul(-1), + oethTotalSupply: firstRequestAmount.add(secondRequestAmount).mul(-1), + oethTotalValue: firstRequestAmount.add(secondRequestAmount).mul(-1), userOeth: firstRequestAmount.mul(-1), userWeth: 0, vaultWeth: 0, @@ -502,7 +512,8 @@ describe("OETH Vault", function () { await assertChangedData( dataBefore, { - oethTotal: secondRequestAmount.mul(-1), + oethTotalSupply: secondRequestAmount.mul(-1), + oethTotalValue: secondRequestAmount.mul(-1), userOeth: secondRequestAmount.mul(-1), userWeth: 0, vaultWeth: 0, @@ -533,7 +544,8 @@ describe("OETH Vault", function () { await assertChangedData( dataBefore, { - oethTotal: 0, + oethTotalSupply: 0, + oethTotalValue: 0, userOeth: 0, userWeth: 0, vaultWeth: 0, @@ -570,7 +582,8 @@ describe("OETH Vault", function () { await assertChangedData( dataBefore, { - oethTotal: 0, + oethTotalSupply: 0, + oethTotalValue: 0, userOeth: 0, userWeth: secondRequestAmount, vaultWeth: secondRequestAmount.mul(-1), @@ -609,7 +622,8 @@ describe("OETH Vault", function () { await assertChangedData( dataBefore, { - oethTotal: 0, + oethTotalSupply: 0, + oethTotalValue: 0, userOeth: 0, userWeth: firstRequestAmount.add(secondRequestAmount), vaultWeth: firstRequestAmount.add(secondRequestAmount).mul(-1), @@ -707,7 +721,8 @@ describe("OETH Vault", function () { await assertChangedData( dataBefore, { - oethTotal: 0, + oethTotalSupply: 0, + oethTotalValue: 0, userOeth: 0, userWeth: firstRequestAmount, vaultWeth: firstRequestAmount.mul(-1), @@ -745,7 +760,8 @@ describe("OETH Vault", function () { await assertChangedData( dataBefore, { - oethTotal: 0, + oethTotalSupply: 0, + oethTotalValue: 0, userOeth: 0, userWeth: requestAmount, vaultWeth: requestAmount.mul(-1), @@ -797,7 +813,8 @@ describe("OETH Vault", function () { await assertChangedData( dataBeforeMint, { - oethTotal: 0, + oethTotalSupply: 0, + oethTotalValue: 0, userOeth: 0, userWeth: 0, vaultWeth: withdrawAmount, @@ -839,7 +856,8 @@ describe("OETH Vault", function () { await assertChangedData( dataBeforeMint, { - oethTotal: 0, + oethTotalSupply: 0, + oethTotalValue: 0, userOeth: 0, userWeth: 0, vaultWeth: strategyBalanceBefore, @@ -879,7 +897,8 @@ describe("OETH Vault", function () { await assertChangedData( dataBeforeMint, { - oethTotal: 0, + oethTotalSupply: 0, + oethTotalValue: 0, userOeth: 0, userWeth: 0, vaultWeth: strategyBalanceBefore, @@ -934,7 +953,8 @@ describe("OETH Vault", function () { await assertChangedData( dataBeforeMint, { - oethTotal: mintAmount, + oethTotalSupply: mintAmount, + oethTotalValue: mintAmount, userOeth: mintAmount, userWeth: mintAmount.mul(-1), vaultWeth: mintAmount, From 6ba210a226a6b15de296d056220b168508a95e8c Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Tue, 16 Jul 2024 12:02:26 +1000 Subject: [PATCH 156/273] Fixed prettier --- contracts/contracts/vault/OETHVaultCore.sol | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/contracts/contracts/vault/OETHVaultCore.sol b/contracts/contracts/vault/OETHVaultCore.sol index e3fc2da3fd..e20a227f8c 100644 --- a/contracts/contracts/vault/OETHVaultCore.sol +++ b/contracts/contracts/vault/OETHVaultCore.sol @@ -232,7 +232,8 @@ contract OETHVaultCore is VaultCore { * This requests can be claimed once the withdrawal queue's `claimable` amount * is greater than or equal each request's `queued` amount and 30 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 30 minutes, the whole transaction will revert with `Claim delay not met`. + * If one of the requests is not older than 30 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 From 52b2fe31f92e174ecb47181cadf0ca743f65254b Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Tue, 16 Jul 2024 12:11:16 +1000 Subject: [PATCH 157/273] Asset vault checkBalance of WETH to OETH Vault unit tests --- contracts/test/vault/oeth-vault.js | 50 ++++++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 3 deletions(-) diff --git a/contracts/test/vault/oeth-vault.js b/contracts/test/vault/oeth-vault.js index c377d748e8..1beb21d1bc 100644 --- a/contracts/test/vault/oeth-vault.js +++ b/contracts/test/vault/oeth-vault.js @@ -21,6 +21,7 @@ describe("OETH Vault", function () { const oethTotalSupply = await oeth.totalSupply(); const oethTotalValue = await oethVault.totalValue(); + const vaultCheckBalance = await oethVault.checkBalance(weth.address); const userOeth = await oeth.balanceOf(user.address); const userWeth = await weth.balanceOf(user.address); const vaultWeth = await weth.balanceOf(oethVault.address); @@ -29,6 +30,7 @@ describe("OETH Vault", function () { return { oethTotalSupply, oethTotalValue, + vaultCheckBalance, userOeth, userWeth, vaultWeth, @@ -45,7 +47,11 @@ describe("OETH Vault", function () { ); expect(await oethVault.totalValue()).to.equal( dataBefore.oethTotalValue.add(delta.oethTotalValue), - "OETH Total Value" + "Vault Total Value" + ); + expect(await oethVault.checkBalance(weth.address)).to.equal( + dataBefore.vaultCheckBalance.add(delta.vaultCheckBalance), + "Vault Check Balance of WETH" ); expect(await oeth.balanceOf(user.address)).to.equal( dataBefore.userOeth.add(delta.userOeth), @@ -100,6 +106,7 @@ describe("OETH Vault", function () { { oethTotalSupply: amount, oethTotalValue: amount, + vaultCheckBalance: amount, userOeth: amount, userWeth: amount.mul(-1), vaultWeth: amount, @@ -154,12 +161,34 @@ describe("OETH Vault", function () { .connect(governor) .setAssetDefaultStrategy(weth.address, mockStrategy.address); + const fixtureWithUser = { ...fixture, user: domen }; + const dataBefore = await snapData(fixtureWithUser); + // Mint some WETH await weth.connect(domen).approve(oethVault.address, oethUnits("10000")); - await oethVault.connect(domen).mint(weth.address, oethUnits("100"), "0"); + const mintAmount = oethUnits("100"); + await oethVault.connect(domen).mint(weth.address, mintAmount, "0"); expect(await weth.balanceOf(mockStrategy.address)).to.eq( - oethUnits("100") + mintAmount, + "Strategy has the WETH" + ); + + await assertChangedData( + dataBefore, + { + oethTotalSupply: mintAmount, + oethTotalValue: mintAmount, + vaultCheckBalance: mintAmount, + userOeth: mintAmount, + userWeth: mintAmount.mul(-1), + vaultWeth: 0, + queued: 0, + claimable: 0, + claimed: 0, + nextWithdrawalIndex: 0, + }, + fixtureWithUser ); }); }); @@ -499,6 +528,7 @@ describe("OETH Vault", function () { { oethTotalSupply: firstRequestAmount.mul(-1), oethTotalValue: firstRequestAmount.mul(-1), + vaultCheckBalance: firstRequestAmount.mul(-1), userOeth: firstRequestAmount.mul(-1), userWeth: 0, vaultWeth: 0, @@ -527,6 +557,7 @@ describe("OETH Vault", function () { { oethTotalSupply: 0, oethTotalValue: 0, + vaultCheckBalance: 0, userOeth: 0, userWeth: 0, vaultWeth: 0, @@ -575,6 +606,9 @@ describe("OETH Vault", function () { { oethTotalSupply: firstRequestAmount.add(secondRequestAmount).mul(-1), oethTotalValue: firstRequestAmount.add(secondRequestAmount).mul(-1), + vaultCheckBalance: firstRequestAmount + .add(secondRequestAmount) + .mul(-1), userOeth: firstRequestAmount.mul(-1), userWeth: 0, vaultWeth: 0, @@ -610,6 +644,7 @@ describe("OETH Vault", function () { { oethTotalSupply: secondRequestAmount.mul(-1), oethTotalValue: secondRequestAmount.mul(-1), + vaultCheckBalance: secondRequestAmount.mul(-1), userOeth: secondRequestAmount.mul(-1), userWeth: 0, vaultWeth: 0, @@ -642,6 +677,7 @@ describe("OETH Vault", function () { { oethTotalSupply: 0, oethTotalValue: 0, + vaultCheckBalance: 0, userOeth: 0, userWeth: 0, vaultWeth: 0, @@ -680,6 +716,7 @@ describe("OETH Vault", function () { { oethTotalSupply: 0, oethTotalValue: 0, + vaultCheckBalance: 0, userOeth: 0, userWeth: secondRequestAmount, vaultWeth: secondRequestAmount.mul(-1), @@ -720,6 +757,7 @@ describe("OETH Vault", function () { { oethTotalSupply: 0, oethTotalValue: 0, + vaultCheckBalance: 0, userOeth: 0, userWeth: firstRequestAmount.add(secondRequestAmount), vaultWeth: firstRequestAmount.add(secondRequestAmount).mul(-1), @@ -906,6 +944,7 @@ describe("OETH Vault", function () { { oethTotalSupply: 0, oethTotalValue: 0, + vaultCheckBalance: 0, userOeth: 0, userWeth: firstRequestAmount, vaultWeth: firstRequestAmount.mul(-1), @@ -945,6 +984,7 @@ describe("OETH Vault", function () { { oethTotalSupply: 0, oethTotalValue: 0, + vaultCheckBalance: 0, userOeth: 0, userWeth: requestAmount, vaultWeth: requestAmount.mul(-1), @@ -998,6 +1038,7 @@ describe("OETH Vault", function () { { oethTotalSupply: 0, oethTotalValue: 0, + vaultCheckBalance: 0, userOeth: 0, userWeth: 0, vaultWeth: withdrawAmount, @@ -1041,6 +1082,7 @@ describe("OETH Vault", function () { { oethTotalSupply: 0, oethTotalValue: 0, + vaultCheckBalance: 0, userOeth: 0, userWeth: 0, vaultWeth: strategyBalanceBefore, @@ -1082,6 +1124,7 @@ describe("OETH Vault", function () { { oethTotalSupply: 0, oethTotalValue: 0, + vaultCheckBalance: 0, userOeth: 0, userWeth: 0, vaultWeth: strategyBalanceBefore, @@ -1138,6 +1181,7 @@ describe("OETH Vault", function () { { oethTotalSupply: mintAmount, oethTotalValue: mintAmount, + vaultCheckBalance: mintAmount, userOeth: mintAmount, userWeth: mintAmount.mul(-1), vaultWeth: mintAmount, From f9e9fddc294eb537724ea88636a142a351d02547 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Tue, 16 Jul 2024 13:03:26 +1000 Subject: [PATCH 158/273] _checkBalance and _totalValue on OETH Vault to protect against insolvency with most users requesting a withdrawal --- contracts/contracts/vault/OETHVaultCore.sol | 22 +++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/contracts/contracts/vault/OETHVaultCore.sol b/contracts/contracts/vault/OETHVaultCore.sol index e20a227f8c..9790509fcc 100644 --- a/contracts/contracts/vault/OETHVaultCore.sol +++ b/contracts/contracts/vault/OETHVaultCore.sol @@ -365,6 +365,14 @@ contract OETHVaultCore is VaultCore { } } + /// @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 @@ -376,7 +384,9 @@ contract OETHVaultCore is VaultCore { if (_asset == weth) { WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata; // Need to remove WETH that is reserved for the withdrawal queue - return balance + queue.claimed - queue.queued; + if (balance + queue.claimed >= queue.queued) { + return balance + queue.claimed - queue.queued; + } } } @@ -387,12 +397,20 @@ contract OETHVaultCore is VaultCore { super._allocate(); } + /// @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 = super._totalValue(); // Need to remove WETH that is reserved for the withdrawal queue. // reserved for the withdrawal queue = cumulative queued total - total claimed WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata; - value = value + queue.claimed - queue.queued; + if (value + queue.claimed >= queue.queued) { + return value + queue.claimed - queue.queued; + } } } From e85f4fb1c08fe90d0d19f4bb763ac4f7478183ba Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Tue, 16 Jul 2024 13:19:46 +1000 Subject: [PATCH 159/273] Override _totalValueInVault in OETH Vault --- contracts/contracts/vault/OETHVaultCore.sol | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/contracts/contracts/vault/OETHVaultCore.sol b/contracts/contracts/vault/OETHVaultCore.sol index 9790509fcc..bc6094d5b4 100644 --- a/contracts/contracts/vault/OETHVaultCore.sol +++ b/contracts/contracts/vault/OETHVaultCore.sol @@ -413,4 +413,17 @@ contract OETHVaultCore is VaultCore { return value + queue.claimed - queue.queued; } } + + /// @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)); + } } From 8c7776962a3b30694f4a0ddf3cd8c4d555bfacf4 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Tue, 16 Jul 2024 15:03:58 +1000 Subject: [PATCH 160/273] Removed super._totalValue call --- contracts/contracts/vault/OETHVaultCore.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/contracts/vault/OETHVaultCore.sol b/contracts/contracts/vault/OETHVaultCore.sol index bc6094d5b4..ce08a0b91c 100644 --- a/contracts/contracts/vault/OETHVaultCore.sol +++ b/contracts/contracts/vault/OETHVaultCore.sol @@ -404,7 +404,7 @@ contract OETHVaultCore is VaultCore { // 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 = super._totalValue(); + value = _totalValueInVault() + _totalValueInStrategies(); // Need to remove WETH that is reserved for the withdrawal queue. // reserved for the withdrawal queue = cumulative queued total - total claimed From 6eda2edf0d115f4bbadf2d17bb0ba6a750db3dc2 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Tue, 16 Jul 2024 15:36:09 +1000 Subject: [PATCH 161/273] Fix AMO fork tests --- contracts/test/_fixture.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/contracts/test/_fixture.js b/contracts/test/_fixture.js index 0a8ac859d0..3bcbc106a0 100644 --- a/contracts/test/_fixture.js +++ b/contracts/test/_fixture.js @@ -1801,6 +1801,10 @@ async function convexOETHMetaVaultFixture( .connect(timelock) .setNetOusdMintForStrategyThreshold(parseUnits("500", 21)); + await oethVault + .connect(timelock) + .setAssetDefaultStrategy(weth.address, addresses.zero); + // Impersonate the OETH Vault fixture.oethVaultSigner = await impersonateAndFund(oethVault.address); // Impersonate the Curve gauge that holds all the LP tokens From 28e3ead9587c232db98842602c6e48b2f9dfacb3 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Tue, 16 Jul 2024 16:53:07 +1000 Subject: [PATCH 162/273] Generated latest OETH Vault diagrams --- contracts/docs/OETHVaultAdminSquashed.svg | 4 +- contracts/docs/OETHVaultCoreSquashed.svg | 113 +++++++++++----------- 2 files changed, 59 insertions(+), 58 deletions(-) diff --git a/contracts/docs/OETHVaultAdminSquashed.svg b/contracts/docs/OETHVaultAdminSquashed.svg index 14d1c6e915..5eb606d36e 100644 --- a/contracts/docs/OETHVaultAdminSquashed.svg +++ b/contracts/docs/OETHVaultAdminSquashed.svg @@ -9,9 +9,9 @@ UmlClassDiagram - + -223 +225 OETHVaultAdmin ../contracts/vault/OETHVaultAdmin.sol diff --git a/contracts/docs/OETHVaultCoreSquashed.svg b/contracts/docs/OETHVaultCoreSquashed.svg index d49658abd7..63f3a01825 100644 --- a/contracts/docs/OETHVaultCoreSquashed.svg +++ b/contracts/docs/OETHVaultCoreSquashed.svg @@ -4,63 +4,64 @@ - - + + UmlClassDiagram - - + + -224 - -OETHVaultCore -../contracts/vault/OETHVaultCore.sol - -Private: -   initialized: bool <<Initializable>> -   initializing: bool <<Initializable>> -   ______gap: uint256[50] <<Initializable>> -   governorPosition: bytes32 <<Governable>> -   pendingGovernorPosition: bytes32 <<Governable>> -   reentryStatusPosition: bytes32 <<Governable>> -   _deprecated_rebaseHooksAddr: address <<VaultStorage>> -   _deprecated_uniswapAddr: address <<VaultStorage>> -   _deprecated_swapTokens: address[] <<VaultStorage>> -   __gap: uint256[46] <<VaultStorage>> -Internal: -   assets: mapping(address=>Asset) <<VaultStorage>> -   allAssets: address[] <<VaultStorage>> -   strategies: mapping(address=>Strategy) <<VaultStorage>> -   allStrategies: address[] <<VaultStorage>> -   oUSD: OUSD <<VaultStorage>> -   swapConfig: SwapConfig <<VaultStorage>> -   MAX_INT: uint256 <<VaultCore>> -   MAX_UINT: uint256 <<VaultCore>> -Public: -   _NOT_ENTERED: uint256 <<Governable>> -   _ENTERED: uint256 <<Governable>> -   priceProvider: address <<VaultStorage>> -   rebasePaused: bool <<VaultStorage>> -   capitalPaused: bool <<VaultStorage>> -   redeemFeeBps: uint256 <<VaultStorage>> -   vaultBuffer: uint256 <<VaultStorage>> -   autoAllocateThreshold: uint256 <<VaultStorage>> -   rebaseThreshold: uint256 <<VaultStorage>> -   adminImplPosition: bytes32 <<VaultStorage>> -   strategistAddr: address <<VaultStorage>> -   assetDefaultStrategies: mapping(address=>address) <<VaultStorage>> -   maxSupplyDiff: uint256 <<VaultStorage>> -   trusteeAddress: address <<VaultStorage>> -   trusteeFeeBps: uint256 <<VaultStorage>> -   MINT_MINIMUM_UNIT_PRICE: uint256 <<VaultStorage>> -   ousdMetaStrategy: address <<VaultStorage>> -   netOusdMintedForStrategy: int256 <<VaultStorage>> -   netOusdMintForStrategyThreshold: uint256 <<VaultStorage>> -   MIN_UNIT_PRICE_DRIFT: uint256 <<VaultStorage>> -   MAX_UNIT_PRICE_DRIFT: uint256 <<VaultStorage>> -   dripper: address <<VaultStorage>> -   withdrawalQueueMetadata: WithdrawalQueueMetadata <<VaultStorage>> -   withdrawalRequests: mapping(uint256=>WithdrawalRequest) <<VaultStorage>> +226 + +OETHVaultCore +../contracts/vault/OETHVaultCore.sol + +Private: +   initialized: bool <<Initializable>> +   initializing: bool <<Initializable>> +   ______gap: uint256[50] <<Initializable>> +   governorPosition: bytes32 <<Governable>> +   pendingGovernorPosition: bytes32 <<Governable>> +   reentryStatusPosition: bytes32 <<Governable>> +   _deprecated_rebaseHooksAddr: address <<VaultStorage>> +   _deprecated_uniswapAddr: address <<VaultStorage>> +   _deprecated_swapTokens: address[] <<VaultStorage>> +   __gap: uint256[46] <<VaultStorage>> +Internal: +   assets: mapping(address=>Asset) <<VaultStorage>> +   allAssets: address[] <<VaultStorage>> +   strategies: mapping(address=>Strategy) <<VaultStorage>> +   allStrategies: address[] <<VaultStorage>> +   oUSD: OUSD <<VaultStorage>> +   swapConfig: SwapConfig <<VaultStorage>> +   MAX_INT: uint256 <<VaultCore>> +   MAX_UINT: uint256 <<VaultCore>> +Public: +   _NOT_ENTERED: uint256 <<Governable>> +   _ENTERED: uint256 <<Governable>> +   priceProvider: address <<VaultStorage>> +   rebasePaused: bool <<VaultStorage>> +   capitalPaused: bool <<VaultStorage>> +   redeemFeeBps: uint256 <<VaultStorage>> +   vaultBuffer: uint256 <<VaultStorage>> +   autoAllocateThreshold: uint256 <<VaultStorage>> +   rebaseThreshold: uint256 <<VaultStorage>> +   adminImplPosition: bytes32 <<VaultStorage>> +   strategistAddr: address <<VaultStorage>> +   assetDefaultStrategies: mapping(address=>address) <<VaultStorage>> +   maxSupplyDiff: uint256 <<VaultStorage>> +   trusteeAddress: address <<VaultStorage>> +   trusteeFeeBps: uint256 <<VaultStorage>> +   MINT_MINIMUM_UNIT_PRICE: uint256 <<VaultStorage>> +   ousdMetaStrategy: address <<VaultStorage>> +   netOusdMintedForStrategy: int256 <<VaultStorage>> +   netOusdMintForStrategyThreshold: uint256 <<VaultStorage>> +   MIN_UNIT_PRICE_DRIFT: uint256 <<VaultStorage>> +   MAX_UNIT_PRICE_DRIFT: uint256 <<VaultStorage>> +   dripper: address <<VaultStorage>> +   withdrawalQueueMetadata: WithdrawalQueueMetadata <<VaultStorage>> +   withdrawalRequests: mapping(uint256=>WithdrawalRequest) <<VaultStorage>> +   CLAIM_DELAY: uint256 <<OETHVaultCore>>   weth: address <<OETHVaultCore>>   wethAssetIndex: uint256 <<OETHVaultCore>> @@ -78,7 +79,7 @@    _allocate() <<OETHVaultCore>>    _rebase(): uint256 <<whenNotRebasePaused>> <<VaultCore>>    _totalValue(): (value: uint256) <<OETHVaultCore>> -    _totalValueInVault(): (value: uint256) <<VaultCore>> +    _totalValueInVault(): (value: uint256) <<OETHVaultCore>>    _totalValueInStrategies(): (value: uint256) <<VaultCore>>    _totalValueInStrategy(_strategyAddr: address): (value: uint256) <<VaultCore>>    _checkBalance(_asset: address): (balance: uint256) <<OETHVaultCore>> From e86fa112b66fb7c46ce82ef5fb9c632f939840b9 Mon Sep 17 00:00:00 2001 From: Shahul Hameed <10547529+shahthepro@users.noreply.github.com> Date: Tue, 16 Jul 2024 14:58:04 +0530 Subject: [PATCH 163/273] Don't account for WETH reserved for withdrawal during allocation (#2138) * Override allocate method * Add test --- contracts/contracts/vault/OETHVaultCore.sol | 46 ++++++++++++++++++++- contracts/test/vault/oeth-vault.js | 44 ++++++++++++++++++-- 2 files changed, 85 insertions(+), 5 deletions(-) diff --git a/contracts/contracts/vault/OETHVaultCore.sol b/contracts/contracts/vault/OETHVaultCore.sol index ce08a0b91c..0351430dee 100644 --- a/contracts/contracts/vault/OETHVaultCore.sol +++ b/contracts/contracts/vault/OETHVaultCore.sol @@ -390,11 +390,55 @@ contract OETHVaultCore is VaultCore { } } + // @inheritdoc VaultCore function _allocate() internal override { // Add any unallocated WETH to the withdrawal queue first _addWithdrawalQueueLiquidity(); - super._allocate(); + uint256 wethAvailableInVault = _wethAvailable(); + // Nothing in vault to allocate + if (wethAvailableInVault == 0) return; + uint256 strategiesValue = _totalValueInStrategies(); + // We have a method that does the same as this, gas optimisation + uint256 calculatedTotalValue = wethAvailableInVault + strategiesValue; + + // We want to maintain a buffer on the Vault so calculate a percentage + // modifier to multiply each amount being allocated by to enforce the + // vault buffer + uint256 vaultBufferModifier; + if (strategiesValue == 0) { + // Nothing in Strategies, allocate 100% minus the vault buffer to + // strategies + vaultBufferModifier = uint256(1e18) - vaultBuffer; + } else { + vaultBufferModifier = + (vaultBuffer * calculatedTotalValue) / + wethAvailableInVault; + if (1e18 > vaultBufferModifier) { + // E.g. 1e18 - (1e17 * 10e18)/5e18 = 8e17 + // (5e18 * 8e17) / 1e18 = 4e18 allocated from Vault + vaultBufferModifier = uint256(1e18) - vaultBufferModifier; + } else { + // We need to let the buffer fill + return; + } + } + if (vaultBufferModifier == 0) return; + + uint256 allocateAmount = wethAvailableInVault.mulTruncate( + vaultBufferModifier + ); + + address depositStrategyAddr = assetDefaultStrategies[weth]; + + if (depositStrategyAddr != address(0) && allocateAmount > 0) { + IStrategy strategy = IStrategy(depositStrategyAddr); + // Transfer asset to Strategy and call deposit method to + // mint or take required action + 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 diff --git a/contracts/test/vault/oeth-vault.js b/contracts/test/vault/oeth-vault.js index 1beb21d1bc..c1a6ae2b25 100644 --- a/contracts/test/vault/oeth-vault.js +++ b/contracts/test/vault/oeth-vault.js @@ -68,16 +68,20 @@ describe("OETH Vault", function () { const queueAfter = await oethVault.withdrawalQueueMetadata(); expect(queueAfter.queued).to.equal( - dataBefore.queue.queued.add(delta.queued) + dataBefore.queue.queued.add(delta.queued), + "WithdrawalQueueMetadata.queued mismatch" ); expect(queueAfter.claimable).to.equal( - dataBefore.queue.claimable.add(delta.claimable) + dataBefore.queue.claimable.add(delta.claimable), + "WithdrawalQueueMetadata.claimable mismatch" ); expect(queueAfter.claimed).to.equal( - dataBefore.queue.claimed.add(delta.claimed) + dataBefore.queue.claimed.add(delta.claimed), + "WithdrawalQueueMetadata.claimed mismatch" ); expect(queueAfter.nextWithdrawalIndex).to.equal( - dataBefore.queue.nextWithdrawalIndex.add(delta.nextWithdrawalIndex) + dataBefore.queue.nextWithdrawalIndex.add(delta.nextWithdrawalIndex), + "WithdrawalQueueMetadata.queued nextWithdrawalInded" ); }; @@ -912,6 +916,38 @@ describe("OETH Vault", function () { ); await expect(tx).to.be.revertedWith("Not enough WETH available"); }); + it("should not deposit allocated WETH during allocate", async () => { + const { oethVault, governor, weth } = fixture; + + // Set mock strategy as default strategy + await oethVault + .connect(governor) + .setAssetDefaultStrategy(weth.address, mockStrategy.address); + + // and buffer to 10% + await oethVault.connect(governor).setVaultBuffer(oethUnits("0.1")); + + // WETH in strategy = 15 WETH + // WETH in the vault = 60 - 15 = 45 WETH + // Unallocated WETH in the vault = 45 - 23 = 22 WETH + + await oethVault.connect(governor).allocate(); + + expect(await weth.balanceOf(mockStrategy.address)).to.approxEqual( + // 60 - 23 = 37 Unreserved WETH + // 90% of 37 = 33.3 WETH for allocation + oethUnits("33.3"), + "Strategy has the reserved WETH" + ); + + expect(await weth.balanceOf(oethVault.address)).to.approxEqual( + // 10% of 37 = 3.7 WETH for Vault buffer + // + 23 reserved WETH + oethUnits("23").add(oethUnits("3.7")), + "Vault doesn't have enough WETH" + ); + }); + it("Should deposit unallocated WETH to a strategy", async () => { const { oethVault, weth, governor } = fixture; From 0f383e0f5dc656cae6529cca3788ca0ab40db573 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Tue, 16 Jul 2024 22:29:50 +1000 Subject: [PATCH 164/273] WIP more unit tests --- contracts/test/vault/oeth-vault.js | 1459 ++++++++++++++++------------ 1 file changed, 834 insertions(+), 625 deletions(-) diff --git a/contracts/test/vault/oeth-vault.js b/contracts/test/vault/oeth-vault.js index 1beb21d1bc..eadff9ce4f 100644 --- a/contracts/test/vault/oeth-vault.js +++ b/contracts/test/vault/oeth-vault.js @@ -41,42 +41,38 @@ describe("OETH Vault", function () { const assertChangedData = async (dataBefore, delta, fixture) => { const { oeth, oethVault, weth, user } = fixture; - expect(await oeth.totalSupply()).to.equal( - dataBefore.oethTotalSupply.add(delta.oethTotalSupply), - "OETH Total Supply" + expect(await oeth.totalSupply(), "OETH Total Supply").to.equal( + dataBefore.oethTotalSupply.add(delta.oethTotalSupply) ); - expect(await oethVault.totalValue()).to.equal( - dataBefore.oethTotalValue.add(delta.oethTotalValue), - "Vault Total Value" + expect(await oethVault.totalValue(), "Vault Total Value").to.equal( + dataBefore.oethTotalValue.add(delta.oethTotalValue) ); - expect(await oethVault.checkBalance(weth.address)).to.equal( - dataBefore.vaultCheckBalance.add(delta.vaultCheckBalance), + expect( + await oethVault.checkBalance(weth.address), "Vault Check Balance of WETH" + ).to.equal(dataBefore.vaultCheckBalance.add(delta.vaultCheckBalance)); + expect(await oeth.balanceOf(user.address), "user's OETH balance").to.equal( + dataBefore.userOeth.add(delta.userOeth) ); - expect(await oeth.balanceOf(user.address)).to.equal( - dataBefore.userOeth.add(delta.userOeth), - "user's OETH balance" + expect(await weth.balanceOf(user.address), "user's WETH balance").to.equal( + dataBefore.userWeth.add(delta.userWeth) ); - expect(await weth.balanceOf(user.address)).to.equal( - dataBefore.userWeth.add(delta.userWeth), - "user's WETH balance" - ); - expect(await weth.balanceOf(oethVault.address)).to.equal( - dataBefore.vaultWeth.add(delta.vaultWeth), + expect( + await weth.balanceOf(oethVault.address), "Vault WETH balance" - ); + ).to.equal(dataBefore.vaultWeth.add(delta.vaultWeth)); const queueAfter = await oethVault.withdrawalQueueMetadata(); - expect(queueAfter.queued).to.equal( + expect(queueAfter.queued, "Queued").to.equal( dataBefore.queue.queued.add(delta.queued) ); - expect(queueAfter.claimable).to.equal( + expect(queueAfter.claimable, "Claimable").to.equal( dataBefore.queue.claimable.add(delta.claimable) ); - expect(queueAfter.claimed).to.equal( + expect(queueAfter.claimed, "Claimed").to.equal( dataBefore.queue.claimed.add(delta.claimed) ); - expect(queueAfter.nextWithdrawalIndex).to.equal( + expect(queueAfter.nextWithdrawalIndex, "nextWithdrawalIndex").to.equal( dataBefore.queue.nextWithdrawalIndex.add(delta.nextWithdrawalIndex) ); }; @@ -473,7 +469,7 @@ describe("OETH Vault", function () { ); }); - it("should fail when burnForStrategy because Amoount too high", async () => { + it("Fail when burnForStrategy because Amoount too high", async () => { const { oethVault, governor, daniel } = fixture; await oethVault.connect(governor).setOusdMetaStrategy(daniel.address); @@ -484,7 +480,7 @@ describe("OETH Vault", function () { await expect(tx).to.be.revertedWith("Amount too high"); }); - it("should fail when burnForStrategy because Attempting to burn too much OUSD.", async () => { + it("Fail when burnForStrategy because Attempting to burn too much OUSD.", async () => { const { oethVault, governor, daniel } = fixture; await oethVault.connect(governor).setOusdMetaStrategy(daniel.address); @@ -496,448 +492,186 @@ describe("OETH Vault", function () { }); }); - describe("with withdrawal queue", () => { - beforeEach(async () => { - const { oethVault, weth, daniel, josh, matt } = fixture; - // Mint some OETH to three users - await oethVault.connect(daniel).mint(weth.address, oethUnits("10"), "0"); - await oethVault.connect(josh).mint(weth.address, oethUnits("20"), "0"); - await oethVault.connect(matt).mint(weth.address, oethUnits("30"), "0"); - await oethVault - .connect(await impersonateAndFund(await oethVault.governor())) - .setMaxSupplyDiff(oethUnits("0.03")); - }); - const firstRequestAmount = oethUnits("5"); - const secondRequestAmount = oethUnits("18"); + describe("Withdrawal Queue", () => { const delayPeriod = 30 * 60; // 30 minutes - it("should request first withdrawal by Daniel", async () => { - const { oethVault, daniel } = fixture; - const fixtureWithUser = { ...fixture, user: daniel }; - const dataBefore = await snapData(fixtureWithUser); - - const tx = await oethVault - .connect(daniel) - .requestWithdrawal(firstRequestAmount); - - await expect(tx) - .to.emit(oethVault, "WithdrawalRequested") - .withArgs(daniel.address, 0, firstRequestAmount, firstRequestAmount); - - await assertChangedData( - dataBefore, - { - oethTotalSupply: firstRequestAmount.mul(-1), - oethTotalValue: firstRequestAmount.mul(-1), - vaultCheckBalance: firstRequestAmount.mul(-1), - userOeth: firstRequestAmount.mul(-1), - userWeth: 0, - vaultWeth: 0, - queued: firstRequestAmount, - claimable: 0, - claimed: 0, - nextWithdrawalIndex: 1, - }, - fixtureWithUser - ); - }); - it("should request withdrawal of zero amount", async () => { - const { oethVault, josh } = fixture; - const fixtureWithUser = { ...fixture, user: josh }; - await oethVault.connect(josh).requestWithdrawal(firstRequestAmount); - const dataBefore = await snapData(fixtureWithUser); - - const tx = await oethVault.connect(josh).requestWithdrawal(0); - - await expect(tx) - .to.emit(oethVault, "WithdrawalRequested") - .withArgs(josh.address, 1, 0, firstRequestAmount); - - await assertChangedData( - dataBefore, - { - oethTotalSupply: 0, - oethTotalValue: 0, - vaultCheckBalance: 0, - userOeth: 0, - userWeth: 0, - vaultWeth: 0, - queued: 0, - claimable: 0, - claimed: 0, - nextWithdrawalIndex: 1, - }, - fixtureWithUser - ); - }); - it("should request first and second withdrawals with no WETH in the Vault", async () => { - const { oethVault, governor, josh, matt, weth } = fixture; - const fixtureWithUser = { ...fixture, user: josh }; - - const mockStrategy = await deployWithConfirmation("MockStrategy"); - await oethVault.connect(governor).approveStrategy(mockStrategy.address); - - // Deposit all 10 + 20 + 30 = 60 WETH to strategy - await oethVault - .connect(governor) - .depositToStrategy( - mockStrategy.address, - [weth.address], - [oethUnits("60")] - ); - - const dataBefore = await snapData(fixtureWithUser); - - await oethVault.connect(josh).requestWithdrawal(firstRequestAmount); - const tx = await oethVault - .connect(matt) - .requestWithdrawal(secondRequestAmount); - - await expect(tx) - .to.emit(oethVault, "WithdrawalRequested") - .withArgs( - matt.address, - 1, - secondRequestAmount, - firstRequestAmount.add(secondRequestAmount) - ); - - await assertChangedData( - dataBefore, - { - oethTotalSupply: firstRequestAmount.add(secondRequestAmount).mul(-1), - oethTotalValue: firstRequestAmount.add(secondRequestAmount).mul(-1), - vaultCheckBalance: firstRequestAmount - .add(secondRequestAmount) - .mul(-1), - userOeth: firstRequestAmount.mul(-1), - userWeth: 0, - vaultWeth: 0, - queued: firstRequestAmount.add(secondRequestAmount), - claimable: 0, - claimed: 0, - nextWithdrawalIndex: 2, - }, - fixtureWithUser - ); - }); - it("should request second withdrawal by matt", async () => { - const { oethVault, daniel, matt } = fixture; - const fixtureWithUser = { ...fixture, user: matt }; - await oethVault.connect(daniel).requestWithdrawal(firstRequestAmount); - const dataBefore = await snapData(fixtureWithUser); - - const tx = await oethVault - .connect(matt) - .requestWithdrawal(secondRequestAmount); - - await expect(tx) - .to.emit(oethVault, "WithdrawalRequested") - .withArgs( - matt.address, - 1, - secondRequestAmount, - firstRequestAmount.add(secondRequestAmount) - ); - - await assertChangedData( - dataBefore, - { - oethTotalSupply: secondRequestAmount.mul(-1), - oethTotalValue: secondRequestAmount.mul(-1), - vaultCheckBalance: secondRequestAmount.mul(-1), - userOeth: secondRequestAmount.mul(-1), - userWeth: 0, - vaultWeth: 0, - queued: secondRequestAmount, - claimable: 0, - claimed: 0, - nextWithdrawalIndex: 1, - }, - fixtureWithUser - ); - }); - it("Should add claimable liquidity to the withdrawal queue", async () => { - const { oethVault, daniel, josh } = fixture; - const fixtureWithUser = { ...fixture, user: josh }; - await oethVault.connect(daniel).requestWithdrawal(firstRequestAmount); - await oethVault.connect(josh).requestWithdrawal(secondRequestAmount); - const dataBefore = await snapData(fixtureWithUser); - - const tx = await oethVault.connect(josh).addWithdrawalQueueLiquidity(); - - await expect(tx) - .to.emit(oethVault, "WithdrawalClaimable") - .withArgs( - firstRequestAmount.add(secondRequestAmount), - firstRequestAmount.add(secondRequestAmount) - ); - - await assertChangedData( - dataBefore, - { - oethTotalSupply: 0, - oethTotalValue: 0, - vaultCheckBalance: 0, - userOeth: 0, - userWeth: 0, - vaultWeth: 0, - queued: 0, - claimable: firstRequestAmount.add(secondRequestAmount), - claimed: 0, - nextWithdrawalIndex: 0, - }, - fixtureWithUser - ); - }); - it("Should claim second request with enough liquidity", async () => { - const { oethVault, daniel, josh } = fixture; - const fixtureWithUser = { ...fixture, user: josh }; - await oethVault.connect(daniel).requestWithdrawal(firstRequestAmount); - await oethVault.connect(josh).requestWithdrawal(secondRequestAmount); - const requestId = 1; // ids start at 0 so the second request is at index 1 - const dataBefore = await snapData(fixtureWithUser); + describe("with all 60 WETH in the vault", () => { + beforeEach(async () => { + const { oethVault, weth, daniel, josh, matt } = fixture; + // Mint some OETH to three users + await oethVault + .connect(daniel) + .mint(weth.address, oethUnits("10"), "0"); + await oethVault.connect(josh).mint(weth.address, oethUnits("20"), "0"); + await oethVault.connect(matt).mint(weth.address, oethUnits("30"), "0"); + await oethVault + .connect(await impersonateAndFund(await oethVault.governor())) + .setMaxSupplyDiff(oethUnits("0.03")); + }); + const firstRequestAmount = oethUnits("5"); + const secondRequestAmount = oethUnits("18"); + it("should request first withdrawal by Daniel", async () => { + const { oethVault, daniel } = fixture; + const fixtureWithUser = { ...fixture, user: daniel }; + const dataBefore = await snapData(fixtureWithUser); - await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. + const tx = await oethVault + .connect(daniel) + .requestWithdrawal(firstRequestAmount); - const tx = await oethVault.connect(josh).claimWithdrawal(requestId); + await expect(tx) + .to.emit(oethVault, "WithdrawalRequested") + .withArgs(daniel.address, 0, firstRequestAmount, firstRequestAmount); - await expect(tx) - .to.emit(oethVault, "WithdrawalClaimed") - .withArgs(josh.address, requestId, secondRequestAmount); - await expect(tx) - .to.emit(oethVault, "WithdrawalClaimable") - .withArgs( - firstRequestAmount.add(secondRequestAmount), - firstRequestAmount.add(secondRequestAmount) + await assertChangedData( + dataBefore, + { + oethTotalSupply: firstRequestAmount.mul(-1), + oethTotalValue: firstRequestAmount.mul(-1), + vaultCheckBalance: firstRequestAmount.mul(-1), + userOeth: firstRequestAmount.mul(-1), + userWeth: 0, + vaultWeth: 0, + queued: firstRequestAmount, + claimable: 0, + claimed: 0, + nextWithdrawalIndex: 1, + }, + fixtureWithUser ); + }); + it("should request withdrawal of zero amount", async () => { + const { oethVault, josh } = fixture; + const fixtureWithUser = { ...fixture, user: josh }; + await oethVault.connect(josh).requestWithdrawal(firstRequestAmount); + const dataBefore = await snapData(fixtureWithUser); - await assertChangedData( - dataBefore, - { - oethTotalSupply: 0, - oethTotalValue: 0, - vaultCheckBalance: 0, - userOeth: 0, - userWeth: secondRequestAmount, - vaultWeth: secondRequestAmount.mul(-1), - queued: 0, - claimable: firstRequestAmount.add(secondRequestAmount), - claimed: secondRequestAmount, - nextWithdrawalIndex: 0, - }, - fixtureWithUser - ); - }); - it("Should claim multiple requests with enough liquidity", async () => { - const { oethVault, matt } = fixture; - const fixtureWithUser = { ...fixture, user: matt }; - await oethVault.connect(matt).requestWithdrawal(firstRequestAmount); - await oethVault.connect(matt).requestWithdrawal(secondRequestAmount); - const dataBefore = await snapData(fixtureWithUser); - - await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. + const tx = await oethVault.connect(josh).requestWithdrawal(0); - const tx = await oethVault.connect(matt).claimWithdrawals([0, 1]); + await expect(tx) + .to.emit(oethVault, "WithdrawalRequested") + .withArgs(josh.address, 1, 0, firstRequestAmount); - await expect(tx) - .to.emit(oethVault, "WithdrawalClaimed") - .withArgs(matt.address, 0, firstRequestAmount); - await expect(tx) - .to.emit(oethVault, "WithdrawalClaimed") - .withArgs(matt.address, 1, secondRequestAmount); - await expect(tx) - .to.emit(oethVault, "WithdrawalClaimable") - .withArgs( - firstRequestAmount.add(secondRequestAmount), - firstRequestAmount.add(secondRequestAmount) + await assertChangedData( + dataBefore, + { + oethTotalSupply: 0, + oethTotalValue: 0, + vaultCheckBalance: 0, + userOeth: 0, + userWeth: 0, + vaultWeth: 0, + queued: 0, + claimable: 0, + claimed: 0, + nextWithdrawalIndex: 1, + }, + fixtureWithUser ); + }); + it("should request first and second withdrawals with no WETH in the Vault", async () => { + const { oethVault, governor, josh, matt, weth } = fixture; + const fixtureWithUser = { ...fixture, user: josh }; - await assertChangedData( - dataBefore, - { - oethTotalSupply: 0, - oethTotalValue: 0, - vaultCheckBalance: 0, - userOeth: 0, - userWeth: firstRequestAmount.add(secondRequestAmount), - vaultWeth: firstRequestAmount.add(secondRequestAmount).mul(-1), - queued: 0, - claimable: firstRequestAmount.add(secondRequestAmount), - claimed: firstRequestAmount.add(secondRequestAmount), - nextWithdrawalIndex: 0, - }, - fixtureWithUser - ); - }); - it("Should claim single big request as a whale", async () => { - const { oethVault, oeth, matt } = fixture; - - const oethBalanceBefore = await oeth.balanceOf(matt.address); - const totalValueBefore = await oethVault.totalValue(); - - await oethVault.connect(matt).requestWithdrawal(oethUnits("30")); - - const oethBalanceAfter = await oeth.balanceOf(matt.address); - const totalValueAfter = await oethVault.totalValue(); - await expect(oethBalanceBefore).to.equal(oethUnits("30")); - await expect(oethBalanceAfter).to.equal(oethUnits("0")); - await expect(totalValueBefore.sub(totalValueAfter)).to.equal( - oethUnits("30") - ); - - const oethTotalSupply = await oeth.totalSupply(); - await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. - const tx = await oethVault.connect(matt).claimWithdrawal(0); // Claim withdrawal for 50% of the supply - - await expect(tx) - .to.emit(oethVault, "WithdrawalClaimed") - .withArgs(matt.address, 0, oethUnits("30")); - - await expect(oethTotalSupply).to.equal(await oeth.totalSupply()); - await expect(totalValueAfter).to.equal(await oethVault.totalValue()); - }); - - it("Should fail claim request because of not enough time passed", async () => { - const { oethVault, daniel } = fixture; - - // Daniel requests 5 OETH to be withdrawn - await oethVault.connect(daniel).requestWithdrawal(firstRequestAmount); - const requestId = 0; - - // Daniel claimWithdraw request in the same block as the request - const tx = oethVault.connect(daniel).claimWithdrawal(requestId); - - await expect(tx).to.revertedWith("Claim delay not met"); - }); - it("Should fail request withdrawal because of solvency check too high", async () => { - const { oethVault, daniel, weth } = fixture; - - await weth.connect(daniel).transfer(oethVault.address, oethUnits("10")); - - const tx = oethVault - .connect(daniel) - .requestWithdrawal(firstRequestAmount); - - await expect(tx).to.revertedWith("Backing supply liquidity error"); - }); - it("Should fail claim request because of solvency check too high", async () => { - const { oethVault, daniel, weth } = fixture; - - // Request withdrawal of 5 OETH - await oethVault.connect(daniel).requestWithdrawal(firstRequestAmount); - - // Transfer 10 WETH to the vault - await weth.connect(daniel).transfer(oethVault.address, oethUnits("10")); - - await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. - - // Claim the withdrawal - const tx = oethVault.connect(daniel).claimWithdrawal(0); - - await expect(tx).to.revertedWith("Backing supply liquidity error"); - }); - it("Should fail multiple claim requests because of solvency check too high", async () => { - const { oethVault, matt, weth } = fixture; - - // Request withdrawal of 5 OETH - await oethVault.connect(matt).requestWithdrawal(firstRequestAmount); - await oethVault.connect(matt).requestWithdrawal(secondRequestAmount); - - // Transfer 10 WETH to the vault - await weth.connect(matt).transfer(oethVault.address, oethUnits("10")); - - await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. - - // Claim the withdrawal - const tx = oethVault.connect(matt).claimWithdrawals([0, 1]); - - await expect(tx).to.revertedWith("Backing supply liquidity error"); - }); - - it("Should fail request withdrawal because of solvency check too low", async () => { - const { oethVault, daniel, weth } = fixture; - - // Simulate a loss of funds from the vault - await weth - .connect(await impersonateAndFund(oethVault.address)) - .transfer(daniel.address, oethUnits("10")); - - const tx = oethVault - .connect(daniel) - .requestWithdrawal(firstRequestAmount); - - await expect(tx).to.revertedWith("Backing supply liquidity error"); - }); - - describe("when deposit some WETH to a strategy", () => { - let mockStrategy; - beforeEach(async () => { - const { oethVault, weth, governor, daniel, josh } = fixture; - - const dMockStrategy = await deployWithConfirmation("MockStrategy"); - mockStrategy = await ethers.getContractAt( - "MockStrategy", - dMockStrategy.address - ); - await mockStrategy.setWithdrawAll(weth.address, oethVault.address); + const mockStrategy = await deployWithConfirmation("MockStrategy"); await oethVault.connect(governor).approveStrategy(mockStrategy.address); - // Deposit 15 WETH of 10 + 20 + 30 = 60 WETH to strategy - // This leave 60 - 15 = 45 WETH in the vault + // Deposit all 10 + 20 + 30 = 60 WETH to strategy await oethVault .connect(governor) .depositToStrategy( mockStrategy.address, [weth.address], - [oethUnits("15")] + [oethUnits("60")] ); - // Request withdrawal of 5 + 18 = 23 OETH - // This leave 45 - 23 = 22 WETH unallocated to the withdrawal queue - await oethVault.connect(daniel).requestWithdrawal(firstRequestAmount); - await oethVault.connect(josh).requestWithdrawal(secondRequestAmount); - }); - it("Should not deposit allocated WETH to a strategy", async () => { - const { oethVault, weth, governor } = fixture; - // WETH in the vault = 60 - 15 = 45 WETH - // unallocated WETH in the Vault = 45 - 23 = 22 WETH - // 23 WETH to deposit > the 22 WETH available so it should revert - const depositAmount = oethUnits("23"); - const tx = oethVault - .connect(governor) - .depositToStrategy( - mockStrategy.address, - [weth.address], - [depositAmount] + const dataBefore = await snapData(fixtureWithUser); + + await oethVault.connect(josh).requestWithdrawal(firstRequestAmount); + const tx = await oethVault + .connect(matt) + .requestWithdrawal(secondRequestAmount); + + await expect(tx) + .to.emit(oethVault, "WithdrawalRequested") + .withArgs( + matt.address, + 1, + secondRequestAmount, + firstRequestAmount.add(secondRequestAmount) ); - await expect(tx).to.be.revertedWith("Not enough WETH available"); + + await assertChangedData( + dataBefore, + { + oethTotalSupply: firstRequestAmount + .add(secondRequestAmount) + .mul(-1), + oethTotalValue: firstRequestAmount.add(secondRequestAmount).mul(-1), + vaultCheckBalance: firstRequestAmount + .add(secondRequestAmount) + .mul(-1), + userOeth: firstRequestAmount.mul(-1), + userWeth: 0, + vaultWeth: 0, + queued: firstRequestAmount.add(secondRequestAmount), + claimable: 0, + claimed: 0, + nextWithdrawalIndex: 2, + }, + fixtureWithUser + ); }); - it("Should deposit unallocated WETH to a strategy", async () => { - const { oethVault, weth, governor } = fixture; + it("should request second withdrawal by matt", async () => { + const { oethVault, daniel, matt } = fixture; + const fixtureWithUser = { ...fixture, user: matt }; + await oethVault.connect(daniel).requestWithdrawal(firstRequestAmount); + const dataBefore = await snapData(fixtureWithUser); - // WETH in the vault = 60 - 15 = 45 WETH - // unallocated WETH in the Vault = 45 - 23 = 22 WETH - const depositAmount = oethUnits("22"); - await oethVault - .connect(governor) - .depositToStrategy( - mockStrategy.address, - [weth.address], - [depositAmount] + const tx = await oethVault + .connect(matt) + .requestWithdrawal(secondRequestAmount); + + await expect(tx) + .to.emit(oethVault, "WithdrawalRequested") + .withArgs( + matt.address, + 1, + secondRequestAmount, + firstRequestAmount.add(secondRequestAmount) ); + + await assertChangedData( + dataBefore, + { + oethTotalSupply: secondRequestAmount.mul(-1), + oethTotalValue: secondRequestAmount.mul(-1), + vaultCheckBalance: secondRequestAmount.mul(-1), + userOeth: secondRequestAmount.mul(-1), + userWeth: 0, + vaultWeth: 0, + queued: secondRequestAmount, + claimable: 0, + claimed: 0, + nextWithdrawalIndex: 1, + }, + fixtureWithUser + ); }); - it("Should claim first request with enough liquidity", async () => { - const { oethVault, daniel } = fixture; - const fixtureWithUser = { ...fixture, user: daniel }; + it("Should add claimable liquidity to the withdrawal queue", async () => { + const { oethVault, daniel, josh } = fixture; + const fixtureWithUser = { ...fixture, user: josh }; + await oethVault.connect(daniel).requestWithdrawal(firstRequestAmount); + await oethVault.connect(josh).requestWithdrawal(secondRequestAmount); const dataBefore = await snapData(fixtureWithUser); - await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. - - const tx = await oethVault.connect(daniel).claimWithdrawal(0); + const tx = await oethVault.connect(josh).addWithdrawalQueueLiquidity(); await expect(tx) - .to.emit(oethVault, "WithdrawalClaimed") - .withArgs(daniel.address, 0, firstRequestAmount); + .to.emit(oethVault, "WithdrawalClaimable") + .withArgs( + firstRequestAmount.add(secondRequestAmount), + firstRequestAmount.add(secondRequestAmount) + ); await assertChangedData( dataBefore, @@ -946,38 +680,37 @@ describe("OETH Vault", function () { oethTotalValue: 0, vaultCheckBalance: 0, userOeth: 0, - userWeth: firstRequestAmount, - vaultWeth: firstRequestAmount.mul(-1), + userWeth: 0, + vaultWeth: 0, queued: 0, claimable: firstRequestAmount.add(secondRequestAmount), - claimed: firstRequestAmount, + claimed: 0, nextWithdrawalIndex: 0, }, fixtureWithUser ); }); - it("Should claim a new request with enough WETH liquidity", async () => { - const { oethVault, matt } = fixture; - const fixtureWithUser = { ...fixture, user: matt }; - - // Set the claimable amount to the queued amount - await oethVault.addWithdrawalQueueLiquidity(); - - // WETH in the vault = 60 - 15 = 45 WETH - // unallocated WETH in the Vault = 45 - 23 = 22 WETH - // Matt request all unallocated WETH to be withdrawn - const requestAmount = oethUnits("22"); - await oethVault.connect(matt).requestWithdrawal(requestAmount); - + it("Should claim second request with enough liquidity", async () => { + const { oethVault, daniel, josh } = fixture; + const fixtureWithUser = { ...fixture, user: josh }; + await oethVault.connect(daniel).requestWithdrawal(firstRequestAmount); + await oethVault.connect(josh).requestWithdrawal(secondRequestAmount); + const requestId = 1; // ids start at 0 so the second request is at index 1 const dataBefore = await snapData(fixtureWithUser); await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. - const tx = await oethVault.connect(matt).claimWithdrawal(2); + const tx = await oethVault.connect(josh).claimWithdrawal(requestId); await expect(tx) .to.emit(oethVault, "WithdrawalClaimed") - .withArgs(matt.address, 2, requestAmount); + .withArgs(josh.address, requestId, secondRequestAmount); + await expect(tx) + .to.emit(oethVault, "WithdrawalClaimable") + .withArgs( + firstRequestAmount.add(secondRequestAmount), + firstRequestAmount.add(secondRequestAmount) + ); await assertChangedData( dataBefore, @@ -986,241 +719,717 @@ describe("OETH Vault", function () { oethTotalValue: 0, vaultCheckBalance: 0, userOeth: 0, - userWeth: requestAmount, - vaultWeth: requestAmount.mul(-1), + userWeth: secondRequestAmount, + vaultWeth: secondRequestAmount.mul(-1), queued: 0, - claimable: requestAmount, - claimed: requestAmount, + claimable: firstRequestAmount.add(secondRequestAmount), + claimed: secondRequestAmount, nextWithdrawalIndex: 0, }, fixtureWithUser ); }); - it("Should fail to claim a new request with NOT enough WETH liquidity", async () => { + it("Should claim multiple requests with enough liquidity", async () => { const { oethVault, matt } = fixture; - - // Matt request 23 OETH to be withdrawn when only 22 WETH is unallocated to existing requests - const requestAmount = oethUnits("23"); - await oethVault.connect(matt).requestWithdrawal(requestAmount); + const fixtureWithUser = { ...fixture, user: matt }; + await oethVault.connect(matt).requestWithdrawal(firstRequestAmount); + await oethVault.connect(matt).requestWithdrawal(secondRequestAmount); + const dataBefore = await snapData(fixtureWithUser); await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. - const tx = oethVault.connect(matt).claimWithdrawal(2); - await expect(tx).to.be.revertedWith("Queue pending liquidity"); - }); - it("Should claim a new request after withdraw from strategy adds enough liquidity", async () => { - const { oethVault, daniel, matt, strategist, weth } = fixture; - - // Set the claimable amount to the queued amount - await oethVault.addWithdrawalQueueLiquidity(); - - // Matt requests all 30 OETH to be withdrawn which is currently 8 WETH short - const requestAmount = oethUnits("30"); - await oethVault.connect(matt).requestWithdrawal(requestAmount); + const tx = await oethVault.connect(matt).claimWithdrawals([0, 1]); - const fixtureWithUser = { ...fixture, user: daniel }; - const dataBeforeMint = await snapData(fixtureWithUser); - - // WETH in the vault = 60 - 15 = 45 WETH - // unallocated WETH in the Vault = 45 - 23 = 22 WETH - // Add another 8 WETH so the unallocated WETH is 22 + 8 = 30 WETH - const withdrawAmount = oethUnits("8"); - await oethVault - .connect(strategist) - .withdrawFromStrategy( - mockStrategy.address, - [weth.address], - [withdrawAmount] + await expect(tx) + .to.emit(oethVault, "WithdrawalClaimed") + .withArgs(matt.address, 0, firstRequestAmount); + await expect(tx) + .to.emit(oethVault, "WithdrawalClaimed") + .withArgs(matt.address, 1, secondRequestAmount); + await expect(tx) + .to.emit(oethVault, "WithdrawalClaimable") + .withArgs( + firstRequestAmount.add(secondRequestAmount), + firstRequestAmount.add(secondRequestAmount) ); await assertChangedData( - dataBeforeMint, + dataBefore, { oethTotalSupply: 0, oethTotalValue: 0, vaultCheckBalance: 0, userOeth: 0, - userWeth: 0, - vaultWeth: withdrawAmount, + userWeth: firstRequestAmount.add(secondRequestAmount), + vaultWeth: firstRequestAmount.add(secondRequestAmount).mul(-1), queued: 0, - claimable: requestAmount, - claimed: 0, + claimable: firstRequestAmount.add(secondRequestAmount), + claimed: firstRequestAmount.add(secondRequestAmount), nextWithdrawalIndex: 0, }, fixtureWithUser ); + }); + it("Should claim single big request as a whale", async () => { + const { oethVault, oeth, matt } = fixture; + + const oethBalanceBefore = await oeth.balanceOf(matt.address); + const totalValueBefore = await oethVault.totalValue(); + await oethVault.connect(matt).requestWithdrawal(oethUnits("30")); + + const oethBalanceAfter = await oeth.balanceOf(matt.address); + const totalValueAfter = await oethVault.totalValue(); + await expect(oethBalanceBefore).to.equal(oethUnits("30")); + await expect(oethBalanceAfter).to.equal(oethUnits("0")); + await expect(totalValueBefore.sub(totalValueAfter)).to.equal( + oethUnits("30") + ); + + const oethTotalSupply = await oeth.totalSupply(); await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. + const tx = await oethVault.connect(matt).claimWithdrawal(0); // Claim withdrawal for 50% of the supply + + await expect(tx) + .to.emit(oethVault, "WithdrawalClaimed") + .withArgs(matt.address, 0, oethUnits("30")); - await oethVault.connect(matt).claimWithdrawal(2); + await expect(oethTotalSupply).to.equal(await oeth.totalSupply()); + await expect(totalValueAfter).to.equal(await oethVault.totalValue()); }); - it("Should claim a new request after withdrawAllFromStrategy adds enough liquidity", async () => { - const { oethVault, daniel, matt, strategist, weth } = fixture; - // Set the claimable amount to the queued amount - await oethVault.addWithdrawalQueueLiquidity(); + it("Fail to claim request because of not enough time passed", async () => { + const { oethVault, daniel } = fixture; - // Matt requests all 30 OETH to be withdrawn which is currently 8 WETH short - const requestAmount = oethUnits("30"); - await oethVault.connect(matt).requestWithdrawal(requestAmount); + // Daniel requests 5 OETH to be withdrawn + await oethVault.connect(daniel).requestWithdrawal(firstRequestAmount); + const requestId = 0; - const fixtureWithUser = { ...fixture, user: daniel }; - const dataBeforeMint = await snapData(fixtureWithUser); - const strategyBalanceBefore = await weth.balanceOf( - mockStrategy.address - ); + // Daniel claimWithdraw request in the same block as the request + const tx = oethVault.connect(daniel).claimWithdrawal(requestId); - // WETH in the vault = 60 - 15 = 45 WETH - // unallocated WETH in the Vault = 45 - 23 = 22 WETH - // Add another 8 WETH so the unallocated WETH is 22 + 8 = 30 WETH - await oethVault - .connect(strategist) - .withdrawAllFromStrategy(mockStrategy.address); + await expect(tx).to.revertedWith("Claim delay not met"); + }); + it("Fail to request withdrawal because of solvency check too high", async () => { + const { oethVault, daniel, weth } = fixture; - await assertChangedData( - dataBeforeMint, - { - oethTotalSupply: 0, - oethTotalValue: 0, - vaultCheckBalance: 0, - userOeth: 0, - userWeth: 0, - vaultWeth: strategyBalanceBefore, - queued: 0, - claimable: requestAmount, - claimed: 0, - nextWithdrawalIndex: 0, - }, - fixtureWithUser - ); + await weth.connect(daniel).transfer(oethVault.address, oethUnits("10")); - await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. + const tx = oethVault + .connect(daniel) + .requestWithdrawal(firstRequestAmount); - await oethVault.connect(matt).claimWithdrawal(2); + await expect(tx).to.revertedWith("Backing supply liquidity error"); }); - it("Should claim a new request after withdrawAll from strategies adds enough liquidity", async () => { - const { oethVault, daniel, matt, strategist, weth } = fixture; + it("Fail to claim request because of solvency check too high", async () => { + const { oethVault, daniel, weth } = fixture; - // Set the claimable amount to the queued amount - await oethVault.addWithdrawalQueueLiquidity(); + // Request withdrawal of 5 OETH + await oethVault.connect(daniel).requestWithdrawal(firstRequestAmount); - // Matt requests all 30 OETH to be withdrawn which is currently 8 WETH short - const requestAmount = oethUnits("30"); - await oethVault.connect(matt).requestWithdrawal(requestAmount); + // Transfer 10 WETH to the vault + await weth.connect(daniel).transfer(oethVault.address, oethUnits("10")); - const fixtureWithUser = { ...fixture, user: daniel }; - const dataBeforeMint = await snapData(fixtureWithUser); - const strategyBalanceBefore = await weth.balanceOf( - mockStrategy.address - ); + await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. - // WETH in the vault = 60 - 15 = 45 WETH - // unallocated WETH in the Vault = 45 - 23 = 22 WETH - // Add another 8 WETH so the unallocated WETH is 22 + 8 = 30 WETH - await oethVault.connect(strategist).withdrawAllFromStrategies(); + // Claim the withdrawal + const tx = oethVault.connect(daniel).claimWithdrawal(0); - await assertChangedData( - dataBeforeMint, - { - oethTotalSupply: 0, - oethTotalValue: 0, - vaultCheckBalance: 0, - userOeth: 0, - userWeth: 0, - vaultWeth: strategyBalanceBefore, - queued: 0, - claimable: requestAmount, - claimed: 0, - nextWithdrawalIndex: 0, - }, - fixtureWithUser - ); + await expect(tx).to.revertedWith("Backing supply liquidity error"); + }); + it("Fail multiple claim requests because of solvency check too high", async () => { + const { oethVault, matt, weth } = fixture; + + // Request withdrawal of 5 OETH + await oethVault.connect(matt).requestWithdrawal(firstRequestAmount); + await oethVault.connect(matt).requestWithdrawal(secondRequestAmount); + + // Transfer 10 WETH to the vault + await weth.connect(matt).transfer(oethVault.address, oethUnits("10")); await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. - await oethVault.connect(matt).claimWithdrawal(2); + // Claim the withdrawal + const tx = oethVault.connect(matt).claimWithdrawals([0, 1]); + + await expect(tx).to.revertedWith("Backing supply liquidity error"); }); - it("Should fail to claim a new request after mint with NOT enough liquidity", async () => { - const { oethVault, daniel, matt, weth } = fixture; - // Matt requests all 30 OETH to be withdrawn which is not enough liquidity - const requestAmount = oethUnits("30"); - await oethVault.connect(matt).requestWithdrawal(requestAmount); + it("Fail request withdrawal because of solvency check too low", async () => { + const { oethVault, daniel, weth } = fixture; - // WETH in the vault = 60 - 15 = 45 WETH - // unallocated WETH in the Vault = 45 - 23 = 22 WETH - // Add another 6 WETH so the unallocated WETH is 22 + 6 = 28 WETH - await oethVault.connect(daniel).mint(weth.address, oethUnits("6"), 0); + // Simulate a loss of funds from the vault + await weth + .connect(await impersonateAndFund(oethVault.address)) + .transfer(daniel.address, oethUnits("10")); - await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. + const tx = oethVault + .connect(daniel) + .requestWithdrawal(firstRequestAmount); - const tx = oethVault.connect(matt).claimWithdrawal(2); - await expect(tx).to.be.revertedWith("Queue pending liquidity"); + await expect(tx).to.revertedWith("Backing supply liquidity error"); }); - it("Should claim a new request after mint adds enough liquidity", async () => { - const { oethVault, daniel, matt, weth } = fixture; - // Set the claimable amount to the queued amount - await oethVault.addWithdrawalQueueLiquidity(); + describe("when deposit 15 WETH to a strategy, leaving 60 - 15 = 45 WETH in the vault; request withdrawal of 5 + 18 = 23 OETH, leaving 45 - 23 = 22 WETH unallocated", () => { + let mockStrategy; + beforeEach(async () => { + const { oethVault, weth, governor, daniel, josh } = fixture; - // Matt requests all 30 OETH to be withdrawn which is currently 8 WETH short - const requestAmount = oethUnits("30"); - await oethVault.connect(matt).requestWithdrawal(requestAmount); + const dMockStrategy = await deployWithConfirmation("MockStrategy"); + mockStrategy = await ethers.getContractAt( + "MockStrategy", + dMockStrategy.address + ); + await mockStrategy.setWithdrawAll(weth.address, oethVault.address); + await oethVault + .connect(governor) + .approveStrategy(mockStrategy.address); + + // Deposit 15 WETH of 10 + 20 + 30 = 60 WETH to strategy + // This leave 60 - 15 = 45 WETH in the vault + await oethVault + .connect(governor) + .depositToStrategy( + mockStrategy.address, + [weth.address], + [oethUnits("15")] + ); + // Request withdrawal of 5 + 18 = 23 OETH + // This leave 45 - 23 = 22 WETH unallocated to the withdrawal queue + await oethVault.connect(daniel).requestWithdrawal(firstRequestAmount); + await oethVault.connect(josh).requestWithdrawal(secondRequestAmount); + }); + it("Should not deposit allocated WETH to a strategy", async () => { + const { oethVault, weth, governor } = fixture; + + // WETH in the vault = 60 - 15 = 45 WETH + // unallocated WETH in the Vault = 45 - 23 = 22 WETH + // 23 WETH to deposit > the 22 WETH available so it should revert + const depositAmount = oethUnits("23"); + const tx = oethVault + .connect(governor) + .depositToStrategy( + mockStrategy.address, + [weth.address], + [depositAmount] + ); + await expect(tx).to.be.revertedWith("Not enough WETH available"); + }); + it("Should deposit unallocated WETH to a strategy", async () => { + const { oethVault, weth, governor } = fixture; + + // WETH in the vault = 60 - 15 = 45 WETH + // unallocated WETH in the Vault = 45 - 23 = 22 WETH + const depositAmount = oethUnits("22"); + await oethVault + .connect(governor) + .depositToStrategy( + mockStrategy.address, + [weth.address], + [depositAmount] + ); + }); + it("Should claim first request with enough liquidity", async () => { + const { oethVault, daniel } = fixture; + const fixtureWithUser = { ...fixture, user: daniel }; + const dataBefore = await snapData(fixtureWithUser); + + await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. + + const tx = await oethVault.connect(daniel).claimWithdrawal(0); + + await expect(tx) + .to.emit(oethVault, "WithdrawalClaimed") + .withArgs(daniel.address, 0, firstRequestAmount); + + await assertChangedData( + dataBefore, + { + oethTotalSupply: 0, + oethTotalValue: 0, + vaultCheckBalance: 0, + userOeth: 0, + userWeth: firstRequestAmount, + vaultWeth: firstRequestAmount.mul(-1), + queued: 0, + claimable: firstRequestAmount.add(secondRequestAmount), + claimed: firstRequestAmount, + nextWithdrawalIndex: 0, + }, + fixtureWithUser + ); + }); + it("Should claim a new request with enough WETH liquidity", async () => { + const { oethVault, matt } = fixture; + const fixtureWithUser = { ...fixture, user: matt }; + + // Set the claimable amount to the queued amount + await oethVault.addWithdrawalQueueLiquidity(); + + // WETH in the vault = 60 - 15 = 45 WETH + // unallocated WETH in the Vault = 45 - 23 = 22 WETH + // Matt request all unallocated WETH to be withdrawn + const requestAmount = oethUnits("22"); + await oethVault.connect(matt).requestWithdrawal(requestAmount); + + const dataBefore = await snapData(fixtureWithUser); + + await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. + + const tx = await oethVault.connect(matt).claimWithdrawal(2); + + await expect(tx) + .to.emit(oethVault, "WithdrawalClaimed") + .withArgs(matt.address, 2, requestAmount); + + await assertChangedData( + dataBefore, + { + oethTotalSupply: 0, + oethTotalValue: 0, + vaultCheckBalance: 0, + userOeth: 0, + userWeth: requestAmount, + vaultWeth: requestAmount.mul(-1), + queued: 0, + claimable: requestAmount, + claimed: requestAmount, + nextWithdrawalIndex: 0, + }, + fixtureWithUser + ); + }); + it("Fail to claim a new request with NOT enough WETH liquidity", async () => { + const { oethVault, matt } = fixture; + + // Matt request 23 OETH to be withdrawn when only 22 WETH is unallocated to existing requests + const requestAmount = oethUnits("23"); + await oethVault.connect(matt).requestWithdrawal(requestAmount); + + await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. + + const tx = oethVault.connect(matt).claimWithdrawal(2); + await expect(tx).to.be.revertedWith("Queue pending liquidity"); + }); + it("Should claim a new request after withdraw from strategy adds enough liquidity", async () => { + const { oethVault, daniel, matt, strategist, weth } = fixture; + + // Set the claimable amount to the queued amount + await oethVault.addWithdrawalQueueLiquidity(); + + // Matt requests all 30 OETH to be withdrawn which is currently 8 WETH short + const requestAmount = oethUnits("30"); + await oethVault.connect(matt).requestWithdrawal(requestAmount); + + const fixtureWithUser = { ...fixture, user: daniel }; + const dataBeforeMint = await snapData(fixtureWithUser); + + // WETH in the vault = 60 - 15 = 45 WETH + // unallocated WETH in the Vault = 45 - 23 = 22 WETH + // Add another 8 WETH so the unallocated WETH is 22 + 8 = 30 WETH + const withdrawAmount = oethUnits("8"); + await oethVault + .connect(strategist) + .withdrawFromStrategy( + mockStrategy.address, + [weth.address], + [withdrawAmount] + ); + + await assertChangedData( + dataBeforeMint, + { + oethTotalSupply: 0, + oethTotalValue: 0, + vaultCheckBalance: 0, + userOeth: 0, + userWeth: 0, + vaultWeth: withdrawAmount, + queued: 0, + claimable: requestAmount, + claimed: 0, + nextWithdrawalIndex: 0, + }, + fixtureWithUser + ); - const fixtureWithUser = { ...fixture, user: daniel }; - const dataBeforeMint = await snapData(fixtureWithUser); + await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. - // WETH in the vault = 60 - 15 = 45 WETH - // unallocated WETH in the Vault = 45 - 23 = 22 WETH - // Add another 8 WETH so the unallocated WETH is 22 + 8 = 30 WETH - const mintAmount = oethUnits("8"); - await oethVault.connect(daniel).mint(weth.address, mintAmount, 0); + await oethVault.connect(matt).claimWithdrawal(2); + }); + it("Should claim a new request after withdrawAllFromStrategy adds enough liquidity", async () => { + const { oethVault, daniel, matt, strategist, weth } = fixture; - await assertChangedData( - dataBeforeMint, - { - oethTotalSupply: mintAmount, - oethTotalValue: mintAmount, - vaultCheckBalance: mintAmount, - userOeth: mintAmount, - userWeth: mintAmount.mul(-1), - vaultWeth: mintAmount, - queued: 0, - claimable: requestAmount, - claimed: 0, - nextWithdrawalIndex: 0, - }, - fixtureWithUser - ); + // Set the claimable amount to the queued amount + await oethVault.addWithdrawalQueueLiquidity(); - await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. + // Matt requests all 30 OETH to be withdrawn which is currently 8 WETH short + const requestAmount = oethUnits("30"); + await oethVault.connect(matt).requestWithdrawal(requestAmount); + + const fixtureWithUser = { ...fixture, user: daniel }; + const dataBeforeMint = await snapData(fixtureWithUser); + const strategyBalanceBefore = await weth.balanceOf( + mockStrategy.address + ); + + // WETH in the vault = 60 - 15 = 45 WETH + // unallocated WETH in the Vault = 45 - 23 = 22 WETH + // Add another 8 WETH so the unallocated WETH is 22 + 8 = 30 WETH + await oethVault + .connect(strategist) + .withdrawAllFromStrategy(mockStrategy.address); + + await assertChangedData( + dataBeforeMint, + { + oethTotalSupply: 0, + oethTotalValue: 0, + vaultCheckBalance: 0, + userOeth: 0, + userWeth: 0, + vaultWeth: strategyBalanceBefore, + queued: 0, + claimable: requestAmount, + claimed: 0, + nextWithdrawalIndex: 0, + }, + fixtureWithUser + ); + + await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. - await oethVault.connect(matt).claimWithdrawal(2); + await oethVault.connect(matt).claimWithdrawal(2); + }); + it("Should claim a new request after withdrawAll from strategies adds enough liquidity", async () => { + const { oethVault, daniel, matt, strategist, weth } = fixture; + + // Set the claimable amount to the queued amount + await oethVault.addWithdrawalQueueLiquidity(); + + // Matt requests all 30 OETH to be withdrawn which is currently 8 WETH short + const requestAmount = oethUnits("30"); + await oethVault.connect(matt).requestWithdrawal(requestAmount); + + const fixtureWithUser = { ...fixture, user: daniel }; + const dataBeforeMint = await snapData(fixtureWithUser); + const strategyBalanceBefore = await weth.balanceOf( + mockStrategy.address + ); + + // WETH in the vault = 60 - 15 = 45 WETH + // unallocated WETH in the Vault = 45 - 23 = 22 WETH + // Add another 8 WETH so the unallocated WETH is 22 + 8 = 30 WETH + await oethVault.connect(strategist).withdrawAllFromStrategies(); + + await assertChangedData( + dataBeforeMint, + { + oethTotalSupply: 0, + oethTotalValue: 0, + vaultCheckBalance: 0, + userOeth: 0, + userWeth: 0, + vaultWeth: strategyBalanceBefore, + queued: 0, + claimable: requestAmount, + claimed: 0, + nextWithdrawalIndex: 0, + }, + fixtureWithUser + ); + + await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. + + await oethVault.connect(matt).claimWithdrawal(2); + }); + it("Fail to claim a new request after mint with NOT enough liquidity", async () => { + const { oethVault, daniel, matt, weth } = fixture; + + // Matt requests all 30 OETH to be withdrawn which is not enough liquidity + const requestAmount = oethUnits("30"); + await oethVault.connect(matt).requestWithdrawal(requestAmount); + + // WETH in the vault = 60 - 15 = 45 WETH + // unallocated WETH in the Vault = 45 - 23 = 22 WETH + // Add another 6 WETH so the unallocated WETH is 22 + 6 = 28 WETH + await oethVault.connect(daniel).mint(weth.address, oethUnits("6"), 0); + + await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. + + const tx = oethVault.connect(matt).claimWithdrawal(2); + await expect(tx).to.be.revertedWith("Queue pending liquidity"); + }); + it("Should claim a new request after mint adds enough liquidity", async () => { + const { oethVault, daniel, matt, weth } = fixture; + + // Set the claimable amount to the queued amount + await oethVault.addWithdrawalQueueLiquidity(); + + // Matt requests all 30 OETH to be withdrawn which is currently 8 WETH short + const requestAmount = oethUnits("30"); + await oethVault.connect(matt).requestWithdrawal(requestAmount); + + const fixtureWithUser = { ...fixture, user: daniel }; + const dataBeforeMint = await snapData(fixtureWithUser); + + // WETH in the vault = 60 - 15 = 45 WETH + // unallocated WETH in the Vault = 45 - 23 = 22 WETH + // Add another 8 WETH so the unallocated WETH is 22 + 8 = 30 WETH + const mintAmount = oethUnits("8"); + await oethVault.connect(daniel).mint(weth.address, mintAmount, 0); + + await assertChangedData( + dataBeforeMint, + { + oethTotalSupply: mintAmount, + oethTotalValue: mintAmount, + vaultCheckBalance: mintAmount, + userOeth: mintAmount, + userWeth: mintAmount.mul(-1), + vaultWeth: mintAmount, + queued: 0, + claimable: requestAmount, + claimed: 0, + nextWithdrawalIndex: 0, + }, + fixtureWithUser + ); + + await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. + + await oethVault.connect(matt).claimWithdrawal(2); + }); + }); + + describe("Fail when", () => { + it("request doesn't have enough OETH", async () => { + const { oethVault, josh } = fixture; + const fixtureWithUser = { ...fixture, user: josh }; + const dataBefore = await snapData(fixtureWithUser); + + const tx = oethVault + .connect(josh) + .requestWithdrawal(dataBefore.userOeth.add(1)); + + await expect(tx).to.revertedWith("Remove exceeds balance"); + }); + it("capital is paused", async () => { + const { oethVault, governor, josh } = fixture; + + await oethVault.connect(governor).pauseCapital(); + + const tx = oethVault + .connect(josh) + .requestWithdrawal(firstRequestAmount); + + await expect(tx).to.be.revertedWith("Capital paused"); + }); }); }); + describe("with 1% vault buffer, 30 WETH in the queue, 15 WETH in the vault, 85 WETH in the strategy, 5 WETH already claimed", () => { + let mockStrategy; + beforeEach(async () => { + const { governor, oethVault, weth, daniel, domen, josh, matt } = + fixture; + // Mint 105 OETH to four users + await oethVault + .connect(daniel) + .mint(weth.address, oethUnits("15"), "0"); + await oethVault.connect(josh).mint(weth.address, oethUnits("20"), "0"); + await oethVault.connect(matt).mint(weth.address, oethUnits("30"), "0"); + await oethVault.connect(domen).mint(weth.address, oethUnits("40"), "0"); + await oethVault + .connect(await impersonateAndFund(await oethVault.governor())) + .setMaxSupplyDiff(oethUnits("0.03")); - describe("Should fail when", () => { - it("request doesn't have enough OETH", async () => { - const { oethVault, josh } = fixture; - const fixtureWithUser = { ...fixture, user: josh }; - const dataBefore = await snapData(fixtureWithUser); + // Request and claim 2 + 3 = 5 WETH from Vault + await oethVault.connect(daniel).requestWithdrawal(oethUnits("2")); + await oethVault.connect(josh).requestWithdrawal(oethUnits("3")); + await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. + await oethVault.connect(daniel).claimWithdrawal(0); + await oethVault.connect(josh).claimWithdrawal(1); - const tx = oethVault - .connect(josh) - .requestWithdrawal(dataBefore.userOeth.add(1)); + // Deploy a mock strategy + mockStrategy = await deployWithConfirmation("MockStrategy"); + await oethVault.connect(governor).approveStrategy(mockStrategy.address); - await expect(tx).to.revertedWith("Remove exceeds balance"); + // Deposit 85 WETH to strategy + await oethVault + .connect(governor) + .depositToStrategy( + mockStrategy.address, + [weth.address], + [oethUnits("85")] + ); + + // Set vault buffer to 1% + await oethVault.connect(governor).setVaultBuffer(oethUnits("0.01")); + + // Have 4 + 12 + 16 = 32 WETH outstanding requests + await oethVault.connect(daniel).requestWithdrawal(oethUnits("4")); + await oethVault.connect(josh).requestWithdrawal(oethUnits("12")); + await oethVault.connect(matt).requestWithdrawal(oethUnits("16")); + + await oethVault.connect(josh).addWithdrawalQueueLiquidity(); }); - it("capital is paused", async () => { - const { oethVault, governor, josh } = fixture; + describe("Fail to claim", () => { + it("a previously claimed withdrawal", async () => { + const { oethVault, daniel } = fixture; - await oethVault.connect(governor).pauseCapital(); + const tx = oethVault.connect(daniel).claimWithdrawal(0); - const tx = oethVault - .connect(josh) - .requestWithdrawal(firstRequestAmount); + await expect(tx).to.be.revertedWith("Already claimed"); + }); + it("the first withdrawal with wrong withdrawer", async () => { + const { oethVault, matt } = fixture; + + const tx = oethVault.connect(matt).claimWithdrawal(2); - await expect(tx).to.be.revertedWith("Capital paused"); + await expect(tx).to.be.revertedWith("Not requester"); + }); + it("the first withdrawal request in the queue before 30 minutes", async () => { + const { oethVault, daniel } = fixture; + + const tx = oethVault.connect(daniel).claimWithdrawal(2); + + await expect(tx).to.be.revertedWith("Claim delay not met"); + }); + }); + describe("when waited 30 minutes", () => { + beforeEach(async () => { + // Advance in time to ensure time delay between request and claim. + await advanceTime(delayPeriod); + }); + it("Fail to claim the first withdrawal with wrong withdrawer", async () => { + const { oethVault, matt } = fixture; + + const tx = oethVault.connect(matt).claimWithdrawal(2); + + await expect(tx).to.be.revertedWith("Not requester"); + }); + it("Should claim the first withdrawal request in the queue after 30 minutes", async () => { + const { oethVault, daniel } = fixture; + const fixtureWithUser = { ...fixture, user: daniel }; + const dataBefore = await snapData(fixtureWithUser); + + const tx = await oethVault.connect(daniel).claimWithdrawal(2); + + await expect(tx) + .to.emit(oethVault, "WithdrawalClaimed") + .withArgs(daniel.address, 2, oethUnits("4")); + + await assertChangedData( + dataBefore, + { + oethTotalSupply: 0, + oethTotalValue: 0, + vaultCheckBalance: 0, + userOeth: 0, + userWeth: oethUnits("4"), + vaultWeth: oethUnits("4").mul(-1), + queued: 0, + claimable: 0, + claimed: oethUnits("4"), + nextWithdrawalIndex: 0, + }, + fixtureWithUser + ); + }); + it("Fail to claim the second withdrawal request in the queue after 30 minutes", async () => { + const { oethVault, josh } = fixture; + + const tx = oethVault.connect(josh).claimWithdrawal(3); + + await expect(tx).to.be.revertedWith("Queue pending liquidity"); + }); + it("Fail to claim the last (3rd) withdrawal request in the queue", async () => { + const { oethVault, matt } = fixture; + + const tx = oethVault.connect(matt).claimWithdrawal(4); + + await expect(tx).to.be.revertedWith("Queue pending liquidity"); + }); + }); + describe("when mint covers exactly outstanding requests (32 - 15 = 17 OETH)", () => { + beforeEach(async () => { + const { oethVault, daniel, weth } = fixture; + await oethVault + .connect(daniel) + .mint(weth.address, oethUnits("17"), "0"); + + // Advance in time to ensure time delay between request and claim. + await advanceTime(delayPeriod); + }); + it("Should claim the 2nd and 3rd withdrawal requests in the queue", async () => { + const { oethVault, daniel, josh } = fixture; + const fixtureWithUser = { ...fixture, user: daniel }; + const dataBefore = await snapData(fixtureWithUser); + + const tx1 = await oethVault.connect(daniel).claimWithdrawal(2); + + await expect(tx1) + .to.emit(oethVault, "WithdrawalClaimed") + .withArgs(daniel.address, 2, oethUnits("4")); + + const tx2 = await oethVault.connect(josh).claimWithdrawal(3); + + await expect(tx2) + .to.emit(oethVault, "WithdrawalClaimed") + .withArgs(josh.address, 3, oethUnits("12")); + + await assertChangedData( + dataBefore, + { + oethTotalSupply: 0, + oethTotalValue: 0, + vaultCheckBalance: 0, + userOeth: 0, + userWeth: oethUnits("4"), + vaultWeth: oethUnits("16").mul(-1), + queued: 0, + claimable: 0, + claimed: oethUnits("16"), + nextWithdrawalIndex: 0, + }, + fixtureWithUser + ); + }); + it("Fail to deposit 1 WETH to the default strategy", async () => { + const { oethVault, weth, governor } = fixture; + + const tx = oethVault + .connect(governor) + .depositToStrategy( + mockStrategy.address, + [weth.address], + [oethUnits("1")] + ); + + await expect(tx).to.be.revertedWith("Not enough WETH available"); + }); + it("Should not allocate any WETH to the default strategy", async () => {}); + }); + describe("when mint covers exactly outstanding requests and vault buffer (31 OETH)", () => { + beforeEach(async () => { + const { oethVault, daniel, weth } = fixture; + await oethVault + .connect(daniel) + .mint(weth.address, oethUnits("31"), "0"); + }); + it("Fail to deposit 1 WETH to the default strategy", async () => {}); + it("Should not allocate any WETH to the default strategy", async () => {}); + }); + describe("when mint more than covers outstanding requests and vault buffer (40 OETH)", () => { + beforeEach(async () => { + const { oethVault, daniel, weth } = fixture; + await oethVault + .connect(daniel) + .mint(weth.address, oethUnits("40"), "0"); + }); + it("Should deposit 1 WETH to the default strategy", async () => {}); + it("Fail to deposit 10 WETH to the default strategy", async () => {}); + it("Should allocate WETH to the default strategy", async () => {}); }); }); }); From e66dc125105b343f73dd09d5bb7cb33f6d30ff74 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Tue, 16 Jul 2024 22:37:27 +1000 Subject: [PATCH 165/273] Added more unit tests --- contracts/test/vault/oeth-vault.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/contracts/test/vault/oeth-vault.js b/contracts/test/vault/oeth-vault.js index eadff9ce4f..8dc5b1bd98 100644 --- a/contracts/test/vault/oeth-vault.js +++ b/contracts/test/vault/oeth-vault.js @@ -1408,7 +1408,13 @@ describe("OETH Vault", function () { await expect(tx).to.be.revertedWith("Not enough WETH available"); }); - it("Should not allocate any WETH to the default strategy", async () => {}); + it("Should not allocate any WETH to the default strategy", async () => { + const { oethVault, domen } = fixture; + + const tx = await oethVault.connect(domen).allocate(); + + await expect(tx).to.not.emit(oethVault, "AssetAllocated"); + }); }); describe("when mint covers exactly outstanding requests and vault buffer (31 OETH)", () => { beforeEach(async () => { From 61ead28231235b3198ada1f6612ff1b881e11c7a Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Tue, 16 Jul 2024 23:09:00 +1000 Subject: [PATCH 166/273] Added more withdrawal unit tests --- contracts/test/vault/oeth-vault.js | 85 ++++++++++++++++++++++++++---- 1 file changed, 75 insertions(+), 10 deletions(-) diff --git a/contracts/test/vault/oeth-vault.js b/contracts/test/vault/oeth-vault.js index 9a390160ee..b8d07b31ad 100644 --- a/contracts/test/vault/oeth-vault.js +++ b/contracts/test/vault/oeth-vault.js @@ -1426,7 +1426,7 @@ describe("OETH Vault", function () { fixtureWithUser ); }); - it("Fail to deposit 1 WETH to the default strategy", async () => { + it("Fail to deposit 1 WETH to a strategy", async () => { const { oethVault, weth, governor } = fixture; const tx = oethVault @@ -1447,26 +1447,91 @@ describe("OETH Vault", function () { await expect(tx).to.not.emit(oethVault, "AssetAllocated"); }); }); - describe("when mint covers exactly outstanding requests and vault buffer (31 OETH)", () => { + describe("when mint covers exactly outstanding requests and vault buffer (17 + 1 WETH)", () => { beforeEach(async () => { const { oethVault, daniel, weth } = fixture; await oethVault .connect(daniel) - .mint(weth.address, oethUnits("31"), "0"); + .mint(weth.address, oethUnits("18"), "0"); + }); + it("Should deposit 1 WETH to a strategy which is the vault buffer", async () => { + const { oethVault, weth, governor } = fixture; + + const tx = await oethVault + .connect(governor) + .depositToStrategy( + mockStrategy.address, + [weth.address], + [oethUnits("1")] + ); + + expect(tx) + .to.emit(weth, "Transfer") + .withArgs(oethVault.address, mockStrategy.address, oethUnits("1")); + }); + it("Fail to deposit 1.1 WETH to the default strategy", async () => { + const { oethVault, weth, governor } = fixture; + + const tx = oethVault + .connect(governor) + .depositToStrategy( + mockStrategy.address, + [weth.address], + [oethUnits("1.1")] + ); + + await expect(tx).to.be.revertedWith("Not enough WETH available"); + }); + it("Should not allocate any WETH to the default strategy", async () => { + const { oethVault, domen } = fixture; + + const tx = await oethVault.connect(domen).allocate(); + + await expect(tx).to.not.emit(oethVault, "AssetAllocated"); }); - it("Fail to deposit 1 WETH to the default strategy", async () => {}); - it("Should not allocate any WETH to the default strategy", async () => {}); }); - describe("when mint more than covers outstanding requests and vault buffer (40 OETH)", () => { + describe("when mint more than covers outstanding requests and vault buffer (17 + 1 + 3 WETH)", () => { beforeEach(async () => { const { oethVault, daniel, weth } = fixture; await oethVault .connect(daniel) - .mint(weth.address, oethUnits("40"), "0"); + .mint(weth.address, oethUnits("21"), "0"); + }); + it("Should deposit 4 WETH to a strategy", async () => { + const { oethVault, weth, governor } = fixture; + + const tx = await oethVault + .connect(governor) + .depositToStrategy( + mockStrategy.address, + [weth.address], + [oethUnits("4")] + ); + + expect(tx) + .to.emit(weth, "Transfer") + .withArgs(oethVault.address, mockStrategy.address, oethUnits("4")); + }); + it("Fail to deposit 5 WETH to the default strategy", async () => { + const { oethVault, weth, governor } = fixture; + + const tx = oethVault + .connect(governor) + .depositToStrategy( + mockStrategy.address, + [weth.address], + [oethUnits("5")] + ); + + await expect(tx).to.be.revertedWith("Not enough WETH available"); + }); + it.skip("Should allocate 3 WETH to the default strategy", async () => { + const { oethVault, domen } = fixture; + + const tx = await oethVault.connect(domen).allocate(); + + await expect(tx).to.emit(oethVault, "AssetAllocated"); }); - it("Should deposit 1 WETH to the default strategy", async () => {}); - it("Fail to deposit 10 WETH to the default strategy", async () => {}); - it("Should allocate WETH to the default strategy", async () => {}); }); }); }); From b0cd0785993d1dd4ff0a3e62869b55dd5b0b178b Mon Sep 17 00:00:00 2001 From: Shahul Hameed <10547529+shahthepro@users.noreply.github.com> Date: Tue, 16 Jul 2024 19:36:57 +0530 Subject: [PATCH 167/273] Fix skipped test --- contracts/test/vault/oeth-vault.js | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/contracts/test/vault/oeth-vault.js b/contracts/test/vault/oeth-vault.js index b8d07b31ad..a52ba6e22c 100644 --- a/contracts/test/vault/oeth-vault.js +++ b/contracts/test/vault/oeth-vault.js @@ -1525,12 +1525,27 @@ describe("OETH Vault", function () { await expect(tx).to.be.revertedWith("Not enough WETH available"); }); - it.skip("Should allocate 3 WETH to the default strategy", async () => { - const { oethVault, domen } = fixture; + it("Should allocate 3 WETH to the default strategy", async () => { + const { oethVault, governor, domen, weth } = fixture; + + await oethVault + .connect(governor) + .setAssetDefaultStrategy(weth.address, mockStrategy.address); + + const vaultBalance = await weth.balanceOf(oethVault.address); + const stratBalance = await weth.balanceOf(mockStrategy.address); const tx = await oethVault.connect(domen).allocate(); await expect(tx).to.emit(oethVault, "AssetAllocated"); + + expect( + await weth.balanceOf(oethVault.address) + ).to.approxEqualTolerance(vaultBalance.sub(oethUnits("3")), 5); + + expect( + await weth.balanceOf(mockStrategy.address) + ).to.approxEqualTolerance(stratBalance.add(oethUnits("3")), 5); }); }); }); From 5ac4175a33be09920d64f793c3337fc43fd5fb9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment?= <55331875+clement-ux@users.noreply.github.com> Date: Wed, 17 Jul 2024 04:35:14 +0200 Subject: [PATCH 168/273] Add extra test to OETH ARM. (#2139) * test: add extra fork test for claiming withdraw. * fix: div by zero on `_postRedeem()`. * test: add test when vault is insolvent. * test: when enough WETH in vault to cover exactly withdraw. * test: when more than enough WETH in vault to cover withdraw. --- contracts/contracts/vault/VaultCore.sol | 2 +- contracts/test/vault/oeth-vault.js | 291 ++++++++++++++++++ .../vault/oeth-vault.mainnet.fork-test.js | 28 +- 3 files changed, 319 insertions(+), 2 deletions(-) diff --git a/contracts/contracts/vault/VaultCore.sol b/contracts/contracts/vault/VaultCore.sol index b126d0917f..3e7aabe4c4 100644 --- a/contracts/contracts/vault/VaultCore.sol +++ b/contracts/contracts/vault/VaultCore.sol @@ -224,7 +224,7 @@ contract VaultCore is VaultInitializer { } // Check that the OTokens are backed by enough assets - if (maxSupplyDiff > 0) { + if (maxSupplyDiff > 0 && totalUnits > 0) { // Allow a max difference of maxSupplyDiff% between // backing assets value and OUSD total supply uint256 diff = oUSD.totalSupply().divPrecisely(totalUnits); diff --git a/contracts/test/vault/oeth-vault.js b/contracts/test/vault/oeth-vault.js index a52ba6e22c..8c810508ea 100644 --- a/contracts/test/vault/oeth-vault.js +++ b/contracts/test/vault/oeth-vault.js @@ -317,6 +317,14 @@ describe("OETH Vault", function () { .redeem(oethUnits("1023232323232"), "0"); await expect(tx).to.be.revertedWith("Liquidity error"); }); + it("should allow every user to redeem", async () => { + const { oethVault, weth, daniel } = fixture; + await oethVault.connect(daniel).mint(weth.address, oethUnits("10"), "0"); + + await oethVault.connect(daniel).redeem(oethUnits("10"), oethUnits("0")); + + await expect(await weth.balanceOf(oethVault.address)).to.equal(0); + }); }); describe("Config", () => { @@ -1549,5 +1557,288 @@ describe("OETH Vault", function () { }); }); }); + describe("with 40 WETH in the queue, 10 WETH in the vault, 30 WETH already claimed", () => { + beforeEach(async () => { + const { oethVault, weth, daniel, josh, matt } = fixture; + + // Mint 60 OETH to three users + await oethVault + .connect(daniel) + .mint(weth.address, oethUnits("10"), "0"); + await oethVault.connect(josh).mint(weth.address, oethUnits("20"), "0"); + await oethVault.connect(matt).mint(weth.address, oethUnits("10"), "0"); + + // Request and claim 10 WETH from Vault + await oethVault.connect(daniel).requestWithdrawal(oethUnits("10")); + await oethVault.connect(josh).requestWithdrawal(oethUnits("20")); + await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. + + // Claim 10 + 20 = 30 WETH from Vault + await oethVault.connect(daniel).claimWithdrawal(0); + await oethVault.connect(josh).claimWithdrawal(1); + }); + it("should allow the last user to request the remaining 10 WETH", async () => { + const { oethVault, matt } = fixture; + const fixtureWithUser = { ...fixture, user: matt }; + const dataBefore = await snapData(fixtureWithUser); + + const tx = await oethVault + .connect(matt) + .requestWithdrawal(oethUnits("10")); + + await expect(tx) + .to.emit(oethVault, "WithdrawalRequested") + .withArgs(matt.address, 2, oethUnits("10"), oethUnits("40")); + + await assertChangedData( + dataBefore, + { + oethTotalSupply: oethUnits("10").mul(-1), + oethTotalValue: oethUnits("10").mul(-1), + vaultCheckBalance: oethUnits("10").mul(-1), + userOeth: oethUnits("10").mul(-1), + userWeth: 0, + vaultWeth: 0, + queued: oethUnits("10").mul(1), + claimable: 0, + claimed: 0, + nextWithdrawalIndex: 1, + }, + fixtureWithUser + ); + }); + it("should allow the last user to claim the request of 10 WETH", async () => { + const { oethVault, matt } = fixture; + const fixtureWithUser = { ...fixture, user: matt }; + await oethVault.connect(matt).requestWithdrawal(oethUnits("10")); + await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. + + const dataBefore = await snapData(fixtureWithUser); + + const tx = await oethVault.connect(matt).claimWithdrawal(2); + + await expect(tx) + .to.emit(oethVault, "WithdrawalClaimed") + .withArgs(matt.address, 2, oethUnits("10")); + + await assertChangedData( + dataBefore, + { + oethTotalSupply: 0, + oethTotalValue: 0, + vaultCheckBalance: 0, + userOeth: 0, + userWeth: oethUnits("10"), + vaultWeth: oethUnits("10").mul(-1), + queued: 0, + claimable: oethUnits("10"), + claimed: oethUnits("10"), + nextWithdrawalIndex: 0, + }, + fixtureWithUser + ); + + expect(await oethVault.totalValue()).to.equal(0); + }); + }); + describe("with 40 WETH in the queue, 100 WETH in the vault, 0 WETH in the strategy", () => { + beforeEach(async () => { + const { oethVault, weth, daniel, josh, matt } = fixture; + // Mint 100 OETH to three users + await oethVault + .connect(daniel) + .mint(weth.address, oethUnits("10"), "0"); + await oethVault.connect(josh).mint(weth.address, oethUnits("20"), "0"); + await oethVault.connect(matt).mint(weth.address, oethUnits("70"), "0"); + + // Request 40 WETH from Vault + await oethVault.connect(matt).requestWithdrawal(oethUnits("40")); + await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. + }); + it("should allow user to claim the request of 40 WETH", async () => { + const { oethVault, matt } = fixture; + const fixtureWithUser = { ...fixture, user: matt }; + const dataBefore = await snapData(fixtureWithUser); + + const tx = await oethVault.connect(matt).claimWithdrawal(0); + + await expect(tx) + .to.emit(oethVault, "WithdrawalClaimed") + .withArgs(matt.address, 0, oethUnits("40")); + + await assertChangedData( + dataBefore, + { + oethTotalSupply: 0, + oethTotalValue: 0, + vaultCheckBalance: 0, + userOeth: 0, + userWeth: oethUnits("40"), + vaultWeth: oethUnits("40").mul(-1), + queued: 0, + claimable: oethUnits("40"), + claimed: oethUnits("40"), + nextWithdrawalIndex: 0, + }, + fixtureWithUser + ); + }); + it("should allow user to perform a new request and claim a smaller than the WETH available", async () => { + const { oethVault, josh } = fixture; + + await oethVault.connect(josh).requestWithdrawal(oethUnits("20")); + await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. + + const tx = await oethVault.connect(josh).claimWithdrawal(1); + + await expect(tx).to.emit(oethVault, "WithdrawalClaimed"); + }); + it("should allow user to perform a new request and claim exactly the WETH available", async () => { + const { oethVault, oeth, josh, matt, daniel } = fixture; + await oethVault.connect(matt).claimWithdrawal(0); + // All user give OETH to another user + await oeth.connect(josh).transfer(matt.address, oethUnits("20")); + await oeth.connect(daniel).transfer(matt.address, oethUnits("10")); + + const fixtureWithUser = { ...fixture, user: matt }; + + // Matt request the remaining 60 OETH to be withdrawn + await oethVault.connect(matt).requestWithdrawal(oethUnits("60")); + await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. + + const dataBefore = await snapData(fixtureWithUser); + + const tx = await oethVault.connect(matt).claimWithdrawal(1); + + await expect(tx) + .to.emit(oethVault, "WithdrawalClaimed") + .withArgs(matt.address, 1, oethUnits("60")); + + await assertChangedData( + dataBefore, + { + oethTotalSupply: 0, + oethTotalValue: 0, + vaultCheckBalance: 0, + userOeth: 0, + userWeth: oethUnits("60"), + vaultWeth: oethUnits("60").mul(-1), + queued: 0, + claimable: oethUnits("60"), + claimed: oethUnits("60"), + nextWithdrawalIndex: 0, + }, + fixtureWithUser + ); + }); + it("shouldn't allow user to perform a new request and claim more than the WETH available", async () => { + const { oethVault, oeth, weth, josh, matt, daniel } = fixture; + await oethVault.connect(matt).claimWithdrawal(0); + // All user give OETH to another user + await oeth.connect(josh).transfer(matt.address, oethUnits("20")); + await oeth.connect(daniel).transfer(matt.address, oethUnits("10")); + + // Matt request more than the remaining 60 OETH to be withdrawn + await oethVault.connect(matt).requestWithdrawal(oethUnits("60")); + await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. + await weth + .connect(await impersonateAndFund(oethVault.address)) + .transfer(addresses.dead, oethUnits("50")); // Vault loses 50 WETH + + const tx = oethVault.connect(matt).claimWithdrawal(1); + await expect(tx).to.be.revertedWith("Queue pending liquidity"); + }); + }); + describe("with 40 WETH in the queue, 10 WETH in the vault, 10 WETH in the strategy => Slash event", () => { + beforeEach(async () => { + const { governor, oethVault, weth, daniel, josh, matt } = fixture; + // Deploy a mock strategy + const mockStrategy = await deployWithConfirmation("MockStrategy"); + await oethVault.connect(governor).approveStrategy(mockStrategy.address); + await oethVault + .connect(governor) + .setAssetDefaultStrategy(weth.address, mockStrategy.address); + + // Mint 60 OETH to three users + await oethVault + .connect(daniel) + .mint(weth.address, oethUnits("10"), "0"); + await oethVault.connect(josh).mint(weth.address, oethUnits("20"), "0"); + await oethVault.connect(matt).mint(weth.address, oethUnits("30"), "0"); + + // Request and claim 10 + 20 + 10 = 40 WETH from Vault + await oethVault.connect(daniel).requestWithdrawal(oethUnits("10")); + await oethVault.connect(josh).requestWithdrawal(oethUnits("20")); + await oethVault.connect(matt).requestWithdrawal(oethUnits("10")); + await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. + + // Simulate slash event of 10 ethers + await weth + .connect(await impersonateAndFund(mockStrategy.address)) + .transfer(addresses.dead, oethUnits("20")); + + // Simulate strategist sending 20 WETH to the vault + await weth + .connect(await impersonateAndFund(mockStrategy.address)) + .transfer(oethVault.address, oethUnits("20")); + + await oethVault.connect(josh).addWithdrawalQueueLiquidity(); + }); + it("should allow first user to claim the request of 10 WETH, no loss", async () => { + const { oethVault, daniel } = fixture; + const fixtureWithUser = { ...fixture, user: daniel }; + const dataBefore = await snapData(fixtureWithUser); + + const tx = await oethVault.connect(daniel).claimWithdrawal(0); + + await expect(tx) + .to.emit(oethVault, "WithdrawalClaimed") + .withArgs(daniel.address, 0, oethUnits("10")); + + await assertChangedData( + dataBefore, + { + oethTotalSupply: 0, + oethTotalValue: 0, + vaultCheckBalance: 0, + userOeth: 0, + userWeth: oethUnits("10"), + vaultWeth: oethUnits("10").mul(-1), + queued: 0, + claimable: 0, + claimed: oethUnits("10"), + nextWithdrawalIndex: 0, + }, + fixtureWithUser + ); + }); + it("shouldn't allow second user to claim the request of 20 WETH, due to loss", async () => { + const { oethVault, josh } = fixture; + + const tx = oethVault.connect(josh).claimWithdrawal(1); + + await expect(tx).to.be.revertedWith("Queue pending liquidity"); + }); + it("should allow a user to create a new request, even if the vault is insolvent", async () => { + const { oethVault, matt } = fixture; + + const tx = oethVault.connect(matt).requestWithdrawal(oethUnits("10")); + + await expect(tx) + .to.emit(oethVault, "WithdrawalRequested") + .withArgs(matt.address, 3, oethUnits("10"), oethUnits("50")); + }); + it("should not allow user to create a new request, as insolvent with solvency check", async () => { + const { oethVault, matt } = fixture; + + await oethVault + .connect(await impersonateAndFund(await oethVault.governor())) + .setMaxSupplyDiff(oethUnits("0.03")); + + const tx = oethVault.connect(matt).requestWithdrawal(oethUnits("10")); + + await expect(tx).to.be.revertedWith("Backing supply liquidity error"); + }); + }); }); }); diff --git a/contracts/test/vault/oeth-vault.mainnet.fork-test.js b/contracts/test/vault/oeth-vault.mainnet.fork-test.js index 34892eb868..90affe12a9 100644 --- a/contracts/test/vault/oeth-vault.mainnet.fork-test.js +++ b/contracts/test/vault/oeth-vault.mainnet.fork-test.js @@ -3,7 +3,7 @@ const { formatUnits, parseUnits } = require("ethers/lib/utils"); const addresses = require("../../utils/addresses"); const { createFixtureLoader, oethDefaultFixture } = require("../_fixture"); -const { isCI, oethUnits } = require("../helpers"); +const { isCI, oethUnits, advanceTime } = require("../helpers"); const { impersonateAndFund } = require("../../utils/signers"); const { logTxDetails } = require("../../utils/txLogger"); const { @@ -66,6 +66,7 @@ describe("ForkTest: OETH Vault", function () { describe("user operations", () => { let oethWhaleSigner; + const delayPeriod = 30 * 60; // 30 minutes beforeEach(async () => { oethWhaleSigner = await impersonateAndFund(oethWhaleAddress); }); @@ -221,6 +222,31 @@ describe("ForkTest: OETH Vault", function () { _amount: oethWhaleBalance, }); }); + it("should claim withdraw by a OETH whale", async () => { + const { oeth, oethVault } = fixture; + + let oethWhaleBalance = await oeth.balanceOf(oethWhaleAddress); + + expect(oethWhaleBalance, "no longer an OETH whale").to.gt( + parseUnits("100", 18) + ); + + oethWhaleBalance = oethUnits("50"); + + // First Request withdrawal + await oethVault + .connect(oethWhaleSigner) + .requestWithdrawal(oethWhaleBalance); + + await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. + + // Then Claim withdrawal + const tx = await oethVault.connect(oethWhaleSigner).claimWithdrawal(0); + + await expect(tx) + .to.emit(oethVault, "WithdrawalClaimed") + .withArgs(oethWhaleAddress, 0, oethWhaleBalance); + }); it("OETH whale can redeem after withdraw from all strategies", async () => { const { oeth, oethVault, timelock } = fixture; From 5b61c2b03994fc8675b72ffd1596be68d6620678 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment?= <55331875+clement-ux@users.noreply.github.com> Date: Wed, 17 Jul 2024 07:59:12 +0200 Subject: [PATCH 169/273] fix: reduce delay period between request and claim to 10min. (#2140) --- contracts/contracts/vault/OETHVaultCore.sol | 2 +- contracts/test/vault/oeth-vault.js | 2 +- contracts/test/vault/oeth-vault.mainnet.fork-test.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/contracts/contracts/vault/OETHVaultCore.sol b/contracts/contracts/vault/OETHVaultCore.sol index 0351430dee..001a7251a0 100644 --- a/contracts/contracts/vault/OETHVaultCore.sol +++ b/contracts/contracts/vault/OETHVaultCore.sol @@ -17,7 +17,7 @@ contract OETHVaultCore is VaultCore { using SafeERC20 for IERC20; using StableMath for uint256; - uint256 constant CLAIM_DELAY = 30 minutes; + uint256 constant CLAIM_DELAY = 10 minutes; address public immutable weth; uint256 public wethAssetIndex; diff --git a/contracts/test/vault/oeth-vault.js b/contracts/test/vault/oeth-vault.js index 8c810508ea..f421f68337 100644 --- a/contracts/test/vault/oeth-vault.js +++ b/contracts/test/vault/oeth-vault.js @@ -501,7 +501,7 @@ describe("OETH Vault", function () { }); describe("Withdrawal Queue", () => { - const delayPeriod = 30 * 60; // 30 minutes + const delayPeriod = 10 * 60; // 10 minutes describe("with all 60 WETH in the vault", () => { beforeEach(async () => { const { oethVault, weth, daniel, josh, matt } = fixture; diff --git a/contracts/test/vault/oeth-vault.mainnet.fork-test.js b/contracts/test/vault/oeth-vault.mainnet.fork-test.js index 90affe12a9..4b8e6c0099 100644 --- a/contracts/test/vault/oeth-vault.mainnet.fork-test.js +++ b/contracts/test/vault/oeth-vault.mainnet.fork-test.js @@ -66,7 +66,7 @@ describe("ForkTest: OETH Vault", function () { describe("user operations", () => { let oethWhaleSigner; - const delayPeriod = 30 * 60; // 30 minutes + const delayPeriod = 10 * 60; // 10 minutes beforeEach(async () => { oethWhaleSigner = await impersonateAndFund(oethWhaleAddress); }); From 975c3c651f114aedd3708b11c65cc69bb60928fb Mon Sep 17 00:00:00 2001 From: Nick Addison Date: Wed, 17 Jul 2024 16:46:21 +1000 Subject: [PATCH 170/273] Refactor OETH Vault's `_allocate()` (#2141) * Refactor of OETH Vault's _allocate * Updated allocate test --- contracts/contracts/vault/OETHVaultCore.sol | 40 ++++++--------------- contracts/test/vault/oeth-vault.js | 22 +++++++----- 2 files changed, 24 insertions(+), 38 deletions(-) diff --git a/contracts/contracts/vault/OETHVaultCore.sol b/contracts/contracts/vault/OETHVaultCore.sol index 001a7251a0..839606f04a 100644 --- a/contracts/contracts/vault/OETHVaultCore.sol +++ b/contracts/contracts/vault/OETHVaultCore.sol @@ -398,40 +398,20 @@ contract OETHVaultCore is VaultCore { uint256 wethAvailableInVault = _wethAvailable(); // Nothing in vault to allocate if (wethAvailableInVault == 0) return; - uint256 strategiesValue = _totalValueInStrategies(); - // We have a method that does the same as this, gas optimisation - uint256 calculatedTotalValue = wethAvailableInVault + strategiesValue; - - // We want to maintain a buffer on the Vault so calculate a percentage - // modifier to multiply each amount being allocated by to enforce the - // vault buffer - uint256 vaultBufferModifier; - if (strategiesValue == 0) { - // Nothing in Strategies, allocate 100% minus the vault buffer to - // strategies - vaultBufferModifier = uint256(1e18) - vaultBuffer; - } else { - vaultBufferModifier = - (vaultBuffer * calculatedTotalValue) / - wethAvailableInVault; - if (1e18 > vaultBufferModifier) { - // E.g. 1e18 - (1e17 * 10e18)/5e18 = 8e17 - // (5e18 * 8e17) / 1e18 = 4e18 allocated from Vault - vaultBufferModifier = uint256(1e18) - vaultBufferModifier; - } else { - // We need to let the buffer fill - return; - } - } - if (vaultBufferModifier == 0) return; - uint256 allocateAmount = wethAvailableInVault.mulTruncate( - vaultBufferModifier - ); + // 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 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; address depositStrategyAddr = assetDefaultStrategies[weth]; - if (depositStrategyAddr != address(0) && allocateAmount > 0) { + if (depositStrategyAddr != address(0)) { IStrategy strategy = IStrategy(depositStrategyAddr); // Transfer asset to Strategy and call deposit method to // mint or take required action diff --git a/contracts/test/vault/oeth-vault.js b/contracts/test/vault/oeth-vault.js index f421f68337..bf7c992d30 100644 --- a/contracts/test/vault/oeth-vault.js +++ b/contracts/test/vault/oeth-vault.js @@ -1306,6 +1306,7 @@ describe("OETH Vault", function () { await oethVault.connect(governor).setVaultBuffer(oethUnits("0.01")); // Have 4 + 12 + 16 = 32 WETH outstanding requests + // So a total supply of 100 - 32 = 68 OETH await oethVault.connect(daniel).requestWithdrawal(oethUnits("4")); await oethVault.connect(josh).requestWithdrawal(oethUnits("12")); await oethVault.connect(matt).requestWithdrawal(oethUnits("16")); @@ -1498,7 +1499,7 @@ describe("OETH Vault", function () { await expect(tx).to.not.emit(oethVault, "AssetAllocated"); }); }); - describe("when mint more than covers outstanding requests and vault buffer (17 + 1 + 3 WETH)", () => { + describe("when mint more than covers outstanding requests and vault buffer (17 + 1 + 3 = 21 OETH)", () => { beforeEach(async () => { const { oethVault, daniel, weth } = fixture; await oethVault @@ -1545,15 +1546,20 @@ describe("OETH Vault", function () { const tx = await oethVault.connect(domen).allocate(); - await expect(tx).to.emit(oethVault, "AssetAllocated"); + // total supply is 68 starting + 21 minted = 89 OETH + // Vault buffer is 1% of 89 = 0.89 WETH + // WETH transfer amount = 4 WETH available in vault - 0.89 WETH buffer = 3.11 WETH + await expect(tx) + .to.emit(oethVault, "AssetAllocated") + .withArgs(weth.address, mockStrategy.address, oethUnits("3.11")); - expect( - await weth.balanceOf(oethVault.address) - ).to.approxEqualTolerance(vaultBalance.sub(oethUnits("3")), 5); + expect(await weth.balanceOf(oethVault.address)).to.eq( + vaultBalance.sub(oethUnits("3.11")) + ); - expect( - await weth.balanceOf(mockStrategy.address) - ).to.approxEqualTolerance(stratBalance.add(oethUnits("3")), 5); + expect(await weth.balanceOf(mockStrategy.address)).to.eq( + stratBalance.add(oethUnits("3.11")) + ); }); }); }); From 5422808b6180d47e6f75c74d427dfbbc33702456 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment?= <55331875+clement-ux@users.noreply.github.com> Date: Wed, 17 Jul 2024 14:06:52 +0200 Subject: [PATCH 171/273] Add extra test for OETH Withdraw Queue (#2142) * test: add tests for `_allocate()`. --- contracts/test/vault/oeth-vault.js | 191 +++++++++++++++++++++++++++++ 1 file changed, 191 insertions(+) diff --git a/contracts/test/vault/oeth-vault.js b/contracts/test/vault/oeth-vault.js index bf7c992d30..fc846234dc 100644 --- a/contracts/test/vault/oeth-vault.js +++ b/contracts/test/vault/oeth-vault.js @@ -500,6 +500,197 @@ describe("OETH Vault", function () { }); }); + describe("Allocate", () => { + const delayPeriod = 10 * 60; // 10mins + it("Shouldn't allocate as minted amount is lower than autoAllocateThreshold", async () => { + const { oethVault, weth, daniel } = fixture; + + // Set auto allocate threshold to 100 WETH + await oethVault + .connect(await impersonateAndFund(await oethVault.governor())) + .setAutoAllocateThreshold(oethUnits("100")); + + // Mint for 10 WETH + const tx = oethVault + .connect(daniel) + .mint(weth.address, oethUnits("10"), "0"); + + await expect(tx).to.not.emit(oethVault, "AssetAllocated"); + }); + it("Shouldn't allocate as no WETH available", async () => { + const { oethVault, weth, daniel } = fixture; + + // Deploy default strategy + const mockStrategy = await deployWithConfirmation("MockStrategy"); + await oethVault + .connect(await impersonateAndFund(await oethVault.governor())) + .approveStrategy(mockStrategy.address); + await oethVault + .connect(await impersonateAndFund(await oethVault.governor())) + .setAssetDefaultStrategy(weth.address, mockStrategy.address); + + // Mint will allocate all to default strategy bc no buffer, no threshold + await oethVault.connect(daniel).mint(weth.address, oethUnits("10"), "0"); + await oethVault.connect(daniel).requestWithdrawal(oethUnits("5")); + + // Deposit less than queued amount (5 WETH) => _wethAvailable() return 0 + const tx = oethVault + .connect(daniel) + .mint(weth.address, oethUnits("3", "0")); + expect(tx).to.not.emit(oethVault, "AssetAllocated"); + }); + it("Shouldn't allocate as WETH available is lower than buffer", async () => { + const { oethVault, weth, daniel } = fixture; + + await oethVault.connect(daniel).mint(weth.address, oethUnits("100"), "0"); + + // Set vault buffer to 5% + await oethVault + .connect(await impersonateAndFund(await oethVault.governor())) + .setVaultBuffer(oethUnits("0.05")); + + // OETH total supply = 100(first deposit) + 5(second deposit) = 105 + // Buffer = 105 * 5% = 5.25 WETH + // Second deposit should remain in the vault as below vault buffer + const tx = oethVault.connect(daniel).mint(oethUnits("5"), "0"); + expect(tx).to.not.emit(oethVault, "AssetAllocated"); + }); + it("Shouldn't allocate as default strategy is address null", async () => { + const { oethVault, weth, daniel } = fixture; + + const tx = oethVault + .connect(daniel) + .mint(weth.address, oethUnits("100"), "0"); + + expect(tx).to.not.emit(oethVault, "AssetAllocated"); + }); + describe("Should allocate WETH available to default strategy when: ", () => { + let mockStrategy; + beforeEach(async () => { + // Deploy default strategy + const { oethVault, weth } = fixture; + mockStrategy = await deployWithConfirmation("MockStrategy"); + await oethVault + .connect(await impersonateAndFund(await oethVault.governor())) + .approveStrategy(mockStrategy.address); + await oethVault + .connect(await impersonateAndFund(await oethVault.governor())) + .setAssetDefaultStrategy(weth.address, mockStrategy.address); + }); + it("buffer is 0%, 0 WETH in queue", async () => { + const { oethVault, daniel, weth } = fixture; + const tx = oethVault + .connect(daniel) + .mint(weth.address, oethUnits("10"), "0"); + await expect(tx) + .to.emit(oethVault, "AssetAllocated") + .withArgs(weth.address, mockStrategy.address, oethUnits("10")); + expect(await weth.balanceOf(mockStrategy.address)).to.be.equal( + oethUnits("10") + ); + }); + it("buffer is 5%", async () => { + const { oethVault, daniel, weth } = fixture; + // Set vault buffer to 5% + await oethVault + .connect(await impersonateAndFund(await oethVault.governor())) + .setVaultBuffer(oethUnits("0.05")); + + const tx = oethVault + .connect(daniel) + .mint(weth.address, oethUnits("10"), "0"); + await expect(tx) + .to.emit(oethVault, "AssetAllocated") + .withArgs(weth.address, mockStrategy.address, oethUnits("9.5")); + expect(await weth.balanceOf(mockStrategy.address)).to.be.equal( + oethUnits("9.5") + ); + }); + it("buffer is 0%, 10 WETH in queue", async () => { + const { oethVault, daniel, weth } = fixture; + await oethVault + .connect(daniel) + .mint(weth.address, oethUnits("10"), "0"); + await oethVault.connect(daniel).requestWithdrawal(oethUnits("10")); + const tx = oethVault + .connect(daniel) + .mint(weth.address, oethUnits("20"), "0"); + + // 10 WETH in the queue, 10 WETH in strat. New deposit of 20, only 10 WETH available to allocate to strategy. + await expect(tx) + .to.emit(oethVault, "AssetAllocated") + .withArgs(weth.address, mockStrategy.address, oethUnits("10")); + expect(await weth.balanceOf(mockStrategy.address)).to.be.equal( + oethUnits("20") + ); + }); + it("buffer is 0%, 20 WETH in queue, 10 WETH claimed", async () => { + const { oethVault, daniel, weth } = fixture; + await oethVault + .connect(daniel) + .mint(weth.address, oethUnits("30"), "0"); + await oethVault.connect(daniel).requestWithdrawal(oethUnits("10")); + await advanceTime(delayPeriod); + // Simulate strategist pulling back WETH to the vault. + await weth + .connect(await impersonateAndFund(mockStrategy.address)) + .transfer(oethVault.address, oethUnits("10")); + await oethVault.connect(daniel).claimWithdrawal(0); + // So far, 10 WETH queued, 10 WETH claimed, 0 WETH available, 20 WETH in strat + + await oethVault.connect(daniel).requestWithdrawal(oethUnits("10")); + // So far, 20 WETH queued, 10 WETH claimed, 0 WETH available, 20 WETH in strat + + // Deposit 35 WETH, 10 WETH should remain in the vault for withdraw, so strat should have 45WETH. + const tx = oethVault + .connect(daniel) + .mint(weth.address, oethUnits("35"), "0"); + await expect(tx) + .to.emit(oethVault, "AssetAllocated") + .withArgs(weth.address, mockStrategy.address, oethUnits("25")); + + expect(await weth.balanceOf(mockStrategy.address)).to.be.equal( + oethUnits("45") + ); + }); + it("buffer is 5%, 20 WETH in queue, 10 WETH claimed", async () => { + const { oethVault, daniel, weth } = fixture; + await oethVault + .connect(daniel) + .mint(weth.address, oethUnits("40"), "0"); + await oethVault.connect(daniel).requestWithdrawal(oethUnits("10")); + await advanceTime(delayPeriod); + // Simulate strategist pulling back WETH to the vault. + await weth + .connect(await impersonateAndFund(mockStrategy.address)) + .transfer(oethVault.address, oethUnits("10")); + await oethVault.connect(daniel).claimWithdrawal(0); + // So far, 10 WETH queued, 10 WETH claimed, 0 WETH available, 30 WETH in strat + + await oethVault.connect(daniel).requestWithdrawal(oethUnits("10")); + // So far, 20 WETH queued, 10 WETH claimed, 0 WETH available, 30 WETH in strat + + // Set vault buffer to 5% + await oethVault + .connect(await impersonateAndFund(await oethVault.governor())) + .setVaultBuffer(oethUnits("0.05")); + + // Deposit 40 WETH, 10 WETH should remain in the vault for withdraw + 3 (i.e. 20+40 *5%) + // So strat should have 57WETH. + const tx = oethVault + .connect(daniel) + .mint(weth.address, oethUnits("40"), "0"); + await expect(tx) + .to.emit(oethVault, "AssetAllocated") + .withArgs(weth.address, mockStrategy.address, oethUnits("27")); + + expect(await weth.balanceOf(mockStrategy.address)).to.be.equal( + oethUnits("57") + ); + }); + }); + }); + describe("Withdrawal Queue", () => { const delayPeriod = 10 * 60; // 10 minutes describe("with all 60 WETH in the vault", () => { From 839bde2bb292d0a02fbab6365f8ff2810aefbd7b Mon Sep 17 00:00:00 2001 From: Nick Addison Date: Thu, 18 Jul 2024 13:57:47 +1000 Subject: [PATCH 172/273] Override allocate on OETH Vault so _addWithdrawalQueueLiquidity is not called twice on large mints (#2144) OEH Vault _allocate exits early if no default WETH strategy --- contracts/contracts/vault/OETHVaultCore.sol | 35 +++++++++++++-------- contracts/contracts/vault/VaultCore.sol | 2 +- 2 files changed, 23 insertions(+), 14 deletions(-) diff --git a/contracts/contracts/vault/OETHVaultCore.sol b/contracts/contracts/vault/OETHVaultCore.sol index 839606f04a..0505cbe49d 100644 --- a/contracts/contracts/vault/OETHVaultCore.sol +++ b/contracts/contracts/vault/OETHVaultCore.sol @@ -390,35 +390,44 @@ contract OETHVaultCore is VaultCore { } } - // @inheritdoc VaultCore - function _allocate() internal override { + /** + * @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(); - // Nothing in vault to allocate + // 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 the target buffer then there's nothing to allocate + // 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; - address depositStrategyAddr = assetDefaultStrategies[weth]; + 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); - if (depositStrategyAddr != address(0)) { - IStrategy strategy = IStrategy(depositStrategyAddr); - // Transfer asset to Strategy and call deposit method to - // mint or take required action - IERC20(weth).safeTransfer(address(strategy), allocateAmount); - strategy.deposit(weth, allocateAmount); - emit AssetAllocated(weth, depositStrategyAddr, allocateAmount); - } + emit AssetAllocated(weth, depositStrategyAddr, allocateAmount); } /// @dev The total value of all assets held by the vault and all its strategies diff --git a/contracts/contracts/vault/VaultCore.sol b/contracts/contracts/vault/VaultCore.sol index 3e7aabe4c4..d2144004da 100644 --- a/contracts/contracts/vault/VaultCore.sol +++ b/contracts/contracts/vault/VaultCore.sol @@ -284,7 +284,7 @@ contract VaultCore is VaultInitializer { /** * @notice Allocate unallocated funds on Vault to strategies. **/ - function allocate() external whenNotCapitalPaused nonReentrant { + function allocate() external virtual whenNotCapitalPaused nonReentrant { _allocate(); } From 5d29d4508dbee585a2ab4435db9df189a5e6742d Mon Sep 17 00:00:00 2001 From: Shahul Hameed <10547529+shahthepro@users.noreply.github.com> Date: Thu, 18 Jul 2024 10:12:17 +0530 Subject: [PATCH 173/273] Skip waiting for confirmation on Tenderly testnets --- contracts/utils/deploy.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/contracts/utils/deploy.js b/contracts/utils/deploy.js index 570def4a0c..1f7cc786eb 100644 --- a/contracts/utils/deploy.js +++ b/contracts/utils/deploy.js @@ -120,6 +120,12 @@ const withConfirmation = async ( logContractAbi = false ) => { const result = await deployOrTransactionPromise; + + if (process.env.PROVIDER_URL.includes("rpc.tenderly.co")) { + // Skip on Tenderly + return result; + } + const receipt = await hre.ethers.provider.waitForTransaction( result.receipt ? result.receipt.transactionHash : result.hash, NUM_CONFIRMATIONS From bb5a82a14600e0aca032ebdc9785af00119b9b63 Mon Sep 17 00:00:00 2001 From: Shahul Hameed <10547529+shahthepro@users.noreply.github.com> Date: Thu, 18 Jul 2024 12:03:35 +0530 Subject: [PATCH 174/273] Fix unit tests --- contracts/utils/deploy.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/utils/deploy.js b/contracts/utils/deploy.js index 1f7cc786eb..3149fc1759 100644 --- a/contracts/utils/deploy.js +++ b/contracts/utils/deploy.js @@ -121,7 +121,7 @@ const withConfirmation = async ( ) => { const result = await deployOrTransactionPromise; - if (process.env.PROVIDER_URL.includes("rpc.tenderly.co")) { + if (process.env.PROVIDER_URL?.includes("rpc.tenderly.co")) { // Skip on Tenderly return result; } From 9135275b8fc363c02588ed754ad0ef566cb874cb Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Thu, 25 Jul 2024 22:01:21 +1000 Subject: [PATCH 175/273] Add snapVault hardhat task --- contracts/tasks/tasks.js | 23 +++++++++++++++++ contracts/tasks/vault.js | 54 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 76 insertions(+), 1 deletion(-) diff --git a/contracts/tasks/tasks.js b/contracts/tasks/tasks.js index a2896381b2..e32f8df017 100644 --- a/contracts/tasks/tasks.js +++ b/contracts/tasks/tasks.js @@ -42,6 +42,7 @@ const { } = require("./tokens"); const { depositWETH, withdrawWETH } = require("./weth"); const { + addWithdrawalQueueLiquidity, allocate, capital, depositToStrategy, @@ -51,6 +52,7 @@ const { redeemAll, requestWithdrawal, claimWithdrawal, + snapVault, withdrawFromStrategy, withdrawAllFromStrategy, withdrawAllFromStrategies, @@ -272,6 +274,15 @@ task("withdrawWETH").setAction(async (_, __, runSuper) => { }); // Vault tasks. + +task( + "queueLiquidity", + "Call addWithdrawalQueueLiquidity() on the Vault to add WETH to the withdrawal queue" +).setAction(addWithdrawalQueueLiquidity); +task("queueLiquidity").setAction(async (_, __, runSuper) => { + return runSuper(); +}); + task("allocate", "Call allocate() on the Vault") .addOptionalParam( "symbol", @@ -1412,6 +1423,18 @@ task("snapStaking").setAction(async (_, __, runSuper) => { return runSuper(); }); +subtask("snapVault", "Takes a snapshot of a OETH Vault") + .addOptionalParam( + "block", + "Block number. (default: latest)", + undefined, + types.int + ) + .setAction(snapVault); +task("snapVault").setAction(async (_, __, runSuper) => { + return runSuper(); +}); + subtask( "depositRoot", "Calculates the Beacon chain deposit root for a validator" diff --git a/contracts/tasks/vault.js b/contracts/tasks/vault.js index 75cc75da1f..a37296b969 100644 --- a/contracts/tasks/vault.js +++ b/contracts/tasks/vault.js @@ -1,10 +1,12 @@ -const { parseUnits } = require("ethers/lib/utils"); +const { formatUnits, parseUnits } = require("ethers/lib/utils"); +const { getBlock } = require("./block"); const addresses = require("../utils/addresses"); const { resolveAsset } = require("../utils/resolvers"); const { getSigner } = require("../utils/signers"); const { logTxDetails } = require("../utils/txLogger"); const { ethereumAddress } = require("../utils/regex"); +const { networkMap } = require("../utils/hardhat-helpers"); const log = require("../utils/logger")("task:vault"); @@ -26,6 +28,54 @@ async function getContract(hre, symbol) { }; } +async function snapVault({ block }, hre) { + const blockTag = getBlock(block); + + const vaultProxy = await hre.ethers.getContract(`OETHVaultProxy`); + const vault = await hre.ethers.getContractAt("IVault", vaultProxy.address); + + const { chainId } = await hre.ethers.provider.getNetwork(); + const wethAddress = addresses[networkMap[chainId]].WETH; + const weth = await ethers.getContractAt("IERC20", wethAddress); + + const wethBalance = await weth.balanceOf(vault.address, { + blockTag, + }); + + const queue = await vault.withdrawalQueueMetadata({ + blockTag, + }); + const shortfall = queue.queued.sub(queue.claimable); + const unclaimed = queue.queued.sub(queue.claimed); + const available = wethBalance.sub(unclaimed).sub(shortfall); + + console.log(`Vault WETH : ${formatUnits(wethBalance)}, ${wethBalance} wei`); + + console.log(`Queued : ${formatUnits(queue.queued)}, ${queue.queued} wei`); + console.log( + `Claimable : ${formatUnits(queue.claimable)}, ${queue.claimable} wei` + ); + console.log( + `Claimed : ${formatUnits(queue.claimed)}, ${queue.claimed} wei` + ); + console.log(`Shortfall : ${formatUnits(shortfall)}, ${shortfall} wei`); + console.log(`Unclaimed : ${formatUnits(unclaimed)}, ${unclaimed} wei`); + console.log(`Available : ${formatUnits(available)}, ${available} wei`); +} + +async function addWithdrawalQueueLiquidity(_, hre) { + const signer = await getSigner(); + + const vaultProxy = await hre.ethers.getContract(`OETHVaultProxy`); + const vault = await hre.ethers.getContractAt("IVault", vaultProxy.address); + + log( + `About to call addWithdrawalQueueLiquidity() on the vault with address ${vault.address}` + ); + const tx = await vault.connect(signer).addWithdrawalQueueLiquidity(); + await logTxDetails(tx, "addWithdrawalQueueLiquidity"); +} + async function allocate({ symbol }, hre) { const signer = await getSigner(); @@ -326,6 +376,7 @@ async function claimWithdrawal({ requestId, symbol }, hre) { } module.exports = { + addWithdrawalQueueLiquidity, allocate, capital, depositToStrategy, @@ -335,6 +386,7 @@ module.exports = { redeemAll, requestWithdrawal, claimWithdrawal, + snapVault, withdrawFromStrategy, withdrawAllFromStrategy, withdrawAllFromStrategies, From cc6f2f370cc5c34fc83e62f006337ce205e6e312 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Fri, 26 Jul 2024 13:20:39 +1000 Subject: [PATCH 176/273] Updated insolvency unit tests --- contracts/test/vault/oeth-vault.js | 33 ++++++++++++++++++------------ 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/contracts/test/vault/oeth-vault.js b/contracts/test/vault/oeth-vault.js index fc846234dc..63bf424c51 100644 --- a/contracts/test/vault/oeth-vault.js +++ b/contracts/test/vault/oeth-vault.js @@ -1946,9 +1946,10 @@ describe("OETH Vault", function () { await expect(tx).to.be.revertedWith("Queue pending liquidity"); }); }); - describe("with 40 WETH in the queue, 10 WETH in the vault, 10 WETH in the strategy => Slash event", () => { + describe("with 40 WETH in the queue, 15 WETH in the vault, 44 WETH in the strategy, vault insolvent by 5% => Slash 1 ether (1/20 = 5%), 19 WETH total value", () => { beforeEach(async () => { - const { governor, oethVault, weth, daniel, josh, matt } = fixture; + const { governor, oethVault, weth, daniel, josh, matt, strategist } = + fixture; // Deploy a mock strategy const mockStrategy = await deployWithConfirmation("MockStrategy"); await oethVault.connect(governor).approveStrategy(mockStrategy.address); @@ -1969,19 +1970,23 @@ describe("OETH Vault", function () { await oethVault.connect(matt).requestWithdrawal(oethUnits("10")); await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. - // Simulate slash event of 10 ethers + // Simulate slash event of 1 ethers await weth .connect(await impersonateAndFund(mockStrategy.address)) - .transfer(addresses.dead, oethUnits("20")); + .transfer(addresses.dead, oethUnits("1")); - // Simulate strategist sending 20 WETH to the vault - await weth - .connect(await impersonateAndFund(mockStrategy.address)) - .transfer(oethVault.address, oethUnits("20")); + // Strategist sends 15 WETH to the vault + await oethVault + .connect(strategist) + .withdrawFromStrategy( + mockStrategy.address, + [weth.address], + [oethUnits("15")] + ); await oethVault.connect(josh).addWithdrawalQueueLiquidity(); }); - it("should allow first user to claim the request of 10 WETH, no loss", async () => { + it("Should allow first user to claim the request of 10 WETH, no loss", async () => { const { oethVault, daniel } = fixture; const fixtureWithUser = { ...fixture, user: daniel }; const dataBefore = await snapData(fixtureWithUser); @@ -2009,14 +2014,15 @@ describe("OETH Vault", function () { fixtureWithUser ); }); - it("shouldn't allow second user to claim the request of 20 WETH, due to loss", async () => { + it("Fail to allow second user to claim the request of 20 WETH, due to liquidity", async () => { const { oethVault, josh } = fixture; const tx = oethVault.connect(josh).claimWithdrawal(1); await expect(tx).to.be.revertedWith("Queue pending liquidity"); }); - it("should allow a user to create a new request, even if the vault is insolvent", async () => { + it("Should allow a user to create a new request, with the vault insolvent and solvency check off", async () => { + // maxSupplyDiff is set to 0 so no insolvency check const { oethVault, matt } = fixture; const tx = oethVault.connect(matt).requestWithdrawal(oethUnits("10")); @@ -2025,14 +2031,15 @@ describe("OETH Vault", function () { .to.emit(oethVault, "WithdrawalRequested") .withArgs(matt.address, 3, oethUnits("10"), oethUnits("50")); }); - it("should not allow user to create a new request, as insolvent with solvency check", async () => { + it("Fail to allow user to create a new request, with the vault insolvent and solvency check at 3%", async () => { const { oethVault, matt } = fixture; + // Turn on insolvency check with 3% buffer await oethVault .connect(await impersonateAndFund(await oethVault.governor())) .setMaxSupplyDiff(oethUnits("0.03")); - const tx = oethVault.connect(matt).requestWithdrawal(oethUnits("10")); + const tx = oethVault.connect(matt).requestWithdrawal(oethUnits("1")); await expect(tx).to.be.revertedWith("Backing supply liquidity error"); }); From 133ddcb0d1bba63a109bf2ce3af9aa18a1b1300a Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Fri, 26 Jul 2024 13:46:36 +1000 Subject: [PATCH 177/273] Added more insolvency unit tests --- contracts/test/vault/oeth-vault.js | 85 +++++++++++++++++++++++++----- 1 file changed, 73 insertions(+), 12 deletions(-) diff --git a/contracts/test/vault/oeth-vault.js b/contracts/test/vault/oeth-vault.js index 63bf424c51..0002a109ed 100644 --- a/contracts/test/vault/oeth-vault.js +++ b/contracts/test/vault/oeth-vault.js @@ -1986,14 +1986,14 @@ describe("OETH Vault", function () { await oethVault.connect(josh).addWithdrawalQueueLiquidity(); }); - it("Should allow first user to claim the request of 10 WETH, no loss", async () => { + it("Should allow first user to claim the request of 10 WETH", async () => { const { oethVault, daniel } = fixture; const fixtureWithUser = { ...fixture, user: daniel }; const dataBefore = await snapData(fixtureWithUser); const tx = await oethVault.connect(daniel).claimWithdrawal(0); - await expect(tx) + expect(tx) .to.emit(oethVault, "WithdrawalClaimed") .withArgs(daniel.address, 0, oethUnits("10")); @@ -2021,27 +2021,88 @@ describe("OETH Vault", function () { await expect(tx).to.be.revertedWith("Queue pending liquidity"); }); - it("Should allow a user to create a new request, with the vault insolvent and solvency check off", async () => { + it("Should allow a user to create a new request with solvency check off", async () => { // maxSupplyDiff is set to 0 so no insolvency check const { oethVault, matt } = fixture; + const fixtureWithUser = { ...fixture, user: matt }; + const dataBefore = await snapData(fixtureWithUser); const tx = oethVault.connect(matt).requestWithdrawal(oethUnits("10")); - await expect(tx) + expect(tx) .to.emit(oethVault, "WithdrawalRequested") .withArgs(matt.address, 3, oethUnits("10"), oethUnits("50")); + + await assertChangedData( + dataBefore, + { + oethTotalSupply: oethUnits("10").mul(-1), + oethTotalValue: oethUnits("10").mul(-1), + vaultCheckBalance: oethUnits("10").mul(-1), + userOeth: oethUnits("10").mul(-1), + userWeth: 0, + vaultWeth: 0, + queued: oethUnits("10").mul(1), + claimable: 0, + claimed: 0, + nextWithdrawalIndex: 1, + }, + fixtureWithUser + ); }); - it("Fail to allow user to create a new request, with the vault insolvent and solvency check at 3%", async () => { - const { oethVault, matt } = fixture; + describe("with solvency check at 3%", () => { + beforeEach(async () => { + const { oethVault } = fixture; + // Turn on insolvency check with 3% buffer + await oethVault + .connect(await impersonateAndFund(await oethVault.governor())) + .setMaxSupplyDiff(oethUnits("0.03")); + }); + it("Fail to allow user to create a new request due to insolvency check", async () => { + const { oethVault, matt } = fixture; - // Turn on insolvency check with 3% buffer - await oethVault - .connect(await impersonateAndFund(await oethVault.governor())) - .setMaxSupplyDiff(oethUnits("0.03")); + const tx = oethVault.connect(matt).requestWithdrawal(oethUnits("1")); + + await expect(tx).to.be.revertedWith("Backing supply liquidity error"); + }); + it("Fail to allow first user to claim a withdrawal due to insolvency check", async () => { + const { oethVault, daniel } = fixture; + + await advanceTime(delayPeriod); + + const tx = oethVault.connect(daniel).claimWithdrawal(0); + + await expect(tx).to.be.revertedWith("Backing supply liquidity error"); + }); + }); + describe("with solvency check at 10%", () => { + beforeEach(async () => { + const { oethVault } = fixture; + // Turn on insolvency check with 10% buffer + await oethVault + .connect(await impersonateAndFund(await oethVault.governor())) + .setMaxSupplyDiff(oethUnits("0.1")); + }); + it("Should allow user to create a new request", async () => { + const { oethVault, matt } = fixture; - const tx = oethVault.connect(matt).requestWithdrawal(oethUnits("1")); + const tx = await oethVault + .connect(matt) + .requestWithdrawal(oethUnits("1")); - await expect(tx).to.be.revertedWith("Backing supply liquidity error"); + expect(tx) + .to.emit(oethVault, "WithdrawalRequested") + .withArgs(matt.address, 3, oethUnits("1"), oethUnits("41")); + }); + it("Should allow first user to claim the request of 10 WETH", async () => { + const { oethVault, daniel } = fixture; + + const tx = await oethVault.connect(daniel).claimWithdrawal(0); + + expect(tx) + .to.emit(oethVault, "WithdrawalClaimed") + .withArgs(daniel.address, 0, oethUnits("10")); + }); }); }); }); From fb765e1a56ee2a65f30992368d5dd9f4ede1a43f Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Fri, 26 Jul 2024 14:05:42 +1000 Subject: [PATCH 178/273] Fix _totalValue so it handles when vault value is less than the outstanding withdrawal requests --- contracts/contracts/vault/OETHVaultCore.sol | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/contracts/contracts/vault/OETHVaultCore.sol b/contracts/contracts/vault/OETHVaultCore.sol index 0505cbe49d..89fa150684 100644 --- a/contracts/contracts/vault/OETHVaultCore.sol +++ b/contracts/contracts/vault/OETHVaultCore.sol @@ -440,10 +440,18 @@ contract OETHVaultCore is VaultCore { value = _totalValueInVault() + _totalValueInStrategies(); // Need to remove WETH that is reserved for the withdrawal queue. - // reserved for the withdrawal queue = cumulative queued total - total claimed WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata; - if (value + queue.claimed >= queue.queued) { - return value + queue.claimed - queue.queued; + // reserved for the withdrawal queue = cumulative queued total - total claimed + uint256 reservedForQueue = queue.queued - queue.claimed; + + if (reservedForQueue > 0) { + if (value > reservedForQueue) { + return value - reservedForQueue; + } + // This can happen if the vault becomes insolvent enough that the + // total value in the vault and all strategies < outstanding withdrawals. + // For example, there was a mass slashing event and most users request to withdraw. + return 0; } } From f3053f20a352048bedc1c84c69e20ad50438d6ef Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Fri, 26 Jul 2024 14:10:55 +1000 Subject: [PATCH 179/273] Added SafeCast to unit128 --- contracts/contracts/vault/OETHVaultCore.sol | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/contracts/contracts/vault/OETHVaultCore.sol b/contracts/contracts/vault/OETHVaultCore.sol index 89fa150684..2fbcef0e94 100644 --- a/contracts/contracts/vault/OETHVaultCore.sol +++ b/contracts/contracts/vault/OETHVaultCore.sol @@ -1,11 +1,12 @@ // 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"; @@ -185,7 +186,9 @@ contract OETHVaultCore is VaultCore { queued = withdrawalQueueMetadata.queued + _amount; // store the next withdrawal request - withdrawalQueueMetadata.nextWithdrawalIndex = uint128(requestId + 1); + withdrawalQueueMetadata.nextWithdrawalIndex = SafeCast.toUint128( + requestId + 1 + ); withdrawalQueueMetadata.queued = uint128(queued); emit WithdrawalRequested(msg.sender, requestId, _amount, queued); From 22b8b2b04ee7a26365623d649f0206dd7660ce56 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Fri, 26 Jul 2024 16:49:05 +1000 Subject: [PATCH 180/273] Reject redeems and withdrawals if no available assets due to insolvency --- contracts/contracts/vault/VaultCore.sol | 7 +- contracts/test/vault/oeth-vault.js | 146 ++++++++++++++++++++++++ 2 files changed, 152 insertions(+), 1 deletion(-) diff --git a/contracts/contracts/vault/VaultCore.sol b/contracts/contracts/vault/VaultCore.sol index d2144004da..fa3568ab2e 100644 --- a/contracts/contracts/vault/VaultCore.sol +++ b/contracts/contracts/vault/VaultCore.sol @@ -224,7 +224,12 @@ contract VaultCore is VaultInitializer { } // Check that the OTokens are backed by enough assets - if (maxSupplyDiff > 0 && totalUnits > 0) { + 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); diff --git a/contracts/test/vault/oeth-vault.js b/contracts/test/vault/oeth-vault.js index 0002a109ed..13117a07b3 100644 --- a/contracts/test/vault/oeth-vault.js +++ b/contracts/test/vault/oeth-vault.js @@ -2105,5 +2105,151 @@ describe("OETH Vault", function () { }); }); }); + describe("with 99 WETH in the queue, 40 WETH in the vault, total supply 1, 1% insolvency buffer", () => { + let mockStrategy; + beforeEach(async () => { + const { governor, oethVault, weth, daniel, josh, matt, strategist } = + fixture; + // Deploy a mock strategy + mockStrategy = await deployWithConfirmation("MockStrategy"); + await oethVault.connect(governor).approveStrategy(mockStrategy.address); + await oethVault + .connect(governor) + .setAssetDefaultStrategy(weth.address, mockStrategy.address); + + // Mint 100 OETH to three users + await oethVault + .connect(daniel) + .mint(weth.address, oethUnits("20"), "0"); + await oethVault.connect(josh).mint(weth.address, oethUnits("30"), "0"); + await oethVault.connect(matt).mint(weth.address, oethUnits("50"), "0"); + + // Request and claim 20 + 30 + 49 = 99 WETH from Vault + await oethVault.connect(daniel).requestWithdrawal(oethUnits("20")); + await oethVault.connect(josh).requestWithdrawal(oethUnits("30")); + await oethVault.connect(matt).requestWithdrawal(oethUnits("49")); + + await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. + + // Strategist sends 40 WETH to the vault + await oethVault + .connect(strategist) + .withdrawFromStrategy( + mockStrategy.address, + [weth.address], + [oethUnits("40")] + ); + + await oethVault.connect(josh).addWithdrawalQueueLiquidity(); + + // Turn on insolvency check with 10% buffer + await oethVault + .connect(await impersonateAndFund(await oethVault.governor())) + .setMaxSupplyDiff(oethUnits("0.01")); + }); + describe("with 2 ether slashed leaving 100 - 40 - 2 = 58 WETH in the strategy", () => { + beforeEach(async () => { + const { weth } = fixture; + + // Simulate slash event of 2 ethers + await weth + .connect(await impersonateAndFund(mockStrategy.address)) + .transfer(addresses.dead, oethUnits("2")); + }); + it("Should have total value of zero", async () => { + // 100 from mints - 99 outstanding withdrawals - 2 from slashing = -1 value which is rounder up to zero + expect(await fixture.oethVault.totalValue()).to.equal(0); + }); + it("Fail to allow user to create a new request due to too many outstanding requests", async () => { + const { oethVault, matt } = fixture; + + const tx = oethVault.connect(matt).requestWithdrawal(oethUnits("1")); + + await expect(tx).to.be.revertedWith("Too many outstanding requests"); + }); + it("Fail to allow first user to claim a withdrawal due to too many outstanding requests", async () => { + const { oethVault, daniel } = fixture; + + await advanceTime(delayPeriod); + + const tx = oethVault.connect(daniel).claimWithdrawal(0); + + await expect(tx).to.be.revertedWith("Too many outstanding requests"); + }); + }); + describe("with 1 ether slashed leaving 100 - 40 - 1 = 59 WETH in the strategy", () => { + beforeEach(async () => { + const { weth } = fixture; + + // Simulate slash event of 1 ethers + await weth + .connect(await impersonateAndFund(mockStrategy.address)) + .transfer(addresses.dead, oethUnits("1")); + }); + it("Should have total value of zero", async () => { + // 100 from mints - 99 outstanding withdrawals - 1 from slashing = 0 value + expect(await fixture.oethVault.totalValue()).to.equal(0); + }); + it("Fail to allow user to create a new request due to too many outstanding requests", async () => { + const { oethVault, matt } = fixture; + + const tx = oethVault.connect(matt).requestWithdrawal(oethUnits("1")); + + await expect(tx).to.be.revertedWith("Too many outstanding requests"); + }); + it("Fail to allow first user to claim a withdrawal due to too many outstanding requests", async () => { + const { oethVault, daniel } = fixture; + + await advanceTime(delayPeriod); + + const tx = oethVault.connect(daniel).claimWithdrawal(0); + + await expect(tx).to.be.revertedWith("Too many outstanding requests"); + }); + }); + describe("with 0.02 ether slashed leaving 100 - 40 - 0.02 = 59.98 WETH in the strategy", () => { + beforeEach(async () => { + const { weth } = fixture; + + // Simulate slash event of 0.001 ethers + await weth + .connect(await impersonateAndFund(mockStrategy.address)) + .transfer(addresses.dead, oethUnits("0.02")); + }); + it("Should have total value of zero", async () => { + // 100 from mints - 99 outstanding withdrawals - 0.001 from slashing = 0.999 total value + expect(await fixture.oethVault.totalValue()).to.equal( + oethUnits("0.98") + ); + }); + it("Fail to allow user to create a new 1 WETH request due to too many outstanding requests", async () => { + const { oethVault, matt } = fixture; + + const tx = oethVault.connect(matt).requestWithdrawal(oethUnits("1")); + + await expect(tx).to.be.revertedWith("Too many outstanding requests"); + }); + + it("Fail to allow user to create a new 0.01 WETH request due to insolvency check", async () => { + const { oethVault, matt } = fixture; + + const tx = oethVault + .connect(matt) + .requestWithdrawal(oethUnits("0.01")); + + await expect(tx).to.be.revertedWith("Backing supply liquidity error"); + }); + it("Fail to allow first user to claim a withdrawal due to insolvency check", async () => { + const { oethVault, daniel } = fixture; + + await advanceTime(delayPeriod); + + const tx = oethVault.connect(daniel).claimWithdrawal(0); + + // diff = 1 total supply / 0.98 assets = 1.020408163265306122 which is > 1 maxSupplyDiff + await expect(tx).to.be.revertedWith("Backing supply liquidity error"); + }); + }); + }); }); }); From e59268fdce7d1d529b59afe716a276772f847396 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Fri, 26 Jul 2024 17:37:09 +1000 Subject: [PATCH 181/273] Redeem to no longer try and get liquidity from the default strategy if not enough available WETH in the vault --- contracts/contracts/vault/OETHVaultCore.sol | 22 ++--- contracts/test/vault/oeth-vault.js | 90 +++++++++------------ 2 files changed, 45 insertions(+), 67 deletions(-) diff --git a/contracts/contracts/vault/OETHVaultCore.sol b/contracts/contracts/vault/OETHVaultCore.sol index 2fbcef0e94..e7cae61b7f 100644 --- a/contracts/contracts/vault/OETHVaultCore.sol +++ b/contracts/contracts/vault/OETHVaultCore.sol @@ -137,21 +137,11 @@ contract OETHVaultCore is VaultCore { "Redeem amount lower than minimum" ); - // If there is any WETH in the Vault available after accounting for the withdrawal queue - if (_wethAvailable() >= 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); @@ -354,6 +344,8 @@ contract OETHVaultCore is VaultCore { 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; diff --git a/contracts/test/vault/oeth-vault.js b/contracts/test/vault/oeth-vault.js index 13117a07b3..17f37d05cb 100644 --- a/contracts/test/vault/oeth-vault.js +++ b/contracts/test/vault/oeth-vault.js @@ -78,7 +78,7 @@ describe("OETH Vault", function () { }; describe("Mint", () => { - it("should mint with WETH", async () => { + it("Should mint with WETH", async () => { const { oethVault, weth, josh } = fixture; const fixtureWithUser = { ...fixture, user: josh }; @@ -115,7 +115,7 @@ describe("OETH Vault", function () { ); }); - it("should not mint with any other asset", async () => { + it("Fail to mint with any other asset", async () => { const { oethVault, frxETH, stETH, reth, josh } = fixture; const amount = parseUnits("1", 18); @@ -129,14 +129,14 @@ describe("OETH Vault", function () { } }); - it("should revert if mint amount is zero", async () => { + it("Fail to mint if amount is zero", async () => { const { oethVault, weth, josh } = fixture; const tx = oethVault.connect(josh).mint(weth.address, "0", "0"); await expect(tx).to.be.revertedWith("Amount must be greater than 0"); }); - it("should revert if capital is paused", async () => { + it("Fail to mint if capital is paused", async () => { const { oethVault, weth, governor } = fixture; await oethVault.connect(governor).pauseCapital(); @@ -190,7 +190,7 @@ describe("OETH Vault", function () { }); describe("Redeem", () => { - it("should return only WETH in redeem calculations", async () => { + it("Should return only WETH in redeem calculations", async () => { const { oethVault, weth } = fixture; const outputs = await oethVault.calculateRedeemOutputs( @@ -208,7 +208,7 @@ describe("OETH Vault", function () { } }); - it("should revert if WETH index isn't cached", async () => { + it("Fail to calculateRedeemOutputs if WETH index isn't cached", async () => { const { frxETH, weth } = fixture; await deployWithConfirmation("MockOETHVault", [weth.address]); @@ -220,7 +220,7 @@ describe("OETH Vault", function () { await expect(tx).to.be.revertedWith("WETH Asset index not cached"); }); - it("should update total supply correctly without redeem fee", async () => { + it("Should update total supply correctly without redeem fee", async () => { const { oethVault, oeth, weth, daniel } = fixture; await oethVault.connect(daniel).mint(weth.address, oethUnits("10"), "0"); @@ -240,7 +240,7 @@ describe("OETH Vault", function () { expect(supplyBefore.sub(supplyAfter)).to.eq(oethUnits("10")); }); - it("should update total supply correctly with redeem fee", async () => { + it("Should update total supply correctly with redeem fee", async () => { const { oethVault, oeth, weth, daniel } = fixture; await oethVault.connect(daniel).mint(weth.address, oethUnits("10"), "0"); @@ -268,7 +268,7 @@ describe("OETH Vault", function () { expect(supplyBefore.sub(supplyAfter)).to.eq(oethUnits("10")); }); - it("Should withdraw from strategy if necessary", async () => { + it("Fail to redeem if not enough liquidity available in the vault", async () => { const { oethVault, weth, domen, governor } = fixture; const mockStrategy = await deployWithConfirmation("MockStrategy"); @@ -284,40 +284,26 @@ describe("OETH Vault", function () { // Mint a small amount that won't get allocated to the strategy await oethVault.connect(domen).mint(weth.address, oethUnits("1.23"), "0"); - const vaultBalanceBefore = await weth.balanceOf(oethVault.address); - const stratBalanceBefore = await weth.balanceOf(mockStrategy.address); - const userBalanceBefore = await weth.balanceOf(domen.address); - // Withdraw something more than what the Vault holds - await oethVault.connect(domen).redeem(oethUnits("12.55"), "0"); - - const vaultBalanceAfter = await weth.balanceOf(oethVault.address); - const stratBalanceAfter = await weth.balanceOf(mockStrategy.address); - const userBalanceAfter = await weth.balanceOf(domen.address); - - expect(userBalanceAfter.sub(userBalanceBefore)).to.eq(oethUnits("12.55")); - - expect(stratBalanceBefore.sub(stratBalanceAfter)).to.eq( - oethUnits("12.55") - ); + const tx = oethVault.connect(domen).redeem(oethUnits("12.55"), "0"); - expect(vaultBalanceBefore).to.eq(vaultBalanceAfter); + await expect(tx).to.revertedWith("Liquidity error"); }); - it("should redeem zero amount without revert", async () => { + it("Should redeem zero amount without revert", async () => { const { oethVault, daniel } = fixture; await oethVault.connect(daniel).redeem(0, 0); }); - it("should revert on liquidity error", async () => { + it("Fail to redeem if not enough liquidity", async () => { const { oethVault, daniel } = fixture; const tx = oethVault .connect(daniel) .redeem(oethUnits("1023232323232"), "0"); await expect(tx).to.be.revertedWith("Liquidity error"); }); - it("should allow every user to redeem", async () => { + it("Should allow every user to redeem", async () => { const { oethVault, weth, daniel } = fixture; await oethVault.connect(daniel).mint(weth.address, oethUnits("10"), "0"); @@ -328,7 +314,7 @@ describe("OETH Vault", function () { }); describe("Config", () => { - it("should allow caching WETH index", async () => { + it("Should allow caching WETH index", async () => { const { oethVault, weth, governor } = fixture; await oethVault.connect(governor).cacheWETHAssetIndex(); @@ -340,14 +326,14 @@ describe("OETH Vault", function () { expect(assets[index]).to.equal(weth.address); }); - it("should not allow anyone other than Governor to change cached index", async () => { + it("Fail to allow anyone other than Governor to change cached index", async () => { const { oethVault, strategist } = fixture; const tx = oethVault.connect(strategist).cacheWETHAssetIndex(); await expect(tx).to.be.revertedWith("Caller is not the Governor"); }); - it("should revert if WETH is not an supported asset", async () => { + it("Fail to cacheWETHAssetIndex if WETH is not a supported asset", async () => { const { frxETH, weth } = fixture; const { deployerAddr } = await hre.getNamedAccounts(); const sDeployer = hre.ethers.provider.getSigner(deployerAddr); @@ -361,7 +347,7 @@ describe("OETH Vault", function () { await expect(tx).to.be.revertedWith("Invalid WETH Asset Index"); }); - it("should return all strategies", async () => { + it("Should return all strategies", async () => { // Mostly to increase coverage const { oethVault, weth, governor } = fixture; @@ -380,7 +366,7 @@ describe("OETH Vault", function () { }); describe("Remove Asset", () => { - it("should allow removing a single asset", async () => { + it("Should allow removing a single asset", async () => { const { oethVault, frxETH, governor } = fixture; const vaultAdmin = await ethers.getContractAt( @@ -413,7 +399,7 @@ describe("OETH Vault", function () { expect(config.isSupported).to.be.false; }); - it("should only allow governance to remove assets", async () => { + it("Should only allow governance to remove assets", async () => { const { oethVault, weth, strategist, josh } = fixture; for (const signer of [strategist, josh]) { @@ -425,14 +411,14 @@ describe("OETH Vault", function () { } }); - it("should revert if asset is not supported", async () => { + it("Fail to remove asset if asset is not supported", async () => { const { oethVault, dai, governor } = fixture; const tx = oethVault.connect(governor).removeAsset(dai.address); await expect(tx).to.be.revertedWith("Asset not supported"); }); - it("should revert if vault still holds the asset", async () => { + it("Fail to remove asset if vault still holds the asset", async () => { const { oethVault, weth, governor, daniel } = fixture; await oethVault.connect(daniel).mint(weth.address, oethUnits("1"), "0"); @@ -442,7 +428,7 @@ describe("OETH Vault", function () { await expect(tx).to.be.revertedWith("Vault still holds asset"); }); - it("should not revert for smaller dust", async () => { + it("Fail to revert for smaller dust", async () => { const { oethVault, weth, governor, daniel } = fixture; await oethVault.connect(daniel).mint(weth.address, "500000000000", "0"); @@ -452,7 +438,7 @@ describe("OETH Vault", function () { await expect(tx).to.not.be.revertedWith("Vault still holds asset"); }); - it("should allow strategy to burnForStrategy", async () => { + it("Should allow strategy to burnForStrategy", async () => { const { oethVault, oeth, weth, governor, daniel } = fixture; await oethVault.connect(governor).setOusdMetaStrategy(daniel.address); @@ -708,7 +694,7 @@ describe("OETH Vault", function () { }); const firstRequestAmount = oethUnits("5"); const secondRequestAmount = oethUnits("18"); - it("should request first withdrawal by Daniel", async () => { + it("Should request first withdrawal by Daniel", async () => { const { oethVault, daniel } = fixture; const fixtureWithUser = { ...fixture, user: daniel }; const dataBefore = await snapData(fixtureWithUser); @@ -738,7 +724,7 @@ describe("OETH Vault", function () { fixtureWithUser ); }); - it("should request withdrawal of zero amount", async () => { + it("Should request withdrawal of zero amount", async () => { const { oethVault, josh } = fixture; const fixtureWithUser = { ...fixture, user: josh }; await oethVault.connect(josh).requestWithdrawal(firstRequestAmount); @@ -767,7 +753,7 @@ describe("OETH Vault", function () { fixtureWithUser ); }); - it("should request first and second withdrawals with no WETH in the Vault", async () => { + it("Should request first and second withdrawals with no WETH in the Vault", async () => { const { oethVault, governor, josh, matt, weth } = fixture; const fixtureWithUser = { ...fixture, user: josh }; @@ -820,7 +806,7 @@ describe("OETH Vault", function () { fixtureWithUser ); }); - it("should request second withdrawal by matt", async () => { + it("Should request second withdrawal by matt", async () => { const { oethVault, daniel, matt } = fixture; const fixtureWithUser = { ...fixture, user: matt }; await oethVault.connect(daniel).requestWithdrawal(firstRequestAmount); @@ -1098,7 +1084,7 @@ describe("OETH Vault", function () { await oethVault.connect(daniel).requestWithdrawal(firstRequestAmount); await oethVault.connect(josh).requestWithdrawal(secondRequestAmount); }); - it("Should not deposit allocated WETH to a strategy", async () => { + it("Fail to deposit allocated WETH to a strategy", async () => { const { oethVault, weth, governor } = fixture; // WETH in the vault = 60 - 15 = 45 WETH @@ -1114,7 +1100,7 @@ describe("OETH Vault", function () { ); await expect(tx).to.be.revertedWith("Not enough WETH available"); }); - it("should not deposit allocated WETH during allocate", async () => { + it("Fail to deposit allocated WETH during allocate", async () => { const { oethVault, governor, weth } = fixture; // Set mock strategy as default strategy @@ -1639,7 +1625,7 @@ describe("OETH Vault", function () { await expect(tx).to.be.revertedWith("Not enough WETH available"); }); - it("Should not allocate any WETH to the default strategy", async () => { + it("Fail to allocate any WETH to the default strategy", async () => { const { oethVault, domen } = fixture; const tx = await oethVault.connect(domen).allocate(); @@ -1682,7 +1668,7 @@ describe("OETH Vault", function () { await expect(tx).to.be.revertedWith("Not enough WETH available"); }); - it("Should not allocate any WETH to the default strategy", async () => { + it("Fail to allocate any WETH to the default strategy", async () => { const { oethVault, domen } = fixture; const tx = await oethVault.connect(domen).allocate(); @@ -1774,7 +1760,7 @@ describe("OETH Vault", function () { await oethVault.connect(daniel).claimWithdrawal(0); await oethVault.connect(josh).claimWithdrawal(1); }); - it("should allow the last user to request the remaining 10 WETH", async () => { + it("Should allow the last user to request the remaining 10 WETH", async () => { const { oethVault, matt } = fixture; const fixtureWithUser = { ...fixture, user: matt }; const dataBefore = await snapData(fixtureWithUser); @@ -1804,7 +1790,7 @@ describe("OETH Vault", function () { fixtureWithUser ); }); - it("should allow the last user to claim the request of 10 WETH", async () => { + it("Should allow the last user to claim the request of 10 WETH", async () => { const { oethVault, matt } = fixture; const fixtureWithUser = { ...fixture, user: matt }; await oethVault.connect(matt).requestWithdrawal(oethUnits("10")); @@ -1852,7 +1838,7 @@ describe("OETH Vault", function () { await oethVault.connect(matt).requestWithdrawal(oethUnits("40")); await advanceTime(delayPeriod); // Advance in time to ensure time delay between request and claim. }); - it("should allow user to claim the request of 40 WETH", async () => { + it("Should allow user to claim the request of 40 WETH", async () => { const { oethVault, matt } = fixture; const fixtureWithUser = { ...fixture, user: matt }; const dataBefore = await snapData(fixtureWithUser); @@ -1880,7 +1866,7 @@ describe("OETH Vault", function () { fixtureWithUser ); }); - it("should allow user to perform a new request and claim a smaller than the WETH available", async () => { + it("Should allow user to perform a new request and claim a smaller than the WETH available", async () => { const { oethVault, josh } = fixture; await oethVault.connect(josh).requestWithdrawal(oethUnits("20")); @@ -1890,7 +1876,7 @@ describe("OETH Vault", function () { await expect(tx).to.emit(oethVault, "WithdrawalClaimed"); }); - it("should allow user to perform a new request and claim exactly the WETH available", async () => { + it("Should allow user to perform a new request and claim exactly the WETH available", async () => { const { oethVault, oeth, josh, matt, daniel } = fixture; await oethVault.connect(matt).claimWithdrawal(0); // All user give OETH to another user @@ -1928,7 +1914,7 @@ describe("OETH Vault", function () { fixtureWithUser ); }); - it("shouldn't allow user to perform a new request and claim more than the WETH available", async () => { + it("Shouldn't allow user to perform a new request and claim more than the WETH available", async () => { const { oethVault, oeth, weth, josh, matt, daniel } = fixture; await oethVault.connect(matt).claimWithdrawal(0); // All user give OETH to another user From 74afa41aee0069b992cea9bbac8b955331d8846c Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Fri, 26 Jul 2024 18:47:53 +1000 Subject: [PATCH 182/273] Simplify _wethAvailable --- contracts/contracts/vault/OETHVaultCore.sol | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/contracts/contracts/vault/OETHVaultCore.sol b/contracts/contracts/vault/OETHVaultCore.sol index e7cae61b7f..08f09c7562 100644 --- a/contracts/contracts/vault/OETHVaultCore.sol +++ b/contracts/contracts/vault/OETHVaultCore.sol @@ -349,14 +349,15 @@ contract OETHVaultCore is VaultCore { function _wethAvailable() internal view returns (uint256 wethAvailable) { WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata; - // Check if the claimable WETH is less than the queued amount - uint256 queueShortfall = queue.queued - queue.claimable; + // 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)); - // Of the claimable withdrawal requests, how much is unclaimed? - uint256 unclaimed = queue.claimable - queue.claimed; - if (wethBalance > queueShortfall + unclaimed) { - wethAvailable = wethBalance - queueShortfall - unclaimed; + // If there is more WETH in the vault than the outstanding withdrawals + if (wethBalance > outstandingWithdrawals) { + wethAvailable = wethBalance - outstandingWithdrawals; } } From dc46164872c4fc1f76748cb4387e26d1588c0d3b Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Fri, 26 Jul 2024 20:45:50 +1000 Subject: [PATCH 183/273] refactor of _claimWithdrawal --- contracts/contracts/vault/OETHVaultCore.sol | 62 +++++++++++---------- contracts/test/vault/oeth-vault.js | 3 + 2 files changed, 36 insertions(+), 29 deletions(-) diff --git a/contracts/contracts/vault/OETHVaultCore.sol b/contracts/contracts/vault/OETHVaultCore.sol index 08f09c7562..f2ec1d5be9 100644 --- a/contracts/contracts/vault/OETHVaultCore.sol +++ b/contracts/contracts/vault/OETHVaultCore.sol @@ -198,9 +198,9 @@ contract OETHVaultCore is VaultCore { /** * @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 30 minutes has passed. + * 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 30 minutes, the transaction will revert with `Claim delay not met`. + * 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 @@ -211,6 +211,18 @@ contract OETHVaultCore is VaultCore { 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 @@ -223,9 +235,9 @@ contract OETHVaultCore is VaultCore { /** * @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 30 minutes has passed. + * 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 30 minutes, + * 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 @@ -237,6 +249,15 @@ contract OETHVaultCore is VaultCore { 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]); @@ -250,50 +271,33 @@ contract OETHVaultCore is VaultCore { _postRedeem(totalAmount); } - // slither-disable-start reentrancy-no-eth - function _claimWithdrawal(uint256 requestId) internal returns (uint256 amount) { - // Check if there's enough liquidity to cover the withdrawal request - WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata; + // Load the structs from storage into memory WithdrawalRequest memory request = withdrawalRequests[requestId]; + WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata; - require(request.claimed == false, "Already claimed"); - require(request.withdrawer == msg.sender, "Not requester"); 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"); - // Try and get more liquidity in the withdrawal queue if there is not enough - if (request.queued > queue.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 - uint256 addedClaimable = _addWithdrawalQueueLiquidity(); - - // If there still isn't enough liquidity in the queue to claim, revert - require( - request.queued <= queue.claimable + addedClaimable, - "Queue pending liquidity" - ); - } - - // Store the updated claimed amount - withdrawalQueueMetadata.claimed = queue.claimed + request.amount; // 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; } - // slither-disable-end reentrancy-no-eth - /// @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. diff --git a/contracts/test/vault/oeth-vault.js b/contracts/test/vault/oeth-vault.js index 17f37d05cb..92d7571af9 100644 --- a/contracts/test/vault/oeth-vault.js +++ b/contracts/test/vault/oeth-vault.js @@ -1501,6 +1501,9 @@ describe("OETH Vault", function () { it("the first withdrawal with wrong withdrawer", async () => { const { oethVault, matt } = fixture; + // Advance in time to ensure time delay between request and claim. + await advanceTime(delayPeriod); + const tx = oethVault.connect(matt).claimWithdrawal(2); await expect(tx).to.be.revertedWith("Not requester"); From 4f5a57d1db46f70fe2d9311f88df6c103a69a029 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Fri, 26 Jul 2024 20:49:39 +1000 Subject: [PATCH 184/273] Generated latest OETHVaultCore diagram --- contracts/docs/OETHVaultCoreSquashed.svg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/docs/OETHVaultCoreSquashed.svg b/contracts/docs/OETHVaultCoreSquashed.svg index 63f3a01825..dfca8fbe99 100644 --- a/contracts/docs/OETHVaultCoreSquashed.svg +++ b/contracts/docs/OETHVaultCoreSquashed.svg @@ -100,7 +100,7 @@    redeem(_amount: uint256, _minimumUnitAmount: uint256) <<whenNotCapitalPaused, nonReentrant>> <<VaultCore>>    burnForStrategy(_amount: uint256) <<whenNotCapitalPaused, onlyOusdMetaStrategy>> <<VaultCore>>    redeemAll(_minimumUnitAmount: uint256) <<whenNotCapitalPaused, nonReentrant>> <<VaultCore>> -    allocate() <<whenNotCapitalPaused, nonReentrant>> <<VaultCore>> +    allocate() <<whenNotCapitalPaused, nonReentrant>> <<OETHVaultCore>>    rebase() <<nonReentrant>> <<VaultCore>>    totalValue(): (value: uint256) <<VaultCore>>    checkBalance(_asset: address): uint256 <<VaultCore>> From 193ad6dae2618d93de936e18ecd86786de8210b8 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Fri, 26 Jul 2024 21:06:45 +1000 Subject: [PATCH 185/273] Fix Slither --- contracts/contracts/vault/OETHVaultCore.sol | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/contracts/contracts/vault/OETHVaultCore.sol b/contracts/contracts/vault/OETHVaultCore.sol index f2ec1d5be9..c468f3e11c 100644 --- a/contracts/contracts/vault/OETHVaultCore.sol +++ b/contracts/contracts/vault/OETHVaultCore.sol @@ -195,6 +195,8 @@ contract OETHVaultCore is VaultCore { _postRedeem(_amount); } + + // 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 @@ -232,6 +234,8 @@ contract OETHVaultCore is VaultCore { _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 From f4de2e6b8a588414ed7d626e1e7a81b1ef9134e8 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Fri, 26 Jul 2024 21:19:59 +1000 Subject: [PATCH 186/273] Updated the other _wethAvailable function --- contracts/contracts/vault/OETHVaultAdmin.sol | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/contracts/contracts/vault/OETHVaultAdmin.sol b/contracts/contracts/vault/OETHVaultAdmin.sol index 5c067f9475..9365400003 100644 --- a/contracts/contracts/vault/OETHVaultAdmin.sol +++ b/contracts/contracts/vault/OETHVaultAdmin.sol @@ -78,14 +78,15 @@ contract OETHVaultAdmin is VaultAdmin { function _wethAvailable() internal view returns (uint256 wethAvailable) { WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata; - // Check if the claimable WETH is less than the queued amount - uint256 queueShortfall = queue.queued - queue.claimable; + // 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)); - // Of the claimable withdrawal requests, how much is unclaimed? - uint256 unclaimed = queue.claimable - queue.claimed; - if (wethBalance > queueShortfall + unclaimed) { - wethAvailable = wethBalance - queueShortfall - unclaimed; + // If there is more WETH in the vault than the outstanding withdrawals + if (wethBalance > outstandingWithdrawals) { + wethAvailable = wethBalance - outstandingWithdrawals; } } From b9d5e00de55cf74c3fee551010436f9974f34ef6 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Fri, 26 Jul 2024 22:14:49 +1000 Subject: [PATCH 187/273] Set Vault buffer to 0.2% --- contracts/deploy/mainnet/103_oeth_withdraw_queue.js | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/contracts/deploy/mainnet/103_oeth_withdraw_queue.js b/contracts/deploy/mainnet/103_oeth_withdraw_queue.js index b46e5e84ba..d556ca89d2 100644 --- a/contracts/deploy/mainnet/103_oeth_withdraw_queue.js +++ b/contracts/deploy/mainnet/103_oeth_withdraw_queue.js @@ -1,4 +1,4 @@ -const { formatUnits } = require("ethers/lib/utils"); +const { formatUnits, parseEther } = require("ethers/lib/utils"); const addresses = require("../../utils/addresses"); const { deploymentWithGovernanceProposal } = require("../../utils/deploy"); @@ -118,6 +118,17 @@ module.exports = deploymentWithGovernanceProposal( signature: "setAssetDefaultStrategy(address,address)", args: [addresses.mainnet.WETH, cNativeStakingStrategy2Proxy.address], }, + // 10. Allocate WETH to the second Native Staking Strategy + { + contract: cVault, + signature: "allocate()", + }, + // 11. Set Vault buffer to 0.2% + { + contract: cVault, + signature: "setVaultBuffer(uint256)", + args: [parseEther("0.002")], + }, ], }; } From acf271d5bd9d2dd0b03433c6841052ad6048cfb2 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Fri, 26 Jul 2024 22:20:32 +1000 Subject: [PATCH 188/273] Swapped order in deploy script --- contracts/deploy/mainnet/103_oeth_withdraw_queue.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/contracts/deploy/mainnet/103_oeth_withdraw_queue.js b/contracts/deploy/mainnet/103_oeth_withdraw_queue.js index d556ca89d2..44eaba2246 100644 --- a/contracts/deploy/mainnet/103_oeth_withdraw_queue.js +++ b/contracts/deploy/mainnet/103_oeth_withdraw_queue.js @@ -118,16 +118,16 @@ module.exports = deploymentWithGovernanceProposal( signature: "setAssetDefaultStrategy(address,address)", args: [addresses.mainnet.WETH, cNativeStakingStrategy2Proxy.address], }, - // 10. Allocate WETH to the second Native Staking Strategy + // 10. Set Vault buffer to 0.2% { contract: cVault, - signature: "allocate()", + signature: "setVaultBuffer(uint256)", + args: [parseEther("0.002")], }, - // 11. Set Vault buffer to 0.2% + // 11. Allocate WETH to the second Native Staking Strategy { contract: cVault, - signature: "setVaultBuffer(uint256)", - args: [parseEther("0.002")], + signature: "allocate()", }, ], }; From 5978d6dfe2a771c31a8478ed35e78a9791a974ed Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Mon, 29 Jul 2024 13:07:03 +1000 Subject: [PATCH 189/273] Simplify _totalValue logic --- contracts/contracts/vault/OETHVaultCore.sol | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/contracts/contracts/vault/OETHVaultCore.sol b/contracts/contracts/vault/OETHVaultCore.sol index c468f3e11c..6a04d9e0f6 100644 --- a/contracts/contracts/vault/OETHVaultCore.sol +++ b/contracts/contracts/vault/OETHVaultCore.sol @@ -195,7 +195,6 @@ contract OETHVaultCore is VaultCore { _postRedeem(_amount); } - // slither-disable-start reentrancy-no-eth /** * @notice Claim a previously requested withdrawal once it is claimable. @@ -448,15 +447,15 @@ contract OETHVaultCore is VaultCore { // reserved for the withdrawal queue = cumulative queued total - total claimed uint256 reservedForQueue = queue.queued - queue.claimed; - if (reservedForQueue > 0) { - if (value > reservedForQueue) { - return value - reservedForQueue; - } + if (value < reservedForQueue) { // This can happen if the vault becomes insolvent enough that the - // total value in the vault and all strategies < outstanding withdrawals. - // For example, there was a mass slashing event and most users request to withdraw. + // 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 From faa060aa4f07e5dab5f888e208885ac73ea44e4f Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Mon, 29 Jul 2024 13:36:56 +1000 Subject: [PATCH 190/273] Moved the burn of OETH lower in the request withdrawal --- contracts/contracts/vault/OETHVaultCore.sol | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/contracts/contracts/vault/OETHVaultCore.sol b/contracts/contracts/vault/OETHVaultCore.sol index 2afcbe2838..744b3ac445 100644 --- a/contracts/contracts/vault/OETHVaultCore.sol +++ b/contracts/contracts/vault/OETHVaultCore.sol @@ -171,21 +171,19 @@ contract OETHVaultCore is VaultCore { nonReentrant returns (uint256 requestId, uint256 queued) { - // Burn the user's OETH - // This also checks the requester has enough OETH to burn - oUSD.burn(msg.sender, _amount); + // 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 + // 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 = uint128(queued); - - emit WithdrawalRequested(msg.sender, requestId, _amount, queued); - + // Store the user's withdrawal request withdrawalRequests[requestId] = WithdrawalRequest({ withdrawer: msg.sender, claimed: false, @@ -194,8 +192,13 @@ contract OETHVaultCore is VaultCore { queued: uint128(queued) }); - // Prevent insolvency + // 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 From d16970d64e951f75f4bfacf0ca5a89f02801f5a7 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Mon, 29 Jul 2024 13:38:21 +1000 Subject: [PATCH 191/273] Added reentrant protection to addWithdrawalQueueLiquidity --- contracts/contracts/vault/OETHVaultCore.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/contracts/vault/OETHVaultCore.sol b/contracts/contracts/vault/OETHVaultCore.sol index 744b3ac445..eeb987bf9b 100644 --- a/contracts/contracts/vault/OETHVaultCore.sol +++ b/contracts/contracts/vault/OETHVaultCore.sol @@ -311,7 +311,7 @@ contract OETHVaultCore is VaultCore { /// 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 { + function addWithdrawalQueueLiquidity() external nonReentrant { // Stream any harvested rewards (WETH) that are available to the Vault IDripper(dripper).collect(); From b6a2fbbc2da601e9f8e37977031b470d7657d7f9 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Mon, 29 Jul 2024 14:49:19 +1000 Subject: [PATCH 192/273] Refactor _addWithdrawalQueueLiquidity Removed nonReentrant on addWithdrawalQueueLiquidity for now --- contracts/contracts/vault/OETHVaultCore.sol | 45 ++++++++++++--------- 1 file changed, 26 insertions(+), 19 deletions(-) diff --git a/contracts/contracts/vault/OETHVaultCore.sol b/contracts/contracts/vault/OETHVaultCore.sol index eeb987bf9b..72ae8f3368 100644 --- a/contracts/contracts/vault/OETHVaultCore.sol +++ b/contracts/contracts/vault/OETHVaultCore.sol @@ -311,7 +311,7 @@ contract OETHVaultCore is VaultCore { /// 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 nonReentrant { + function addWithdrawalQueueLiquidity() external { // Stream any harvested rewards (WETH) that are available to the Vault IDripper(dripper).collect(); @@ -329,28 +329,35 @@ contract OETHVaultCore is VaultCore { // Check if the claimable WETH is less than the queued amount uint256 queueShortfall = queue.queued - queue.claimable; - // No need to get WETH balance if all the withdrawal requests are claimable - if (queueShortfall > 0) { - uint256 wethBalance = IERC20(weth).balanceOf(address(this)); - - // Of the claimable withdrawal requests, how much is unclaimed? - uint256 unclaimed = queue.claimable - queue.claimed; - if (wethBalance > unclaimed) { - uint256 unallocatedWeth = wethBalance - unclaimed; + // No need to do anything is the withdrawal queue is full funded + if (queueShortfall == 0) { + return 0; + } - // the new claimable amount is the smaller of the queue shortfall or unallocated weth - addedClaimable = queueShortfall < unallocatedWeth - ? queueShortfall - : unallocatedWeth; - uint256 newClaimable = queue.claimable + addedClaimable; + uint256 wethBalance = IERC20(weth).balanceOf(address(this)); - // Store the new claimable amount back to storage - withdrawalQueueMetadata.claimable = uint128(newClaimable); + // 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; - // emit a WithdrawalClaimable event - emit WithdrawalClaimable(newClaimable, addedClaimable); - } + // 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 = uint128(newClaimable); + + // emit a WithdrawalClaimable event + emit WithdrawalClaimable(newClaimable, addedClaimable); } /*************************************** From 0ad9592c995957abbc5c22548e49bf8b54c72ad3 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Mon, 29 Jul 2024 17:22:41 +1000 Subject: [PATCH 193/273] Added vault buffer to snapVault Hardhat task --- contracts/tasks/vault.js | 51 ++++++++++++++++++++++++++++++++++------ 1 file changed, 44 insertions(+), 7 deletions(-) diff --git a/contracts/tasks/vault.js b/contracts/tasks/vault.js index a37296b969..3152dcb8ff 100644 --- a/contracts/tasks/vault.js +++ b/contracts/tasks/vault.js @@ -33,6 +33,8 @@ async function snapVault({ block }, hre) { const vaultProxy = await hre.ethers.getContract(`OETHVaultProxy`); const vault = await hre.ethers.getContractAt("IVault", vaultProxy.address); + const oethProxy = await hre.ethers.getContract(`OETHProxy`); + const oeth = await hre.ethers.getContractAt("OETH", oethProxy.address); const { chainId } = await hre.ethers.provider.getNetwork(); const wethAddress = addresses[networkMap[chainId]].WETH; @@ -49,18 +51,53 @@ async function snapVault({ block }, hre) { const unclaimed = queue.queued.sub(queue.claimed); const available = wethBalance.sub(unclaimed).sub(shortfall); - console.log(`Vault WETH : ${formatUnits(wethBalance)}, ${wethBalance} wei`); + const totalSupply = await oeth.totalSupply({ + blockTag, + }); - console.log(`Queued : ${formatUnits(queue.queued)}, ${queue.queued} wei`); + const totalAssets = await vault.totalValue({ + blockTag, + }); + const assetSupplyDiff = totalAssets.sub(totalSupply); + const vaultBufferPercentage = await vault.vaultBuffer({ + blockTag, + }); + const vaultBuffer = totalSupply + .mul(vaultBufferPercentage) + .div(parseUnits("1")); + + console.log( + `Vault WETH : ${formatUnits(wethBalance)}, ${wethBalance} wei` + ); + + console.log( + `Queued : ${formatUnits(queue.queued)}, ${queue.queued} wei` + ); + console.log( + `Claimable : ${formatUnits(queue.claimable)}, ${queue.claimable} wei` + ); + console.log( + `Claimed : ${formatUnits(queue.claimed)}, ${queue.claimed} wei` + ); + console.log(`Shortfall : ${formatUnits(shortfall)}, ${shortfall} wei`); + console.log(`Unclaimed : ${formatUnits(unclaimed)}, ${unclaimed} wei`); + console.log(`Available : ${formatUnits(available)}, ${available} wei`); + console.log( + `Target Buffer : ${formatUnits(vaultBuffer)} (${formatUnits( + vaultBufferPercentage, + 16 + )}%)` + ); + + console.log( + `Total Asset : ${formatUnits(totalAssets)}, ${totalAssets} wei` + ); console.log( - `Claimable : ${formatUnits(queue.claimable)}, ${queue.claimable} wei` + `Total Supply : ${formatUnits(totalSupply)}, ${totalSupply} wei` ); console.log( - `Claimed : ${formatUnits(queue.claimed)}, ${queue.claimed} wei` + `Asset - Supply: ${formatUnits(assetSupplyDiff)}, ${assetSupplyDiff} wei` ); - console.log(`Shortfall : ${formatUnits(shortfall)}, ${shortfall} wei`); - console.log(`Unclaimed : ${formatUnits(unclaimed)}, ${unclaimed} wei`); - console.log(`Available : ${formatUnits(available)}, ${available} wei`); } async function addWithdrawalQueueLiquidity(_, hre) { From f9a2c8049ecddc76eea2a6ed91e7b21062bf0771 Mon Sep 17 00:00:00 2001 From: Nick Addison Date: Tue, 6 Aug 2024 17:49:57 +1000 Subject: [PATCH 194/273] M-01 _checkBalance Returns an Incorrect Value During Insolvency (#2166) * Fix checkBalance bug in new OETHVaultCore (#2162) * Added unit test for checkBalance when balance is less than the outstanding requests * Fix _checkBalance so it returns 0 when the amount of WETH in the vault and strategies is less than the outstanding withdrawal requests * Moved asset check to top of _checkBalance * simplified _totalValue by calling _checkBalance (#2163) --- contracts/contracts/vault/OETHVaultCore.sol | 42 +++++++++------------ contracts/test/vault/oeth-vault.js | 5 +++ 2 files changed, 23 insertions(+), 24 deletions(-) diff --git a/contracts/contracts/vault/OETHVaultCore.sol b/contracts/contracts/vault/OETHVaultCore.sol index 72ae8f3368..12b14c3041 100644 --- a/contracts/contracts/vault/OETHVaultCore.sol +++ b/contracts/contracts/vault/OETHVaultCore.sol @@ -395,15 +395,24 @@ contract OETHVaultCore is VaultCore { override returns (uint256 balance) { + if (_asset != weth) { + return 0; + } + + // Get the WETH in the vault and the strategies 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; - } + WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata; + + // 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. + if (balance + queue.claimed < queue.queued) { + return 0; } + + // Need to remove WETH that is reserved for the withdrawal queue + return balance + queue.claimed - queue.queued; } /** @@ -446,29 +455,14 @@ contract OETHVaultCore is VaultCore { emit AssetAllocated(weth, depositStrategyAddr, allocateAmount); } - /// @dev The total value of all assets held by the vault and all its strategies + /// @dev The total value of all WETH 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; + // As WETH is the only asset, just return the WETH balance + return _checkBalance(weth); } /// @dev Only WETH is supported in the OETH Vault so return the WETH balance only diff --git a/contracts/test/vault/oeth-vault.js b/contracts/test/vault/oeth-vault.js index 92d7571af9..60d45f1f99 100644 --- a/contracts/test/vault/oeth-vault.js +++ b/contracts/test/vault/oeth-vault.js @@ -2149,6 +2149,11 @@ describe("OETH Vault", function () { // 100 from mints - 99 outstanding withdrawals - 2 from slashing = -1 value which is rounder up to zero expect(await fixture.oethVault.totalValue()).to.equal(0); }); + it("Should have check balance of zero", async () => { + const { oethVault, weth } = fixture; + // 100 from mints - 99 outstanding withdrawals - 2 from slashing = -1 value which is rounder up to zero + expect(await oethVault.checkBalance(weth.address)).to.equal(0); + }); it("Fail to allow user to create a new request due to too many outstanding requests", async () => { const { oethVault, matt } = fixture; From f82a54dd4642e1820b6c8f64b7cd0bee83944125 Mon Sep 17 00:00:00 2001 From: Nick Addison Date: Tue, 6 Aug 2024 17:50:23 +1000 Subject: [PATCH 195/273] Fix vault storage slots (#2167) --- contracts/contracts/vault/VaultStorage.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/contracts/vault/VaultStorage.sol b/contracts/contracts/vault/VaultStorage.sol index e93ca9a548..3b9b55f1d0 100644 --- a/contracts/contracts/vault/VaultStorage.sol +++ b/contracts/contracts/vault/VaultStorage.sol @@ -222,7 +222,7 @@ contract VaultStorage is Initializable, Governable { mapping(uint256 => WithdrawalRequest) public withdrawalRequests; // For future use - uint256[46] 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 From b2d3e9c1fa92deb89dd7c6bb22b5a4ff125d5b1e Mon Sep 17 00:00:00 2001 From: Nick Addison Date: Tue, 6 Aug 2024 18:17:27 +1000 Subject: [PATCH 196/273] L-03 Missing Docstrings (#2169) * Added Natspec to VaultStorage * Added Natspec to VaultCore --- contracts/contracts/vault/VaultCore.sol | 19 +++++++++++++++++-- contracts/contracts/vault/VaultStorage.sol | 9 +++++---- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/contracts/contracts/vault/VaultCore.sol b/contracts/contracts/vault/VaultCore.sol index fa3568ab2e..6878cbfe28 100644 --- a/contracts/contracts/vault/VaultCore.sol +++ b/contracts/contracts/vault/VaultCore.sol @@ -23,9 +23,9 @@ import "./VaultInitializer.sol"; contract VaultCore is VaultInitializer { using SafeERC20 for IERC20; using StableMath for uint256; - // max signed int + /// @dev max signed int uint256 internal constant MAX_INT = 2**255 - 1; - // max un-signed int + /// @dev max un-signed int uint256 internal constant MAX_UINT = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff; @@ -45,6 +45,9 @@ contract VaultCore is VaultInitializer { _; } + /** + * @dev Verifies that the caller is the AMO strategy. + */ modifier onlyOusdMetaStrategy() { require( msg.sender == ousdMetaStrategy, @@ -67,6 +70,12 @@ contract VaultCore is VaultInitializer { _mint(_asset, _amount, _minimumOusdAmount); } + /** + * @dev Deposit a supported asset and mint OTokens. + * @param _asset Address of the asset being deposited + * @param _amount Amount of the asset being deposited + * @param _minimumOusdAmount Minimum OTokens to mint + */ function _mint( address _asset, uint256 _amount, @@ -731,6 +740,11 @@ contract VaultCore is VaultInitializer { } } + /** + * @dev Get the number of decimals of a token asset + * @param _asset Address of the asset + * @return decimals number of decimals + */ function _getDecimals(address _asset) internal view @@ -749,6 +763,7 @@ contract VaultCore is VaultInitializer { /** * @notice Gets the vault configuration of a supported asset. + * @param _asset Address of the token asset */ function getAssetConfig(address _asset) public diff --git a/contracts/contracts/vault/VaultStorage.sol b/contracts/contracts/vault/VaultStorage.sol index 3b9b55f1d0..4c039b0019 100644 --- a/contracts/contracts/vault/VaultStorage.sol +++ b/contracts/contracts/vault/VaultStorage.sol @@ -122,14 +122,15 @@ contract VaultStorage is Initializable, Governable { // slither-disable-next-line uninitialized-state OUSD internal oUSD; - //keccak256("OUSD.vault.governor.admin.impl"); + /// @dev Storage slot for the address of the VaultAdmin contract that is delegated to + // keccak256("OUSD.vault.governor.admin.impl"); bytes32 constant adminImplPosition = 0xa2bd3d3cf188a41358c8b401076eb59066b09dec5775650c0de4c55187d17bd9; - // Address of the contract responsible for post rebase syncs with AMMs + /// @dev Address of the contract responsible for post rebase syncs with AMMs address private _deprecated_rebaseHooksAddr = address(0); - // Deprecated: Address of Uniswap + /// @dev Deprecated: Address of Uniswap // slither-disable-next-line constable-states address private _deprecated_uniswapAddr = address(0); @@ -221,7 +222,7 @@ contract VaultStorage is Initializable, Governable { /// @notice Mapping of withdrawal request indices to the user withdrawal request data mapping(uint256 => WithdrawalRequest) public withdrawalRequests; - // For future use + /// @dev For future use uint256[45] private __gap; /** From ecd480f9860bf89b6dca279cefac5957a8f5b230 Mon Sep 17 00:00:00 2001 From: Nick Addison Date: Tue, 6 Aug 2024 18:26:17 +1000 Subject: [PATCH 197/273] Fixed Natspec on requestWithdrawal (#2170) --- contracts/contracts/vault/OETHVaultCore.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/contracts/vault/OETHVaultCore.sol b/contracts/contracts/vault/OETHVaultCore.sol index 12b14c3041..7dc8ff07a3 100644 --- a/contracts/contracts/vault/OETHVaultCore.sol +++ b/contracts/contracts/vault/OETHVaultCore.sol @@ -162,8 +162,8 @@ contract OETHVaultCore is VaultCore { * 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. + * @return requestId Unique ID for the withdrawal request + * @return queued Cumulative total of all WETH queued including already claimed requests. */ function requestWithdrawal(uint256 _amount) external From 4c746ae3a92fa41f4aaded20776d2bd069bc6835 Mon Sep 17 00:00:00 2001 From: Nick Addison Date: Tue, 6 Aug 2024 18:31:31 +1000 Subject: [PATCH 198/273] Changed _requestIds param in claimWithdrawals be of type calldata (#2171) --- contracts/contracts/vault/OETHVaultCore.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/contracts/vault/OETHVaultCore.sol b/contracts/contracts/vault/OETHVaultCore.sol index 7dc8ff07a3..005a447de3 100644 --- a/contracts/contracts/vault/OETHVaultCore.sol +++ b/contracts/contracts/vault/OETHVaultCore.sol @@ -252,7 +252,7 @@ contract OETHVaultCore is VaultCore { * @return amounts Amount of WETH received for each request * @return totalAmount Total amount of WETH transferred to the withdrawer */ - function claimWithdrawals(uint256[] memory _requestIds) + function claimWithdrawals(uint256[] calldata _requestIds) external whenNotCapitalPaused nonReentrant From 7bdbfd849b39bb8181c35a0804dfdb9e94e7e34f Mon Sep 17 00:00:00 2001 From: Nick Addison Date: Tue, 6 Aug 2024 18:35:13 +1000 Subject: [PATCH 199/273] Remove unnecessary address cast (#2172) --- contracts/contracts/vault/VaultAdmin.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/contracts/vault/VaultAdmin.sol b/contracts/contracts/vault/VaultAdmin.sol index 0bc783a766..01aea902c4 100644 --- a/contracts/contracts/vault/VaultAdmin.sol +++ b/contracts/contracts/vault/VaultAdmin.sol @@ -205,7 +205,7 @@ contract VaultAdmin is VaultStorage { bytes calldata _data ) internal virtual returns (uint256 toAssetAmount) { // Check fromAsset and toAsset are valid - Asset memory fromAssetConfig = assets[address(_fromAsset)]; + Asset memory fromAssetConfig = assets[_fromAsset]; Asset memory toAssetConfig = assets[_toAsset]; require(fromAssetConfig.isSupported, "From asset is not supported"); require(toAssetConfig.isSupported, "To asset is not supported"); From 3b66f0377a71d1b4153990b36bd7a58e96080934 Mon Sep 17 00:00:00 2001 From: Nick Addison Date: Tue, 6 Aug 2024 19:04:45 +1000 Subject: [PATCH 200/273] Updated Natpsec of _checkBalance and _checkBalance (#2173) --- contracts/contracts/vault/OETHVaultCore.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/contracts/vault/OETHVaultCore.sol b/contracts/contracts/vault/OETHVaultCore.sol index 005a447de3..4993ba7c6e 100644 --- a/contracts/contracts/vault/OETHVaultCore.sol +++ b/contracts/contracts/vault/OETHVaultCore.sol @@ -158,7 +158,7 @@ contract OETHVaultCore is VaultCore { * 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 + * There is a minimum of 10 minutes before a request can be claimed. After that, the request 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. @@ -383,7 +383,7 @@ contract OETHVaultCore is VaultCore { /// @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. + /// WETH is the only asset that can return a non-zero balance. /// 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. /// From afb03d85176a699d86f3a810771c36a5dfebce67 Mon Sep 17 00:00:00 2001 From: Nick Addison Date: Tue, 6 Aug 2024 19:09:08 +1000 Subject: [PATCH 201/273] made constant CLAIM_DELAY public (#2174) --- contracts/contracts/vault/OETHVaultCore.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/contracts/vault/OETHVaultCore.sol b/contracts/contracts/vault/OETHVaultCore.sol index 4993ba7c6e..00df75e21d 100644 --- a/contracts/contracts/vault/OETHVaultCore.sol +++ b/contracts/contracts/vault/OETHVaultCore.sol @@ -18,7 +18,7 @@ contract OETHVaultCore is VaultCore { using SafeERC20 for IERC20; using StableMath for uint256; - uint256 constant CLAIM_DELAY = 10 minutes; + uint256 public constant CLAIM_DELAY = 10 minutes; address public immutable weth; uint256 public wethAssetIndex; From edaf36e10c293126942b3f2b21cbbda509e43832 Mon Sep 17 00:00:00 2001 From: Nick Addison Date: Tue, 6 Aug 2024 19:17:17 +1000 Subject: [PATCH 202/273] Removed unused MAX_UINT constant (#2175) --- contracts/contracts/vault/VaultCore.sol | 3 --- 1 file changed, 3 deletions(-) diff --git a/contracts/contracts/vault/VaultCore.sol b/contracts/contracts/vault/VaultCore.sol index 6878cbfe28..c15be51cdf 100644 --- a/contracts/contracts/vault/VaultCore.sol +++ b/contracts/contracts/vault/VaultCore.sol @@ -25,9 +25,6 @@ contract VaultCore is VaultInitializer { using StableMath for uint256; /// @dev max signed int uint256 internal constant MAX_INT = 2**255 - 1; - /// @dev max un-signed int - uint256 internal constant MAX_UINT = - 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff; /** * @dev Verifies that the rebasing is not paused. From 3e6b68e686c85a9306679d52ae22bc8917462b5c Mon Sep 17 00:00:00 2001 From: Nick Addison Date: Tue, 6 Aug 2024 19:26:07 +1000 Subject: [PATCH 203/273] N-08 Variables Are Initialized to Their Default Values (#2176) * Removed unused MAX_UINT constant * Removed variables being initialized to their default values --- contracts/contracts/vault/OETHVaultCore.sol | 4 ++-- contracts/contracts/vault/VaultCore.sol | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/contracts/contracts/vault/OETHVaultCore.sol b/contracts/contracts/vault/OETHVaultCore.sol index 00df75e21d..a391437065 100644 --- a/contracts/contracts/vault/OETHVaultCore.sol +++ b/contracts/contracts/vault/OETHVaultCore.sol @@ -35,7 +35,7 @@ contract OETHVaultCore is VaultCore { */ function cacheWETHAssetIndex() external onlyGovernor { uint256 assetCount = allAssets.length; - for (uint256 i = 0; i < assetCount; ++i) { + for (uint256 i; i < assetCount; ++i) { if (allAssets[i] == weth) { wethAssetIndex = i; break; @@ -268,7 +268,7 @@ contract OETHVaultCore is VaultCore { _addWithdrawalQueueLiquidity(); amounts = new uint256[](_requestIds.length); - for (uint256 i = 0; i < _requestIds.length; ++i) { + for (uint256 i; i < _requestIds.length; ++i) { amounts[i] = _claimWithdrawal(_requestIds[i]); totalAmount += amounts[i]; } diff --git a/contracts/contracts/vault/VaultCore.sol b/contracts/contracts/vault/VaultCore.sol index c15be51cdf..b7ecd6db74 100644 --- a/contracts/contracts/vault/VaultCore.sol +++ b/contracts/contracts/vault/VaultCore.sol @@ -437,7 +437,7 @@ contract VaultCore is VaultInitializer { returns (uint256 value) { uint256 assetCount = allAssets.length; - for (uint256 y = 0; y < assetCount; ++y) { + for (uint256 y; y < assetCount; ++y) { address assetAddr = allAssets[y]; uint256 balance = IERC20(assetAddr).balanceOf(address(this)); if (balance > 0) { @@ -469,7 +469,7 @@ contract VaultCore is VaultInitializer { { IStrategy strategy = IStrategy(_strategyAddr); uint256 assetCount = allAssets.length; - for (uint256 y = 0; y < assetCount; ++y) { + for (uint256 y; y < assetCount; ++y) { address assetAddr = allAssets[y]; if (strategy.supportsAsset(assetAddr)) { uint256 balance = strategy.checkBalance(assetAddr); From c59070f6c9d1862348b160c7a4d659149bdb97e7 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Tue, 6 Aug 2024 19:49:29 +1000 Subject: [PATCH 204/273] Generated latest Vault contract diagrams --- contracts/docs/OETHVaultAdminSquashed.svg | 6 +- contracts/docs/OETHVaultCoreSquashed.svg | 61 +++++++++--------- contracts/docs/OETHVaultHierarchy.svg | 76 +++++++++++------------ contracts/docs/VaultAdminSquashed.svg | 6 +- contracts/docs/VaultCoreSquashed.svg | 59 +++++++++--------- contracts/docs/VaultHierarchy.svg | 60 +++++++++--------- 6 files changed, 133 insertions(+), 135 deletions(-) diff --git a/contracts/docs/OETHVaultAdminSquashed.svg b/contracts/docs/OETHVaultAdminSquashed.svg index 1f01da55bc..d5af64e4d8 100644 --- a/contracts/docs/OETHVaultAdminSquashed.svg +++ b/contracts/docs/OETHVaultAdminSquashed.svg @@ -9,9 +9,9 @@ UmlClassDiagram - + -232 +233 OETHVaultAdmin ../contracts/vault/OETHVaultAdmin.sol @@ -26,7 +26,7 @@   _deprecated_rebaseHooksAddr: address <<VaultStorage>>   _deprecated_uniswapAddr: address <<VaultStorage>>   _deprecated_swapTokens: address[] <<VaultStorage>> -   __gap: uint256[46] <<VaultStorage>> +   __gap: uint256[45] <<VaultStorage>> Internal:   assets: mapping(address=>Asset) <<VaultStorage>>   allAssets: address[] <<VaultStorage>> diff --git a/contracts/docs/OETHVaultCoreSquashed.svg b/contracts/docs/OETHVaultCoreSquashed.svg index 9e32946122..7ff1c7040e 100644 --- a/contracts/docs/OETHVaultCoreSquashed.svg +++ b/contracts/docs/OETHVaultCoreSquashed.svg @@ -4,39 +4,38 @@ - - + + UmlClassDiagram - - + + -233 - -OETHVaultCore -../contracts/vault/OETHVaultCore.sol - -Private: -   initialized: bool <<Initializable>> -   initializing: bool <<Initializable>> -   ______gap: uint256[50] <<Initializable>> -   governorPosition: bytes32 <<Governable>> -   pendingGovernorPosition: bytes32 <<Governable>> -   reentryStatusPosition: bytes32 <<Governable>> -   _deprecated_rebaseHooksAddr: address <<VaultStorage>> -   _deprecated_uniswapAddr: address <<VaultStorage>> -   _deprecated_swapTokens: address[] <<VaultStorage>> -   __gap: uint256[46] <<VaultStorage>> -   __gap: uint256[50] <<OETHVaultCore>> -Internal: -   assets: mapping(address=>Asset) <<VaultStorage>> -   allAssets: address[] <<VaultStorage>> -   strategies: mapping(address=>Strategy) <<VaultStorage>> -   allStrategies: address[] <<VaultStorage>> -   oUSD: OUSD <<VaultStorage>> -   swapConfig: SwapConfig <<VaultStorage>> -   MAX_INT: uint256 <<VaultCore>> -   MAX_UINT: uint256 <<VaultCore>> +234 + +OETHVaultCore +../contracts/vault/OETHVaultCore.sol + +Private: +   initialized: bool <<Initializable>> +   initializing: bool <<Initializable>> +   ______gap: uint256[50] <<Initializable>> +   governorPosition: bytes32 <<Governable>> +   pendingGovernorPosition: bytes32 <<Governable>> +   reentryStatusPosition: bytes32 <<Governable>> +   _deprecated_rebaseHooksAddr: address <<VaultStorage>> +   _deprecated_uniswapAddr: address <<VaultStorage>> +   _deprecated_swapTokens: address[] <<VaultStorage>> +   __gap: uint256[45] <<VaultStorage>> +   __gap: uint256[50] <<OETHVaultCore>> +Internal: +   assets: mapping(address=>Asset) <<VaultStorage>> +   allAssets: address[] <<VaultStorage>> +   strategies: mapping(address=>Strategy) <<VaultStorage>> +   allStrategies: address[] <<VaultStorage>> +   oUSD: OUSD <<VaultStorage>> +   swapConfig: SwapConfig <<VaultStorage>> +   MAX_INT: uint256 <<VaultCore>> Public:   _NOT_ENTERED: uint256 <<Governable>>   _ENTERED: uint256 <<Governable>> diff --git a/contracts/docs/OETHVaultHierarchy.svg b/contracts/docs/OETHVaultHierarchy.svg index 4e9795682a..ce6caafd6c 100644 --- a/contracts/docs/OETHVaultHierarchy.svg +++ b/contracts/docs/OETHVaultHierarchy.svg @@ -29,127 +29,127 @@ - + -224 +225 <<Abstract>> Initializable ../contracts/utils/Initializable.sol - + -215->224 +215->225 - + -227 +228 <<Abstract>> InitializableERC20Detailed ../contracts/utils/InitializableERC20Detailed.sol - + -215->227 +215->228 - + -232 +233 OETHVaultAdmin ../contracts/vault/OETHVaultAdmin.sol - + -236 +237 VaultAdmin ../contracts/vault/VaultAdmin.sol - + -232->236 +233->237 - + -233 +234 OETHVaultCore ../contracts/vault/OETHVaultCore.sol - + -237 +238 VaultCore ../contracts/vault/VaultCore.sol - + -233->237 +234->238 - + -239 +240 VaultStorage ../contracts/vault/VaultStorage.sol - + -236->239 +237->240 - + -238 +239 VaultInitializer ../contracts/vault/VaultInitializer.sol - + -237->238 +238->239 - + -238->215 +239->215 - + -238->239 +239->240 - + -239->20 +240->20 - + -239->215 +240->215 - + -239->224 +240->225 diff --git a/contracts/docs/VaultAdminSquashed.svg b/contracts/docs/VaultAdminSquashed.svg index da6d5b6985..dc1af3bc9f 100644 --- a/contracts/docs/VaultAdminSquashed.svg +++ b/contracts/docs/VaultAdminSquashed.svg @@ -9,9 +9,9 @@ UmlClassDiagram - + -236 +237 VaultAdmin ../contracts/vault/VaultAdmin.sol @@ -26,7 +26,7 @@   _deprecated_rebaseHooksAddr: address <<VaultStorage>>   _deprecated_uniswapAddr: address <<VaultStorage>>   _deprecated_swapTokens: address[] <<VaultStorage>> -   __gap: uint256[46] <<VaultStorage>> +   __gap: uint256[45] <<VaultStorage>> Internal:   assets: mapping(address=>Asset) <<VaultStorage>>   allAssets: address[] <<VaultStorage>> diff --git a/contracts/docs/VaultCoreSquashed.svg b/contracts/docs/VaultCoreSquashed.svg index 815ea72cf9..b7e10a7f97 100644 --- a/contracts/docs/VaultCoreSquashed.svg +++ b/contracts/docs/VaultCoreSquashed.svg @@ -4,38 +4,37 @@ - - + + UmlClassDiagram - - + + -237 - -VaultCore -../contracts/vault/VaultCore.sol - -Private: -   initialized: bool <<Initializable>> -   initializing: bool <<Initializable>> -   ______gap: uint256[50] <<Initializable>> -   governorPosition: bytes32 <<Governable>> -   pendingGovernorPosition: bytes32 <<Governable>> -   reentryStatusPosition: bytes32 <<Governable>> -   _deprecated_rebaseHooksAddr: address <<VaultStorage>> -   _deprecated_uniswapAddr: address <<VaultStorage>> -   _deprecated_swapTokens: address[] <<VaultStorage>> -   __gap: uint256[46] <<VaultStorage>> -Internal: -   assets: mapping(address=>Asset) <<VaultStorage>> -   allAssets: address[] <<VaultStorage>> -   strategies: mapping(address=>Strategy) <<VaultStorage>> -   allStrategies: address[] <<VaultStorage>> -   oUSD: OUSD <<VaultStorage>> -   swapConfig: SwapConfig <<VaultStorage>> -   MAX_INT: uint256 <<VaultCore>> -   MAX_UINT: uint256 <<VaultCore>> +238 + +VaultCore +../contracts/vault/VaultCore.sol + +Private: +   initialized: bool <<Initializable>> +   initializing: bool <<Initializable>> +   ______gap: uint256[50] <<Initializable>> +   governorPosition: bytes32 <<Governable>> +   pendingGovernorPosition: bytes32 <<Governable>> +   reentryStatusPosition: bytes32 <<Governable>> +   _deprecated_rebaseHooksAddr: address <<VaultStorage>> +   _deprecated_uniswapAddr: address <<VaultStorage>> +   _deprecated_swapTokens: address[] <<VaultStorage>> +   __gap: uint256[45] <<VaultStorage>> +Internal: +   assets: mapping(address=>Asset) <<VaultStorage>> +   allAssets: address[] <<VaultStorage>> +   strategies: mapping(address=>Strategy) <<VaultStorage>> +   allStrategies: address[] <<VaultStorage>> +   oUSD: OUSD <<VaultStorage>> +   swapConfig: SwapConfig <<VaultStorage>> +   MAX_INT: uint256 <<VaultCore>> Public:   _NOT_ENTERED: uint256 <<Governable>>   _ENTERED: uint256 <<Governable>> diff --git a/contracts/docs/VaultHierarchy.svg b/contracts/docs/VaultHierarchy.svg index 33b2a2a61e..044158df15 100644 --- a/contracts/docs/VaultHierarchy.svg +++ b/contracts/docs/VaultHierarchy.svg @@ -29,101 +29,101 @@ - + -224 +225 <<Abstract>> Initializable ../contracts/utils/Initializable.sol - + -215->224 +215->225 - + -227 +228 <<Abstract>> InitializableERC20Detailed ../contracts/utils/InitializableERC20Detailed.sol - + -215->227 +215->228 - + -236 +237 VaultAdmin ../contracts/vault/VaultAdmin.sol - + -239 +240 VaultStorage ../contracts/vault/VaultStorage.sol - + -236->239 +237->240 - + -237 +238 VaultCore ../contracts/vault/VaultCore.sol - + -238 +239 VaultInitializer ../contracts/vault/VaultInitializer.sol - + -237->238 +238->239 - + -238->215 +239->215 - + -238->239 +239->240 - + -239->20 +240->20 - + -239->215 +240->215 - + -239->224 +240->225 From dd018063ca5facb03e5ab3a212e9680f1b229f4a Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Wed, 18 Dec 2024 10:21:32 +1100 Subject: [PATCH 205/273] initial commit --- contracts/contracts/mocks/MockWS.sol | 17 +++ contracts/contracts/proxies/SonicProxies.sol | 34 ++++++ contracts/contracts/token/OSonic.sol | 10 ++ contracts/contracts/token/WOSonic.sol | 55 +++++++++ contracts/deploy/sonic/000_mock.js | 111 +++++++++++++++++++ contracts/dev.env | 14 ++- contracts/hardhat.config.js | 42 +++++++ contracts/utils/addresses.js | 4 + contracts/utils/hardhat-helpers.js | 19 ++++ 9 files changed, 302 insertions(+), 4 deletions(-) create mode 100644 contracts/contracts/mocks/MockWS.sol create mode 100644 contracts/contracts/proxies/SonicProxies.sol create mode 100644 contracts/contracts/token/OSonic.sol create mode 100644 contracts/contracts/token/WOSonic.sol create mode 100644 contracts/deploy/sonic/000_mock.js diff --git a/contracts/contracts/mocks/MockWS.sol b/contracts/contracts/mocks/MockWS.sol new file mode 100644 index 0000000000..447f5eb02d --- /dev/null +++ b/contracts/contracts/mocks/MockWS.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "./MintableERC20.sol"; + +contract MockWS is MintableERC20 { + constructor() ERC20("Wrapped Sonic", "wS") {} + + function deposit() external payable { + _mint(msg.sender, msg.value); + } + + function withdraw(uint256 wad) external { + _burn(msg.sender, wad); + payable(msg.sender).transfer(wad); + } +} diff --git a/contracts/contracts/proxies/SonicProxies.sol b/contracts/contracts/proxies/SonicProxies.sol new file mode 100644 index 0000000000..fdfb46bb81 --- /dev/null +++ b/contracts/contracts/proxies/SonicProxies.sol @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import { InitializeGovernedUpgradeabilityProxy } from "./InitializeGovernedUpgradeabilityProxy.sol"; + +/** + * @notice OSonicVaultProxy delegates calls to OSonicVault implementation + */ +contract OSonicVaultProxy is InitializeGovernedUpgradeabilityProxy {} + +/** + * @notice OSonicProxy delegates calls to OSonic implementation + */ +contract OSonicProxy is InitializeGovernedUpgradeabilityProxy {} + +/** + * @notice WOSonicProxy delegates calls to WOSonic implementation + */ +contract WOSonicProxy is InitializeGovernedUpgradeabilityProxy {} + +/** + * @notice OSonicDripperProxy delegates calls to a OSonicDripper implementation + */ +contract OSonicDripperProxy is InitializeGovernedUpgradeabilityProxy {} + +/** + * @notice SonicStakingStrategyProxy delegates calls to SonicStakingStrategy implementation + */ +contract SonicStakingStrategyProxy is InitializeGovernedUpgradeabilityProxy {} + +/** + * @notice OSonicHarvesterProxy delegates calls to a OSonicHarvester implementation + */ +contract OSonicHarvesterProxy is InitializeGovernedUpgradeabilityProxy {} diff --git a/contracts/contracts/token/OSonic.sol b/contracts/contracts/token/OSonic.sol new file mode 100644 index 0000000000..31a129ce18 --- /dev/null +++ b/contracts/contracts/token/OSonic.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import { OUSD } from "./OUSD.sol"; + +/** + * @title Origin S (OS) Token Contract on Sonic + * @author Origin Protocol Inc + */ +contract OSonic is OUSD {} diff --git a/contracts/contracts/token/WOSonic.sol b/contracts/contracts/token/WOSonic.sol new file mode 100644 index 0000000000..79a9e1e047 --- /dev/null +++ b/contracts/contracts/token/WOSonic.sol @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import { ERC4626 } from "../../lib/openzeppelin/contracts/token/ERC20/extensions/ERC4626.sol"; +import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; + +import { Governable } from "../governance/Governable.sol"; +import { Initializable } from "../utils/Initializable.sol"; +import { OSonic } from "./OSonic.sol"; + +/** + * @title Wrapped Origin S Token contract on Sonic (wOS) + * @author Origin Protocol Inc + */ + +contract WOSonic is ERC4626, Governable, Initializable { + using SafeERC20 for IERC20; + + constructor( + ERC20 underlying_, + string memory name_, + string memory symbol_ + ) ERC20(name_, symbol_) ERC4626(underlying_) Governable() {} + + /** + * @notice Enable Origin Sonic rebasing for this contract + */ + function initialize() external onlyGovernor initializer { + OSonic(address(asset())).rebaseOptIn(); + } + + function name() public view virtual override returns (string memory) { + return "Wrapped Origin S"; + } + + function symbol() public view virtual override returns (string memory) { + return "wOS"; + } + + /** + * @notice Transfer token to governor. Intended for recovering tokens stuck in + * contract, i.e. mistaken sends. Cannot transfer Origin S + * @param asset_ Address for the asset + * @param amount_ Amount of the asset to transfer + */ + function transferToken( + address asset_, + uint256 amount_ + ) external onlyGovernor { + require(asset_ != address(asset()), "Cannot collect Origin S"); + IERC20(asset_).safeTransfer(governor(), amount_); + } +} diff --git a/contracts/deploy/sonic/000_mock.js b/contracts/deploy/sonic/000_mock.js new file mode 100644 index 0000000000..45c40835a7 --- /dev/null +++ b/contracts/deploy/sonic/000_mock.js @@ -0,0 +1,111 @@ +const { deployWithConfirmation } = require("../../utils/deploy"); +const { isFork, isSonic } = require("../../test/helpers"); + +const deployMocks = async () => { + await deployWithConfirmation("MockWS", []); +}; + +const deployCore = async () => { + const { governorAddr, deployerAddr } = await getNamedAccounts(); + const sGovernor = await ethers.provider.getSigner(governorAddr); + const sDeployer = await ethers.provider.getSigner(deployerAddr); + + const cWS = await ethers.getContract("MockWS"); + + // Proxies + await deployWithConfirmation("OSonicProxy"); + await deployWithConfirmation("WOSonicProxy"); + await deployWithConfirmation("OSonicVaultProxy"); + + const cOETHbProxy = await ethers.getContract("OSonicProxy"); + const cwOETHbProxy = await ethers.getContract("WSonicProxy"); + const cOETHbVaultProxy = await ethers.getContract("OSonicVaultProxy"); + + // Core contracts + const dOETHb = await deployWithConfirmation("OSonic"); + const dwOETHb = await deployWithConfirmation("WOSonic", [ + cOETHbProxy.address, // Base token + ]); + const dOETHbVault = await deployWithConfirmation("OSonicVault"); + const dOETHbVaultCore = await deployWithConfirmation("OSonicVaultCore", [ + cWS.address, + ]); + const dOETHbVaultAdmin = await deployWithConfirmation("OSonicVaultAdmin"); + + // Get contract instances + const cOETHb = await ethers.getContractAt("OSonic", cOETHbProxy.address); + const cwOETHb = await ethers.getContractAt("WOSonic", cwOETHbProxy.address); + const cOETHbVault = await ethers.getContractAt( + "IVault", + cOETHbVaultProxy.address + ); + const cOracleRouter = await ethers.getContract("MockOracleRouter"); + + // Init OETHb + const resolution = ethers.utils.parseUnits("1", 27); + const initDataOETHb = cOETHb.interface.encodeFunctionData( + "initialize(string,string,address,uint256)", + [ + "Origin S", // Token Name + "OS", // Token Symbol + cOETHbVaultProxy.address, // OETHb Vault + resolution, // HighRes + ] + ); + // prettier-ignore + await cOETHbProxy + .connect(sDeployer)["initialize(address,address,bytes)"]( + dOETHb.address, + governorAddr, + initDataOETHb + ); + + // Init OETHbVault + const initDataOETHbVault = cOETHbVault.interface.encodeFunctionData( + "initialize(address,address)", + [ + cOracleRouter.address, // OracleRouter + cOETHbProxy.address, // OETHb + ] + ); + // prettier-ignore + await cOETHbVaultProxy + .connect(sDeployer)["initialize(address,address,bytes)"]( + dOETHbVault.address, + governorAddr, + initDataOETHbVault + ); + + // Init wOETHb + const initDatawOETHb = cwOETHb.interface.encodeFunctionData( + "initialize()", + [] + ); + // prettier-ignore + await cwOETHbProxy + .connect(sDeployer)["initialize(address,address,bytes)"]( + dwOETHb.address, + governorAddr, + initDatawOETHb + ) + + await cOETHbVaultProxy.connect(sGovernor).upgradeTo(dOETHbVaultCore.address); + await cOETHbVault.connect(sGovernor).setAdminImpl(dOETHbVaultAdmin.address); + + await cOETHbVault.connect(sGovernor).supportAsset(cWS.address, 0); + await cOETHbVault.connect(sGovernor).unpauseCapital(); +}; + +const main = async () => { + await deployMocks(); + // await deployOracleRouter(); + await deployCore(); +}; + +main.id = "000_mock"; +main.tags = ["base_unit_tests"]; + +// Only run for unit tests +main.skip = () => isFork || isSonic; + +module.exports = main; diff --git a/contracts/dev.env b/contracts/dev.env index eae459ee53..b21e5eeff3 100644 --- a/contracts/dev.env +++ b/contracts/dev.env @@ -1,12 +1,16 @@ #providers PROVIDER_URL=[SET PROVIDER URL HERE] -HOLESKY_PROVIDER_URL=[SET HOLESKY PROVIDER URL HERE] +# HOLESKY_PROVIDER_URL=[SET HOLESKY PROVIDER URL HERE] +# BASE_PROVIDER_URL= +SONIC_PROVIDER_URL=https://rpc.soniclabs.com # Set it to latest block number or leave it empty -BLOCK_NUMBER= -HOLESKY_BLOCK_NUMBER= +# BLOCK_NUMBER= +# BASE_BLOCK_NUMBER= +# SONIC_BLOCK_NUMBER= +# HOLESKY_BLOCK_NUMBER= -ARBITRUM_PROVIDER_URL=[SET PROVIDER URL HERE] +# ARBITRUM_PROVIDER_URL=[SET PROVIDER URL HERE] # Add a list of comma separated accounts you want funded in node running forked mode ACCOUNTS_TO_FUND= @@ -22,6 +26,8 @@ ACCOUNTS_TO_FUND= # Used for verifying contracts on Etherscan # ETHERSCAN_API_KEY=[SET API Key] +# BASESCAN_API_KEY= +# SONICSCAN_API_KEY= # The 1Inch enterprise API # ONEINCH_API=https://[SET DOMAIN HERE]/v5.0/1/swap diff --git a/contracts/hardhat.config.js b/contracts/hardhat.config.js index ab81ef5886..8341ae1596 100644 --- a/contracts/hardhat.config.js +++ b/contracts/hardhat.config.js @@ -10,7 +10,12 @@ const { isBaseFork, isBaseForkTest, isBaseUnitTest, + isSonic, + isSonicFork, + isSonicForkTest, + isSonicUnitTest, baseProviderUrl, + sonicProviderUrl, arbitrumProviderUrl, holeskyProviderUrl, adjustTheForkBlockNumber, @@ -49,6 +54,9 @@ const HOLESKY_DEPLOYER = "0x1b94CA50D3Ad9f8368851F8526132272d1a5028C"; const BASE_DEPLOYER = MAINNET_DEPLOYER; const BASE_GOVERNOR = "0x92A19381444A001d62cE67BaFF066fA1111d7202"; const BASE_STRATEGIST = "0x28bce2eE5775B652D92bB7c2891A89F036619703"; +const SONIC_DEPLOYER = MAINNET_DEPLOYER; +const SONIC_GOVERNOR = ""; +const SONIC_STRATEGIST = ""; const mnemonic = "replace hover unaware super where filter stone fine garlic address matrix basic"; @@ -74,6 +82,8 @@ if (isHolesky || isHoleskyForkTest || isHoleskyFork) { paths.deploy = "deploy/holesky"; } else if (isBase || isBaseFork || isBaseForkTest || isBaseUnitTest) { paths.deploy = "deploy/base"; +} else if (isSonic || isSonicFork || isSonicForkTest || isSonicUnitTest) { + paths.deploy = "deploy/sonic"; } else { // holesky deployment files are in contracts/deploy/mainnet paths.deploy = "deploy/mainnet"; @@ -110,6 +120,8 @@ module.exports = { ? { tags: ["arbitrumOne"] } : isBaseFork ? { tags: ["base"] } + : isSonicFork + ? { tags: ["sonic"] } : {}), ...(isForkTest ? { @@ -179,6 +191,17 @@ module.exports = { live: true, saveDeployments: true, }, + sonic: { + url: sonicProviderUrl, + accounts: [ + process.env.DEPLOYER_PK || privateKeys[0], + process.env.GOVERNOR_PK || privateKeys[0], + ], + chainId: 146, + tags: ["sonic"], + live: true, + saveDeployments: true, + }, }, mocha: { bail: process.env.BAIL === "true", @@ -204,6 +227,7 @@ module.exports = { arbitrumOne: MAINNET_DEPLOYER, holesky: HOLESKY_DEPLOYER, base: MAINNET_DEPLOYER, + sonic: MAINNET_DEPLOYER, }, governorAddr: { default: 1, @@ -214,6 +238,8 @@ module.exports = { ? HOLESKY_DEPLOYER : isBaseFork ? BASE_GOVERNOR + : isSonicFork + ? SONIC_GOVERNOR : MAINNET_GOVERNOR : 1, hardhat: @@ -227,6 +253,7 @@ module.exports = { mainnet: MAINNET_GOVERNOR, holesky: HOLESKY_DEPLOYER, // on Holesky the deployer is also the governor base: BASE_GOVERNOR, + sonic: BASE_GOVERNOR, }, /* Local node environment currently has no access to Decentralized governance * address, since the contract is in another repo. Once we merge the ousd-governance @@ -282,6 +309,7 @@ module.exports = { : ethers.constants.AddressZero, mainnet: MAINNET_TIMELOCK, base: addresses.base.timelock, + sonic: addresses.sonic.timelock, }, guardianAddr: { default: 1, @@ -304,6 +332,8 @@ module.exports = { ? HOLESKY_DEPLOYER : isBaseFork ? BASE_STRATEGIST + : isSonicFork + ? SONIC_STRATEGIST : MAINNET_STRATEGIST : 0, hardhat: @@ -312,11 +342,14 @@ module.exports = { ? HOLESKY_DEPLOYER : isBaseFork ? BASE_STRATEGIST + : isSonicFork + ? SONIC_STRATEGIST : MAINNET_STRATEGIST : 0, mainnet: MAINNET_STRATEGIST, holesky: HOLESKY_DEPLOYER, // on Holesky the deployer is also the strategist base: BASE_STRATEGIST, + sonic: SONIC_STRATEGIST, }, }, contractSizer: { @@ -329,6 +362,7 @@ module.exports = { arbitrumOne: process.env.ARBISCAN_API_KEY, holesky: process.env.ETHERSCAN_API_KEY, base: process.env.BASESCAN_API_KEY, + sonic: process.env.SONICSCAN_API_KEY, }, customChains: [ { @@ -347,6 +381,14 @@ module.exports = { browserURL: "https://basescan.org", }, }, + { + network: "sonic", + chainId: 146, + urls: { + apiURL: "https://api.sonicscan.org/api", + browserURL: "https://sonicscan.org", + }, + }, ], }, gasReporter: { diff --git a/contracts/utils/addresses.js b/contracts/utils/addresses.js index a62455b786..0ca2410d3e 100644 --- a/contracts/utils/addresses.js +++ b/contracts/utils/addresses.js @@ -331,6 +331,10 @@ addresses.base.oethbBribesContract = addresses.base.OZRelayerAddress = "0xc0D6fa24D135c006dE5B8b2955935466A03D920a"; +// Sonic +addresses.sonic = {}; +addresses.sonic.wS = "0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38" + // Holesky addresses.holesky.WETH = "0x94373a4919B3240D86eA41593D5eBa789FEF3848"; diff --git a/contracts/utils/hardhat-helpers.js b/contracts/utils/hardhat-helpers.js index a40632a9e5..d300963ba0 100644 --- a/contracts/utils/hardhat-helpers.js +++ b/contracts/utils/hardhat-helpers.js @@ -7,12 +7,16 @@ const isHoleskyFork = process.env.FORK_NETWORK_NAME === "holesky"; const isHolesky = process.env.NETWORK_NAME === "holesky"; const isBase = process.env.NETWORK_NAME === "base"; const isBaseFork = process.env.FORK_NETWORK_NAME === "base"; +const isSonic = process.env.NETWORK_NAME === "sonic"; +const isSonicFork = process.env.FORK_NETWORK_NAME === "sonic"; const isForkTest = isFork && process.env.IS_TEST === "true"; const isArbForkTest = isForkTest && isArbitrumFork; const isHoleskyForkTest = isForkTest && isHoleskyFork; const isBaseForkTest = isForkTest && isBaseFork; const isBaseUnitTest = process.env.UNIT_TESTS_NETWORK === "base"; +const isSonicForkTest = isForkTest && isSonicFork; +const isSonicUnitTest = process.env.UNIT_TESTS_NETWORK === "sonic"; const providerUrl = `${ process.env.LOCAL_PROVIDER_URL || process.env.PROVIDER_URL @@ -20,6 +24,7 @@ const providerUrl = `${ const arbitrumProviderUrl = `${process.env.ARBITRUM_PROVIDER_URL}`; const holeskyProviderUrl = `${process.env.HOLESKY_PROVIDER_URL}`; const baseProviderUrl = `${process.env.BASE_PROVIDER_URL}`; +const sonicProviderUrl = `${process.env.SONIC_PROVIDER_URL}`; const standaloneLocalNodeRunning = !!process.env.LOCAL_PROVIDER_URL; /** @@ -44,6 +49,10 @@ const adjustTheForkBlockNumber = () => { forkBlockNumber = process.env.BASE_BLOCK_NUMBER ? process.env.BASE_BLOCK_NUMBER : undefined; + } else if (isSonicForkTest) { + forkBlockNumber = process.env.SONIC_BLOCK_NUMBER + ? process.env.SONIC_BLOCK_NUMBER + : undefined; } else { forkBlockNumber = process.env.BLOCK_NUMBER ? Number(process.env.BLOCK_NUMBER) @@ -108,6 +117,8 @@ const getHardhatNetworkProperties = () => { chainId = 17000; } else if (isBaseFork && isFork) { chainId = 8453; + } else if (isSonicFork && isSonic) { + chainId = 146; } else if (isFork) { // is mainnet fork chainId = 1; @@ -121,6 +132,8 @@ const getHardhatNetworkProperties = () => { provider = holeskyProviderUrl; } else if (isBaseForkTest) { provider = baseProviderUrl; + } else if (isSonicForkTest) { + provider = sonicProviderUrl; } } @@ -133,6 +146,7 @@ const networkMap = { 42161: "arbitrumOne", 1337: "hardhat", 8453: "base", + 146: "sonic", }; module.exports = { @@ -142,6 +156,10 @@ module.exports = { isBaseFork, isBaseForkTest, isBaseUnitTest, + isSonic, + isSonicFork, + isSonicForkTest, + isSonicUnitTest, isHoleskyFork, isHolesky, isForkTest, @@ -154,4 +172,5 @@ module.exports = { getHardhatNetworkProperties, networkMap, baseProviderUrl, + sonicProviderUrl, }; From b50f70613e0463fbaa02058f4d86c6edd911f02f Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Wed, 18 Dec 2024 10:22:22 +1100 Subject: [PATCH 206/273] WIP Sonic Vault --- .../contracts/vault/OSonicVaultAdmin.sol | 91 ++++ contracts/contracts/vault/OSonicVaultCore.sol | 459 ++++++++++++++++++ 2 files changed, 550 insertions(+) create mode 100644 contracts/contracts/vault/OSonicVaultAdmin.sol create mode 100644 contracts/contracts/vault/OSonicVaultCore.sol diff --git a/contracts/contracts/vault/OSonicVaultAdmin.sol b/contracts/contracts/vault/OSonicVaultAdmin.sol new file mode 100644 index 0000000000..d517302ddd --- /dev/null +++ b/contracts/contracts/vault/OSonicVaultAdmin.sol @@ -0,0 +1,91 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import { VaultAdmin } from "./VaultAdmin.sol"; + +/** + * @title Origin S VaultAdmin Contract on Sonic + * @author Origin Protocol Inc + */ +contract OSonicVaultAdmin is VaultAdmin { + using SafeERC20 for IERC20; + + /// @notice Sonic's Wrapped S token + address public immutable wS; + + constructor(address _wS) { + wS = _wS; + } + + /// @dev Simplified version of the deposit function as wS 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] == wS, + "Only wS is supported" + ); + + // Check the there is enough wS to transfer once the wS reserved for the withdrawal queue is accounted for + require(_amounts[0] <= _wSAvailable(), "Not enough wS 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 Wrapped S tokens in the vault is not reserved for the withdrawal queue. + // That is, it is available to be redeemed or deposited into a strategy. + function _wSAvailable() internal view returns (uint256 wSAvailable) { + WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata; + + // The amount 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 wSBalance = IERC20(sW).balanceOf(address(this)); + + // If there is not enough wS in the vault to cover the outstanding withdrawals + if (wSBalance <= outstandingWithdrawals) { + return 0; + } + + return wSBalance - outstandingWithdrawals; + } +} diff --git a/contracts/contracts/vault/OSonicVaultCore.sol b/contracts/contracts/vault/OSonicVaultCore.sol new file mode 100644 index 0000000000..f78442642b --- /dev/null +++ b/contracts/contracts/vault/OSonicVaultCore.sol @@ -0,0 +1,459 @@ +// 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 { 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 Origin S VaultCore contract on Sonic + * @author Origin Protocol Inc + */ +contract OSonicVaultCore is VaultCore { + using SafeERC20 for IERC20; + using StableMath for uint256; + + /// @notice Sonic's Wrapped S token + address public immutable wS; + uint256 public constant wSAssetIndex = 0; + + constructor(address _wS) { + wS = _wS; + } + + // @inheritdoc VaultCore + // slither-disable-start reentrancy-no-eth + function _mint( + address _asset, + uint256 _amount, + uint256 _minimumOusdAmount + ) internal virtual override { + require(_asset == wS, "Unsupported asset for minting"); + require(_amount > 0, "Amount must be greater than 0"); + require( + _amount >= _minimumOusdAmount, + "Mint amount lower than minimum" + ); + + emit Mint(msg.sender, _amount); + + // Rebase must happen before any transfers occur. + if (!rebasePaused && _amount >= rebaseThreshold) { + // Stream any harvested rewards (wS) that are available to the Vault + IDripper(dripper).collect(); + + _rebase(); + } + + // Mint oTokens + oUSD.mint(msg.sender, _amount); + + // Transfer the deposited coins to the vault + IERC20(_asset).safeTransferFrom(msg.sender, address(this), _amount); + + // Give priority to the withdrawal queue for the new wS liquidity + _addWithdrawalQueueLiquidity(); + + // Auto-allocate if necessary + if (_amount >= autoAllocateThreshold) { + _allocate(); + } + } + + // slither-disable-end reentrancy-no-eth + + // @inheritdoc VaultCore + function _calculateRedeemOutputs( + uint256 _amount + ) internal view virtual override returns (uint256[] memory outputs) { + // Overrides `VaultCore._calculateRedeemOutputs` to redeem with only + // wS instead of LST-mix. Doesn't change the function signature + // for backward compatibility + + // Calculate redeem fee + if (redeemFeeBps > 0) { + uint256 redeemFee = _amount.mulTruncateScale(redeemFeeBps, 1e4); + _amount = _amount - redeemFee; + } + + // Ensure the Vault's assets line up + require(allAssets[wSAssetIndex] == wS, "wS asset invalid"); + + outputs = new uint256[](allAssets.length); + outputs[wSAssetIndex] = _amount; + } + + // @inheritdoc VaultCore + function _redeem( + uint256 _amount, + uint256 _minimumUnitAmount + ) internal virtual override { + // Override `VaultCore._redeem` to simplify it. Gets rid of oracle + // usage and looping through all assets for LST-mix redeem. Instead + // does a simple wS-only redeem. + emit Redeem(msg.sender, _amount); + + if (_amount == 0) { + return; + } + + // Amount excluding fees + uint256 amountMinusFee = _calculateRedeemOutputs(_amount)[wSAssetIndex]; + + require( + amountMinusFee >= _minimumUnitAmount, + "Redeem amount lower than minimum" + ); + + // Is there enough wS in the Vault available after accounting for the withdrawal queue + require(_wSAvailable() >= amountMinusFee, "Liquidity error"); + + // Transfer wS minus the fee to the redeemer + IERC20(wS).safeTransfer(msg.sender, amountMinusFee); + + // Burn OSonic from user (including fees) + oUSD.burn(msg.sender, _amount); + + // Prevent insolvency + _postRedeem(_amount); + } + + /** + * @notice Request an asynchronous withdrawal of wS in exchange for Origin S tokens (OS). + * The OS tokens are burned on request and the wS 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 a minimum of 10 minutes before a request can be claimed. After that, the request just needs + * enough wS liquidity in the Vault to satisfy all the outstanding requests to that point in the queue. + * OS is converted to wS at 1:1. + * @param _amount Amount of OETH to burn. + * @param requestId Unique ID for the withdrawal request + * @param queued Cumulative total of all wS queued including already claimed requests. + */ + function requestWithdrawal( + uint256 _amount + ) + external + virtual + whenNotCapitalPaused + nonReentrant + returns (uint256 requestId, uint256 queued) + { + require(withdrawalClaimDelay > 0, "Async withdrawals not enabled"); + + // 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 wS 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`. + * OS is converted to wS at 1:1. + * @param _requestId Unique ID for the withdrawal request + * @return amount Amount of wS transferred to the withdrawer + */ + function claimWithdrawal( + uint256 _requestId + ) + external + virtual + 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 (wS) that are available to the Vault + IDripper(dripper).collect(); + + // Add any wS from the Dripper to the withdrawal queue + _addWithdrawalQueueLiquidity(); + } + + amount = _claimWithdrawal(_requestId); + + // transfer wS from the vault to the withdrawer + IERC20(wS).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 wS received for each request + * @return totalAmount Total amount of wS transferred to the withdrawer + */ + function claimWithdrawals( + uint256[] calldata _requestIds + ) + external + virtual + 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 (wS) that are available to the Vault + IDripper(dripper).collect(); + + // Add any wS from the Dripper to the withdrawal queue + _addWithdrawalQueueLiquidity(); + + amounts = new uint256[](_requestIds.length); + for (uint256 i; i < _requestIds.length; ++i) { + amounts[i] = _claimWithdrawal(_requestIds[i]); + totalAmount += amounts[i]; + } + + // transfer all the claimed wS from the vault to the withdrawer + IERC20(wS).safeTransfer(msg.sender, totalAmount); + + // Prevent insolvency + _postRedeem(totalAmount); + } + + function _claimWithdrawal( + uint256 requestId + ) internal returns (uint256 amount) { + require(withdrawalClaimDelay > 0, "Async withdrawals not enabled"); + + // Load the structs from storage into memory + WithdrawalRequest memory request = withdrawalRequests[requestId]; + WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata; + + require( + request.timestamp + withdrawalClaimDelay <= 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 wS then + /// adds wS to the withdrawal queue if there is a funding shortfall. + /// @dev is called from the Sonic Staking Strategy when validator withdrawals are processed. + /// It also called before any wS is allocated to a strategy. + function addWithdrawalQueueLiquidity() external { + // Stream any harvested rewards (wS) that are available to the Vault + IDripper(dripper).collect(); + + _addWithdrawalQueueLiquidity(); + } + + /// @dev Adds wS to the withdrawal queue if there is a funding shortfall. + /// This assumes 1 wS equals 1 OSonic. + function _addWithdrawalQueueLiquidity() + internal + returns (uint256 addedClaimable) + { + WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata; + + // Check if the claimable wS 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 wSBalance = IERC20(wS).balanceOf(address(this)); + + // Of the claimable withdrawal requests, how much is unclaimed? + // That is, the amount of wS that is currently allocated for the withdrawal queue + uint256 allocatedWS = queue.claimable - queue.claimed; + + // If there is no unallocated wS then there is nothing to add to the queue + if (wSBalance <= allocatedWS) { + return 0; + } + + uint256 unallocatedWS = wSBalance - allocatedWS; + + // the new claimable amount is the smaller of the queue shortfall or unallocated wS + addedClaimable = queueShortfall < unallocatedWS + ? queueShortfall + : unallocatedWS; + 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 Wrapped S tokens in the vault is not reserved for the withdrawal queue. + // That is, it is available to be redeemed or deposited into a strategy. + function _wSAvailable() internal view returns (uint256 wSAvailable) { + WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata; + + // The amount that is still to be claimed in the withdrawal queue + uint256 outstandingWithdrawals = queue.queued - queue.claimed; + + // The amount of sitting in wS in the vault + uint256 wSBalance = IERC20(sW).balanceOf(address(this)); + + // If there is not enough wS in the vault to cover the outstanding withdrawals + if (wSBalance <= outstandingWithdrawals) { + return 0; + } + + return wSBalance - outstandingWithdrawals; + } + + /// @dev Get the balance of an asset held in Vault and all strategies + /// less any wS that is reserved for the withdrawal queue. + /// wS is the only asset that can return a non-zero balance. + /// + /// If there is not enough wS in the vault and all strategies to cover all outstanding + /// withdrawal requests then return a wS balance of 0 + function _checkBalance( + address _asset + ) internal view override returns (uint256 balance) { + if (_asset != wS) { + return 0; + } + + // Get the wS in the vault and the strategies + balance = super._checkBalance(_asset); + + WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata; + + // 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. + if (balance + queue.claimed < queue.queued) { + return 0; + } + + // Need to remove wS that is reserved for the withdrawal queue + return balance + queue.claimed - queue.queued; + } + + /** + * @notice Allocate unallocated funds on Vault to strategies. + **/ + function allocate() external override whenNotCapitalPaused nonReentrant { + // Add any unallocated wS to the withdrawal queue first + _addWithdrawalQueueLiquidity(); + + _allocate(); + } + + /// @dev Allocate wS to the default wS 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 wS + address depositStrategyAddr = assetDefaultStrategies[wS]; + if (depositStrategyAddr == address(0)) return; + + uint256 wSAvailableInVault = _wSAvailable(); + // No need to do anything if there isn't any wS in the vault to allocate + if (wSAvailableInVault == 0) return; + + // Calculate the target buffer for the vault using the total supply + uint256 totalSupply = oUSD.totalSupply(); + uint256 targetBuffer = totalSupply.mulTruncate(vaultBuffer); + + // If available wS in the Vault is below or equal the target buffer then there's nothing to allocate + if (wSAvailableInVault <= targetBuffer) return; + + // The amount of assets to allocate to the default strategy + uint256 allocateAmount = wSAvailableInVault - targetBuffer; + + IStrategy strategy = IStrategy(depositStrategyAddr); + // Transfer wS to the strategy and call the strategy's deposit function + IERC20(wS).safeTransfer(address(strategy), allocateAmount); + strategy.deposit(wS, allocateAmount); + + emit AssetAllocated(wS, depositStrategyAddr, allocateAmount); + } + + /// @dev The total value of all wS held by the vault and all its strategies + /// less any wS that is reserved for the withdrawal queue. + /// + // If there is not enough wS 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) { + // As wS is the only asset, just return the wS balance + return _checkBalance(wS); + } + + /// @dev Only wS is supported in the OETH Vault so return the wS 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(wS).balanceOf(address(this)); + } +} From 86a86bbaf900b5c4abd37918a9edefb3ac7723a2 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Wed, 18 Dec 2024 14:03:45 +1100 Subject: [PATCH 207/273] Changed Sonic Vault to use OETH Base Vault --- .../contracts/vault/OSonicVaultAdmin.sol | 86 +--- contracts/contracts/vault/OSonicVaultCore.sol | 454 +----------------- 2 files changed, 8 insertions(+), 532 deletions(-) diff --git a/contracts/contracts/vault/OSonicVaultAdmin.sol b/contracts/contracts/vault/OSonicVaultAdmin.sol index d517302ddd..98f9d14e64 100644 --- a/contracts/contracts/vault/OSonicVaultAdmin.sol +++ b/contracts/contracts/vault/OSonicVaultAdmin.sol @@ -1,91 +1,13 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import { VaultAdmin } from "./VaultAdmin.sol"; +import { OETHVaultAdmin } from "./OETHVaultAdmin.sol"; /** * @title Origin S VaultAdmin Contract on Sonic * @author Origin Protocol Inc */ -contract OSonicVaultAdmin is VaultAdmin { - using SafeERC20 for IERC20; - - /// @notice Sonic's Wrapped S token - address public immutable wS; - - constructor(address _wS) { - wS = _wS; - } - - /// @dev Simplified version of the deposit function as wS 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] == wS, - "Only wS is supported" - ); - - // Check the there is enough wS to transfer once the wS reserved for the withdrawal queue is accounted for - require(_amounts[0] <= _wSAvailable(), "Not enough wS 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 Wrapped S tokens in the vault is not reserved for the withdrawal queue. - // That is, it is available to be redeemed or deposited into a strategy. - function _wSAvailable() internal view returns (uint256 wSAvailable) { - WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata; - - // The amount 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 wSBalance = IERC20(sW).balanceOf(address(this)); - - // If there is not enough wS in the vault to cover the outstanding withdrawals - if (wSBalance <= outstandingWithdrawals) { - return 0; - } - - return wSBalance - outstandingWithdrawals; - } +contract OSonicVaultAdmin is OETHVaultAdmin { + /// @param _wS Sonic's Wrapped S token + constructor(address _wS) OETHVaultAdmin(_wS) {} } diff --git a/contracts/contracts/vault/OSonicVaultCore.sol b/contracts/contracts/vault/OSonicVaultCore.sol index f78442642b..885288b87a 100644 --- a/contracts/contracts/vault/OSonicVaultCore.sol +++ b/contracts/contracts/vault/OSonicVaultCore.sol @@ -1,459 +1,13 @@ // 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 { 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"; +import { OETHVaultCore } from "./OETHVaultCore.sol"; /** * @title Origin S VaultCore contract on Sonic * @author Origin Protocol Inc */ -contract OSonicVaultCore is VaultCore { - using SafeERC20 for IERC20; - using StableMath for uint256; - - /// @notice Sonic's Wrapped S token - address public immutable wS; - uint256 public constant wSAssetIndex = 0; - - constructor(address _wS) { - wS = _wS; - } - - // @inheritdoc VaultCore - // slither-disable-start reentrancy-no-eth - function _mint( - address _asset, - uint256 _amount, - uint256 _minimumOusdAmount - ) internal virtual override { - require(_asset == wS, "Unsupported asset for minting"); - require(_amount > 0, "Amount must be greater than 0"); - require( - _amount >= _minimumOusdAmount, - "Mint amount lower than minimum" - ); - - emit Mint(msg.sender, _amount); - - // Rebase must happen before any transfers occur. - if (!rebasePaused && _amount >= rebaseThreshold) { - // Stream any harvested rewards (wS) that are available to the Vault - IDripper(dripper).collect(); - - _rebase(); - } - - // Mint oTokens - oUSD.mint(msg.sender, _amount); - - // Transfer the deposited coins to the vault - IERC20(_asset).safeTransferFrom(msg.sender, address(this), _amount); - - // Give priority to the withdrawal queue for the new wS liquidity - _addWithdrawalQueueLiquidity(); - - // Auto-allocate if necessary - if (_amount >= autoAllocateThreshold) { - _allocate(); - } - } - - // slither-disable-end reentrancy-no-eth - - // @inheritdoc VaultCore - function _calculateRedeemOutputs( - uint256 _amount - ) internal view virtual override returns (uint256[] memory outputs) { - // Overrides `VaultCore._calculateRedeemOutputs` to redeem with only - // wS instead of LST-mix. Doesn't change the function signature - // for backward compatibility - - // Calculate redeem fee - if (redeemFeeBps > 0) { - uint256 redeemFee = _amount.mulTruncateScale(redeemFeeBps, 1e4); - _amount = _amount - redeemFee; - } - - // Ensure the Vault's assets line up - require(allAssets[wSAssetIndex] == wS, "wS asset invalid"); - - outputs = new uint256[](allAssets.length); - outputs[wSAssetIndex] = _amount; - } - - // @inheritdoc VaultCore - function _redeem( - uint256 _amount, - uint256 _minimumUnitAmount - ) internal virtual override { - // Override `VaultCore._redeem` to simplify it. Gets rid of oracle - // usage and looping through all assets for LST-mix redeem. Instead - // does a simple wS-only redeem. - emit Redeem(msg.sender, _amount); - - if (_amount == 0) { - return; - } - - // Amount excluding fees - uint256 amountMinusFee = _calculateRedeemOutputs(_amount)[wSAssetIndex]; - - require( - amountMinusFee >= _minimumUnitAmount, - "Redeem amount lower than minimum" - ); - - // Is there enough wS in the Vault available after accounting for the withdrawal queue - require(_wSAvailable() >= amountMinusFee, "Liquidity error"); - - // Transfer wS minus the fee to the redeemer - IERC20(wS).safeTransfer(msg.sender, amountMinusFee); - - // Burn OSonic from user (including fees) - oUSD.burn(msg.sender, _amount); - - // Prevent insolvency - _postRedeem(_amount); - } - - /** - * @notice Request an asynchronous withdrawal of wS in exchange for Origin S tokens (OS). - * The OS tokens are burned on request and the wS 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 a minimum of 10 minutes before a request can be claimed. After that, the request just needs - * enough wS liquidity in the Vault to satisfy all the outstanding requests to that point in the queue. - * OS is converted to wS at 1:1. - * @param _amount Amount of OETH to burn. - * @param requestId Unique ID for the withdrawal request - * @param queued Cumulative total of all wS queued including already claimed requests. - */ - function requestWithdrawal( - uint256 _amount - ) - external - virtual - whenNotCapitalPaused - nonReentrant - returns (uint256 requestId, uint256 queued) - { - require(withdrawalClaimDelay > 0, "Async withdrawals not enabled"); - - // 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 wS 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`. - * OS is converted to wS at 1:1. - * @param _requestId Unique ID for the withdrawal request - * @return amount Amount of wS transferred to the withdrawer - */ - function claimWithdrawal( - uint256 _requestId - ) - external - virtual - 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 (wS) that are available to the Vault - IDripper(dripper).collect(); - - // Add any wS from the Dripper to the withdrawal queue - _addWithdrawalQueueLiquidity(); - } - - amount = _claimWithdrawal(_requestId); - - // transfer wS from the vault to the withdrawer - IERC20(wS).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 wS received for each request - * @return totalAmount Total amount of wS transferred to the withdrawer - */ - function claimWithdrawals( - uint256[] calldata _requestIds - ) - external - virtual - 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 (wS) that are available to the Vault - IDripper(dripper).collect(); - - // Add any wS from the Dripper to the withdrawal queue - _addWithdrawalQueueLiquidity(); - - amounts = new uint256[](_requestIds.length); - for (uint256 i; i < _requestIds.length; ++i) { - amounts[i] = _claimWithdrawal(_requestIds[i]); - totalAmount += amounts[i]; - } - - // transfer all the claimed wS from the vault to the withdrawer - IERC20(wS).safeTransfer(msg.sender, totalAmount); - - // Prevent insolvency - _postRedeem(totalAmount); - } - - function _claimWithdrawal( - uint256 requestId - ) internal returns (uint256 amount) { - require(withdrawalClaimDelay > 0, "Async withdrawals not enabled"); - - // Load the structs from storage into memory - WithdrawalRequest memory request = withdrawalRequests[requestId]; - WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata; - - require( - request.timestamp + withdrawalClaimDelay <= 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 wS then - /// adds wS to the withdrawal queue if there is a funding shortfall. - /// @dev is called from the Sonic Staking Strategy when validator withdrawals are processed. - /// It also called before any wS is allocated to a strategy. - function addWithdrawalQueueLiquidity() external { - // Stream any harvested rewards (wS) that are available to the Vault - IDripper(dripper).collect(); - - _addWithdrawalQueueLiquidity(); - } - - /// @dev Adds wS to the withdrawal queue if there is a funding shortfall. - /// This assumes 1 wS equals 1 OSonic. - function _addWithdrawalQueueLiquidity() - internal - returns (uint256 addedClaimable) - { - WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata; - - // Check if the claimable wS 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 wSBalance = IERC20(wS).balanceOf(address(this)); - - // Of the claimable withdrawal requests, how much is unclaimed? - // That is, the amount of wS that is currently allocated for the withdrawal queue - uint256 allocatedWS = queue.claimable - queue.claimed; - - // If there is no unallocated wS then there is nothing to add to the queue - if (wSBalance <= allocatedWS) { - return 0; - } - - uint256 unallocatedWS = wSBalance - allocatedWS; - - // the new claimable amount is the smaller of the queue shortfall or unallocated wS - addedClaimable = queueShortfall < unallocatedWS - ? queueShortfall - : unallocatedWS; - 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 Wrapped S tokens in the vault is not reserved for the withdrawal queue. - // That is, it is available to be redeemed or deposited into a strategy. - function _wSAvailable() internal view returns (uint256 wSAvailable) { - WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata; - - // The amount that is still to be claimed in the withdrawal queue - uint256 outstandingWithdrawals = queue.queued - queue.claimed; - - // The amount of sitting in wS in the vault - uint256 wSBalance = IERC20(sW).balanceOf(address(this)); - - // If there is not enough wS in the vault to cover the outstanding withdrawals - if (wSBalance <= outstandingWithdrawals) { - return 0; - } - - return wSBalance - outstandingWithdrawals; - } - - /// @dev Get the balance of an asset held in Vault and all strategies - /// less any wS that is reserved for the withdrawal queue. - /// wS is the only asset that can return a non-zero balance. - /// - /// If there is not enough wS in the vault and all strategies to cover all outstanding - /// withdrawal requests then return a wS balance of 0 - function _checkBalance( - address _asset - ) internal view override returns (uint256 balance) { - if (_asset != wS) { - return 0; - } - - // Get the wS in the vault and the strategies - balance = super._checkBalance(_asset); - - WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata; - - // 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. - if (balance + queue.claimed < queue.queued) { - return 0; - } - - // Need to remove wS that is reserved for the withdrawal queue - return balance + queue.claimed - queue.queued; - } - - /** - * @notice Allocate unallocated funds on Vault to strategies. - **/ - function allocate() external override whenNotCapitalPaused nonReentrant { - // Add any unallocated wS to the withdrawal queue first - _addWithdrawalQueueLiquidity(); - - _allocate(); - } - - /// @dev Allocate wS to the default wS 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 wS - address depositStrategyAddr = assetDefaultStrategies[wS]; - if (depositStrategyAddr == address(0)) return; - - uint256 wSAvailableInVault = _wSAvailable(); - // No need to do anything if there isn't any wS in the vault to allocate - if (wSAvailableInVault == 0) return; - - // Calculate the target buffer for the vault using the total supply - uint256 totalSupply = oUSD.totalSupply(); - uint256 targetBuffer = totalSupply.mulTruncate(vaultBuffer); - - // If available wS in the Vault is below or equal the target buffer then there's nothing to allocate - if (wSAvailableInVault <= targetBuffer) return; - - // The amount of assets to allocate to the default strategy - uint256 allocateAmount = wSAvailableInVault - targetBuffer; - - IStrategy strategy = IStrategy(depositStrategyAddr); - // Transfer wS to the strategy and call the strategy's deposit function - IERC20(wS).safeTransfer(address(strategy), allocateAmount); - strategy.deposit(wS, allocateAmount); - - emit AssetAllocated(wS, depositStrategyAddr, allocateAmount); - } - - /// @dev The total value of all wS held by the vault and all its strategies - /// less any wS that is reserved for the withdrawal queue. - /// - // If there is not enough wS 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) { - // As wS is the only asset, just return the wS balance - return _checkBalance(wS); - } - - /// @dev Only wS is supported in the OETH Vault so return the wS 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(wS).balanceOf(address(this)); - } +contract OSonicVaultCore is OETHVaultCore { + /// @param _wS Sonic's Wrapped S token + constructor(address _wS) OETHVaultCore(_wS) {} } From 25bdd793d773fb09d55e2703130564e561fea3d9 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Wed, 18 Dec 2024 17:27:50 +1100 Subject: [PATCH 208/273] WIP sonic --- contracts/deploy/sonic/000_mock.js | 73 +++++----- contracts/package.json | 6 + contracts/test/_fixture-sonic.js | 162 ++++++++++++++++++++++ contracts/test/helpers.js | 8 ++ contracts/test/vault/os-vault.sonic.js | 180 +++++++++++++++++++++++++ 5 files changed, 393 insertions(+), 36 deletions(-) create mode 100644 contracts/test/_fixture-sonic.js create mode 100644 contracts/test/vault/os-vault.sonic.js diff --git a/contracts/deploy/sonic/000_mock.js b/contracts/deploy/sonic/000_mock.js index 45c40835a7..a860fe20df 100644 --- a/contracts/deploy/sonic/000_mock.js +++ b/contracts/deploy/sonic/000_mock.js @@ -17,93 +17,94 @@ const deployCore = async () => { await deployWithConfirmation("WOSonicProxy"); await deployWithConfirmation("OSonicVaultProxy"); - const cOETHbProxy = await ethers.getContract("OSonicProxy"); - const cwOETHbProxy = await ethers.getContract("WSonicProxy"); - const cOETHbVaultProxy = await ethers.getContract("OSonicVaultProxy"); + const cOSonicProxy = await ethers.getContract("OSonicProxy"); + const cWOSonicProxy = await ethers.getContract("WSonicProxy"); + const cOSonicVaultProxy = await ethers.getContract("OSonicVaultProxy"); // Core contracts - const dOETHb = await deployWithConfirmation("OSonic"); - const dwOETHb = await deployWithConfirmation("WOSonic", [ - cOETHbProxy.address, // Base token + const dOSonic = await deployWithConfirmation("OSonic"); + const dWOSonic = await deployWithConfirmation("WOSonic", [ + cOSonicProxy.address, // Base token ]); - const dOETHbVault = await deployWithConfirmation("OSonicVault"); - const dOETHbVaultCore = await deployWithConfirmation("OSonicVaultCore", [ + const dOSonicVault = await deployWithConfirmation("OSonicVault"); + const dOSonicVaultCore = await deployWithConfirmation("OSonicVaultCore", [ cWS.address, ]); - const dOETHbVaultAdmin = await deployWithConfirmation("OSonicVaultAdmin"); + const dOSonicVaultAdmin = await deployWithConfirmation("OSonicVaultAdmin"); // Get contract instances - const cOETHb = await ethers.getContractAt("OSonic", cOETHbProxy.address); - const cwOETHb = await ethers.getContractAt("WOSonic", cwOETHbProxy.address); - const cOETHbVault = await ethers.getContractAt( + const cOSonic = await ethers.getContractAt("OSonic", cOSonicProxy.address); + const cWOSonic = await ethers.getContractAt("WOSonic", cWOSonicProxy.address); + const cOSonicVault = await ethers.getContractAt( "IVault", - cOETHbVaultProxy.address + cOSonicVaultProxy.address ); const cOracleRouter = await ethers.getContract("MockOracleRouter"); - // Init OETHb + // Init OSonic const resolution = ethers.utils.parseUnits("1", 27); - const initDataOETHb = cOETHb.interface.encodeFunctionData( + const initDataOSonic = cOSonic.interface.encodeFunctionData( "initialize(string,string,address,uint256)", [ "Origin S", // Token Name "OS", // Token Symbol - cOETHbVaultProxy.address, // OETHb Vault + cOSonicVaultProxy.address, // OETHb Vault resolution, // HighRes ] ); // prettier-ignore - await cOETHbProxy + await cOSonicProxy .connect(sDeployer)["initialize(address,address,bytes)"]( - dOETHb.address, + dOSonic.address, governorAddr, - initDataOETHb + initDataOSonic ); - // Init OETHbVault - const initDataOETHbVault = cOETHbVault.interface.encodeFunctionData( + // Init OSonicVault + const initDataOSonicVault = cOSonicVault.interface.encodeFunctionData( "initialize(address,address)", [ cOracleRouter.address, // OracleRouter - cOETHbProxy.address, // OETHb + cOSonicProxy.address, // OETHb ] ); // prettier-ignore - await cOETHbVaultProxy + await cOSonicVaultProxy .connect(sDeployer)["initialize(address,address,bytes)"]( - dOETHbVault.address, + dOSonicVault.address, governorAddr, - initDataOETHbVault + initDataOSonicVault ); - // Init wOETHb - const initDatawOETHb = cwOETHb.interface.encodeFunctionData( + // Init WOSonic + const initDataWOSonic = cWOSonic.interface.encodeFunctionData( "initialize()", [] ); // prettier-ignore - await cwOETHbProxy + await cWOSonicProxy .connect(sDeployer)["initialize(address,address,bytes)"]( - dwOETHb.address, + dWOSonic.address, governorAddr, - initDatawOETHb + initDataWOSonic ) - await cOETHbVaultProxy.connect(sGovernor).upgradeTo(dOETHbVaultCore.address); - await cOETHbVault.connect(sGovernor).setAdminImpl(dOETHbVaultAdmin.address); + await cOSonicVaultProxy + .connect(sGovernor) + .upgradeTo(dOSonicVaultCore.address); + await cOSonicVault.connect(sGovernor).setAdminImpl(dOSonicVaultAdmin.address); - await cOETHbVault.connect(sGovernor).supportAsset(cWS.address, 0); - await cOETHbVault.connect(sGovernor).unpauseCapital(); + await cOSonicVault.connect(sGovernor).supportAsset(cWS.address, 0); + await cOSonicVault.connect(sGovernor).unpauseCapital(); }; const main = async () => { await deployMocks(); - // await deployOracleRouter(); await deployCore(); }; main.id = "000_mock"; -main.tags = ["base_unit_tests"]; +main.tags = ["sonic_unit_tests"]; // Only run for unit tests main.skip = () => isFork || isSonic; diff --git a/contracts/package.json b/contracts/package.json index 41a2283c17..84790884da 100644 --- a/contracts/package.json +++ b/contracts/package.json @@ -9,6 +9,7 @@ "deploy:arbitrum": "npx hardhat deploy --network arbitrumOne --tags arbitrumOne --verbose", "deploy:holesky": "NETWORK_NAME=holesky npx hardhat deploy --network holesky --verbose", "deploy:base": "NETWORK_NAME=base npx hardhat deploy --network base --verbose", + "deploy:sonic": "NETWORK_NAME=sonic npx hardhat deploy --network sonic --verbose", "abi:generate": "(rm -rf deployments/hardhat && mkdir -p dist/abi && npx hardhat deploy --export '../dist/network.json')", "abi:dist": "find ./artifacts/contracts -name \"*.json\" -type f -exec cp {} ./dist/abi \\; && rm -rf dist/abi/*.dbg.json dist/abi/Mock*.json && cp ./abi.package.json dist/package.json && cp ./.npmrc.abi dist/.npmrc", "node": "yarn run node:fork", @@ -16,6 +17,7 @@ "node:arb": "FORK_NETWORK_NAME=arbitrumOne yarn run node:fork", "node:hol": "FORK_NETWORK_NAME=holesky yarn run node:fork", "node:base": "FORK_NETWORK_NAME=base yarn run node:fork", + "node:sonic": "FORK_NETWORK_NAME=sonic yarn run node:fork", "lint": "yarn run lint:js && yarn run lint:sol", "lint:js": "eslint \"test/**/*.js\" \"tasks/**/*.js\" \"deploy/**/*.js\"", "lint:sol": "solhint \"contracts/**/*.sol\"", @@ -25,9 +27,11 @@ "prettier:sol": "prettier --write \"contracts/**/*.sol\"", "test": "rm -rf deployments/hardhat && IS_TEST=true npx hardhat test", "test:base": "rm -rf deployments/hardhat && UNIT_TESTS_NETWORK=base IS_TEST=true npx hardhat test", + "test:sonic": "rm -rf deployments/hardhat && UNIT_TESTS_NETWORK=sonic IS_TEST=true npx hardhat test", "test:fork": "./fork-test.sh", "test:arb-fork": "FORK_NETWORK_NAME=arbitrumOne ./fork-test.sh", "test:base-fork": "FORK_NETWORK_NAME=base ./fork-test.sh", + "test:sonic-fork": "FORK_NETWORK_NAME=sonic ./fork-test.sh", "test:hol-fork": "FORK_NETWORK_NAME=holesky ./fork-test.sh", "test:fork:w_trace": "TRACE=true ./fork-test.sh", "fund": "FORK=true npx hardhat fund --network localhost", @@ -40,9 +44,11 @@ "cache-clean:light": "rm -rf cache/hardhat-network-fork/network-1337/", "test:coverage": "IS_TEST=true npx hardhat coverage", "test:coverage:base": "UNIT_TESTS_NETWORK=base IS_TEST=true npx hardhat coverage", + "test:coverage:sonic": "UNIT_TESTS_NETWORK=sonic IS_TEST=true npx hardhat coverage", "test:coverage:fork": "REPORT_COVERAGE=true ./fork-test.sh", "test:coverage:arb-fork": "REPORT_COVERAGE=true FORK_NETWORK_NAME=arbitrumOne ./fork-test.sh", "test:coverage:base-fork": "REPORT_COVERAGE=true FORK_NETWORK_NAME=base ./fork-test.sh", + "test:coverage:sonic-fork": "REPORT_COVERAGE=true FORK_NETWORK_NAME=sonic ./fork-test.sh", "test:coverage:hol-fork": "REPORT_COVERAGE=true FORK_NETWORK_NAME=holesky ./fork-test.sh" }, "author": "Origin Protocol Inc ", diff --git a/contracts/test/_fixture-sonic.js b/contracts/test/_fixture-sonic.js new file mode 100644 index 0000000000..f970573742 --- /dev/null +++ b/contracts/test/_fixture-sonic.js @@ -0,0 +1,162 @@ +const hre = require("hardhat"); +const { ethers } = hre; +const mocha = require("mocha"); +const { isFork, isSonicFork, oethUnits } = require("./helpers"); +const { impersonateAndFund, impersonateAccount } = require("../utils/signers"); +const { nodeRevert, nodeSnapshot } = require("./_fixture"); +const addresses = require("../utils/addresses"); +const hhHelpers = require("@nomicfoundation/hardhat-network-helpers"); + +const log = require("../utils/logger")("test:fixtures-arb"); + +const MINTER_ROLE = + "0x9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a6"; +const BURNER_ROLE = + "0x3c11d16cbaffd01df69ce1c404f6340ee057498f5f00246190ea54220576a848"; + +let snapshotId; +const defaultSonicFixture = deployments.createFixture(async () => { + if (!snapshotId && !isFork) { + snapshotId = await nodeSnapshot(); + } + + if (!isSonicFork && isFork) { + // Only works for Sonic fork + return; + } + + if (isFork) { + // Fund deployer account + const { deployerAddr } = await getNamedAccounts(); + await impersonateAndFund(deployerAddr); + } + + log( + `Before deployments with param "${ + isFork ? ["sonic"] : ["sonic_unit_tests"] + }"` + ); + + // Run the contract deployments + await deployments.fixture(isFork ? ["sonic"] : ["sonic_unit_tests"], { + keepExistingDeployments: true, + fallbackToGlobal: true, + }); + + // OETHb + const oSonicProxy = await ethers.getContract("OSonicProxy"); + const oSonic = await ethers.getContractAt("OSonic", oSonicProxy.address); + + // Wrapped Origin S (4626) + const wOSonicProxy = await ethers.getContract("WOSonicProxy"); + const wOSonic = await ethers.getContractAt("WOSonic", wOSonicProxy.address); + + // Origin S Vault + const oSonicVaultProxy = await ethers.getContract("OSonicVaultProxy"); + const oSonicVault = await ethers.getContractAt( + "IVault", + oSonicVaultProxy.address + ); + + let dripper, harvester; + if (isFork) { + // Harvester + const harvesterProxy = await ethers.getContract("OSonicHarvesterProxy"); + harvester = await ethers.getContractAt( + "OSonicHarvester", + harvesterProxy.address + ); + + // Dripper + const dripperProxy = await ethers.getContract("OSonicDripperProxy"); + dripper = await ethers.getContractAt( + "FixedRateDripper", + dripperProxy.address + ); + } + + // WETH + let wS; + + if (isFork) { + wS = await ethers.getContractAt("IERC20", addresses.base.WETH); + } else { + wS = await ethers.getContract("MockWS"); + } + + // Zapper + const zapper = !isFork + ? undefined + : await ethers.getContract("OETHBaseZapper"); + + const signers = await hre.ethers.getSigners(); + + const [minter, burner, rafael, nick, clement] = signers.slice(4); // Skip first 4 addresses to avoid conflict + const { governorAddr, strategistAddr, timelockAddr } = + await getNamedAccounts(); + const governor = await ethers.getSigner(isFork ? timelockAddr : governorAddr); + await hhHelpers.setBalance(governorAddr, oethUnits("1")); // Fund governor with some ETH + + const guardian = await ethers.getSigner(governorAddr); + const timelock = await ethers.getContractAt( + "ITimelockController", + timelockAddr + ); + const oSonicVaultSigner = await impersonateAccount(oSonicVault.address); + + let strategist; + if (isFork) { + // Impersonate strategist on Fork + strategist = await impersonateAndFund(strategistAddr); + strategist.address = strategistAddr; + + await impersonateAndFund(governor.address); + await impersonateAndFund(timelock.address); + + // configure Vault to not automatically deposit to strategy + await oSonicVault.connect(governor).setVaultBuffer(oethUnits("1")); + } + + if (isFork) { + // Governor opts in for rebasing + await oSonic.connect(governor).rebaseOptIn(); + } + + return { + // Origin S + oSonic, + oSonicVault, + wOSonic, + zapper, + harvester, + dripper, + + // Wrapped S + wS, + + // Signers + governor, + guardian, + timelock, + strategist, + minter, + burner, + oSonicVaultSigner, + + rafael, + nick, + clement, + }; +}); + +mocha.after(async () => { + if (snapshotId) { + await nodeRevert(snapshotId); + } +}); + +module.exports = { + defaultSonicFixture, + MINTER_ROLE, + BURNER_ROLE, +}; diff --git a/contracts/test/helpers.js b/contracts/test/helpers.js index eae2879037..f0ebd61011 100644 --- a/contracts/test/helpers.js +++ b/contracts/test/helpers.js @@ -305,6 +305,10 @@ const isBase = hre.network.name == "base"; const isBaseFork = isFork && process.env.FORK_NETWORK_NAME == "base"; const isBaseOrFork = isBase || isBaseFork; const isBaseUnitTest = process.env.UNIT_TESTS_NETWORK === "base"; +const isSonic = hre.network.name == "sonic"; +const isSonicFork = isFork && process.env.FORK_NETWORK_NAME == "sonic"; +const isSonicOrFork = isSonic || isSonicFork; +const isSonicUnitTest = process.env.UNIT_TESTS_NETWORK === "sonic"; /// Advances the EVM time by the given number of seconds const advanceTime = async (seconds) => { @@ -838,6 +842,10 @@ module.exports = { isBaseFork, isBaseOrFork, isBaseUnitTest, + isSonic, + isSonicFork, + isSonicOrFork, + isSonicUnitTest, getOracleAddress, setOracleTokenPriceUsd, getOracleAddresses, diff --git a/contracts/test/vault/os-vault.sonic.js b/contracts/test/vault/os-vault.sonic.js new file mode 100644 index 0000000000..0b495a3a70 --- /dev/null +++ b/contracts/test/vault/os-vault.sonic.js @@ -0,0 +1,180 @@ +const { createFixtureLoader } = require("../_fixture"); +const { defaultSonicFixture } = require("../_fixture-sonic"); +const { expect } = require("chai"); +const addresses = require("../../utils/addresses"); +const { impersonateAndFund } = require("../../utils/signers"); +const { oethUnits } = require("../helpers"); +const { deployWithConfirmation } = require("../../utils/deploy"); + +const sonicFixture = createFixtureLoader(defaultSonicFixture); + +describe("Origin S Vault", function () { + let fixture; + + describe("Mint Whitelist", function () { + beforeEach(async () => { + fixture = await sonicFixture(); + }); + + it("Should allow a strategy to be added to the whitelist", async () => { + const { oSonicVault, governor } = fixture; + + // Pretend addresses.dead is a strategy + await oSonicVault.connect(governor).approveStrategy(addresses.dead); + + const tx = oSonicVault + .connect(governor) + .addStrategyToMintWhitelist(addresses.dead); + + await expect(tx).to.emit(oSonicVault, "StrategyAddedToMintWhitelist"); + expect(await oSonicVault.isMintWhitelistedStrategy(addresses.dead)).to.be + .true; + }); + + it("Should allow a strategy to be removed from the whitelist", async () => { + const { oethbVault, governor } = fixture; + + // Pretend addresses.dead is a strategy + await oethbVault.connect(governor).approveStrategy(addresses.dead); + await oethbVault + .connect(governor) + .addStrategyToMintWhitelist(addresses.dead); + + // Remove it + const tx = oethbVault + .connect(governor) + .removeStrategyFromMintWhitelist(addresses.dead); + + await expect(tx).to.emit(oethbVault, "StrategyRemovedFromMintWhitelist"); + expect(await oethbVault.isMintWhitelistedStrategy(addresses.dead)).to.be + .false; + }); + + it("Should not allow non-governor to add to whitelist", async () => { + const { oethbVault, rafael } = fixture; + const tx = oethbVault + .connect(rafael) + .addStrategyToMintWhitelist(addresses.dead); + await expect(tx).to.be.revertedWith("Caller is not the Governor"); + }); + + it("Should not allow non-governor to remove from whitelist", async () => { + const { oethbVault, rafael } = fixture; + const tx = oethbVault + .connect(rafael) + .removeStrategyFromMintWhitelist(addresses.dead); + await expect(tx).to.be.revertedWith("Caller is not the Governor"); + }); + + it("Should not allow adding unapproved strategy", async () => { + const { oethbVault, governor } = fixture; + const tx = oethbVault + .connect(governor) + .addStrategyToMintWhitelist(addresses.dead); + await expect(tx).to.be.revertedWith("Strategy not approved"); + }); + + it("Should not whitelist if already whitelisted", async () => { + const { oethbVault, governor } = fixture; + + await oethbVault.connect(governor).approveStrategy(addresses.dead); + await oethbVault + .connect(governor) + .addStrategyToMintWhitelist(addresses.dead); + + const tx = oethbVault + .connect(governor) + .addStrategyToMintWhitelist(addresses.dead); + await expect(tx).to.be.revertedWith("Already whitelisted"); + }); + + it("Should revert when removing unwhitelisted strategy", async () => { + const { oethbVault, governor } = fixture; + + const tx = oethbVault + .connect(governor) + .removeStrategyFromMintWhitelist(addresses.dead); + await expect(tx).to.be.revertedWith("Not whitelisted"); + }); + }); + + describe("Mint & Burn For Strategy", function () { + let strategySigner, mockStrategy; + + beforeEach(async () => { + fixture = await sonicFixture(); + const { oethbVault, governor } = fixture; + + mockStrategy = await deployWithConfirmation("MockStrategy"); + + await oethbVault.connect(governor).approveStrategy(mockStrategy.address); + await oethbVault + .connect(governor) + .addStrategyToMintWhitelist(mockStrategy.address); + strategySigner = await impersonateAndFund(mockStrategy.address); + }); + + it("Should allow a whitelisted strategy to mint and burn", async () => { + const { oethbVault, oethb } = fixture; + + await oethbVault.rebase(); + + const amount = oethUnits("1"); + + const supplyBefore = await oethb.totalSupply(); + await oethbVault.connect(strategySigner).mintForStrategy(amount); + expect(await oethb.balanceOf(mockStrategy.address)).to.eq(amount); + expect(await oethb.totalSupply()).to.eq(supplyBefore.add(amount)); + + await oethbVault.connect(strategySigner).burnForStrategy(amount); + expect(await oethb.balanceOf(mockStrategy.address)).to.eq(0); + expect(await oethb.totalSupply()).to.eq(supplyBefore); + }); + + it("Should not allow a non-supported strategy to mint", async () => { + const { oethbVault, governor } = fixture; + + const amount = oethUnits("1"); + + const tx = oethbVault.connect(governor).mintForStrategy(amount); + await expect(tx).to.be.revertedWith("Unsupported strategy"); + }); + + it("Should not allow a non-supported strategy to burn", async () => { + const { oethbVault, governor } = fixture; + + const amount = oethUnits("1"); + + const tx = oethbVault.connect(governor).burnForStrategy(amount); + await expect(tx).to.be.revertedWith("Unsupported strategy"); + }); + + it("Should not allow a non-white listed strategy to mint", async () => { + const { oethbVault, governor } = fixture; + + // Pretend addresses.dead is a strategy + await oethbVault.connect(governor).approveStrategy(addresses.dead); + + const amount = oethUnits("1"); + + const tx = oethbVault + .connect(await impersonateAndFund(addresses.dead)) + .mintForStrategy(amount); + await expect(tx).to.be.revertedWith("Not whitelisted strategy"); + }); + + it("Should not allow a non-white listed strategy to burn", async () => { + const { oethbVault, governor } = fixture; + + // Pretend addresses.dead is a strategy + await oethbVault.connect(governor).approveStrategy(addresses.dead); + + const amount = oethUnits("1"); + + const tx = oethbVault + .connect(await impersonateAndFund(addresses.dead)) + .burnForStrategy(amount); + await expect(tx).to.be.revertedWith("Not whitelisted strategy"); + }); + }); +}); From c87f50381e00f0db389968dbc6ca295da4360dfc Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Wed, 18 Dec 2024 20:21:29 +1100 Subject: [PATCH 209/273] WIP sonic --- contracts/deploy/sonic/000_mock.js | 30 +++++-- contracts/hardhat.config.js | 2 + contracts/test/_fixture-base.js | 2 +- contracts/test/_fixture-sonic.js | 12 ++- contracts/test/vault/os-vault.sonic.js | 107 ++++++++++++++++++++++++- 5 files changed, 139 insertions(+), 14 deletions(-) diff --git a/contracts/deploy/sonic/000_mock.js b/contracts/deploy/sonic/000_mock.js index a860fe20df..b4040190f3 100644 --- a/contracts/deploy/sonic/000_mock.js +++ b/contracts/deploy/sonic/000_mock.js @@ -1,10 +1,25 @@ const { deployWithConfirmation } = require("../../utils/deploy"); -const { isFork, isSonic } = require("../../test/helpers"); +const { isFork, isSonic, oethUnits } = require("../../test/helpers"); const deployMocks = async () => { await deployWithConfirmation("MockWS", []); }; +const deployOracleRouter = async () => { + const cWS = await ethers.getContract("MockWS"); + + await deployWithConfirmation("MockOracleRouter"); + const cOracleRouter = await ethers.getContract("MockOracleRouter"); + + const wsFeed = await deployWithConfirmation( + "MockPriceFeedWS", + [oethUnits("1"), 18], + "MockChainlinkOracleFeed" + ); + + await cOracleRouter.setFeed(cWS.address, wsFeed.address, 24 * 60 * 60); +}; + const deployCore = async () => { const { governorAddr, deployerAddr } = await getNamedAccounts(); const sGovernor = await ethers.provider.getSigner(governorAddr); @@ -18,19 +33,23 @@ const deployCore = async () => { await deployWithConfirmation("OSonicVaultProxy"); const cOSonicProxy = await ethers.getContract("OSonicProxy"); - const cWOSonicProxy = await ethers.getContract("WSonicProxy"); + const cWOSonicProxy = await ethers.getContract("WOSonicProxy"); const cOSonicVaultProxy = await ethers.getContract("OSonicVaultProxy"); // Core contracts const dOSonic = await deployWithConfirmation("OSonic"); const dWOSonic = await deployWithConfirmation("WOSonic", [ cOSonicProxy.address, // Base token + "Wrapped Origin S", // Token Name + "wOS", // Token Symbol ]); - const dOSonicVault = await deployWithConfirmation("OSonicVault"); const dOSonicVaultCore = await deployWithConfirmation("OSonicVaultCore", [ cWS.address, ]); - const dOSonicVaultAdmin = await deployWithConfirmation("OSonicVaultAdmin"); + + const dOSonicVaultAdmin = await deployWithConfirmation("OSonicVaultAdmin", [ + cWS.address, + ]); // Get contract instances const cOSonic = await ethers.getContractAt("OSonic", cOSonicProxy.address); @@ -71,7 +90,7 @@ const deployCore = async () => { // prettier-ignore await cOSonicVaultProxy .connect(sDeployer)["initialize(address,address,bytes)"]( - dOSonicVault.address, + dOSonicVaultCore.address, governorAddr, initDataOSonicVault ); @@ -100,6 +119,7 @@ const deployCore = async () => { const main = async () => { await deployMocks(); + await deployOracleRouter(); await deployCore(); }; diff --git a/contracts/hardhat.config.js b/contracts/hardhat.config.js index 8341ae1596..092370a3fb 100644 --- a/contracts/hardhat.config.js +++ b/contracts/hardhat.config.js @@ -148,6 +148,8 @@ module.exports = { ? { tags: ["arbitrumOne"] } : isBaseFork ? { tags: ["base"] } + : isSonicFork + ? { tags: ["sonic"] } : {}), }, mainnet: { diff --git a/contracts/test/_fixture-base.js b/contracts/test/_fixture-base.js index 4b73d0f896..0895098ecc 100644 --- a/contracts/test/_fixture-base.js +++ b/contracts/test/_fixture-base.js @@ -9,7 +9,7 @@ const addresses = require("../utils/addresses"); const erc20Abi = require("./abi/erc20.json"); const hhHelpers = require("@nomicfoundation/hardhat-network-helpers"); -const log = require("../utils/logger")("test:fixtures-arb"); +const log = require("../utils/logger")("test:fixtures-base"); const aeroSwapRouterAbi = require("./abi/aerodromeSwapRouter.json"); const aeroNonfungiblePositionManagerAbi = require("./abi/aerodromeNonfungiblePositionManager.json"); diff --git a/contracts/test/_fixture-sonic.js b/contracts/test/_fixture-sonic.js index f970573742..03b77aafa8 100644 --- a/contracts/test/_fixture-sonic.js +++ b/contracts/test/_fixture-sonic.js @@ -7,7 +7,7 @@ const { nodeRevert, nodeSnapshot } = require("./_fixture"); const addresses = require("../utils/addresses"); const hhHelpers = require("@nomicfoundation/hardhat-network-helpers"); -const log = require("../utils/logger")("test:fixtures-arb"); +const log = require("../utils/logger")("test:fixtures-sonic"); const MINTER_ROLE = "0x9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a6"; @@ -43,7 +43,7 @@ const defaultSonicFixture = deployments.createFixture(async () => { fallbackToGlobal: true, }); - // OETHb + // Origin S token const oSonicProxy = await ethers.getContract("OSonicProxy"); const oSonic = await ethers.getContractAt("OSonic", oSonicProxy.address); @@ -75,19 +75,17 @@ const defaultSonicFixture = deployments.createFixture(async () => { ); } - // WETH + // Sonic's wrapped S token let wS; if (isFork) { - wS = await ethers.getContractAt("IERC20", addresses.base.WETH); + wS = await ethers.getContractAt("IERC20", addresses.sonic.WS); } else { wS = await ethers.getContract("MockWS"); } // Zapper - const zapper = !isFork - ? undefined - : await ethers.getContract("OETHBaseZapper"); + const zapper = !isFork ? undefined : await ethers.getContract("OSonicZapper"); const signers = await hre.ethers.getSigners(); diff --git a/contracts/test/vault/os-vault.sonic.js b/contracts/test/vault/os-vault.sonic.js index 0b495a3a70..3eeb537be8 100644 --- a/contracts/test/vault/os-vault.sonic.js +++ b/contracts/test/vault/os-vault.sonic.js @@ -1,6 +1,8 @@ +const { expect } = require("chai"); +const { parseUnits } = require("ethers/lib/utils"); + const { createFixtureLoader } = require("../_fixture"); const { defaultSonicFixture } = require("../_fixture-sonic"); -const { expect } = require("chai"); const addresses = require("../../utils/addresses"); const { impersonateAndFund } = require("../../utils/signers"); const { oethUnits } = require("../helpers"); @@ -10,6 +12,109 @@ const sonicFixture = createFixtureLoader(defaultSonicFixture); describe("Origin S Vault", function () { let fixture; + beforeEach(async () => { + fixture = await sonicFixture(); + }); + + const snapData = async (fixture) => { + const { oSonic, oSonicVault, wS, user } = fixture; + + const oSonicTotalSupply = await oSonic.totalSupply(); + const oSonicTotalValue = await oSonicVault.totalValue(); + const vaultCheckBalance = await oSonicVault.checkBalance(wS.address); + const userOSonic = await oSonic.balanceOf(user.address); + const userWS = await wS.balanceOf(user.address); + const vaultWS = await wS.balanceOf(oSonicVault.address); + const queue = await oSonicVault.withdrawalQueueMetadata(); + + return { + oSonicTotalSupply, + oSonicTotalValue, + vaultCheckBalance, + userOSonic, + userWS, + vaultWS, + queue, + }; + }; + + const assertChangedData = async (dataBefore, delta, fixture) => { + const { oSonic, oSonicVault, wS, user } = fixture; + + expect(await oSonic.totalSupply(), "OSonic Total Supply").to.equal( + dataBefore.oethTotalSupply.add(delta.oethTotalSupply) + ); + expect(await oSonicVault.totalValue(), "Vault Total Value").to.equal( + dataBefore.oethTotalValue.add(delta.oethTotalValue) + ); + expect( + await oSonicVault.checkBalance(wS.address), + "Vault Check Balance of wS" + ).to.equal(dataBefore.vaultCheckBalance.add(delta.vaultCheckBalance)); + expect(await oSonic.balanceOf(user.address), "user's OS balance").to.equal( + dataBefore.userOeth.add(delta.userOeth) + ); + expect(await wS.balanceOf(user.address), "user's wS balance").to.equal( + dataBefore.userWeth.add(delta.userWeth) + ); + expect( + await wS.balanceOf(oSonicVault.address), + "Vault wS balance" + ).to.equal(dataBefore.vaultWeth.add(delta.vaultWeth)); + + const queueAfter = await oSonicVault.withdrawalQueueMetadata(); + expect(queueAfter.queued, "Queued").to.equal( + dataBefore.queue.queued.add(delta.queued) + ); + expect(queueAfter.claimable, "Claimable").to.equal( + dataBefore.queue.claimable.add(delta.claimable) + ); + expect(queueAfter.claimed, "Claimed").to.equal( + dataBefore.queue.claimed.add(delta.claimed) + ); + expect(queueAfter.nextWithdrawalIndex, "nextWithdrawalIndex").to.equal( + dataBefore.queue.nextWithdrawalIndex.add(delta.nextWithdrawalIndex) + ); + }; + + describe("Mint", () => { + it("Should mint with wS", async () => { + const { oSonicVault, wS, nick } = fixture; + + const fixtureWithUser = { ...fixture, user: nick }; + const dataBefore = await snapData(fixtureWithUser); + + const amount = parseUnits("1", 18); + const minOeth = parseUnits("0.8", 18); + + await wS.connect(nick).approve(oSonicVault.address, amount); + + const tx = await oSonicVault + .connect(nick) + .mint(wS.address, amount, minOeth); + + await expect(tx) + .to.emit(oSonicVault, "Mint") + .withArgs(nick.address, amount); + + await assertChangedData( + dataBefore, + { + oSonicTotalSupply: amount, + oSonicTotalValue: amount, + vaultCheckBalance: amount, + userOSonic: amount, + userWS: amount.mul(-1), + vaultWS: amount, + queued: 0, + claimable: 0, + claimed: 0, + nextWithdrawalIndex: 0, + }, + fixtureWithUser + ); + }); + }); describe("Mint Whitelist", function () { beforeEach(async () => { From cde33f008e5cd5e88052b507ce811068704caf44 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Wed, 18 Dec 2024 21:33:48 +1100 Subject: [PATCH 210/273] WIP sonic --- contracts/test/_fixture-sonic.js | 9 +++++++++ contracts/test/vault/os-vault.sonic.js | 14 +++++++------- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/contracts/test/_fixture-sonic.js b/contracts/test/_fixture-sonic.js index 03b77aafa8..3c57f0f20d 100644 --- a/contracts/test/_fixture-sonic.js +++ b/contracts/test/_fixture-sonic.js @@ -115,6 +115,15 @@ const defaultSonicFixture = deployments.createFixture(async () => { await oSonicVault.connect(governor).setVaultBuffer(oethUnits("1")); } + for (const user of [rafael, nick, clement]) { + // Mint some Sonic Wrapped S + await hhHelpers.setBalance(user.address, oethUnits("100000000")); + await wS.connect(user).deposit({ value: oethUnits("10000000") }); + + // Set allowance on the vault + await wS.connect(user).approve(oSonicVault.address, oethUnits("5000")); + } + if (isFork) { // Governor opts in for rebasing await oSonic.connect(governor).rebaseOptIn(); diff --git a/contracts/test/vault/os-vault.sonic.js b/contracts/test/vault/os-vault.sonic.js index 3eeb537be8..a47f1e41cb 100644 --- a/contracts/test/vault/os-vault.sonic.js +++ b/contracts/test/vault/os-vault.sonic.js @@ -42,25 +42,25 @@ describe("Origin S Vault", function () { const { oSonic, oSonicVault, wS, user } = fixture; expect(await oSonic.totalSupply(), "OSonic Total Supply").to.equal( - dataBefore.oethTotalSupply.add(delta.oethTotalSupply) + dataBefore.oSonicTotalSupply.add(delta.oSonicTotalSupply) ); expect(await oSonicVault.totalValue(), "Vault Total Value").to.equal( - dataBefore.oethTotalValue.add(delta.oethTotalValue) + dataBefore.oSonicTotalValue.add(delta.oSonicTotalValue) ); expect( await oSonicVault.checkBalance(wS.address), "Vault Check Balance of wS" ).to.equal(dataBefore.vaultCheckBalance.add(delta.vaultCheckBalance)); expect(await oSonic.balanceOf(user.address), "user's OS balance").to.equal( - dataBefore.userOeth.add(delta.userOeth) + dataBefore.userOSonic.add(delta.userOSonic) ); expect(await wS.balanceOf(user.address), "user's wS balance").to.equal( - dataBefore.userWeth.add(delta.userWeth) + dataBefore.userWS.add(delta.userWS) ); expect( await wS.balanceOf(oSonicVault.address), "Vault wS balance" - ).to.equal(dataBefore.vaultWeth.add(delta.vaultWeth)); + ).to.equal(dataBefore.vaultWS.add(delta.vaultWS)); const queueAfter = await oSonicVault.withdrawalQueueMetadata(); expect(queueAfter.queued, "Queued").to.equal( @@ -116,7 +116,7 @@ describe("Origin S Vault", function () { }); }); - describe("Mint Whitelist", function () { + describe.skip("Mint Whitelist", function () { beforeEach(async () => { fixture = await sonicFixture(); }); @@ -203,7 +203,7 @@ describe("Origin S Vault", function () { }); }); - describe("Mint & Burn For Strategy", function () { + describe.skip("Mint & Burn For Strategy", function () { let strategySigner, mockStrategy; beforeEach(async () => { From 40185e4bdf6a1641b838076677fe0084ebfc7864 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Thu, 19 Dec 2024 19:13:13 +1100 Subject: [PATCH 211/273] Got unit tests working --- contracts/test/_global-hooks.js | 13 ++++++++- contracts/utils/deploy-l2.js | 52 ++++++++++++++++++++++++++++++++- contracts/utils/deploy.js | 14 ++++++--- 3 files changed, 73 insertions(+), 6 deletions(-) diff --git a/contracts/test/_global-hooks.js b/contracts/test/_global-hooks.js index 788d7ee577..6873bc7824 100644 --- a/contracts/test/_global-hooks.js +++ b/contracts/test/_global-hooks.js @@ -6,6 +6,8 @@ const { isHoleskyFork, isBaseFork, isBaseUnitTest, + isSonicFork, + isSonicUnitTest, } = require("./helpers"); const _chunkId = Number(process.env.CHUNK_ID); @@ -46,7 +48,12 @@ mocha.before(function () { const isArbTestFile = s.file.endsWith(".arb.fork-test.js"); const isBaseTestFile = s.file.endsWith(".base.fork-test.js"); const isBaseUnitTestFile = s.file.endsWith(".base.js"); - const unitTest = !s.file.endsWith(".fork-test.js") && !isBaseUnitTestFile; + const isSonicTestFile = s.file.endsWith(".sonic.fork-test.js"); + const isSonicUnitTestFile = s.file.endsWith(".sonic.js"); + const unitTest = + !s.file.endsWith(".fork-test.js") && + !isBaseUnitTestFile && + !isSonicUnitTestFile; if (isArbFork) { return isArbTestFile; @@ -54,10 +61,14 @@ mocha.before(function () { return isMainnetForkTestFile; } else if (isBaseFork) { return isBaseTestFile; + } else if (isSonicFork) { + return isSonicTestFile; } else if (isHoleskyFork) { return isHoleskyTestFile; } else if (isBaseUnitTest) { return isBaseUnitTestFile; + } else if (isSonicUnitTest) { + return isSonicUnitTestFile; } else { // else is unit test return unitTest; diff --git a/contracts/utils/deploy-l2.js b/contracts/utils/deploy-l2.js index 0d4564c78d..edfcc3002b 100644 --- a/contracts/utils/deploy-l2.js +++ b/contracts/utils/deploy-l2.js @@ -1,4 +1,9 @@ -const { isFork, isArbFork, isBaseFork } = require("../test/helpers"); +const { + isFork, + isArbFork, + isBaseFork, + isSonicFork, +} = require("../test/helpers"); const addresses = require("./addresses"); const { deployWithConfirmation, @@ -202,8 +207,53 @@ function deployOnBaseWithGuardian(opts, fn) { return main; } +function deployOnSonic(opts, fn) { + const { deployName, dependencies } = opts; + + const runDeployment = async (hre) => { + const tools = { + deployWithConfirmation, + ethers: hre.ethers, + getTxOpts: getTxOpts, + withConfirmation, + }; + + if (isFork) { + const { deployerAddr } = await getNamedAccounts(); + await impersonateAndFund(deployerAddr); + } + + await fn(tools); + }; + + const main = async (hre) => { + console.log(`Running ${deployName} deployment...`); + if (!hre) { + hre = require("hardhat"); + } + await runDeployment(hre); + console.log(`${deployName} deploy done.`); + return true; + }; + + main.id = deployName; + main.dependencies = dependencies || []; + + main.tags = ["sonic"]; + + main.skip = () => + !( + isSonicFork || + hre.network.name == "sonic" || + hre.network.config.chainId == 146 + ); + + return main; +} + module.exports = { deployOnArb, deployOnBase, deployOnBaseWithGuardian, + deployOnSonic, }; diff --git a/contracts/utils/deploy.js b/contracts/utils/deploy.js index d2cba63269..930c2114fc 100644 --- a/contracts/utils/deploy.js +++ b/contracts/utils/deploy.js @@ -23,6 +23,8 @@ const { isArbitrumOne, isBase, isBaseFork, + isSonic, + isSonicFork, isCI, isTest, } = require("../test/helpers.js"); @@ -110,7 +112,7 @@ const deployWithConfirmation = async ( ); // if upgrade happened on the mainnet save the new storage slot layout to the repo - if (isMainnet || isArbitrumOne || isBase) { + if (isMainnet || isArbitrumOne || isBase || isSonic) { await storeStorageLayoutForContract(hre, contractName); } @@ -155,8 +157,8 @@ const withConfirmation = async ( }; const _verifyProxyInitializedWithCorrectGovernor = (transactionData) => { - if (isBaseFork) { - // Skip proxy check on base for now + if (isBaseFork || isSonicFork) { + // Skip proxy check on base and sonic for now return; } @@ -1050,7 +1052,11 @@ async function handleTransitionGovernance(propDesc, propArgs) { const guardian = !isFork ? undefined : await impersonateAndFund( - isBaseFork ? addresses.base.governor : addresses.mainnet.Guardian + isBaseFork + ? addresses.base.governor + : isSonicFork + ? addresses.sonic.governor + : addresses.mainnet.Guardian ); if (!isScheduled) { From cf127088902f29eee28fd00f3f68d15a7d898a4a Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Fri, 20 Dec 2024 09:12:25 +1100 Subject: [PATCH 212/273] Added sonic to node script --- contracts/node.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/contracts/node.sh b/contracts/node.sh index 3fa6356927..b7afaf38da 100755 --- a/contracts/node.sh +++ b/contracts/node.sh @@ -37,6 +37,10 @@ main() PROVIDER_URL=$BASE_PROVIDER_URL; BLOCK_NUMBER=$BASE_BLOCK_NUMBER; params+=" --tags base"; + elif [[ $FORK_NETWORK_NAME == "sonic" ]]; then + PROVIDER_URL=$SONIC_PROVIDER_URL; + BLOCK_NUMBER=$SONIC_BLOCK_NUMBER; + params+=" --tags sonic"; fi echo "Fork Network: $FORK_NETWORK_NAME" From 908b8d4c0dfa07a394ae5204c9c5ab715848c01f Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Fri, 20 Dec 2024 09:13:09 +1100 Subject: [PATCH 213/273] WIP Sonic deploy script --- .../interfaces/sonic/IWrappedSonic.sol | 23 ++++ contracts/deploy/sonic/000_mock.js | 4 +- contracts/deploy/sonic/001_origin_sonic.js | 114 ++++++++++++++++++ 3 files changed, 139 insertions(+), 2 deletions(-) create mode 100644 contracts/contracts/interfaces/sonic/IWrappedSonic.sol create mode 100644 contracts/deploy/sonic/001_origin_sonic.js diff --git a/contracts/contracts/interfaces/sonic/IWrappedSonic.sol b/contracts/contracts/interfaces/sonic/IWrappedSonic.sol new file mode 100644 index 0000000000..9eba6c81ab --- /dev/null +++ b/contracts/contracts/interfaces/sonic/IWrappedSonic.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +interface IWrappedSonic { + function allowance( + address owner, + address spender + ) external view returns (uint256); + function approve(address spender, uint256 value) external returns (bool); + function balanceOf(address account) external view returns (uint256); + function decimals() external view returns (uint8); + function deposit() external; + function depositFor(address account) external returns (bool); + function totalSupply() external view returns (uint256); + function transfer(address to, uint256 value) external returns (bool); + function transferFrom( + address from, + address to, + uint256 value + ) external returns (bool); + function withdraw(uint256 value) external; + function withdrawTo(address account, uint256 value) external returns (bool); +} diff --git a/contracts/deploy/sonic/000_mock.js b/contracts/deploy/sonic/000_mock.js index b4040190f3..627b6521de 100644 --- a/contracts/deploy/sonic/000_mock.js +++ b/contracts/deploy/sonic/000_mock.js @@ -67,7 +67,7 @@ const deployCore = async () => { [ "Origin S", // Token Name "OS", // Token Symbol - cOSonicVaultProxy.address, // OETHb Vault + cOSonicVaultProxy.address, // Origin Sonic Vault resolution, // HighRes ] ); @@ -84,7 +84,7 @@ const deployCore = async () => { "initialize(address,address)", [ cOracleRouter.address, // OracleRouter - cOSonicProxy.address, // OETHb + cOSonicProxy.address, // OSonic ] ); // prettier-ignore diff --git a/contracts/deploy/sonic/001_origin_sonic.js b/contracts/deploy/sonic/001_origin_sonic.js new file mode 100644 index 0000000000..b70acdeca8 --- /dev/null +++ b/contracts/deploy/sonic/001_origin_sonic.js @@ -0,0 +1,114 @@ +const { deployOnSonic } = require("../../utils/deploy-l2"); +const addresses = require("../../utils/addresses"); + +module.exports = deployOnSonic( + { + deployName: "001_origin_sonic", + }, + async ({ ethers }) => { + const { governorAddr, deployerAddr } = await getNamedAccounts(); + const sGovernor = await ethers.provider.getSigner(governorAddr); + const sDeployer = await ethers.provider.getSigner(deployerAddr); + + const cWS = await ethers.getContractAt("IWrappedSonic", addresses.sonic.wS); + + // Proxies + await deployOnSonic("OSonicProxy"); + console.log("Deployed Origin S proxy"); + await deployOnSonic("WOSonicProxy"); + console.log("Deployed Wrapped Origin S proxy"); + await deployOnSonic("OSonicVaultProxy"); + console.log("Deployed Vault proxy"); + + const cOSonicProxy = await ethers.getContract("OSonicProxy"); + const cWOSonicProxy = await ethers.getContract("WOSonicProxy"); + const cOSonicVaultProxy = await ethers.getContract("OSonicVaultProxy"); + + // Core contracts + const dOSonic = await deployOnSonic("OSonic"); + console.log("Deployed Origin S"); + const dWOSonic = await deployOnSonic("WOSonic", [ + cOSonicProxy.address, // Base token + "Wrapped Origin S", // Token Name + "wOS", // Token Symbol + ]); + console.log("Deployed Wrapped Origin S"); + const dOSonicVaultCore = await deployOnSonic("OSonicVaultCore", [ + cWS.address, + ]); + console.log("Deployed Vault Core"); + const dOSonicVaultAdmin = await deployOnSonic("OSonicVaultAdmin", [ + cWS.address, + ]); + console.log("Deployed Vault Admin"); + + // Get contract instances + const cOSonic = await ethers.getContractAt("OSonic", cOSonicProxy.address); + const cWOSonic = await ethers.getContractAt( + "WOSonic", + cWOSonicProxy.address + ); + const cOSonicVault = await ethers.getContractAt( + "IVault", + cOSonicVaultProxy.address + ); + + // Init OSonic + const resolution = ethers.utils.parseUnits("1", 27); + const initDataOSonic = cOSonic.interface.encodeFunctionData( + "initialize(string,string,address,uint256)", + [ + "Origin S", // Token Name + "OS", // Token Symbol + cOSonicVaultProxy.address, // Origin Sonic Vault + resolution, // HighRes + ] + ); + // prettier-ignore + await cOSonicProxy + .connect(sDeployer)["initialize(address,address,bytes)"]( + dOSonic.address, + governorAddr, + initDataOSonic + ); + + // Init OSonicVault + const initDataOSonicVault = cOSonicVault.interface.encodeFunctionData( + "initialize(address,address)", + [ + addresses.dead, // OracleRouter + cOSonicProxy.address, // OSonic + ] + ); + // prettier-ignore + await cOSonicVaultProxy + .connect(sDeployer)["initialize(address,address,bytes)"]( + dOSonicVaultCore.address, + governorAddr, + initDataOSonicVault + ); + + // Init WOSonic + const initDataWOSonic = cWOSonic.interface.encodeFunctionData( + "initialize()", + [] + ); + // prettier-ignore + await cWOSonicProxy + .connect(sDeployer)["initialize(address,address,bytes)"]( + dWOSonic.address, + governorAddr, + initDataWOSonic + ) + + await cOSonicVaultProxy + .connect(sGovernor) + .upgradeTo(dOSonicVaultCore.address); + await cOSonicVault + .connect(sGovernor) + .setAdminImpl(dOSonicVaultAdmin.address); + + await cOSonicVault.connect(sGovernor).supportAsset(cWS.address, 0); + await cOSonicVault.connect(sGovernor).unpauseCapital(); + } +); From 3e443f33a95c730b1755054b56027b6bed13b12d Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Fri, 20 Dec 2024 21:36:54 +1100 Subject: [PATCH 214/273] Added sonic to storageSlots --- contracts/tasks/storageSlots.js | 4 ++++ contracts/utils/addresses.js | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/contracts/tasks/storageSlots.js b/contracts/tasks/storageSlots.js index 0ff0f45239..e8369d6eda 100644 --- a/contracts/tasks/storageSlots.js +++ b/contracts/tasks/storageSlots.js @@ -17,8 +17,10 @@ const isFork = process.env.FORK === "true"; const getStorageFileLocation = (hre, contractName) => { const isMainnet = hre.network.name === "mainnet"; const isArbitrum = hre.network.name === "arbitrumOne"; + const isSonic = hre.network.name === "sonic"; const forkNetworkName = process.env.FORK_NETWORK_NAME; const isArbitrumFork = isFork && forkNetworkName == "arbitrumOne"; + const isSonicFork = isFork && forkNetworkName == "sonic"; const isMainnetFork = isFork && forkNetworkName == "mainnet"; let folder = "localhost"; @@ -26,6 +28,8 @@ const getStorageFileLocation = (hre, contractName) => { folder = "mainnet"; } else if (isArbitrumFork || isArbitrum) { folder = "arbitrumOne"; + } else if (isSonicFork || isSonic) { + folder = "sonic"; } const layoutFolder = `./storageLayout/${folder}/`; diff --git a/contracts/utils/addresses.js b/contracts/utils/addresses.js index 0ca2410d3e..bbf4947273 100644 --- a/contracts/utils/addresses.js +++ b/contracts/utils/addresses.js @@ -333,7 +333,7 @@ addresses.base.OZRelayerAddress = "0xc0D6fa24D135c006dE5B8b2955935466A03D920a"; // Sonic addresses.sonic = {}; -addresses.sonic.wS = "0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38" +addresses.sonic.wS = "0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38"; // Holesky addresses.holesky.WETH = "0x94373a4919B3240D86eA41593D5eBa789FEF3848"; From ecd9132cd7d25c6e6db200638f3573fc4e6353d2 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Fri, 20 Dec 2024 22:00:23 +1100 Subject: [PATCH 215/273] Fix getHardhatNetworkProperties --- contracts/utils/hardhat-helpers.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/utils/hardhat-helpers.js b/contracts/utils/hardhat-helpers.js index d300963ba0..a69b495ee3 100644 --- a/contracts/utils/hardhat-helpers.js +++ b/contracts/utils/hardhat-helpers.js @@ -117,7 +117,7 @@ const getHardhatNetworkProperties = () => { chainId = 17000; } else if (isBaseFork && isFork) { chainId = 8453; - } else if (isSonicFork && isSonic) { + } else if (isSonicFork && isFork) { chainId = 146; } else if (isFork) { // is mainnet fork From 148b08b381adfa15b487eec8914855b59b08ac14 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Sat, 21 Dec 2024 13:24:30 +1100 Subject: [PATCH 216/273] Added sonic deployment files --- contracts/deployments/sonic/.chainId | 1 + contracts/deployments/sonic/.migrations.json | 1 + contracts/fork-test.sh | 3 +++ 3 files changed, 5 insertions(+) create mode 100644 contracts/deployments/sonic/.chainId create mode 100644 contracts/deployments/sonic/.migrations.json diff --git a/contracts/deployments/sonic/.chainId b/contracts/deployments/sonic/.chainId new file mode 100644 index 0000000000..bc768da71a --- /dev/null +++ b/contracts/deployments/sonic/.chainId @@ -0,0 +1 @@ +146 \ No newline at end of file diff --git a/contracts/deployments/sonic/.migrations.json b/contracts/deployments/sonic/.migrations.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/contracts/deployments/sonic/.migrations.json @@ -0,0 +1 @@ +{} diff --git a/contracts/fork-test.sh b/contracts/fork-test.sh index ce5f4d93e8..b33a4919c8 100755 --- a/contracts/fork-test.sh +++ b/contracts/fork-test.sh @@ -45,6 +45,9 @@ main() elif [[ $FORK_NETWORK_NAME == "base" ]]; then PROVIDER_URL=$BASE_PROVIDER_URL; BLOCK_NUMBER=$BASE_BLOCK_NUMBER; + elif [[ $FORK_NETWORK_NAME == "sonic" ]]; then + PROVIDER_URL=$SONIC_PROVIDER_URL; + BLOCK_NUMBER=$SONIC_BLOCK_NUMBER; fi if $is_local; then From 2f0173444551b640453913d5e9e83617e88b8d63 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Mon, 30 Dec 2024 10:45:40 +1100 Subject: [PATCH 217/273] Added WETH address on Sonic --- contracts/utils/addresses.js | 1 + 1 file changed, 1 insertion(+) diff --git a/contracts/utils/addresses.js b/contracts/utils/addresses.js index bbf4947273..61843d1b72 100644 --- a/contracts/utils/addresses.js +++ b/contracts/utils/addresses.js @@ -334,6 +334,7 @@ addresses.base.OZRelayerAddress = "0xc0D6fa24D135c006dE5B8b2955935466A03D920a"; // Sonic addresses.sonic = {}; addresses.sonic.wS = "0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38"; +addresses.sonic.WETH = "0x309C92261178fA0CF748A855e90Ae73FDb79EBc7"; // Holesky addresses.holesky.WETH = "0x94373a4919B3240D86eA41593D5eBa789FEF3848"; From d9c4b086f7efc0b22955ee0d4e91bb7cc287da72 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Mon, 30 Dec 2024 10:55:10 +1100 Subject: [PATCH 218/273] Fix Sonic deployment --- contracts/deploy/sonic/001_origin_sonic.js | 7 ++++--- contracts/utils/deploy.js | 5 ++++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/contracts/deploy/sonic/001_origin_sonic.js b/contracts/deploy/sonic/001_origin_sonic.js index b70acdeca8..ec269e20c8 100644 --- a/contracts/deploy/sonic/001_origin_sonic.js +++ b/contracts/deploy/sonic/001_origin_sonic.js @@ -1,4 +1,5 @@ const { deployOnSonic } = require("../../utils/deploy-l2"); +const { deployWithConfirmation } = require("../../utils/deploy"); const addresses = require("../../utils/addresses"); module.exports = deployOnSonic( @@ -13,11 +14,11 @@ module.exports = deployOnSonic( const cWS = await ethers.getContractAt("IWrappedSonic", addresses.sonic.wS); // Proxies - await deployOnSonic("OSonicProxy"); + await deployWithConfirmation("OSonicProxy"); console.log("Deployed Origin S proxy"); - await deployOnSonic("WOSonicProxy"); + await deployWithConfirmation("WOSonicProxy"); console.log("Deployed Wrapped Origin S proxy"); - await deployOnSonic("OSonicVaultProxy"); + await deployWithConfirmation("OSonicVaultProxy"); console.log("Deployed Vault proxy"); const cOSonicProxy = await ethers.getContract("OSonicProxy"); diff --git a/contracts/utils/deploy.js b/contracts/utils/deploy.js index 930c2114fc..76b35870f2 100644 --- a/contracts/utils/deploy.js +++ b/contracts/utils/deploy.js @@ -94,7 +94,10 @@ const deployWithConfirmation = async ( const { deployerAddr } = await getNamedAccounts(); if (!args) args = null; if (!contract) contract = contractName; - const feeData = await hre.ethers.provider.getFeeData(); + let feeData; + if (useFeeData) { + feeData = await hre.ethers.provider.getFeeData(); + } const result = await withConfirmation( deploy(contractName, { from: deployerAddr, From 648d2136e54ee972198e0c2a7f574a32feb4937b Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Mon, 30 Dec 2024 11:04:34 +1100 Subject: [PATCH 219/273] Upgraded Hardhat --- contracts/package.json | 4 +- contracts/yarn.lock | 540 ++++++++++++++--------------------------- 2 files changed, 187 insertions(+), 357 deletions(-) diff --git a/contracts/package.json b/contracts/package.json index 84790884da..284a50b1f3 100644 --- a/contracts/package.json +++ b/contracts/package.json @@ -81,12 +81,12 @@ "eslint-plugin-no-only-tests": "^3.1.0", "ethereum-waffle": "^4.0.10", "ethers": "^5.4.6", - "hardhat": "^2.14.1", + "hardhat": "^2.22.17", "hardhat-contract-sizer": "^2.9.0", "hardhat-deploy": "^0.11.30", "hardhat-deploy-ethers": "^0.3.0-beta.13", "hardhat-gas-reporter": "^1.0.9", - "hardhat-tracer": "^2.3.2", + "hardhat-tracer": "^3.1.0", "husky": "^7.0.2", "lodash": "^4.17.21", "mocha": "^10.2.0", diff --git a/contracts/yarn.lock b/contracts/yarn.lock index 56eb66971e..b693568574 100644 --- a/contracts/yarn.lock +++ b/contracts/yarn.lock @@ -827,42 +827,6 @@ "@openzeppelin/contracts-upgradeable-4.7.3" "npm:@openzeppelin/contracts-upgradeable@v4.7.3" "@openzeppelin/contracts-v0.7" "npm:@openzeppelin/contracts@v3.4.2" -"@chainsafe/as-sha256@^0.3.1": - version "0.3.1" - resolved "https://registry.yarnpkg.com/@chainsafe/as-sha256/-/as-sha256-0.3.1.tgz#3639df0e1435cab03f4d9870cc3ac079e57a6fc9" - integrity sha512-hldFFYuf49ed7DAakWVXSJODuq3pzJEguD8tQ7h+sGkM18vja+OFoJI9krnGmgzyuZC2ETX0NOIcCTy31v2Mtg== - -"@chainsafe/persistent-merkle-tree@^0.4.2": - version "0.4.2" - resolved "https://registry.yarnpkg.com/@chainsafe/persistent-merkle-tree/-/persistent-merkle-tree-0.4.2.tgz#4c9ee80cc57cd3be7208d98c40014ad38f36f7ff" - integrity sha512-lLO3ihKPngXLTus/L7WHKaw9PnNJWizlOF1H9NNzHP6Xvh82vzg9F2bzkXhYIFshMZ2gTCEz8tq6STe7r5NDfQ== - dependencies: - "@chainsafe/as-sha256" "^0.3.1" - -"@chainsafe/persistent-merkle-tree@^0.5.0": - version "0.5.0" - resolved "https://registry.yarnpkg.com/@chainsafe/persistent-merkle-tree/-/persistent-merkle-tree-0.5.0.tgz#2b4a62c9489a5739dedd197250d8d2f5427e9f63" - integrity sha512-l0V1b5clxA3iwQLXP40zYjyZYospQLZXzBVIhhr9kDg/1qHZfzzHw0jj4VPBijfYCArZDlPkRi1wZaV2POKeuw== - dependencies: - "@chainsafe/as-sha256" "^0.3.1" - -"@chainsafe/ssz@^0.10.0": - version "0.10.2" - resolved "https://registry.yarnpkg.com/@chainsafe/ssz/-/ssz-0.10.2.tgz#c782929e1bb25fec66ba72e75934b31fd087579e" - integrity sha512-/NL3Lh8K+0q7A3LsiFq09YXS9fPE+ead2rr7vM2QK8PLzrNsw3uqrif9bpRX5UxgeRjM+vYi+boCM3+GM4ovXg== - dependencies: - "@chainsafe/as-sha256" "^0.3.1" - "@chainsafe/persistent-merkle-tree" "^0.5.0" - -"@chainsafe/ssz@^0.9.2": - version "0.9.4" - resolved "https://registry.yarnpkg.com/@chainsafe/ssz/-/ssz-0.9.4.tgz#696a8db46d6975b600f8309ad3a12f7c0e310497" - integrity sha512-77Qtg2N1ayqs4Bg/wvnWfg5Bta7iy7IRh8XqXh7oNMeP2HBbBwx8m6yTpA8p0EHItWPEBkgZd5S5/LSlp3GXuQ== - dependencies: - "@chainsafe/as-sha256" "^0.3.1" - "@chainsafe/persistent-merkle-tree" "^0.4.2" - case "^1.6.3" - "@colors/colors@1.5.0": version "1.5.0" resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9" @@ -1261,7 +1225,7 @@ dependencies: "@ethersproject/logger" "^5.7.0" -"@ethersproject/providers@5.7.2", "@ethersproject/providers@^5.7.0", "@ethersproject/providers@^5.7.1", "@ethersproject/providers@^5.7.2": +"@ethersproject/providers@5.7.2", "@ethersproject/providers@^5.7.0", "@ethersproject/providers@^5.7.2": version "5.7.2" resolved "https://registry.yarnpkg.com/@ethersproject/providers/-/providers-5.7.2.tgz#f8b1a4f275d7ce58cf0a2eec222269a08beb18cb" integrity sha512-g34EWZ1WWAVgr4aptGlVBF8mhl3VWjv+8hoAnzStu8Ah22VHBsuGzP17eb6xDVRzw895G4W7vvx60lFFur/1Rg== @@ -1559,140 +1523,84 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" -"@nomicfoundation/ethereumjs-block@5.0.1": - version "5.0.1" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-block/-/ethereumjs-block-5.0.1.tgz#6f89664f55febbd723195b6d0974773d29ee133d" - integrity sha512-u1Yioemi6Ckj3xspygu/SfFvm8vZEO8/Yx5a1QLzi6nVU0jz3Pg2OmHKJ5w+D9Ogk1vhwRiqEBAqcb0GVhCyHw== - dependencies: - "@nomicfoundation/ethereumjs-common" "4.0.1" - "@nomicfoundation/ethereumjs-rlp" "5.0.1" - "@nomicfoundation/ethereumjs-trie" "6.0.1" - "@nomicfoundation/ethereumjs-tx" "5.0.1" - "@nomicfoundation/ethereumjs-util" "9.0.1" - ethereum-cryptography "0.1.3" - ethers "^5.7.1" - -"@nomicfoundation/ethereumjs-blockchain@7.0.1": - version "7.0.1" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-blockchain/-/ethereumjs-blockchain-7.0.1.tgz#80e0bd3535bfeb9baa29836b6f25123dab06a726" - integrity sha512-NhzndlGg829XXbqJEYrF1VeZhAwSPgsK/OB7TVrdzft3y918hW5KNd7gIZ85sn6peDZOdjBsAXIpXZ38oBYE5A== - dependencies: - "@nomicfoundation/ethereumjs-block" "5.0.1" - "@nomicfoundation/ethereumjs-common" "4.0.1" - "@nomicfoundation/ethereumjs-ethash" "3.0.1" - "@nomicfoundation/ethereumjs-rlp" "5.0.1" - "@nomicfoundation/ethereumjs-trie" "6.0.1" - "@nomicfoundation/ethereumjs-tx" "5.0.1" - "@nomicfoundation/ethereumjs-util" "9.0.1" - abstract-level "^1.0.3" - debug "^4.3.3" - ethereum-cryptography "0.1.3" - level "^8.0.0" - lru-cache "^5.1.1" - memory-level "^1.0.0" - -"@nomicfoundation/ethereumjs-common@4.0.1": - version "4.0.1" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-common/-/ethereumjs-common-4.0.1.tgz#4702d82df35b07b5407583b54a45bf728e46a2f0" - integrity sha512-OBErlkfp54GpeiE06brBW/TTbtbuBJV5YI5Nz/aB2evTDo+KawyEzPjBlSr84z/8MFfj8wS2wxzQX1o32cev5g== - dependencies: - "@nomicfoundation/ethereumjs-util" "9.0.1" - crc-32 "^1.2.0" - -"@nomicfoundation/ethereumjs-ethash@3.0.1": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-ethash/-/ethereumjs-ethash-3.0.1.tgz#65ca494d53e71e8415c9a49ef48bc921c538fc41" - integrity sha512-KDjGIB5igzWOp8Ik5I6QiRH5DH+XgILlplsHR7TEuWANZA759G6krQ6o8bvj+tRUz08YygMQu/sGd9mJ1DYT8w== - dependencies: - "@nomicfoundation/ethereumjs-block" "5.0.1" - "@nomicfoundation/ethereumjs-rlp" "5.0.1" - "@nomicfoundation/ethereumjs-util" "9.0.1" - abstract-level "^1.0.3" - bigint-crypto-utils "^3.0.23" - ethereum-cryptography "0.1.3" - -"@nomicfoundation/ethereumjs-evm@2.0.1": - version "2.0.1" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-evm/-/ethereumjs-evm-2.0.1.tgz#f35681e203363f69ce2b3d3bf9f44d4e883ca1f1" - integrity sha512-oL8vJcnk0Bx/onl+TgQOQ1t/534GKFaEG17fZmwtPFeH8S5soiBYPCLUrvANOl4sCp9elYxIMzIiTtMtNNN8EQ== - dependencies: - "@ethersproject/providers" "^5.7.1" - "@nomicfoundation/ethereumjs-common" "4.0.1" - "@nomicfoundation/ethereumjs-tx" "5.0.1" - "@nomicfoundation/ethereumjs-util" "9.0.1" - debug "^4.3.3" - ethereum-cryptography "0.1.3" - mcl-wasm "^0.7.1" - rustbn.js "~0.2.0" - -"@nomicfoundation/ethereumjs-rlp@5.0.1": - version "5.0.1" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-rlp/-/ethereumjs-rlp-5.0.1.tgz#0b30c1cf77d125d390408e391c4bb5291ef43c28" - integrity sha512-xtxrMGa8kP4zF5ApBQBtjlSbN5E2HI8m8FYgVSYAnO6ssUoY5pVPGy2H8+xdf/bmMa22Ce8nWMH3aEW8CcqMeQ== - -"@nomicfoundation/ethereumjs-statemanager@2.0.1": - version "2.0.1" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-statemanager/-/ethereumjs-statemanager-2.0.1.tgz#8824a97938db4471911e2d2f140f79195def5935" - integrity sha512-B5ApMOnlruVOR7gisBaYwFX+L/AP7i/2oAahatssjPIBVDF6wTX1K7Qpa39E/nzsH8iYuL3krkYeUFIdO3EMUQ== +"@nomicfoundation/edr-darwin-arm64@0.6.5": + version "0.6.5" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-darwin-arm64/-/edr-darwin-arm64-0.6.5.tgz#37a31565d7ef42bed9028ac44aed82144de30bd1" + integrity sha512-A9zCCbbNxBpLgjS1kEJSpqxIvGGAX4cYbpDYCU2f3jVqOwaZ/NU761y1SvuCRVpOwhoCXqByN9b7HPpHi0L4hw== + +"@nomicfoundation/edr-darwin-x64@0.6.5": + version "0.6.5" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-darwin-x64/-/edr-darwin-x64-0.6.5.tgz#3252f6e86397af460b7a480bfe1b889464d75b89" + integrity sha512-x3zBY/v3R0modR5CzlL6qMfFMdgwd6oHrWpTkuuXnPFOX8SU31qq87/230f4szM+ukGK8Hi+mNq7Ro2VF4Fj+w== + +"@nomicfoundation/edr-linux-arm64-gnu@0.6.5": + version "0.6.5" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-arm64-gnu/-/edr-linux-arm64-gnu-0.6.5.tgz#e7dc2934920b6cfabeb5ee7a5e26c8fb0d4964ac" + integrity sha512-HGpB8f1h8ogqPHTyUpyPRKZxUk2lu061g97dOQ/W4CxevI0s/qiw5DB3U3smLvSnBHKOzYS1jkxlMeGN01ky7A== + +"@nomicfoundation/edr-linux-arm64-musl@0.6.5": + version "0.6.5" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-arm64-musl/-/edr-linux-arm64-musl-0.6.5.tgz#00459cd53e9fb7bd5b7e32128b508a6e89079d89" + integrity sha512-ESvJM5Y9XC03fZg9KaQg3Hl+mbx7dsSkTIAndoJS7X2SyakpL9KZpOSYrDk135o8s9P9lYJdPOyiq+Sh+XoCbQ== + +"@nomicfoundation/edr-linux-x64-gnu@0.6.5": + version "0.6.5" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-x64-gnu/-/edr-linux-x64-gnu-0.6.5.tgz#5c9e4e2655caba48e0196977cba395bbde6fe97d" + integrity sha512-HCM1usyAR1Ew6RYf5AkMYGvHBy64cPA5NMbaeY72r0mpKaH3txiMyydcHibByOGdQ8iFLWpyUdpl1egotw+Tgg== + +"@nomicfoundation/edr-linux-x64-musl@0.6.5": + version "0.6.5" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-x64-musl/-/edr-linux-x64-musl-0.6.5.tgz#9c220751b66452dc43a365f380e1e236a0a8c5a9" + integrity sha512-nB2uFRyczhAvWUH7NjCsIO6rHnQrof3xcCe6Mpmnzfl2PYcGyxN7iO4ZMmRcQS7R1Y670VH6+8ZBiRn8k43m7A== + +"@nomicfoundation/edr-win32-x64-msvc@0.6.5": + version "0.6.5" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-win32-x64-msvc/-/edr-win32-x64-msvc-0.6.5.tgz#90d3ac2a6a8a687522bda5ff2e92dd97e68126ea" + integrity sha512-B9QD/4DSSCFtWicO8A3BrsnitO1FPv7axB62wq5Q+qeJ50yJlTmyeGY3cw62gWItdvy2mh3fRM6L1LpnHiB77A== + +"@nomicfoundation/edr@^0.6.5": + version "0.6.5" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr/-/edr-0.6.5.tgz#b3b1ebcdd0148cfe67cca128e7ebe8092e200359" + integrity sha512-tAqMslLP+/2b2sZP4qe9AuGxG3OkQ5gGgHE4isUuq6dUVjwCRPFhAOhpdFl+OjY5P3yEv3hmq9HjUGRa2VNjng== + dependencies: + "@nomicfoundation/edr-darwin-arm64" "0.6.5" + "@nomicfoundation/edr-darwin-x64" "0.6.5" + "@nomicfoundation/edr-linux-arm64-gnu" "0.6.5" + "@nomicfoundation/edr-linux-arm64-musl" "0.6.5" + "@nomicfoundation/edr-linux-x64-gnu" "0.6.5" + "@nomicfoundation/edr-linux-x64-musl" "0.6.5" + "@nomicfoundation/edr-win32-x64-msvc" "0.6.5" + +"@nomicfoundation/ethereumjs-common@4.0.4": + version "4.0.4" + resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-common/-/ethereumjs-common-4.0.4.tgz#9901f513af2d4802da87c66d6f255b510bef5acb" + integrity sha512-9Rgb658lcWsjiicr5GzNCjI1llow/7r0k50dLL95OJ+6iZJcVbi15r3Y0xh2cIO+zgX0WIHcbzIu6FeQf9KPrg== dependencies: - "@nomicfoundation/ethereumjs-common" "4.0.1" - "@nomicfoundation/ethereumjs-rlp" "5.0.1" - debug "^4.3.3" - ethereum-cryptography "0.1.3" - ethers "^5.7.1" - js-sdsl "^4.1.4" + "@nomicfoundation/ethereumjs-util" "9.0.4" -"@nomicfoundation/ethereumjs-trie@6.0.1": - version "6.0.1" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-trie/-/ethereumjs-trie-6.0.1.tgz#662c55f6b50659fd4b22ea9f806a7401cafb7717" - integrity sha512-A64It/IMpDVODzCgxDgAAla8jNjNtsoQZIzZUfIV5AY6Coi4nvn7+VReBn5itlxMiL2yaTlQr9TRWp3CSI6VoA== - dependencies: - "@nomicfoundation/ethereumjs-rlp" "5.0.1" - "@nomicfoundation/ethereumjs-util" "9.0.1" - "@types/readable-stream" "^2.3.13" - ethereum-cryptography "0.1.3" - readable-stream "^3.6.0" +"@nomicfoundation/ethereumjs-rlp@5.0.4": + version "5.0.4" + resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-rlp/-/ethereumjs-rlp-5.0.4.tgz#66c95256fc3c909f6fb18f6a586475fc9762fa30" + integrity sha512-8H1S3s8F6QueOc/X92SdrA4RDenpiAEqMg5vJH99kcQaCy/a3Q6fgseo75mgWlbanGJXSlAPtnCeG9jvfTYXlw== -"@nomicfoundation/ethereumjs-tx@5.0.1": - version "5.0.1" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-tx/-/ethereumjs-tx-5.0.1.tgz#7629dc2036b4a33c34e9f0a592b43227ef4f0c7d" - integrity sha512-0HwxUF2u2hrsIM1fsasjXvlbDOq1ZHFV2dd1yGq8CA+MEYhaxZr8OTScpVkkxqMwBcc5y83FyPl0J9MZn3kY0w== +"@nomicfoundation/ethereumjs-tx@5.0.4": + version "5.0.4" + resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-tx/-/ethereumjs-tx-5.0.4.tgz#b0ceb58c98cc34367d40a30d255d6315b2f456da" + integrity sha512-Xjv8wAKJGMrP1f0n2PeyfFCCojHd7iS3s/Ab7qzF1S64kxZ8Z22LCMynArYsVqiFx6rzYy548HNVEyI+AYN/kw== dependencies: - "@chainsafe/ssz" "^0.9.2" - "@ethersproject/providers" "^5.7.2" - "@nomicfoundation/ethereumjs-common" "4.0.1" - "@nomicfoundation/ethereumjs-rlp" "5.0.1" - "@nomicfoundation/ethereumjs-util" "9.0.1" + "@nomicfoundation/ethereumjs-common" "4.0.4" + "@nomicfoundation/ethereumjs-rlp" "5.0.4" + "@nomicfoundation/ethereumjs-util" "9.0.4" ethereum-cryptography "0.1.3" -"@nomicfoundation/ethereumjs-util@9.0.1": - version "9.0.1" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-util/-/ethereumjs-util-9.0.1.tgz#530cda8bae33f8b5020a8f199ed1d0a2ce48ec89" - integrity sha512-TwbhOWQ8QoSCFhV/DDfSmyfFIHjPjFBj957219+V3jTZYZ2rf9PmDtNOeZWAE3p3vlp8xb02XGpd0v6nTUPbsA== +"@nomicfoundation/ethereumjs-util@9.0.4": + version "9.0.4" + resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-util/-/ethereumjs-util-9.0.4.tgz#84c5274e82018b154244c877b76bc049a4ed7b38" + integrity sha512-sLOzjnSrlx9Bb9EFNtHzK/FJFsfg2re6bsGqinFinH1gCqVfz9YYlXiMWwDM4C/L4ywuHFCYwfKTVr/QHQcU0Q== dependencies: - "@chainsafe/ssz" "^0.10.0" - "@nomicfoundation/ethereumjs-rlp" "5.0.1" + "@nomicfoundation/ethereumjs-rlp" "5.0.4" ethereum-cryptography "0.1.3" -"@nomicfoundation/ethereumjs-vm@7.0.1": - version "7.0.1" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-vm/-/ethereumjs-vm-7.0.1.tgz#7d035e0993bcad10716c8b36e61dfb87fa3ca05f" - integrity sha512-rArhyn0jPsS/D+ApFsz3yVJMQ29+pVzNZ0VJgkzAZ+7FqXSRtThl1C1prhmlVr3YNUlfpZ69Ak+RUT4g7VoOuQ== - dependencies: - "@nomicfoundation/ethereumjs-block" "5.0.1" - "@nomicfoundation/ethereumjs-blockchain" "7.0.1" - "@nomicfoundation/ethereumjs-common" "4.0.1" - "@nomicfoundation/ethereumjs-evm" "2.0.1" - "@nomicfoundation/ethereumjs-rlp" "5.0.1" - "@nomicfoundation/ethereumjs-statemanager" "2.0.1" - "@nomicfoundation/ethereumjs-trie" "6.0.1" - "@nomicfoundation/ethereumjs-tx" "5.0.1" - "@nomicfoundation/ethereumjs-util" "9.0.1" - debug "^4.3.3" - ethereum-cryptography "0.1.3" - mcl-wasm "^0.7.1" - rustbn.js "~0.2.0" - "@nomicfoundation/hardhat-network-helpers@^1.0.9": version "1.0.9" resolved "https://registry.yarnpkg.com/@nomicfoundation/hardhat-network-helpers/-/hardhat-network-helpers-1.0.9.tgz#767449e8a2acda79306ac84626117583d95d25aa" @@ -3037,14 +2945,6 @@ resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.7.tgz#63bb7d067db107cc1e457c303bc25d511febf6cb" integrity sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw== -"@types/readable-stream@^2.3.13": - version "2.3.15" - resolved "https://registry.yarnpkg.com/@types/readable-stream/-/readable-stream-2.3.15.tgz#3d79c9ceb1b6a57d5f6e6976f489b9b5384321ae" - integrity sha512-oM5JSKQCcICF1wvGgmecmHldZ48OZamtMxcGGVICOJA8o8cahXC1zEVAif8iwoc5j8etxFaRFnf095+CDsuoFQ== - dependencies: - "@types/node" "*" - safe-buffer "~5.1.1" - "@types/resolve@1.20.2": version "1.20.2" resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-1.20.2.tgz#97d26e00cd4a0423b4af620abecf3e6f442b7975" @@ -3127,31 +3027,11 @@ abbrev@1.0.x: resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.0.9.tgz#91b4792588a7738c25f35dd6f63752a2f8776135" integrity sha512-LEyx4aLEC3x6T0UguF6YILf+ntvmOaWsVfENmIW0E9H09vKlLDGelMjjSm0jkDHALj8A8quZ/HapKNigzwge+Q== -abort-controller@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" - integrity sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg== - dependencies: - event-target-shim "^5.0.0" - abortcontroller-polyfill@^1.7.5: version "1.7.5" resolved "https://registry.yarnpkg.com/abortcontroller-polyfill/-/abortcontroller-polyfill-1.7.5.tgz#6738495f4e901fbb57b6c0611d0c75f76c485bed" integrity sha512-JMJ5soJWP18htbbxJjG7bG6yuI6pRhgJ0scHHTfkUjf6wjP912xZWvM+A4sJK3gqd9E8fcPbDnOefbA9Th/FIQ== -abstract-level@^1.0.0, abstract-level@^1.0.2, abstract-level@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/abstract-level/-/abstract-level-1.0.3.tgz#78a67d3d84da55ee15201486ab44c09560070741" - integrity sha512-t6jv+xHy+VYwc4xqZMn2Pa9DjcdzvzZmQGRjTFc8spIbRGHgBrEKbPq+rYXc7CCo0lxgYvSgKVg9qZAhpVQSjA== - dependencies: - buffer "^6.0.3" - catering "^2.1.0" - is-buffer "^2.0.5" - level-supports "^4.0.0" - level-transcoder "^1.0.1" - module-error "^1.0.1" - queue-microtask "^1.2.3" - abstract-leveldown@^6.2.1: version "6.3.0" resolved "https://registry.yarnpkg.com/abstract-leveldown/-/abstract-leveldown-6.3.0.tgz#d25221d1e6612f820c35963ba4bd739928f6026a" @@ -3296,6 +3176,13 @@ amdefine@>=0.0.4: resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" integrity sha512-S2Hw0TtNkMJhIabBwIojKL9YHO5T0n5eNqWJ7Lrlel/zDbftQpxpapi8tZs3X1HWa+u+QeydGmzzNU0m09+Rcg== +ansi-align@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-3.0.1.tgz#0cdf12e111ace773a86e9a1fad1225c43cb19a59" + integrity sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w== + dependencies: + string-width "^4.1.0" + ansi-colors@3.2.3: version "3.2.3" resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.3.tgz#57d35b8686e851e2cc04c403f1c00203976a1813" @@ -3610,11 +3497,6 @@ bech32@1.1.4: resolved "https://registry.yarnpkg.com/bech32/-/bech32-1.1.4.tgz#e38c9f37bf179b8eb16ae3a772b40c356d4832e9" integrity sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ== -bigint-crypto-utils@^3.0.23: - version "3.2.2" - resolved "https://registry.yarnpkg.com/bigint-crypto-utils/-/bigint-crypto-utils-3.2.2.tgz#e30a49ec38357c6981cd3da5aaa6480b1f752ee4" - integrity sha512-U1RbE3aX9ayCUVcIPHuPDPKcK3SFOXf93J1UK/iHlJuQB7bhagPIX06/CLpLEsDThJ7KA4Dhrnzynl+d2weTiw== - bignumber.js@^9.0.0: version "9.1.1" resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.1.1.tgz#c4df7dc496bd849d4c9464344c1aa74228b4dac6" @@ -3693,6 +3575,20 @@ bowser@^2.11.0: resolved "https://registry.yarnpkg.com/bowser/-/bowser-2.11.0.tgz#5ca3c35757a7aa5771500c70a73a9f91ef420a8f" integrity sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA== +boxen@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/boxen/-/boxen-5.1.2.tgz#788cb686fc83c1f486dfa8a40c68fc2b831d2b50" + integrity sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ== + dependencies: + ansi-align "^3.0.0" + camelcase "^6.2.0" + chalk "^4.1.0" + cli-boxes "^2.2.1" + string-width "^4.2.2" + type-fest "^0.20.2" + widest-line "^3.1.0" + wrap-ansi "^7.0.0" + brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" @@ -3720,16 +3616,6 @@ brorand@^1.0.1, brorand@^1.1.0: resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" integrity sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w== -browser-level@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/browser-level/-/browser-level-1.0.1.tgz#36e8c3183d0fe1c405239792faaab5f315871011" - integrity sha512-XECYKJ+Dbzw0lbydyQuJzwNXtOpbMSq737qxJN11sIRTErOMShvDpbzTlgju7orJKvx4epULolZAuJGLzCmWRQ== - dependencies: - abstract-level "^1.0.2" - catering "^2.1.1" - module-error "^1.0.2" - run-parallel-limit "^1.1.0" - browser-stdout@1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" @@ -3983,22 +3869,17 @@ camelcase@^5.0.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== -camelcase@^6.0.0: +camelcase@^6.0.0, camelcase@^6.2.0: version "6.3.0" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== -case@^1.6.3: - version "1.6.3" - resolved "https://registry.yarnpkg.com/case/-/case-1.6.3.tgz#0a4386e3e9825351ca2e6216c60467ff5f1ea1c9" - integrity sha512-mzDSXIPaFwVDvZAHqZ9VlbyF4yyXRuX6IvB06WvPYkqJVO24kX1PPhv9bfpKNFZyxYFmmgo03HUiD8iklmJYRQ== - caseless@^0.12.0, caseless@~0.12.0: version "0.12.0" resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" integrity sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw== -catering@^2.0.0, catering@^2.1.0, catering@^2.1.1: +catering@^2.0.0, catering@^2.1.0: version "2.1.1" resolved "https://registry.yarnpkg.com/catering/-/catering-2.1.1.tgz#66acba06ed5ee28d5286133982a927de9a04b510" integrity sha512-K7Qy8O9p76sL3/3m7/zLKbRkyOlSZAgzEaLhyj2mXS8PsCud2Eo4hAb8aLtZqHh0QGqLcb9dlJSu6lHRVENm1w== @@ -4090,7 +3971,7 @@ chokidar@3.3.0: optionalDependencies: fsevents "~2.1.1" -chokidar@3.5.3, chokidar@^3.4.0, chokidar@^3.5.2: +chokidar@3.5.3, chokidar@^3.5.2: version "3.5.3" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== @@ -4105,6 +3986,13 @@ chokidar@3.5.3, chokidar@^3.4.0, chokidar@^3.5.2: optionalDependencies: fsevents "~2.3.2" +chokidar@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-4.0.3.tgz#7be37a4c03c9aee1ecfe862a4a23b2c70c205d30" + integrity sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA== + dependencies: + readdirp "^4.0.1" + chownr@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" @@ -4147,22 +4035,16 @@ class-validator@^0.13.2: libphonenumber-js "^1.9.43" validator "^13.7.0" -classic-level@^1.2.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/classic-level/-/classic-level-1.3.0.tgz#5e36680e01dc6b271775c093f2150844c5edd5c8" - integrity sha512-iwFAJQYtqRTRM0F6L8h4JCt00ZSGdOyqh7yVrhhjrOpFhmBjNlRUey64MCiyo6UmQHMJ+No3c81nujPv+n9yrg== - dependencies: - abstract-level "^1.0.2" - catering "^2.1.0" - module-error "^1.0.1" - napi-macros "^2.2.2" - node-gyp-build "^4.3.0" - clean-stack@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== +cli-boxes@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-2.2.1.tgz#ddd5035d25094fce220e9cab40a45840a440318f" + integrity sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw== + cli-cursor@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" @@ -5443,7 +5325,7 @@ ethers@^4.0.40: uuid "2.0.1" xmlhttprequest "1.8.0" -ethers@^5.4.6, ethers@^5.5.3, ethers@^5.6.1, ethers@^5.7.1, ethers@^5.7.2: +ethers@^5.4.6, ethers@^5.5.3, ethers@^5.6.1, ethers@^5.7.2: version "5.7.2" resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.7.2.tgz#3a7deeabbb8c030d4126b24f84e525466145872e" integrity sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg== @@ -5516,11 +5398,6 @@ event-emitter@^0.3.5: d "1" es5-ext "~0.10.14" -event-target-shim@^5.0.0: - version "5.0.1" - resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" - integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== - eventemitter3@4.0.4: version "4.0.4" resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.4.tgz#b5463ace635a083d018bdc7c917b4c5f10a85384" @@ -5657,6 +5534,11 @@ fastq@^1.6.0: dependencies: reusify "^1.0.4" +fdir@^6.4.2: + version "6.4.2" + resolved "https://registry.yarnpkg.com/fdir/-/fdir-6.4.2.tgz#ddaa7ce1831b161bc3657bb99cb36e1622702689" + integrity sha512-KnhMXsKSPZlAhp7+IjUkRZKPb4fUyccpDrdFXbi4QL1qkmFh9kVY09Yox+n4MaOb3lHZ1Tv829C3oaaXoMYPDQ== + figlet@^1.5.2: version "1.7.0" resolved "https://registry.yarnpkg.com/figlet/-/figlet-1.7.0.tgz#46903a04603fd19c3e380358418bb2703587a72e" @@ -5717,7 +5599,7 @@ find-up@3.0.0, find-up@^3.0.0: dependencies: locate-path "^3.0.0" -find-up@5.0.0: +find-up@5.0.0, find-up@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== @@ -5725,13 +5607,6 @@ find-up@5.0.0: locate-path "^6.0.0" path-exists "^4.0.0" -find-up@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" - integrity sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ== - dependencies: - locate-path "^2.0.0" - flat-cache@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0" @@ -6354,65 +6229,61 @@ hardhat-gas-reporter@^1.0.9: eth-gas-reporter "^0.2.25" sha1 "^1.1.1" -hardhat-tracer@^2.3.2: - version "2.4.0" - resolved "https://registry.yarnpkg.com/hardhat-tracer/-/hardhat-tracer-2.4.0.tgz#c650251cc504e68e890edf3675b132bcd7cc2322" - integrity sha512-MFWN0Suu2KsUBDntdKemmuqh8M6DraIfW2yd+erCtTdzZjGfF09PzJ1gW/n3Gu2TFR1pwwMqQeilyspQ8G3KNw== +hardhat-tracer@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/hardhat-tracer/-/hardhat-tracer-3.1.0.tgz#460ced6bd6919928fc679a8d5764f2b861283b3b" + integrity sha512-Ip16HQAuzbqbNJUIEVfqmbPmOY90bxZSpwu5Q73cwloy+LUYA04BATUM9Gui5H7zcgsgZ1IVy7pSYn6ZMjLmag== dependencies: chalk "^4.1.2" + debug "^4.3.4" ethers "^5.6.1" + semver "^7.6.2" -hardhat@^2.14.1: - version "2.15.0" - resolved "https://registry.yarnpkg.com/hardhat/-/hardhat-2.15.0.tgz#0cacb2b44c4c4651aa8ab649fef12804848b0267" - integrity sha512-cC9tM/N10YaES04zPOp7yR13iX3YibqaNmi0//Ep40Nt9ELIJx3kFpQmucur0PAIfXYpGnw5RuXHNLkxpnVHEw== +hardhat@^2.22.17: + version "2.22.17" + resolved "https://registry.yarnpkg.com/hardhat/-/hardhat-2.22.17.tgz#96036bbe6bad8eb6a6b65c54dc5fbc1324541612" + integrity sha512-tDlI475ccz4d/dajnADUTRc1OJ3H8fpP9sWhXhBPpYsQOg8JHq5xrDimo53UhWPl7KJmAeDCm1bFG74xvpGRpg== dependencies: "@ethersproject/abi" "^5.1.2" "@metamask/eth-sig-util" "^4.0.0" - "@nomicfoundation/ethereumjs-block" "5.0.1" - "@nomicfoundation/ethereumjs-blockchain" "7.0.1" - "@nomicfoundation/ethereumjs-common" "4.0.1" - "@nomicfoundation/ethereumjs-evm" "2.0.1" - "@nomicfoundation/ethereumjs-rlp" "5.0.1" - "@nomicfoundation/ethereumjs-statemanager" "2.0.1" - "@nomicfoundation/ethereumjs-trie" "6.0.1" - "@nomicfoundation/ethereumjs-tx" "5.0.1" - "@nomicfoundation/ethereumjs-util" "9.0.1" - "@nomicfoundation/ethereumjs-vm" "7.0.1" + "@nomicfoundation/edr" "^0.6.5" + "@nomicfoundation/ethereumjs-common" "4.0.4" + "@nomicfoundation/ethereumjs-tx" "5.0.4" + "@nomicfoundation/ethereumjs-util" "9.0.4" "@nomicfoundation/solidity-analyzer" "^0.1.0" "@sentry/node" "^5.18.1" "@types/bn.js" "^5.1.0" "@types/lru-cache" "^5.1.0" - abort-controller "^3.0.0" adm-zip "^0.4.16" aggregate-error "^3.0.0" ansi-escapes "^4.3.0" - chalk "^2.4.2" - chokidar "^3.4.0" + boxen "^5.1.2" + chokidar "^4.0.0" ci-info "^2.0.0" debug "^4.1.1" enquirer "^2.3.0" env-paths "^2.2.0" ethereum-cryptography "^1.0.3" ethereumjs-abi "^0.6.8" - find-up "^2.1.0" + find-up "^5.0.0" fp-ts "1.19.3" fs-extra "^7.0.1" - glob "7.2.0" immutable "^4.0.0-rc.12" io-ts "1.10.4" + json-stream-stringify "^3.1.4" keccak "^3.0.2" lodash "^4.17.11" mnemonist "^0.38.0" mocha "^10.0.0" p-map "^4.0.0" - qs "^6.7.0" + picocolors "^1.1.0" raw-body "^2.4.1" resolve "1.17.0" semver "^6.3.0" - solc "0.7.3" + solc "0.8.26" source-map-support "^0.5.13" stacktrace-parser "^0.1.10" + tinyglobby "^0.2.6" tsort "0.0.1" undici "^5.14.0" uuid "^8.3.2" @@ -7058,11 +6929,6 @@ js-cookie@^2.2.1: resolved "https://registry.yarnpkg.com/js-cookie/-/js-cookie-2.2.1.tgz#69e106dc5d5806894562902aa5baec3744e9b2b8" integrity sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ== -js-sdsl@^4.1.4: - version "4.4.1" - resolved "https://registry.yarnpkg.com/js-sdsl/-/js-sdsl-4.4.1.tgz#9e3c7b566d8d9a7e1fe8fc26d00b5ab0f8918ab3" - integrity sha512-6Gsx8R0RucyePbWqPssR8DyfuXmLBooYN5cZFZKjHGnQuaf7pEzhtpceagJxVu4LqhYY5EYA7nko3FmeHZ1KbA== - js-sha3@0.5.7, js-sha3@^0.5.7: version "0.5.7" resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.5.7.tgz#0d4ffd8002d5333aabaf4a23eed2f6374c9f28e7" @@ -7158,6 +7024,11 @@ json-stable-stringify-without-jsonify@^1.0.1: resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== +json-stream-stringify@^3.1.4: + version "3.1.6" + resolved "https://registry.yarnpkg.com/json-stream-stringify/-/json-stream-stringify-3.1.6.tgz#ebe32193876fb99d4ec9f612389a8d8e2b5d54d4" + integrity sha512-x7fpwxOkbhFCaJDJ8vb1fBY3DdSa4AlITaz+HHILQJzdPMnHEFjxPwVUi1ALIbcIxDE0PNe/0i7frnY8QnBQog== + json-stringify-safe@~5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" @@ -7329,11 +7200,6 @@ level-supports@^2.0.1: resolved "https://registry.yarnpkg.com/level-supports/-/level-supports-2.1.0.tgz#9af908d853597ecd592293b2fad124375be79c5f" integrity sha512-E486g1NCjW5cF78KGPrMDRBYzPuueMZ6VBXHT6gC7A8UYWGiM14fGgp+s/L1oFfDWSPV/+SFkYCmZ0SiESkRKA== -level-supports@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/level-supports/-/level-supports-4.0.1.tgz#431546f9d81f10ff0fea0e74533a0e875c08c66a" - integrity sha512-PbXpve8rKeNcZ9C1mUicC9auIYFyGpkV9/i6g76tLgANwWhtG2v7I4xNBUlkn3lE2/dZF3Pi0ygYGtLc4RXXdA== - level-supports@~1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/level-supports/-/level-supports-1.0.1.tgz#2f530a596834c7301622521988e2c36bb77d122d" @@ -7341,14 +7207,6 @@ level-supports@~1.0.0: dependencies: xtend "^4.0.2" -level-transcoder@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/level-transcoder/-/level-transcoder-1.0.1.tgz#f8cef5990c4f1283d4c86d949e73631b0bc8ba9c" - integrity sha512-t7bFwFtsQeD8cl8NIoQ2iwxA0CL/9IFw7/9gAjOonH0PWTTiRfY7Hq+Ejbsxh86tXobDQ6IOiddjNYIfOBs06w== - dependencies: - buffer "^6.0.3" - module-error "^1.0.1" - level-ws@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/level-ws/-/level-ws-2.0.0.tgz#207a07bcd0164a0ec5d62c304b4615c54436d339" @@ -7358,14 +7216,6 @@ level-ws@^2.0.0: readable-stream "^3.1.0" xtend "^4.0.1" -level@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/level/-/level-8.0.0.tgz#41b4c515dabe28212a3e881b61c161ffead14394" - integrity sha512-ypf0jjAk2BWI33yzEaaotpq7fkOPALKAgDBxggO6Q9HGX2MRXn0wbP1Jn/tJv1gtL867+YOjOB49WaUF3UoJNQ== - dependencies: - browser-level "^1.0.1" - classic-level "^1.2.0" - leveldown@6.1.0: version "6.1.0" resolved "https://registry.yarnpkg.com/leveldown/-/leveldown-6.1.0.tgz#7ab1297706f70c657d1a72b31b40323aa612b9ee" @@ -7419,14 +7269,6 @@ lines-and-columns@^1.1.6: resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== -locate-path@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" - integrity sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA== - dependencies: - p-locate "^2.0.0" - path-exists "^3.0.0" - locate-path@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" @@ -7578,15 +7420,6 @@ memdown@^5.0.0: ltgt "~2.2.0" safe-buffer "~5.2.0" -memory-level@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/memory-level/-/memory-level-1.0.0.tgz#7323c3fd368f9af2f71c3cd76ba403a17ac41692" - integrity sha512-UXzwewuWeHBz5krr7EvehKcmLFNoXxGcvuYhC41tRnkrTbJohtS7kVn9akmgirtRygg+f7Yjsfi8Uu5SGSQ4Og== - dependencies: - abstract-level "^1.0.0" - functional-red-black-tree "^1.0.1" - module-error "^1.0.1" - memorystream@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/memorystream/-/memorystream-0.3.1.tgz#86d7090b30ce455d63fbae12dda51a47ddcaf9b2" @@ -7867,11 +7700,6 @@ mock-fs@^4.1.0: resolved "https://registry.yarnpkg.com/mock-fs/-/mock-fs-4.14.0.tgz#ce5124d2c601421255985e6e94da80a7357b1b18" integrity sha512-qYvlv/exQ4+svI3UOvPUpLDF0OMX5euvUH0Ny4N5QyRyhNdgAgUrVH3iUINSzEPLvx0kbo/Bp28GJKIqvE7URw== -module-error@^1.0.1, module-error@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/module-error/-/module-error-1.0.2.tgz#8d1a48897ca883f47a45816d4fb3e3c6ba404d86" - integrity sha512-0yuvsqSCv8LbaOKhnsQ/T5JhyFlCYLPXK3U2sgV10zoKQwzs/MyfuQUOZQ1V/6OCOJsK/TRgNVrPuPDqtdMFtA== - moment@^2.29.3: version "2.30.1" resolved "https://registry.yarnpkg.com/moment/-/moment-2.30.1.tgz#f8c91c07b7a786e30c59926df530b4eac96974ae" @@ -7961,11 +7789,6 @@ nanoid@3.3.3: resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.3.tgz#fd8e8b7aa761fe807dba2d1b98fb7241bb724a25" integrity sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w== -napi-macros@^2.2.2: - version "2.2.2" - resolved "https://registry.yarnpkg.com/napi-macros/-/napi-macros-2.2.2.tgz#817fef20c3e0e40a963fbf7b37d1600bd0201044" - integrity sha512-hmEVtAGYzVQpCKdbQea4skABsdXW4RUh5t5mJ2zzqowJS2OyXZTU1KhDVFhx+NlWZ4ap9mqR9TcDO3LTTttd+g== - napi-macros@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/napi-macros/-/napi-macros-2.0.0.tgz#2b6bae421e7b96eb687aa6c77a7858640670001b" @@ -8232,13 +8055,6 @@ p-cancelable@^3.0.0: resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-3.0.0.tgz#63826694b54d61ca1c20ebcb6d3ecf5e14cd8050" integrity sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw== -p-limit@^1.1.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" - integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== - dependencies: - p-try "^1.0.0" - p-limit@^2.0.0: version "2.3.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" @@ -8253,13 +8069,6 @@ p-limit@^3.0.2: dependencies: yocto-queue "^0.1.0" -p-locate@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" - integrity sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg== - dependencies: - p-limit "^1.1.0" - p-locate@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" @@ -8281,11 +8090,6 @@ p-map@^4.0.0: dependencies: aggregate-error "^3.0.0" -p-try@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" - integrity sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww== - p-try@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" @@ -8424,11 +8228,21 @@ performance-now@^2.1.0: resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" integrity sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow== +picocolors@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" + integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== + picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== +picomatch@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.2.tgz#77c742931e8f3b8820946c76cd0c1f13730d1dab" + integrity sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg== + pify@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" @@ -8595,7 +8409,7 @@ qs@6.11.0: dependencies: side-channel "^1.0.4" -qs@^6.11.0, qs@^6.4.0, qs@^6.7.0, qs@^6.9.4: +qs@^6.11.0, qs@^6.4.0, qs@^6.9.4: version "6.11.2" resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.2.tgz#64bea51f12c1f5da1bc01496f48ffcff7c69d7d9" integrity sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA== @@ -8678,6 +8492,11 @@ readable-stream@^3.1.0, readable-stream@^3.4.0, readable-stream@^3.6.0: string_decoder "^1.1.1" util-deprecate "^1.0.1" +readdirp@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-4.0.2.tgz#388fccb8b75665da3abffe2d8f8ed59fe74c230a" + integrity sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA== + readdirp@~3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.2.0.tgz#c30c33352b12c96dfb4b895421a49fd5a9593839" @@ -8966,13 +8785,6 @@ run-async@^2.2.0: resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ== -run-parallel-limit@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/run-parallel-limit/-/run-parallel-limit-1.1.0.tgz#be80e936f5768623a38a963262d6bef8ff11e7ba" - integrity sha512-jJA7irRNM91jaKc3Hcl1npHsFLOXOoTkPCUL1JEa1R82O2miplXXRaGdjW/KM/98YQWDhJLiSs793CnXfblJUw== - dependencies: - queue-microtask "^1.2.2" - run-parallel@^1.1.9: version "1.2.0" resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" @@ -9104,6 +8916,11 @@ semver@^7.5.1: dependencies: lru-cache "^6.0.0" +semver@^7.6.2: + version "7.6.3" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" + integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== + send@0.18.0: version "0.18.0" resolved "https://registry.yarnpkg.com/send/-/send-0.18.0.tgz#670167cc654b05f5aa4a767f9113bb371bc706be" @@ -9288,25 +9105,23 @@ slice-ansi@^4.0.0: astral-regex "^2.0.0" is-fullwidth-code-point "^3.0.0" -solc@0.7.3: - version "0.7.3" - resolved "https://registry.yarnpkg.com/solc/-/solc-0.7.3.tgz#04646961bd867a744f63d2b4e3c0701ffdc7d78a" - integrity sha512-GAsWNAjGzIDg7VxzP6mPjdurby3IkGCjQcM8GFYZT6RyaoUZKmMU6Y7YwG+tFGhv7dwZ8rmR4iwFDrrD99JwqA== +solc@0.8.15: + version "0.8.15" + resolved "https://registry.yarnpkg.com/solc/-/solc-0.8.15.tgz#d274dca4d5a8b7d3c9295d4cbdc9291ee1c52152" + integrity sha512-Riv0GNHNk/SddN/JyEuFKwbcWcEeho15iyupTSHw5Np6WuXA5D8kEHbyzDHi6sqmvLzu2l+8b1YmL8Ytple+8w== dependencies: command-exists "^1.2.8" - commander "3.0.2" + commander "^8.1.0" follow-redirects "^1.12.1" - fs-extra "^0.30.0" js-sha3 "0.8.0" memorystream "^0.3.1" - require-from-string "^2.0.0" semver "^5.5.0" tmp "0.0.33" -solc@0.8.15: - version "0.8.15" - resolved "https://registry.yarnpkg.com/solc/-/solc-0.8.15.tgz#d274dca4d5a8b7d3c9295d4cbdc9291ee1c52152" - integrity sha512-Riv0GNHNk/SddN/JyEuFKwbcWcEeho15iyupTSHw5Np6WuXA5D8kEHbyzDHi6sqmvLzu2l+8b1YmL8Ytple+8w== +solc@0.8.26: + version "0.8.26" + resolved "https://registry.yarnpkg.com/solc/-/solc-0.8.26.tgz#afc78078953f6ab3e727c338a2fefcd80dd5b01a" + integrity sha512-yiPQNVf5rBFHwN6SIf3TUUvVAFKcQqmSUFeq+fb6pNRCo0ZCgpYOZDi3BVoezCPIAcKrVYd/qXlBLUP9wVrZ9g== dependencies: command-exists "^1.2.8" commander "^8.1.0" @@ -9566,7 +9381,7 @@ string-width@^3.0.0, string-width@^3.1.0: is-fullwidth-code-point "^2.0.0" strip-ansi "^5.1.0" -string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3: +string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -9815,6 +9630,14 @@ timed-out@^4.0.1: resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" integrity sha512-G7r3AhovYtr5YKOWQkta8RKAPb+J9IsO4uVmzjl8AZwfhs8UcUwTiD6gcJYSgOtzyjvQKrKYn41syHbUWMkafA== +tinyglobby@^0.2.6: + version "0.2.10" + resolved "https://registry.yarnpkg.com/tinyglobby/-/tinyglobby-0.2.10.tgz#e712cf2dc9b95a1f5c5bbd159720e15833977a0f" + integrity sha512-Zc+8eJlFMvgatPZTl6A9L/yht8QqdmUNtURHaKZLmKBE12hNPSrqNkUp2cs3M/UKmNVVAMFQYSjYIVHDjW5zew== + dependencies: + fdir "^6.4.2" + picomatch "^4.0.2" + tmp@0.0.33, tmp@^0.0.33: version "0.0.33" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" @@ -10773,6 +10596,13 @@ wide-align@1.1.3: dependencies: string-width "^1.0.2 || 2" +widest-line@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-3.1.0.tgz#8292333bbf66cb45ff0de1603b136b7ae1496eca" + integrity sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg== + dependencies: + string-width "^4.0.0" + word-wrap@^1.2.3, word-wrap@~1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" From 2653e2b3081c0658f8dc7dd9c2e877a800de7360 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Mon, 30 Dec 2024 11:44:43 +1100 Subject: [PATCH 220/273] More Sonic deployment changes --- contracts/deploy/sonic/001_origin_sonic.js | 24 ++++++++++++++++------ contracts/hardhat.config.js | 8 ++++---- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/contracts/deploy/sonic/001_origin_sonic.js b/contracts/deploy/sonic/001_origin_sonic.js index ec269e20c8..ef7eb6bd87 100644 --- a/contracts/deploy/sonic/001_origin_sonic.js +++ b/contracts/deploy/sonic/001_origin_sonic.js @@ -8,6 +8,8 @@ module.exports = deployOnSonic( }, async ({ ethers }) => { const { governorAddr, deployerAddr } = await getNamedAccounts(); + console.log(`Governor: ${governorAddr}`); + console.log(`Deployer: ${deployerAddr}`); const sGovernor = await ethers.provider.getSigner(governorAddr); const sDeployer = await ethers.provider.getSigner(deployerAddr); @@ -26,19 +28,19 @@ module.exports = deployOnSonic( const cOSonicVaultProxy = await ethers.getContract("OSonicVaultProxy"); // Core contracts - const dOSonic = await deployOnSonic("OSonic"); - console.log("Deployed Origin S"); - const dWOSonic = await deployOnSonic("WOSonic", [ + const dOSonic = await deployWithConfirmation("OSonic"); + console.log(`Deployed Origin S to ${dOSonic.address}`); + const dWOSonic = await deployWithConfirmation("WOSonic", [ cOSonicProxy.address, // Base token "Wrapped Origin S", // Token Name "wOS", // Token Symbol ]); - console.log("Deployed Wrapped Origin S"); - const dOSonicVaultCore = await deployOnSonic("OSonicVaultCore", [ + console.log(`Deployed Wrapped Origin S to ${dWOSonic.address}`); + const dOSonicVaultCore = await deployWithConfirmation("OSonicVaultCore", [ cWS.address, ]); console.log("Deployed Vault Core"); - const dOSonicVaultAdmin = await deployOnSonic("OSonicVaultAdmin", [ + const dOSonicVaultAdmin = await deployWithConfirmation("OSonicVaultAdmin", [ cWS.address, ]); console.log("Deployed Vault Admin"); @@ -65,6 +67,9 @@ module.exports = deployOnSonic( resolution, // HighRes ] ); + console.log(`cOSonicVaultProxy ${cOSonicVaultProxy.address}`); + console.log(`dOSonic ${dOSonic.address}`); + console.log(`governorAddr ${governorAddr}`); // prettier-ignore await cOSonicProxy .connect(sDeployer)["initialize(address,address,bytes)"]( @@ -72,6 +77,7 @@ module.exports = deployOnSonic( governorAddr, initDataOSonic ); + console.log("Initialized Origin S"); // Init OSonicVault const initDataOSonicVault = cOSonicVault.interface.encodeFunctionData( @@ -88,6 +94,7 @@ module.exports = deployOnSonic( governorAddr, initDataOSonicVault ); + console.log("Initialized Origin S Vault"); // Init WOSonic const initDataWOSonic = cWOSonic.interface.encodeFunctionData( @@ -101,15 +108,20 @@ module.exports = deployOnSonic( governorAddr, initDataWOSonic ) + console.log("Initialized Wrapper Origin S"); await cOSonicVaultProxy .connect(sGovernor) .upgradeTo(dOSonicVaultCore.address); + console.log("Upgrade Vault proxy to VaultCore"); await cOSonicVault .connect(sGovernor) .setAdminImpl(dOSonicVaultAdmin.address); + console.log("Set VaultAdmin on Vault"); await cOSonicVault.connect(sGovernor).supportAsset(cWS.address, 0); + console.log("Added vault support of Wrapped S"); await cOSonicVault.connect(sGovernor).unpauseCapital(); + console.log("Unpaused capital"); } ); diff --git a/contracts/hardhat.config.js b/contracts/hardhat.config.js index 092370a3fb..f517fc01c8 100644 --- a/contracts/hardhat.config.js +++ b/contracts/hardhat.config.js @@ -55,7 +55,7 @@ const BASE_DEPLOYER = MAINNET_DEPLOYER; const BASE_GOVERNOR = "0x92A19381444A001d62cE67BaFF066fA1111d7202"; const BASE_STRATEGIST = "0x28bce2eE5775B652D92bB7c2891A89F036619703"; const SONIC_DEPLOYER = MAINNET_DEPLOYER; -const SONIC_GOVERNOR = ""; +const SONIC_GOVERNOR = MAINNET_DEPLOYER; const SONIC_STRATEGIST = ""; const mnemonic = @@ -228,8 +228,8 @@ module.exports = { mainnet: MAINNET_DEPLOYER, arbitrumOne: MAINNET_DEPLOYER, holesky: HOLESKY_DEPLOYER, - base: MAINNET_DEPLOYER, - sonic: MAINNET_DEPLOYER, + base: BASE_DEPLOYER, + sonic: SONIC_DEPLOYER, }, governorAddr: { default: 1, @@ -255,7 +255,7 @@ module.exports = { mainnet: MAINNET_GOVERNOR, holesky: HOLESKY_DEPLOYER, // on Holesky the deployer is also the governor base: BASE_GOVERNOR, - sonic: BASE_GOVERNOR, + sonic: SONIC_GOVERNOR, }, /* Local node environment currently has no access to Decentralized governance * address, since the contract is in another repo. Once we merge the ousd-governance From 92a7dd6cee3b25853f352970cb46d98cc5e7c64f Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Mon, 30 Dec 2024 13:38:56 +1100 Subject: [PATCH 221/273] More Sonic fixes --- contracts/hardhat.config.js | 10 ++++++++++ contracts/utils/deploy.js | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/contracts/hardhat.config.js b/contracts/hardhat.config.js index f517fc01c8..7748653408 100644 --- a/contracts/hardhat.config.js +++ b/contracts/hardhat.config.js @@ -217,12 +217,20 @@ module.exports = { process.env.FORK === "true" ? isHoleskyFork ? HOLESKY_DEPLOYER + : isBaseFork + ? BASE_DEPLOYER + : isSonicFork + ? SONIC_DEPLOYER : MAINNET_DEPLOYER : 0, hardhat: process.env.FORK === "true" ? isHoleskyFork ? HOLESKY_DEPLOYER + : isBaseFork + ? BASE_DEPLOYER + : isSonicFork + ? SONIC_DEPLOYER : MAINNET_DEPLOYER : 0, mainnet: MAINNET_DEPLOYER, @@ -250,6 +258,8 @@ module.exports = { ? HOLESKY_DEPLOYER : isBaseFork ? BASE_GOVERNOR + : isSonicFork + ? SONIC_GOVERNOR : MAINNET_GOVERNOR : 1, mainnet: MAINNET_GOVERNOR, diff --git a/contracts/utils/deploy.js b/contracts/utils/deploy.js index 76b35870f2..6adf7d2081 100644 --- a/contracts/utils/deploy.js +++ b/contracts/utils/deploy.js @@ -95,7 +95,7 @@ const deployWithConfirmation = async ( if (!args) args = null; if (!contract) contract = contractName; let feeData; - if (useFeeData) { + if (!useFeeData && !isSonic) { feeData = await hre.ethers.provider.getFeeData(); } const result = await withConfirmation( From cba9f6cfc604678c95bc9b00211927973986f15a Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Mon, 30 Dec 2024 13:53:58 +1100 Subject: [PATCH 222/273] Sonic VaultAdmin override supportAsset as it doesn't have a price provider --- .../contracts/vault/OSonicVaultAdmin.sol | 30 +++++++++++++++++++ contracts/contracts/vault/VaultAdmin.sol | 1 + 2 files changed, 31 insertions(+) diff --git a/contracts/contracts/vault/OSonicVaultAdmin.sol b/contracts/contracts/vault/OSonicVaultAdmin.sol index 98f9d14e64..fbc67957db 100644 --- a/contracts/contracts/vault/OSonicVaultAdmin.sol +++ b/contracts/contracts/vault/OSonicVaultAdmin.sol @@ -10,4 +10,34 @@ import { OETHVaultAdmin } from "./OETHVaultAdmin.sol"; contract OSonicVaultAdmin is OETHVaultAdmin { /// @param _wS Sonic's Wrapped S token constructor(address _wS) OETHVaultAdmin(_wS) {} + + /*************************************** + Asset Config + ****************************************/ + + /** + * @notice Add a supported asset to the contract, i.e. one that can be to mint OTokens. + * @dev Overridden to remove price provider integration + * @param _asset Address of asset + * @param _unitConversion 0 decimals, 1 exchange rate + */ + function supportAsset(address _asset, uint8 _unitConversion) + external + override + onlyGovernor + { + require(!assets[_asset].isSupported, "Asset already supported"); + + assets[_asset] = Asset({ + isSupported: true, + unitConversion: UnitConversion(_unitConversion), + decimals: 0, // will be overridden in _cacheDecimals + allowedOracleSlippageBps: 0 // 0% by default + }); + + _cacheDecimals(_asset); + allAssets.push(_asset); + + emit AssetSupported(_asset); + } } diff --git a/contracts/contracts/vault/VaultAdmin.sol b/contracts/contracts/vault/VaultAdmin.sol index a66d277523..4eaef6b5ec 100644 --- a/contracts/contracts/vault/VaultAdmin.sol +++ b/contracts/contracts/vault/VaultAdmin.sol @@ -361,6 +361,7 @@ contract VaultAdmin is VaultStorage { */ function supportAsset(address _asset, uint8 _unitConversion) external + virtual onlyGovernor { require(!assets[_asset].isSupported, "Asset already supported"); From 61e9146bb5f49f8a1b56c2b5c60ad4375247b110 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Mon, 30 Dec 2024 13:55:35 +1100 Subject: [PATCH 223/273] Solidity prettier --- .../interfaces/sonic/IWrappedSonic.sol | 18 ++++++++++---- contracts/contracts/proxies/SonicProxies.sol | 24 ++++++++++++++----- .../strategies/Generalized4626Strategy.sol | 1 - .../Generalized4626USDTStrategy.sol | 9 ++++--- contracts/contracts/token/OSonic.sol | 4 +++- contracts/contracts/token/WOSonic.sol | 8 +++---- 6 files changed, 43 insertions(+), 21 deletions(-) diff --git a/contracts/contracts/interfaces/sonic/IWrappedSonic.sol b/contracts/contracts/interfaces/sonic/IWrappedSonic.sol index 9eba6c81ab..8ebf93f3c8 100644 --- a/contracts/contracts/interfaces/sonic/IWrappedSonic.sol +++ b/contracts/contracts/interfaces/sonic/IWrappedSonic.sol @@ -2,22 +2,32 @@ pragma solidity ^0.8.0; interface IWrappedSonic { - function allowance( - address owner, - address spender - ) external view returns (uint256); + function allowance(address owner, address spender) + external + view + returns (uint256); + function approve(address spender, uint256 value) external returns (bool); + function balanceOf(address account) external view returns (uint256); + function decimals() external view returns (uint8); + function deposit() external; + function depositFor(address account) external returns (bool); + function totalSupply() external view returns (uint256); + function transfer(address to, uint256 value) external returns (bool); + function transferFrom( address from, address to, uint256 value ) external returns (bool); + function withdraw(uint256 value) external; + function withdrawTo(address account, uint256 value) external returns (bool); } diff --git a/contracts/contracts/proxies/SonicProxies.sol b/contracts/contracts/proxies/SonicProxies.sol index fdfb46bb81..aea4267ff2 100644 --- a/contracts/contracts/proxies/SonicProxies.sol +++ b/contracts/contracts/proxies/SonicProxies.sol @@ -6,29 +6,41 @@ import { InitializeGovernedUpgradeabilityProxy } from "./InitializeGovernedUpgra /** * @notice OSonicVaultProxy delegates calls to OSonicVault implementation */ -contract OSonicVaultProxy is InitializeGovernedUpgradeabilityProxy {} +contract OSonicVaultProxy is InitializeGovernedUpgradeabilityProxy { + +} /** * @notice OSonicProxy delegates calls to OSonic implementation */ -contract OSonicProxy is InitializeGovernedUpgradeabilityProxy {} +contract OSonicProxy is InitializeGovernedUpgradeabilityProxy { + +} /** * @notice WOSonicProxy delegates calls to WOSonic implementation */ -contract WOSonicProxy is InitializeGovernedUpgradeabilityProxy {} +contract WOSonicProxy is InitializeGovernedUpgradeabilityProxy { + +} /** * @notice OSonicDripperProxy delegates calls to a OSonicDripper implementation */ -contract OSonicDripperProxy is InitializeGovernedUpgradeabilityProxy {} +contract OSonicDripperProxy is InitializeGovernedUpgradeabilityProxy { + +} /** * @notice SonicStakingStrategyProxy delegates calls to SonicStakingStrategy implementation */ -contract SonicStakingStrategyProxy is InitializeGovernedUpgradeabilityProxy {} +contract SonicStakingStrategyProxy is InitializeGovernedUpgradeabilityProxy { + +} /** * @notice OSonicHarvesterProxy delegates calls to a OSonicHarvester implementation */ -contract OSonicHarvesterProxy is InitializeGovernedUpgradeabilityProxy {} +contract OSonicHarvesterProxy is InitializeGovernedUpgradeabilityProxy { + +} diff --git a/contracts/contracts/strategies/Generalized4626Strategy.sol b/contracts/contracts/strategies/Generalized4626Strategy.sol index 6c0feedfca..cac76fe1eb 100644 --- a/contracts/contracts/strategies/Generalized4626Strategy.sol +++ b/contracts/contracts/strategies/Generalized4626Strategy.sol @@ -10,7 +10,6 @@ import { IERC4626 } from "../../lib/openzeppelin/interfaces/IERC4626.sol"; import { IERC20, InitializableAbstractStrategy } from "../utils/InitializableAbstractStrategy.sol"; contract Generalized4626Strategy is InitializableAbstractStrategy { - /// @dev Replaced with an immutable variable // slither-disable-next-line constable-states address private _deprecate_shareToken; diff --git a/contracts/contracts/strategies/Generalized4626USDTStrategy.sol b/contracts/contracts/strategies/Generalized4626USDTStrategy.sol index b8d65053b0..3a5e9d2cab 100644 --- a/contracts/contracts/strategies/Generalized4626USDTStrategy.sol +++ b/contracts/contracts/strategies/Generalized4626USDTStrategy.sol @@ -4,7 +4,7 @@ pragma solidity ^0.8.0; interface IUSDT { // Tether's approve does not return a bool like standard IERC20 contracts // slither-disable-next-line erc20-interface - function approve(address _spender, uint _value) external; + function approve(address _spender, uint256 _value) external; } /** @@ -20,10 +20,9 @@ contract Generalized4626USDTStrategy is Generalized4626Strategy { * and vaultAddress (OToken Vault contract), eg VaultProxy or OETHVaultProxy * @param _assetToken Address of the ERC-4626 asset token. eg frxETH or DAI */ - constructor( - BaseStrategyConfig memory _baseConfig, - address _assetToken - ) Generalized4626Strategy(_baseConfig, _assetToken) {} + constructor(BaseStrategyConfig memory _baseConfig, address _assetToken) + Generalized4626Strategy(_baseConfig, _assetToken) + {} /// @dev Override for Tether as USDT does not return a bool on approve. /// Using assetToken.approve will fail as it expects a bool return value diff --git a/contracts/contracts/token/OSonic.sol b/contracts/contracts/token/OSonic.sol index 31a129ce18..845f132922 100644 --- a/contracts/contracts/token/OSonic.sol +++ b/contracts/contracts/token/OSonic.sol @@ -7,4 +7,6 @@ import { OUSD } from "./OUSD.sol"; * @title Origin S (OS) Token Contract on Sonic * @author Origin Protocol Inc */ -contract OSonic is OUSD {} +contract OSonic is OUSD { + +} diff --git a/contracts/contracts/token/WOSonic.sol b/contracts/contracts/token/WOSonic.sol index 79a9e1e047..ce5a2f9d32 100644 --- a/contracts/contracts/token/WOSonic.sol +++ b/contracts/contracts/token/WOSonic.sol @@ -45,10 +45,10 @@ contract WOSonic is ERC4626, Governable, Initializable { * @param asset_ Address for the asset * @param amount_ Amount of the asset to transfer */ - function transferToken( - address asset_, - uint256 amount_ - ) external onlyGovernor { + function transferToken(address asset_, uint256 amount_) + external + onlyGovernor + { require(asset_ != address(asset()), "Cannot collect Origin S"); IERC20(asset_).safeTransfer(governor(), amount_); } From c36ed1752a6df24b5e3106c454f27f56fbebbd0c Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Mon, 30 Dec 2024 20:02:48 +1100 Subject: [PATCH 224/273] Skipping reborn attack tests now self-destruct has been removed --- contracts/test/hacks/reborn.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/test/hacks/reborn.js b/contracts/test/hacks/reborn.js index 3e8f51283f..101a41c23d 100644 --- a/contracts/test/hacks/reborn.js +++ b/contracts/test/hacks/reborn.js @@ -3,7 +3,7 @@ const { expect } = require("chai"); const { createFixtureLoader, rebornFixture } = require("../_fixture"); const { isFork, daiUnits, ousdUnits } = require("../helpers"); -describe("Reborn Attack Protection", function () { +describe.skip("Reborn Attack Protection", function () { if (isFork) { this.timeout(0); } From 7cc647f173c981c05c0a5107f0cf61e636ad355b Mon Sep 17 00:00:00 2001 From: Domen Grabec Date: Mon, 30 Dec 2024 11:29:00 +0100 Subject: [PATCH 225/273] fix reborn tests --- .../contracts/mocks/MockRebornMinter.sol | 11 ++++ contracts/test/_fixture.js | 12 +++- contracts/test/hacks/reborn.js | 56 ++++++++++++------- 3 files changed, 56 insertions(+), 23 deletions(-) diff --git a/contracts/contracts/mocks/MockRebornMinter.sol b/contracts/contracts/mocks/MockRebornMinter.sol index c78d54ea43..200ec50390 100644 --- a/contracts/contracts/mocks/MockRebornMinter.sol +++ b/contracts/contracts/mocks/MockRebornMinter.sol @@ -11,6 +11,8 @@ contract Sanctum { address public vault; address public reborner; bool public shouldAttack = false; + // should selfdestruct in the constructor + bool public shouldDestruct = false; uint256 public targetMethod; address public ousdContract; @@ -51,6 +53,11 @@ contract Sanctum { shouldAttack = _shouldAttack; } + // should call selfdestruct in the constructor + function setShouldDesctruct(bool _shouldDestruct) public { + shouldDestruct = _shouldDestruct; + } + function setTargetMethod(uint256 target) public { targetMethod = target; } @@ -80,6 +87,10 @@ contract Reborner { mint(); } } + + if (sanctum.shouldDestruct()) { + bye(); + } } function mint() public { diff --git a/contracts/test/_fixture.js b/contracts/test/_fixture.js index 51a81a387d..75ce1a5917 100644 --- a/contracts/test/_fixture.js +++ b/contracts/test/_fixture.js @@ -2433,19 +2433,25 @@ async function rebornFixture() { const initCode = (await ethers.getContractFactory("Reborner")).bytecode; const deployCode = `${initCode}${encodedCallbackAddress}`; - await sanctum.deploy(12345, deployCode); const rebornAddress = await sanctum.computeAddress(12345, deployCode); const reborner = await ethers.getContractAt("Reborner", rebornAddress); - const rebornAttack = async (shouldAttack = true, targetMethod = null) => { + // deploy the reborn contract and call a method + const deployAndCall = async ({ + shouldAttack = true, + targetMethod = null, + shouldDestruct = false + }) => { await sanctum.setShouldAttack(shouldAttack); + await sanctum.setShouldDesctruct(shouldDestruct); if (targetMethod) await sanctum.setTargetMethod(targetMethod); await sanctum.setOUSDAddress(fixture.ousd.address); await sanctum.deploy(12345, deployCode); }; + fixture.rebornAddress = rebornAddress; fixture.reborner = reborner; - fixture.rebornAttack = rebornAttack; + fixture.deployAndCall = deployAndCall; return fixture; } diff --git a/contracts/test/hacks/reborn.js b/contracts/test/hacks/reborn.js index 101a41c23d..6e30ef2141 100644 --- a/contracts/test/hacks/reborn.js +++ b/contracts/test/hacks/reborn.js @@ -15,48 +15,64 @@ describe.skip("Reborn Attack Protection", function () { fixture = await loadFixture(); }); it("Should correctly do accounting when reborn calls mint as different types of addresses", async function () { - const { dai, ousd, matt, reborner, rebornAttack } = fixture; - await dai.connect(matt).transfer(reborner.address, daiUnits("4")); + const { dai, ousd, matt, rebornAddress, reborner, deployAndCall } = fixture; + await dai.connect(matt).transfer(rebornAddress, daiUnits("4")); + // call mint and self destruct (since account.code.length = 0) in constructor this is done + // as an EOA from OUSD.sol's point of view + await deployAndCall({ shouldAttack:true, shouldDestruct:true }); + // just deploy reborner contract + await deployAndCall({ shouldAttack:false }); + // call mint and expect to be migrated to a contract address await reborner.mint(); - await reborner.bye(); - await rebornAttack(true); - await expect(reborner).to.have.a.balanceOf("2", ousd); + await expect(await ousd.balanceOf(rebornAddress)).to.equal(ousdUnits("2")); expect(await ousd.nonRebasingSupply()).to.equal(ousdUnits("2")); }); it("Should correctly do accounting when reborn calls burn as different types of addresses", async function () { - const { dai, ousd, matt, reborner, rebornAttack } = fixture; + const { dai, ousd, matt, reborner, rebornAddress, deployAndCall } = fixture; await dai.connect(matt).transfer(reborner.address, daiUnits("4")); - await reborner.mint(); - await reborner.bye(); - await rebornAttack(true, 1); - await expect(reborner).to.have.a.balanceOf("0", ousd); - expect(await ousd.nonRebasingSupply()).to.equal(ousdUnits("0")); + // call mint and self destruct (since account.code.length = 0) in constructor this is done + // as an EOA from OUSD.sol's point of view + await deployAndCall({ shouldAttack:true, shouldDestruct:true }); + await deployAndCall({ shouldAttack:true, shouldDestruct:true }); + + await deployAndCall({ shouldAttack:false}); + // call redeem and expect to be migrated to a contract address + await reborner.redeem(); + await expect(await ousd.balanceOf(rebornAddress)).to.equal(ousdUnits("1")); + expect(await ousd.nonRebasingSupply()).to.equal(ousdUnits("1")); }); it("Should correctly do accounting when reborn calls transfer as different types of addresses", async function () { - const { dai, ousd, matt, reborner, rebornAttack } = fixture; + const { dai, ousd, matt, reborner, rebornAddress, deployAndCall } = fixture; await dai.connect(matt).transfer(reborner.address, daiUnits("4")); + // call mint and self destruct (since account.code.length = 0) in constructor this is done + // as an EOA from OUSD.sol's point of view + await deployAndCall({ shouldAttack:true, shouldDestruct:true }); + expect(await ousd.nonRebasingSupply()).to.equal(ousdUnits("0")); + expect(await ousd.nonRebasingSupply()).to.equal(ousdUnits("0")); + + await deployAndCall({ shouldAttack:false}); + // call transfer and expect to be migrated to a contract address + await reborner.transfer(); + await expect(await ousd.balanceOf(rebornAddress)).to.equal(ousdUnits("0")); + expect(await ousd.nonRebasingSupply()).to.equal(ousdUnits("0")); await reborner.mint(); - await reborner.bye(); + await expect(await ousd.balanceOf(rebornAddress)).to.equal(ousdUnits("1")); expect(await ousd.nonRebasingSupply()).to.equal(ousdUnits("1")); - await rebornAttack(true, 2); - await expect(reborner).to.have.a.balanceOf("0", ousd); - expect(await ousd.nonRebasingSupply()).to.equal(ousdUnits("0")); }); it("Should have correct balance even after recreating", async function () { - const { dai, matt, reborner, rebornAttack, ousd } = fixture; + const { dai, matt, reborner, deployAndCall, ousd } = fixture; // Mint one OUSD and self-destruct await dai.connect(matt).transfer(reborner.address, daiUnits("4")); - await reborner.mint(); + await deployAndCall({ shouldAttack:true, shouldDestruct:true }); await expect(reborner).to.have.a.balanceOf("1", ousd); - await reborner.bye(); // Recreate the contract at the same address but expect // to not have any change in balance (outside constructor) - await rebornAttack(false); + await deployAndCall({ shouldAttack:false }); await expect(reborner).to.have.a.balanceOf("1", ousd); await reborner.mint(); await expect(reborner).to.have.a.balanceOf("2", ousd); From e18c53fe25bb541c29ef15178d318dc74e2aaca9 Mon Sep 17 00:00:00 2001 From: Domen Grabec Date: Mon, 30 Dec 2024 12:05:34 +0100 Subject: [PATCH 226/273] re-enable fixed reborn tests --- contracts/test/hacks/reborn.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/test/hacks/reborn.js b/contracts/test/hacks/reborn.js index 6e30ef2141..6f7d74d255 100644 --- a/contracts/test/hacks/reborn.js +++ b/contracts/test/hacks/reborn.js @@ -3,7 +3,7 @@ const { expect } = require("chai"); const { createFixtureLoader, rebornFixture } = require("../_fixture"); const { isFork, daiUnits, ousdUnits } = require("../helpers"); -describe.skip("Reborn Attack Protection", function () { +describe("Reborn Attack Protection", function () { if (isFork) { this.timeout(0); } From 665f4d003da60b086183a9f0d296f3905439f1dd Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Tue, 31 Dec 2024 10:21:46 +1100 Subject: [PATCH 227/273] Added SPC --- contracts/contracts/interfaces/ISFC.sol | 40 +++++++++++++++++++++++++ contracts/utils/addresses.js | 1 + 2 files changed, 41 insertions(+) create mode 100644 contracts/contracts/interfaces/ISFC.sol diff --git a/contracts/contracts/interfaces/ISFC.sol b/contracts/contracts/interfaces/ISFC.sol new file mode 100644 index 0000000000..f99378aab5 --- /dev/null +++ b/contracts/contracts/interfaces/ISFC.sol @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.27; + +/** + * @title Special Fee Contract for Sonic network + * @notice The SFC maintains a list of validators and delegators and distributes rewards to them. + * @custom:security-contact security@fantom.foundation + */ +interface ISFC { + error StakeIsFullySlashed(); + + function currentEpoch() external view returns (uint256); + + function getStake(address, uint256) external view returns (uint256); + + function delegate(uint256 toValidatorID) external payable; + + function undelegate( + uint256 toValidatorID, + uint256 wrID, + uint256 amount + ) external; + + function withdraw(uint256 toValidatorID, uint256 wrID) external; + + function pendingRewards( + address delegator, + uint256 toValidatorID + ) external view returns (uint256); + + function claimRewards(uint256 toValidatorID) external; + + function getSelfStake(uint256 validatorID) external view returns (uint256); + + function isSlashed(uint256 validatorID) external view returns (bool); + + function slashingRefundRatio( + uint256 validatorID + ) external view returns (uint256); +} diff --git a/contracts/utils/addresses.js b/contracts/utils/addresses.js index 7de1a94891..fd7c0c9a88 100644 --- a/contracts/utils/addresses.js +++ b/contracts/utils/addresses.js @@ -339,6 +339,7 @@ addresses.base.OZRelayerAddress = "0xc0D6fa24D135c006dE5B8b2955935466A03D920a"; addresses.sonic = {}; addresses.sonic.wS = "0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38"; addresses.sonic.WETH = "0x309C92261178fA0CF748A855e90Ae73FDb79EBc7"; +addresses.sonic.SFC = "0xFC00FACE00000000000000000000000000000000"; // Holesky addresses.holesky.WETH = "0x94373a4919B3240D86eA41593D5eBa789FEF3848"; From d1991333ce27dd704586e5a7355c197f477408da Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Tue, 31 Dec 2024 10:37:23 +1100 Subject: [PATCH 228/273] fix reborn tests --- .../contracts/mocks/MockRebornMinter.sol | 11 ++++ contracts/test/_fixture.js | 12 +++- contracts/test/hacks/reborn.js | 58 ++++++++++++------- 3 files changed, 57 insertions(+), 24 deletions(-) diff --git a/contracts/contracts/mocks/MockRebornMinter.sol b/contracts/contracts/mocks/MockRebornMinter.sol index c78d54ea43..200ec50390 100644 --- a/contracts/contracts/mocks/MockRebornMinter.sol +++ b/contracts/contracts/mocks/MockRebornMinter.sol @@ -11,6 +11,8 @@ contract Sanctum { address public vault; address public reborner; bool public shouldAttack = false; + // should selfdestruct in the constructor + bool public shouldDestruct = false; uint256 public targetMethod; address public ousdContract; @@ -51,6 +53,11 @@ contract Sanctum { shouldAttack = _shouldAttack; } + // should call selfdestruct in the constructor + function setShouldDesctruct(bool _shouldDestruct) public { + shouldDestruct = _shouldDestruct; + } + function setTargetMethod(uint256 target) public { targetMethod = target; } @@ -80,6 +87,10 @@ contract Reborner { mint(); } } + + if (sanctum.shouldDestruct()) { + bye(); + } } function mint() public { diff --git a/contracts/test/_fixture.js b/contracts/test/_fixture.js index 51a81a387d..75ce1a5917 100644 --- a/contracts/test/_fixture.js +++ b/contracts/test/_fixture.js @@ -2433,19 +2433,25 @@ async function rebornFixture() { const initCode = (await ethers.getContractFactory("Reborner")).bytecode; const deployCode = `${initCode}${encodedCallbackAddress}`; - await sanctum.deploy(12345, deployCode); const rebornAddress = await sanctum.computeAddress(12345, deployCode); const reborner = await ethers.getContractAt("Reborner", rebornAddress); - const rebornAttack = async (shouldAttack = true, targetMethod = null) => { + // deploy the reborn contract and call a method + const deployAndCall = async ({ + shouldAttack = true, + targetMethod = null, + shouldDestruct = false + }) => { await sanctum.setShouldAttack(shouldAttack); + await sanctum.setShouldDesctruct(shouldDestruct); if (targetMethod) await sanctum.setTargetMethod(targetMethod); await sanctum.setOUSDAddress(fixture.ousd.address); await sanctum.deploy(12345, deployCode); }; + fixture.rebornAddress = rebornAddress; fixture.reborner = reborner; - fixture.rebornAttack = rebornAttack; + fixture.deployAndCall = deployAndCall; return fixture; } diff --git a/contracts/test/hacks/reborn.js b/contracts/test/hacks/reborn.js index 101a41c23d..6f7d74d255 100644 --- a/contracts/test/hacks/reborn.js +++ b/contracts/test/hacks/reborn.js @@ -3,7 +3,7 @@ const { expect } = require("chai"); const { createFixtureLoader, rebornFixture } = require("../_fixture"); const { isFork, daiUnits, ousdUnits } = require("../helpers"); -describe.skip("Reborn Attack Protection", function () { +describe("Reborn Attack Protection", function () { if (isFork) { this.timeout(0); } @@ -15,48 +15,64 @@ describe.skip("Reborn Attack Protection", function () { fixture = await loadFixture(); }); it("Should correctly do accounting when reborn calls mint as different types of addresses", async function () { - const { dai, ousd, matt, reborner, rebornAttack } = fixture; - await dai.connect(matt).transfer(reborner.address, daiUnits("4")); + const { dai, ousd, matt, rebornAddress, reborner, deployAndCall } = fixture; + await dai.connect(matt).transfer(rebornAddress, daiUnits("4")); + // call mint and self destruct (since account.code.length = 0) in constructor this is done + // as an EOA from OUSD.sol's point of view + await deployAndCall({ shouldAttack:true, shouldDestruct:true }); + // just deploy reborner contract + await deployAndCall({ shouldAttack:false }); + // call mint and expect to be migrated to a contract address await reborner.mint(); - await reborner.bye(); - await rebornAttack(true); - await expect(reborner).to.have.a.balanceOf("2", ousd); + await expect(await ousd.balanceOf(rebornAddress)).to.equal(ousdUnits("2")); expect(await ousd.nonRebasingSupply()).to.equal(ousdUnits("2")); }); it("Should correctly do accounting when reborn calls burn as different types of addresses", async function () { - const { dai, ousd, matt, reborner, rebornAttack } = fixture; + const { dai, ousd, matt, reborner, rebornAddress, deployAndCall } = fixture; await dai.connect(matt).transfer(reborner.address, daiUnits("4")); - await reborner.mint(); - await reborner.bye(); - await rebornAttack(true, 1); - await expect(reborner).to.have.a.balanceOf("0", ousd); - expect(await ousd.nonRebasingSupply()).to.equal(ousdUnits("0")); + // call mint and self destruct (since account.code.length = 0) in constructor this is done + // as an EOA from OUSD.sol's point of view + await deployAndCall({ shouldAttack:true, shouldDestruct:true }); + await deployAndCall({ shouldAttack:true, shouldDestruct:true }); + + await deployAndCall({ shouldAttack:false}); + // call redeem and expect to be migrated to a contract address + await reborner.redeem(); + await expect(await ousd.balanceOf(rebornAddress)).to.equal(ousdUnits("1")); + expect(await ousd.nonRebasingSupply()).to.equal(ousdUnits("1")); }); it("Should correctly do accounting when reborn calls transfer as different types of addresses", async function () { - const { dai, ousd, matt, reborner, rebornAttack } = fixture; + const { dai, ousd, matt, reborner, rebornAddress, deployAndCall } = fixture; await dai.connect(matt).transfer(reborner.address, daiUnits("4")); + // call mint and self destruct (since account.code.length = 0) in constructor this is done + // as an EOA from OUSD.sol's point of view + await deployAndCall({ shouldAttack:true, shouldDestruct:true }); + expect(await ousd.nonRebasingSupply()).to.equal(ousdUnits("0")); + expect(await ousd.nonRebasingSupply()).to.equal(ousdUnits("0")); + + await deployAndCall({ shouldAttack:false}); + // call transfer and expect to be migrated to a contract address + await reborner.transfer(); + await expect(await ousd.balanceOf(rebornAddress)).to.equal(ousdUnits("0")); + expect(await ousd.nonRebasingSupply()).to.equal(ousdUnits("0")); await reborner.mint(); - await reborner.bye(); + await expect(await ousd.balanceOf(rebornAddress)).to.equal(ousdUnits("1")); expect(await ousd.nonRebasingSupply()).to.equal(ousdUnits("1")); - await rebornAttack(true, 2); - await expect(reborner).to.have.a.balanceOf("0", ousd); - expect(await ousd.nonRebasingSupply()).to.equal(ousdUnits("0")); }); it("Should have correct balance even after recreating", async function () { - const { dai, matt, reborner, rebornAttack, ousd } = fixture; + const { dai, matt, reborner, deployAndCall, ousd } = fixture; // Mint one OUSD and self-destruct await dai.connect(matt).transfer(reborner.address, daiUnits("4")); - await reborner.mint(); + await deployAndCall({ shouldAttack:true, shouldDestruct:true }); await expect(reborner).to.have.a.balanceOf("1", ousd); - await reborner.bye(); // Recreate the contract at the same address but expect // to not have any change in balance (outside constructor) - await rebornAttack(false); + await deployAndCall({ shouldAttack:false }); await expect(reborner).to.have.a.balanceOf("1", ousd); await reborner.mint(); await expect(reborner).to.have.a.balanceOf("2", ousd); From 35ec1dc7ea157727182f249409506e580fccac4d Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Tue, 31 Dec 2024 10:37:50 +1100 Subject: [PATCH 229/273] Fix Solidity compile --- contracts/contracts/interfaces/ISFC.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/contracts/interfaces/ISFC.sol b/contracts/contracts/interfaces/ISFC.sol index f99378aab5..83894a2bae 100644 --- a/contracts/contracts/interfaces/ISFC.sol +++ b/contracts/contracts/interfaces/ISFC.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity ^0.8.27; +pragma solidity ^0.8.0; /** * @title Special Fee Contract for Sonic network From 4223599fe5de5b430b622205d018fb71353b71d6 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Tue, 31 Dec 2024 19:59:30 +1100 Subject: [PATCH 230/273] WIP Sonic Staking Strategy --- .../contracts/interfaces/{ => sonic}/ISFC.sol | 0 .../interfaces/sonic/IWrappedSonic.sol | 12 +- .../strategies/sonic/SonicStakingStrategy.sol | 180 +++++++++++++++ .../sonic/SonicValidatorDelegator.sol | 212 ++++++++++++++++++ 4 files changed, 398 insertions(+), 6 deletions(-) rename contracts/contracts/interfaces/{ => sonic}/ISFC.sol (100%) create mode 100644 contracts/contracts/strategies/sonic/SonicStakingStrategy.sol create mode 100644 contracts/contracts/strategies/sonic/SonicValidatorDelegator.sol diff --git a/contracts/contracts/interfaces/ISFC.sol b/contracts/contracts/interfaces/sonic/ISFC.sol similarity index 100% rename from contracts/contracts/interfaces/ISFC.sol rename to contracts/contracts/interfaces/sonic/ISFC.sol diff --git a/contracts/contracts/interfaces/sonic/IWrappedSonic.sol b/contracts/contracts/interfaces/sonic/IWrappedSonic.sol index 8ebf93f3c8..43ea4927cd 100644 --- a/contracts/contracts/interfaces/sonic/IWrappedSonic.sol +++ b/contracts/contracts/interfaces/sonic/IWrappedSonic.sol @@ -2,10 +2,10 @@ pragma solidity ^0.8.0; interface IWrappedSonic { - function allowance(address owner, address spender) - external - view - returns (uint256); + function allowance( + address owner, + address spender + ) external view returns (uint256); function approve(address spender, uint256 value) external returns (bool); @@ -13,9 +13,9 @@ interface IWrappedSonic { function decimals() external view returns (uint8); - function deposit() external; + function deposit() external payable; - function depositFor(address account) external returns (bool); + function depositFor(address account) external payable returns (bool); function totalSupply() external view returns (uint256); diff --git a/contracts/contracts/strategies/sonic/SonicStakingStrategy.sol b/contracts/contracts/strategies/sonic/SonicStakingStrategy.sol new file mode 100644 index 0000000000..f8aca56cf6 --- /dev/null +++ b/contracts/contracts/strategies/sonic/SonicStakingStrategy.sol @@ -0,0 +1,180 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import { IERC20, InitializableAbstractStrategy } from "../../utils/InitializableAbstractStrategy.sol"; +import { SonicValidatorDelegator } from "./SonicValidatorDelegator.sol"; + +/** + * @title Staking Strategy for Sonic's native S currency + * @author Origin Protocol Inc + */ +contract SonicStakingStrategy is SonicValidatorDelegator { + /// @dev This contract receives Wrapped S (wS) as the deposit asset, but unlike other strategies doesn't immediately + /// deposit it to an underlying platform. Rather a special privilege account stakes it to the validators. + /// For that reason calling wrappedSonic.balanceOf(this) in a deposit function can contain wS that has just been + /// deposited and also wS that has previously been deposited. To keep a correct count we need to keep track + /// of wS that has already been accounted for. + /// This value represents the amount of wS balance of this contract that has already been accounted for by the + /// deposit events. + uint256 public depositedWSAccountedFor; + + // For future use + uint256[49] private __gap; + + constructor( + BaseStrategyConfig memory _baseConfig, + address _wrappedSonic, + address _sfc + ) SonicValidatorDelegator(_baseConfig, _wrappedSonic, _sfc) {} + + function initialize() external virtual onlyGovernor initializer { + address[] memory rewardTokens = new address[](0); + address[] memory assets = new address[](1); + address[] memory pTokens = new address[](1); + + assets[0] = address(wrappedSonic); + pTokens[0] = address(platformAddress); + + InitializableAbstractStrategy._initialize( + rewardTokens, + assets, + pTokens + ); + } + + /// @notice Unlike other strategies, this does not deposit assets into the underlying platform. + /// It just checks the asset is Wrapped Sonic (wS) and emits the Deposit event. + /// To deposit wS into validators `delegate` must be used. + /// @param _asset Address of asset to deposit. Has to be Wrapped Sonic (wS). + /// @param _amount Amount of assets that were transferred to the strategy by the vault. + function deposit( + address _asset, + uint256 _amount + ) external override onlyVault nonReentrant { + require(_asset == wrappedSonic, "Unsupported asset"); + depositedWSAccountedFor += _amount; + _deposit(_asset, _amount); + } + + /** + * @notice Deposit Wrapped Sonic (wS) to this strategy so it can later be delegated to a validator. + * @param _asset Address of Wrapped Sonic (wS) token + * @param _amount Amount of Wrapped Sonic (wS) to deposit + */ + function _deposit(address _asset, uint256 _amount) internal virtual { + require(_amount > 0, "Must deposit something"); + + emit Deposit(_asset, address(0), _amount); + } + + /** + * @notice Deposit the entire balance of wrapped S in this strategy contract + */ + + /// @notice Unlike other strategies, this does not deposit assets into the underlying platform. + /// It just emits the Deposit event. + /// To deposit WETH into validators `registerSsvValidator` and `stakeEth` must be used. + /// Will NOT revert if the strategy is paused from an accounting failure. + function depositAll() external virtual override onlyVault nonReentrant { + uint256 wSBalance = IERC20(wrappedSonic).balanceOf(address(this)); + uint256 newWS = wSBalance - depositedWSAccountedFor; + + if (newWS > 0) { + depositedWSAccountedFor = wSBalance; + + _deposit(wrappedSonic, newWS); + } + } + + /// @notice Withdraw Wrapped Sonic (wS) from this strategy contract. + /// Used only if some wS is lingering on the contract. + /// That can happen when: + /// - after mints if the strategy is the default + /// - time between depositToStrategy and delegate + /// - someone sent wS directly to this contract + /// @param _recipient Address to receive withdrawn assets + /// @param _asset Address of the Wrapped Sonic (wS) token + /// @param _amount Amount of Wrapped Sonic (wS) to withdraw + function withdraw( + address _recipient, + address _asset, + uint256 _amount + ) external override onlyVault nonReentrant { + require(_asset == wrappedSonic, "Unsupported asset"); + _withdraw(_recipient, _asset, _amount); + } + + function _withdraw( + address _recipient, + address _asset, + uint256 _amount + ) internal { + require(_amount > 0, "Must withdraw something"); + require(_recipient != address(0), "Must specify recipient"); + + emit Withdrawal(wrappedSonic, address(0), _amount); + + IERC20(_asset).transfer(_recipient, _amount); + emit Withdrawal(_asset, address(0), _amount); + } + + /// @notice transfer all Wrapped Sonic (wS) deposits back to the vault. + /// This does not withdraw from delegated validators. That has to be done separately with `undelegate`. + /// Any native S in this strategy will not be withdrawn. + function withdrawAll() external override onlyVaultOrGovernor nonReentrant { + uint256 wSBalance = IERC20(wrappedSonic).balanceOf(address(this)); + if (wSBalance > 0) { + _withdraw(vaultAddress, wrappedSonic, wSBalance); + } + } + + /// @notice Returns the total value of Sonic (S) that is delegated validators. + /// Wrapped Sonic (wS) deposits that are still to be delegated and any undelegated amounts + /// still pending a withdrawal. + /// @param _asset Address of Wrapped Sonic (wS) token + /// @return balance Total value managed by the strategy + function checkBalance( + address _asset + ) external view virtual override returns (uint256 balance) { + require(_asset == wrappedSonic, "Unsupported asset"); + + balance = + totalDelegated + + pendingWithdrawals + + // add the Wrapped Sonic (wS) in the strategy from deposits that are still to be delegated + IERC20(wrappedSonic).balanceOf(address(this)); + } + + /** + * @dev Returns bool indicating whether asset is supported by strategy + * @param _asset Address of the asset + */ + function supportsAsset( + address _asset + ) public view virtual override returns (bool) { + return _asset == wrappedSonic; + } + + /** + * @notice is not supported for this strategy as the + * Wrapped Sonic (wS) token is set at deploy time. + */ + function setPTokenAddress( + address, + address + ) external view override onlyGovernor { + revert("unsupported function"); + } + + /** + * @notice is not supported for this strategy as the + * Wrapped Sonic (wS) token is set at deploy time. + */ + function removePToken(uint256) external view override onlyGovernor { + revert("unsupported function"); + } + + function _abstractSetPToken(address, address) internal virtual override {} + + function safeApproveAllTokens() external override onlyGovernor {} +} diff --git a/contracts/contracts/strategies/sonic/SonicValidatorDelegator.sol b/contracts/contracts/strategies/sonic/SonicValidatorDelegator.sol new file mode 100644 index 0000000000..ad61a9b994 --- /dev/null +++ b/contracts/contracts/strategies/sonic/SonicValidatorDelegator.sol @@ -0,0 +1,212 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import { IERC20, InitializableAbstractStrategy } from "../../utils/InitializableAbstractStrategy.sol"; +import { IVault } from "../../interfaces/IVault.sol"; +import { ISFC } from "../../interfaces/sonic/ISFC.sol"; +import { IWrappedSonic } from "../../interfaces/sonic/IWrappedSonic.sol"; + +/** + * @title Manages delegation to Sonic validators + * @notice This contract implements all the required functionality to delegate to, undelegate from and withdraw from validators. + * @author Origin Protocol Inc + */ +abstract contract SonicValidatorDelegator is InitializableAbstractStrategy { + /// @notice Address of Sonic's wrapped S token + address public immutable wrappedSonic; + /// @notice Address of Sonic's Special Fee Contract (SFC) + address public immutable sfc; + + uint256 public totalDelegated; + uint256 public pendingWithdrawals; + /** + * @notice a unique ID for each withdrawal request + */ + uint256 public nextWithdrawId = 1; + + struct WithdrawRequest { + uint256 validatorId; + uint256 undelegatedAmount; + } + /// @notice Mapping of withdrawIds to validatorIds and undelegatedAmounts + mapping(uint256 => WithdrawRequest) public withdrawals; + + /// @notice Address of the registrator - allowed to register, exit and remove validators + address public validatorRegistrator; + + // For future use + uint256[43] private __gap; + + event Delegated(uint256 indexed validatorId, uint256 delegatedAmount); + event Undelegated( + uint256 withdrawId, + uint256 validatorId, + uint256 undelegatedAmount + ); + event Withdrawn( + uint256 withdrawId, + uint256 validatorId, + uint256 undelegatedAmount, + uint256 withdrawnAmount + ); + event RegistratorChanged(address indexed newAddress); + + /// @dev Throws if called by any account other than the Registrator + modifier onlyRegistrator() { + require( + msg.sender == validatorRegistrator, + "Caller is not the Registrator" + ); + _; + } + + /// @dev Throws if called by any account other than the Strategist + modifier onlyStrategist() { + require( + msg.sender == IVault(vaultAddress).strategistAddr(), + "Caller is not the Strategist" + ); + _; + } + + constructor( + BaseStrategyConfig memory _baseConfig, + address _wrappedSonic, + address _sfc + ) InitializableAbstractStrategy(_baseConfig) { + wrappedSonic = _wrappedSonic; + sfc = _sfc; + } + + /** + * @notice Delegate from this strategy to a specific Sonic validator. + * Only the registrator can call this function. + * @param validatorId the ID of the validator to delegate to + * @param amount the amount of Sonic (S) to delegate. + */ + function delegate( + uint256 validatorId, + uint256 amount + ) external onlyRegistrator nonReentrant { + require(amount > 0, "Must delegate something"); + + // unwrap Wrapped Sonic (wS) to native Sonic (S) + IWrappedSonic(wrappedSonic).withdraw(amount); + + totalDelegated += amount; + + ISFC(sfc).delegate{ value: amount }(validatorId); + + emit Delegated(validatorId, amount); + } + + function undelegate( + uint256 validatorId, + uint256 undelegateAmount + ) external onlyRegistrator returns (uint256 withdrawId) { + require(undelegateAmount > 0, "Must undelegate something"); + + uint256 amountDelegated = ISFC(sfc).getStake( + address(this), + validatorId + ); + require(undelegateAmount <= amountDelegated, "Insufficient delegation"); + + withdrawId = nextWithdrawId++; + + withdrawals[withdrawId] = WithdrawRequest( + validatorId, + undelegateAmount + ); + totalDelegated -= undelegateAmount; + pendingWithdrawals += undelegateAmount; + + ISFC(sfc).undelegate(validatorId, withdrawId, undelegateAmount); + + emit Undelegated(withdrawId, validatorId, undelegateAmount); + } + + function withdraw( + uint256 withdrawId + ) external onlyRegistrator returns (uint256 withdrawnAmount) { + // Load the withdrawal from storage into memory + WithdrawRequest memory withdrawal = withdrawals[withdrawId]; + + require(withdrawal.validatorId > 0, "Invalid withdrawId"); + require(withdrawal.undelegatedAmount > 0, "Already withdrawn"); + + uint256 sBalanceBefore = address(this).balance; + + ISFC(sfc).withdraw(withdrawal.validatorId, withdrawId); + + withdrawnAmount = address(this).balance - sBalanceBefore; + pendingWithdrawals -= withdrawal.undelegatedAmount; + withdrawals[withdrawId].undelegatedAmount = 0; + + // Wrap Sonic (S) to Wrapped Sonic (wS) + IWrappedSonic(wrappedSonic).deposit(); + + // Transfer the Wrapped Sonic (wS) to the Vault + IERC20(wrappedSonic).transfer(vaultAddress, withdrawnAmount); + + emit Withdrawn( + withdrawId, + withdrawal.validatorId, + withdrawal.undelegatedAmount, + withdrawnAmount + ); + } + + /// @notice Set the address of the registrator which can delegate, undelegate and withdraw + function setRegistrator(address _address) external onlyGovernor { + validatorRegistrator = _address; + emit RegistratorChanged(_address); + } + + /// @dev Convert accumulated ETH to WETH and send to the Harvester. + /// Will revert if the strategy is paused for accounting. + function collectRewards(uint256[] calldata validatorIds) external { + uint256 balanceBefore = address(this).balance; + + for (uint256 i = 0; i < validatorIds.length; ++i) { + uint256 rewards = ISFC(sfc).pendingRewards( + address(this), + validatorIds[i] + ); + + if (rewards > 0) { + ISFC(sfc).claimRewards(validatorIds[i]); + } + } + + uint256 totalRewards = address(this).balance - balanceBefore; + + require( + address(this).balance >= totalRewards, + "Insufficient S balance" + ); + + if (totalRewards > 0) { + // Convert native S to Wrapped Sonic (wS) + IWrappedSonic(wrappedSonic).deposit{ value: totalRewards }(); + + IERC20(wrappedSonic).transfer(harvesterAddress, totalRewards); + + emit RewardTokenCollected( + harvesterAddress, + wrappedSonic, + totalRewards + ); + } + } + + /** + * @notice To receive native S from SFC and Wrapped Sonic (wS) + */ + receive() external payable { + require( + msg.sender == sfc || msg.sender == wrappedSonic, + "S not from allowed contracts" + ); + } +} From 0623f9bd36271ca5e708f7fee0d2374fadfac305 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Thu, 2 Jan 2025 20:34:53 +1100 Subject: [PATCH 231/273] Add supported validators to Sonic Staking Strategy --- .../strategies/sonic/SonicStakingStrategy.sol | 15 ---- .../sonic/SonicValidatorDelegator.sol | 68 ++++++++++++++++--- 2 files changed, 60 insertions(+), 23 deletions(-) diff --git a/contracts/contracts/strategies/sonic/SonicStakingStrategy.sol b/contracts/contracts/strategies/sonic/SonicStakingStrategy.sol index b190a0b44f..b70c4885a9 100644 --- a/contracts/contracts/strategies/sonic/SonicStakingStrategy.sol +++ b/contracts/contracts/strategies/sonic/SonicStakingStrategy.sol @@ -27,21 +27,6 @@ contract SonicStakingStrategy is SonicValidatorDelegator { address _sfc ) SonicValidatorDelegator(_baseConfig, _wrappedSonic, _sfc) {} - function initialize() external virtual onlyGovernor initializer { - address[] memory rewardTokens = new address[](0); - address[] memory assets = new address[](1); - address[] memory pTokens = new address[](1); - - assets[0] = address(wrappedSonic); - pTokens[0] = address(platformAddress); - - InitializableAbstractStrategy._initialize( - rewardTokens, - assets, - pTokens - ); - } - /// @notice Unlike other strategies, this does not deposit assets into the underlying platform. /// It just checks the asset is Wrapped Sonic (wS) and emits the Deposit event. /// To deposit wS into validators `delegate` must be used. diff --git a/contracts/contracts/strategies/sonic/SonicValidatorDelegator.sol b/contracts/contracts/strategies/sonic/SonicValidatorDelegator.sol index 16053b1332..d3a597ba3d 100644 --- a/contracts/contracts/strategies/sonic/SonicValidatorDelegator.sol +++ b/contracts/contracts/strategies/sonic/SonicValidatorDelegator.sol @@ -22,7 +22,10 @@ abstract contract SonicValidatorDelegator is InitializableAbstractStrategy { /** * @notice a unique ID for each withdrawal request */ - uint256 public nextWithdrawId = 1; + uint256 public nextWithdrawId; + + /// @notice Mapping of supported validatorIds + mapping(uint256 => bool) public supportedValidators; struct WithdrawRequest { uint256 validatorId; @@ -35,7 +38,7 @@ abstract contract SonicValidatorDelegator is InitializableAbstractStrategy { address public validatorRegistrator; // For future use - uint256[43] private __gap; + uint256[44] private __gap; event Delegated(uint256 indexed validatorId, uint256 delegatedAmount); event Undelegated( @@ -50,6 +53,8 @@ abstract contract SonicValidatorDelegator is InitializableAbstractStrategy { uint256 withdrawnAmount ); event RegistratorChanged(address indexed newAddress); + event SupportedValidator(uint256 indexed validatorId); + event UnsupportedValidator(uint256 indexed validatorId); /// @dev Throws if called by any account other than the Registrator modifier onlyRegistrator() { @@ -78,6 +83,21 @@ abstract contract SonicValidatorDelegator is InitializableAbstractStrategy { sfc = _sfc; } + function initialize() external virtual onlyGovernor initializer { + address[] memory rewardTokens = new address[](0); + address[] memory assets = new address[](1); + address[] memory pTokens = new address[](1); + + assets[0] = address(wrappedSonic); + pTokens[0] = address(platformAddress); + + InitializableAbstractStrategy._initialize( + rewardTokens, + assets, + pTokens + ); + } + /** * @notice Delegate from this strategy to a specific Sonic validator. * Only the registrator can call this function. @@ -89,6 +109,7 @@ abstract contract SonicValidatorDelegator is InitializableAbstractStrategy { onlyRegistrator nonReentrant { + require(supportedValidators[validatorId], "Validator not supported"); require(amount > 0, "Must delegate something"); // unwrap Wrapped Sonic (wS) to native Sonic (S) @@ -106,6 +127,7 @@ abstract contract SonicValidatorDelegator is InitializableAbstractStrategy { onlyRegistrator returns (uint256 withdrawId) { + // Can still undelegate even if the validator is no longer supported require(undelegateAmount > 0, "Must undelegate something"); uint256 amountDelegated = ISFC(sfc).getStake( @@ -133,6 +155,7 @@ abstract contract SonicValidatorDelegator is InitializableAbstractStrategy { onlyRegistrator returns (uint256 withdrawnAmount) { + // Can still withdraw even if the validator is no longer supported // Load the withdrawal from storage into memory WithdrawRequest memory withdrawal = withdrawals[withdrawId]; @@ -161,15 +184,10 @@ abstract contract SonicValidatorDelegator is InitializableAbstractStrategy { ); } - /// @notice Set the address of the registrator which can delegate, undelegate and withdraw - function setRegistrator(address _address) external onlyGovernor { - validatorRegistrator = _address; - emit RegistratorChanged(_address); - } - /// @dev Convert accumulated ETH to WETH and send to the Harvester. /// Will revert if the strategy is paused for accounting. function collectRewards(uint256[] calldata validatorIds) external { + // Can still collect rewards even if the validator is no longer supported uint256 balanceBefore = address(this).balance; for (uint256 i = 0; i < validatorIds.length; ++i) { @@ -213,4 +231,38 @@ abstract contract SonicValidatorDelegator is InitializableAbstractStrategy { "S not from allowed contracts" ); } + + /*************************************** + Admin functions + ****************************************/ + + /// @notice Set the address of the Registrator which can delegate, undelegate and withdraw + function setRegistrator(address _address) external onlyGovernor { + validatorRegistrator = _address; + emit RegistratorChanged(_address); + } + + /// @notice Allows a validator to be delegated to by the Registrator + function supportValidator(uint256 validatorId) external onlyGovernor { + require( + supportedValidators[validatorId] == false, + "Validator already supported" + ); + supportedValidators[validatorId] = true; + + emit SupportedValidator(validatorId); + } + + /// @notice Removes a validator from the supported list. + /// Unsupported validators can still be undelegated from, withdrawn from and rewards collected. + function unsupportValidator(uint256 validatorId) external onlyGovernor { + require( + supportedValidators[validatorId] == true, + "Validator not supported" + ); + + supportedValidators[validatorId] = false; + + emit UnsupportedValidator(validatorId); + } } From e6d910232137f6d74f01aea8254e261e44bb25f3 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Thu, 2 Jan 2025 20:35:15 +1100 Subject: [PATCH 232/273] Added Sonic Staking Strategy to deploy script --- contracts/deploy/sonic/001_origin_sonic.js | 44 +++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/contracts/deploy/sonic/001_origin_sonic.js b/contracts/deploy/sonic/001_origin_sonic.js index ef7eb6bd87..c675f882cc 100644 --- a/contracts/deploy/sonic/001_origin_sonic.js +++ b/contracts/deploy/sonic/001_origin_sonic.js @@ -1,5 +1,8 @@ const { deployOnSonic } = require("../../utils/deploy-l2"); -const { deployWithConfirmation } = require("../../utils/deploy"); +const { + deployWithConfirmation, + withConfirmation, +} = require("../../utils/deploy"); const addresses = require("../../utils/addresses"); module.exports = deployOnSonic( @@ -123,5 +126,44 @@ module.exports = deployOnSonic( console.log("Added vault support of Wrapped S"); await cOSonicVault.connect(sGovernor).unpauseCapital(); console.log("Unpaused capital"); + + // Staking Strategy + await deployWithConfirmation("SonicStakingStrategyProxy"); + console.log("Deployed Sonic Staking Strategy proxy"); + + const cSonicStakingStrategyProxy = await ethers.getContract( + "SonicStakingStrategyProxy" + ); + const dSonicStakingStrategy = await deployWithConfirmation( + "SonicStakingStrategy", + [ + [addresses.sonic.SFC, cOSonicVault.address], // platformAddress, VaultAddress + addresses.sonic.wS, + addresses.sonic.SFC, + ] + ); + console.log( + `Deployed Sonic Staking Strategy to ${dSonicStakingStrategy.address}` + ); + const cSonicStakingStrategy = await ethers.getContractAt( + "SonicStakingStrategy", + cSonicStakingStrategyProxy.address + ); + + // Init the Sonic Staking Strategy + const initSonicStakingStrategy = + cSonicStakingStrategy.interface.encodeFunctionData("initialize()", []); + // prettier-ignore + await withConfirmation( + cSonicStakingStrategyProxy + .connect(sDeployer)["initialize(address,address,bytes)"]( + dSonicStakingStrategy.address, + deployerAddr, + initSonicStakingStrategy + ) + ); + console.log("Initialized SonicStakingStrategy proxy and implementation"); + + // TODO transfer governor to ? } ); From 9c9f499a9bb8ae3411bf263705bf3834be205f7b Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Tue, 7 Jan 2025 19:13:28 +1100 Subject: [PATCH 233/273] checkBalance now gets stake and pending rewards --- contracts/contracts/interfaces/sonic/ISFC.sol | 265 +++++++++++++++++- .../strategies/sonic/SonicStakingStrategy.sol | 21 -- .../sonic/SonicValidatorDelegator.sol | 115 +++++--- 3 files changed, 325 insertions(+), 76 deletions(-) diff --git a/contracts/contracts/interfaces/sonic/ISFC.sol b/contracts/contracts/interfaces/sonic/ISFC.sol index 2ff35fce07..182cbfeda1 100644 --- a/contracts/contracts/interfaces/sonic/ISFC.sol +++ b/contracts/contracts/interfaces/sonic/ISFC.sol @@ -7,35 +7,276 @@ pragma solidity ^0.8.0; * @custom:security-contact security@fantom.foundation */ interface ISFC { - error StakeIsFullySlashed(); + event CreatedValidator( + uint256 indexed validatorID, + address indexed auth, + uint256 createdEpoch, + uint256 createdTime + ); + event Delegated( + address indexed delegator, + uint256 indexed validatorID, + uint256 amount + ); + event Undelegated( + address indexed delegator, + uint256 indexed validatorID, + uint256 indexed wrID, + uint256 amount + ); + event Withdrawn( + address indexed delegator, + uint256 indexed validatorID, + uint256 indexed wrID, + uint256 amount, + uint256 penalty + ); + event ClaimedRewards( + address indexed delegator, + uint256 indexed validatorID, + uint256 rewards + ); + event RestakedRewards( + address indexed delegator, + uint256 indexed validatorID, + uint256 rewards + ); + event BurntFTM(uint256 amount); + event UpdatedSlashingRefundRatio( + uint256 indexed validatorID, + uint256 refundRatio + ); + event RefundedSlashedLegacyDelegation( + address indexed delegator, + uint256 indexed validatorID, + uint256 amount + ); + + event DeactivatedValidator( + uint256 indexed validatorID, + uint256 deactivatedEpoch, + uint256 deactivatedTime + ); + event ChangedValidatorStatus(uint256 indexed validatorID, uint256 status); + event AnnouncedRedirection(address indexed from, address indexed to); + + function currentSealedEpoch() external view returns (uint256); + + function getEpochSnapshot(uint256 epoch) + external + view + returns ( + uint256 endTime, + uint256 endBlock, + uint256 epochFee, + uint256 baseRewardPerSecond, + uint256 totalStake, + uint256 totalSupply + ); + + function getStake(address delegator, uint256 validatorID) + external + view + returns (uint256); + + function getValidator(uint256 validatorID) + external + view + returns ( + uint256 status, + uint256 receivedStake, + address auth, + uint256 createdEpoch, + uint256 createdTime, + uint256 deactivatedTime, + uint256 deactivatedEpoch + ); + + function getValidatorID(address auth) external view returns (uint256); + + function getValidatorPubkey(uint256 validatorID) + external + view + returns (bytes memory); + + function pubkeyAddressvalidatorID(address pubkeyAddress) + external + view + returns (uint256); + + function getWithdrawalRequest( + address delegator, + uint256 validatorID, + uint256 wrID + ) + external + view + returns ( + uint256 epoch, + uint256 time, + uint256 amount + ); + + function isOwner() external view returns (bool); + + function lastValidatorID() external view returns (uint256); + + function minGasPrice() external view returns (uint256); + + function owner() external view returns (address); + + function renounceOwnership() external; + + function slashingRefundRatio(uint256 validatorID) + external + view + returns (uint256); + + function stashedRewardsUntilEpoch(address delegator, uint256 validatorID) + external + view + returns (uint256); + + function totalActiveStake() external view returns (uint256); + + function totalStake() external view returns (uint256); + + function totalSupply() external view returns (uint256); + + function transferOwnership(address newOwner) external; + + function treasuryAddress() external view returns (address); + + function version() external pure returns (bytes3); function currentEpoch() external view returns (uint256); - function getStake(address, uint256) external view returns (uint256); + function updateConstsAddress(address v) external; - function delegate(uint256 toValidatorID) external payable; + function constsAddress() external view returns (address); - function undelegate( - uint256 toValidatorID, - uint256 wrID, - uint256 amount - ) external; + function getEpochValidatorIDs(uint256 epoch) + external + view + returns (uint256[] memory); - function withdraw(uint256 toValidatorID, uint256 wrID) external; + function getEpochReceivedStake(uint256 epoch, uint256 validatorID) + external + view + returns (uint256); + + function getEpochAccumulatedRewardPerToken( + uint256 epoch, + uint256 validatorID + ) external view returns (uint256); + + function getEpochAccumulatedUptime(uint256 epoch, uint256 validatorID) + external + view + returns (uint256); + + function getEpochAverageUptime(uint256 epoch, uint256 validatorID) + external + view + returns (uint32); + + function getEpochAccumulatedOriginatedTxsFee( + uint256 epoch, + uint256 validatorID + ) external view returns (uint256); + + function getEpochOfflineTime(uint256 epoch, uint256 validatorID) + external + view + returns (uint256); - function pendingRewards(address delegator, uint256 toValidatorID) + function getEpochOfflineBlocks(uint256 epoch, uint256 validatorID) external view returns (uint256); - function claimRewards(uint256 toValidatorID) external; + function getEpochEndBlock(uint256 epoch) external view returns (uint256); + + function rewardsStash(address delegator, uint256 validatorID) + external + view + returns (uint256); + + function createValidator(bytes calldata pubkey) external payable; function getSelfStake(uint256 validatorID) external view returns (uint256); + function delegate(uint256 validatorID) external payable; + + function undelegate( + uint256 validatorID, + uint256 wrID, + uint256 amount + ) external; + function isSlashed(uint256 validatorID) external view returns (bool); - function slashingRefundRatio(uint256 validatorID) + function withdraw(uint256 validatorID, uint256 wrID) external; + + function deactivateValidator(uint256 validatorID, uint256 status) external; + + function pendingRewards(address delegator, uint256 validatorID) external view returns (uint256); + + function stashRewards(address delegator, uint256 validatorID) external; + + function claimRewards(uint256 validatorID) external; + + function restakeRewards(uint256 validatorID) external; + + function updateSlashingRefundRatio(uint256 validatorID, uint256 refundRatio) + external; + + function updateTreasuryAddress(address v) external; + + function burnFTM(uint256 amount) external; + + function sealEpoch( + uint256[] calldata offlineTime, + uint256[] calldata offlineBlocks, + uint256[] calldata uptimes, + uint256[] calldata originatedTxsFee + ) external; + + function sealEpochValidators(uint256[] calldata nextValidatorIDs) external; + + function initialize( + uint256 sealedEpoch, + uint256 _totalSupply, + address nodeDriver, + address consts, + address _owner + ) external; + + function setGenesisValidator( + address auth, + uint256 validatorID, + bytes calldata pubkey, + uint256 createdTime + ) external; + + function setGenesisDelegation( + address delegator, + uint256 validatorID, + uint256 stake + ) external; + + function updateStakeSubscriberAddress(address v) external; + + function stakeSubscriberAddress() external view returns (address); + + function setRedirectionAuthorizer(address v) external; + + function announceRedirection(address to) external; + + function initiateRedirection(address from, address to) external; + + function redirect(address to) external; } diff --git a/contracts/contracts/strategies/sonic/SonicStakingStrategy.sol b/contracts/contracts/strategies/sonic/SonicStakingStrategy.sol index b70c4885a9..1252867e22 100644 --- a/contracts/contracts/strategies/sonic/SonicStakingStrategy.sol +++ b/contracts/contracts/strategies/sonic/SonicStakingStrategy.sol @@ -115,27 +115,6 @@ contract SonicStakingStrategy is SonicValidatorDelegator { } } - /// @notice Returns the total value of Sonic (S) that is delegated validators. - /// Wrapped Sonic (wS) deposits that are still to be delegated and any undelegated amounts - /// still pending a withdrawal. - /// @param _asset Address of Wrapped Sonic (wS) token - /// @return balance Total value managed by the strategy - function checkBalance(address _asset) - external - view - virtual - override - returns (uint256 balance) - { - require(_asset == wrappedSonic, "Unsupported asset"); - - balance = - totalDelegated + - pendingWithdrawals + - // add the Wrapped Sonic (wS) in the strategy from deposits that are still to be delegated - IERC20(wrappedSonic).balanceOf(address(this)); - } - /** * @dev Returns bool indicating whether asset is supported by strategy * @param _asset Address of the asset diff --git a/contracts/contracts/strategies/sonic/SonicValidatorDelegator.sol b/contracts/contracts/strategies/sonic/SonicValidatorDelegator.sol index d3a597ba3d..da0de1882a 100644 --- a/contracts/contracts/strategies/sonic/SonicValidatorDelegator.sol +++ b/contracts/contracts/strategies/sonic/SonicValidatorDelegator.sol @@ -17,15 +17,13 @@ abstract contract SonicValidatorDelegator is InitializableAbstractStrategy { /// @notice Address of Sonic's Special Fee Contract (SFC) address public immutable sfc; - uint256 public totalDelegated; - uint256 public pendingWithdrawals; - /** - * @notice a unique ID for each withdrawal request - */ + /// @notice a unique ID for each withdrawal request uint256 public nextWithdrawId; + /// @notice Sonic (S) that is pending withdrawal after undelegating + uint256 public pendingWithdrawals; - /// @notice Mapping of supported validatorIds - mapping(uint256 => bool) public supportedValidators; + /// @notice List of supported validator IDs that can be delegated to + uint256[] public supportedValidators; struct WithdrawRequest { uint256 validatorId; @@ -38,7 +36,7 @@ abstract contract SonicValidatorDelegator is InitializableAbstractStrategy { address public validatorRegistrator; // For future use - uint256[44] private __gap; + uint256[45] private __gap; event Delegated(uint256 indexed validatorId, uint256 delegatedAmount); event Undelegated( @@ -98,6 +96,35 @@ abstract contract SonicValidatorDelegator is InitializableAbstractStrategy { ); } + /// @notice Returns the total value of Sonic (S) that is delegated validators. + /// Wrapped Sonic (wS) deposits that are still to be delegated and any undelegated amounts + /// still pending a withdrawal. + /// @param _asset Address of Wrapped Sonic (wS) token + /// @return balance Total value managed by the strategy + function checkBalance(address _asset) + external + view + virtual + override + returns (uint256 balance) + { + require(_asset == wrappedSonic, "Unsupported asset"); + + // add the Wrapped Sonic (wS) in the strategy from deposits that are still to be delegated + // and any undelegated amounts still pending a withdrawal + balance = + IERC20(wrappedSonic).balanceOf(address(this)) + + pendingWithdrawals; + + // For each supported validator, get the staked amount and pending rewards + for (uint256 i = 1; i <= supportedValidators.length; i++) { + // Get the staked amount and any pending rewards + balance += + ISFC(sfc).getStake(address(this), supportedValidators[i]) + + ISFC(sfc).pendingRewards(address(this), supportedValidators[i]); + } + } + /** * @notice Delegate from this strategy to a specific Sonic validator. * Only the registrator can call this function. @@ -109,14 +136,12 @@ abstract contract SonicValidatorDelegator is InitializableAbstractStrategy { onlyRegistrator nonReentrant { - require(supportedValidators[validatorId], "Validator not supported"); + require(_isSupportedValidator(validatorId), "Validator not supported"); require(amount > 0, "Must delegate something"); // unwrap Wrapped Sonic (wS) to native Sonic (S) IWrappedSonic(wrappedSonic).withdraw(amount); - totalDelegated += amount; - ISFC(sfc).delegate{ value: amount }(validatorId); emit Delegated(validatorId, amount); @@ -142,7 +167,6 @@ abstract contract SonicValidatorDelegator is InitializableAbstractStrategy { validatorId, undelegateAmount ); - totalDelegated -= undelegateAmount; pendingWithdrawals += undelegateAmount; ISFC(sfc).undelegate(validatorId, withdrawId, undelegateAmount); @@ -184,12 +208,9 @@ abstract contract SonicValidatorDelegator is InitializableAbstractStrategy { ); } - /// @dev Convert accumulated ETH to WETH and send to the Harvester. - /// Will revert if the strategy is paused for accounting. - function collectRewards(uint256[] calldata validatorIds) external { - // Can still collect rewards even if the validator is no longer supported - uint256 balanceBefore = address(this).balance; - + /// @dev restake any pending validator rewards for all supported validators + function restakeRewards(uint256[] calldata validatorIds) external { + uint256 totalRewards = 0; for (uint256 i = 0; i < validatorIds.length; ++i) { uint256 rewards = ISFC(sfc).pendingRewards( address(this), @@ -197,29 +218,14 @@ abstract contract SonicValidatorDelegator is InitializableAbstractStrategy { ); if (rewards > 0) { - ISFC(sfc).claimRewards(validatorIds[i]); + totalRewards += rewards; + ISFC(sfc).restakeRewards(validatorIds[i]); } } - uint256 totalRewards = address(this).balance - balanceBefore; - - require( - address(this).balance >= totalRewards, - "Insufficient S balance" - ); - - if (totalRewards > 0) { - // Convert native S to Wrapped Sonic (wS) - IWrappedSonic(wrappedSonic).deposit{ value: totalRewards }(); - - IERC20(wrappedSonic).transfer(harvesterAddress, totalRewards); - - emit RewardTokenCollected( - harvesterAddress, - wrappedSonic, - totalRewards - ); - } + // TODO use Deposit event or something else? + // The SFC contract will emit Delegated and RestakedRewards events + emit Deposit(wrappedSonic, address(0), totalRewards); } /** @@ -245,10 +251,11 @@ abstract contract SonicValidatorDelegator is InitializableAbstractStrategy { /// @notice Allows a validator to be delegated to by the Registrator function supportValidator(uint256 validatorId) external onlyGovernor { require( - supportedValidators[validatorId] == false, + !_isSupportedValidator(validatorId), "Validator already supported" ); - supportedValidators[validatorId] = true; + + supportedValidators.push(validatorId); emit SupportedValidator(validatorId); } @@ -256,13 +263,35 @@ abstract contract SonicValidatorDelegator is InitializableAbstractStrategy { /// @notice Removes a validator from the supported list. /// Unsupported validators can still be undelegated from, withdrawn from and rewards collected. function unsupportValidator(uint256 validatorId) external onlyGovernor { + require(_isSupportedValidator(validatorId), "Validator not supported"); require( - supportedValidators[validatorId] == true, - "Validator not supported" + ISFC(sfc).getStake(address(this), validatorId) == 0, + "Validator still has stake" ); - supportedValidators[validatorId] = false; + for (uint256 i = 0; i < supportedValidators.length; ++i) { + if (supportedValidators[i] == validatorId) { + supportedValidators[i] = supportedValidators[ + supportedValidators.length - 1 + ]; + supportedValidators.pop(); + break; + } + } emit UnsupportedValidator(validatorId); } + + function _isSupportedValidator(uint256 validatorId) + internal + view + returns (bool) + { + for (uint256 i = 0; i < supportedValidators.length; ++i) { + if (supportedValidators[i] == validatorId) { + return true; + } + } + return false; + } } From 44da67a090ab5b736f21411f1437df138f89dd3f Mon Sep 17 00:00:00 2001 From: Domen Grabec Date: Tue, 7 Jan 2025 18:19:57 +0100 Subject: [PATCH 234/273] add basic fork tests for Sonic staking --- .../strategies/sonic/SonicStakingStrategy.sol | 4 + .../sonic/SonicValidatorDelegator.sol | 21 ++- contracts/deploy/sonic/001_origin_sonic.js | 14 ++ contracts/hardhat.config.js | 3 +- contracts/test/_fixture-sonic.js | 69 ++++---- .../test/behaviour/sfcStakingStrategy.js | 166 ++++++++++++++++++ .../sonicStaking.sonic.fork-test.js | 25 +++ contracts/utils/addresses.js | 2 + contracts/utils/deploy-l2.js | 4 +- 9 files changed, 265 insertions(+), 43 deletions(-) create mode 100644 contracts/test/behaviour/sfcStakingStrategy.js create mode 100644 contracts/test/strategies/sonicStaking.sonic.fork-test.js diff --git a/contracts/contracts/strategies/sonic/SonicStakingStrategy.sol b/contracts/contracts/strategies/sonic/SonicStakingStrategy.sol index 1252867e22..1c995c0c44 100644 --- a/contracts/contracts/strategies/sonic/SonicStakingStrategy.sol +++ b/contracts/contracts/strategies/sonic/SonicStakingStrategy.sol @@ -142,6 +142,10 @@ contract SonicStakingStrategy is SonicValidatorDelegator { revert("unsupported function"); } + function collectRewardTokens() external override nonReentrant { + revert("unsupported function"); + } + /** * @notice is not supported for this strategy as the * Wrapped Sonic (wS) token is set at deploy time. diff --git a/contracts/contracts/strategies/sonic/SonicValidatorDelegator.sol b/contracts/contracts/strategies/sonic/SonicValidatorDelegator.sol index da0de1882a..70be9bd48e 100644 --- a/contracts/contracts/strategies/sonic/SonicValidatorDelegator.sol +++ b/contracts/contracts/strategies/sonic/SonicValidatorDelegator.sol @@ -6,6 +6,8 @@ import { IVault } from "../../interfaces/IVault.sol"; import { ISFC } from "../../interfaces/sonic/ISFC.sol"; import { IWrappedSonic } from "../../interfaces/sonic/IWrappedSonic.sol"; +import "hardhat/console.sol"; + /** * @title Manages delegation to Sonic validators * @notice This contract implements all the required functionality to delegate to, undelegate from and withdraw from validators. @@ -117,10 +119,10 @@ abstract contract SonicValidatorDelegator is InitializableAbstractStrategy { pendingWithdrawals; // For each supported validator, get the staked amount and pending rewards - for (uint256 i = 1; i <= supportedValidators.length; i++) { + for (uint256 i = 0; i < supportedValidators.length; i++) { // Get the staked amount and any pending rewards balance += - ISFC(sfc).getStake(address(this), supportedValidators[i]) + + ISFC(sfc).getStake(address(this), supportedValidators[i]); ISFC(sfc).pendingRewards(address(this), supportedValidators[i]); } } @@ -136,7 +138,7 @@ abstract contract SonicValidatorDelegator is InitializableAbstractStrategy { onlyRegistrator nonReentrant { - require(_isSupportedValidator(validatorId), "Validator not supported"); + require(isSupportedValidator(validatorId), "Validator not supported"); require(amount > 0, "Must delegate something"); // unwrap Wrapped Sonic (wS) to native Sonic (S) @@ -251,7 +253,7 @@ abstract contract SonicValidatorDelegator is InitializableAbstractStrategy { /// @notice Allows a validator to be delegated to by the Registrator function supportValidator(uint256 validatorId) external onlyGovernor { require( - !_isSupportedValidator(validatorId), + !isSupportedValidator(validatorId), "Validator already supported" ); @@ -263,7 +265,7 @@ abstract contract SonicValidatorDelegator is InitializableAbstractStrategy { /// @notice Removes a validator from the supported list. /// Unsupported validators can still be undelegated from, withdrawn from and rewards collected. function unsupportValidator(uint256 validatorId) external onlyGovernor { - require(_isSupportedValidator(validatorId), "Validator not supported"); + require(isSupportedValidator(validatorId), "Validator not supported"); require( ISFC(sfc).getStake(address(this), validatorId) == 0, "Validator still has stake" @@ -282,8 +284,13 @@ abstract contract SonicValidatorDelegator is InitializableAbstractStrategy { emit UnsupportedValidator(validatorId); } - function _isSupportedValidator(uint256 validatorId) - internal + /// @notice Returns the length of the supportedValidators array + function supportedValidatorsLength() external view returns(uint256) { + return supportedValidators.length; + } + + function isSupportedValidator(uint256 validatorId) + public view returns (bool) { diff --git a/contracts/deploy/sonic/001_origin_sonic.js b/contracts/deploy/sonic/001_origin_sonic.js index c675f882cc..7404ecb915 100644 --- a/contracts/deploy/sonic/001_origin_sonic.js +++ b/contracts/deploy/sonic/001_origin_sonic.js @@ -162,6 +162,20 @@ module.exports = deployOnSonic( initSonicStakingStrategy ) ); + + // verify validators here: https://explorer.soniclabs.com/staking + // TODO: change to actual validators we want to use on the sonic mainnet + for (const validatorId of [14, 16]) { + await cSonicStakingStrategy + .connect(sDeployer) + .supportValidator(validatorId) + } + + // TODO: change to Defender Sonic Relayer + await cSonicStakingStrategy + .connect(sDeployer) + .setRegistrator("0xFacEfACE000000000000000000000000facefaCe"); + console.log("Initialized SonicStakingStrategy proxy and implementation"); // TODO transfer governor to ? diff --git a/contracts/hardhat.config.js b/contracts/hardhat.config.js index 7748653408..2a3bb95870 100644 --- a/contracts/hardhat.config.js +++ b/contracts/hardhat.config.js @@ -55,8 +55,9 @@ const BASE_DEPLOYER = MAINNET_DEPLOYER; const BASE_GOVERNOR = "0x92A19381444A001d62cE67BaFF066fA1111d7202"; const BASE_STRATEGIST = "0x28bce2eE5775B652D92bB7c2891A89F036619703"; const SONIC_DEPLOYER = MAINNET_DEPLOYER; +// TODO: update Sonic Governor and strategist const SONIC_GOVERNOR = MAINNET_DEPLOYER; -const SONIC_STRATEGIST = ""; +const SONIC_STRATEGIST = MAINNET_DEPLOYER; const mnemonic = "replace hover unaware super where filter stone fine garlic address matrix basic"; diff --git a/contracts/test/_fixture-sonic.js b/contracts/test/_fixture-sonic.js index 3c57f0f20d..d23875206c 100644 --- a/contracts/test/_fixture-sonic.js +++ b/contracts/test/_fixture-sonic.js @@ -2,7 +2,7 @@ const hre = require("hardhat"); const { ethers } = hre; const mocha = require("mocha"); const { isFork, isSonicFork, oethUnits } = require("./helpers"); -const { impersonateAndFund, impersonateAccount } = require("../utils/signers"); +const { impersonateAndFund } = require("../utils/signers"); const { nodeRevert, nodeSnapshot } = require("./_fixture"); const addresses = require("../utils/addresses"); const hhHelpers = require("@nomicfoundation/hardhat-network-helpers"); @@ -25,9 +25,11 @@ const defaultSonicFixture = deployments.createFixture(async () => { return; } + let deployerAddr; if (isFork) { // Fund deployer account - const { deployerAddr } = await getNamedAccounts(); + const namedAccounts = await getNamedAccounts(); + deployerAddr = namedAccounts.deployerAddr; await impersonateAndFund(deployerAddr); } @@ -58,41 +60,43 @@ const defaultSonicFixture = deployments.createFixture(async () => { oSonicVaultProxy.address ); - let dripper, harvester; - if (isFork) { - // Harvester - const harvesterProxy = await ethers.getContract("OSonicHarvesterProxy"); - harvester = await ethers.getContractAt( - "OSonicHarvester", - harvesterProxy.address - ); - - // Dripper - const dripperProxy = await ethers.getContract("OSonicDripperProxy"); - dripper = await ethers.getContractAt( - "FixedRateDripper", - dripperProxy.address - ); - } + // Sonic staking strategy + const sonicStakingStrategyProxy = await ethers.getContract("SonicStakingStrategyProxy"); + const sonicStakingStrategy = await ethers.getContractAt("SonicStakingStrategy", sonicStakingStrategyProxy.address); + + // let dripper, harvester; + // if (isFork) { + // // Harvester + // const harvesterProxy = await ethers.getContract("OSonicHarvesterProxy"); + // harvester = await ethers.getContractAt( + // "OSonicHarvester", + // harvesterProxy.address + // ); + + // // Dripper + // const dripperProxy = await ethers.getContract("OSonicDripperProxy"); + // dripper = await ethers.getContractAt( + // "FixedRateDripper", + // dripperProxy.address + // ); + // } // Sonic's wrapped S token let wS; if (isFork) { - wS = await ethers.getContractAt("IERC20", addresses.sonic.WS); + wS = await ethers.getContractAt("IWrappedSonic", addresses.sonic.wS); } else { wS = await ethers.getContract("MockWS"); } - // Zapper - const zapper = !isFork ? undefined : await ethers.getContract("OSonicZapper"); - const signers = await hre.ethers.getSigners(); const [minter, burner, rafael, nick, clement] = signers.slice(4); // Skip first 4 addresses to avoid conflict const { governorAddr, strategistAddr, timelockAddr } = await getNamedAccounts(); - const governor = await ethers.getSigner(isFork ? timelockAddr : governorAddr); + // TODO: change the deployerAddr to the appropriate governor address + const governor = await ethers.getSigner(isFork ? deployerAddr : governorAddr); await hhHelpers.setBalance(governorAddr, oethUnits("1")); // Fund governor with some ETH const guardian = await ethers.getSigner(governorAddr); @@ -100,14 +104,17 @@ const defaultSonicFixture = deployments.createFixture(async () => { "ITimelockController", timelockAddr ); - const oSonicVaultSigner = await impersonateAccount(oSonicVault.address); + const oSonicVaultSigner = await impersonateAndFund(oSonicVault.address); - let strategist; + let strategist, validatorRegistrator; if (isFork) { // Impersonate strategist on Fork strategist = await impersonateAndFund(strategistAddr); strategist.address = strategistAddr; + validatorRegistrator = await impersonateAndFund(addresses.sonic.validatorRegistrator); + validatorRegistrator.address = addresses.sonic.validatorRegistrator; + await impersonateAndFund(governor.address); await impersonateAndFund(timelock.address); @@ -124,19 +131,14 @@ const defaultSonicFixture = deployments.createFixture(async () => { await wS.connect(user).approve(oSonicVault.address, oethUnits("5000")); } - if (isFork) { - // Governor opts in for rebasing - await oSonic.connect(governor).rebaseOptIn(); - } - return { // Origin S oSonic, oSonicVault, wOSonic, - zapper, - harvester, - dripper, + // harvester, + // dripper, + sonicStakingStrategy, // Wrapped S wS, @@ -149,6 +151,7 @@ const defaultSonicFixture = deployments.createFixture(async () => { minter, burner, oSonicVaultSigner, + validatorRegistrator, rafael, nick, diff --git a/contracts/test/behaviour/sfcStakingStrategy.js b/contracts/test/behaviour/sfcStakingStrategy.js new file mode 100644 index 0000000000..24df6fcbe8 --- /dev/null +++ b/contracts/test/behaviour/sfcStakingStrategy.js @@ -0,0 +1,166 @@ +const { expect } = require("chai"); +const { AddressZero } = require("@ethersproject/constants"); + +const { oethUnits } = require("../helpers"); + +/** + * + * @param {*} context a function that returns a fixture with the additional properties: + * @example + shouldBehaveLikeASFCStakingStrategy(async () => { + return { + ...fixture, + addresses: addresses.sonic, + sfcAddress: await ethers.getContractAt( + "ISFC", + addresses.sonic.SFC + ), + // see validators here: https://explorer.soniclabs.com/staking + testValidatorIds: [16, 18], + }; + }); + */ + +const shouldBehaveLikeASFCStakingStrategy = (context) => { + describe("Initial setup", function () { + it("Should verify the initial state", async () => { + const { sonicStakingStrategy, addresses, oSonicVault, testValidatorIds } = await context(); + expect(await sonicStakingStrategy.wrappedSonic()).to.equal( + addresses.wS, + "Incorrect wrapped sonic address set" + ); + + expect(await sonicStakingStrategy.sfc()).to.equal( + addresses.SFC, + "Incorrect SFC address set" + ); + + // TODO: change once the official supported validators change + expect(await sonicStakingStrategy.supportedValidatorsLength()).to.equal( + 2, + "Incorrect Supported validators length" + ); + + for (const validatorId of testValidatorIds) { + expect(await sonicStakingStrategy.isSupportedValidator(validatorId)).to.equal( + true, + "Validator expected to be supported" + ); + } + + expect(await sonicStakingStrategy.platformAddress()).to.equal( + addresses.SFC, + "Incorrect platform address set" + ); + + expect(await sonicStakingStrategy.vaultAddress()).to.equal( + oSonicVault.address, + "Incorrect Vault address" + ); + + expect(await sonicStakingStrategy.harvesterAddress()).to.equal( + AddressZero, + "Harvester address not empty" + ); + + expect((await sonicStakingStrategy.getRewardTokenAddresses()).length).to.equal( + 0, + "Incorrectly configured Reward Token Addresses" + ); + }); + }); + + describe("Deposit/Delegation", function () { + const depositTokenAmount = async (depositAmount) => { + const { sonicStakingStrategy, oSonicVaultSigner, wS, clement } = await context(); + + const wsBalanceBefore = await wS.balanceOf( + sonicStakingStrategy.address + ); + + const strategyBalanceBefore = await sonicStakingStrategy.checkBalance( + wS.address + ); + + // Transfer some WS to strategy + await wS + .connect(clement) + .transfer(sonicStakingStrategy.address, depositAmount); + + // Call deposit by impersonating the Vault + const tx = await sonicStakingStrategy + .connect(oSonicVaultSigner) + .deposit(wS.address, depositAmount); + + expect(tx) + .to.emit(sonicStakingStrategy, "Deposit") + .withArgs(wS.address, AddressZero, depositAmount); + + expect(await wS.balanceOf(sonicStakingStrategy.address)).to.equal( + wsBalanceBefore.add(depositAmount), + "WS not transferred" + ); + expect( + await sonicStakingStrategy.checkBalance(wS.address) + ).to.equal( + strategyBalanceBefore.add(depositAmount), + "strategy checkBalance not increased" + ); + }; + + it("Should fail when unsupported functions are called", async () => { + const { sonicStakingStrategy, governor, wS } = await context(); + + await expect( + sonicStakingStrategy + .connect(governor) + .setPTokenAddress(wS.address, wS.address) + ).to.be.revertedWith("unsupported function"); + + await expect( + sonicStakingStrategy + .connect(governor) + .collectRewardTokens() + ).to.be.revertedWith("unsupported function"); + + await expect( + sonicStakingStrategy + .connect(governor) + .removePToken(wS.address) + ).to.be.revertedWith("unsupported function"); + + }); + + it("Should accept and handle S token allocation", async () => { + const depositAmount = oethUnits("15000"); + await depositTokenAmount(depositAmount); + }); + + it("Should accept and handle S token allocation and delegation to SFC", async () => { + const { sonicStakingStrategy, validatorRegistrator, testValidatorIds, wS } = await context(); + const depositAmount = oethUnits("15000"); + + await depositTokenAmount(depositAmount); + + const tx = await sonicStakingStrategy + .connect(validatorRegistrator) + .delegate(testValidatorIds[0], depositAmount); + + expect(tx) + .to.emit(sonicStakingStrategy, "Delegated") + .withArgs(testValidatorIds[0], depositAmount); + + // checkBalance should account for the full amount delegated to the validator + expect( + await sonicStakingStrategy.checkBalance(wS.address) + ).to.equal( + depositAmount, + "Strategy checkBalance not expected" + ); + }); + + + }); +}; + +module.exports = { shouldBehaveLikeASFCStakingStrategy }; diff --git a/contracts/test/strategies/sonicStaking.sonic.fork-test.js b/contracts/test/strategies/sonicStaking.sonic.fork-test.js new file mode 100644 index 0000000000..1f73218b7d --- /dev/null +++ b/contracts/test/strategies/sonicStaking.sonic.fork-test.js @@ -0,0 +1,25 @@ +const { defaultSonicFixture } = require("./../_fixture-sonic"); +const { shouldBehaveLikeASFCStakingStrategy } = require("../behaviour/sfcStakingStrategy"); +const addresses = require("../../utils/addresses"); + +describe("Sonic ForkTest: Sonic Staking Strategy", function () { + this.timeout(0); + + let fixture; + beforeEach(async () => { + fixture = await defaultSonicFixture(); + }); + + shouldBehaveLikeASFCStakingStrategy(async () => { + return { + ...fixture, + addresses: addresses.sonic, + sfcAddress: await ethers.getContractAt( + "ISFC", + addresses.sonic.SFC + ), + // see validators here: https://explorer.soniclabs.com/staking + testValidatorIds: [14, 16], + }; + }); +}); diff --git a/contracts/utils/addresses.js b/contracts/utils/addresses.js index fd7c0c9a88..2bb8594f44 100644 --- a/contracts/utils/addresses.js +++ b/contracts/utils/addresses.js @@ -340,6 +340,8 @@ addresses.sonic = {}; addresses.sonic.wS = "0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38"; addresses.sonic.WETH = "0x309C92261178fA0CF748A855e90Ae73FDb79EBc7"; addresses.sonic.SFC = "0xFC00FACE00000000000000000000000000000000"; +// TODO: change to Defender Sonic Relayer +addresses.sonic.validatorRegistrator = "0xFacEfACE000000000000000000000000facefaCe"; // Holesky addresses.holesky.WETH = "0x94373a4919B3240D86eA41593D5eBa789FEF3848"; diff --git a/contracts/utils/deploy-l2.js b/contracts/utils/deploy-l2.js index edfcc3002b..4a142aaf3e 100644 --- a/contracts/utils/deploy-l2.js +++ b/contracts/utils/deploy-l2.js @@ -208,7 +208,7 @@ function deployOnBaseWithGuardian(opts, fn) { } function deployOnSonic(opts, fn) { - const { deployName, dependencies } = opts; + const { deployName, dependencies, forceSkip } = opts; const runDeployment = async (hre) => { const tools = { @@ -242,12 +242,12 @@ function deployOnSonic(opts, fn) { main.tags = ["sonic"]; main.skip = () => + forceSkip || !( isSonicFork || hre.network.name == "sonic" || hre.network.config.chainId == 146 ); - return main; } From d6bffbcb43b9fa09bd6cfdb86bbeea1b993373e0 Mon Sep 17 00:00:00 2001 From: Domen Grabec Date: Tue, 7 Jan 2025 21:20:39 +0100 Subject: [PATCH 235/273] add correct validator ids --- contracts/deploy/sonic/001_origin_sonic.js | 3 +-- contracts/test/behaviour/sfcStakingStrategy.js | 3 +-- contracts/test/strategies/sonicStaking.sonic.fork-test.js | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/contracts/deploy/sonic/001_origin_sonic.js b/contracts/deploy/sonic/001_origin_sonic.js index 7404ecb915..7a3a3be176 100644 --- a/contracts/deploy/sonic/001_origin_sonic.js +++ b/contracts/deploy/sonic/001_origin_sonic.js @@ -164,8 +164,7 @@ module.exports = deployOnSonic( ); // verify validators here: https://explorer.soniclabs.com/staking - // TODO: change to actual validators we want to use on the sonic mainnet - for (const validatorId of [14, 16]) { + for (const validatorId of [15, 16, 17, 18]) { await cSonicStakingStrategy .connect(sDeployer) .supportValidator(validatorId) diff --git a/contracts/test/behaviour/sfcStakingStrategy.js b/contracts/test/behaviour/sfcStakingStrategy.js index 24df6fcbe8..ef3743d963 100644 --- a/contracts/test/behaviour/sfcStakingStrategy.js +++ b/contracts/test/behaviour/sfcStakingStrategy.js @@ -35,9 +35,8 @@ const shouldBehaveLikeASFCStakingStrategy = (context) => { "Incorrect SFC address set" ); - // TODO: change once the official supported validators change expect(await sonicStakingStrategy.supportedValidatorsLength()).to.equal( - 2, + 4, "Incorrect Supported validators length" ); diff --git a/contracts/test/strategies/sonicStaking.sonic.fork-test.js b/contracts/test/strategies/sonicStaking.sonic.fork-test.js index 1f73218b7d..2345107cc0 100644 --- a/contracts/test/strategies/sonicStaking.sonic.fork-test.js +++ b/contracts/test/strategies/sonicStaking.sonic.fork-test.js @@ -19,7 +19,7 @@ describe("Sonic ForkTest: Sonic Staking Strategy", function () { addresses.sonic.SFC ), // see validators here: https://explorer.soniclabs.com/staking - testValidatorIds: [14, 16], + testValidatorIds: [15, 16, 17, 18], }; }); }); From eebc29398931834bdc18f623a895153f1b87b536 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Wed, 8 Jan 2025 13:18:48 +1100 Subject: [PATCH 236/273] Added Defender Relayer for Sonic --- contracts/deploy/sonic/001_origin_sonic.js | 11 ++++++----- contracts/utils/addresses.js | 4 ++-- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/contracts/deploy/sonic/001_origin_sonic.js b/contracts/deploy/sonic/001_origin_sonic.js index 7a3a3be176..5c3598e5ff 100644 --- a/contracts/deploy/sonic/001_origin_sonic.js +++ b/contracts/deploy/sonic/001_origin_sonic.js @@ -162,20 +162,21 @@ module.exports = deployOnSonic( initSonicStakingStrategy ) ); + console.log("Initialized SonicStakingStrategy proxy and implementation"); // verify validators here: https://explorer.soniclabs.com/staking for (const validatorId of [15, 16, 17, 18]) { await cSonicStakingStrategy .connect(sDeployer) - .supportValidator(validatorId) + .supportValidator(validatorId); } + console.log("Added supported validators"); - // TODO: change to Defender Sonic Relayer + // Set Defender Relayer for Sonic validator controls await cSonicStakingStrategy .connect(sDeployer) - .setRegistrator("0xFacEfACE000000000000000000000000facefaCe"); - - console.log("Initialized SonicStakingStrategy proxy and implementation"); + .setRegistrator(addresses.sonic.validatorRegistrator); + console.log("Set registrator"); // TODO transfer governor to ? } diff --git a/contracts/utils/addresses.js b/contracts/utils/addresses.js index 2bb8594f44..52cbf2eb6f 100644 --- a/contracts/utils/addresses.js +++ b/contracts/utils/addresses.js @@ -340,8 +340,8 @@ addresses.sonic = {}; addresses.sonic.wS = "0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38"; addresses.sonic.WETH = "0x309C92261178fA0CF748A855e90Ae73FDb79EBc7"; addresses.sonic.SFC = "0xFC00FACE00000000000000000000000000000000"; -// TODO: change to Defender Sonic Relayer -addresses.sonic.validatorRegistrator = "0xFacEfACE000000000000000000000000facefaCe"; +addresses.sonic.validatorRegistrator = + "0x531B8D5eD6db72A56cF1238D4cE478E7cB7f2825"; // Holesky addresses.holesky.WETH = "0x94373a4919B3240D86eA41593D5eBa789FEF3848"; From 6f563aae163d0eccc645fb7b43bbdf5cb5ca6501 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Wed, 8 Jan 2025 15:11:14 +1100 Subject: [PATCH 237/273] Fixed Sonic unit tests Prettier and linter --- contracts/contracts/mocks/MockSFC.sol | 69 +++++++ .../sonic/SonicValidatorDelegator.sol | 15 +- contracts/deploy/sonic/000_mock.js | 56 +++++- contracts/test/_fixture-sonic.js | 23 ++- .../test/behaviour/sfcStakingStrategy.js | 52 +++-- .../sonicStaking.sonic.fork-test.js | 9 +- contracts/test/vault/os-vault.sonic.js | 177 ++---------------- 7 files changed, 193 insertions(+), 208 deletions(-) create mode 100644 contracts/contracts/mocks/MockSFC.sol diff --git a/contracts/contracts/mocks/MockSFC.sol b/contracts/contracts/mocks/MockSFC.sol new file mode 100644 index 0000000000..bb842adebf --- /dev/null +++ b/contracts/contracts/mocks/MockSFC.sol @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "./MintableERC20.sol"; + +contract MockSFC { + error ZeroAmount(); + error TransferFailed(); + + // Mapping of delegator address to validator ID to amount delegated + mapping(address => mapping(uint256 => uint256)) public delegations; + // Mapping of delegator address to validator ID to withdrawal request ID to amount + mapping(address => mapping(uint256 => mapping(uint256 => uint256))) + public withdraws; + + function getStake(address delegator, uint256 validatorID) + external + view + returns (uint256) + { + return delegations[delegator][validatorID]; + } + + function delegate(uint256 validatorID) external payable { + if (msg.value == 0) { + revert ZeroAmount(); + } + delegations[msg.sender][validatorID] += msg.value; + } + + function undelegate( + uint256 validatorID, + uint256 wrID, + uint256 amount + ) external { + require( + delegations[msg.sender][validatorID] >= amount, + "insufficient stake" + ); + require( + withdraws[msg.sender][validatorID][wrID] == 0, + "withdrawal request already exists" + ); + + delegations[msg.sender][validatorID] -= amount; + withdraws[msg.sender][validatorID][wrID] = amount; + } + + function withdraw(uint256 validatorID, uint256 wrID) external { + require(withdraws[msg.sender][validatorID][wrID] > 0, "no withdrawal"); + + (bool sent, ) = msg.sender.call{ + value: withdraws[msg.sender][validatorID][wrID] + }(""); + if (!sent) { + revert TransferFailed(); + } + } + + function pendingRewards(address delegator, uint256 validatorID) + external + view + returns (uint256) + {} + + function claimRewards(uint256 validatorID) external {} + + function restakeRewards(uint256 validatorID) external {} +} diff --git a/contracts/contracts/strategies/sonic/SonicValidatorDelegator.sol b/contracts/contracts/strategies/sonic/SonicValidatorDelegator.sol index 70be9bd48e..db5bb5cfaa 100644 --- a/contracts/contracts/strategies/sonic/SonicValidatorDelegator.sol +++ b/contracts/contracts/strategies/sonic/SonicValidatorDelegator.sol @@ -6,11 +6,10 @@ import { IVault } from "../../interfaces/IVault.sol"; import { ISFC } from "../../interfaces/sonic/ISFC.sol"; import { IWrappedSonic } from "../../interfaces/sonic/IWrappedSonic.sol"; -import "hardhat/console.sol"; - /** * @title Manages delegation to Sonic validators - * @notice This contract implements all the required functionality to delegate to, undelegate from and withdraw from validators. + * @notice This contract implements all the required functionality to delegate to, + undelegate from and withdraw from validators. * @author Origin Protocol Inc */ abstract contract SonicValidatorDelegator is InitializableAbstractStrategy { @@ -121,9 +120,11 @@ abstract contract SonicValidatorDelegator is InitializableAbstractStrategy { // For each supported validator, get the staked amount and pending rewards for (uint256 i = 0; i < supportedValidators.length; i++) { // Get the staked amount and any pending rewards - balance += - ISFC(sfc).getStake(address(this), supportedValidators[i]); - ISFC(sfc).pendingRewards(address(this), supportedValidators[i]); + balance += ISFC(sfc).getStake( + address(this), + supportedValidators[i] + ); + ISFC(sfc).pendingRewards(address(this), supportedValidators[i]); } } @@ -285,7 +286,7 @@ abstract contract SonicValidatorDelegator is InitializableAbstractStrategy { } /// @notice Returns the length of the supportedValidators array - function supportedValidatorsLength() external view returns(uint256) { + function supportedValidatorsLength() external view returns (uint256) { return supportedValidators.length; } diff --git a/contracts/deploy/sonic/000_mock.js b/contracts/deploy/sonic/000_mock.js index 627b6521de..cbaf69d446 100644 --- a/contracts/deploy/sonic/000_mock.js +++ b/contracts/deploy/sonic/000_mock.js @@ -1,8 +1,12 @@ -const { deployWithConfirmation } = require("../../utils/deploy"); +const { + deployWithConfirmation, + withConfirmation, +} = require("../../utils/deploy"); const { isFork, isSonic, oethUnits } = require("../../test/helpers"); const deployMocks = async () => { await deployWithConfirmation("MockWS", []); + await deployWithConfirmation("MockSFC", []); }; const deployOracleRouter = async () => { @@ -117,10 +121,60 @@ const deployCore = async () => { await cOSonicVault.connect(sGovernor).unpauseCapital(); }; +const deployStakingStrategy = async () => { + const { deployerAddr, governorAddr } = await getNamedAccounts(); + const sDeployer = await ethers.provider.getSigner(deployerAddr); + + const cWS = await ethers.getContract("MockWS"); + const cSFC = await ethers.getContract("MockSFC"); + + const cOSonicVaultProxy = await ethers.getContract("OSonicVaultProxy"); + + // Get contract instances + const cOSonicVault = await ethers.getContractAt( + "IVault", + cOSonicVaultProxy.address + ); + + // Staking Strategy + await deployWithConfirmation("SonicStakingStrategyProxy"); + + const cSonicStakingStrategyProxy = await ethers.getContract( + "SonicStakingStrategyProxy" + ); + const dSonicStakingStrategy = await deployWithConfirmation( + "SonicStakingStrategy", + [ + [cSFC.address, cOSonicVault.address], // platformAddress, VaultAddress + cWS.address, + cSFC.address, + ] + ); + const cSonicStakingStrategy = await ethers.getContractAt( + "SonicStakingStrategy", + cSonicStakingStrategyProxy.address + ); + + // Init the Sonic Staking Strategy + const initSonicStakingStrategy = + cSonicStakingStrategy.interface.encodeFunctionData("initialize()", []); + // prettier-ignore + await withConfirmation( + cSonicStakingStrategyProxy + .connect(sDeployer)["initialize(address,address,bytes)"]( + dSonicStakingStrategy.address, + governorAddr, + initSonicStakingStrategy + ) + ); + console.log("Initialized SonicStakingStrategy proxy and implementation"); +}; + const main = async () => { await deployMocks(); await deployOracleRouter(); await deployCore(); + await deployStakingStrategy(); }; main.id = "000_mock"; diff --git a/contracts/test/_fixture-sonic.js b/contracts/test/_fixture-sonic.js index d23875206c..917859f387 100644 --- a/contracts/test/_fixture-sonic.js +++ b/contracts/test/_fixture-sonic.js @@ -61,8 +61,13 @@ const defaultSonicFixture = deployments.createFixture(async () => { ); // Sonic staking strategy - const sonicStakingStrategyProxy = await ethers.getContract("SonicStakingStrategyProxy"); - const sonicStakingStrategy = await ethers.getContractAt("SonicStakingStrategy", sonicStakingStrategyProxy.address); + const sonicStakingStrategyProxy = await ethers.getContract( + "SonicStakingStrategyProxy" + ); + const sonicStakingStrategy = await ethers.getContractAt( + "SonicStakingStrategy", + sonicStakingStrategyProxy.address + ); // let dripper, harvester; // if (isFork) { @@ -106,13 +111,15 @@ const defaultSonicFixture = deployments.createFixture(async () => { ); const oSonicVaultSigner = await impersonateAndFund(oSonicVault.address); - let strategist, validatorRegistrator; - if (isFork) { - // Impersonate strategist on Fork - strategist = await impersonateAndFund(strategistAddr); - strategist.address = strategistAddr; + // Impersonate strategist + const strategist = await impersonateAndFund(strategistAddr); + strategist.address = strategistAddr; - validatorRegistrator = await impersonateAndFund(addresses.sonic.validatorRegistrator); + let validatorRegistrator; + if (isFork) { + validatorRegistrator = await impersonateAndFund( + addresses.sonic.validatorRegistrator + ); validatorRegistrator.address = addresses.sonic.validatorRegistrator; await impersonateAndFund(governor.address); diff --git a/contracts/test/behaviour/sfcStakingStrategy.js b/contracts/test/behaviour/sfcStakingStrategy.js index ef3743d963..45ed64bbf9 100644 --- a/contracts/test/behaviour/sfcStakingStrategy.js +++ b/contracts/test/behaviour/sfcStakingStrategy.js @@ -24,12 +24,13 @@ const { oethUnits } = require("../helpers"); const shouldBehaveLikeASFCStakingStrategy = (context) => { describe("Initial setup", function () { it("Should verify the initial state", async () => { - const { sonicStakingStrategy, addresses, oSonicVault, testValidatorIds } = await context(); + const { sonicStakingStrategy, addresses, oSonicVault, testValidatorIds } = + await context(); expect(await sonicStakingStrategy.wrappedSonic()).to.equal( addresses.wS, "Incorrect wrapped sonic address set" ); - + expect(await sonicStakingStrategy.sfc()).to.equal( addresses.SFC, "Incorrect SFC address set" @@ -41,10 +42,9 @@ const shouldBehaveLikeASFCStakingStrategy = (context) => { ); for (const validatorId of testValidatorIds) { - expect(await sonicStakingStrategy.isSupportedValidator(validatorId)).to.equal( - true, - "Validator expected to be supported" - ); + expect( + await sonicStakingStrategy.isSupportedValidator(validatorId) + ).to.equal(true, "Validator expected to be supported"); } expect(await sonicStakingStrategy.platformAddress()).to.equal( @@ -62,20 +62,18 @@ const shouldBehaveLikeASFCStakingStrategy = (context) => { "Harvester address not empty" ); - expect((await sonicStakingStrategy.getRewardTokenAddresses()).length).to.equal( - 0, - "Incorrectly configured Reward Token Addresses" - ); + expect( + (await sonicStakingStrategy.getRewardTokenAddresses()).length + ).to.equal(0, "Incorrectly configured Reward Token Addresses"); }); }); describe("Deposit/Delegation", function () { const depositTokenAmount = async (depositAmount) => { - const { sonicStakingStrategy, oSonicVaultSigner, wS, clement } = await context(); + const { sonicStakingStrategy, oSonicVaultSigner, wS, clement } = + await context(); - const wsBalanceBefore = await wS.balanceOf( - sonicStakingStrategy.address - ); + const wsBalanceBefore = await wS.balanceOf(sonicStakingStrategy.address); const strategyBalanceBefore = await sonicStakingStrategy.checkBalance( wS.address @@ -99,9 +97,7 @@ const shouldBehaveLikeASFCStakingStrategy = (context) => { wsBalanceBefore.add(depositAmount), "WS not transferred" ); - expect( - await sonicStakingStrategy.checkBalance(wS.address) - ).to.equal( + expect(await sonicStakingStrategy.checkBalance(wS.address)).to.equal( strategyBalanceBefore.add(depositAmount), "strategy checkBalance not increased" ); @@ -117,17 +113,12 @@ const shouldBehaveLikeASFCStakingStrategy = (context) => { ).to.be.revertedWith("unsupported function"); await expect( - sonicStakingStrategy - .connect(governor) - .collectRewardTokens() + sonicStakingStrategy.connect(governor).collectRewardTokens() ).to.be.revertedWith("unsupported function"); await expect( - sonicStakingStrategy - .connect(governor) - .removePToken(wS.address) + sonicStakingStrategy.connect(governor).removePToken(wS.address) ).to.be.revertedWith("unsupported function"); - }); it("Should accept and handle S token allocation", async () => { @@ -136,7 +127,12 @@ const shouldBehaveLikeASFCStakingStrategy = (context) => { }); it("Should accept and handle S token allocation and delegation to SFC", async () => { - const { sonicStakingStrategy, validatorRegistrator, testValidatorIds, wS } = await context(); + const { + sonicStakingStrategy, + validatorRegistrator, + testValidatorIds, + wS, + } = await context(); const depositAmount = oethUnits("15000"); await depositTokenAmount(depositAmount); @@ -150,15 +146,11 @@ const shouldBehaveLikeASFCStakingStrategy = (context) => { .withArgs(testValidatorIds[0], depositAmount); // checkBalance should account for the full amount delegated to the validator - expect( - await sonicStakingStrategy.checkBalance(wS.address) - ).to.equal( + expect(await sonicStakingStrategy.checkBalance(wS.address)).to.equal( depositAmount, "Strategy checkBalance not expected" ); }); - - }); }; diff --git a/contracts/test/strategies/sonicStaking.sonic.fork-test.js b/contracts/test/strategies/sonicStaking.sonic.fork-test.js index 2345107cc0..f8c035c26b 100644 --- a/contracts/test/strategies/sonicStaking.sonic.fork-test.js +++ b/contracts/test/strategies/sonicStaking.sonic.fork-test.js @@ -1,5 +1,7 @@ const { defaultSonicFixture } = require("./../_fixture-sonic"); -const { shouldBehaveLikeASFCStakingStrategy } = require("../behaviour/sfcStakingStrategy"); +const { + shouldBehaveLikeASFCStakingStrategy, +} = require("../behaviour/sfcStakingStrategy"); const addresses = require("../../utils/addresses"); describe("Sonic ForkTest: Sonic Staking Strategy", function () { @@ -14,10 +16,7 @@ describe("Sonic ForkTest: Sonic Staking Strategy", function () { return { ...fixture, addresses: addresses.sonic, - sfcAddress: await ethers.getContractAt( - "ISFC", - addresses.sonic.SFC - ), + sfcAddress: await ethers.getContractAt("ISFC", addresses.sonic.SFC), // see validators here: https://explorer.soniclabs.com/staking testValidatorIds: [15, 16, 17, 18], }; diff --git a/contracts/test/vault/os-vault.sonic.js b/contracts/test/vault/os-vault.sonic.js index a47f1e41cb..504df6940e 100644 --- a/contracts/test/vault/os-vault.sonic.js +++ b/contracts/test/vault/os-vault.sonic.js @@ -3,10 +3,6 @@ const { parseUnits } = require("ethers/lib/utils"); const { createFixtureLoader } = require("../_fixture"); const { defaultSonicFixture } = require("../_fixture-sonic"); -const addresses = require("../../utils/addresses"); -const { impersonateAndFund } = require("../../utils/signers"); -const { oethUnits } = require("../helpers"); -const { deployWithConfirmation } = require("../../utils/deploy"); const sonicFixture = createFixtureLoader(defaultSonicFixture); @@ -116,170 +112,37 @@ describe("Origin S Vault", function () { }); }); - describe.skip("Mint Whitelist", function () { + describe("Administer Sonic Staking Strategy", function () { beforeEach(async () => { fixture = await sonicFixture(); }); - it("Should allow a strategy to be added to the whitelist", async () => { - const { oSonicVault, governor } = fixture; + it("Should allow governor to set validator registrator", async () => { + const { sonicStakingStrategy, governor } = fixture; - // Pretend addresses.dead is a strategy - await oSonicVault.connect(governor).approveStrategy(addresses.dead); + // generate a wallet + const newRegistrator = ethers.Wallet.createRandom(); - const tx = oSonicVault + const tx = await sonicStakingStrategy .connect(governor) - .addStrategyToMintWhitelist(addresses.dead); + .setRegistrator(newRegistrator.address); - await expect(tx).to.emit(oSonicVault, "StrategyAddedToMintWhitelist"); - expect(await oSonicVault.isMintWhitelistedStrategy(addresses.dead)).to.be - .true; - }); - - it("Should allow a strategy to be removed from the whitelist", async () => { - const { oethbVault, governor } = fixture; - - // Pretend addresses.dead is a strategy - await oethbVault.connect(governor).approveStrategy(addresses.dead); - await oethbVault - .connect(governor) - .addStrategyToMintWhitelist(addresses.dead); - - // Remove it - const tx = oethbVault - .connect(governor) - .removeStrategyFromMintWhitelist(addresses.dead); - - await expect(tx).to.emit(oethbVault, "StrategyRemovedFromMintWhitelist"); - expect(await oethbVault.isMintWhitelistedStrategy(addresses.dead)).to.be - .false; - }); - - it("Should not allow non-governor to add to whitelist", async () => { - const { oethbVault, rafael } = fixture; - const tx = oethbVault - .connect(rafael) - .addStrategyToMintWhitelist(addresses.dead); - await expect(tx).to.be.revertedWith("Caller is not the Governor"); - }); - - it("Should not allow non-governor to remove from whitelist", async () => { - const { oethbVault, rafael } = fixture; - const tx = oethbVault - .connect(rafael) - .removeStrategyFromMintWhitelist(addresses.dead); - await expect(tx).to.be.revertedWith("Caller is not the Governor"); - }); - - it("Should not allow adding unapproved strategy", async () => { - const { oethbVault, governor } = fixture; - const tx = oethbVault - .connect(governor) - .addStrategyToMintWhitelist(addresses.dead); - await expect(tx).to.be.revertedWith("Strategy not approved"); - }); - - it("Should not whitelist if already whitelisted", async () => { - const { oethbVault, governor } = fixture; - - await oethbVault.connect(governor).approveStrategy(addresses.dead); - await oethbVault - .connect(governor) - .addStrategyToMintWhitelist(addresses.dead); - - const tx = oethbVault - .connect(governor) - .addStrategyToMintWhitelist(addresses.dead); - await expect(tx).to.be.revertedWith("Already whitelisted"); - }); - - it("Should revert when removing unwhitelisted strategy", async () => { - const { oethbVault, governor } = fixture; - - const tx = oethbVault - .connect(governor) - .removeStrategyFromMintWhitelist(addresses.dead); - await expect(tx).to.be.revertedWith("Not whitelisted"); - }); - }); - - describe.skip("Mint & Burn For Strategy", function () { - let strategySigner, mockStrategy; - - beforeEach(async () => { - fixture = await sonicFixture(); - const { oethbVault, governor } = fixture; - - mockStrategy = await deployWithConfirmation("MockStrategy"); - - await oethbVault.connect(governor).approveStrategy(mockStrategy.address); - await oethbVault - .connect(governor) - .addStrategyToMintWhitelist(mockStrategy.address); - strategySigner = await impersonateAndFund(mockStrategy.address); - }); - - it("Should allow a whitelisted strategy to mint and burn", async () => { - const { oethbVault, oethb } = fixture; - - await oethbVault.rebase(); - - const amount = oethUnits("1"); - - const supplyBefore = await oethb.totalSupply(); - await oethbVault.connect(strategySigner).mintForStrategy(amount); - expect(await oethb.balanceOf(mockStrategy.address)).to.eq(amount); - expect(await oethb.totalSupply()).to.eq(supplyBefore.add(amount)); - - await oethbVault.connect(strategySigner).burnForStrategy(amount); - expect(await oethb.balanceOf(mockStrategy.address)).to.eq(0); - expect(await oethb.totalSupply()).to.eq(supplyBefore); - }); - - it("Should not allow a non-supported strategy to mint", async () => { - const { oethbVault, governor } = fixture; - - const amount = oethUnits("1"); - - const tx = oethbVault.connect(governor).mintForStrategy(amount); - await expect(tx).to.be.revertedWith("Unsupported strategy"); - }); - - it("Should not allow a non-supported strategy to burn", async () => { - const { oethbVault, governor } = fixture; - - const amount = oethUnits("1"); - - const tx = oethbVault.connect(governor).burnForStrategy(amount); - await expect(tx).to.be.revertedWith("Unsupported strategy"); - }); - - it("Should not allow a non-white listed strategy to mint", async () => { - const { oethbVault, governor } = fixture; - - // Pretend addresses.dead is a strategy - await oethbVault.connect(governor).approveStrategy(addresses.dead); - - const amount = oethUnits("1"); - - const tx = oethbVault - .connect(await impersonateAndFund(addresses.dead)) - .mintForStrategy(amount); - await expect(tx).to.be.revertedWith("Not whitelisted strategy"); + await expect(tx) + .to.emit(sonicStakingStrategy, "RegistratorChanged") + .withArgs(newRegistrator.address); + expect(await sonicStakingStrategy.validatorRegistrator()).to.eq( + newRegistrator.address + ); }); - it("Should not allow a non-white listed strategy to burn", async () => { - const { oethbVault, governor } = fixture; - - // Pretend addresses.dead is a strategy - await oethbVault.connect(governor).approveStrategy(addresses.dead); - - const amount = oethUnits("1"); + it("Should not allow set validator registrator by non-Governor", async () => { + const { sonicStakingStrategy, strategist, nick, rafael } = fixture; - const tx = oethbVault - .connect(await impersonateAndFund(addresses.dead)) - .burnForStrategy(amount); - await expect(tx).to.be.revertedWith("Not whitelisted strategy"); + for (const signer of [strategist, nick, rafael]) { + await expect( + sonicStakingStrategy.connect(signer).setRegistrator(signer.address) + ).to.be.revertedWith("Caller is not the Governor"); + } }); }); }); From b19829a9e6e221b3d4a953e1dc25947b035dca4e Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Wed, 8 Jan 2025 15:44:42 +1100 Subject: [PATCH 238/273] More admin unit tests --- contracts/test/vault/os-vault.sonic.js | 114 +++++++++++++++++++++++++ 1 file changed, 114 insertions(+) diff --git a/contracts/test/vault/os-vault.sonic.js b/contracts/test/vault/os-vault.sonic.js index 504df6940e..c66463304c 100644 --- a/contracts/test/vault/os-vault.sonic.js +++ b/contracts/test/vault/os-vault.sonic.js @@ -144,5 +144,119 @@ describe("Origin S Vault", function () { ).to.be.revertedWith("Caller is not the Governor"); } }); + + it("Should allow governor to add supported validator", async () => { + const { sonicStakingStrategy, governor } = fixture; + + expect(await sonicStakingStrategy.supportedValidatorsLength()).to.eq( + 0, + "Validators length before" + ); + expect(await sonicStakingStrategy.isSupportedValidator(98)).to.eq(false); + + // Add two validators + const tx1 = await sonicStakingStrategy + .connect(governor) + .supportValidator(98); + const tx2 = await sonicStakingStrategy + .connect(governor) + .supportValidator(99); + + await expect(tx1) + .to.emit(sonicStakingStrategy, "SupportedValidator") + .withArgs(98); + await expect(tx2) + .to.emit(sonicStakingStrategy, "SupportedValidator") + .withArgs(99); + + expect(await sonicStakingStrategy.supportedValidators(0)).to.eq(98); + expect(await sonicStakingStrategy.supportedValidators(1)).to.eq(99); + expect(await sonicStakingStrategy.supportedValidatorsLength()).to.eq( + 2, + "Validators length after" + ); + expect(await sonicStakingStrategy.isSupportedValidator(98)).to.eq(true); + }); + + it("Should not allow adding a supported validator twice", async () => { + const { sonicStakingStrategy, governor } = fixture; + + // Add validators + await sonicStakingStrategy.connect(governor).supportValidator(98); + + // Try adding again + const tx = sonicStakingStrategy.connect(governor).supportValidator(98); + + await expect(tx).to.revertedWith("Validator already supported"); + }); + + it("Should not allow add supported validator by non-Governor", async () => { + const { sonicStakingStrategy, strategist, nick, rafael } = fixture; + + for (const signer of [strategist, nick, rafael]) { + await expect( + sonicStakingStrategy.connect(signer).supportValidator(99) + ).to.be.revertedWith("Caller is not the Governor"); + } + }); + + it("Should allow governor to unsupport validator", async () => { + const { sonicStakingStrategy, governor } = fixture; + + // Add three validators + await sonicStakingStrategy.connect(governor).supportValidator(95); + await sonicStakingStrategy.connect(governor).supportValidator(98); + await sonicStakingStrategy.connect(governor).supportValidator(99); + + expect(await sonicStakingStrategy.supportedValidatorsLength()).to.eq( + 3, + "Validators length before" + ); + expect(await sonicStakingStrategy.isSupportedValidator(98)).to.eq(true); + + const tx = await sonicStakingStrategy + .connect(governor) + .unsupportValidator(98); + + await expect(tx) + .to.emit(sonicStakingStrategy, "UnsupportedValidator") + .withArgs(98); + + expect(await sonicStakingStrategy.supportedValidators(0)).to.eq(95); + expect(await sonicStakingStrategy.supportedValidators(1)).to.eq(99); + expect(await sonicStakingStrategy.supportedValidatorsLength()).to.eq( + 2, + "Validators length after" + ); + expect(await sonicStakingStrategy.isSupportedValidator(95)).to.eq(true); + expect(await sonicStakingStrategy.isSupportedValidator(98)).to.eq(false); + expect(await sonicStakingStrategy.isSupportedValidator(99)).to.eq(true); + }); + + it("Should not allow unsupport validator by non-Governor", async () => { + const { governor, sonicStakingStrategy, strategist, nick, rafael } = + fixture; + + // Add validator + await sonicStakingStrategy.connect(governor).supportValidator(95); + + for (const signer of [strategist, nick, rafael]) { + await expect( + sonicStakingStrategy.connect(signer).unsupportValidator(95) + ).to.be.revertedWith("Caller is not the Governor"); + } + }); + + it("Should not allow unsupport of an unsupported validator", async () => { + const { sonicStakingStrategy, governor } = fixture; + + expect(await sonicStakingStrategy.isSupportedValidator(90)).to.eq(false); + + const tx = sonicStakingStrategy.connect(governor).unsupportValidator(90); + + await expect(tx).to.revertedWith("Validator not supported"); + + expect(await sonicStakingStrategy.isSupportedValidator(90)).to.eq(false); + }); }); }); From 78eb22a0e23e47582865c79a0a3504472b5ab029 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Wed, 8 Jan 2025 16:23:04 +1100 Subject: [PATCH 239/273] More unit tests --- contracts/test/vault/os-vault.sonic.js | 32 ++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/contracts/test/vault/os-vault.sonic.js b/contracts/test/vault/os-vault.sonic.js index c66463304c..562363c61e 100644 --- a/contracts/test/vault/os-vault.sonic.js +++ b/contracts/test/vault/os-vault.sonic.js @@ -113,10 +113,6 @@ describe("Origin S Vault", function () { }); describe("Administer Sonic Staking Strategy", function () { - beforeEach(async () => { - fixture = await sonicFixture(); - }); - it("Should allow governor to set validator registrator", async () => { const { sonicStakingStrategy, governor } = fixture; @@ -259,4 +255,32 @@ describe("Origin S Vault", function () { expect(await sonicStakingStrategy.isSupportedValidator(90)).to.eq(false); }); }); + + describe("Unsupported strategy functions", function () { + it("Should not support collectRewardTokens", async () => { + const { sonicStakingStrategy, governor } = fixture; + + const tx = sonicStakingStrategy.connect(governor).collectRewardTokens(); + + await expect(tx).to.be.revertedWith("unsupported function"); + }); + + it("Should not support setPTokenAddress", async () => { + const { sonicStakingStrategy, governor, wS, nick } = fixture; + + const tx = sonicStakingStrategy + .connect(governor) + .setPTokenAddress(wS.address, nick.address); + + await expect(tx).to.be.revertedWith("unsupported function"); + }); + + it("Should not support removePToken", async () => { + const { sonicStakingStrategy, governor } = fixture; + + const tx = sonicStakingStrategy.connect(governor).removePToken(1); + + await expect(tx).to.be.revertedWith("unsupported function"); + }); + }); }); From efd90f8ba5df2f07a31e097683d6aef0785a4149 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Wed, 8 Jan 2025 16:25:20 +1100 Subject: [PATCH 240/273] Update dependencies --- contracts/yarn.lock | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/contracts/yarn.lock b/contracts/yarn.lock index b33ce5228c..1615c427fd 100644 --- a/contracts/yarn.lock +++ b/contracts/yarn.lock @@ -3042,7 +3042,7 @@ abortcontroller-polyfill@^1.7.5: resolved "https://registry.yarnpkg.com/abortcontroller-polyfill/-/abortcontroller-polyfill-1.7.5.tgz#6738495f4e901fbb57b6c0611d0c75f76c485bed" integrity sha512-JMJ5soJWP18htbbxJjG7bG6yuI6pRhgJ0scHHTfkUjf6wjP912xZWvM+A4sJK3gqd9E8fcPbDnOefbA9Th/FIQ== -abstract-level@1.0.3, abstract-level@^1.0.0, abstract-level@^1.0.2, abstract-level@^1.0.3: +abstract-level@1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/abstract-level/-/abstract-level-1.0.3.tgz#78a67d3d84da55ee15201486ab44c09560070741" integrity sha512-t6jv+xHy+VYwc4xqZMn2Pa9DjcdzvzZmQGRjTFc8spIbRGHgBrEKbPq+rYXc7CCo0lxgYvSgKVg9qZAhpVQSjA== @@ -7251,6 +7251,11 @@ level-supports@^2.0.1: resolved "https://registry.yarnpkg.com/level-supports/-/level-supports-2.1.0.tgz#9af908d853597ecd592293b2fad124375be79c5f" integrity sha512-E486g1NCjW5cF78KGPrMDRBYzPuueMZ6VBXHT6gC7A8UYWGiM14fGgp+s/L1oFfDWSPV/+SFkYCmZ0SiESkRKA== +level-supports@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/level-supports/-/level-supports-4.0.1.tgz#431546f9d81f10ff0fea0e74533a0e875c08c66a" + integrity sha512-PbXpve8rKeNcZ9C1mUicC9auIYFyGpkV9/i6g76tLgANwWhtG2v7I4xNBUlkn3lE2/dZF3Pi0ygYGtLc4RXXdA== + level-supports@~1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/level-supports/-/level-supports-1.0.1.tgz#2f530a596834c7301622521988e2c36bb77d122d" @@ -7258,6 +7263,14 @@ level-supports@~1.0.0: dependencies: xtend "^4.0.2" +level-transcoder@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/level-transcoder/-/level-transcoder-1.0.1.tgz#f8cef5990c4f1283d4c86d949e73631b0bc8ba9c" + integrity sha512-t7bFwFtsQeD8cl8NIoQ2iwxA0CL/9IFw7/9gAjOonH0PWTTiRfY7Hq+Ejbsxh86tXobDQ6IOiddjNYIfOBs06w== + dependencies: + buffer "^6.0.3" + module-error "^1.0.1" + level-ws@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/level-ws/-/level-ws-2.0.0.tgz#207a07bcd0164a0ec5d62c304b4615c54436d339" @@ -7751,6 +7764,11 @@ mock-fs@^4.1.0: resolved "https://registry.yarnpkg.com/mock-fs/-/mock-fs-4.14.0.tgz#ce5124d2c601421255985e6e94da80a7357b1b18" integrity sha512-qYvlv/exQ4+svI3UOvPUpLDF0OMX5euvUH0Ny4N5QyRyhNdgAgUrVH3iUINSzEPLvx0kbo/Bp28GJKIqvE7URw== +module-error@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/module-error/-/module-error-1.0.2.tgz#8d1a48897ca883f47a45816d4fb3e3c6ba404d86" + integrity sha512-0yuvsqSCv8LbaOKhnsQ/T5JhyFlCYLPXK3U2sgV10zoKQwzs/MyfuQUOZQ1V/6OCOJsK/TRgNVrPuPDqtdMFtA== + moment@^2.29.3: version "2.30.1" resolved "https://registry.yarnpkg.com/moment/-/moment-2.30.1.tgz#f8c91c07b7a786e30c59926df530b4eac96974ae" From f4ed6496dd9cf6c96515c20c3057a349711b9410 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Wed, 8 Jan 2025 17:43:11 +1100 Subject: [PATCH 241/273] bumped solidity-coverage version --- contracts/package.json | 2 +- contracts/yarn.lock | 65 +++++++++--------------------------------- 2 files changed, 14 insertions(+), 53 deletions(-) diff --git a/contracts/package.json b/contracts/package.json index 0d2589c831..88d5ac9357 100644 --- a/contracts/package.json +++ b/contracts/package.json @@ -101,7 +101,7 @@ "solc": "0.8.6", "solhint": "^3.4.1", "solidifier": "^2.2.3", - "solidity-coverage": "^0.8.2", + "solidity-coverage": "^0.8.14", "ssv-keys": "^1.1.0", "ssv-scanner": "github:bloxapp/ssv-scanner", "sync-fetch": "^0.5.2", diff --git a/contracts/yarn.lock b/contracts/yarn.lock index 1615c427fd..ab01adbfa3 100644 --- a/contracts/yarn.lock +++ b/contracts/yarn.lock @@ -2717,7 +2717,7 @@ dependencies: antlr4ts "^0.5.0-alpha.4" -"@solidity-parser/parser@^0.14.0", "@solidity-parser/parser@^0.14.1": +"@solidity-parser/parser@^0.14.0": version "0.14.5" resolved "https://registry.yarnpkg.com/@solidity-parser/parser/-/parser-0.14.5.tgz#87bc3cc7b068e08195c219c91cd8ddff5ef1a804" integrity sha512-6dKnHZn7fg/iQATVEzqyUOyEidbn05q7YA2mQ9hC0MMXhhV3/JrsxmFSYZAcr7j1yUP700LLhTruvJ3MiQmjJg== @@ -2731,6 +2731,11 @@ dependencies: antlr4ts "^0.5.0-alpha.4" +"@solidity-parser/parser@^0.19.0": + version "0.19.0" + resolved "https://registry.yarnpkg.com/@solidity-parser/parser/-/parser-0.19.0.tgz#37a8983b2725af9b14ff8c4a475fa0e98d773c3f" + integrity sha512-RV16k/qIxW/wWc+mLzV3ARyKUaMUTBy9tOLMzFhtNSKYeTAanQ3a5MudJKf/8arIFnA2L27SNjarQKmFg0w/jA== + "@szmarczak/http-timer@^1.1.2": version "1.1.2" resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-1.1.2.tgz#b1665e2c461a2cd92f4c1bbf50d5454de0d4b421" @@ -3112,11 +3117,6 @@ acorn@^7.4.0: resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== -address@^1.0.1: - version "1.2.2" - resolved "https://registry.yarnpkg.com/address/-/address-1.2.2.tgz#2b5248dac5485a6390532c6a517fda2e3faac89e" - integrity sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA== - adm-zip@^0.4.16: version "0.4.16" resolved "https://registry.yarnpkg.com/adm-zip/-/adm-zip-0.4.16.tgz#cf4c508fdffab02c269cbc7f471a875f05570365" @@ -4614,14 +4614,6 @@ destroy@1.2.0: resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== -detect-port@^1.3.0: - version "1.5.1" - resolved "https://registry.yarnpkg.com/detect-port/-/detect-port-1.5.1.tgz#451ca9b6eaf20451acb0799b8ab40dff7718727b" - integrity sha512-aBzdj76lueB6uUst5iAs7+0H/oOjqI5D16XUWxlWMIMROhcM0rfsNVk93zTngq1dDNpoXRr++Sus7ETAExppAQ== - dependencies: - address "^1.0.1" - debug "4" - diff@3.5.0: version "3.5.0" resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" @@ -7672,36 +7664,6 @@ mnemonist@^0.38.0: dependencies: obliterator "^2.0.0" -mocha@7.1.2: - version "7.1.2" - resolved "https://registry.yarnpkg.com/mocha/-/mocha-7.1.2.tgz#8e40d198acf91a52ace122cd7599c9ab857b29e6" - integrity sha512-o96kdRKMKI3E8U0bjnfqW4QMk12MwZ4mhdBTf+B5a1q9+aq2HRnj+3ZdJu0B/ZhJeK78MgYuv6L8d/rA5AeBJA== - dependencies: - ansi-colors "3.2.3" - browser-stdout "1.3.1" - chokidar "3.3.0" - debug "3.2.6" - diff "3.5.0" - escape-string-regexp "1.0.5" - find-up "3.0.0" - glob "7.1.3" - growl "1.10.5" - he "1.2.0" - js-yaml "3.13.1" - log-symbols "3.0.0" - minimatch "3.0.4" - mkdirp "0.5.5" - ms "2.1.1" - node-environment-flags "1.0.6" - object.assign "4.1.0" - strip-json-comments "2.0.1" - supports-color "6.0.0" - which "1.3.1" - wide-align "1.1.3" - yargs "13.3.2" - yargs-parser "13.1.2" - yargs-unparser "1.6.0" - mocha@^10.0.0, mocha@^10.2.0: version "10.2.0" resolved "https://registry.yarnpkg.com/mocha/-/mocha-10.2.0.tgz#1fd4a7c32ba5ac372e03a17eef435bd00e5c68b8" @@ -9277,24 +9239,23 @@ solidity-comments-extractor@^0.0.7: resolved "https://registry.yarnpkg.com/solidity-comments-extractor/-/solidity-comments-extractor-0.0.7.tgz#99d8f1361438f84019795d928b931f4e5c39ca19" integrity sha512-wciNMLg/Irp8OKGrh3S2tfvZiZ0NEyILfcRCXCD4mp7SgK/i9gzLfhY2hY7VMCQJ3kH9UB9BzNdibIVMchzyYw== -solidity-coverage@^0.8.2: - version "0.8.2" - resolved "https://registry.yarnpkg.com/solidity-coverage/-/solidity-coverage-0.8.2.tgz#bc39604ab7ce0a3fa7767b126b44191830c07813" - integrity sha512-cv2bWb7lOXPE9/SSleDO6czkFiMHgP4NXPj+iW9W7iEKLBk7Cj0AGBiNmGX3V1totl9wjPrT0gHmABZKZt65rQ== +solidity-coverage@^0.8.14: + version "0.8.14" + resolved "https://registry.yarnpkg.com/solidity-coverage/-/solidity-coverage-0.8.14.tgz#db9bfcc10e3bc369fc074b35b267d665bcc6ae2e" + integrity sha512-ItAAObe5GaEOp20kXC2BZRnph+9P7Rtoqg2mQc2SXGEHgSDF2wWd1Wxz3ntzQWXkbCtIIGdJT918HG00cObwbA== dependencies: "@ethersproject/abi" "^5.0.9" - "@solidity-parser/parser" "^0.14.1" + "@solidity-parser/parser" "^0.19.0" chalk "^2.4.2" death "^1.1.0" - detect-port "^1.3.0" difflib "^0.2.4" fs-extra "^8.1.0" ghost-testrpc "^0.0.2" global-modules "^2.0.0" globby "^10.0.1" jsonschema "^1.2.4" - lodash "^4.17.15" - mocha "7.1.2" + lodash "^4.17.21" + mocha "^10.2.0" node-emoji "^1.10.0" pify "^4.0.1" recursive-readdir "^2.2.2" From 086073fc5862b5a7b074636026dca406e1a4fe8b Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Wed, 8 Jan 2025 17:56:00 +1100 Subject: [PATCH 242/273] Added Sonic tests to CI --- .github/workflows/defi.yml | 87 +++++++++++++++++++++++++++++++++++--- 1 file changed, 80 insertions(+), 7 deletions(-) diff --git a/.github/workflows/defi.yml b/.github/workflows/defi.yml index 5872321d5b..6499c83fe4 100644 --- a/.github/workflows/defi.yml +++ b/.github/workflows/defi.yml @@ -43,7 +43,7 @@ jobs: working-directory: ./contracts contracts-test: - name: "Contracts Unit Tests" + name: "Contracts Mainnet Unit Tests" runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -59,7 +59,7 @@ jobs: working-directory: ./contracts # this will run the unit tests and report the gas usage - - name: Run Unit Tests + - name: Run Mainnet Unit Tests env: REPORT_GAS: true run: yarn run test @@ -81,7 +81,7 @@ jobs: - run: yarn install --frozen-lockfile working-directory: ./contracts - - name: Run Unit Coverage + - name: Run Mainnet Unit Coverage run: yarn run test:coverage working-directory: ./contracts @@ -109,8 +109,7 @@ jobs: - run: yarn install --frozen-lockfile working-directory: ./contracts - # this will run the unit tests and report the gas usage - - name: Run Unit Tests + - name: Run Base Unit Coverage env: REPORT_GAS: true UNIT_TESTS_NETWORK: base @@ -125,6 +124,37 @@ jobs: ./contracts/coverage/**/* retention-days: 1 + contracts-sonic-test: + name: "Contracts Unit Tests (Sonic)" + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Use Node.js + uses: actions/setup-node@v4 + with: + node-version: "20.x" + cache: "yarn" + cache-dependency-path: contracts/yarn.lock + + - run: yarn install --frozen-lockfile + working-directory: ./contracts + + - name: Run Sonic Unit Coverage + env: + REPORT_GAS: true + UNIT_TESTS_NETWORK: sonic + run: yarn run test:coverage:sonic + working-directory: ./contracts + + - uses: actions/upload-artifact@v4 + with: + name: sonic-unit-test-coverage-${{ github.sha }} + path: | + ./contracts/coverage.json + ./contracts/coverage/**/* + retention-days: 1 + contracts-forktest: name: "Contracts Fork Tests ${{ matrix.chunk_id }}" runs-on: ubuntu-latest @@ -289,16 +319,59 @@ jobs: ./contracts/coverage.json ./contracts/coverage/**/* retention-days: 1 - + + contracts-sonic-forktest: + name: "Sonic Fork Tests" + runs-on: ubuntu-latest + continue-on-error: true + env: + HARDHAT_CACHE_DIR: ./cache + PROVIDER_URL: ${{ secrets.PROVIDER_URL }} + SONIC_PROVIDER_URL: ${{ secrets.SONIC_PROVIDER_URL }} + steps: + - uses: actions/checkout@v4 + + - name: Use Node.js + uses: actions/setup-node@v4 + with: + node-version: "20.x" + cache: "yarn" + cache-dependency-path: contracts/yarn.lock + + - uses: actions/cache@v3 + id: hardhat-cache + with: + path: contracts/cache + key: ${{ runner.os }}-hardhat-${{ hashFiles('contracts/cache/*.json') }} + restore-keys: | + ${{ runner.os }}-hardhat-cache + + - run: yarn install --frozen-lockfile + working-directory: ./contracts + + - run: yarn run test:coverage:sonic-fork + working-directory: ./contracts + + - uses: actions/upload-artifact@v3 + with: + name: fork-test-sonic-coverage-${{ github.sha }} + path: | + ./contracts/coverage.json + ./contracts/coverage/**/* + retention-days: 1 + coverage-uploader: name: "Upload Coverage Reports" runs-on: ubuntu-latest needs: - contracts-unit-coverage + - contracts-base-test + - contracts-sonic-test - contracts-forktest - contracts-arb-forktest - contracts-hol-forktest - - contracts-base-test + - contracts-base-forktest + - contracts-sonic-forktest env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} steps: From 24fd32b2637e968d364e4d9a2261db7a8547ee56 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Wed, 8 Jan 2025 18:11:04 +1100 Subject: [PATCH 243/273] Fix deprecation notices Renamed actions --- .github/workflows/defi.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/defi.yml b/.github/workflows/defi.yml index 6499c83fe4..edca80879e 100644 --- a/.github/workflows/defi.yml +++ b/.github/workflows/defi.yml @@ -66,7 +66,7 @@ jobs: working-directory: ./contracts contracts-unit-coverage: - name: "Contracts Unit Coverage" + name: "Mainnet Unit Coverage" runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -94,7 +94,7 @@ jobs: retention-days: 1 contracts-base-test: - name: "Contracts Unit Tests (Base)" + name: "Base Unit Coverage" runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -125,7 +125,7 @@ jobs: retention-days: 1 contracts-sonic-test: - name: "Contracts Unit Tests (Sonic)" + name: "Sonic Unit Coverage" runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -156,7 +156,7 @@ jobs: retention-days: 1 contracts-forktest: - name: "Contracts Fork Tests ${{ matrix.chunk_id }}" + name: "Mainnet Fork Tests ${{ matrix.chunk_id }}" runs-on: ubuntu-latest strategy: matrix: @@ -298,7 +298,7 @@ jobs: cache: "yarn" cache-dependency-path: contracts/yarn.lock - - uses: actions/cache@v3 + - uses: actions/cache@v4 id: hardhat-cache with: path: contracts/cache @@ -312,7 +312,7 @@ jobs: - run: yarn run test:coverage:base-fork working-directory: ./contracts - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: fork-test-base-coverage-${{ github.sha }} path: | @@ -338,7 +338,7 @@ jobs: cache: "yarn" cache-dependency-path: contracts/yarn.lock - - uses: actions/cache@v3 + - uses: actions/cache@v4 id: hardhat-cache with: path: contracts/cache @@ -352,7 +352,7 @@ jobs: - run: yarn run test:coverage:sonic-fork working-directory: ./contracts - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: fork-test-sonic-coverage-${{ github.sha }} path: | From a3904cee714493e8503b242ac5248c8c22b0fe2a Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Wed, 8 Jan 2025 18:25:40 +1100 Subject: [PATCH 244/273] Formatting of fork-test.sh script --- contracts/fork-test.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/fork-test.sh b/contracts/fork-test.sh index b33a4919c8..97b4c47ec0 100755 --- a/contracts/fork-test.sh +++ b/contracts/fork-test.sh @@ -46,8 +46,8 @@ main() PROVIDER_URL=$BASE_PROVIDER_URL; BLOCK_NUMBER=$BASE_BLOCK_NUMBER; elif [[ $FORK_NETWORK_NAME == "sonic" ]]; then - PROVIDER_URL=$SONIC_PROVIDER_URL; - BLOCK_NUMBER=$SONIC_BLOCK_NUMBER; + PROVIDER_URL=$SONIC_PROVIDER_URL; + BLOCK_NUMBER=$SONIC_BLOCK_NUMBER; fi if $is_local; then From 0b51ee9bcd030a95540de4e8d663a7102b1775aa Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Wed, 8 Jan 2025 19:30:57 +1100 Subject: [PATCH 245/273] Slither fixes --- .../strategies/sonic/SonicStakingStrategy.sol | 2 ++ .../sonic/SonicValidatorDelegator.sol | 25 +++++++++++++------ 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/contracts/contracts/strategies/sonic/SonicStakingStrategy.sol b/contracts/contracts/strategies/sonic/SonicStakingStrategy.sol index 1c995c0c44..964eacb045 100644 --- a/contracts/contracts/strategies/sonic/SonicStakingStrategy.sol +++ b/contracts/contracts/strategies/sonic/SonicStakingStrategy.sol @@ -101,7 +101,9 @@ contract SonicStakingStrategy is SonicValidatorDelegator { emit Withdrawal(wrappedSonic, address(0), _amount); + // slither-disable-next-line unchecked-transfer unused-return IERC20(_asset).transfer(_recipient, _amount); + emit Withdrawal(_asset, address(0), _amount); } diff --git a/contracts/contracts/strategies/sonic/SonicValidatorDelegator.sol b/contracts/contracts/strategies/sonic/SonicValidatorDelegator.sol index db5bb5cfaa..1690f5164f 100644 --- a/contracts/contracts/strategies/sonic/SonicValidatorDelegator.sol +++ b/contracts/contracts/strategies/sonic/SonicValidatorDelegator.sol @@ -118,7 +118,8 @@ abstract contract SonicValidatorDelegator is InitializableAbstractStrategy { pendingWithdrawals; // For each supported validator, get the staked amount and pending rewards - for (uint256 i = 0; i < supportedValidators.length; i++) { + uint256 validatorLen = supportedValidators.length; + for (uint256 i = 0; i < validatorLen; i++) { // Get the staked amount and any pending rewards balance += ISFC(sfc).getStake( address(this), @@ -153,6 +154,7 @@ abstract contract SonicValidatorDelegator is InitializableAbstractStrategy { function undelegate(uint256 validatorId, uint256 undelegateAmount) external onlyRegistrator + nonReentrant returns (uint256 withdrawId) { // Can still undelegate even if the validator is no longer supported @@ -177,9 +179,11 @@ abstract contract SonicValidatorDelegator is InitializableAbstractStrategy { emit Undelegated(withdrawId, validatorId, undelegateAmount); } + // slither-disable-start reentrancy-no-eth function withdraw(uint256 withdrawId) external onlyRegistrator + nonReentrant returns (uint256 withdrawnAmount) { // Can still withdraw even if the validator is no longer supported @@ -193,6 +197,7 @@ abstract contract SonicValidatorDelegator is InitializableAbstractStrategy { ISFC(sfc).withdraw(withdrawal.validatorId, withdrawId); + // Save state to storage withdrawnAmount = address(this).balance - sBalanceBefore; pendingWithdrawals -= withdrawal.undelegatedAmount; withdrawals[withdrawId].undelegatedAmount = 0; @@ -201,6 +206,7 @@ abstract contract SonicValidatorDelegator is InitializableAbstractStrategy { IWrappedSonic(wrappedSonic).deposit(); // Transfer the Wrapped Sonic (wS) to the Vault + // slither-disable-next-line unchecked-transfer unused-return IERC20(wrappedSonic).transfer(vaultAddress, withdrawnAmount); emit Withdrawn( @@ -211,8 +217,13 @@ abstract contract SonicValidatorDelegator is InitializableAbstractStrategy { ); } + // slither-disable-end reentrancy-no-eth + /// @dev restake any pending validator rewards for all supported validators - function restakeRewards(uint256[] calldata validatorIds) external { + function restakeRewards(uint256[] calldata validatorIds) + external + nonReentrant + { uint256 totalRewards = 0; for (uint256 i = 0; i < validatorIds.length; ++i) { uint256 rewards = ISFC(sfc).pendingRewards( @@ -272,11 +283,10 @@ abstract contract SonicValidatorDelegator is InitializableAbstractStrategy { "Validator still has stake" ); - for (uint256 i = 0; i < supportedValidators.length; ++i) { + uint256 validatorLen = supportedValidators.length; + for (uint256 i = 0; i < validatorLen; ++i) { if (supportedValidators[i] == validatorId) { - supportedValidators[i] = supportedValidators[ - supportedValidators.length - 1 - ]; + supportedValidators[i] = supportedValidators[validatorLen - 1]; supportedValidators.pop(); break; } @@ -295,7 +305,8 @@ abstract contract SonicValidatorDelegator is InitializableAbstractStrategy { view returns (bool) { - for (uint256 i = 0; i < supportedValidators.length; ++i) { + uint256 validatorLen = supportedValidators.length; + for (uint256 i = 0; i < validatorLen; ++i) { if (supportedValidators[i] == validatorId) { return true; } From 73fc883091b4d6bd2495b53e82b918e673c16464 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Wed, 8 Jan 2025 19:37:13 +1100 Subject: [PATCH 246/273] Removed unit tests to get gas numbers from CI --- .github/workflows/defi.yml | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/.github/workflows/defi.yml b/.github/workflows/defi.yml index edca80879e..7666fc33ef 100644 --- a/.github/workflows/defi.yml +++ b/.github/workflows/defi.yml @@ -42,29 +42,6 @@ jobs: - run: yarn prettier:check working-directory: ./contracts - contracts-test: - name: "Contracts Mainnet Unit Tests" - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - - name: Use Node.js - uses: actions/setup-node@v4 - with: - node-version: "20.x" - cache: "yarn" - cache-dependency-path: contracts/yarn.lock - - - run: yarn install --frozen-lockfile - working-directory: ./contracts - - # this will run the unit tests and report the gas usage - - name: Run Mainnet Unit Tests - env: - REPORT_GAS: true - run: yarn run test - working-directory: ./contracts - contracts-unit-coverage: name: "Mainnet Unit Coverage" runs-on: ubuntu-latest @@ -111,7 +88,6 @@ jobs: - name: Run Base Unit Coverage env: - REPORT_GAS: true UNIT_TESTS_NETWORK: base run: yarn run test:coverage:base working-directory: ./contracts @@ -142,7 +118,6 @@ jobs: - name: Run Sonic Unit Coverage env: - REPORT_GAS: true UNIT_TESTS_NETWORK: sonic run: yarn run test:coverage:sonic working-directory: ./contracts From d61013c36b02328be0c00f7a5708440912764f24 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Wed, 8 Jan 2025 20:24:19 +1100 Subject: [PATCH 247/273] Removed redeem from OSonicVault --- contracts/contracts/vault/OSonicVaultCore.sol | 8 ++++++++ contracts/contracts/vault/VaultCore.sol | 1 + contracts/test/vault/os-vault.sonic.js | 13 +++++++++++++ 3 files changed, 22 insertions(+) diff --git a/contracts/contracts/vault/OSonicVaultCore.sol b/contracts/contracts/vault/OSonicVaultCore.sol index 885288b87a..bc42fd9afd 100644 --- a/contracts/contracts/vault/OSonicVaultCore.sol +++ b/contracts/contracts/vault/OSonicVaultCore.sol @@ -10,4 +10,12 @@ import { OETHVaultCore } from "./OETHVaultCore.sol"; contract OSonicVaultCore is OETHVaultCore { /// @param _wS Sonic's Wrapped S token constructor(address _wS) OETHVaultCore(_wS) {} + + /** + * @notice Instant redeem is not supported on Sonic. + * Use the asynchronous `requestWithdrawal` a `claimWithdrawal` instead. + */ + function redeem(uint256, uint256) external override { + revert("unsupported function"); + } } diff --git a/contracts/contracts/vault/VaultCore.sol b/contracts/contracts/vault/VaultCore.sol index 1b7cd786e2..18bbcde5db 100644 --- a/contracts/contracts/vault/VaultCore.sol +++ b/contracts/contracts/vault/VaultCore.sol @@ -159,6 +159,7 @@ contract VaultCore is VaultInitializer { */ function redeem(uint256 _amount, uint256 _minimumUnitAmount) external + virtual whenNotCapitalPaused nonReentrant { diff --git a/contracts/test/vault/os-vault.sonic.js b/contracts/test/vault/os-vault.sonic.js index 562363c61e..f5a2697990 100644 --- a/contracts/test/vault/os-vault.sonic.js +++ b/contracts/test/vault/os-vault.sonic.js @@ -110,9 +110,22 @@ describe("Origin S Vault", function () { fixtureWithUser ); }); + + it("Should not support redeem", async () => { + const { oSonicVault, wS, nick } = fixture; + + const tx = oSonicVault.connect(nick).redeem(wS.address, 1); + await expect(tx).to.be.revertedWith("unsupported function"); + }); }); describe("Administer Sonic Staking Strategy", function () { + it("Should support Wrapped S asset", async () => { + const { sonicStakingStrategy, wS } = fixture; + + expect(await sonicStakingStrategy.supportsAsset(wS.address)).to.eq(true); + }); + it("Should allow governor to set validator registrator", async () => { const { sonicStakingStrategy, governor } = fixture; From ba6142839bc8aeb0681778cf2ade708f07d68d89 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Wed, 8 Jan 2025 20:38:42 +1100 Subject: [PATCH 248/273] Removed unused code from SonicValidatorDelegator --- .../strategies/sonic/SonicValidatorDelegator.sol | 9 --------- 1 file changed, 9 deletions(-) diff --git a/contracts/contracts/strategies/sonic/SonicValidatorDelegator.sol b/contracts/contracts/strategies/sonic/SonicValidatorDelegator.sol index 1690f5164f..f79cdfae3c 100644 --- a/contracts/contracts/strategies/sonic/SonicValidatorDelegator.sol +++ b/contracts/contracts/strategies/sonic/SonicValidatorDelegator.sol @@ -64,15 +64,6 @@ abstract contract SonicValidatorDelegator is InitializableAbstractStrategy { _; } - /// @dev Throws if called by any account other than the Strategist - modifier onlyStrategist() { - require( - msg.sender == IVault(vaultAddress).strategistAddr(), - "Caller is not the Strategist" - ); - _; - } - constructor( BaseStrategyConfig memory _baseConfig, address _wrappedSonic, From d40026ffae537a7104f6310294289fa7892dbf6d Mon Sep 17 00:00:00 2001 From: Domen Grabec Date: Wed, 8 Jan 2025 11:18:00 +0100 Subject: [PATCH 249/273] clean up fork test structure --- .../test/behaviour/sfcStakingStrategy.js | 127 ++++++++++-------- 1 file changed, 70 insertions(+), 57 deletions(-) diff --git a/contracts/test/behaviour/sfcStakingStrategy.js b/contracts/test/behaviour/sfcStakingStrategy.js index 45ed64bbf9..c768b5fbfb 100644 --- a/contracts/test/behaviour/sfcStakingStrategy.js +++ b/contracts/test/behaviour/sfcStakingStrategy.js @@ -69,40 +69,6 @@ const shouldBehaveLikeASFCStakingStrategy = (context) => { }); describe("Deposit/Delegation", function () { - const depositTokenAmount = async (depositAmount) => { - const { sonicStakingStrategy, oSonicVaultSigner, wS, clement } = - await context(); - - const wsBalanceBefore = await wS.balanceOf(sonicStakingStrategy.address); - - const strategyBalanceBefore = await sonicStakingStrategy.checkBalance( - wS.address - ); - - // Transfer some WS to strategy - await wS - .connect(clement) - .transfer(sonicStakingStrategy.address, depositAmount); - - // Call deposit by impersonating the Vault - const tx = await sonicStakingStrategy - .connect(oSonicVaultSigner) - .deposit(wS.address, depositAmount); - - expect(tx) - .to.emit(sonicStakingStrategy, "Deposit") - .withArgs(wS.address, AddressZero, depositAmount); - - expect(await wS.balanceOf(sonicStakingStrategy.address)).to.equal( - wsBalanceBefore.add(depositAmount), - "WS not transferred" - ); - expect(await sonicStakingStrategy.checkBalance(wS.address)).to.equal( - strategyBalanceBefore.add(depositAmount), - "strategy checkBalance not increased" - ); - }; - it("Should fail when unsupported functions are called", async () => { const { sonicStakingStrategy, governor, wS } = await context(); @@ -127,31 +93,78 @@ const shouldBehaveLikeASFCStakingStrategy = (context) => { }); it("Should accept and handle S token allocation and delegation to SFC", async () => { - const { - sonicStakingStrategy, - validatorRegistrator, - testValidatorIds, - wS, - } = await context(); - const depositAmount = oethUnits("15000"); - - await depositTokenAmount(depositAmount); - - const tx = await sonicStakingStrategy - .connect(validatorRegistrator) - .delegate(testValidatorIds[0], depositAmount); - - expect(tx) - .to.emit(sonicStakingStrategy, "Delegated") - .withArgs(testValidatorIds[0], depositAmount); - - // checkBalance should account for the full amount delegated to the validator - expect(await sonicStakingStrategy.checkBalance(wS.address)).to.equal( - depositAmount, - "Strategy checkBalance not expected" - ); + const delegateAmount = oethUnits("15000"); + await depositTokenAmount(delegateAmount); + await delegateTokenAmount(delegateAmount); }); }); + + // deposit the depositAmount into the Sonic Staking Strategy + const depositTokenAmount = async (depositAmount) => { + const { sonicStakingStrategy, oSonicVaultSigner, wS, clement } = + await context(); + + const wsBalanceBefore = await wS.balanceOf(sonicStakingStrategy.address); + + const strategyBalanceBefore = await sonicStakingStrategy.checkBalance( + wS.address + ); + + // Transfer some WS to strategy + await wS + .connect(clement) + .transfer(sonicStakingStrategy.address, depositAmount); + + // Call deposit by impersonating the Vault + const tx = await sonicStakingStrategy + .connect(oSonicVaultSigner) + .deposit(wS.address, depositAmount); + + expect(tx) + .to.emit(sonicStakingStrategy, "Deposit") + .withArgs(wS.address, AddressZero, depositAmount); + + expect(await wS.balanceOf(sonicStakingStrategy.address)).to.equal( + wsBalanceBefore.add(depositAmount), + "WS not transferred" + ); + + expect(await sonicStakingStrategy.checkBalance(wS.address)).to.equal( + strategyBalanceBefore.add(depositAmount), + "strategy checkBalance not increased" + ); + }; + + // delegate the delegateAmount into the Sonic Special Fee Contract + const delegateTokenAmount = async (delegateAmount) => { + const { + sonicStakingStrategy, + validatorRegistrator, + testValidatorIds, + wS, + } = await context(); + + const wsBalanceBefore = await wS.balanceOf(sonicStakingStrategy.address); + + const tx = await sonicStakingStrategy + .connect(validatorRegistrator) + .delegate(testValidatorIds[0], delegateAmount); + + expect(tx) + .to.emit(sonicStakingStrategy, "Delegated") + .withArgs(testValidatorIds[0], delegateAmount); + + // checkBalance should account for the full amount delegated to the validator + expect(await sonicStakingStrategy.checkBalance(wS.address)).to.equal( + delegateAmount, + "Strategy checkBalance not expected" + ); + + expect(await wS.balanceOf(sonicStakingStrategy.address)).to.equal( + wsBalanceBefore.sub(delegateAmount), + "not the expected WS amount" + ); + }; }; module.exports = { shouldBehaveLikeASFCStakingStrategy }; From a6feef5843302da3854d7196b4516fde812b8c56 Mon Sep 17 00:00:00 2001 From: Domen Grabec Date: Wed, 8 Jan 2025 12:20:02 +0100 Subject: [PATCH 250/273] improve fork test checks --- .../sonic/SonicValidatorDelegator.sol | 6 +++ .../test/behaviour/sfcStakingStrategy.js | 46 +++++++++++++------ 2 files changed, 39 insertions(+), 13 deletions(-) diff --git a/contracts/contracts/strategies/sonic/SonicValidatorDelegator.sol b/contracts/contracts/strategies/sonic/SonicValidatorDelegator.sol index f79cdfae3c..e1c5666378 100644 --- a/contracts/contracts/strategies/sonic/SonicValidatorDelegator.sol +++ b/contracts/contracts/strategies/sonic/SonicValidatorDelegator.sol @@ -177,6 +177,8 @@ abstract contract SonicValidatorDelegator is InitializableAbstractStrategy { nonReentrant returns (uint256 withdrawnAmount) { + require(withdrawId < nextWithdrawId, "Invalid withdrawId"); + // Can still withdraw even if the validator is no longer supported // Load the withdrawal from storage into memory WithdrawRequest memory withdrawal = withdrawals[withdrawId]; @@ -190,6 +192,10 @@ abstract contract SonicValidatorDelegator is InitializableAbstractStrategy { // Save state to storage withdrawnAmount = address(this).balance - sBalanceBefore; + require( + withdrawnAmount == withdrawal.undelegatedAmount, + "Incorrect amount withdrawn" + ); pendingWithdrawals -= withdrawal.undelegatedAmount; withdrawals[withdrawId].undelegatedAmount = 0; diff --git a/contracts/test/behaviour/sfcStakingStrategy.js b/contracts/test/behaviour/sfcStakingStrategy.js index c768b5fbfb..054fbed726 100644 --- a/contracts/test/behaviour/sfcStakingStrategy.js +++ b/contracts/test/behaviour/sfcStakingStrategy.js @@ -95,7 +95,17 @@ const shouldBehaveLikeASFCStakingStrategy = (context) => { it("Should accept and handle S token allocation and delegation to SFC", async () => { const delegateAmount = oethUnits("15000"); await depositTokenAmount(delegateAmount); - await delegateTokenAmount(delegateAmount); + await delegateTokenAmount(delegateAmount, 0, true); + }); + + it("Should accept and handle S token allocation and delegation to all delegators", async () => { + const depositAmount = oethUnits("20000"); + const delegateAmount = oethUnits("5000"); + await depositTokenAmount(depositAmount); + await delegateTokenAmount(delegateAmount, 0); + await delegateTokenAmount(delegateAmount, 1); + await delegateTokenAmount(delegateAmount, 2); + await delegateTokenAmount(delegateAmount, 3); }); }); @@ -136,30 +146,40 @@ const shouldBehaveLikeASFCStakingStrategy = (context) => { }; // delegate the delegateAmount into the Sonic Special Fee Contract - const delegateTokenAmount = async (delegateAmount) => { - const { - sonicStakingStrategy, - validatorRegistrator, - testValidatorIds, - wS, - } = await context(); + const delegateTokenAmount = async ( + delegateAmount, + validatorIndex, + checkBalanceMatchesDelegatedAmount = false + ) => { + const { sonicStakingStrategy, validatorRegistrator, testValidatorIds, wS } = + await context(); const wsBalanceBefore = await wS.balanceOf(sonicStakingStrategy.address); + const contractBalanceBefore = await sonicStakingStrategy.checkBalance( + wS.address + ); const tx = await sonicStakingStrategy .connect(validatorRegistrator) - .delegate(testValidatorIds[0], delegateAmount); + .delegate(testValidatorIds[validatorIndex], delegateAmount); expect(tx) .to.emit(sonicStakingStrategy, "Delegated") - .withArgs(testValidatorIds[0], delegateAmount); + .withArgs(testValidatorIds[validatorIndex], delegateAmount); - // checkBalance should account for the full amount delegated to the validator + // checkBalance should not change when delegating expect(await sonicStakingStrategy.checkBalance(wS.address)).to.equal( - delegateAmount, - "Strategy checkBalance not expected" + contractBalanceBefore, + "Strategy checkBalance not as expected" ); + if (checkBalanceMatchesDelegatedAmount) { + expect(await sonicStakingStrategy.checkBalance(wS.address)).to.equal( + delegateAmount, + "Strategy checkBalance doesn't match delegated amount" + ); + } + expect(await wS.balanceOf(sonicStakingStrategy.address)).to.equal( wsBalanceBefore.sub(delegateAmount), "not the expected WS amount" From 96d0cda5aabcc3b8f227d11efd1852b05f8a68b3 Mon Sep 17 00:00:00 2001 From: Domen Grabec Date: Wed, 8 Jan 2025 23:25:55 +0100 Subject: [PATCH 251/273] add basic withdrawal tests --- .../interfaces/sonic/INodeDriver.sol | 12 + .../sonic/SonicValidatorDelegator.sol | 25 +- contracts/contracts/token/OSonic.sol | 6 + contracts/contracts/token/OUSD.sol | 18 +- contracts/deploy/sonic/001_origin_sonic.js | 4 +- contracts/test/_fixture-sonic.js | 10 + .../test/behaviour/sfcStakingStrategy.js | 242 ++++++++++++++++-- contracts/utils/addresses.js | 2 + 8 files changed, 278 insertions(+), 41 deletions(-) create mode 100644 contracts/contracts/interfaces/sonic/INodeDriver.sol diff --git a/contracts/contracts/interfaces/sonic/INodeDriver.sol b/contracts/contracts/interfaces/sonic/INodeDriver.sol new file mode 100644 index 0000000000..c3bd3d4820 --- /dev/null +++ b/contracts/contracts/interfaces/sonic/INodeDriver.sol @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.0; + +interface INodeDriver { + /// Seal epoch. Called BEFORE epoch sealing made by the client itself. + function sealEpoch( + uint256[] calldata offlineTimes, + uint256[] calldata offlineBlocks, + uint256[] calldata uptimes, + uint256[] calldata originatedTxsFee + ) external; +} diff --git a/contracts/contracts/strategies/sonic/SonicValidatorDelegator.sol b/contracts/contracts/strategies/sonic/SonicValidatorDelegator.sol index e1c5666378..01729b6b3b 100644 --- a/contracts/contracts/strategies/sonic/SonicValidatorDelegator.sol +++ b/contracts/contracts/strategies/sonic/SonicValidatorDelegator.sol @@ -116,7 +116,10 @@ abstract contract SonicValidatorDelegator is InitializableAbstractStrategy { address(this), supportedValidators[i] ); - ISFC(sfc).pendingRewards(address(this), supportedValidators[i]); + balance += ISFC(sfc).pendingRewards( + address(this), + supportedValidators[i] + ); } } @@ -171,7 +174,7 @@ abstract contract SonicValidatorDelegator is InitializableAbstractStrategy { } // slither-disable-start reentrancy-no-eth - function withdraw(uint256 withdrawId) + function withdrawFromSFC(uint256 withdrawId) external onlyRegistrator nonReentrant @@ -182,9 +185,7 @@ abstract contract SonicValidatorDelegator is InitializableAbstractStrategy { // Can still withdraw even if the validator is no longer supported // Load the withdrawal from storage into memory WithdrawRequest memory withdrawal = withdrawals[withdrawId]; - - require(withdrawal.validatorId > 0, "Invalid withdrawId"); - require(withdrawal.undelegatedAmount > 0, "Already withdrawn"); + require(!isWithdrawnFromSFC(withdrawId), "Already withdrawn"); uint256 sBalanceBefore = address(this).balance; @@ -192,20 +193,17 @@ abstract contract SonicValidatorDelegator is InitializableAbstractStrategy { // Save state to storage withdrawnAmount = address(this).balance - sBalanceBefore; - require( - withdrawnAmount == withdrawal.undelegatedAmount, - "Incorrect amount withdrawn" - ); pendingWithdrawals -= withdrawal.undelegatedAmount; withdrawals[withdrawId].undelegatedAmount = 0; // Wrap Sonic (S) to Wrapped Sonic (wS) - IWrappedSonic(wrappedSonic).deposit(); + IWrappedSonic(wrappedSonic).deposit{ value: withdrawnAmount }(); // Transfer the Wrapped Sonic (wS) to the Vault // slither-disable-next-line unchecked-transfer unused-return IERC20(wrappedSonic).transfer(vaultAddress, withdrawnAmount); + // withdrawal.undelegatedAmount & withdrawnAmount can differ in case of slashing emit Withdrawn( withdrawId, withdrawal.validatorId, @@ -216,6 +214,13 @@ abstract contract SonicValidatorDelegator is InitializableAbstractStrategy { // slither-disable-end reentrancy-no-eth + /// @notice returns a bool whether a withdrawalId has already been withdrawn or not + function isWithdrawnFromSFC(uint256 withdrawId) public view returns (bool) { + WithdrawRequest memory withdrawal = withdrawals[withdrawId]; + require(withdrawal.validatorId > 0, "Invalid withdrawId"); + return withdrawal.undelegatedAmount == 0; + } + /// @dev restake any pending validator rewards for all supported validators function restakeRewards(uint256[] calldata validatorIds) external diff --git a/contracts/contracts/token/OSonic.sol b/contracts/contracts/token/OSonic.sol index 845f132922..ed46724e03 100644 --- a/contracts/contracts/token/OSonic.sol +++ b/contracts/contracts/token/OSonic.sol @@ -8,5 +8,11 @@ import { OUSD } from "./OUSD.sol"; * @author Origin Protocol Inc */ contract OSonic is OUSD { + function symbol() external pure override returns (string memory) { + return "OS"; + } + function name() external pure override returns (string memory) { + return "Origin S"; + } } diff --git a/contracts/contracts/token/OUSD.sol b/contracts/contracts/token/OUSD.sol index 9c9f87b750..d24398dc4e 100644 --- a/contracts/contracts/token/OUSD.sol +++ b/contracts/contracts/token/OUSD.sol @@ -495,7 +495,7 @@ contract OUSD is Governable { // at least the balance that they should have. // Note this should always be used on an absolute account value, // not on a possibly negative diff, because then the rounding would be wrong. - return ((_balance) * rebasingCreditsPerToken_ + 1e18 - 1) / 1e18; + return ((_balance) * rebasingCreditsPerToken_ + 1e18 - 1) / 1e18; } /** @@ -656,12 +656,14 @@ contract OUSD is Governable { uint256 fromBalance = balanceOf(_from); uint256 toBalance = balanceOf(_to); uint256 oldToCredits = creditBalances[_to]; - uint256 newToCredits = _balanceToRebasingCredits(fromBalance + toBalance); + uint256 newToCredits = _balanceToRebasingCredits( + fromBalance + toBalance + ); // Set up the bidirectional links yieldTo[_from] = _to; yieldFrom[_to] = _from; - + // Local rebaseState[_from] = RebaseOptions.YieldDelegationSource; alternativeCreditsPerToken[_from] = 1e18; @@ -670,7 +672,8 @@ contract OUSD is Governable { creditBalances[_to] = newToCredits; // Global - int256 creditsChange = newToCredits.toInt256() - oldToCredits.toInt256(); + int256 creditsChange = newToCredits.toInt256() - + oldToCredits.toInt256(); _adjustGlobals(creditsChange, -(fromBalance).toInt256()); emit YieldDelegated(_from, _to); } @@ -685,13 +688,13 @@ contract OUSD is Governable { address to = yieldTo[_from]; uint256 fromBalance = balanceOf(_from); uint256 toBalance = balanceOf(to); - uint256 oldToCredits = creditBalances[to]; + uint256 oldToCredits = creditBalances[to]; uint256 newToCredits = _balanceToRebasingCredits(toBalance); // Remove the bidirectional links yieldFrom[to] = address(0); yieldTo[_from] = address(0); - + // Local rebaseState[_from] = RebaseOptions.StdNonRebasing; // alternativeCreditsPerToken[from] already 1e18 from `delegateYield()` @@ -701,7 +704,8 @@ contract OUSD is Governable { creditBalances[to] = newToCredits; // Global - int256 creditsChange = newToCredits.toInt256() - oldToCredits.toInt256(); + int256 creditsChange = newToCredits.toInt256() - + oldToCredits.toInt256(); _adjustGlobals(creditsChange, fromBalance.toInt256()); emit YieldUndelegated(_from, to); } diff --git a/contracts/deploy/sonic/001_origin_sonic.js b/contracts/deploy/sonic/001_origin_sonic.js index 5c3598e5ff..f53190a23c 100644 --- a/contracts/deploy/sonic/001_origin_sonic.js +++ b/contracts/deploy/sonic/001_origin_sonic.js @@ -62,10 +62,8 @@ module.exports = deployOnSonic( // Init OSonic const resolution = ethers.utils.parseUnits("1", 27); const initDataOSonic = cOSonic.interface.encodeFunctionData( - "initialize(string,string,address,uint256)", + "initialize(address,uint256)", [ - "Origin S", // Token Name - "OS", // Token Symbol cOSonicVaultProxy.address, // Origin Sonic Vault resolution, // HighRes ] diff --git a/contracts/test/_fixture-sonic.js b/contracts/test/_fixture-sonic.js index 917859f387..cc52290548 100644 --- a/contracts/test/_fixture-sonic.js +++ b/contracts/test/_fixture-sonic.js @@ -69,6 +69,13 @@ const defaultSonicFixture = deployments.createFixture(async () => { sonicStakingStrategyProxy.address ); + const nodeDriver = await ethers.getContractAt( + "INodeDriver", + addresses.sonic.nodeDriver + ); + + const sfc = await ethers.getContractAt("ISFC", addresses.sonic.SFC); + // let dripper, harvester; // if (isFork) { // // Harvester @@ -163,6 +170,9 @@ const defaultSonicFixture = deployments.createFixture(async () => { rafael, nick, clement, + + nodeDriver, + sfc, }; }); diff --git a/contracts/test/behaviour/sfcStakingStrategy.js b/contracts/test/behaviour/sfcStakingStrategy.js index 054fbed726..794ea31f87 100644 --- a/contracts/test/behaviour/sfcStakingStrategy.js +++ b/contracts/test/behaviour/sfcStakingStrategy.js @@ -1,7 +1,8 @@ const { expect } = require("chai"); const { AddressZero } = require("@ethersproject/constants"); - -const { oethUnits } = require("../helpers"); +const { oethUnits, advanceTime } = require("../helpers"); +const { BigNumber } = ethers; +const { impersonateAndFund } = require("../../utils/signers"); /** * @@ -21,6 +22,7 @@ const { oethUnits } = require("../helpers"); }); */ +const MIN_WITHDRAWAL_EPOCH_ADVANCE = 4; const shouldBehaveLikeASFCStakingStrategy = (context) => { describe("Initial setup", function () { it("Should verify the initial state", async () => { @@ -93,9 +95,9 @@ const shouldBehaveLikeASFCStakingStrategy = (context) => { }); it("Should accept and handle S token allocation and delegation to SFC", async () => { - const delegateAmount = oethUnits("15000"); - await depositTokenAmount(delegateAmount); - await delegateTokenAmount(delegateAmount, 0, true); + const amount = oethUnits("15000"); + await depositTokenAmount(amount); + await delegateTokenAmount(amount, 0, true); }); it("Should accept and handle S token allocation and delegation to all delegators", async () => { @@ -109,45 +111,99 @@ const shouldBehaveLikeASFCStakingStrategy = (context) => { }); }); - // deposit the depositAmount into the Sonic Staking Strategy - const depositTokenAmount = async (depositAmount) => { + describe("Undelegation/Withdrawal", function () { + it("Should undelegate and withdraw", async () => { + const amount = oethUnits("15000"); + await depositTokenAmount(amount); + await delegateTokenAmount(amount, 0, true); + await undelegateTokenAmount(amount, 0); + }); + + it("Should not undelegate with 0 amount", async () => { + const amount = oethUnits("15000"); + await depositTokenAmount(amount); + await delegateTokenAmount(amount, 0, true); + + const { sonicStakingStrategy, validatorRegistrator, testValidatorIds } = + await context(); + + await expect( + sonicStakingStrategy + .connect(validatorRegistrator) + .undelegate(testValidatorIds[0], oethUnits("0")) + ).to.be.revertedWith("Must undelegate something"); + }); + + it("Should not undelegate more than has been delegated", async () => { + const amount = oethUnits("15000"); + await depositTokenAmount(amount); + await delegateTokenAmount(amount, 0, true); + + const { sonicStakingStrategy, validatorRegistrator, testValidatorIds } = + await context(); + + await expect( + sonicStakingStrategy + .connect(validatorRegistrator) + .undelegate(testValidatorIds[0], oethUnits("1500000000")) + ).to.be.revertedWith("Insufficient delegation"); + }); + + it("Withdraw what has been delegated", async () => { + const amount = oethUnits("15000"); + await depositTokenAmount(amount); + await delegateTokenAmount(amount, 0, true); + const withdrawalId = await undelegateTokenAmount(amount, 0); + await advanceWeek(); + await advanceWeek(); + await withdrawFromSFC(withdrawalId, amount); + }); + + it("Can not withdraw too soon", async () => {}); + + it("Can withdraw multiple times", async () => {}); + + it("Incorrect withdrawal ID should revert", async () => {}); + + it("Can not withdraw with the same ID twice", async () => {}); + }); + + // deposit the amount into the Sonic Staking Strategy + const depositTokenAmount = async (amount) => { const { sonicStakingStrategy, oSonicVaultSigner, wS, clement } = await context(); const wsBalanceBefore = await wS.balanceOf(sonicStakingStrategy.address); - const strategyBalanceBefore = await sonicStakingStrategy.checkBalance( wS.address ); // Transfer some WS to strategy - await wS - .connect(clement) - .transfer(sonicStakingStrategy.address, depositAmount); + await wS.connect(clement).transfer(sonicStakingStrategy.address, amount); // Call deposit by impersonating the Vault const tx = await sonicStakingStrategy .connect(oSonicVaultSigner) - .deposit(wS.address, depositAmount); + .deposit(wS.address, amount); expect(tx) .to.emit(sonicStakingStrategy, "Deposit") - .withArgs(wS.address, AddressZero, depositAmount); + .withArgs(wS.address, AddressZero, amount); expect(await wS.balanceOf(sonicStakingStrategy.address)).to.equal( - wsBalanceBefore.add(depositAmount), + wsBalanceBefore.add(amount), "WS not transferred" ); expect(await sonicStakingStrategy.checkBalance(wS.address)).to.equal( - strategyBalanceBefore.add(depositAmount), + strategyBalanceBefore.add(amount), "strategy checkBalance not increased" ); }; - // delegate the delegateAmount into the Sonic Special Fee Contract + // delegate the amount into the Sonic Special Fee Contract const delegateTokenAmount = async ( - delegateAmount, + amount, validatorIndex, checkBalanceMatchesDelegatedAmount = false ) => { @@ -161,11 +217,11 @@ const shouldBehaveLikeASFCStakingStrategy = (context) => { const tx = await sonicStakingStrategy .connect(validatorRegistrator) - .delegate(testValidatorIds[validatorIndex], delegateAmount); + .delegate(testValidatorIds[validatorIndex], amount); expect(tx) .to.emit(sonicStakingStrategy, "Delegated") - .withArgs(testValidatorIds[validatorIndex], delegateAmount); + .withArgs(testValidatorIds[validatorIndex], amount); // checkBalance should not change when delegating expect(await sonicStakingStrategy.checkBalance(wS.address)).to.equal( @@ -175,16 +231,160 @@ const shouldBehaveLikeASFCStakingStrategy = (context) => { if (checkBalanceMatchesDelegatedAmount) { expect(await sonicStakingStrategy.checkBalance(wS.address)).to.equal( - delegateAmount, + amount, "Strategy checkBalance doesn't match delegated amount" ); } expect(await wS.balanceOf(sonicStakingStrategy.address)).to.equal( - wsBalanceBefore.sub(delegateAmount), + wsBalanceBefore.sub(amount), "not the expected WS amount" ); }; + + // undelegate the amount into the Sonic Special Fee Contract + const undelegateTokenAmount = async (amount, validatorIndex) => { + const { sonicStakingStrategy, validatorRegistrator, testValidatorIds, wS } = + await context(); + + const contractBalanceBefore = await sonicStakingStrategy.checkBalance( + wS.address + ); + const expectedWithdrawId = await sonicStakingStrategy.nextWithdrawId(); + const pendingWithdrawalsBefore = + await sonicStakingStrategy.pendingWithdrawals(); + + const tx = await sonicStakingStrategy + .connect(validatorRegistrator) + .undelegate(testValidatorIds[validatorIndex], amount); + + expect(tx) + .to.emit(sonicStakingStrategy, "Undelegated") + .withArgs(expectedWithdrawId, testValidatorIds[validatorIndex], amount); + const withdrawal = await sonicStakingStrategy.withdrawals( + expectedWithdrawId + ); + + expect(withdrawal.validatorId).to.equal(testValidatorIds[validatorIndex]); + expect(withdrawal.undelegatedAmount).to.equal(amount); + + await expect(await sonicStakingStrategy.pendingWithdrawals()).to.equal( + pendingWithdrawalsBefore.add(amount) + ); + + expect(await sonicStakingStrategy.checkBalance(wS.address)).to.equal( + contractBalanceBefore, + "Strategy checkBalance doesn't match" + ); + + return expectedWithdrawId; + }; + + // Withdraw the matured undelegated funds from the Sonic Special Fee Contract + const withdrawFromSFC = async (withdrawalId, expectedAmountToWithdraw) => { + const { + sonicStakingStrategy, + validatorRegistrator, + wS, + oSonicVault, + } = await context(); + + console.log("00"); + const contractBalanceBefore = await sonicStakingStrategy.checkBalance( + wS.address + ); + + const vaultBalanceBefore = await wS.balanceOf(oSonicVault.address); + const withdrawal = await sonicStakingStrategy.withdrawals(withdrawalId); + const amountToWithdraw = withdrawal.undelegatedAmount; + const pendingWithdrawalsBefore = + await sonicStakingStrategy.pendingWithdrawals(); + expect(expectedAmountToWithdraw).to.equal(amountToWithdraw); + + console.log("ADVANCE EPOCH"); + await advanceSfcEpoch(MIN_WITHDRAWAL_EPOCH_ADVANCE); + + console.log("ADVANCE EPOCH DONE"); + // checkBalance should be smaller by withdrawn amount + const tx = await sonicStakingStrategy + .connect(validatorRegistrator) + .withdrawFromSFC(withdrawalId); + + const withdrawalAfter = await sonicStakingStrategy.withdrawals( + withdrawalId + ); + + expect(tx) + .to.emit(sonicStakingStrategy, "Withdrawn") + .withArgs( + withdrawalId, + withdrawal.validatorId, + amountToWithdraw, + amountToWithdraw + ); + + expect(await wS.balanceOf(oSonicVault.address)).to.equal( + vaultBalanceBefore.add(amountToWithdraw) + ); + expect(withdrawalAfter.undelegatedAmount).to.equal(oethUnits("0")); + + expect(await sonicStakingStrategy.pendingWithdrawals()).to.equal( + pendingWithdrawalsBefore.sub(amountToWithdraw), + "Pending withdrawals not reduced by expected amount" + ); + + expect(await sonicStakingStrategy.checkBalance(wS.address)).to.equal( + contractBalanceBefore.sub(amountToWithdraw), + "Strategy checkBalance not reduced by expected amount" + ); + }; + + // const advanceDay = async () => { + // await advanceTime(60 * 60 * 24); + // }; + + const advance10min = async () => { + await advanceTime(60 * 10); + }; + + const advanceWeek = async () => { + await advanceTime(60 * 60 * 24 * 7); + }; + + const advanceSfcEpoch = async (epochsToAdvance) => { + const { sfc, addresses } = await context(); + const currentSealedEpoch = await sfc.currentSealedEpoch(); + const validatorsLength = ( + await sfc.getEpochValidatorIDs(currentSealedEpoch) + ).length; + + const nodeDriverAuthSigner = await impersonateAndFund( + addresses.nodeDriveAuth + ); + for (let i = 0; i < epochsToAdvance; i++) { + // create array filled with 0s + const offlineTimes = Array.from(Array(validatorsLength).keys()).fill( + BigNumber.from("0") + ); + const offlineBlocks = offlineTimes; + const uptimes = Array.from(Array(validatorsLength).keys()).fill( + BigNumber.from("600") + ); + const originatedTxsFee = Array.from(Array(validatorsLength).keys()).fill( + BigNumber.from("2955644249909388016706") + ); + await advance10min(); + console.log("Call seal epoch"); + // await wS + // .connect(clement) + // .withdrawTo(sfc.address, oethUnits("15")); // TransfersNotAllowed + await sfc + .connect(nodeDriverAuthSigner) + .sealEpoch(offlineTimes, offlineBlocks, uptimes, originatedTxsFee); + + console.log("Seal epoch called"); + } + }; }; module.exports = { shouldBehaveLikeASFCStakingStrategy }; diff --git a/contracts/utils/addresses.js b/contracts/utils/addresses.js index 52cbf2eb6f..3f18675d38 100644 --- a/contracts/utils/addresses.js +++ b/contracts/utils/addresses.js @@ -340,6 +340,8 @@ addresses.sonic = {}; addresses.sonic.wS = "0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38"; addresses.sonic.WETH = "0x309C92261178fA0CF748A855e90Ae73FDb79EBc7"; addresses.sonic.SFC = "0xFC00FACE00000000000000000000000000000000"; +addresses.sonic.nodeDriver = "0xd100a01e00000000000000000000000000000001"; +addresses.sonic.nodeDriveAuth = "0xd100ae0000000000000000000000000000000000"; addresses.sonic.validatorRegistrator = "0x531B8D5eD6db72A56cF1238D4cE478E7cB7f2825"; From 6a1a8fd17bd4440b1a74ae8e9b569d3c2942fb1e Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Thu, 9 Jan 2025 10:46:38 +1100 Subject: [PATCH 252/273] prettier --- contracts/test/behaviour/sfcStakingStrategy.js | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/contracts/test/behaviour/sfcStakingStrategy.js b/contracts/test/behaviour/sfcStakingStrategy.js index 794ea31f87..f6f38fc07c 100644 --- a/contracts/test/behaviour/sfcStakingStrategy.js +++ b/contracts/test/behaviour/sfcStakingStrategy.js @@ -282,12 +282,8 @@ const shouldBehaveLikeASFCStakingStrategy = (context) => { // Withdraw the matured undelegated funds from the Sonic Special Fee Contract const withdrawFromSFC = async (withdrawalId, expectedAmountToWithdraw) => { - const { - sonicStakingStrategy, - validatorRegistrator, - wS, - oSonicVault, - } = await context(); + const { sonicStakingStrategy, validatorRegistrator, wS, oSonicVault } = + await context(); console.log("00"); const contractBalanceBefore = await sonicStakingStrategy.checkBalance( From bf2c72b28cbf7aaa0203a768ed14a4139e75d8aa Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Thu, 9 Jan 2025 10:59:02 +1100 Subject: [PATCH 253/273] Fix OSonic unit test deploy after merge with yield delegation --- contracts/deploy/sonic/000_mock.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/contracts/deploy/sonic/000_mock.js b/contracts/deploy/sonic/000_mock.js index cbaf69d446..b0a1773f84 100644 --- a/contracts/deploy/sonic/000_mock.js +++ b/contracts/deploy/sonic/000_mock.js @@ -67,10 +67,8 @@ const deployCore = async () => { // Init OSonic const resolution = ethers.utils.parseUnits("1", 27); const initDataOSonic = cOSonic.interface.encodeFunctionData( - "initialize(string,string,address,uint256)", + "initialize(address,uint256)", [ - "Origin S", // Token Name - "OS", // Token Symbol cOSonicVaultProxy.address, // Origin Sonic Vault resolution, // HighRes ] From 98056a1a085591771b3d0703cd45648af036cd14 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Thu, 9 Jan 2025 14:13:11 +1100 Subject: [PATCH 254/273] Added Fixed Rate Dripper for Sonic --- contracts/contracts/proxies/SonicProxies.sol | 2 +- contracts/deploy/sonic/000_mock.js | 40 ++++- contracts/deploy/sonic/001_origin_sonic.js | 26 ++++ contracts/test/vault/os-vault.sonic.js | 150 +++++++++++++++++-- 4 files changed, 204 insertions(+), 14 deletions(-) diff --git a/contracts/contracts/proxies/SonicProxies.sol b/contracts/contracts/proxies/SonicProxies.sol index aea4267ff2..f4c721c08a 100644 --- a/contracts/contracts/proxies/SonicProxies.sol +++ b/contracts/contracts/proxies/SonicProxies.sol @@ -25,7 +25,7 @@ contract WOSonicProxy is InitializeGovernedUpgradeabilityProxy { } /** - * @notice OSonicDripperProxy delegates calls to a OSonicDripper implementation + * @notice OSonicDripperProxy delegates calls to a FixedRateDripper implementation */ contract OSonicDripperProxy is InitializeGovernedUpgradeabilityProxy { diff --git a/contracts/deploy/sonic/000_mock.js b/contracts/deploy/sonic/000_mock.js index b0a1773f84..9284f22123 100644 --- a/contracts/deploy/sonic/000_mock.js +++ b/contracts/deploy/sonic/000_mock.js @@ -117,6 +117,8 @@ const deployCore = async () => { await cOSonicVault.connect(sGovernor).supportAsset(cWS.address, 0); await cOSonicVault.connect(sGovernor).unpauseCapital(); + // Set withdrawal claim delay to 1 day + await cOSonicVault.connect(sGovernor).setWithdrawalClaimDelay(86400); }; const deployStakingStrategy = async () => { @@ -165,7 +167,42 @@ const deployStakingStrategy = async () => { initSonicStakingStrategy ) ); - console.log("Initialized SonicStakingStrategy proxy and implementation"); +}; + +const deployDripper = async () => { + const { deployerAddr, governorAddr } = await getNamedAccounts(); + const sDeployer = await ethers.provider.getSigner(deployerAddr); + const sGovernor = await ethers.provider.getSigner(governorAddr); + + const cWS = await ethers.getContract("MockWS"); + const cOSonicVaultProxy = await ethers.getContract("OSonicVaultProxy"); + const cOSonicVault = await ethers.getContractAt( + "IVault", + cOSonicVaultProxy.address + ); + + await deployWithConfirmation("OSonicDripperProxy"); + + const cOSonicDripperProxy = await ethers.getContract("OSonicDripperProxy"); + const dFixedRateDripper = await deployWithConfirmation("FixedRateDripper", [ + cOSonicVaultProxy.address, // VaultAddress + cWS.address, + ]); + + // Init the Dripper proxy + // prettier-ignore + await withConfirmation( + cOSonicDripperProxy + .connect(sDeployer)["initialize(address,address,bytes)"]( + dFixedRateDripper.address, + governorAddr, + "0x" + ) + ); + + await withConfirmation( + cOSonicVault.connect(sGovernor).setDripper(cOSonicDripperProxy.address) + ); }; const main = async () => { @@ -173,6 +210,7 @@ const main = async () => { await deployOracleRouter(); await deployCore(); await deployStakingStrategy(); + await deployDripper(); }; main.id = "000_mock"; diff --git a/contracts/deploy/sonic/001_origin_sonic.js b/contracts/deploy/sonic/001_origin_sonic.js index f53190a23c..ea41511666 100644 --- a/contracts/deploy/sonic/001_origin_sonic.js +++ b/contracts/deploy/sonic/001_origin_sonic.js @@ -124,6 +124,8 @@ module.exports = deployOnSonic( console.log("Added vault support of Wrapped S"); await cOSonicVault.connect(sGovernor).unpauseCapital(); console.log("Unpaused capital"); + await cOSonicVault.connect(sGovernor).setWithdrawalClaimDelay(86400); + console.log("withdrawal claim delay set to 1 day"); // Staking Strategy await deployWithConfirmation("SonicStakingStrategyProxy"); @@ -176,6 +178,30 @@ module.exports = deployOnSonic( .setRegistrator(addresses.sonic.validatorRegistrator); console.log("Set registrator"); + // Deploy the Dripper + await deployWithConfirmation("OSonicDripperProxy"); + + const cOSonicDripperProxy = await ethers.getContract("OSonicDripperProxy"); + const dFixedRateDripper = await deployWithConfirmation("FixedRateDripper", [ + cOSonicVaultProxy.address, // VaultAddress + cWS.address, + ]); + + // Init the Dripper proxy + // prettier-ignore + await withConfirmation( + cOSonicDripperProxy + .connect(sDeployer)["initialize(address,address,bytes)"]( + dFixedRateDripper.address, + governorAddr, + "0x" + ) + ); + + await withConfirmation( + cOSonicVault.connect(sGovernor).setDripper(cOSonicDripperProxy.address) + ); + // TODO transfer governor to ? } ); diff --git a/contracts/test/vault/os-vault.sonic.js b/contracts/test/vault/os-vault.sonic.js index f5a2697990..68d1cd1b81 100644 --- a/contracts/test/vault/os-vault.sonic.js +++ b/contracts/test/vault/os-vault.sonic.js @@ -3,6 +3,7 @@ const { parseUnits } = require("ethers/lib/utils"); const { createFixtureLoader } = require("../_fixture"); const { defaultSonicFixture } = require("../_fixture-sonic"); +const { advanceTime } = require("../helpers"); const sonicFixture = createFixtureLoader(defaultSonicFixture); @@ -73,35 +74,35 @@ describe("Origin S Vault", function () { ); }; - describe("Mint", () => { + describe("Vault operations", () => { it("Should mint with wS", async () => { const { oSonicVault, wS, nick } = fixture; const fixtureWithUser = { ...fixture, user: nick }; const dataBefore = await snapData(fixtureWithUser); - const amount = parseUnits("1", 18); - const minOeth = parseUnits("0.8", 18); + const mintAmount = parseUnits("1", 18); + const minOS = parseUnits("0.8", 18); - await wS.connect(nick).approve(oSonicVault.address, amount); + await wS.connect(nick).approve(oSonicVault.address, mintAmount); const tx = await oSonicVault .connect(nick) - .mint(wS.address, amount, minOeth); + .mint(wS.address, mintAmount, minOS); await expect(tx) .to.emit(oSonicVault, "Mint") - .withArgs(nick.address, amount); + .withArgs(nick.address, mintAmount); await assertChangedData( dataBefore, { - oSonicTotalSupply: amount, - oSonicTotalValue: amount, - vaultCheckBalance: amount, - userOSonic: amount, - userWS: amount.mul(-1), - vaultWS: amount, + oSonicTotalSupply: mintAmount, + oSonicTotalValue: mintAmount, + vaultCheckBalance: mintAmount, + userOSonic: mintAmount, + userWS: mintAmount.mul(-1), + vaultWS: mintAmount, queued: 0, claimable: 0, claimed: 0, @@ -111,6 +112,131 @@ describe("Origin S Vault", function () { ); }); + it("Should request withdraw from Vault", async () => { + const { oSonicVault, wS, nick } = fixture; + + // Mint some OSonic + const mintAmount = parseUnits("100", 18); + await wS.connect(nick).approve(oSonicVault.address, mintAmount); + await oSonicVault.connect(nick).mint(wS.address, mintAmount, 0); + + const fixtureWithUser = { ...fixture, user: nick }; + const dataBefore = await snapData(fixtureWithUser); + + const withdrawAmount = parseUnits("90", 18); + const tx = await oSonicVault + .connect(nick) + .requestWithdrawal(withdrawAmount); + + await expect(tx) + .to.emit(oSonicVault, "WithdrawalRequested") + .withArgs(nick.address, 0, withdrawAmount, withdrawAmount); + + const deltaAmount = withdrawAmount.mul(-1); + await assertChangedData( + dataBefore, + { + oSonicTotalSupply: deltaAmount, + oSonicTotalValue: deltaAmount, + vaultCheckBalance: deltaAmount, + userOSonic: deltaAmount, + userWS: 0, + vaultWS: 0, + queued: withdrawAmount, + claimable: 0, + claimed: 0, + nextWithdrawalIndex: 1, + }, + fixtureWithUser + ); + }); + + it("Should claim withdraw from Vault", async () => { + const { oSonicVault, wS, nick } = fixture; + + // Mint some OSonic + const mintAmount = parseUnits("100", 18); + await wS.connect(nick).approve(oSonicVault.address, mintAmount); + await oSonicVault.connect(nick).mint(wS.address, mintAmount, 0); + const withdrawAmount = parseUnits("90", 18); + await oSonicVault.connect(nick).requestWithdrawal(withdrawAmount); + + const fixtureWithUser = { ...fixture, user: nick }; + const dataBefore = await snapData(fixtureWithUser); + + await advanceTime(86400); // 1 day + + const withdrawalId = 0; + const tx = await oSonicVault.connect(nick).claimWithdrawal(withdrawalId); + + await expect(tx) + .to.emit(oSonicVault, "WithdrawalClaimed") + .withArgs(nick.address, withdrawalId, withdrawAmount); + + await assertChangedData( + dataBefore, + { + oSonicTotalSupply: 0, + oSonicTotalValue: 0, + vaultCheckBalance: 0, + userOSonic: 0, + userWS: withdrawAmount, + vaultWS: withdrawAmount.mul(-1), + queued: 0, + claimable: withdrawAmount, + claimed: withdrawAmount, + nextWithdrawalIndex: 0, + }, + fixtureWithUser + ); + }); + + it("Should claim multiple withdrawal from Vault", async () => { + const { oSonicVault, wS, nick } = fixture; + + // Mint some OSonic + const mintAmount = parseUnits("100", 18); + await wS.connect(nick).approve(oSonicVault.address, mintAmount); + await oSonicVault.connect(nick).mint(wS.address, mintAmount, 0); + const withdrawAmount1 = parseUnits("10", 18); + const withdrawAmount2 = parseUnits("20", 18); + const withdrawAmount = withdrawAmount1.add(withdrawAmount2); + await oSonicVault.connect(nick).requestWithdrawal(withdrawAmount1); + await oSonicVault.connect(nick).requestWithdrawal(withdrawAmount2); + + const fixtureWithUser = { ...fixture, user: nick }; + const dataBefore = await snapData(fixtureWithUser); + + await advanceTime(86400); // 1 day + + // Claim both withdrawals + const tx = await oSonicVault.connect(nick).claimWithdrawals([0, 1]); + + await expect(tx) + .to.emit(oSonicVault, "WithdrawalClaimed") + .withArgs(nick.address, 0, withdrawAmount1); + await expect(tx) + .to.emit(oSonicVault, "WithdrawalClaimed") + .withArgs(nick.address, 1, withdrawAmount2); + + await assertChangedData( + dataBefore, + { + oSonicTotalSupply: 0, + oSonicTotalValue: 0, + vaultCheckBalance: 0, + userOSonic: 0, + userWS: withdrawAmount, + vaultWS: withdrawAmount.mul(-1), + queued: 0, + claimable: withdrawAmount, + claimed: withdrawAmount, + nextWithdrawalIndex: 0, + }, + fixtureWithUser + ); + }); + it("Should not support redeem", async () => { const { oSonicVault, wS, nick } = fixture; From d8200447430cddd46a14df7d91ef647f1843e18d Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Thu, 9 Jan 2025 17:28:34 +1100 Subject: [PATCH 255/273] Fixed base unit tests after Fix upgrade script of OETHBase --- contracts/deploy/base/000_mock.js | 4 +--- contracts/deploy/base/021_upgrade_oeth.js | 7 ++++++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/contracts/deploy/base/000_mock.js b/contracts/deploy/base/000_mock.js index e3fa3ce690..af6b617cdc 100644 --- a/contracts/deploy/base/000_mock.js +++ b/contracts/deploy/base/000_mock.js @@ -101,10 +101,8 @@ const deployCore = async () => { // Init OETHb const resolution = ethers.utils.parseUnits("1", 27); const initDataOETHb = cOETHb.interface.encodeFunctionData( - "initialize(string,string,address,uint256)", + "initialize(address,uint256)", [ - "Super OETH", - "superOETHb", // Token Symbol cOETHbVaultProxy.address, // OETHb Vault resolution, // HighRes ] diff --git a/contracts/deploy/base/021_upgrade_oeth.js b/contracts/deploy/base/021_upgrade_oeth.js index c2fd99fae3..5da1c0573e 100644 --- a/contracts/deploy/base/021_upgrade_oeth.js +++ b/contracts/deploy/base/021_upgrade_oeth.js @@ -6,7 +6,12 @@ module.exports = deployOnBaseWithGuardian( deployName: "021_upgrade_oeth", }, async ({ ethers }) => { - const dOETHb = await deployWithConfirmation("OETHBase"); + const dOETHb = await deployWithConfirmation( + "OETHBase", + [], + undefined, + true + ); const cOETHbProxy = await ethers.getContract("OETHBaseProxy"); From 8a4bf9b47712ee3a0c60d7f70e0728d66dac131e Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Thu, 9 Jan 2025 20:01:23 +1100 Subject: [PATCH 256/273] Added Sonic Zapper --- contracts/contracts/vault/OSonicZapper.sol | 138 +++++++++++++++++++++ contracts/deploy/sonic/001_origin_sonic.js | 8 ++ 2 files changed, 146 insertions(+) create mode 100644 contracts/contracts/vault/OSonicZapper.sol diff --git a/contracts/contracts/vault/OSonicZapper.sol b/contracts/contracts/vault/OSonicZapper.sol new file mode 100644 index 0000000000..911c9ff3a3 --- /dev/null +++ b/contracts/contracts/vault/OSonicZapper.sol @@ -0,0 +1,138 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import { IVault } from "../interfaces/IVault.sol"; +import { IWrappedSonic } from "../interfaces/sonic/IWrappedSonic.sol"; +import { IERC4626 } from "../../lib/openzeppelin/interfaces/IERC4626.sol"; + +/** + * @title Zapper for Origin Sonic (OS) tokens + * @author Origin Protocol Inc + */ +contract OSonicZapper { + IERC20 public immutable OS; + IERC4626 public immutable wOS; + IVault public immutable vault; + + IWrappedSonic public constant wS = + IWrappedSonic(0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38); + address private constant ETH_MARKER = + 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; + + event Zap(address indexed minter, address indexed asset, uint256 amount); + + constructor( + address _OS, + address _wOS, + address _vault + ) { + OS = IERC20(_OS); + wOS = IERC4626(_wOS); + vault = IVault(_vault); + + wS.approve(address(_vault), type(uint256).max); + IERC20(_OS).approve(_wOS, type(uint256).max); + } + + /** + * @dev Deposit native S currency and receive Origin Sonic (OS) tokens in return. + * Will verify that the user is sent 1:1 for S. + */ + receive() external payable { + deposit(); + } + + /** + * @dev Deposit native S currency and receive Origin Sonic (OS) tokens in return. + * Will verify that the user is sent 1:1 for S. + * @return Amount of Origin Sonic (OS) tokens sent to user + */ + function deposit() public payable returns (uint256) { + uint256 balance = address(this).balance; + + emit Zap(msg.sender, ETH_MARKER, balance); + + // Wrap native S + wS.deposit{ value: balance }(); + + // Mint Origin Sonic (OS) with Wrapped Sonic (wS) + return _mint(balance, msg.sender); + } + + /** + * @dev Deposit S and receive Wrapped Origin Sonic (wOS) in return + * @param minReceived min amount of Wrapped Origin Sonic (wOS) to receive + * @return Amount of Wrapped Origin Sonic (wOS) tokens sent to user + */ + function depositSForWrappedTokens(uint256 minReceived) + external + payable + returns (uint256) + { + uint256 balance = address(this).balance; + + emit Zap(msg.sender, ETH_MARKER, balance); + + // Wrap S + wS.deposit{ value: balance }(); + + // Mint with Wrapped Sonic + uint256 mintOS = _mint(balance, address(this)); + + // Wrap Origin Sonic (OS) into Wrapped Origin Sonic (wOS) + uint256 mintedWOS = wOS.deposit(mintOS, msg.sender); + + require(mintedWOS >= minReceived, "Zapper: not enough minted"); + + return mintedWOS; + } + + /** + * @dev Deposit Wrapped Sonic (wS) tokens and receive Wrapped Origin Sonic (wOS) tokens in return + * @param wSAmount Amount of Wrapped Sonic (wS) to deposit + * @param minReceived min amount of Wrapped Origin Sonic (wOS) token to receive + * @return Amount of Wrapped Origin Sonic (wOS) tokens sent to user + */ + function depositWSForWrappedTokens(uint256 wSAmount, uint256 minReceived) + external + returns (uint256) + { + // slither-disable-next-line unchecked-transfer unused-return + wS.transferFrom(msg.sender, address(this), wSAmount); + + emit Zap(msg.sender, address(wS), wSAmount); + + // Mint with Wrapped Sonic (wS) + uint256 mintedOS = _mint(wSAmount, address(this)); + + // Wrap Origin Sonic (OS) tokens into Wrapped Origin Sonic (wOS) tokens + uint256 mintedWOS = wOS.deposit(mintedOS, msg.sender); + + require(mintedWOS >= minReceived, "Zapper: not enough minted"); + + return mintedWOS; + } + + /** + * @dev Internal function to mint Origin Sonic (OS) with Wrapped S (wS) + * @param minOS Minimum amount of Origin Sonic (OS) tokens the user can receive + * @param recipient Address that receives the tokens + * @return Amount of Origin Sonic (OS) tokens sent to the recipient + */ + function _mint(uint256 minOS, address recipient) + internal + returns (uint256) + { + uint256 toMint = wS.balanceOf(address(this)); + vault.mint(address(wS), toMint, minOS); + uint256 mintedAmount = OS.balanceOf(address(this)); + require(mintedAmount >= minOS, "Zapper: not enough minted"); + + if (recipient != address(this)) { + require(OS.transfer(recipient, mintedAmount)); + } + + return mintedAmount; + } +} diff --git a/contracts/deploy/sonic/001_origin_sonic.js b/contracts/deploy/sonic/001_origin_sonic.js index ea41511666..d5f5d37e27 100644 --- a/contracts/deploy/sonic/001_origin_sonic.js +++ b/contracts/deploy/sonic/001_origin_sonic.js @@ -202,6 +202,14 @@ module.exports = deployOnSonic( cOSonicVault.connect(sGovernor).setDripper(cOSonicDripperProxy.address) ); + // Deploy the Zapper + await deployWithConfirmation("OSonicZapper", [ + cOSonic.address, + cWOSonic.address, + cOSonicVault.address, + ]); + console.log("Deployed Origin Sonic Zapper"); + // TODO transfer governor to ? } ); From 3b087422da7014dc05bc13983643f75e4a767129 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Thu, 9 Jan 2025 21:43:57 +1100 Subject: [PATCH 257/273] Added Sonic contract dependency diagram --- contracts/docs/plantuml/sonicContracts.png | Bin 0 -> 24169 bytes contracts/docs/plantuml/sonicContracts.puml | 66 ++++++++++++++++++++ 2 files changed, 66 insertions(+) create mode 100644 contracts/docs/plantuml/sonicContracts.png create mode 100644 contracts/docs/plantuml/sonicContracts.puml diff --git a/contracts/docs/plantuml/sonicContracts.png b/contracts/docs/plantuml/sonicContracts.png new file mode 100644 index 0000000000000000000000000000000000000000..2e9de7c92b0eeb3716b3dbcf571b2d06f835371f GIT binary patch literal 24169 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�h$lQ0) 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 literal 0 HcmV?d00001 diff --git a/contracts/docs/plantuml/sonicContracts.puml b/contracts/docs/plantuml/sonicContracts.puml new file mode 100644 index 0000000000..c4a13e6c83 --- /dev/null +++ b/contracts/docs/plantuml/sonicContracts.puml @@ -0,0 +1,66 @@ +@startuml + +!$originColor = DeepSkyBlue +' !$originColor = WhiteSmoke +!$newColor = LightGreen +!$changedColor = Orange +!$thirdPartyColor = WhiteSmoke + +' legend +' blue - Origin +' ' green - new +' ' orange - changed +' white - 3rd Party +' end legend + +title "Sonic Contract Dependencies" + +object "OSonicZapper" as zap <> #$originColor { + assets: S, wS +} + +object "WOSonic" as wos <><> #$originColor { + asset: OS + symbol: wOS + name: Wrapped Origin Sonic +} + +object "OSonicDripper" as drip <><> #$originColor { + asset: wS +} + +object "OSonicVaultValueChecker" as checker <> #$originColor { +} + +object "OSonic" as os <><> #$originColor { + symbol: OS + name: Origin Sonic +} + +object "OSonicVault" as vault <><> #$originColor { + asset: wS +} + +object "SonicStakingStrategy" as stakeStrat <><> #$originColor { + asset: wS +} + +' object "AMOStrategy" as amoStrat <><> #$originColor { +' asset: wS +' reward: ? +' } + +wos <. zap +zap ..> os +zap ..> vault + +checker ..> vault + +wos ..> os +os <.> vault +vault <.> drip +vault <...> stakeStrat +' vault <...> amoStrat + + +@enduml \ No newline at end of file From 634b0966db7e078a40fe619703046c163d4bfbf6 Mon Sep 17 00:00:00 2001 From: Domen Grabec Date: Thu, 9 Jan 2025 15:01:08 +0100 Subject: [PATCH 258/273] add withdrawal fork tests --- .../test/behaviour/sfcStakingStrategy.js | 130 +++++++++++++++--- 1 file changed, 111 insertions(+), 19 deletions(-) diff --git a/contracts/test/behaviour/sfcStakingStrategy.js b/contracts/test/behaviour/sfcStakingStrategy.js index 794ea31f87..3dd1aa4f13 100644 --- a/contracts/test/behaviour/sfcStakingStrategy.js +++ b/contracts/test/behaviour/sfcStakingStrategy.js @@ -159,13 +159,79 @@ const shouldBehaveLikeASFCStakingStrategy = (context) => { await withdrawFromSFC(withdrawalId, amount); }); - it("Can not withdraw too soon", async () => {}); + it("Can not withdraw too soon", async () => { + const amount = oethUnits("15000"); + await depositTokenAmount(amount); + await delegateTokenAmount(amount, 0, true); + const withdrawalId = await undelegateTokenAmount(amount, 0); + await advanceWeek(); - it("Can withdraw multiple times", async () => {}); + await withdrawFromSFC( + withdrawalId, + amount, + { expectedError: "NotEnoughTimePassed()" } + ); - it("Incorrect withdrawal ID should revert", async () => {}); + }); + + it("Can not withdraw with too little epochs passing", async () => { + const amount = oethUnits("15000"); + await depositTokenAmount(amount); + await delegateTokenAmount(amount, 0, true); + const withdrawalId = await undelegateTokenAmount(amount, 0); + await advanceWeek(); + await advanceWeek(); + + await withdrawFromSFC( + withdrawalId, + amount, + { advanceSufficientEpochs: false, expectedError: "NotEnoughEpochsPassed()" } + ); + + }); + + it("Can withdraw multiple times", async () => { + const amount = oethUnits("15000"); + const smallAmount = oethUnits("5000"); + await depositTokenAmount(amount); + await delegateTokenAmount(amount, 0, true); + const withdrawalId1 = await undelegateTokenAmount(smallAmount, 0); + const withdrawalId2 = await undelegateTokenAmount(smallAmount, 0); + const withdrawalId3 = await undelegateTokenAmount(smallAmount, 0); + await advanceWeek(); + await advanceWeek(); + await withdrawFromSFC(withdrawalId1, smallAmount); + // skip epoch advancement + await withdrawFromSFC(withdrawalId2, smallAmount, { skipEpochAdvancement: true }); + // skip epoch advancement + await withdrawFromSFC(withdrawalId3, smallAmount, { skipEpochAdvancement: true }); + }); + + it("Incorrect withdrawal ID should revert", async () => { + const amount = oethUnits("15000"); + await depositTokenAmount(amount); + await delegateTokenAmount(amount, 0, true); + const withdrawalId = await undelegateTokenAmount(amount, 0); + await withdrawFromSFC(withdrawalId + 10, amount, { + skipEpochAdvancement: true, + expectedRevert: "Invalid withdrawId" + }); + }); + + it("Can not withdraw with the same ID twice", async () => { + const amount = oethUnits("15000"); + await depositTokenAmount(amount); + await delegateTokenAmount(amount, 0, true); + const withdrawalId = await undelegateTokenAmount(amount, 0); + await advanceWeek(); + await advanceWeek(); + await withdrawFromSFC(withdrawalId, amount); + await withdrawFromSFC(withdrawalId, amount, { + skipEpochAdvancement: true, + expectedRevert: "Already withdrawn" + }); + }); - it("Can not withdraw with the same ID twice", async () => {}); }); // deposit the amount into the Sonic Staking Strategy @@ -281,7 +347,16 @@ const shouldBehaveLikeASFCStakingStrategy = (context) => { }; // Withdraw the matured undelegated funds from the Sonic Special Fee Contract - const withdrawFromSFC = async (withdrawalId, expectedAmountToWithdraw) => { + const withdrawFromSFC = async ( + withdrawalId, + expectedAmountToWithdraw, + { + advanceSufficientEpochs = true, + skipEpochAdvancement = false, + expectedError = false, + expectedRevert = false + } = {} + ) => { const { sonicStakingStrategy, validatorRegistrator, @@ -289,7 +364,6 @@ const shouldBehaveLikeASFCStakingStrategy = (context) => { oSonicVault, } = await context(); - console.log("00"); const contractBalanceBefore = await sonicStakingStrategy.checkBalance( wS.address ); @@ -299,12 +373,32 @@ const shouldBehaveLikeASFCStakingStrategy = (context) => { const amountToWithdraw = withdrawal.undelegatedAmount; const pendingWithdrawalsBefore = await sonicStakingStrategy.pendingWithdrawals(); - expect(expectedAmountToWithdraw).to.equal(amountToWithdraw); + if (!expectedError && !expectedRevert) { + expect(expectedAmountToWithdraw).to.equal(amountToWithdraw); + } - console.log("ADVANCE EPOCH"); - await advanceSfcEpoch(MIN_WITHDRAWAL_EPOCH_ADVANCE); + if (!skipEpochAdvancement) { + if (!advanceSufficientEpochs) { + await advanceSfcEpoch(1); + } else { + await advanceSfcEpoch(MIN_WITHDRAWAL_EPOCH_ADVANCE); + } + } + + if (expectedError) { + await expect(sonicStakingStrategy + .connect(validatorRegistrator) + .withdrawFromSFC(withdrawalId) + ).to.be.revertedWithCustomError(expectedError); + return; + } else if (expectedRevert) { + await expect(sonicStakingStrategy + .connect(validatorRegistrator) + .withdrawFromSFC(withdrawalId) + ).to.be.revertedWith(expectedRevert); + return; + } - console.log("ADVANCE EPOCH DONE"); // checkBalance should be smaller by withdrawn amount const tx = await sonicStakingStrategy .connect(validatorRegistrator) @@ -354,13 +448,14 @@ const shouldBehaveLikeASFCStakingStrategy = (context) => { const advanceSfcEpoch = async (epochsToAdvance) => { const { sfc, addresses } = await context(); const currentSealedEpoch = await sfc.currentSealedEpoch(); - const validatorsLength = ( - await sfc.getEpochValidatorIDs(currentSealedEpoch) - ).length; + const epochValidators = await sfc.getEpochValidatorIDs(currentSealedEpoch); + const validatorsLength = (epochValidators).length; const nodeDriverAuthSigner = await impersonateAndFund( addresses.nodeDriveAuth ); + + console.log(`Preparing to seal ${epochsToAdvance} epoch(s) on Sonic`); for (let i = 0; i < epochsToAdvance; i++) { // create array filled with 0s const offlineTimes = Array.from(Array(validatorsLength).keys()).fill( @@ -374,15 +469,12 @@ const shouldBehaveLikeASFCStakingStrategy = (context) => { BigNumber.from("2955644249909388016706") ); await advance10min(); - console.log("Call seal epoch"); - // await wS - // .connect(clement) - // .withdrawTo(sfc.address, oethUnits("15")); // TransfersNotAllowed await sfc .connect(nodeDriverAuthSigner) .sealEpoch(offlineTimes, offlineBlocks, uptimes, originatedTxsFee); - - console.log("Seal epoch called"); + await sfc + .connect(nodeDriverAuthSigner) + .sealEpochValidators(epochValidators); } }; }; From 648c99ad93c539fbfb184ca9f5966a121791c6c8 Mon Sep 17 00:00:00 2001 From: Domen Grabec Date: Thu, 9 Jan 2025 23:27:59 +0100 Subject: [PATCH 259/273] add restaking test --- .../test/behaviour/sfcStakingStrategy.js | 122 +++++++++++++----- contracts/test/vault/os-vault.sonic.js | 9 ++ 2 files changed, 100 insertions(+), 31 deletions(-) diff --git a/contracts/test/behaviour/sfcStakingStrategy.js b/contracts/test/behaviour/sfcStakingStrategy.js index 3c6914e258..ebfc3aa638 100644 --- a/contracts/test/behaviour/sfcStakingStrategy.js +++ b/contracts/test/behaviour/sfcStakingStrategy.js @@ -100,6 +100,39 @@ const shouldBehaveLikeASFCStakingStrategy = (context) => { await delegateTokenAmount(amount, 0, true); }); + it("Should earn rewards as epochs pass", async () => { + const { sonicStakingStrategy, wS } = await context(); + + const amount = oethUnits("15000"); + await depositTokenAmount(amount); + await delegateTokenAmount(amount, 0, true); + + const balanceBefore = await sonicStakingStrategy.checkBalance(wS.address); + await advanceSfcEpoch(1); + expect(await sonicStakingStrategy.checkBalance(wS.address)).to.be.gt( + balanceBefore + ); + }); + + it("Should be able to restake the earned rewards", async () => { + const { sonicStakingStrategy, wS, testValidatorIds } = await context(); + + const amount = oethUnits("15000"); + await depositTokenAmount(amount); + await delegateTokenAmount(amount, 0, true); + await advanceSfcEpoch(1); + + const tx = await sonicStakingStrategy.restakeRewards([testValidatorIds[0]]); + + await expect(tx).to.emittedEvent("Deposit", [ + wS.address, + AddressZero, + (totalRewards) => { + expect(totalRewards).to.be.gt(oethUnits("0")) + } + ]); + }); + it("Should accept and handle S token allocation and delegation to all delegators", async () => { const depositAmount = oethUnits("20000"); const delegateAmount = oethUnits("5000"); @@ -109,6 +142,33 @@ const shouldBehaveLikeASFCStakingStrategy = (context) => { await delegateTokenAmount(delegateAmount, 2); await delegateTokenAmount(delegateAmount, 3); }); + + it("Should not allow delegation to unsupported validator", async () => { + const amount = oethUnits("5000"); + await depositTokenAmount(amount); + + const { sonicStakingStrategy, validatorRegistrator } = await context(); + + const tx = sonicStakingStrategy + .connect(validatorRegistrator) + .delegate(1, amount); + + await expect(tx).to.be.revertedWith("Validator not supported"); + }); + + it("Should not allow delegation of 0 amount", async () => { + const amount = oethUnits("5000"); + await depositTokenAmount(amount); + + const { sonicStakingStrategy, validatorRegistrator, testValidatorIds } = + await context(); + + const tx = sonicStakingStrategy + .connect(validatorRegistrator) + .delegate(testValidatorIds[0], oethUnits("0")); + + await expect(tx).to.be.revertedWith("Must delegate something"); + }); }); describe("Undelegation/Withdrawal", function () { @@ -166,12 +226,9 @@ const shouldBehaveLikeASFCStakingStrategy = (context) => { const withdrawalId = await undelegateTokenAmount(amount, 0); await advanceWeek(); - await withdrawFromSFC( - withdrawalId, - amount, - { expectedError: "NotEnoughTimePassed()" } - ); - + await withdrawFromSFC(withdrawalId, amount, { + expectedError: "NotEnoughTimePassed()", + }); }); it("Can not withdraw with too little epochs passing", async () => { @@ -182,12 +239,10 @@ const shouldBehaveLikeASFCStakingStrategy = (context) => { await advanceWeek(); await advanceWeek(); - await withdrawFromSFC( - withdrawalId, - amount, - { advanceSufficientEpochs: false, expectedError: "NotEnoughEpochsPassed()" } - ); - + await withdrawFromSFC(withdrawalId, amount, { + advanceSufficientEpochs: false, + expectedError: "NotEnoughEpochsPassed()", + }); }); it("Can withdraw multiple times", async () => { @@ -202,9 +257,13 @@ const shouldBehaveLikeASFCStakingStrategy = (context) => { await advanceWeek(); await withdrawFromSFC(withdrawalId1, smallAmount); // skip epoch advancement - await withdrawFromSFC(withdrawalId2, smallAmount, { skipEpochAdvancement: true }); + await withdrawFromSFC(withdrawalId2, smallAmount, { + skipEpochAdvancement: true, + }); // skip epoch advancement - await withdrawFromSFC(withdrawalId3, smallAmount, { skipEpochAdvancement: true }); + await withdrawFromSFC(withdrawalId3, smallAmount, { + skipEpochAdvancement: true, + }); }); it("Incorrect withdrawal ID should revert", async () => { @@ -214,7 +273,7 @@ const shouldBehaveLikeASFCStakingStrategy = (context) => { const withdrawalId = await undelegateTokenAmount(amount, 0); await withdrawFromSFC(withdrawalId + 10, amount, { skipEpochAdvancement: true, - expectedRevert: "Invalid withdrawId" + expectedRevert: "Invalid withdrawId", }); }); @@ -228,10 +287,9 @@ const shouldBehaveLikeASFCStakingStrategy = (context) => { await withdrawFromSFC(withdrawalId, amount); await withdrawFromSFC(withdrawalId, amount, { skipEpochAdvancement: true, - expectedRevert: "Already withdrawn" + expectedRevert: "Already withdrawn", }); }); - }); // deposit the amount into the Sonic Staking Strategy @@ -350,13 +408,13 @@ const shouldBehaveLikeASFCStakingStrategy = (context) => { const withdrawFromSFC = async ( withdrawalId, expectedAmountToWithdraw, - { - advanceSufficientEpochs = true, - skipEpochAdvancement = false, - expectedError = false, - expectedRevert = false - } = {} - ) => { + { + advanceSufficientEpochs = true, + skipEpochAdvancement = false, + expectedError = false, + expectedRevert = false, + } = {} + ) => { const { sonicStakingStrategy, validatorRegistrator, wS, oSonicVault } = await context(); @@ -382,15 +440,17 @@ const shouldBehaveLikeASFCStakingStrategy = (context) => { } if (expectedError) { - await expect(sonicStakingStrategy - .connect(validatorRegistrator) - .withdrawFromSFC(withdrawalId) + await expect( + sonicStakingStrategy + .connect(validatorRegistrator) + .withdrawFromSFC(withdrawalId) ).to.be.revertedWithCustomError(expectedError); return; } else if (expectedRevert) { - await expect(sonicStakingStrategy - .connect(validatorRegistrator) - .withdrawFromSFC(withdrawalId) + await expect( + sonicStakingStrategy + .connect(validatorRegistrator) + .withdrawFromSFC(withdrawalId) ).to.be.revertedWith(expectedRevert); return; } @@ -445,7 +505,7 @@ const shouldBehaveLikeASFCStakingStrategy = (context) => { const { sfc, addresses } = await context(); const currentSealedEpoch = await sfc.currentSealedEpoch(); const epochValidators = await sfc.getEpochValidatorIDs(currentSealedEpoch); - const validatorsLength = (epochValidators).length; + const validatorsLength = epochValidators.length; const nodeDriverAuthSigner = await impersonateAndFund( addresses.nodeDriveAuth diff --git a/contracts/test/vault/os-vault.sonic.js b/contracts/test/vault/os-vault.sonic.js index 68d1cd1b81..6c93300f76 100644 --- a/contracts/test/vault/os-vault.sonic.js +++ b/contracts/test/vault/os-vault.sonic.js @@ -422,4 +422,13 @@ describe("Origin S Vault", function () { await expect(tx).to.be.revertedWith("unsupported function"); }); }); + + describe("Other function checks", function () { + it("Should not allow checkBalance with incorrect asset", async () => { + const { sonicStakingStrategy, nick } = fixture; + + const tx = sonicStakingStrategy.checkBalance(nick.address); + await expect(tx).to.be.revertedWith("Unsupported asset"); + }); + }); }); From c920ca986ed3751b9d62e960615e88d9a7b5c43d Mon Sep 17 00:00:00 2001 From: Domen Grabec Date: Thu, 9 Jan 2025 23:53:13 +0100 Subject: [PATCH 260/273] add withdrawal timestamp to the withdrawal struct --- .../contracts/strategies/sonic/SonicValidatorDelegator.sol | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/contracts/contracts/strategies/sonic/SonicValidatorDelegator.sol b/contracts/contracts/strategies/sonic/SonicValidatorDelegator.sol index 01729b6b3b..d51f06bb86 100644 --- a/contracts/contracts/strategies/sonic/SonicValidatorDelegator.sol +++ b/contracts/contracts/strategies/sonic/SonicValidatorDelegator.sol @@ -29,6 +29,7 @@ abstract contract SonicValidatorDelegator is InitializableAbstractStrategy { struct WithdrawRequest { uint256 validatorId; uint256 undelegatedAmount; + uint256 timestamp; } /// @notice Mapping of withdrawIds to validatorIds and undelegatedAmounts mapping(uint256 => WithdrawRequest) public withdrawals; @@ -164,7 +165,8 @@ abstract contract SonicValidatorDelegator is InitializableAbstractStrategy { withdrawals[withdrawId] = WithdrawRequest( validatorId, - undelegateAmount + undelegateAmount, + block.timestamp ); pendingWithdrawals += undelegateAmount; From ad65a5a92a482f7aaae9161cc9b2a73f88cc617c Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Fri, 10 Jan 2025 11:55:15 +1100 Subject: [PATCH 261/273] Updated Sonic token metadata --- contracts/contracts/token/OSonic.sol | 2 +- contracts/contracts/token/WOSonic.sol | 2 +- contracts/test/vault/os-vault.sonic.js | 17 +++++++++++++++++ 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/contracts/contracts/token/OSonic.sol b/contracts/contracts/token/OSonic.sol index ed46724e03..9ee4a6c81d 100644 --- a/contracts/contracts/token/OSonic.sol +++ b/contracts/contracts/token/OSonic.sol @@ -13,6 +13,6 @@ contract OSonic is OUSD { } function name() external pure override returns (string memory) { - return "Origin S"; + return "Origin Sonic"; } } diff --git a/contracts/contracts/token/WOSonic.sol b/contracts/contracts/token/WOSonic.sol index ce5a2f9d32..a8c2c1f80e 100644 --- a/contracts/contracts/token/WOSonic.sol +++ b/contracts/contracts/token/WOSonic.sol @@ -32,7 +32,7 @@ contract WOSonic is ERC4626, Governable, Initializable { } function name() public view virtual override returns (string memory) { - return "Wrapped Origin S"; + return "Wrapped Origin Sonic"; } function symbol() public view virtual override returns (string memory) { diff --git a/contracts/test/vault/os-vault.sonic.js b/contracts/test/vault/os-vault.sonic.js index 6c93300f76..600ba875b8 100644 --- a/contracts/test/vault/os-vault.sonic.js +++ b/contracts/test/vault/os-vault.sonic.js @@ -74,6 +74,23 @@ describe("Origin S Vault", function () { ); }; + describe("Sonic tokens", () => { + it("Should read Origin Sonic metadata", async () => { + const { oSonic } = fixture; + + expect(await oSonic.name()).to.equal("Origin Sonic"); + expect(await oSonic.symbol()).to.equal("OS"); + expect(await oSonic.decimals()).to.equal(18); + }); + it("Should read Wrapped Origin Sonic metadata", async () => { + const { wOSonic } = fixture; + + expect(await wOSonic.name()).to.equal("Wrapped Origin Sonic"); + expect(await wOSonic.symbol()).to.equal("wOS"); + expect(await wOSonic.decimals()).to.equal(18); + }); + }); + describe("Vault operations", () => { it("Should mint with wS", async () => { const { oSonicVault, wS, nick } = fixture; From ce6d461886a86a11b5656c75e105215d8ae083b5 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Fri, 10 Jan 2025 11:55:33 +1100 Subject: [PATCH 262/273] prettier --- contracts/test/behaviour/sfcStakingStrategy.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/contracts/test/behaviour/sfcStakingStrategy.js b/contracts/test/behaviour/sfcStakingStrategy.js index ebfc3aa638..b10e6f09d0 100644 --- a/contracts/test/behaviour/sfcStakingStrategy.js +++ b/contracts/test/behaviour/sfcStakingStrategy.js @@ -122,14 +122,16 @@ const shouldBehaveLikeASFCStakingStrategy = (context) => { await delegateTokenAmount(amount, 0, true); await advanceSfcEpoch(1); - const tx = await sonicStakingStrategy.restakeRewards([testValidatorIds[0]]); + const tx = await sonicStakingStrategy.restakeRewards([ + testValidatorIds[0], + ]); await expect(tx).to.emittedEvent("Deposit", [ wS.address, AddressZero, (totalRewards) => { - expect(totalRewards).to.be.gt(oethUnits("0")) - } + expect(totalRewards).to.be.gt(oethUnits("0")); + }, ]); }); From c76556ade776b4d5aa2ea8160a15b53e8b29fe12 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Fri, 10 Jan 2025 12:17:59 +1100 Subject: [PATCH 263/273] Update Natspec Added governor transfer unit tests --- contracts/contracts/token/OSonic.sol | 2 +- contracts/contracts/token/WOSonic.sol | 5 ++- .../contracts/vault/OSonicVaultAdmin.sol | 2 +- contracts/contracts/vault/OSonicVaultCore.sol | 2 +- contracts/test/vault/os-vault.sonic.js | 35 +++++++++++++++++++ 5 files changed, 40 insertions(+), 6 deletions(-) diff --git a/contracts/contracts/token/OSonic.sol b/contracts/contracts/token/OSonic.sol index 9ee4a6c81d..bf5314d2e6 100644 --- a/contracts/contracts/token/OSonic.sol +++ b/contracts/contracts/token/OSonic.sol @@ -4,7 +4,7 @@ pragma solidity ^0.8.0; import { OUSD } from "./OUSD.sol"; /** - * @title Origin S (OS) Token Contract on Sonic + * @title Origin Sonic (OS) token on Sonic * @author Origin Protocol Inc */ contract OSonic is OUSD { diff --git a/contracts/contracts/token/WOSonic.sol b/contracts/contracts/token/WOSonic.sol index a8c2c1f80e..28487394df 100644 --- a/contracts/contracts/token/WOSonic.sol +++ b/contracts/contracts/token/WOSonic.sol @@ -11,10 +11,9 @@ import { Initializable } from "../utils/Initializable.sol"; import { OSonic } from "./OSonic.sol"; /** - * @title Wrapped Origin S Token contract on Sonic (wOS) + * @title Wrapped Origin Sonic (wOS) token on Sonic * @author Origin Protocol Inc */ - contract WOSonic is ERC4626, Governable, Initializable { using SafeERC20 for IERC20; @@ -49,7 +48,7 @@ contract WOSonic is ERC4626, Governable, Initializable { external onlyGovernor { - require(asset_ != address(asset()), "Cannot collect Origin S"); + require(asset_ != address(asset()), "Cannot collect OS"); IERC20(asset_).safeTransfer(governor(), amount_); } } diff --git a/contracts/contracts/vault/OSonicVaultAdmin.sol b/contracts/contracts/vault/OSonicVaultAdmin.sol index fbc67957db..11cb133a43 100644 --- a/contracts/contracts/vault/OSonicVaultAdmin.sol +++ b/contracts/contracts/vault/OSonicVaultAdmin.sol @@ -4,7 +4,7 @@ pragma solidity ^0.8.0; import { OETHVaultAdmin } from "./OETHVaultAdmin.sol"; /** - * @title Origin S VaultAdmin Contract on Sonic + * @title Origin Sonic VaultAdmin contract on Sonic * @author Origin Protocol Inc */ contract OSonicVaultAdmin is OETHVaultAdmin { diff --git a/contracts/contracts/vault/OSonicVaultCore.sol b/contracts/contracts/vault/OSonicVaultCore.sol index bc42fd9afd..fd1da2c03f 100644 --- a/contracts/contracts/vault/OSonicVaultCore.sol +++ b/contracts/contracts/vault/OSonicVaultCore.sol @@ -4,7 +4,7 @@ pragma solidity ^0.8.0; import { OETHVaultCore } from "./OETHVaultCore.sol"; /** - * @title Origin S VaultCore contract on Sonic + * @title Origin Sonic VaultCore contract on Sonic * @author Origin Protocol Inc */ contract OSonicVaultCore is OETHVaultCore { diff --git a/contracts/test/vault/os-vault.sonic.js b/contracts/test/vault/os-vault.sonic.js index 600ba875b8..c6c3cf3640 100644 --- a/contracts/test/vault/os-vault.sonic.js +++ b/contracts/test/vault/os-vault.sonic.js @@ -1,4 +1,5 @@ const { expect } = require("chai"); +const { deployWithConfirmation } = require("../../utils/deploy"); const { parseUnits } = require("ethers/lib/utils"); const { createFixtureLoader } = require("../_fixture"); @@ -89,6 +90,40 @@ describe("Origin S Vault", function () { expect(await wOSonic.symbol()).to.equal("wOS"); expect(await wOSonic.decimals()).to.equal(18); }); + + describe("governor transfers", () => { + const amount = parseUnits("1000", 18); + let weth; + beforeEach(async () => { + const { wOSonic } = fixture; + + await deployWithConfirmation("MockWETH", []); + weth = await ethers.getContract("MockWETH"); + await weth.mint(amount); + await weth.transfer(wOSonic.address, amount); + }); + it("Should allow transfer of arbitrary token by Governor", async () => { + const { wOSonic, governor } = fixture; + + await wOSonic.connect(governor).transferToken(weth.address, amount); + await expect(governor).has.a.balanceOf(amount, weth); + }); + it("Should not allow transfer of arbitrary token by non-Governor", async () => { + const { wOSonic, nick } = fixture; + + // Naughty Nick + await expect( + wOSonic.connect(nick).transferToken(weth.address, amount) + ).to.be.revertedWith("Caller is not the Governor"); + }); + it("Should not allow transfer of Origin Sonic token by governor", async () => { + const { oSonic, wOSonic, governor } = fixture; + + await expect( + wOSonic.connect(governor).transferToken(oSonic.address, amount) + ).to.be.revertedWith("Cannot collect OS"); + }); + }); }); describe("Vault operations", () => { From 07b1a519f628d9dabe61021f0b185beb47858f3c Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Fri, 10 Jan 2025 12:42:12 +1100 Subject: [PATCH 264/273] Added VaultValueChecker to Sonic deploy script --- contracts/deploy/sonic/001_origin_sonic.js | 8 ++++++++ contracts/docs/plantuml/sonicContracts.png | Bin 24169 -> 28851 bytes contracts/docs/plantuml/sonicContracts.puml | 9 +++++++-- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/contracts/deploy/sonic/001_origin_sonic.js b/contracts/deploy/sonic/001_origin_sonic.js index d5f5d37e27..7611f8d32a 100644 --- a/contracts/deploy/sonic/001_origin_sonic.js +++ b/contracts/deploy/sonic/001_origin_sonic.js @@ -210,6 +210,14 @@ module.exports = deployOnSonic( ]); console.log("Deployed Origin Sonic Zapper"); + // Deploy the VaultValueChecker + await deployWithConfirmation("VaultValueChecker", [ + cOSonicVault.address, // Origin Sonic Vault + cOSonic.address, // Origin Sonic token + ]); + const vaultValueChecker = await ethers.getContract("VaultValueChecker"); + console.log("Deployed Vault Value Checker", vaultValueChecker.address); + // TODO transfer governor to ? } ); diff --git a/contracts/docs/plantuml/sonicContracts.png b/contracts/docs/plantuml/sonicContracts.png index 2e9de7c92b0eeb3716b3dbcf571b2d06f835371f..0241cdefc550132c3dcfb803897526f8925daff4 100644 GIT binary patch literal 28851 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 Wg;sonYIPQ=)!dbk7tgt^@9|#+s#(PV literal 24169 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�h$lQ0) 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 diff --git a/contracts/docs/plantuml/sonicContracts.puml b/contracts/docs/plantuml/sonicContracts.puml index c4a13e6c83..6946244815 100644 --- a/contracts/docs/plantuml/sonicContracts.puml +++ b/contracts/docs/plantuml/sonicContracts.puml @@ -29,7 +29,7 @@ object "OSonicDripper" as drip <><> #$originColor { asset: wS } -object "OSonicVaultValueChecker" as checker <> #$originColor { +object "VaultValueChecker" as checker <> #$originColor { } object "OSonic" as os <><> #$originColor { @@ -45,6 +45,10 @@ object "SonicStakingStrategy" as stakeStrat <><> #$originColor { asset: wS } +object "Special Fee Contract" as sfc <><> { + asset: S +} + ' object "AMOStrategy" as amoStrat <><> #$originColor { ' asset: wS ' reward: ? @@ -59,7 +63,8 @@ checker ..> vault wos ..> os os <.> vault vault <.> drip -vault <...> stakeStrat +vault <..> stakeStrat +stakeStrat ..> sfc ' vault <...> amoStrat From 3dcdcc0fd6544346d5081a8e85b137629e97cad4 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Fri, 10 Jan 2025 12:52:44 +1100 Subject: [PATCH 265/273] Added phase 2 contracts to Sonic contract dependencies --- contracts/docs/plantuml/sonicContracts.png | Bin 28851 -> 44501 bytes contracts/docs/plantuml/sonicContracts.puml | 35 +++++++++++++------- 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/contracts/docs/plantuml/sonicContracts.png b/contracts/docs/plantuml/sonicContracts.png index 0241cdefc550132c3dcfb803897526f8925daff4..78ea2c39d474e7ad0f1a81849b104c9ff7618670 100644 GIT binary patch literal 44501 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 Wg;sonYIPQ=)!dbk7tgt^@9|#+s#(PV diff --git a/contracts/docs/plantuml/sonicContracts.puml b/contracts/docs/plantuml/sonicContracts.puml index 6946244815..29c25d2d2e 100644 --- a/contracts/docs/plantuml/sonicContracts.puml +++ b/contracts/docs/plantuml/sonicContracts.puml @@ -1,17 +1,19 @@ @startuml !$originColor = DeepSkyBlue +!$phase2 = Yellow ' !$originColor = WhiteSmoke !$newColor = LightGreen !$changedColor = Orange !$thirdPartyColor = WhiteSmoke -' legend -' blue - Origin -' ' green - new -' ' orange - changed -' white - 3rd Party -' end legend +legend +blue - Origin +' green - new +' orange - changed +yellow - phase2 +white - 3rd Party +end legend title "Sonic Contract Dependencies" @@ -49,10 +51,14 @@ object "Special Fee Contract" as sfc <><> { asset: S } -' object "AMOStrategy" as amoStrat <><> #$originColor { -' asset: wS -' reward: ? -' } +object "AMOStrategy" as amoStrat <><> #$phase2 { + asset: wS + reward: ? +} + +object "OSonicHarvester" as harv <><> #$phase2 { + rewards: ? +} wos <. zap zap ..> os @@ -63,9 +69,14 @@ checker ..> vault wos ..> os os <.> vault vault <.> drip -vault <..> stakeStrat +vault <...> stakeStrat stakeStrat ..> sfc -' vault <...> amoStrat +vault <...> amoStrat + +vault <.. harv +drip <.. harv + +harv <..> amoStrat @enduml \ No newline at end of file From 2d60303afadd4b59b420b3e798d9adf027c6e137 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Fri, 10 Jan 2025 13:44:03 +1100 Subject: [PATCH 266/273] Generated Sonic contract diagrams Updated existing OToken diagrams after Yield Delegation --- .../contracts/strategies/sonic/README.md | 15 + contracts/contracts/token/README.md | 34 ++ contracts/docs/OETHBaseHierarchy.svg | 102 ++--- contracts/docs/OETHBaseSquashed.svg | 168 ++++---- contracts/docs/OETHBaseStorage.svg | 150 ++++---- contracts/docs/OETHHierarchy.svg | 96 ++--- contracts/docs/OETHSquashed.svg | 181 ++++----- contracts/docs/OETHStorage.svg | 150 ++++---- contracts/docs/OSonicHierarchy.svg | 46 +++ contracts/docs/OSonicSquashed.svg | 103 +++++ contracts/docs/OSonicStorage.svg | 81 ++++ contracts/docs/OSonicVaultAdminSquashed.svg | 165 ++++++++ contracts/docs/OSonicVaultCoreSquashed.svg | 173 +++++++++ contracts/docs/OSonicVaultStorage.svg | 359 ++++++++++++++++++ contracts/docs/OUSDHierarchy.svg | 8 +- contracts/docs/OUSDSquashed.svg | 183 +++++---- contracts/docs/OUSDStorage.svg | 132 +++---- .../docs/SonicStakingStrategyHierarchy.svg | 75 ++++ .../docs/SonicStakingStrategySquashed.svg | 124 ++++++ .../docs/SonicStakingStrategyStorage.svg | 208 ++++++++++ contracts/docs/WOETHBaseHierarchy.svg | 314 ++++++--------- contracts/docs/WOETHHierarchy.svg | 286 +++++--------- contracts/docs/WOETHSquashed.svg | 4 +- contracts/docs/WOETHStorage.svg | 122 +++--- contracts/docs/WOSonicHierarchy.svg | 126 ++++++ contracts/docs/WOSonicSquashed.svg | 101 +++++ contracts/docs/WOSonicStorage.svg | 55 +++ contracts/docs/WOUSDHierarchy.svg | 268 +++++-------- contracts/docs/WOUSDSquashed.svg | 4 +- contracts/docs/WOUSDStorage.svg | 122 +++--- contracts/docs/generate.sh | 42 +- 31 files changed, 2601 insertions(+), 1396 deletions(-) create mode 100644 contracts/contracts/strategies/sonic/README.md create mode 100644 contracts/docs/OSonicHierarchy.svg create mode 100644 contracts/docs/OSonicSquashed.svg create mode 100644 contracts/docs/OSonicStorage.svg create mode 100644 contracts/docs/OSonicVaultAdminSquashed.svg create mode 100644 contracts/docs/OSonicVaultCoreSquashed.svg create mode 100644 contracts/docs/OSonicVaultStorage.svg create mode 100644 contracts/docs/SonicStakingStrategyHierarchy.svg create mode 100644 contracts/docs/SonicStakingStrategySquashed.svg create mode 100644 contracts/docs/SonicStakingStrategyStorage.svg create mode 100644 contracts/docs/WOSonicHierarchy.svg create mode 100644 contracts/docs/WOSonicSquashed.svg create mode 100644 contracts/docs/WOSonicStorage.svg diff --git a/contracts/contracts/strategies/sonic/README.md b/contracts/contracts/strategies/sonic/README.md new file mode 100644 index 0000000000..87e25ccdc2 --- /dev/null +++ b/contracts/contracts/strategies/sonic/README.md @@ -0,0 +1,15 @@ +# Diagrams + +## Sonic Staking Strategy + +### Hierarchy + +![Sonic Staking Strategy Hierarchy](../../../docs/SonicStakingStrategyHierarchy.svg) + +### Squashed + +![Sonic Staking Strategy Squashed](../../../docs/SonicStakingStrategySquashed.svg) + +### Storage + +![Sonic Staking Strategy Storage](../../../docs/SonicStakingStrategyStorage.svg) diff --git a/contracts/contracts/token/README.md b/contracts/contracts/token/README.md index da89ba4061..98018683a4 100644 --- a/contracts/contracts/token/README.md +++ b/contracts/contracts/token/README.md @@ -101,3 +101,37 @@ ### Storage ![Base Wrapped Origin Ether Storage](../../docs/WOETHBaseStorage.svg) + +## Origin Sonic (OS) + +- Symbol `OS` +- Name `Origin Sonic` + +### Hierarchy + +![Origin Sonic Hierarchy](../../docs/OSonicHierarchy.svg) + +### Squashed + +![Origin Sonic Squashed](../../docs/OSonicSquashed.svg) + +### Storage + +![Origin Sonic Storage](../../docs/OSonicStorage.svg) + +## Wrapped Origin Sonic (wOS) + +- Symbol `wOS` +- Name `Wrapped Origin Sonic` + +### Hierarchy + +![Wrapped Origin Sonic Hierarchy](../../docs/WOSonicHierarchy.svg) + +### Squashed + +![Wrapped Origin Sonic Squashed](../../docs/WOSonicSquashed.svg) + +### Storage + +![Wrapped Origin Sonic Storage](../../docs/WOSonicStorage.svg) diff --git a/contracts/docs/OETHBaseHierarchy.svg b/contracts/docs/OETHBaseHierarchy.svg index 4efb4a1344..96c9e666f7 100644 --- a/contracts/docs/OETHBaseHierarchy.svg +++ b/contracts/docs/OETHBaseHierarchy.svg @@ -4,91 +4,43 @@ - - + + UmlClassDiagram - - + + -20 - -Governable -../contracts/governance/Governable.sol +21 + +Governable +../contracts/governance/Governable.sol - + -215 - -OETHBase -../contracts/token/OETHBase.sol +243 + +OETHBase +../contracts/token/OETHBase.sol - + -216 - -OUSD -../contracts/token/OUSD.sol +245 + +OUSD +../contracts/token/OUSD.sol - + -215->216 - - +243->245 + + - - -229 - -<<Abstract>> -InitializableERC20Detailed -../contracts/utils/InitializableERC20Detailed.sol - - + -215->229 - - - - - -216->20 - - - - - -226 - -<<Abstract>> -Initializable -../contracts/utils/Initializable.sol - - - -216->226 - - - - - -216->229 - - - - - -712 - -<<Interface>> -IERC20 -../node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol - - - -229->712 - - +245->21 + + diff --git a/contracts/docs/OETHBaseSquashed.svg b/contracts/docs/OETHBaseSquashed.svg index 4a0694f19d..fb70c46819 100644 --- a/contracts/docs/OETHBaseSquashed.svg +++ b/contracts/docs/OETHBaseSquashed.svg @@ -4,102 +4,100 @@ - - + + UmlClassDiagram - - + + -215 - -OETHBase -../contracts/token/OETHBase.sol - -Private: -   initialized: bool <<Initializable>> -   initializing: bool <<Initializable>> -   ______gap: uint256[50] <<Initializable>> -   _____gap: uint256[100] <<InitializableERC20Detailed>> -   _name: string <<InitializableERC20Detailed>> -   _symbol: string <<InitializableERC20Detailed>> -   _decimals: uint8 <<InitializableERC20Detailed>> -   governorPosition: bytes32 <<Governable>> -   pendingGovernorPosition: bytes32 <<Governable>> -   reentryStatusPosition: bytes32 <<Governable>> -   MAX_SUPPLY: uint256 <<OUSD>> -   _allowances: mapping(address=>mapping(address=>uint256)) <<OUSD>> -   _creditBalances: mapping(address=>uint256) <<OUSD>> -   _rebasingCredits: uint256 <<OUSD>> -   _rebasingCreditsPerToken: uint256 <<OUSD>> -   RESOLUTION_INCREASE: uint256 <<OUSD>> +243 + +OETHBase +../contracts/token/OETHBase.sol + +Private: +   governorPosition: bytes32 <<Governable>> +   pendingGovernorPosition: bytes32 <<Governable>> +   reentryStatusPosition: bytes32 <<Governable>> +   _gap: uint256[154] <<OUSD>> +   MAX_SUPPLY: uint256 <<OUSD>> +   allowances: mapping(address=>mapping(address=>uint256)) <<OUSD>> +   rebasingCredits_: uint256 <<OUSD>> +   rebasingCreditsPerToken_: uint256 <<OUSD>> +   __deprecated_isUpgraded: mapping(address=>uint256) <<OUSD>> +   RESOLUTION_INCREASE: uint256 <<OUSD>> +   __gap: uint256[34] <<OUSD>> +Internal: +   creditBalances: mapping(address=>uint256) <<OUSD>> +   alternativeCreditsPerToken: mapping(address=>uint256) <<OUSD>> Public:   _NOT_ENTERED: uint256 <<Governable>>   _ENTERED: uint256 <<Governable>> -   _totalSupply: uint256 <<OUSD>> +   totalSupply: uint256 <<OUSD>>   vaultAddress: address <<OUSD>>   nonRebasingSupply: uint256 <<OUSD>> -   nonRebasingCreditsPerToken: mapping(address=>uint256) <<OUSD>> -   rebaseState: mapping(address=>RebaseOptions) <<OUSD>> -   isUpgraded: mapping(address=>uint256) <<OUSD>> - +   rebaseState: mapping(address=>RebaseOptions) <<OUSD>> +   yieldTo: mapping(address=>address) <<OUSD>> +   yieldFrom: mapping(address=>address) <<OUSD>> + Internal: -    _initialize(nameArg: string, symbolArg: string, decimalsArg: uint8) <<InitializableERC20Detailed>> -    _governor(): (governorOut: address) <<Governable>> -    _pendingGovernor(): (pendingGovernor: address) <<Governable>> -    _setGovernor(newGovernor: address) <<Governable>> -    _setPendingGovernor(newGovernor: address) <<Governable>> -    _changeGovernor(_newGovernor: address) <<Governable>> -    _executeTransfer(_from: address, _to: address, _value: uint256) <<OUSD>> -    _mint(_account: address, _amount: uint256) <<nonReentrant>> <<OUSD>> -    _burn(_account: address, _amount: uint256) <<nonReentrant>> <<OUSD>> -    _creditsPerToken(_account: address): uint256 <<OUSD>> -    _isNonRebasingAccount(_account: address): bool <<OUSD>> -    _ensureRebasingMigration(_account: address) <<OUSD>> -    _rebaseOptIn(_account: address) <<OUSD>> +    _governor(): (governorOut: address) <<Governable>> +    _pendingGovernor(): (pendingGovernor: address) <<Governable>> +    _setGovernor(newGovernor: address) <<Governable>> +    _setPendingGovernor(newGovernor: address) <<Governable>> +    _changeGovernor(_newGovernor: address) <<Governable>> +    _executeTransfer(_from: address, _to: address, _value: uint256) <<OUSD>> +    _adjustAccount(_account: address, _balanceChange: int256): (rebasingCreditsDiff: int256, nonRebasingSupplyDiff: int256) <<OUSD>> +    _adjustGlobals(_rebasingCreditsDiff: int256, _nonRebasingSupplyDiff: int256) <<OUSD>> +    _creditsPerToken(_account: address): uint256 <<OUSD>> +    _autoMigrate(_account: address) <<OUSD>> +    _balanceToRebasingCredits(_balance: uint256): (rebasingCredits: uint256) <<OUSD>> +    _rebaseOptIn(_account: address) <<OUSD>> +    _rebaseOptOut(_account: address) <<OUSD>> External:    transferGovernance(_newGovernor: address) <<onlyGovernor>> <<Governable>>    claimGovernance() <<Governable>> -    initialize(_nameArg: string, _symbolArg: string, _vaultAddress: address, _initialCreditsPerToken: uint256) <<onlyGovernor, initializer>> <<OUSD>> -    mint(_account: address, _amount: uint256) <<onlyVault>> <<OUSD>> -    burn(account: address, amount: uint256) <<onlyVault>> <<OUSD>> -    changeSupply(_newTotalSupply: uint256) <<onlyVault, nonReentrant>> <<OUSD>> -    initialize2() <<onlyGovernor>> <<OETHBase>> -Public: -    <<event>> Transfer(from: address, to: address, value: uint256) <<IERC20>> -    <<event>> Approval(owner: address, spender: address, value: uint256) <<IERC20>> -    <<event>> PendingGovernorshipTransfer(previousGovernor: address, newGovernor: address) <<Governable>> -    <<event>> GovernorshipTransferred(previousGovernor: address, newGovernor: address) <<Governable>> -    <<event>> TotalSupplyUpdatedHighres(totalSupply: uint256, rebasingCredits: uint256, rebasingCreditsPerToken: uint256) <<OUSD>> -    <<event>> AccountRebasingEnabled(account: address) <<OUSD>> -    <<event>> AccountRebasingDisabled(account: address) <<OUSD>> -    <<modifier>> initializer() <<Initializable>> -    <<modifier>> onlyGovernor() <<Governable>> -    <<modifier>> nonReentrant() <<Governable>> -    <<modifier>> onlyVault() <<OUSD>> -    totalSupply(): uint256 <<OUSD>> -    balanceOf(_account: address): uint256 <<OUSD>> -    transfer(_to: address, _value: uint256): bool <<OUSD>> -    allowance(_owner: address, _spender: address): uint256 <<OUSD>> -    approve(_spender: address, _value: uint256): bool <<OUSD>> -    transferFrom(_from: address, _to: address, _value: uint256): bool <<OUSD>> -    name(): string <<InitializableERC20Detailed>> -    symbol(): string <<InitializableERC20Detailed>> -    decimals(): uint8 <<InitializableERC20Detailed>> -    constructor() <<Governable>> -    governor(): address <<Governable>> -    isGovernor(): bool <<Governable>> -    rebasingCreditsPerToken(): uint256 <<OUSD>> -    rebasingCredits(): uint256 <<OUSD>> -    rebasingCreditsPerTokenHighres(): uint256 <<OUSD>> -    rebasingCreditsHighres(): uint256 <<OUSD>> -    creditsBalanceOf(_account: address): (uint256, uint256) <<OUSD>> -    creditsBalanceOfHighres(_account: address): (uint256, uint256, bool) <<OUSD>> -    increaseAllowance(_spender: address, _addedValue: uint256): bool <<OUSD>> -    decreaseAllowance(_spender: address, _subtractedValue: uint256): bool <<OUSD>> -    governanceRebaseOptIn(_account: address) <<nonReentrant, onlyGovernor>> <<OUSD>> -    rebaseOptIn() <<nonReentrant>> <<OUSD>> -    rebaseOptOut() <<nonReentrant>> <<OUSD>> +    initialize(_vaultAddress: address, _initialCreditsPerToken: uint256) <<onlyGovernor>> <<OUSD>> +    symbol(): string <<OETHBase>> +    name(): string <<OETHBase>> +    decimals(): uint8 <<OETHBase>> +    rebasingCreditsPerTokenHighres(): uint256 <<OUSD>> +    rebasingCreditsPerToken(): uint256 <<OUSD>> +    rebasingCreditsHighres(): uint256 <<OUSD>> +    rebasingCredits(): uint256 <<OUSD>> +    creditsBalanceOf(_account: address): (uint256, uint256) <<OUSD>> +    creditsBalanceOfHighres(_account: address): (uint256, uint256, bool) <<OUSD>> +    nonRebasingCreditsPerToken(_account: address): uint256 <<OUSD>> +    transfer(_to: address, _value: uint256): bool <<OUSD>> +    transferFrom(_from: address, _to: address, _value: uint256): bool <<OUSD>> +    allowance(_owner: address, _spender: address): uint256 <<OUSD>> +    approve(_spender: address, _value: uint256): bool <<OUSD>> +    mint(_account: address, _amount: uint256) <<onlyVault>> <<OUSD>> +    burn(_account: address, _amount: uint256) <<onlyVault>> <<OUSD>> +    governanceRebaseOptIn(_account: address) <<onlyGovernor>> <<OUSD>> +    rebaseOptIn() <<OUSD>> +    rebaseOptOut() <<OUSD>> +    changeSupply(_newTotalSupply: uint256) <<onlyVault>> <<OUSD>> +    delegateYield(_from: address, _to: address) <<onlyGovernor>> <<OUSD>> +    undelegateYield(_from: address) <<onlyGovernor>> <<OUSD>> +Public: +    <<event>> PendingGovernorshipTransfer(previousGovernor: address, newGovernor: address) <<Governable>> +    <<event>> GovernorshipTransferred(previousGovernor: address, newGovernor: address) <<Governable>> +    <<event>> TotalSupplyUpdatedHighres(totalSupply: uint256, rebasingCredits: uint256, rebasingCreditsPerToken: uint256) <<OUSD>> +    <<event>> AccountRebasingEnabled(account: address) <<OUSD>> +    <<event>> AccountRebasingDisabled(account: address) <<OUSD>> +    <<event>> Transfer(from: address, to: address, value: uint256) <<OUSD>> +    <<event>> Approval(owner: address, spender: address, value: uint256) <<OUSD>> +    <<event>> YieldDelegated(source: address, target: address) <<OUSD>> +    <<event>> YieldUndelegated(source: address, target: address) <<OUSD>> +    <<modifier>> onlyGovernor() <<Governable>> +    <<modifier>> nonReentrant() <<Governable>> +    <<modifier>> onlyVault() <<OUSD>> +    constructor() <<Governable>> +    governor(): address <<Governable>> +    isGovernor(): bool <<Governable>> +    balanceOf(_account: address): uint256 <<OUSD>> diff --git a/contracts/docs/OETHBaseStorage.svg b/contracts/docs/OETHBaseStorage.svg index fbc538f35b..925f1a9977 100644 --- a/contracts/docs/OETHBaseStorage.svg +++ b/contracts/docs/OETHBaseStorage.svg @@ -4,92 +4,78 @@ - - + + StorageDiagram - + 1 - -OETHBase <<Contract>> - -slot - -0 - -1-50 - -51-150 - -151 - -152 - -153 - -154 - -155 - -156 - -157 - -158 - -159 - -160 - -161 - -162 - -163 - -type: <inherited contract>.variable (bytes) - -unallocated (30) - -bool: Initializable.initializing (1) - -bool: Initializable.initialized (1) - -uint256[50]: Initializable.______gap (1600) - -uint256[100]: InitializableERC20Detailed._____gap (3200) - -string: InitializableERC20Detailed._name (32) - -string: InitializableERC20Detailed._symbol (32) - -unallocated (31) - -uint8: InitializableERC20Detailed._decimals (1) - -uint256: OUSD._totalSupply (32) - -mapping(address=>mapping(address=>uint256)): OUSD._allowances (32) - -unallocated (12) - -address: OUSD.vaultAddress (20) - -mapping(address=>uint256): OUSD._creditBalances (32) - -uint256: OUSD._rebasingCredits (32) - -uint256: OUSD._rebasingCreditsPerToken (32) - -uint256: OUSD.nonRebasingSupply (32) - -mapping(address=>uint256): OUSD.nonRebasingCreditsPerToken (32) - -mapping(address=>RebaseOptions): OUSD.rebaseState (32) - -mapping(address=>uint256): OUSD.isUpgraded (32) + +OETHBase <<Contract>> + +slot + +0-153 + +154 + +155 + +156 + +157 + +158 + +159 + +160 + +161 + +162 + +163 + +164 + +165 + +166-199 + +type: <inherited contract>.variable (bytes) + +uint256[154]: OUSD._gap (4928) + +uint256: OUSD.totalSupply (32) + +mapping(address=>mapping(address=>uint256)): OUSD.allowances (32) + +unallocated (12) + +address: OUSD.vaultAddress (20) + +mapping(address=>uint256): OUSD.creditBalances (32) + +uint256: OUSD.rebasingCredits_ (32) + +uint256: OUSD.rebasingCreditsPerToken_ (32) + +uint256: OUSD.nonRebasingSupply (32) + +mapping(address=>uint256): OUSD.alternativeCreditsPerToken (32) + +mapping(address=>RebaseOptions): OUSD.rebaseState (32) + +mapping(address=>uint256): OUSD.__deprecated_isUpgraded (32) + +mapping(address=>address): OUSD.yieldTo (32) + +mapping(address=>address): OUSD.yieldFrom (32) + +uint256[34]: OUSD.__gap (1088) diff --git a/contracts/docs/OETHHierarchy.svg b/contracts/docs/OETHHierarchy.svg index 507830576d..a06def7727 100644 --- a/contracts/docs/OETHHierarchy.svg +++ b/contracts/docs/OETHHierarchy.svg @@ -4,85 +4,43 @@ - - + + UmlClassDiagram - - + + -20 - -Governable -../contracts/governance/Governable.sol +21 + +Governable +../contracts/governance/Governable.sol - + -185 - -OETH -../contracts/token/OETH.sol +242 + +OETH +../contracts/token/OETH.sol - + -186 - -OUSD -../contracts/token/OUSD.sol +245 + +OUSD +../contracts/token/OUSD.sol - + -185->186 - - +242->245 + + - - -186->20 - - - - - -194 - -<<Abstract>> -Initializable -../contracts/utils/Initializable.sol - - + -186->194 - - - - - -197 - -<<Abstract>> -InitializableERC20Detailed -../contracts/utils/InitializableERC20Detailed.sol - - - -186->197 - - - - - -392 - -<<Interface>> -IERC20 -../node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol - - - -197->392 - - +245->21 + + diff --git a/contracts/docs/OETHSquashed.svg b/contracts/docs/OETHSquashed.svg index 36093480d6..2126ec0640 100644 --- a/contracts/docs/OETHSquashed.svg +++ b/contracts/docs/OETHSquashed.svg @@ -4,97 +4,100 @@ - - + + UmlClassDiagram - - + + -185 - -OETH -../contracts/token/OETH.sol - -Private: -   initialized: bool <<Initializable>> -   initializing: bool <<Initializable>> -   ______gap: uint256[50] <<Initializable>> -   _____gap: uint256[100] <<InitializableERC20Detailed>> -   _name: string <<InitializableERC20Detailed>> -   _symbol: string <<InitializableERC20Detailed>> -   _decimals: uint8 <<InitializableERC20Detailed>> -   governorPosition: bytes32 <<Governable>> -   pendingGovernorPosition: bytes32 <<Governable>> -   reentryStatusPosition: bytes32 <<Governable>> -   MAX_SUPPLY: uint256 <<OUSD>> -   _allowances: mapping(address=>mapping(address=>uint256)) <<OUSD>> -   _creditBalances: mapping(address=>uint256) <<OUSD>> -   _rebasingCredits: uint256 <<OUSD>> -   _rebasingCreditsPerToken: uint256 <<OUSD>> -   RESOLUTION_INCREASE: uint256 <<OUSD>> -Public: -   _NOT_ENTERED: uint256 <<Governable>> -   _ENTERED: uint256 <<Governable>> -   _totalSupply: uint256 <<OUSD>> -   vaultAddress: address <<OUSD>> -   nonRebasingSupply: uint256 <<OUSD>> -   nonRebasingCreditsPerToken: mapping(address=>uint256) <<OUSD>> -   rebaseState: mapping(address=>RebaseOptions) <<OUSD>> -   isUpgraded: mapping(address=>uint256) <<OUSD>> - -Internal: -    _initialize(nameArg: string, symbolArg: string, decimalsArg: uint8) <<InitializableERC20Detailed>> -    _governor(): (governorOut: address) <<Governable>> -    _pendingGovernor(): (pendingGovernor: address) <<Governable>> -    _setGovernor(newGovernor: address) <<Governable>> -    _setPendingGovernor(newGovernor: address) <<Governable>> -    _changeGovernor(_newGovernor: address) <<Governable>> -    _executeTransfer(_from: address, _to: address, _value: uint256) <<OUSD>> -    _mint(_account: address, _amount: uint256) <<nonReentrant>> <<OUSD>> -    _burn(_account: address, _amount: uint256) <<nonReentrant>> <<OUSD>> -    _creditsPerToken(_account: address): uint256 <<OUSD>> -    _isNonRebasingAccount(_account: address): bool <<OUSD>> -    _ensureRebasingMigration(_account: address) <<OUSD>> -External: -    transferGovernance(_newGovernor: address) <<onlyGovernor>> <<Governable>> -    claimGovernance() <<Governable>> -    initialize(_nameArg: string, _symbolArg: string, _vaultAddress: address, _initialCreditsPerToken: uint256) <<onlyGovernor, initializer>> <<OUSD>> -    mint(_account: address, _amount: uint256) <<onlyVault>> <<OUSD>> -    burn(account: address, amount: uint256) <<onlyVault>> <<OUSD>> -    changeSupply(_newTotalSupply: uint256) <<onlyVault, nonReentrant>> <<OUSD>> -Public: -    <<event>> Transfer(from: address, to: address, value: uint256) <<IERC20>> -    <<event>> Approval(owner: address, spender: address, value: uint256) <<IERC20>> -    <<event>> PendingGovernorshipTransfer(previousGovernor: address, newGovernor: address) <<Governable>> -    <<event>> GovernorshipTransferred(previousGovernor: address, newGovernor: address) <<Governable>> -    <<event>> TotalSupplyUpdatedHighres(totalSupply: uint256, rebasingCredits: uint256, rebasingCreditsPerToken: uint256) <<OUSD>> -    <<modifier>> initializer() <<Initializable>> -    <<modifier>> onlyGovernor() <<Governable>> -    <<modifier>> nonReentrant() <<Governable>> -    <<modifier>> onlyVault() <<OUSD>> -    totalSupply(): uint256 <<OUSD>> -    balanceOf(_account: address): uint256 <<OUSD>> -    transfer(_to: address, _value: uint256): bool <<OUSD>> -    allowance(_owner: address, _spender: address): uint256 <<OUSD>> -    approve(_spender: address, _value: uint256): bool <<OUSD>> -    transferFrom(_from: address, _to: address, _value: uint256): bool <<OUSD>> -    name(): string <<InitializableERC20Detailed>> -    symbol(): string <<InitializableERC20Detailed>> -    decimals(): uint8 <<InitializableERC20Detailed>> -    constructor() <<Governable>> -    governor(): address <<Governable>> -    isGovernor(): bool <<Governable>> -    rebasingCreditsPerToken(): uint256 <<OUSD>> -    rebasingCredits(): uint256 <<OUSD>> -    rebasingCreditsPerTokenHighres(): uint256 <<OUSD>> -    rebasingCreditsHighres(): uint256 <<OUSD>> -    creditsBalanceOf(_account: address): (uint256, uint256) <<OUSD>> -    creditsBalanceOfHighres(_account: address): (uint256, uint256, bool) <<OUSD>> -    increaseAllowance(_spender: address, _addedValue: uint256): bool <<OUSD>> -    decreaseAllowance(_spender: address, _subtractedValue: uint256): bool <<OUSD>> -    rebaseOptIn() <<nonReentrant>> <<OUSD>> -    rebaseOptOut() <<nonReentrant>> <<OUSD>> +242 + +OETH +../contracts/token/OETH.sol + +Private: +   governorPosition: bytes32 <<Governable>> +   pendingGovernorPosition: bytes32 <<Governable>> +   reentryStatusPosition: bytes32 <<Governable>> +   _gap: uint256[154] <<OUSD>> +   MAX_SUPPLY: uint256 <<OUSD>> +   allowances: mapping(address=>mapping(address=>uint256)) <<OUSD>> +   rebasingCredits_: uint256 <<OUSD>> +   rebasingCreditsPerToken_: uint256 <<OUSD>> +   __deprecated_isUpgraded: mapping(address=>uint256) <<OUSD>> +   RESOLUTION_INCREASE: uint256 <<OUSD>> +   __gap: uint256[34] <<OUSD>> +Internal: +   creditBalances: mapping(address=>uint256) <<OUSD>> +   alternativeCreditsPerToken: mapping(address=>uint256) <<OUSD>> +Public: +   _NOT_ENTERED: uint256 <<Governable>> +   _ENTERED: uint256 <<Governable>> +   totalSupply: uint256 <<OUSD>> +   vaultAddress: address <<OUSD>> +   nonRebasingSupply: uint256 <<OUSD>> +   rebaseState: mapping(address=>RebaseOptions) <<OUSD>> +   yieldTo: mapping(address=>address) <<OUSD>> +   yieldFrom: mapping(address=>address) <<OUSD>> + +Internal: +    _governor(): (governorOut: address) <<Governable>> +    _pendingGovernor(): (pendingGovernor: address) <<Governable>> +    _setGovernor(newGovernor: address) <<Governable>> +    _setPendingGovernor(newGovernor: address) <<Governable>> +    _changeGovernor(_newGovernor: address) <<Governable>> +    _executeTransfer(_from: address, _to: address, _value: uint256) <<OUSD>> +    _adjustAccount(_account: address, _balanceChange: int256): (rebasingCreditsDiff: int256, nonRebasingSupplyDiff: int256) <<OUSD>> +    _adjustGlobals(_rebasingCreditsDiff: int256, _nonRebasingSupplyDiff: int256) <<OUSD>> +    _creditsPerToken(_account: address): uint256 <<OUSD>> +    _autoMigrate(_account: address) <<OUSD>> +    _balanceToRebasingCredits(_balance: uint256): (rebasingCredits: uint256) <<OUSD>> +    _rebaseOptIn(_account: address) <<OUSD>> +    _rebaseOptOut(_account: address) <<OUSD>> +External: +    transferGovernance(_newGovernor: address) <<onlyGovernor>> <<Governable>> +    claimGovernance() <<Governable>> +    initialize(_vaultAddress: address, _initialCreditsPerToken: uint256) <<onlyGovernor>> <<OUSD>> +    symbol(): string <<OETH>> +    name(): string <<OETH>> +    decimals(): uint8 <<OETH>> +    rebasingCreditsPerTokenHighres(): uint256 <<OUSD>> +    rebasingCreditsPerToken(): uint256 <<OUSD>> +    rebasingCreditsHighres(): uint256 <<OUSD>> +    rebasingCredits(): uint256 <<OUSD>> +    creditsBalanceOf(_account: address): (uint256, uint256) <<OUSD>> +    creditsBalanceOfHighres(_account: address): (uint256, uint256, bool) <<OUSD>> +    nonRebasingCreditsPerToken(_account: address): uint256 <<OUSD>> +    transfer(_to: address, _value: uint256): bool <<OUSD>> +    transferFrom(_from: address, _to: address, _value: uint256): bool <<OUSD>> +    allowance(_owner: address, _spender: address): uint256 <<OUSD>> +    approve(_spender: address, _value: uint256): bool <<OUSD>> +    mint(_account: address, _amount: uint256) <<onlyVault>> <<OUSD>> +    burn(_account: address, _amount: uint256) <<onlyVault>> <<OUSD>> +    governanceRebaseOptIn(_account: address) <<onlyGovernor>> <<OUSD>> +    rebaseOptIn() <<OUSD>> +    rebaseOptOut() <<OUSD>> +    changeSupply(_newTotalSupply: uint256) <<onlyVault>> <<OUSD>> +    delegateYield(_from: address, _to: address) <<onlyGovernor>> <<OUSD>> +    undelegateYield(_from: address) <<onlyGovernor>> <<OUSD>> +Public: +    <<event>> PendingGovernorshipTransfer(previousGovernor: address, newGovernor: address) <<Governable>> +    <<event>> GovernorshipTransferred(previousGovernor: address, newGovernor: address) <<Governable>> +    <<event>> TotalSupplyUpdatedHighres(totalSupply: uint256, rebasingCredits: uint256, rebasingCreditsPerToken: uint256) <<OUSD>> +    <<event>> AccountRebasingEnabled(account: address) <<OUSD>> +    <<event>> AccountRebasingDisabled(account: address) <<OUSD>> +    <<event>> Transfer(from: address, to: address, value: uint256) <<OUSD>> +    <<event>> Approval(owner: address, spender: address, value: uint256) <<OUSD>> +    <<event>> YieldDelegated(source: address, target: address) <<OUSD>> +    <<event>> YieldUndelegated(source: address, target: address) <<OUSD>> +    <<modifier>> onlyGovernor() <<Governable>> +    <<modifier>> nonReentrant() <<Governable>> +    <<modifier>> onlyVault() <<OUSD>> +    constructor() <<Governable>> +    governor(): address <<Governable>> +    isGovernor(): bool <<Governable>> +    balanceOf(_account: address): uint256 <<OUSD>> diff --git a/contracts/docs/OETHStorage.svg b/contracts/docs/OETHStorage.svg index 9bceb56483..83457fe343 100644 --- a/contracts/docs/OETHStorage.svg +++ b/contracts/docs/OETHStorage.svg @@ -4,92 +4,78 @@ - - + + StorageDiagram - + 1 - -OETH <<Contract>> - -slot - -0 - -1-50 - -51-150 - -151 - -152 - -153 - -154 - -155 - -156 - -157 - -158 - -159 - -160 - -161 - -162 - -163 - -type: <inherited contract>.variable (bytes) - -unallocated (30) - -bool: Initializable.initializing (1) - -bool: Initializable.initialized (1) - -uint256[50]: Initializable.______gap (1600) - -uint256[100]: InitializableERC20Detailed._____gap (3200) - -string: InitializableERC20Detailed._name (32) - -string: InitializableERC20Detailed._symbol (32) - -unallocated (31) - -uint8: InitializableERC20Detailed._decimals (1) - -uint256: OUSD._totalSupply (32) - -mapping(address=>mapping(address=>uint256)): OUSD._allowances (32) - -unallocated (12) - -address: OUSD.vaultAddress (20) - -mapping(address=>uint256): OUSD._creditBalances (32) - -uint256: OUSD._rebasingCredits (32) - -uint256: OUSD._rebasingCreditsPerToken (32) - -uint256: OUSD.nonRebasingSupply (32) - -mapping(address=>uint256): OUSD.nonRebasingCreditsPerToken (32) - -mapping(address=>RebaseOptions): OUSD.rebaseState (32) - -mapping(address=>uint256): OUSD.isUpgraded (32) + +OETH <<Contract>> + +slot + +0-153 + +154 + +155 + +156 + +157 + +158 + +159 + +160 + +161 + +162 + +163 + +164 + +165 + +166-199 + +type: <inherited contract>.variable (bytes) + +uint256[154]: OUSD._gap (4928) + +uint256: OUSD.totalSupply (32) + +mapping(address=>mapping(address=>uint256)): OUSD.allowances (32) + +unallocated (12) + +address: OUSD.vaultAddress (20) + +mapping(address=>uint256): OUSD.creditBalances (32) + +uint256: OUSD.rebasingCredits_ (32) + +uint256: OUSD.rebasingCreditsPerToken_ (32) + +uint256: OUSD.nonRebasingSupply (32) + +mapping(address=>uint256): OUSD.alternativeCreditsPerToken (32) + +mapping(address=>RebaseOptions): OUSD.rebaseState (32) + +mapping(address=>uint256): OUSD.__deprecated_isUpgraded (32) + +mapping(address=>address): OUSD.yieldTo (32) + +mapping(address=>address): OUSD.yieldFrom (32) + +uint256[34]: OUSD.__gap (1088) diff --git a/contracts/docs/OSonicHierarchy.svg b/contracts/docs/OSonicHierarchy.svg new file mode 100644 index 0000000000..2146b2b5d3 --- /dev/null +++ b/contracts/docs/OSonicHierarchy.svg @@ -0,0 +1,46 @@ + + + + + + +UmlClassDiagram + + + +21 + +Governable +../contracts/governance/Governable.sol + + + +244 + +OSonic +../contracts/token/OSonic.sol + + + +245 + +OUSD +../contracts/token/OUSD.sol + + + +244->245 + + + + + +245->21 + + + + + diff --git a/contracts/docs/OSonicSquashed.svg b/contracts/docs/OSonicSquashed.svg new file mode 100644 index 0000000000..37c9e50349 --- /dev/null +++ b/contracts/docs/OSonicSquashed.svg @@ -0,0 +1,103 @@ + + + + + + +UmlClassDiagram + + + +244 + +OSonic +../contracts/token/OSonic.sol + +Private: +   governorPosition: bytes32 <<Governable>> +   pendingGovernorPosition: bytes32 <<Governable>> +   reentryStatusPosition: bytes32 <<Governable>> +   _gap: uint256[154] <<OUSD>> +   MAX_SUPPLY: uint256 <<OUSD>> +   allowances: mapping(address=>mapping(address=>uint256)) <<OUSD>> +   rebasingCredits_: uint256 <<OUSD>> +   rebasingCreditsPerToken_: uint256 <<OUSD>> +   __deprecated_isUpgraded: mapping(address=>uint256) <<OUSD>> +   RESOLUTION_INCREASE: uint256 <<OUSD>> +   __gap: uint256[34] <<OUSD>> +Internal: +   creditBalances: mapping(address=>uint256) <<OUSD>> +   alternativeCreditsPerToken: mapping(address=>uint256) <<OUSD>> +Public: +   _NOT_ENTERED: uint256 <<Governable>> +   _ENTERED: uint256 <<Governable>> +   totalSupply: uint256 <<OUSD>> +   vaultAddress: address <<OUSD>> +   nonRebasingSupply: uint256 <<OUSD>> +   rebaseState: mapping(address=>RebaseOptions) <<OUSD>> +   yieldTo: mapping(address=>address) <<OUSD>> +   yieldFrom: mapping(address=>address) <<OUSD>> + +Internal: +    _governor(): (governorOut: address) <<Governable>> +    _pendingGovernor(): (pendingGovernor: address) <<Governable>> +    _setGovernor(newGovernor: address) <<Governable>> +    _setPendingGovernor(newGovernor: address) <<Governable>> +    _changeGovernor(_newGovernor: address) <<Governable>> +    _executeTransfer(_from: address, _to: address, _value: uint256) <<OUSD>> +    _adjustAccount(_account: address, _balanceChange: int256): (rebasingCreditsDiff: int256, nonRebasingSupplyDiff: int256) <<OUSD>> +    _adjustGlobals(_rebasingCreditsDiff: int256, _nonRebasingSupplyDiff: int256) <<OUSD>> +    _creditsPerToken(_account: address): uint256 <<OUSD>> +    _autoMigrate(_account: address) <<OUSD>> +    _balanceToRebasingCredits(_balance: uint256): (rebasingCredits: uint256) <<OUSD>> +    _rebaseOptIn(_account: address) <<OUSD>> +    _rebaseOptOut(_account: address) <<OUSD>> +External: +    transferGovernance(_newGovernor: address) <<onlyGovernor>> <<Governable>> +    claimGovernance() <<Governable>> +    initialize(_vaultAddress: address, _initialCreditsPerToken: uint256) <<onlyGovernor>> <<OUSD>> +    symbol(): string <<OSonic>> +    name(): string <<OSonic>> +    decimals(): uint8 <<OUSD>> +    rebasingCreditsPerTokenHighres(): uint256 <<OUSD>> +    rebasingCreditsPerToken(): uint256 <<OUSD>> +    rebasingCreditsHighres(): uint256 <<OUSD>> +    rebasingCredits(): uint256 <<OUSD>> +    creditsBalanceOf(_account: address): (uint256, uint256) <<OUSD>> +    creditsBalanceOfHighres(_account: address): (uint256, uint256, bool) <<OUSD>> +    nonRebasingCreditsPerToken(_account: address): uint256 <<OUSD>> +    transfer(_to: address, _value: uint256): bool <<OUSD>> +    transferFrom(_from: address, _to: address, _value: uint256): bool <<OUSD>> +    allowance(_owner: address, _spender: address): uint256 <<OUSD>> +    approve(_spender: address, _value: uint256): bool <<OUSD>> +    mint(_account: address, _amount: uint256) <<onlyVault>> <<OUSD>> +    burn(_account: address, _amount: uint256) <<onlyVault>> <<OUSD>> +    governanceRebaseOptIn(_account: address) <<onlyGovernor>> <<OUSD>> +    rebaseOptIn() <<OUSD>> +    rebaseOptOut() <<OUSD>> +    changeSupply(_newTotalSupply: uint256) <<onlyVault>> <<OUSD>> +    delegateYield(_from: address, _to: address) <<onlyGovernor>> <<OUSD>> +    undelegateYield(_from: address) <<onlyGovernor>> <<OUSD>> +Public: +    <<event>> PendingGovernorshipTransfer(previousGovernor: address, newGovernor: address) <<Governable>> +    <<event>> GovernorshipTransferred(previousGovernor: address, newGovernor: address) <<Governable>> +    <<event>> TotalSupplyUpdatedHighres(totalSupply: uint256, rebasingCredits: uint256, rebasingCreditsPerToken: uint256) <<OUSD>> +    <<event>> AccountRebasingEnabled(account: address) <<OUSD>> +    <<event>> AccountRebasingDisabled(account: address) <<OUSD>> +    <<event>> Transfer(from: address, to: address, value: uint256) <<OUSD>> +    <<event>> Approval(owner: address, spender: address, value: uint256) <<OUSD>> +    <<event>> YieldDelegated(source: address, target: address) <<OUSD>> +    <<event>> YieldUndelegated(source: address, target: address) <<OUSD>> +    <<modifier>> onlyGovernor() <<Governable>> +    <<modifier>> nonReentrant() <<Governable>> +    <<modifier>> onlyVault() <<OUSD>> +    constructor() <<Governable>> +    governor(): address <<Governable>> +    isGovernor(): bool <<Governable>> +    balanceOf(_account: address): uint256 <<OUSD>> + + + diff --git a/contracts/docs/OSonicStorage.svg b/contracts/docs/OSonicStorage.svg new file mode 100644 index 0000000000..1890591b94 --- /dev/null +++ b/contracts/docs/OSonicStorage.svg @@ -0,0 +1,81 @@ + + + + + + +StorageDiagram + + + +1 + +OSonic <<Contract>> + +slot + +0-153 + +154 + +155 + +156 + +157 + +158 + +159 + +160 + +161 + +162 + +163 + +164 + +165 + +166-199 + +type: <inherited contract>.variable (bytes) + +uint256[154]: OUSD._gap (4928) + +uint256: OUSD.totalSupply (32) + +mapping(address=>mapping(address=>uint256)): OUSD.allowances (32) + +unallocated (12) + +address: OUSD.vaultAddress (20) + +mapping(address=>uint256): OUSD.creditBalances (32) + +uint256: OUSD.rebasingCredits_ (32) + +uint256: OUSD.rebasingCreditsPerToken_ (32) + +uint256: OUSD.nonRebasingSupply (32) + +mapping(address=>uint256): OUSD.alternativeCreditsPerToken (32) + +mapping(address=>RebaseOptions): OUSD.rebaseState (32) + +mapping(address=>uint256): OUSD.__deprecated_isUpgraded (32) + +mapping(address=>address): OUSD.yieldTo (32) + +mapping(address=>address): OUSD.yieldFrom (32) + +uint256[34]: OUSD.__gap (1088) + + + diff --git a/contracts/docs/OSonicVaultAdminSquashed.svg b/contracts/docs/OSonicVaultAdminSquashed.svg new file mode 100644 index 0000000000..22be0c6cef --- /dev/null +++ b/contracts/docs/OSonicVaultAdminSquashed.svg @@ -0,0 +1,165 @@ + + + + + + +UmlClassDiagram + + + +273 + +OSonicVaultAdmin +../contracts/vault/OSonicVaultAdmin.sol + +Private: +   initialized: bool <<Initializable>> +   initializing: bool <<Initializable>> +   ______gap: uint256[50] <<Initializable>> +   governorPosition: bytes32 <<Governable>> +   pendingGovernorPosition: bytes32 <<Governable>> +   reentryStatusPosition: bytes32 <<Governable>> +   _deprecated_rebaseHooksAddr: address <<VaultStorage>> +   _deprecated_uniswapAddr: address <<VaultStorage>> +   _deprecated_swapTokens: address[] <<VaultStorage>> +   __gap: uint256[44] <<VaultStorage>> +Internal: +   assets: mapping(address=>Asset) <<VaultStorage>> +   allAssets: address[] <<VaultStorage>> +   strategies: mapping(address=>Strategy) <<VaultStorage>> +   allStrategies: address[] <<VaultStorage>> +   oUSD: OUSD <<VaultStorage>> +   swapConfig: SwapConfig <<VaultStorage>> +Public: +   _NOT_ENTERED: uint256 <<Governable>> +   _ENTERED: uint256 <<Governable>> +   priceProvider: address <<VaultStorage>> +   rebasePaused: bool <<VaultStorage>> +   capitalPaused: bool <<VaultStorage>> +   redeemFeeBps: uint256 <<VaultStorage>> +   vaultBuffer: uint256 <<VaultStorage>> +   autoAllocateThreshold: uint256 <<VaultStorage>> +   rebaseThreshold: uint256 <<VaultStorage>> +   adminImplPosition: bytes32 <<VaultStorage>> +   strategistAddr: address <<VaultStorage>> +   assetDefaultStrategies: mapping(address=>address) <<VaultStorage>> +   maxSupplyDiff: uint256 <<VaultStorage>> +   trusteeAddress: address <<VaultStorage>> +   trusteeFeeBps: uint256 <<VaultStorage>> +   MINT_MINIMUM_UNIT_PRICE: uint256 <<VaultStorage>> +   ousdMetaStrategy: address <<VaultStorage>> +   netOusdMintedForStrategy: int256 <<VaultStorage>> +   netOusdMintForStrategyThreshold: uint256 <<VaultStorage>> +   MIN_UNIT_PRICE_DRIFT: uint256 <<VaultStorage>> +   MAX_UNIT_PRICE_DRIFT: uint256 <<VaultStorage>> +   isMintWhitelistedStrategy: mapping(address=>bool) <<VaultStorage>> +   dripper: address <<VaultStorage>> +   withdrawalQueueMetadata: WithdrawalQueueMetadata <<VaultStorage>> +   withdrawalRequests: mapping(uint256=>WithdrawalRequest) <<VaultStorage>> +   withdrawalClaimDelay: uint256 <<VaultStorage>> +   weth: address <<OETHVaultAdmin>> + +Internal: +    _governor(): (governorOut: address) <<Governable>> +    _pendingGovernor(): (pendingGovernor: address) <<Governable>> +    _setGovernor(newGovernor: address) <<Governable>> +    _setPendingGovernor(newGovernor: address) <<Governable>> +    _changeGovernor(_newGovernor: address) <<Governable>> +    _swapCollateral(address, address, uint256, uint256, bytes): uint256 <<OETHVaultAdmin>> +    _depositToStrategy(_strategyToAddress: address, _assets: address[], _amounts: uint256[]) <<OETHVaultAdmin>> +    _withdrawFromStrategy(_recipient: address, _strategyFromAddress: address, _assets: address[], _amounts: uint256[]) <<OETHVaultAdmin>> +    _withdrawAllFromStrategy(_strategyAddr: address) <<OETHVaultAdmin>> +    _withdrawAllFromStrategies() <<OETHVaultAdmin>> +    _cacheDecimals(token: address) <<VaultAdmin>> +    _wethAvailable(): (wethAvailable: uint256) <<OETHVaultAdmin>> +External: +    transferGovernance(_newGovernor: address) <<onlyGovernor>> <<Governable>> +    claimGovernance() <<Governable>> +    setAdminImpl(newImpl: address) <<onlyGovernor>> <<VaultStorage>> +    setPriceProvider(_priceProvider: address) <<onlyGovernor>> <<VaultAdmin>> +    setRedeemFeeBps(_redeemFeeBps: uint256) <<onlyGovernor>> <<VaultAdmin>> +    setVaultBuffer(_vaultBuffer: uint256) <<onlyGovernorOrStrategist>> <<VaultAdmin>> +    setAutoAllocateThreshold(_threshold: uint256) <<onlyGovernor>> <<VaultAdmin>> +    setRebaseThreshold(_threshold: uint256) <<onlyGovernor>> <<VaultAdmin>> +    setStrategistAddr(_address: address) <<onlyGovernor>> <<VaultAdmin>> +    setAssetDefaultStrategy(_asset: address, _strategy: address) <<onlyGovernorOrStrategist>> <<VaultAdmin>> +    setNetOusdMintForStrategyThreshold(_threshold: uint256) <<onlyGovernor>> <<VaultAdmin>> +    setDripper(_dripper: address) <<onlyGovernor>> <<VaultAdmin>> +    setWithdrawalClaimDelay(_delay: uint256) <<onlyGovernor>> <<VaultAdmin>> +    swapCollateral(_fromAsset: address, _toAsset: address, _fromAssetAmount: uint256, _minToAssetAmount: uint256, _data: bytes): (toAssetAmount: uint256) <<nonReentrant, onlyGovernorOrStrategist>> <<VaultAdmin>> +    setSwapper(_swapperAddr: address) <<onlyGovernor>> <<VaultAdmin>> +    swapper(): (swapper_: address) <<VaultAdmin>> +    setSwapAllowedUndervalue(_basis: uint16) <<onlyGovernor>> <<VaultAdmin>> +    allowedSwapUndervalue(): (value: uint256) <<VaultAdmin>> +    setOracleSlippage(_asset: address, _allowedOracleSlippageBps: uint16) <<onlyGovernor>> <<VaultAdmin>> +    supportAsset(_asset: address, _unitConversion: uint8) <<onlyGovernor>> <<OSonicVaultAdmin>> +    removeAsset(_asset: address) <<onlyGovernor>> <<VaultAdmin>> +    cacheDecimals(_asset: address) <<onlyGovernor>> <<VaultAdmin>> +    approveStrategy(_addr: address) <<onlyGovernor>> <<VaultAdmin>> +    removeStrategy(_addr: address) <<onlyGovernor>> <<VaultAdmin>> +    depositToStrategy(_strategyToAddress: address, _assets: address[], _amounts: uint256[]) <<onlyGovernorOrStrategist, nonReentrant>> <<VaultAdmin>> +    withdrawFromStrategy(_strategyFromAddress: address, _assets: address[], _amounts: uint256[]) <<onlyGovernorOrStrategist, nonReentrant>> <<VaultAdmin>> +    setMaxSupplyDiff(_maxSupplyDiff: uint256) <<onlyGovernor>> <<VaultAdmin>> +    setTrusteeAddress(_address: address) <<onlyGovernor>> <<VaultAdmin>> +    setTrusteeFeeBps(_basis: uint256) <<onlyGovernor>> <<VaultAdmin>> +    setOusdMetaStrategy(_ousdMetaStrategy: address) <<onlyGovernor>> <<VaultAdmin>> +    pauseRebase() <<onlyGovernorOrStrategist>> <<VaultAdmin>> +    unpauseRebase() <<onlyGovernorOrStrategist>> <<VaultAdmin>> +    pauseCapital() <<onlyGovernorOrStrategist>> <<VaultAdmin>> +    unpauseCapital() <<onlyGovernorOrStrategist>> <<VaultAdmin>> +    transferToken(_asset: address, _amount: uint256) <<onlyGovernor>> <<VaultAdmin>> +    withdrawAllFromStrategy(_strategyAddr: address) <<onlyGovernorOrStrategist>> <<VaultAdmin>> +    withdrawAllFromStrategies() <<onlyGovernorOrStrategist>> <<VaultAdmin>> +Public: +    <<event>> PendingGovernorshipTransfer(previousGovernor: address, newGovernor: address) <<Governable>> +    <<event>> GovernorshipTransferred(previousGovernor: address, newGovernor: address) <<Governable>> +    <<event>> AssetSupported(_asset: address) <<VaultStorage>> +    <<event>> AssetRemoved(_asset: address) <<VaultStorage>> +    <<event>> AssetDefaultStrategyUpdated(_asset: address, _strategy: address) <<VaultStorage>> +    <<event>> AssetAllocated(_asset: address, _strategy: address, _amount: uint256) <<VaultStorage>> +    <<event>> StrategyApproved(_addr: address) <<VaultStorage>> +    <<event>> StrategyRemoved(_addr: address) <<VaultStorage>> +    <<event>> Mint(_addr: address, _value: uint256) <<VaultStorage>> +    <<event>> Redeem(_addr: address, _value: uint256) <<VaultStorage>> +    <<event>> CapitalPaused() <<VaultStorage>> +    <<event>> CapitalUnpaused() <<VaultStorage>> +    <<event>> RebasePaused() <<VaultStorage>> +    <<event>> RebaseUnpaused() <<VaultStorage>> +    <<event>> VaultBufferUpdated(_vaultBuffer: uint256) <<VaultStorage>> +    <<event>> OusdMetaStrategyUpdated(_ousdMetaStrategy: address) <<VaultStorage>> +    <<event>> RedeemFeeUpdated(_redeemFeeBps: uint256) <<VaultStorage>> +    <<event>> PriceProviderUpdated(_priceProvider: address) <<VaultStorage>> +    <<event>> AllocateThresholdUpdated(_threshold: uint256) <<VaultStorage>> +    <<event>> RebaseThresholdUpdated(_threshold: uint256) <<VaultStorage>> +    <<event>> StrategistUpdated(_address: address) <<VaultStorage>> +    <<event>> MaxSupplyDiffChanged(maxSupplyDiff: uint256) <<VaultStorage>> +    <<event>> YieldDistribution(_to: address, _yield: uint256, _fee: uint256) <<VaultStorage>> +    <<event>> TrusteeFeeBpsChanged(_basis: uint256) <<VaultStorage>> +    <<event>> TrusteeAddressChanged(_address: address) <<VaultStorage>> +    <<event>> NetOusdMintForStrategyThresholdChanged(_threshold: uint256) <<VaultStorage>> +    <<event>> SwapperChanged(_address: address) <<VaultStorage>> +    <<event>> SwapAllowedUndervalueChanged(_basis: uint256) <<VaultStorage>> +    <<event>> SwapSlippageChanged(_asset: address, _basis: uint256) <<VaultStorage>> +    <<event>> Swapped(_fromAsset: address, _toAsset: address, _fromAssetAmount: uint256, _toAssetAmount: uint256) <<VaultStorage>> +    <<event>> StrategyAddedToMintWhitelist(strategy: address) <<VaultStorage>> +    <<event>> StrategyRemovedFromMintWhitelist(strategy: address) <<VaultStorage>> +    <<event>> DripperChanged(_dripper: address) <<VaultStorage>> +    <<event>> WithdrawalRequested(_withdrawer: address, _requestId: uint256, _amount: uint256, _queued: uint256) <<VaultStorage>> +    <<event>> WithdrawalClaimed(_withdrawer: address, _requestId: uint256, _amount: uint256) <<VaultStorage>> +    <<event>> WithdrawalClaimable(_claimable: uint256, _newClaimable: uint256) <<VaultStorage>> +    <<event>> WithdrawalClaimDelayUpdated(_newDelay: uint256) <<VaultStorage>> +    <<modifier>> initializer() <<Initializable>> +    <<modifier>> onlyGovernor() <<Governable>> +    <<modifier>> nonReentrant() <<Governable>> +    <<modifier>> onlyGovernorOrStrategist() <<VaultAdmin>> +    constructor() <<Governable>> +    governor(): address <<Governable>> +    isGovernor(): bool <<Governable>> +    constructor(_wS: address) <<OSonicVaultAdmin>> + + + diff --git a/contracts/docs/OSonicVaultCoreSquashed.svg b/contracts/docs/OSonicVaultCoreSquashed.svg new file mode 100644 index 0000000000..51ac9515a6 --- /dev/null +++ b/contracts/docs/OSonicVaultCoreSquashed.svg @@ -0,0 +1,173 @@ + + + + + + +UmlClassDiagram + + + +274 + +OSonicVaultCore +../contracts/vault/OSonicVaultCore.sol + +Private: +   initialized: bool <<Initializable>> +   initializing: bool <<Initializable>> +   ______gap: uint256[50] <<Initializable>> +   governorPosition: bytes32 <<Governable>> +   pendingGovernorPosition: bytes32 <<Governable>> +   reentryStatusPosition: bytes32 <<Governable>> +   _deprecated_rebaseHooksAddr: address <<VaultStorage>> +   _deprecated_uniswapAddr: address <<VaultStorage>> +   _deprecated_swapTokens: address[] <<VaultStorage>> +   __gap: uint256[44] <<VaultStorage>> +   __gap: uint256[50] <<OETHVaultCore>> +Internal: +   assets: mapping(address=>Asset) <<VaultStorage>> +   allAssets: address[] <<VaultStorage>> +   strategies: mapping(address=>Strategy) <<VaultStorage>> +   allStrategies: address[] <<VaultStorage>> +   oUSD: OUSD <<VaultStorage>> +   swapConfig: SwapConfig <<VaultStorage>> +   MAX_INT: uint256 <<VaultCore>> +Public: +   _NOT_ENTERED: uint256 <<Governable>> +   _ENTERED: uint256 <<Governable>> +   priceProvider: address <<VaultStorage>> +   rebasePaused: bool <<VaultStorage>> +   capitalPaused: bool <<VaultStorage>> +   redeemFeeBps: uint256 <<VaultStorage>> +   vaultBuffer: uint256 <<VaultStorage>> +   autoAllocateThreshold: uint256 <<VaultStorage>> +   rebaseThreshold: uint256 <<VaultStorage>> +   adminImplPosition: bytes32 <<VaultStorage>> +   strategistAddr: address <<VaultStorage>> +   assetDefaultStrategies: mapping(address=>address) <<VaultStorage>> +   maxSupplyDiff: uint256 <<VaultStorage>> +   trusteeAddress: address <<VaultStorage>> +   trusteeFeeBps: uint256 <<VaultStorage>> +   MINT_MINIMUM_UNIT_PRICE: uint256 <<VaultStorage>> +   ousdMetaStrategy: address <<VaultStorage>> +   netOusdMintedForStrategy: int256 <<VaultStorage>> +   netOusdMintForStrategyThreshold: uint256 <<VaultStorage>> +   MIN_UNIT_PRICE_DRIFT: uint256 <<VaultStorage>> +   MAX_UNIT_PRICE_DRIFT: uint256 <<VaultStorage>> +   isMintWhitelistedStrategy: mapping(address=>bool) <<VaultStorage>> +   dripper: address <<VaultStorage>> +   withdrawalQueueMetadata: WithdrawalQueueMetadata <<VaultStorage>> +   withdrawalRequests: mapping(uint256=>WithdrawalRequest) <<VaultStorage>> +   withdrawalClaimDelay: uint256 <<VaultStorage>> +   weth: address <<OETHVaultCore>> +   wethAssetIndex: uint256 <<OETHVaultCore>> + +Private: +    abs(x: int256): uint256 <<VaultCore>> +Internal: +    _governor(): (governorOut: address) <<Governable>> +    _pendingGovernor(): (pendingGovernor: address) <<Governable>> +    _setGovernor(newGovernor: address) <<Governable>> +    _setPendingGovernor(newGovernor: address) <<Governable>> +    _changeGovernor(_newGovernor: address) <<Governable>> +    _mint(_asset: address, _amount: uint256, _minimumOusdAmount: uint256) <<OETHVaultCore>> +    _redeem(_amount: uint256, _minimumUnitAmount: uint256) <<OETHVaultCore>> +    _postRedeem(_amount: uint256) <<VaultCore>> +    _allocate() <<OETHVaultCore>> +    _rebase(): uint256 <<whenNotRebasePaused>> <<VaultCore>> +    _totalValue(): (value: uint256) <<OETHVaultCore>> +    _totalValueInVault(): (value: uint256) <<OETHVaultCore>> +    _totalValueInStrategies(): (value: uint256) <<VaultCore>> +    _totalValueInStrategy(_strategyAddr: address): (value: uint256) <<VaultCore>> +    _checkBalance(_asset: address): (balance: uint256) <<OETHVaultCore>> +    _calculateRedeemOutputs(_amount: uint256): (outputs: uint256[]) <<OETHVaultCore>> +    _toUnits(_raw: uint256, _asset: address): uint256 <<VaultCore>> +    _toUnitPrice(_asset: address, isMint: bool): (price: uint256) <<VaultCore>> +    _getDecimals(_asset: address): (decimals: uint256) <<VaultCore>> +    _claimWithdrawal(requestId: uint256): (amount: uint256) <<OETHVaultCore>> +    _addWithdrawalQueueLiquidity(): (addedClaimable: uint256) <<OETHVaultCore>> +    _wethAvailable(): (wethAvailable: uint256) <<OETHVaultCore>> +External: +    transferGovernance(_newGovernor: address) <<onlyGovernor>> <<Governable>> +    claimGovernance() <<Governable>> +    setAdminImpl(newImpl: address) <<onlyGovernor>> <<VaultStorage>> +    initialize(_priceProvider: address, _oToken: address) <<onlyGovernor, initializer>> <<VaultInitializer>> +    mint(_asset: address, _amount: uint256, _minimumOusdAmount: uint256) <<whenNotCapitalPaused, nonReentrant>> <<VaultCore>> +    mintForStrategy(_amount: uint256) <<whenNotCapitalPaused, onlyOusdMetaStrategy>> <<VaultCore>> +    redeem(uint256, uint256) <<OSonicVaultCore>> +    burnForStrategy(_amount: uint256) <<whenNotCapitalPaused, onlyOusdMetaStrategy>> <<VaultCore>> +    redeemAll(_minimumUnitAmount: uint256) <<whenNotCapitalPaused, nonReentrant>> <<VaultCore>> +    allocate() <<whenNotCapitalPaused, nonReentrant>> <<OETHVaultCore>> +    rebase() <<nonReentrant>> <<VaultCore>> +    totalValue(): (value: uint256) <<VaultCore>> +    checkBalance(_asset: address): uint256 <<VaultCore>> +    calculateRedeemOutputs(_amount: uint256): uint256[] <<VaultCore>> +    priceUnitMint(asset: address): (price: uint256) <<VaultCore>> +    priceUnitRedeem(asset: address): (price: uint256) <<VaultCore>> +    getAllAssets(): address[] <<VaultCore>> +    getStrategyCount(): uint256 <<VaultCore>> +    getAllStrategies(): address[] <<VaultCore>> +    isSupportedAsset(_asset: address): bool <<VaultCore>> +    null() <<VaultCore>> +    cacheWETHAssetIndex() <<onlyGovernor>> <<OETHVaultCore>> +    requestWithdrawal(_amount: uint256): (requestId: uint256, queued: uint256) <<whenNotCapitalPaused, nonReentrant>> <<OETHVaultCore>> +    claimWithdrawal(_requestId: uint256): (amount: uint256) <<whenNotCapitalPaused, nonReentrant>> <<OETHVaultCore>> +    claimWithdrawals(_requestIds: uint256[]): (amounts: uint256[], totalAmount: uint256) <<whenNotCapitalPaused, nonReentrant>> <<OETHVaultCore>> +    addWithdrawalQueueLiquidity() <<OETHVaultCore>> +Public: +    <<event>> PendingGovernorshipTransfer(previousGovernor: address, newGovernor: address) <<Governable>> +    <<event>> GovernorshipTransferred(previousGovernor: address, newGovernor: address) <<Governable>> +    <<event>> AssetSupported(_asset: address) <<VaultStorage>> +    <<event>> AssetRemoved(_asset: address) <<VaultStorage>> +    <<event>> AssetDefaultStrategyUpdated(_asset: address, _strategy: address) <<VaultStorage>> +    <<event>> AssetAllocated(_asset: address, _strategy: address, _amount: uint256) <<VaultStorage>> +    <<event>> StrategyApproved(_addr: address) <<VaultStorage>> +    <<event>> StrategyRemoved(_addr: address) <<VaultStorage>> +    <<event>> Mint(_addr: address, _value: uint256) <<VaultStorage>> +    <<event>> Redeem(_addr: address, _value: uint256) <<VaultStorage>> +    <<event>> CapitalPaused() <<VaultStorage>> +    <<event>> CapitalUnpaused() <<VaultStorage>> +    <<event>> RebasePaused() <<VaultStorage>> +    <<event>> RebaseUnpaused() <<VaultStorage>> +    <<event>> VaultBufferUpdated(_vaultBuffer: uint256) <<VaultStorage>> +    <<event>> OusdMetaStrategyUpdated(_ousdMetaStrategy: address) <<VaultStorage>> +    <<event>> RedeemFeeUpdated(_redeemFeeBps: uint256) <<VaultStorage>> +    <<event>> PriceProviderUpdated(_priceProvider: address) <<VaultStorage>> +    <<event>> AllocateThresholdUpdated(_threshold: uint256) <<VaultStorage>> +    <<event>> RebaseThresholdUpdated(_threshold: uint256) <<VaultStorage>> +    <<event>> StrategistUpdated(_address: address) <<VaultStorage>> +    <<event>> MaxSupplyDiffChanged(maxSupplyDiff: uint256) <<VaultStorage>> +    <<event>> YieldDistribution(_to: address, _yield: uint256, _fee: uint256) <<VaultStorage>> +    <<event>> TrusteeFeeBpsChanged(_basis: uint256) <<VaultStorage>> +    <<event>> TrusteeAddressChanged(_address: address) <<VaultStorage>> +    <<event>> NetOusdMintForStrategyThresholdChanged(_threshold: uint256) <<VaultStorage>> +    <<event>> SwapperChanged(_address: address) <<VaultStorage>> +    <<event>> SwapAllowedUndervalueChanged(_basis: uint256) <<VaultStorage>> +    <<event>> SwapSlippageChanged(_asset: address, _basis: uint256) <<VaultStorage>> +    <<event>> Swapped(_fromAsset: address, _toAsset: address, _fromAssetAmount: uint256, _toAssetAmount: uint256) <<VaultStorage>> +    <<event>> StrategyAddedToMintWhitelist(strategy: address) <<VaultStorage>> +    <<event>> StrategyRemovedFromMintWhitelist(strategy: address) <<VaultStorage>> +    <<event>> DripperChanged(_dripper: address) <<VaultStorage>> +    <<event>> WithdrawalRequested(_withdrawer: address, _requestId: uint256, _amount: uint256, _queued: uint256) <<VaultStorage>> +    <<event>> WithdrawalClaimed(_withdrawer: address, _requestId: uint256, _amount: uint256) <<VaultStorage>> +    <<event>> WithdrawalClaimable(_claimable: uint256, _newClaimable: uint256) <<VaultStorage>> +    <<event>> WithdrawalClaimDelayUpdated(_newDelay: uint256) <<VaultStorage>> +    <<modifier>> initializer() <<Initializable>> +    <<modifier>> onlyGovernor() <<Governable>> +    <<modifier>> nonReentrant() <<Governable>> +    <<modifier>> whenNotRebasePaused() <<VaultCore>> +    <<modifier>> whenNotCapitalPaused() <<VaultCore>> +    <<modifier>> onlyOusdMetaStrategy() <<VaultCore>> +    constructor() <<Governable>> +    governor(): address <<Governable>> +    isGovernor(): bool <<Governable>> +    getAssetCount(): uint256 <<VaultCore>> +    getAssetConfig(_asset: address): (config: Asset) <<VaultCore>> +    constructor(_wS: address) <<OSonicVaultCore>> + + + diff --git a/contracts/docs/OSonicVaultStorage.svg b/contracts/docs/OSonicVaultStorage.svg new file mode 100644 index 0000000000..1f9243ad89 --- /dev/null +++ b/contracts/docs/OSonicVaultStorage.svg @@ -0,0 +1,359 @@ + + + + + + +StorageDiagram + + + +8 + +OSonicVaultCore <<Contract>> + +slot + +0 + +1-50 + +51 + +52 + +53 + +54 + +55 + +56 + +57 + +58 + +59 + +60 + +61 + +62 + +63 + +64 + +65 + +66 + +67 + +68 + +69 + +70 + +71 + +72 + +73 + +74 + +75-76 + +77 + +78 + +79-122 + +123 + +124-173 + +type: <inherited contract>.variable (bytes) + +unallocated (30) + +bool: Initializable.initializing (1) + +bool: Initializable.initialized (1) + +uint256[50]: Initializable.______gap (1600) + +mapping(address=>Asset): VaultStorage.assets (32) + +address[]: VaultStorage.allAssets (32) + +mapping(address=>Strategy): VaultStorage.strategies (32) + +address[]: VaultStorage.allStrategies (32) + +unallocated (10) + +bool: VaultStorage.capitalPaused (1) + +bool: VaultStorage.rebasePaused (1) + +address: VaultStorage.priceProvider (20) + +uint256: VaultStorage.redeemFeeBps (32) + +uint256: VaultStorage.vaultBuffer (32) + +uint256: VaultStorage.autoAllocateThreshold (32) + +uint256: VaultStorage.rebaseThreshold (32) + +unallocated (12) + +OUSD: VaultStorage.oUSD (20) + +unallocated (12) + +address: VaultStorage._deprecated_rebaseHooksAddr (20) + +unallocated (12) + +address: VaultStorage._deprecated_uniswapAddr (20) + +unallocated (12) + +address: VaultStorage.strategistAddr (20) + +mapping(address=>address): VaultStorage.assetDefaultStrategies (32) + +uint256: VaultStorage.maxSupplyDiff (32) + +unallocated (12) + +address: VaultStorage.trusteeAddress (20) + +uint256: VaultStorage.trusteeFeeBps (32) + +address[]: VaultStorage._deprecated_swapTokens (32) + +unallocated (12) + +address: VaultStorage.ousdMetaStrategy (20) + +int256: VaultStorage.netOusdMintedForStrategy (32) + +uint256: VaultStorage.netOusdMintForStrategyThreshold (32) + +SwapConfig: VaultStorage.swapConfig (32) + +mapping(address=>bool): VaultStorage.isMintWhitelistedStrategy (32) + +unallocated (12) + +address: VaultStorage.dripper (20) + +WithdrawalQueueMetadata: VaultStorage.withdrawalQueueMetadata (64) + +mapping(uint256=>WithdrawalRequest): VaultStorage.withdrawalRequests (32) + +uint256: VaultStorage.withdrawalClaimDelay (32) + +uint256[44]: VaultStorage.__gap (1408) + +uint256: OETHVaultCore.wethAssetIndex (32) + +uint256[50]: OETHVaultCore.__gap (1600) + + + +1 + +Asset <<Struct>> + +offset + +0 + +type: variable (bytes) + +unallocated (27) + +uint16: allowedOracleSlippageBps (2) + +uint8: decimals (1) + +UnitConversion: unitConversion (1) + +bool: isSupported (1) + + + +8:8->1 + + + + + +2 + +address[]: allAssets <<Array>> +0x46bddb1178e94d7f2892ff5f366840eb658911794f2c3a44c450aa2c505186c1 + +offset + +0 + +type: variable (bytes) + +unallocated (12) + +address (20) + + + +8:10->2 + + + + + +3 + +Strategy <<Struct>> + +offset + +0 + +1 + +type: variable (bytes) + +unallocated (31) + +bool: isSupported (1) + +uint256: _deprecated (32) + + + +8:13->3 + + + + + +4 + +address[]: allStrategies <<Array>> +0x4a11f94e20a93c79f6ec743a1954ec4fc2c08429ae2122118bf234b2185c81b8 + +offset + +0 + +type: variable (bytes) + +unallocated (12) + +address (20) + + + +8:15->4 + + + + + +5 + +SwapConfig <<Struct>> + +slot + +72 + +type: variable (bytes) + +unallocated (10) + +uint16: allowedUndervalueBps (2) + +address: swapper (20) + + + +8:37->5 + + + + + +6 + +WithdrawalQueueMetadata <<Struct>> + +slot + +75 + +76 + +type: variable (bytes) + +uint128: claimable (16) + +uint128: queued (16) + +uint128: nextWithdrawalIndex (16) + +uint128: claimed (16) + + + +8:44->6 + + + + + +7 + +WithdrawalRequest <<Struct>> + +offset + +0 + +1 + +type: variable (bytes) + +unallocated (6) + +uint40: timestamp (5) + +bool: claimed (1) + +address: withdrawer (20) + +uint128: queued (16) + +uint128: amount (16) + + + +8:50->7 + + + + + diff --git a/contracts/docs/OUSDHierarchy.svg b/contracts/docs/OUSDHierarchy.svg index 48065cc6b3..bc07ef4584 100644 --- a/contracts/docs/OUSDHierarchy.svg +++ b/contracts/docs/OUSDHierarchy.svg @@ -16,16 +16,16 @@ Governable ../contracts/governance/Governable.sol - + -228 +245 OUSD ../contracts/token/OUSD.sol - + -228->21 +245->21 diff --git a/contracts/docs/OUSDSquashed.svg b/contracts/docs/OUSDSquashed.svg index 0da5b4771a..6b991fa976 100644 --- a/contracts/docs/OUSDSquashed.svg +++ b/contracts/docs/OUSDSquashed.svg @@ -4,101 +4,100 @@ - - + + UmlClassDiagram - - + + -228 - -OUSD -../contracts/token/OUSD.sol - -Private: -   governorPosition: bytes32 <<Governable>> -   pendingGovernorPosition: bytes32 <<Governable>> -   reentryStatusPosition: bytes32 <<Governable>> -   _gap: uint256[154] <<OUSD>> -   MAX_SUPPLY: uint256 <<OUSD>> -   _allowances: mapping(address=>mapping(address=>uint256)) <<OUSD>> -   _creditBalances: mapping(address=>uint256) <<OUSD>> -   _rebasingCredits: uint256 <<OUSD>> -   _rebasingCreditsPerToken: uint256 <<OUSD>> -   alternativeCreditsPerToken: mapping(address=>uint256) <<OUSD>> +245 + +OUSD +../contracts/token/OUSD.sol + +Private: +   governorPosition: bytes32 <<Governable>> +   pendingGovernorPosition: bytes32 <<Governable>> +   reentryStatusPosition: bytes32 <<Governable>> +   _gap: uint256[154] <<OUSD>> +   MAX_SUPPLY: uint256 <<OUSD>> +   allowances: mapping(address=>mapping(address=>uint256)) <<OUSD>> +   rebasingCredits_: uint256 <<OUSD>> +   rebasingCreditsPerToken_: uint256 <<OUSD>> +   __deprecated_isUpgraded: mapping(address=>uint256) <<OUSD>>   RESOLUTION_INCREASE: uint256 <<OUSD>> -Public: -   _NOT_ENTERED: uint256 <<Governable>> -   _ENTERED: uint256 <<Governable>> -   _totalSupply: uint256 <<OUSD>> -   vaultAddress: address <<OUSD>> -   nonRebasingSupply: uint256 <<OUSD>> -   rebaseState: mapping(address=>RebaseOptions) <<OUSD>> -   isUpgraded: mapping(address=>uint256) <<OUSD>> -   yieldTo: mapping(address=>address) <<OUSD>> -   yieldFrom: mapping(address=>address) <<OUSD>> - -Internal: -    _governor(): (governorOut: address) <<Governable>> -    _pendingGovernor(): (pendingGovernor: address) <<Governable>> -    _setGovernor(newGovernor: address) <<Governable>> -    _setPendingGovernor(newGovernor: address) <<Governable>> -    _changeGovernor(_newGovernor: address) <<Governable>> -    _executeTransfer(_from: address, _to: address, _value: uint256) <<OUSD>> -    _adjustAccount(account: address, balanceChange: int256): (rebasingCreditsDiff: int256, nonRebasingSupplyDiff: int256) <<OUSD>> -    _adjustGlobals(rebasingCreditsDiff: int256, nonRebasingSupplyDiff: int256) <<OUSD>> -    _mint(_account: address, _amount: uint256) <<nonReentrant>> <<OUSD>> -    _burn(_account: address, _amount: uint256) <<nonReentrant>> <<OUSD>> -    _creditsPerToken(_account: address): uint256 <<OUSD>> -    _isNonRebasingAccount(_account: address): bool <<OUSD>> -    _balanceToRebasingCredits(balance: uint256): uint256 <<OUSD>> -    _rebaseOptIn(_account: address) <<OUSD>> -    _rebaseOptOut(_account: address) <<OUSD>> -External: -    transferGovernance(_newGovernor: address) <<onlyGovernor>> <<Governable>> -    claimGovernance() <<Governable>> -    initialize(string, string, _vaultAddress: address, _initialCreditsPerToken: uint256) <<onlyGovernor>> <<OUSD>> -    symbol(): string <<OUSD>> -    name(): string <<OUSD>> -    decimals(): uint8 <<OUSD>> -    nonRebasingCreditsPerToken(_account: address): uint256 <<OUSD>> -    mint(_account: address, _amount: uint256) <<onlyVault>> <<OUSD>> -    burn(account: address, amount: uint256) <<onlyVault>> <<OUSD>> -    changeSupply(_newTotalSupply: uint256) <<onlyVault, nonReentrant>> <<OUSD>> -    delegateYield(from: address, to: address) <<onlyGovernor, nonReentrant>> <<OUSD>> -    undelegateYield(from: address) <<onlyGovernor, nonReentrant>> <<OUSD>> -Public: -    <<event>> PendingGovernorshipTransfer(previousGovernor: address, newGovernor: address) <<Governable>> -    <<event>> GovernorshipTransferred(previousGovernor: address, newGovernor: address) <<Governable>> -    <<event>> TotalSupplyUpdatedHighres(totalSupply: uint256, rebasingCredits: uint256, rebasingCreditsPerToken: uint256) <<OUSD>> -    <<event>> AccountRebasingEnabled(account: address) <<OUSD>> -    <<event>> AccountRebasingDisabled(account: address) <<OUSD>> -    <<event>> Transfer(from: address, to: address, value: uint256) <<OUSD>> -    <<event>> Approval(owner: address, spender: address, value: uint256) <<OUSD>> -    <<modifier>> onlyGovernor() <<Governable>> -    <<modifier>> nonReentrant() <<Governable>> -    <<modifier>> onlyVault() <<OUSD>> -    constructor() <<Governable>> -    governor(): address <<Governable>> -    isGovernor(): bool <<Governable>> -    totalSupply(): uint256 <<OUSD>> -    rebasingCreditsPerTokenHighres(): uint256 <<OUSD>> -    rebasingCreditsPerToken(): uint256 <<OUSD>> -    rebasingCreditsHighres(): uint256 <<OUSD>> -    rebasingCredits(): uint256 <<OUSD>> -    balanceOf(_account: address): uint256 <<OUSD>> -    creditsBalanceOf(_account: address): (uint256, uint256) <<OUSD>> -    creditsBalanceOfHighres(_account: address): (uint256, uint256, bool) <<OUSD>> -    transfer(_to: address, _value: uint256): bool <<OUSD>> -    transferFrom(_from: address, _to: address, _value: uint256): bool <<OUSD>> -    allowance(_owner: address, _spender: address): uint256 <<OUSD>> -    approve(_spender: address, _value: uint256): bool <<OUSD>> -    increaseAllowance(_spender: address, _addedValue: uint256): bool <<OUSD>> -    decreaseAllowance(_spender: address, _subtractedValue: uint256): bool <<OUSD>> -    governanceRebaseOptIn(_account: address) <<nonReentrant, onlyGovernor>> <<OUSD>> -    rebaseOptIn() <<nonReentrant>> <<OUSD>> -    rebaseOptOut() <<nonReentrant>> <<OUSD>> +   __gap: uint256[34] <<OUSD>> +Internal: +   creditBalances: mapping(address=>uint256) <<OUSD>> +   alternativeCreditsPerToken: mapping(address=>uint256) <<OUSD>> +Public: +   _NOT_ENTERED: uint256 <<Governable>> +   _ENTERED: uint256 <<Governable>> +   totalSupply: uint256 <<OUSD>> +   vaultAddress: address <<OUSD>> +   nonRebasingSupply: uint256 <<OUSD>> +   rebaseState: mapping(address=>RebaseOptions) <<OUSD>> +   yieldTo: mapping(address=>address) <<OUSD>> +   yieldFrom: mapping(address=>address) <<OUSD>> + +Internal: +    _governor(): (governorOut: address) <<Governable>> +    _pendingGovernor(): (pendingGovernor: address) <<Governable>> +    _setGovernor(newGovernor: address) <<Governable>> +    _setPendingGovernor(newGovernor: address) <<Governable>> +    _changeGovernor(_newGovernor: address) <<Governable>> +    _executeTransfer(_from: address, _to: address, _value: uint256) <<OUSD>> +    _adjustAccount(_account: address, _balanceChange: int256): (rebasingCreditsDiff: int256, nonRebasingSupplyDiff: int256) <<OUSD>> +    _adjustGlobals(_rebasingCreditsDiff: int256, _nonRebasingSupplyDiff: int256) <<OUSD>> +    _creditsPerToken(_account: address): uint256 <<OUSD>> +    _autoMigrate(_account: address) <<OUSD>> +    _balanceToRebasingCredits(_balance: uint256): (rebasingCredits: uint256) <<OUSD>> +    _rebaseOptIn(_account: address) <<OUSD>> +    _rebaseOptOut(_account: address) <<OUSD>> +External: +    transferGovernance(_newGovernor: address) <<onlyGovernor>> <<Governable>> +    claimGovernance() <<Governable>> +    initialize(_vaultAddress: address, _initialCreditsPerToken: uint256) <<onlyGovernor>> <<OUSD>> +    symbol(): string <<OUSD>> +    name(): string <<OUSD>> +    decimals(): uint8 <<OUSD>> +    rebasingCreditsPerTokenHighres(): uint256 <<OUSD>> +    rebasingCreditsPerToken(): uint256 <<OUSD>> +    rebasingCreditsHighres(): uint256 <<OUSD>> +    rebasingCredits(): uint256 <<OUSD>> +    creditsBalanceOf(_account: address): (uint256, uint256) <<OUSD>> +    creditsBalanceOfHighres(_account: address): (uint256, uint256, bool) <<OUSD>> +    nonRebasingCreditsPerToken(_account: address): uint256 <<OUSD>> +    transfer(_to: address, _value: uint256): bool <<OUSD>> +    transferFrom(_from: address, _to: address, _value: uint256): bool <<OUSD>> +    allowance(_owner: address, _spender: address): uint256 <<OUSD>> +    approve(_spender: address, _value: uint256): bool <<OUSD>> +    mint(_account: address, _amount: uint256) <<onlyVault>> <<OUSD>> +    burn(_account: address, _amount: uint256) <<onlyVault>> <<OUSD>> +    governanceRebaseOptIn(_account: address) <<onlyGovernor>> <<OUSD>> +    rebaseOptIn() <<OUSD>> +    rebaseOptOut() <<OUSD>> +    changeSupply(_newTotalSupply: uint256) <<onlyVault>> <<OUSD>> +    delegateYield(_from: address, _to: address) <<onlyGovernor>> <<OUSD>> +    undelegateYield(_from: address) <<onlyGovernor>> <<OUSD>> +Public: +    <<event>> PendingGovernorshipTransfer(previousGovernor: address, newGovernor: address) <<Governable>> +    <<event>> GovernorshipTransferred(previousGovernor: address, newGovernor: address) <<Governable>> +    <<event>> TotalSupplyUpdatedHighres(totalSupply: uint256, rebasingCredits: uint256, rebasingCreditsPerToken: uint256) <<OUSD>> +    <<event>> AccountRebasingEnabled(account: address) <<OUSD>> +    <<event>> AccountRebasingDisabled(account: address) <<OUSD>> +    <<event>> Transfer(from: address, to: address, value: uint256) <<OUSD>> +    <<event>> Approval(owner: address, spender: address, value: uint256) <<OUSD>> +    <<event>> YieldDelegated(source: address, target: address) <<OUSD>> +    <<event>> YieldUndelegated(source: address, target: address) <<OUSD>> +    <<modifier>> onlyGovernor() <<Governable>> +    <<modifier>> nonReentrant() <<Governable>> +    <<modifier>> onlyVault() <<OUSD>> +    constructor() <<Governable>> +    governor(): address <<Governable>> +    isGovernor(): bool <<Governable>> +    balanceOf(_account: address): uint256 <<OUSD>> diff --git a/contracts/docs/OUSDStorage.svg b/contracts/docs/OUSDStorage.svg index 2adf9ca802..9a43d44a05 100644 --- a/contracts/docs/OUSDStorage.svg +++ b/contracts/docs/OUSDStorage.svg @@ -4,74 +4,78 @@ - - + + StorageDiagram - + 1 - -OUSD <<Contract>> - -slot - -0-153 - -154 - -155 - -156 - -157 - -158 - -159 - -160 - -161 - -162 - -163 - -164 - -165 - -type: <inherited contract>.variable (bytes) - -uint256[154]: _gap (4928) - -uint256: _totalSupply (32) - -mapping(address=>mapping(address=>uint256)): _allowances (32) - -unallocated (12) - -address: vaultAddress (20) - -mapping(address=>uint256): _creditBalances (32) - -uint256: _rebasingCredits (32) - -uint256: _rebasingCreditsPerToken (32) - -uint256: nonRebasingSupply (32) - -mapping(address=>uint256): alternativeCreditsPerToken (32) - -mapping(address=>RebaseOptions): rebaseState (32) - -mapping(address=>uint256): isUpgraded (32) - -mapping(address=>address): yieldTo (32) - -mapping(address=>address): yieldFrom (32) + +OUSD <<Contract>> + +slot + +0-153 + +154 + +155 + +156 + +157 + +158 + +159 + +160 + +161 + +162 + +163 + +164 + +165 + +166-199 + +type: <inherited contract>.variable (bytes) + +uint256[154]: _gap (4928) + +uint256: totalSupply (32) + +mapping(address=>mapping(address=>uint256)): allowances (32) + +unallocated (12) + +address: vaultAddress (20) + +mapping(address=>uint256): creditBalances (32) + +uint256: rebasingCredits_ (32) + +uint256: rebasingCreditsPerToken_ (32) + +uint256: nonRebasingSupply (32) + +mapping(address=>uint256): alternativeCreditsPerToken (32) + +mapping(address=>RebaseOptions): rebaseState (32) + +mapping(address=>uint256): __deprecated_isUpgraded (32) + +mapping(address=>address): yieldTo (32) + +mapping(address=>address): yieldFrom (32) + +uint256[34]: __gap (1088) diff --git a/contracts/docs/SonicStakingStrategyHierarchy.svg b/contracts/docs/SonicStakingStrategyHierarchy.svg new file mode 100644 index 0000000000..f599e11a30 --- /dev/null +++ b/contracts/docs/SonicStakingStrategyHierarchy.svg @@ -0,0 +1,75 @@ + + + + + + +UmlClassDiagram + + + +21 + +Governable +../contracts/governance/Governable.sol + + + +373 + +SonicStakingStrategy +../contracts/strategies/sonic/SonicStakingStrategy.sol + + + +374 + +<<Abstract>> +SonicValidatorDelegator +../contracts/strategies/sonic/SonicValidatorDelegator.sol + + + +373->374 + + + + + +262 + +<<Abstract>> +InitializableAbstractStrategy +../contracts/utils/InitializableAbstractStrategy.sol + + + +374->262 + + + + + +261 + +<<Abstract>> +Initializable +../contracts/utils/Initializable.sol + + + +262->21 + + + + + +262->261 + + + + + diff --git a/contracts/docs/SonicStakingStrategySquashed.svg b/contracts/docs/SonicStakingStrategySquashed.svg new file mode 100644 index 0000000000..b989602dd1 --- /dev/null +++ b/contracts/docs/SonicStakingStrategySquashed.svg @@ -0,0 +1,124 @@ + + + + + + +UmlClassDiagram + + + +373 + +SonicStakingStrategy +../contracts/strategies/sonic/SonicStakingStrategy.sol + +Private: +   initialized: bool <<Initializable>> +   initializing: bool <<Initializable>> +   ______gap: uint256[50] <<Initializable>> +   governorPosition: bytes32 <<Governable>> +   pendingGovernorPosition: bytes32 <<Governable>> +   reentryStatusPosition: bytes32 <<Governable>> +   _deprecated_platformAddress: address <<InitializableAbstractStrategy>> +   _deprecated_vaultAddress: address <<InitializableAbstractStrategy>> +   _deprecated_rewardTokenAddress: address <<InitializableAbstractStrategy>> +   _deprecated_rewardLiquidationThreshold: uint256 <<InitializableAbstractStrategy>> +   _reserved: int256[98] <<InitializableAbstractStrategy>> +   __gap: uint256[45] <<SonicValidatorDelegator>> +   __gap: uint256[49] <<SonicStakingStrategy>> +Internal: +   assetsMapped: address[] <<InitializableAbstractStrategy>> +Public: +   _NOT_ENTERED: uint256 <<Governable>> +   _ENTERED: uint256 <<Governable>> +   platformAddress: address <<InitializableAbstractStrategy>> +   vaultAddress: address <<InitializableAbstractStrategy>> +   assetToPToken: mapping(address=>address) <<InitializableAbstractStrategy>> +   harvesterAddress: address <<InitializableAbstractStrategy>> +   rewardTokenAddresses: address[] <<InitializableAbstractStrategy>> +   wrappedSonic: address <<SonicValidatorDelegator>> +   sfc: address <<SonicValidatorDelegator>> +   nextWithdrawId: uint256 <<SonicValidatorDelegator>> +   pendingWithdrawals: uint256 <<SonicValidatorDelegator>> +   supportedValidators: uint256[] <<SonicValidatorDelegator>> +   withdrawals: mapping(uint256=>WithdrawRequest) <<SonicValidatorDelegator>> +   validatorRegistrator: address <<SonicValidatorDelegator>> +   depositedWSAccountedFor: uint256 <<SonicStakingStrategy>> + +Internal: +    _governor(): (governorOut: address) <<Governable>> +    _pendingGovernor(): (pendingGovernor: address) <<Governable>> +    _setGovernor(newGovernor: address) <<Governable>> +    _setPendingGovernor(newGovernor: address) <<Governable>> +    _changeGovernor(_newGovernor: address) <<Governable>> +    _initialize(_rewardTokenAddresses: address[], _assets: address[], _pTokens: address[]) <<InitializableAbstractStrategy>> +    _collectRewardTokens() <<InitializableAbstractStrategy>> +    _setPTokenAddress(_asset: address, _pToken: address) <<InitializableAbstractStrategy>> +    _abstractSetPToken(address, address) <<SonicStakingStrategy>> +    _deposit(_asset: address, _amount: uint256) <<SonicStakingStrategy>> +    _withdraw(_recipient: address, _asset: address, _amount: uint256) <<SonicStakingStrategy>> +External: +    <<payable>> null() <<SonicValidatorDelegator>> +    transferGovernance(_newGovernor: address) <<onlyGovernor>> <<Governable>> +    claimGovernance() <<Governable>> +    collectRewardTokens() <<nonReentrant>> <<SonicStakingStrategy>> +    setRewardTokenAddresses(_rewardTokenAddresses: address[]) <<onlyGovernor>> <<InitializableAbstractStrategy>> +    getRewardTokenAddresses(): address[] <<InitializableAbstractStrategy>> +    setPTokenAddress(address, address) <<onlyGovernor>> <<SonicStakingStrategy>> +    removePToken(uint256) <<onlyGovernor>> <<SonicStakingStrategy>> +    setHarvesterAddress(_harvesterAddress: address) <<onlyGovernor>> <<InitializableAbstractStrategy>> +    safeApproveAllTokens() <<onlyGovernor>> <<SonicStakingStrategy>> +    deposit(_asset: address, _amount: uint256) <<onlyVault, nonReentrant>> <<SonicStakingStrategy>> +    depositAll() <<onlyVault, nonReentrant>> <<SonicStakingStrategy>> +    withdraw(_recipient: address, _asset: address, _amount: uint256) <<onlyVault, nonReentrant>> <<SonicStakingStrategy>> +    withdrawAll() <<onlyVaultOrGovernor, nonReentrant>> <<SonicStakingStrategy>> +    checkBalance(_asset: address): (balance: uint256) <<SonicValidatorDelegator>> +    initialize() <<onlyGovernor, initializer>> <<SonicValidatorDelegator>> +    delegate(validatorId: uint256, amount: uint256) <<onlyRegistrator, nonReentrant>> <<SonicValidatorDelegator>> +    undelegate(validatorId: uint256, undelegateAmount: uint256): (withdrawId: uint256) <<onlyRegistrator, nonReentrant>> <<SonicValidatorDelegator>> +    withdrawFromSFC(withdrawId: uint256): (withdrawnAmount: uint256) <<onlyRegistrator, nonReentrant>> <<SonicValidatorDelegator>> +    restakeRewards(validatorIds: uint256[]) <<nonReentrant>> <<SonicValidatorDelegator>> +    setRegistrator(_address: address) <<onlyGovernor>> <<SonicValidatorDelegator>> +    supportValidator(validatorId: uint256) <<onlyGovernor>> <<SonicValidatorDelegator>> +    unsupportValidator(validatorId: uint256) <<onlyGovernor>> <<SonicValidatorDelegator>> +    supportedValidatorsLength(): uint256 <<SonicValidatorDelegator>> +Public: +    <<event>> PendingGovernorshipTransfer(previousGovernor: address, newGovernor: address) <<Governable>> +    <<event>> GovernorshipTransferred(previousGovernor: address, newGovernor: address) <<Governable>> +    <<event>> PTokenAdded(_asset: address, _pToken: address) <<InitializableAbstractStrategy>> +    <<event>> PTokenRemoved(_asset: address, _pToken: address) <<InitializableAbstractStrategy>> +    <<event>> Deposit(_asset: address, _pToken: address, _amount: uint256) <<InitializableAbstractStrategy>> +    <<event>> Withdrawal(_asset: address, _pToken: address, _amount: uint256) <<InitializableAbstractStrategy>> +    <<event>> RewardTokenCollected(recipient: address, rewardToken: address, amount: uint256) <<InitializableAbstractStrategy>> +    <<event>> RewardTokenAddressesUpdated(_oldAddresses: address[], _newAddresses: address[]) <<InitializableAbstractStrategy>> +    <<event>> HarvesterAddressesUpdated(_oldHarvesterAddress: address, _newHarvesterAddress: address) <<InitializableAbstractStrategy>> +    <<event>> Delegated(validatorId: uint256, delegatedAmount: uint256) <<SonicValidatorDelegator>> +    <<event>> Undelegated(withdrawId: uint256, validatorId: uint256, undelegatedAmount: uint256) <<SonicValidatorDelegator>> +    <<event>> Withdrawn(withdrawId: uint256, validatorId: uint256, undelegatedAmount: uint256, withdrawnAmount: uint256) <<SonicValidatorDelegator>> +    <<event>> RegistratorChanged(newAddress: address) <<SonicValidatorDelegator>> +    <<event>> SupportedValidator(validatorId: uint256) <<SonicValidatorDelegator>> +    <<event>> UnsupportedValidator(validatorId: uint256) <<SonicValidatorDelegator>> +    <<modifier>> initializer() <<Initializable>> +    <<modifier>> onlyGovernor() <<Governable>> +    <<modifier>> nonReentrant() <<Governable>> +    <<modifier>> onlyVault() <<InitializableAbstractStrategy>> +    <<modifier>> onlyHarvester() <<InitializableAbstractStrategy>> +    <<modifier>> onlyVaultOrGovernor() <<InitializableAbstractStrategy>> +    <<modifier>> onlyVaultOrGovernorOrStrategist() <<InitializableAbstractStrategy>> +    <<modifier>> onlyRegistrator() <<SonicValidatorDelegator>> +    constructor() <<Governable>> +    governor(): address <<Governable>> +    isGovernor(): bool <<Governable>> +    constructor(_config: BaseStrategyConfig) <<InitializableAbstractStrategy>> +    transferToken(_asset: address, _amount: uint256) <<onlyGovernor>> <<InitializableAbstractStrategy>> +    supportsAsset(_asset: address): bool <<SonicStakingStrategy>> +    constructor(_baseConfig: BaseStrategyConfig, _wrappedSonic: address, _sfc: address) <<SonicStakingStrategy>> +    isWithdrawnFromSFC(withdrawId: uint256): bool <<SonicValidatorDelegator>> +    isSupportedValidator(validatorId: uint256): bool <<SonicValidatorDelegator>> + + + diff --git a/contracts/docs/SonicStakingStrategyStorage.svg b/contracts/docs/SonicStakingStrategyStorage.svg new file mode 100644 index 0000000000..0fa464541b --- /dev/null +++ b/contracts/docs/SonicStakingStrategyStorage.svg @@ -0,0 +1,208 @@ + + + + + + +StorageDiagram + + + +5 + +SonicStakingStrategy <<Contract>> + +slot + +0 + +1-50 + +51 + +52 + +53 + +54 + +55 + +56 + +57 + +58 + +59-156 + +157 + +158 + +159 + +160 + +161 + +162-206 + +207 + +208-256 + +type: <inherited contract>.variable (bytes) + +unallocated (30) + +bool: Initializable.initializing (1) + +bool: Initializable.initialized (1) + +uint256[50]: Initializable.______gap (1600) + +unallocated (12) + +address: InitializableAbstractStrategy._deprecated_platformAddress (20) + +unallocated (12) + +address: InitializableAbstractStrategy._deprecated_vaultAddress (20) + +mapping(address=>address): InitializableAbstractStrategy.assetToPToken (32) + +address[]: InitializableAbstractStrategy.assetsMapped (32) + +unallocated (12) + +address: InitializableAbstractStrategy._deprecated_rewardTokenAddress (20) + +uint256: InitializableAbstractStrategy._deprecated_rewardLiquidationThreshold (32) + +unallocated (12) + +address: InitializableAbstractStrategy.harvesterAddress (20) + +address[]: InitializableAbstractStrategy.rewardTokenAddresses (32) + +int256[98]: InitializableAbstractStrategy._reserved (3136) + +uint256: SonicValidatorDelegator.nextWithdrawId (32) + +uint256: SonicValidatorDelegator.pendingWithdrawals (32) + +uint256[]: SonicValidatorDelegator.supportedValidators (32) + +mapping(uint256=>WithdrawRequest): SonicValidatorDelegator.withdrawals (32) + +unallocated (12) + +address: SonicValidatorDelegator.validatorRegistrator (20) + +uint256[45]: SonicValidatorDelegator.__gap (1440) + +uint256: depositedWSAccountedFor (32) + +uint256[49]: __gap (1568) + + + +1 + +address[]: assetsMapped <<Array>> +0x4a11f94e20a93c79f6ec743a1954ec4fc2c08429ae2122118bf234b2185c81b8 + +offset + +0 + +type: variable (bytes) + +unallocated (12) + +address (20) + + + +5:8->1 + + + + + +2 + +address[]: rewardTokenAddresses <<Array>> +0xa2999d817b6757290b50e8ecf3fa939673403dd35c97de392fdb343b4015ce9e + +offset + +0 + +type: variable (bytes) + +unallocated (12) + +address (20) + + + +5:13->2 + + + + + +3 + +uint256[]: supportedValidators <<Array>> +0x0bc14066c33013fe88f66e314e4cf150b0b2d4d6451a1a51dbbd1c27cd11de28 + +offset + +0 + +type: variable (bytes) + +uint256 (32) + + + +5:18->3 + + + + + +4 + +WithdrawRequest <<Struct>> + +offset + +0 + +1 + +2 + +type: variable (bytes) + +uint256: validatorId (32) + +uint256: undelegatedAmount (32) + +uint256: timestamp (32) + + + +5:22->4 + + + + + diff --git a/contracts/docs/WOETHBaseHierarchy.svg b/contracts/docs/WOETHBaseHierarchy.svg index 6a30e8588a..837ec1430b 100644 --- a/contracts/docs/WOETHBaseHierarchy.svg +++ b/contracts/docs/WOETHBaseHierarchy.svg @@ -4,240 +4,142 @@ - - + + UmlClassDiagram - - + + -20 - -Governable -../contracts/governance/Governable.sol +21 + +Governable +../contracts/governance/Governable.sol - + -214 - -OETH -../contracts/token/OETH.sol +242 + +OETH +../contracts/token/OETH.sol - + -216 - -OUSD -../contracts/token/OUSD.sol +245 + +OUSD +../contracts/token/OUSD.sol - + -214->216 - - +242->245 + + - + + +245->21 + + + + + +249 + +WOETH +../contracts/token/WOETH.sol + + -216->20 - - +249->21 + + + + + +249->242 + + - + -226 - -<<Abstract>> -Initializable -../contracts/utils/Initializable.sol +261 + +<<Abstract>> +Initializable +../contracts/utils/Initializable.sol - - -216->226 - - + + +249->261 + + - + -229 - -<<Abstract>> -InitializableERC20Detailed -../contracts/utils/InitializableERC20Detailed.sol +1261 + +<<Abstract>> +ERC4626 +../lib/openzeppelin/contracts/token/ERC20/extensions/ERC4626.sol - + -216->229 - - +249->1261 + + - - -220 - -WOETH -../contracts/token/WOETH.sol + + +775 + +ERC20 +../node_modules/@openzeppelin/contracts/token/ERC20/ERC20.sol - + -220->20 - - +249->775 + + - - -220->214 - - + + +250 + +WOETHBase +../contracts/token/WOETHBase.sol - - -220->226 - - + + +250->249 + + - - -1196 - -<<Abstract>> -ERC4626 -../lib/openzeppelin/contracts/token/ERC20/extensions/ERC4626.sol + + +250->775 + + - - -220->1196 - - - - - -711 - -ERC20 -../node_modules/@openzeppelin/contracts/token/ERC20/ERC20.sol - - - -220->711 - - - - - -712 - -<<Interface>> -IERC20 -../node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol - - + -220->712 - - +1261->775 + + - - -221 - -WOETHBase -../contracts/token/WOETHBase.sol + + +431 + +<<Abstract>> +Context +../node_modules/@openzeppelin/contracts/utils/Context.sol - + -221->220 - - - - - -221->711 - - - - - -229->712 - - - - - -312 - -<<Interface>> -IERC4626 -../lib/openzeppelin/interfaces/IERC4626.sol - - - -1196->312 - - - - - -1196->711 - - - - - -1236 - -<<Interface>> -IERC20Metadata -../node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol - - - -1196->1236 - - - - - -312->712 - - - - - -312->1236 - - - - - -711->712 - - - - - -711->1236 - - - - - -367 - -<<Abstract>> -Context -../node_modules/@openzeppelin/contracts/utils/Context.sol - - - -711->367 - - - - - -1236->712 - - +775->431 + + diff --git a/contracts/docs/WOETHHierarchy.svg b/contracts/docs/WOETHHierarchy.svg index ba45140737..9883c9373d 100644 --- a/contracts/docs/WOETHHierarchy.svg +++ b/contracts/docs/WOETHHierarchy.svg @@ -4,221 +4,123 @@ - - + + UmlClassDiagram - - + + -20 - -Governable -../contracts/governance/Governable.sol +21 + +Governable +../contracts/governance/Governable.sol - + -185 - -OETH -../contracts/token/OETH.sol +242 + +OETH +../contracts/token/OETH.sol - + -186 - -OUSD -../contracts/token/OUSD.sol +245 + +OUSD +../contracts/token/OUSD.sol - + -185->186 - - +242->245 + + - + + +245->21 + + + + + +249 + +WOETH +../contracts/token/WOETH.sol + + -186->20 - - +249->21 + + + + + +249->242 + + - + -194 - -<<Abstract>> -Initializable -../contracts/utils/Initializable.sol +261 + +<<Abstract>> +Initializable +../contracts/utils/Initializable.sol - - -186->194 - - + + +249->261 + + - + -197 - -<<Abstract>> -InitializableERC20Detailed -../contracts/utils/InitializableERC20Detailed.sol +1261 + +<<Abstract>> +ERC4626 +../lib/openzeppelin/contracts/token/ERC20/extensions/ERC4626.sol - + -186->197 - - +249->1261 + + - - -190 - -WOETH -../contracts/token/WOETH.sol + + +775 + +ERC20 +../node_modules/@openzeppelin/contracts/token/ERC20/ERC20.sol - + -190->20 - - +249->775 + + - - -190->185 - - - - - -190->194 - - - - - -745 - -<<Abstract>> -ERC4626 -../lib/openzeppelin/contracts/token/ERC20/extensions/ERC4626.sol - - - -190->745 - - - - - -391 - -ERC20 -../node_modules/@openzeppelin/contracts/token/ERC20/ERC20.sol - - + -190->391 - - - - - -392 - -<<Interface>> -IERC20 -../node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol - - - -190->392 - - - - - -197->392 - - - - +1261->775 + + + + -268 - -<<Interface>> -IERC4626 -../lib/openzeppelin/interfaces/IERC4626.sol - - - -745->268 - - - - - -745->391 - - - - - -763 - -<<Interface>> -IERC20Metadata -../node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol - - - -745->763 - - - - - -268->392 - - - - - -268->763 - - - - - -391->392 - - - - - -391->763 - - - - - -319 - -<<Abstract>> -Context -../node_modules/@openzeppelin/contracts/utils/Context.sol - - - -391->319 - - - - - -763->392 - - +431 + +<<Abstract>> +Context +../node_modules/@openzeppelin/contracts/utils/Context.sol + + + +775->431 + + diff --git a/contracts/docs/WOETHSquashed.svg b/contracts/docs/WOETHSquashed.svg index 28524ff286..6a61807089 100644 --- a/contracts/docs/WOETHSquashed.svg +++ b/contracts/docs/WOETHSquashed.svg @@ -9,9 +9,9 @@ UmlClassDiagram - + -190 +249 WOETH ../contracts/token/WOETH.sol diff --git a/contracts/docs/WOETHStorage.svg b/contracts/docs/WOETHStorage.svg index 7704f5a839..17ed7ae11c 100644 --- a/contracts/docs/WOETHStorage.svg +++ b/contracts/docs/WOETHStorage.svg @@ -4,88 +4,52 @@ - - + + StorageDiagram - - - -2 - -WOETH <<Contract>> - -slot - -0 - -1 - -2 - -3 - -4 - -5 - -6-55 - -type: <inherited contract>.variable (bytes) - -mapping(address=>uint256): ERC20._balances (32) - -mapping(address=>mapping(address=>uint256)): ERC20._allowances (32) - -uint256: ERC20._totalSupply (32) - -string: ERC20._name (32) - -string: ERC20._symbol (32) - -unallocated (30) - -bool: Initializable.initializing (1) - -bool: Initializable.initialized (1) - -uint256[50]: Initializable.______gap (1600) - + - + 1 - -uint256[50]: ______gap <<Array>> - -slot - -6 - -7 - -8-53 - -54 - -55 - -type: variable (bytes) - -uint256 (32) - -uint256 (32) - ----- (1472) - -uint256 (32) - -uint256 (32) - - - -2:13->1 - - + +WOETH <<Contract>> + +slot + +0 + +1 + +2 + +3 + +4 + +5 + +6-55 + +type: <inherited contract>.variable (bytes) + +mapping(address=>uint256): ERC20._balances (32) + +mapping(address=>mapping(address=>uint256)): ERC20._allowances (32) + +uint256: ERC20._totalSupply (32) + +string: ERC20._name (32) + +string: ERC20._symbol (32) + +unallocated (30) + +bool: Initializable.initializing (1) + +bool: Initializable.initialized (1) + +uint256[50]: Initializable.______gap (1600) diff --git a/contracts/docs/WOSonicHierarchy.svg b/contracts/docs/WOSonicHierarchy.svg new file mode 100644 index 0000000000..f1ec28f3b5 --- /dev/null +++ b/contracts/docs/WOSonicHierarchy.svg @@ -0,0 +1,126 @@ + + + + + + +UmlClassDiagram + + + +21 + +Governable +../contracts/governance/Governable.sol + + + +244 + +OSonic +../contracts/token/OSonic.sol + + + +245 + +OUSD +../contracts/token/OUSD.sol + + + +244->245 + + + + + +245->21 + + + + + +251 + +WOSonic +../contracts/token/WOSonic.sol + + + +251->21 + + + + + +251->244 + + + + + +261 + +<<Abstract>> +Initializable +../contracts/utils/Initializable.sol + + + +251->261 + + + + + +1261 + +<<Abstract>> +ERC4626 +../lib/openzeppelin/contracts/token/ERC20/extensions/ERC4626.sol + + + +251->1261 + + + + + +775 + +ERC20 +../node_modules/@openzeppelin/contracts/token/ERC20/ERC20.sol + + + +251->775 + + + + + +1261->775 + + + + + +431 + +<<Abstract>> +Context +../node_modules/@openzeppelin/contracts/utils/Context.sol + + + +775->431 + + + + + diff --git a/contracts/docs/WOSonicSquashed.svg b/contracts/docs/WOSonicSquashed.svg new file mode 100644 index 0000000000..9221e145d3 --- /dev/null +++ b/contracts/docs/WOSonicSquashed.svg @@ -0,0 +1,101 @@ + + + + + + +UmlClassDiagram + + + +251 + +WOSonic +../contracts/token/WOSonic.sol + +Private: +   _balances: mapping(address=>uint256) <<ERC20>> +   _allowances: mapping(address=>mapping(address=>uint256)) <<ERC20>> +   _totalSupply: uint256 <<ERC20>> +   _name: string <<ERC20>> +   _symbol: string <<ERC20>> +   _asset: IERC20Metadata <<ERC4626>> +   governorPosition: bytes32 <<Governable>> +   pendingGovernorPosition: bytes32 <<Governable>> +   reentryStatusPosition: bytes32 <<Governable>> +   initialized: bool <<Initializable>> +   initializing: bool <<Initializable>> +   ______gap: uint256[50] <<Initializable>> +Public: +   _NOT_ENTERED: uint256 <<Governable>> +   _ENTERED: uint256 <<Governable>> + +Internal: +    _msgSender(): address <<Context>> +    _msgData(): bytes <<Context>> +    _transfer(sender: address, recipient: address, amount: uint256) <<ERC20>> +    _mint(account: address, amount: uint256) <<ERC20>> +    _burn(account: address, amount: uint256) <<ERC20>> +    _approve(owner: address, spender: address, amount: uint256) <<ERC20>> +    _beforeTokenTransfer(from: address, to: address, amount: uint256) <<ERC20>> +    _afterTokenTransfer(from: address, to: address, amount: uint256) <<ERC20>> +    _spendAllowance(owner: address, spender: address, amount: uint256) <<ERC4626>> +    _governor(): (governorOut: address) <<Governable>> +    _pendingGovernor(): (pendingGovernor: address) <<Governable>> +    _setGovernor(newGovernor: address) <<Governable>> +    _setPendingGovernor(newGovernor: address) <<Governable>> +    _changeGovernor(_newGovernor: address) <<Governable>> +External: +    transferGovernance(_newGovernor: address) <<onlyGovernor>> <<Governable>> +    claimGovernance() <<Governable>> +    initialize() <<onlyGovernor, initializer>> <<WOSonic>> +    transferToken(asset_: address, amount_: uint256) <<onlyGovernor>> <<WOSonic>> +Public: +    <<event>> Transfer(from: address, to: address, value: uint256) <<IERC20>> +    <<event>> Approval(owner: address, spender: address, value: uint256) <<IERC20>> +    <<event>> Deposit(caller: address, owner: address, assets: uint256, shares: uint256) <<IERC4626>> +    <<event>> Withdraw(caller: address, receiver: address, owner: address, assets: uint256, shares: uint256) <<IERC4626>> +    <<event>> PendingGovernorshipTransfer(previousGovernor: address, newGovernor: address) <<Governable>> +    <<event>> GovernorshipTransferred(previousGovernor: address, newGovernor: address) <<Governable>> +    <<modifier>> onlyGovernor() <<Governable>> +    <<modifier>> nonReentrant() <<Governable>> +    <<modifier>> initializer() <<Initializable>> +    totalSupply(): uint256 <<ERC20>> +    balanceOf(account: address): uint256 <<ERC20>> +    transfer(recipient: address, amount: uint256): bool <<ERC20>> +    allowance(owner: address, spender: address): uint256 <<ERC20>> +    approve(spender: address, amount: uint256): bool <<ERC20>> +    transferFrom(sender: address, recipient: address, amount: uint256): bool <<ERC20>> +    name(): string <<WOSonic>> +    symbol(): string <<WOSonic>> +    decimals(): uint8 <<ERC20>> +    constructor(name_: string, symbol_: string) <<ERC20>> +    increaseAllowance(spender: address, addedValue: uint256): bool <<ERC20>> +    decreaseAllowance(spender: address, subtractedValue: uint256): bool <<ERC20>> +    asset(): address <<ERC4626>> +    totalAssets(): uint256 <<ERC4626>> +    convertToShares(assets: uint256): (shares: uint256) <<ERC4626>> +    convertToAssets(shares: uint256): (assets: uint256) <<ERC4626>> +    maxDeposit(address): uint256 <<ERC4626>> +    previewDeposit(assets: uint256): uint256 <<ERC4626>> +    deposit(assets: uint256, receiver: address): uint256 <<ERC4626>> +    maxMint(address): uint256 <<ERC4626>> +    previewMint(shares: uint256): uint256 <<ERC4626>> +    mint(shares: uint256, receiver: address): uint256 <<ERC4626>> +    maxWithdraw(owner: address): uint256 <<ERC4626>> +    previewWithdraw(assets: uint256): uint256 <<ERC4626>> +    withdraw(assets: uint256, receiver: address, owner: address): uint256 <<ERC4626>> +    maxRedeem(owner: address): uint256 <<ERC4626>> +    previewRedeem(shares: uint256): uint256 <<ERC4626>> +    redeem(shares: uint256, receiver: address, owner: address): uint256 <<ERC4626>> +    constructor(__asset: IERC20Metadata) <<ERC4626>> +    constructor() <<Governable>> +    governor(): address <<Governable>> +    isGovernor(): bool <<Governable>> +    constructor(underlying_: ERC20, name_: string, symbol_: string) <<WOSonic>> + + + diff --git a/contracts/docs/WOSonicStorage.svg b/contracts/docs/WOSonicStorage.svg new file mode 100644 index 0000000000..a71fbb10a8 --- /dev/null +++ b/contracts/docs/WOSonicStorage.svg @@ -0,0 +1,55 @@ + + + + + + +StorageDiagram + + + +1 + +WOSonic <<Contract>> + +slot + +0 + +1 + +2 + +3 + +4 + +5 + +6-55 + +type: <inherited contract>.variable (bytes) + +mapping(address=>uint256): ERC20._balances (32) + +mapping(address=>mapping(address=>uint256)): ERC20._allowances (32) + +uint256: ERC20._totalSupply (32) + +string: ERC20._name (32) + +string: ERC20._symbol (32) + +unallocated (30) + +bool: Initializable.initializing (1) + +bool: Initializable.initialized (1) + +uint256[50]: Initializable.______gap (1600) + + + diff --git a/contracts/docs/WOUSDHierarchy.svg b/contracts/docs/WOUSDHierarchy.svg index 9b7ccc207b..ab686b637b 100644 --- a/contracts/docs/WOUSDHierarchy.svg +++ b/contracts/docs/WOUSDHierarchy.svg @@ -4,208 +4,110 @@ - - + + UmlClassDiagram - - + + -20 - -Governable -../contracts/governance/Governable.sol +21 + +Governable +../contracts/governance/Governable.sol - + -186 - -OUSD -../contracts/token/OUSD.sol +245 + +OUSD +../contracts/token/OUSD.sol - + + +245->21 + + + + + +252 + +WrappedOusd +../contracts/token/WrappedOusd.sol + + -186->20 - - +252->21 + + + + + +252->245 + + - + -194 - -<<Abstract>> -Initializable -../contracts/utils/Initializable.sol +261 + +<<Abstract>> +Initializable +../contracts/utils/Initializable.sol - - -186->194 - - + + +252->261 + + - + -197 - -<<Abstract>> -InitializableERC20Detailed -../contracts/utils/InitializableERC20Detailed.sol +1261 + +<<Abstract>> +ERC4626 +../lib/openzeppelin/contracts/token/ERC20/extensions/ERC4626.sol - + -186->197 - - +252->1261 + + - - -191 - -WrappedOusd -../contracts/token/WrappedOusd.sol + + +775 + +ERC20 +../node_modules/@openzeppelin/contracts/token/ERC20/ERC20.sol - + -191->20 - - +252->775 + + - - -191->186 - - - - - -191->194 - - - - - -745 - -<<Abstract>> -ERC4626 -../lib/openzeppelin/contracts/token/ERC20/extensions/ERC4626.sol - - - -191->745 - - - - - -391 - -ERC20 -../node_modules/@openzeppelin/contracts/token/ERC20/ERC20.sol - - + -191->391 - - - - - -392 - -<<Interface>> -IERC20 -../node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol - - - -191->392 - - - - - -197->392 - - - - +1261->775 + + + + -268 - -<<Interface>> -IERC4626 -../lib/openzeppelin/interfaces/IERC4626.sol - - - -745->268 - - - - - -745->391 - - - - - -763 - -<<Interface>> -IERC20Metadata -../node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol - - - -745->763 - - - - - -268->392 - - - - - -268->763 - - - - - -391->392 - - - - - -391->763 - - - - - -319 - -<<Abstract>> -Context -../node_modules/@openzeppelin/contracts/utils/Context.sol - - - -391->319 - - - - - -763->392 - - +431 + +<<Abstract>> +Context +../node_modules/@openzeppelin/contracts/utils/Context.sol + + + +775->431 + + diff --git a/contracts/docs/WOUSDSquashed.svg b/contracts/docs/WOUSDSquashed.svg index f8f81d23cb..3b802a4b48 100644 --- a/contracts/docs/WOUSDSquashed.svg +++ b/contracts/docs/WOUSDSquashed.svg @@ -9,9 +9,9 @@ UmlClassDiagram - + -191 +252 WrappedOusd ../contracts/token/WrappedOusd.sol diff --git a/contracts/docs/WOUSDStorage.svg b/contracts/docs/WOUSDStorage.svg index d11d00caec..f4c345ca24 100644 --- a/contracts/docs/WOUSDStorage.svg +++ b/contracts/docs/WOUSDStorage.svg @@ -4,88 +4,52 @@ - - + + StorageDiagram - - - -2 - -WrappedOusd <<Contract>> - -slot - -0 - -1 - -2 - -3 - -4 - -5 - -6-55 - -type: <inherited contract>.variable (bytes) - -mapping(address=>uint256): ERC20._balances (32) - -mapping(address=>mapping(address=>uint256)): ERC20._allowances (32) - -uint256: ERC20._totalSupply (32) - -string: ERC20._name (32) - -string: ERC20._symbol (32) - -unallocated (30) - -bool: Initializable.initializing (1) - -bool: Initializable.initialized (1) - -uint256[50]: Initializable.______gap (1600) - + - + 1 - -uint256[50]: ______gap <<Array>> - -slot - -6 - -7 - -8-53 - -54 - -55 - -type: variable (bytes) - -uint256 (32) - -uint256 (32) - ----- (1472) - -uint256 (32) - -uint256 (32) - - - -2:13->1 - - + +WrappedOusd <<Contract>> + +slot + +0 + +1 + +2 + +3 + +4 + +5 + +6-55 + +type: <inherited contract>.variable (bytes) + +mapping(address=>uint256): ERC20._balances (32) + +mapping(address=>mapping(address=>uint256)): ERC20._allowances (32) + +uint256: ERC20._totalSupply (32) + +string: ERC20._name (32) + +string: ERC20._symbol (32) + +unallocated (30) + +bool: Initializable.initializing (1) + +bool: Initializable.initialized (1) + +uint256[50]: Initializable.______gap (1600) diff --git a/contracts/docs/generate.sh b/contracts/docs/generate.sh index 69e89d4f0c..77e5aef682 100644 --- a/contracts/docs/generate.sh +++ b/contracts/docs/generate.sh @@ -105,6 +105,11 @@ sol2uml .. -v -hv -hf -he -hs -hl -hi -b BalancerMetaPoolStrategy -o BalancerMet sol2uml .. -s -d 0 -b BalancerMetaPoolStrategy -o BalancerMetaPoolStrategySquashed.svg sol2uml storage .. -c BalancerMetaPoolStrategy -o BalancerMetaPoolStrategyStorage.svg --hideExpand ______gap,_reserved,__reserved,__reserved_baseAuraStrategy +# contracts/strategies/sonic +sol2uml .. -v -hv -hf -he -hs -hl -hi -b SonicStakingStrategy -o SonicStakingStrategyHierarchy.svg +sol2uml .. -s -d 0 -b SonicStakingStrategy -o SonicStakingStrategySquashed.svg +sol2uml storage .. -c SonicStakingStrategy -o SonicStakingStrategyStorage.svg --hideExpand __gap,______gap,_reserved + # contracts/swapper sol2uml .. -v -hv -hf -he -hs -hl -b Swapper1InchV5 -o Swapper1InchV5Hierarchy.svg sol2uml .. -s -d 0 -b Swapper1InchV5 -o Swapper1InchV5Squashed.svg @@ -116,29 +121,39 @@ sol2uml .. -s -d 0 -b Timelock -o TimelockSquashed.svg sol2uml storage .. -c Timelock -o TimelockStorage.svg # contracts/token -sol2uml .. -v -hv -hf -he -hs -hl -b OUSD -o OUSDHierarchy.svg +sol2uml .. -v -hv -hf -he -hs -hl -hi -b OUSD -o OUSDHierarchy.svg sol2uml .. -s -d 0 -b OUSD -o OUSDSquashed.svg -sol2uml storage .. -c OUSD -o OUSDStorage.svg --hideExpand _gap +sol2uml storage .. -c OUSD -o OUSDStorage.svg --hideExpand _gap,__gap -sol2uml .. -v -hv -hf -he -hs -hl -b WrappedOusd -o WOUSDHierarchy.svg +sol2uml .. -v -hv -hf -he -hs -hl -hi -b WrappedOusd -o WOUSDHierarchy.svg sol2uml .. -s -d 0 -b WrappedOusd -o WOUSDSquashed.svg -sol2uml storage .. -c WrappedOusd -o WOUSDStorage.svg +sol2uml storage .. -c WrappedOusd -o WOUSDStorage.svg --hideExpand ______gap sol2uml .. -v -hv -hf -he -hs -hl -b OETH -o OETHHierarchy.svg sol2uml .. -s -d 0 -b OETH -o OETHSquashed.svg -sol2uml storage .. -c OETH -o OETHStorage.svg --hideExpand _____gap,______gap +sol2uml storage .. -c OETH -o OETHStorage.svg --hideExpand _gap,__gap -sol2uml .. -v -hv -hf -he -hs -hl -b WOETH -o WOETHHierarchy.svg +sol2uml .. -v -hv -hf -he -hs -hl -hi -b WOETH -o WOETHHierarchy.svg sol2uml .. -s -d 0 -b WOETH -o WOETHSquashed.svg -sol2uml storage .. -c WOETH -o WOETHStorage.svg +sol2uml storage .. -c WOETH -o WOETHStorage.svg --hideExpand ______gap -sol2uml .. -v -hv -hf -he -hs -hl -b OETHBase -o OETHBaseHierarchy.svg +# Base tokens +sol2uml .. -v -hv -hf -he -hs -hl -hi -b OETHBase -o OETHBaseHierarchy.svg sol2uml .. -s -d 0 -b OETHBase -o OETHBaseSquashed.svg -sol2uml storage .. -c OETHBase -o OETHBaseStorage.svg --hideExpand _____gap,______gap +sol2uml storage .. -c OETHBase -o OETHBaseStorage.svg --hideExpand _gap,__gap -sol2uml .. -v -hv -hf -he -hs -hl -b WOETHBase -o WOETHBaseHierarchy.svg +sol2uml .. -v -hv -hf -he -hs -hl -hi -b WOETHBase -o WOETHBaseHierarchy.svg sol2uml .. -s -d 0 -b WOETHBase -o WOETHBaseSquashed.svg -sol2uml storage .. -c WOETHBase -o WOETHBaseStorage.svg --hideExpand _____gap,______gap +sol2uml storage .. -c WOETHBase -o WOETHBaseStorage.svg --hideExpand ______gap + +# Sonic tokens +sol2uml .. -v -hv -hf -he -hs -hl -hi -b OSonic -o OSonicHierarchy.svg +sol2uml .. -s -d 0 -b OSonic -o OSonicSquashed.svg +sol2uml storage .. -c OSonic -o OSonicStorage.svg --hideExpand _gap,__gap + +sol2uml .. -v -hv -hf -he -hs -hl -hi -b WOSonic -o WOSonicHierarchy.svg +sol2uml .. -s -d 0 -b WOSonic -o WOSonicSquashed.svg +sol2uml storage .. -c WOSonic -o WOSonicStorage.svg --hideExpand ______gap # contracts/vault sol2uml .. -v -hv -hf -he -hs -hl -hi -b VaultCore,VaultAdmin -o VaultHierarchy.svg @@ -151,6 +166,11 @@ sol2uml .. -s -d 0 -b OETHVaultCore -o OETHVaultCoreSquashed.svg sol2uml .. -s -d 0 -b OETHVaultAdmin -o OETHVaultAdminSquashed.svg sol2uml storage .. -c OETHVaultCore -o OETHVaultStorage.svg --hideExpand __gap,______gap,_deprecated_swapTokens +sol2uml .. -v -hv -hf -he -hs -hl -hi -b OSonicVaultCore,OSonicVaultAdmin -o OSonicVaultHierarchy.svg +sol2uml .. -s -d 0 -b OSonicVaultCore -o OSonicVaultCoreSquashed.svg +sol2uml .. -s -d 0 -b OSonicVaultAdmin -o OSonicVaultAdminSquashed.svg +sol2uml storage .. -c OSonicVaultCore -o OSonicVaultStorage.svg --hideExpand __gap,______gap,_deprecated_swapTokens + # contracts/utils sol2uml .. -v -hv -hf -he -hs -hl -b InitializableAbstractStrategy -o InitializableAbstractStrategyHierarchy.svg sol2uml .. -s -d 0 -b InitializableAbstractStrategy -o InitializableAbstractStrategySquashed.svg From 929ec254ad0e042c07ab72ecac9862ad131b22a6 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Fri, 10 Jan 2025 15:01:47 +1100 Subject: [PATCH 267/273] Added Sonic fork tests for Zapper --- contracts/test/_fixture-sonic.js | 29 ++-- .../zapper/osonic-zapper.sonic.fork-test.js | 138 ++++++++++++++++++ 2 files changed, 151 insertions(+), 16 deletions(-) create mode 100644 contracts/test/zapper/osonic-zapper.sonic.fork-test.js diff --git a/contracts/test/_fixture-sonic.js b/contracts/test/_fixture-sonic.js index cc52290548..c9e20426ed 100644 --- a/contracts/test/_fixture-sonic.js +++ b/contracts/test/_fixture-sonic.js @@ -76,22 +76,17 @@ const defaultSonicFixture = deployments.createFixture(async () => { const sfc = await ethers.getContractAt("ISFC", addresses.sonic.SFC); - // let dripper, harvester; - // if (isFork) { - // // Harvester - // const harvesterProxy = await ethers.getContract("OSonicHarvesterProxy"); - // harvester = await ethers.getContractAt( - // "OSonicHarvester", - // harvesterProxy.address - // ); - - // // Dripper - // const dripperProxy = await ethers.getContract("OSonicDripperProxy"); - // dripper = await ethers.getContractAt( - // "FixedRateDripper", - // dripperProxy.address - // ); - // } + let dripper, zapper; + if (isFork) { + // Dripper + const dripperProxy = await ethers.getContract("OSonicDripperProxy"); + dripper = await ethers.getContractAt( + "FixedRateDripper", + dripperProxy.address + ); + + zapper = await ethers.getContract("OSonicZapper"); + } // Sonic's wrapped S token let wS; @@ -153,6 +148,8 @@ const defaultSonicFixture = deployments.createFixture(async () => { // harvester, // dripper, sonicStakingStrategy, + dripper, + zapper, // Wrapped S wS, diff --git a/contracts/test/zapper/osonic-zapper.sonic.fork-test.js b/contracts/test/zapper/osonic-zapper.sonic.fork-test.js new file mode 100644 index 0000000000..afab451765 --- /dev/null +++ b/contracts/test/zapper/osonic-zapper.sonic.fork-test.js @@ -0,0 +1,138 @@ +const { createFixtureLoader } = require("../_fixture"); +const { defaultSonicFixture } = require("../_fixture-sonic"); +const { expect } = require("chai"); +const { oethUnits } = require("../helpers"); + +const baseFixture = createFixtureLoader(defaultSonicFixture); + +describe("ForkTest: Origin Sonic Zapper", function () { + let fixture; + beforeEach(async () => { + fixture = await baseFixture(); + }); + + it("Should mint Origin Sonic with S transfer", async () => { + const { clement, zapper, oSonic } = fixture; + + const supplyBefore = await oSonic.totalSupply(); + const balanceBefore = await hre.ethers.provider.getBalance(clement.address); + + // Transfer 1 S to the zapper + const tx = await clement.sendTransaction({ + value: oethUnits("1"), + to: zapper.address, + }); + + await expect(tx).to.emit(zapper, "Zap"); + + const supplyAfter = await oSonic.totalSupply(); + const balanceAfter = await hre.ethers.provider.getBalance(clement.address); + + expect(supplyAfter).to.approxEqualTolerance( + supplyBefore.add(oethUnits("1")), + 2 + ); + expect(balanceAfter).to.approxEqualTolerance( + balanceBefore.sub(oethUnits("1")), + 2 + ); + }); + + it("Should mint Origin Sonic with S using deposit", async () => { + const { clement, zapper, oSonic } = fixture; + + const supplyBefore = await oSonic.totalSupply(); + const balanceBefore = await hre.ethers.provider.getBalance(clement.address); + + const tx = await zapper.connect(clement).deposit({ + value: oethUnits("1"), + }); + + await expect(tx).to.emit(zapper, "Zap"); + + const supplyAfter = await oSonic.totalSupply(); + const balanceAfter = await hre.ethers.provider.getBalance(clement.address); + + expect(supplyAfter).to.approxEqualTolerance( + supplyBefore.add(oethUnits("1")), + 2 + ); + expect(balanceAfter).to.approxEqualTolerance( + balanceBefore.sub(oethUnits("1")), + 2 + ); + }); + + it("Should mint Wrapped Sonic with S", async () => { + const { clement, zapper, oSonic, wOSonic } = fixture; + + const supplyBefore = await oSonic.totalSupply(); + const ethBalanceBefore = await hre.ethers.provider.getBalance( + clement.address + ); + const wOSonicBalanceBefore = await wOSonic.balanceOf(clement.address); + + const expected = await wOSonic.previewDeposit(oethUnits("1")); + + const tx = await zapper.connect(clement).depositSForWrappedTokens("0", { + value: oethUnits("1"), + }); + + await expect(tx).to.emit(zapper, "Zap"); + + const supplyAfter = await oSonic.totalSupply(); + const ethBalanceAfter = await hre.ethers.provider.getBalance( + clement.address + ); + const wOSonicBalanceAfter = await wOSonic.balanceOf(clement.address); + + expect(supplyAfter).to.approxEqualTolerance( + supplyBefore.add(oethUnits("1")), + 2 + ); + expect(ethBalanceAfter).to.approxEqualTolerance( + ethBalanceBefore.sub(oethUnits("1")), + 2 + ); + expect(wOSonicBalanceAfter).to.approxEqualTolerance( + wOSonicBalanceBefore.add(expected), + 2 + ); + }); + + it("Should mint Wrapped Origin Sonic with Wrapped S", async () => { + const { clement, zapper, oSonic, wOSonic, wS } = fixture; + + await wS.connect(clement).deposit({ value: oethUnits("1") }); + await wS.connect(clement).approve(zapper.address, oethUnits("1")); + + const supplyBefore = await oSonic.totalSupply(); + const wSBalanceBefore = await wS.balanceOf(clement.address); + const wOSonicBalanceBefore = await wOSonic.balanceOf(clement.address); + + const expected = await wOSonic.previewDeposit(oethUnits("1")); + + const tx = await zapper + .connect(clement) + .depositWSForWrappedTokens(oethUnits("1"), "0"); + + await expect(tx).to.emit(zapper, "Zap"); + + const supplyAfter = await oSonic.totalSupply(); + const wSBalanceAfter = await wS.balanceOf(clement.address); + const wOSonicBalanceAfter = await wOSonic.balanceOf(clement.address); + + expect(supplyAfter).to.approxEqualTolerance( + supplyBefore.add(oethUnits("1")), + 2 + ); + expect(wSBalanceAfter).to.approxEqualTolerance( + wSBalanceBefore.sub(oethUnits("1")), + 2 + ); + expect(wOSonicBalanceAfter).to.approxEqualTolerance( + wOSonicBalanceBefore.add(expected), + 2 + ); + }); +}); From e4ea827363e2c13750aa7a5b6a3178ceb1c5e93b Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Fri, 10 Jan 2025 18:29:00 +1100 Subject: [PATCH 268/273] Reduced depositedWSAccountedFor when delegating or withdrawing from the Sonic Staking Strategy --- .../strategies/sonic/SonicStakingStrategy.sol | 27 ++++++++++++++++--- .../sonic/SonicValidatorDelegator.sol | 11 ++++++++ 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/contracts/contracts/strategies/sonic/SonicStakingStrategy.sol b/contracts/contracts/strategies/sonic/SonicStakingStrategy.sol index 964eacb045..b4ae1afb51 100644 --- a/contracts/contracts/strategies/sonic/SonicStakingStrategy.sol +++ b/contracts/contracts/strategies/sonic/SonicStakingStrategy.sol @@ -1,6 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; +import { Math } from "@openzeppelin/contracts/utils/math/Math.sol"; import { IERC20, InitializableAbstractStrategy } from "../../utils/InitializableAbstractStrategy.sol"; import { SonicValidatorDelegator } from "./SonicValidatorDelegator.sol"; @@ -10,7 +11,7 @@ import { SonicValidatorDelegator } from "./SonicValidatorDelegator.sol"; */ contract SonicStakingStrategy is SonicValidatorDelegator { /// @dev This contract receives Wrapped S (wS) as the deposit asset, but unlike other strategies doesn't immediately - /// deposit it to an underlying platform. Rather a special privilege account stakes it to the validators. + /// deposit it to an underlying platform. Rather a special privilege account delegates it to the validators. /// For that reason calling wrappedSonic.balanceOf(this) in a deposit function can contain wS that has just been /// deposited and also wS that has previously been deposited. To keep a correct count we need to keep track /// of wS that has already been accounted for. @@ -60,7 +61,7 @@ contract SonicStakingStrategy is SonicValidatorDelegator { /// @notice Unlike other strategies, this does not deposit assets into the underlying platform. /// It just emits the Deposit event. - /// To deposit WETH into validators `registerSsvValidator` and `stakeEth` must be used. + /// To deposit native S into Sonic validators, `delegate` must be used. /// Will NOT revert if the strategy is paused from an accounting failure. function depositAll() external virtual override onlyVault nonReentrant { uint256 wSBalance = IERC20(wrappedSonic).balanceOf(address(this)); @@ -99,12 +100,12 @@ contract SonicStakingStrategy is SonicValidatorDelegator { require(_amount > 0, "Must withdraw something"); require(_recipient != address(0), "Must specify recipient"); - emit Withdrawal(wrappedSonic, address(0), _amount); + _wSWithdrawn(_amount); // slither-disable-next-line unchecked-transfer unused-return IERC20(_asset).transfer(_recipient, _amount); - emit Withdrawal(_asset, address(0), _amount); + emit Withdrawal(wrappedSonic, address(0), _amount); } /// @notice transfer all Wrapped Sonic (wS) deposits back to the vault. @@ -117,6 +118,22 @@ contract SonicStakingStrategy is SonicValidatorDelegator { } } + /// @dev Called when Wrapped S (wS) is withdrawn from the strategy or delegated to a validator so + /// the strategy knows how much wS it has on deposit. + /// This is so it can emit the correct amount in the Deposit event in depositAll(). + function _wSWithdrawn(uint256 _amount) internal override { + /* In an ideal world we wouldn't need to reduce the deduction amount when the + * depositedWSAccountedFor is smaller than the _amount. + * + * The reason this is required is that a malicious actor could sent Wrapped S directly + * to this contract and that would circumvent the increase of depositedWSAccountedFor + * property. When the S would be staked the depositedWSAccountedFor amount could + * be deducted so much that it would be negative. + */ + uint256 deductAmount = Math.min(_amount, depositedWSAccountedFor); + depositedWSAccountedFor -= deductAmount; + } + /** * @dev Returns bool indicating whether asset is supported by strategy * @param _asset Address of the asset @@ -144,6 +161,7 @@ contract SonicStakingStrategy is SonicValidatorDelegator { revert("unsupported function"); } + /// @notice is not used by this strategy as all staking rewards are restaked function collectRewardTokens() external override nonReentrant { revert("unsupported function"); } @@ -158,5 +176,6 @@ contract SonicStakingStrategy is SonicValidatorDelegator { function _abstractSetPToken(address, address) internal virtual override {} + /// @notice is not used by this strategy function safeApproveAllTokens() external override onlyGovernor {} } diff --git a/contracts/contracts/strategies/sonic/SonicValidatorDelegator.sol b/contracts/contracts/strategies/sonic/SonicValidatorDelegator.sol index d51f06bb86..811fac6893 100644 --- a/contracts/contracts/strategies/sonic/SonicValidatorDelegator.sol +++ b/contracts/contracts/strategies/sonic/SonicValidatorDelegator.sol @@ -141,6 +141,8 @@ abstract contract SonicValidatorDelegator is InitializableAbstractStrategy { // unwrap Wrapped Sonic (wS) to native Sonic (S) IWrappedSonic(wrappedSonic).withdraw(amount); + _wSWithdrawn(amount); + ISFC(sfc).delegate{ value: amount }(validatorId); emit Delegated(validatorId, amount); @@ -317,4 +319,13 @@ abstract contract SonicValidatorDelegator is InitializableAbstractStrategy { } return false; } + + /*************************************** + Abstract + ****************************************/ + + /// @dev Called when Wrapped S (wS) is withdrawn from the strategy or delegated to a validator so + /// the strategy knows how much wS it has on deposit. + /// This is so it can emit the correct amount in the Deposit event in depositAll(). + function _wSWithdrawn(uint256 _amount) internal virtual; } From 5e541b2894bafd49e166ae7a0664c9d4ccc3e3df Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Fri, 10 Jan 2025 18:31:10 +1100 Subject: [PATCH 269/273] Generated latest SonicStakingStrategy --- .../docs/SonicStakingStrategySquashed.svg | 103 +++++++++--------- 1 file changed, 52 insertions(+), 51 deletions(-) diff --git a/contracts/docs/SonicStakingStrategySquashed.svg b/contracts/docs/SonicStakingStrategySquashed.svg index b989602dd1..3eb488115c 100644 --- a/contracts/docs/SonicStakingStrategySquashed.svg +++ b/contracts/docs/SonicStakingStrategySquashed.svg @@ -4,61 +4,62 @@ - - + + UmlClassDiagram - + 373 - -SonicStakingStrategy -../contracts/strategies/sonic/SonicStakingStrategy.sol - -Private: -   initialized: bool <<Initializable>> -   initializing: bool <<Initializable>> -   ______gap: uint256[50] <<Initializable>> -   governorPosition: bytes32 <<Governable>> -   pendingGovernorPosition: bytes32 <<Governable>> -   reentryStatusPosition: bytes32 <<Governable>> -   _deprecated_platformAddress: address <<InitializableAbstractStrategy>> -   _deprecated_vaultAddress: address <<InitializableAbstractStrategy>> -   _deprecated_rewardTokenAddress: address <<InitializableAbstractStrategy>> -   _deprecated_rewardLiquidationThreshold: uint256 <<InitializableAbstractStrategy>> -   _reserved: int256[98] <<InitializableAbstractStrategy>> -   __gap: uint256[45] <<SonicValidatorDelegator>> -   __gap: uint256[49] <<SonicStakingStrategy>> -Internal: -   assetsMapped: address[] <<InitializableAbstractStrategy>> -Public: -   _NOT_ENTERED: uint256 <<Governable>> -   _ENTERED: uint256 <<Governable>> -   platformAddress: address <<InitializableAbstractStrategy>> -   vaultAddress: address <<InitializableAbstractStrategy>> -   assetToPToken: mapping(address=>address) <<InitializableAbstractStrategy>> -   harvesterAddress: address <<InitializableAbstractStrategy>> -   rewardTokenAddresses: address[] <<InitializableAbstractStrategy>> -   wrappedSonic: address <<SonicValidatorDelegator>> -   sfc: address <<SonicValidatorDelegator>> -   nextWithdrawId: uint256 <<SonicValidatorDelegator>> -   pendingWithdrawals: uint256 <<SonicValidatorDelegator>> -   supportedValidators: uint256[] <<SonicValidatorDelegator>> -   withdrawals: mapping(uint256=>WithdrawRequest) <<SonicValidatorDelegator>> -   validatorRegistrator: address <<SonicValidatorDelegator>> -   depositedWSAccountedFor: uint256 <<SonicStakingStrategy>> - -Internal: -    _governor(): (governorOut: address) <<Governable>> -    _pendingGovernor(): (pendingGovernor: address) <<Governable>> -    _setGovernor(newGovernor: address) <<Governable>> -    _setPendingGovernor(newGovernor: address) <<Governable>> -    _changeGovernor(_newGovernor: address) <<Governable>> -    _initialize(_rewardTokenAddresses: address[], _assets: address[], _pTokens: address[]) <<InitializableAbstractStrategy>> -    _collectRewardTokens() <<InitializableAbstractStrategy>> -    _setPTokenAddress(_asset: address, _pToken: address) <<InitializableAbstractStrategy>> -    _abstractSetPToken(address, address) <<SonicStakingStrategy>> + +SonicStakingStrategy +../contracts/strategies/sonic/SonicStakingStrategy.sol + +Private: +   initialized: bool <<Initializable>> +   initializing: bool <<Initializable>> +   ______gap: uint256[50] <<Initializable>> +   governorPosition: bytes32 <<Governable>> +   pendingGovernorPosition: bytes32 <<Governable>> +   reentryStatusPosition: bytes32 <<Governable>> +   _deprecated_platformAddress: address <<InitializableAbstractStrategy>> +   _deprecated_vaultAddress: address <<InitializableAbstractStrategy>> +   _deprecated_rewardTokenAddress: address <<InitializableAbstractStrategy>> +   _deprecated_rewardLiquidationThreshold: uint256 <<InitializableAbstractStrategy>> +   _reserved: int256[98] <<InitializableAbstractStrategy>> +   __gap: uint256[45] <<SonicValidatorDelegator>> +   __gap: uint256[49] <<SonicStakingStrategy>> +Internal: +   assetsMapped: address[] <<InitializableAbstractStrategy>> +Public: +   _NOT_ENTERED: uint256 <<Governable>> +   _ENTERED: uint256 <<Governable>> +   platformAddress: address <<InitializableAbstractStrategy>> +   vaultAddress: address <<InitializableAbstractStrategy>> +   assetToPToken: mapping(address=>address) <<InitializableAbstractStrategy>> +   harvesterAddress: address <<InitializableAbstractStrategy>> +   rewardTokenAddresses: address[] <<InitializableAbstractStrategy>> +   wrappedSonic: address <<SonicValidatorDelegator>> +   sfc: address <<SonicValidatorDelegator>> +   nextWithdrawId: uint256 <<SonicValidatorDelegator>> +   pendingWithdrawals: uint256 <<SonicValidatorDelegator>> +   supportedValidators: uint256[] <<SonicValidatorDelegator>> +   withdrawals: mapping(uint256=>WithdrawRequest) <<SonicValidatorDelegator>> +   validatorRegistrator: address <<SonicValidatorDelegator>> +   depositedWSAccountedFor: uint256 <<SonicStakingStrategy>> + +Internal: +    _governor(): (governorOut: address) <<Governable>> +    _pendingGovernor(): (pendingGovernor: address) <<Governable>> +    _setGovernor(newGovernor: address) <<Governable>> +    _setPendingGovernor(newGovernor: address) <<Governable>> +    _changeGovernor(_newGovernor: address) <<Governable>> +    _initialize(_rewardTokenAddresses: address[], _assets: address[], _pTokens: address[]) <<InitializableAbstractStrategy>> +    _collectRewardTokens() <<InitializableAbstractStrategy>> +    _setPTokenAddress(_asset: address, _pToken: address) <<InitializableAbstractStrategy>> +    _abstractSetPToken(address, address) <<SonicStakingStrategy>> +    _wSWithdrawn(_amount: uint256) <<SonicStakingStrategy>>    _deposit(_asset: address, _amount: uint256) <<SonicStakingStrategy>>    _withdraw(_recipient: address, _asset: address, _amount: uint256) <<SonicStakingStrategy>> External: From fb3e84b5fd8161da46307ac2b60020944835b3c6 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Fri, 10 Jan 2025 18:53:31 +1100 Subject: [PATCH 270/273] Added Sonic Vault config to deploy script --- contracts/deploy/sonic/001_origin_sonic.js | 18 ++++++++++++++++++ contracts/utils/addresses.js | 5 +++++ 2 files changed, 23 insertions(+) diff --git a/contracts/deploy/sonic/001_origin_sonic.js b/contracts/deploy/sonic/001_origin_sonic.js index 7611f8d32a..61fa55e7c8 100644 --- a/contracts/deploy/sonic/001_origin_sonic.js +++ b/contracts/deploy/sonic/001_origin_sonic.js @@ -1,3 +1,4 @@ +const { parseEther } = require("ethers/lib/utils"); const { deployOnSonic } = require("../../utils/deploy-l2"); const { deployWithConfirmation, @@ -202,6 +203,23 @@ module.exports = deployOnSonic( cOSonicVault.connect(sGovernor).setDripper(cOSonicDripperProxy.address) ); + // Configure the Vault + await withConfirmation( + cOSonicVault.connect(sGovernor).setRebaseThreshold(parseEther("10")) // 10 OS + ); + // setAutoAllocateThreshold is not set + await withConfirmation( + cOSonicVault.connect(sGovernor).setMaxSupplyDiff(parseEther("1")) // 1 OS + ); + await withConfirmation( + cOSonicVault + .connect(sGovernor) + .setTrusteeAddress(addresses.sonic.guardian) + ); + await withConfirmation( + cOSonicVault.connect(sGovernor).setTrusteeFeeBps(2000) // 20% + ); + // Deploy the Zapper await deployWithConfirmation("OSonicZapper", [ cOSonic.address, diff --git a/contracts/utils/addresses.js b/contracts/utils/addresses.js index 3f18675d38..3b390458d3 100644 --- a/contracts/utils/addresses.js +++ b/contracts/utils/addresses.js @@ -344,6 +344,11 @@ addresses.sonic.nodeDriver = "0xd100a01e00000000000000000000000000000001"; addresses.sonic.nodeDriveAuth = "0xd100ae0000000000000000000000000000000000"; addresses.sonic.validatorRegistrator = "0x531B8D5eD6db72A56cF1238D4cE478E7cB7f2825"; +// 5/8 Multisig - formally known as the Governor but not to be confused with the Governor contract +addresses.sonic.admin = "0x4FF1b9D9ba8558F5EAfCec096318eA0d8b541971"; +// 2/8 Multisig - formally known as the Strategist +addresses.sonic.guardian = "0x28bce2eE5775B652D92bB7c2891A89F036619703"; +// addresses.sonic.timelock = ""; // Holesky addresses.holesky.WETH = "0x94373a4919B3240D86eA41593D5eBa789FEF3848"; From f42824c63f53a4addb1806fb1979da481830c2e7 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Fri, 10 Jan 2025 18:57:42 +1100 Subject: [PATCH 271/273] Added TODO in Sonic addresses --- contracts/utils/addresses.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/contracts/utils/addresses.js b/contracts/utils/addresses.js index 3b390458d3..28a3c16d71 100644 --- a/contracts/utils/addresses.js +++ b/contracts/utils/addresses.js @@ -345,8 +345,10 @@ addresses.sonic.nodeDriveAuth = "0xd100ae0000000000000000000000000000000000"; addresses.sonic.validatorRegistrator = "0x531B8D5eD6db72A56cF1238D4cE478E7cB7f2825"; // 5/8 Multisig - formally known as the Governor but not to be confused with the Governor contract +// TODO add when the Sonic Admin Safe has been created addresses.sonic.admin = "0x4FF1b9D9ba8558F5EAfCec096318eA0d8b541971"; // 2/8 Multisig - formally known as the Strategist +// TODO add when the Sonic Guardian Safe has been created addresses.sonic.guardian = "0x28bce2eE5775B652D92bB7c2891A89F036619703"; // addresses.sonic.timelock = ""; From 5a07769adba03036ddcbca8393dadeb3117e3005 Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Fri, 10 Jan 2025 20:48:17 +1100 Subject: [PATCH 272/273] Added Sonic Vault fork tests Added missing Vault config to Sonic deploy script Sonic Staking Strategy governor fixed in deploy script --- contracts/deploy/sonic/001_origin_sonic.js | 21 ++- contracts/hardhat.config.js | 4 +- contracts/test/_fixture-sonic.js | 26 +--- contracts/test/vault/vault.sonic.fork-test.js | 125 ++++++++++++++++++ contracts/utils/deploy-l2.js | 3 +- 5 files changed, 151 insertions(+), 28 deletions(-) create mode 100644 contracts/test/vault/vault.sonic.fork-test.js diff --git a/contracts/deploy/sonic/001_origin_sonic.js b/contracts/deploy/sonic/001_origin_sonic.js index 61fa55e7c8..18e49826a0 100644 --- a/contracts/deploy/sonic/001_origin_sonic.js +++ b/contracts/deploy/sonic/001_origin_sonic.js @@ -159,23 +159,30 @@ module.exports = deployOnSonic( cSonicStakingStrategyProxy .connect(sDeployer)["initialize(address,address,bytes)"]( dSonicStakingStrategy.address, - deployerAddr, + governorAddr, initSonicStakingStrategy ) ); console.log("Initialized SonicStakingStrategy proxy and implementation"); + await withConfirmation( + cOSonicVault + .connect(sGovernor) + .approveStrategy(cSonicStakingStrategy.address) + ); + console.log("Approved Sonic Staking Strategy on Vault"); + // verify validators here: https://explorer.soniclabs.com/staking for (const validatorId of [15, 16, 17, 18]) { await cSonicStakingStrategy - .connect(sDeployer) + .connect(sGovernor) .supportValidator(validatorId); } console.log("Added supported validators"); // Set Defender Relayer for Sonic validator controls await cSonicStakingStrategy - .connect(sDeployer) + .connect(sGovernor) .setRegistrator(addresses.sonic.validatorRegistrator); console.log("Set registrator"); @@ -211,6 +218,11 @@ module.exports = deployOnSonic( await withConfirmation( cOSonicVault.connect(sGovernor).setMaxSupplyDiff(parseEther("1")) // 1 OS ); + await withConfirmation( + cOSonicVault + .connect(sGovernor) + .setStrategistAddr(addresses.sonic.guardian) + ); await withConfirmation( cOSonicVault .connect(sGovernor) @@ -219,6 +231,7 @@ module.exports = deployOnSonic( await withConfirmation( cOSonicVault.connect(sGovernor).setTrusteeFeeBps(2000) // 20% ); + console.log("Configured Vault"); // Deploy the Zapper await deployWithConfirmation("OSonicZapper", [ @@ -235,7 +248,5 @@ module.exports = deployOnSonic( ]); const vaultValueChecker = await ethers.getContract("VaultValueChecker"); console.log("Deployed Vault Value Checker", vaultValueChecker.address); - - // TODO transfer governor to ? } ); diff --git a/contracts/hardhat.config.js b/contracts/hardhat.config.js index 2a3bb95870..37ebc9413a 100644 --- a/contracts/hardhat.config.js +++ b/contracts/hardhat.config.js @@ -56,8 +56,8 @@ const BASE_GOVERNOR = "0x92A19381444A001d62cE67BaFF066fA1111d7202"; const BASE_STRATEGIST = "0x28bce2eE5775B652D92bB7c2891A89F036619703"; const SONIC_DEPLOYER = MAINNET_DEPLOYER; // TODO: update Sonic Governor and strategist -const SONIC_GOVERNOR = MAINNET_DEPLOYER; -const SONIC_STRATEGIST = MAINNET_DEPLOYER; +const SONIC_GOVERNOR = "0x4FF1b9D9ba8558F5EAfCec096318eA0d8b541971"; +const SONIC_STRATEGIST = "0x28bce2eE5775B652D92bB7c2891A89F036619703"; const mnemonic = "replace hover unaware super where filter stone fine garlic address matrix basic"; diff --git a/contracts/test/_fixture-sonic.js b/contracts/test/_fixture-sonic.js index c9e20426ed..d0276f8925 100644 --- a/contracts/test/_fixture-sonic.js +++ b/contracts/test/_fixture-sonic.js @@ -100,35 +100,23 @@ const defaultSonicFixture = deployments.createFixture(async () => { const signers = await hre.ethers.getSigners(); const [minter, burner, rafael, nick, clement] = signers.slice(4); // Skip first 4 addresses to avoid conflict - const { governorAddr, strategistAddr, timelockAddr } = - await getNamedAccounts(); - // TODO: change the deployerAddr to the appropriate governor address - const governor = await ethers.getSigner(isFork ? deployerAddr : governorAddr); - await hhHelpers.setBalance(governorAddr, oethUnits("1")); // Fund governor with some ETH - - const guardian = await ethers.getSigner(governorAddr); - const timelock = await ethers.getContractAt( - "ITimelockController", - timelockAddr - ); - const oSonicVaultSigner = await impersonateAndFund(oSonicVault.address); + const { governorAddr, strategistAddr } = await getNamedAccounts(); + // Impersonate governor + const governor = await impersonateAndFund(governorAddr); + governor.address = governorAddr; // Impersonate strategist const strategist = await impersonateAndFund(strategistAddr); strategist.address = strategistAddr; + const oSonicVaultSigner = await impersonateAndFund(oSonicVault.address); + let validatorRegistrator; if (isFork) { validatorRegistrator = await impersonateAndFund( addresses.sonic.validatorRegistrator ); validatorRegistrator.address = addresses.sonic.validatorRegistrator; - - await impersonateAndFund(governor.address); - await impersonateAndFund(timelock.address); - - // configure Vault to not automatically deposit to strategy - await oSonicVault.connect(governor).setVaultBuffer(oethUnits("1")); } for (const user of [rafael, nick, clement]) { @@ -156,8 +144,6 @@ const defaultSonicFixture = deployments.createFixture(async () => { // Signers governor, - guardian, - timelock, strategist, minter, burner, diff --git a/contracts/test/vault/vault.sonic.fork-test.js b/contracts/test/vault/vault.sonic.fork-test.js new file mode 100644 index 0000000000..6d254b1c66 --- /dev/null +++ b/contracts/test/vault/vault.sonic.fork-test.js @@ -0,0 +1,125 @@ +const { expect } = require("chai"); +const { parseUnits } = require("ethers/lib/utils"); + +const addresses = require("../../utils/addresses"); +const { defaultSonicFixture } = require("./../_fixture-sonic"); +const { isCI } = require("./../helpers"); +const { impersonateAndFund } = require("../../utils/signers"); + +describe("ForkTest: Sonic Vault", function () { + this.timeout(0); + + // Retry up to 3 times on CI + this.retries(isCI ? 3 : 0); + + let fixture; + beforeEach(async () => { + fixture = await defaultSonicFixture(); + }); + + describe("View functions", () => { + // These tests use a transaction to call a view function so the gas usage can be reported. + it("Should get total value", async () => { + const { nick, oSonicVault } = fixture; + + const tx = await oSonicVault + .connect(nick) + .populateTransaction.totalValue(); + await nick.sendTransaction(tx); + }); + it("Should check asset balances", async () => { + const { wS, nick, oSonicVault } = fixture; + + const tx = await oSonicVault + .connect(nick) + .populateTransaction.checkBalance(wS.address); + await nick.sendTransaction(tx); + }); + }); + + describe("Admin", () => { + it("Should have the correct governor address set", async () => { + const { oSonicVault } = fixture; + expect(await oSonicVault.governor()).to.equal(addresses.sonic.admin); + }); + + it("Should have the correct strategist address set", async () => { + const { strategist, oSonicVault } = fixture; + expect(await oSonicVault.strategistAddr()).to.equal( + await strategist.getAddress() + ); + }); + + it("Should have supported assets", async () => { + const { oSonicVault } = fixture; + const assets = await oSonicVault.getAllAssets(); + expect(assets).to.have.length(1); + expect(assets).to.include(addresses.sonic.wS); + + expect(await oSonicVault.isSupportedAsset(addresses.sonic.wS)).to.be.true; + }); + }); + + describe("Rebase", () => { + it(`Shouldn't be paused`, async () => { + const { oSonicVault } = fixture; + expect(await oSonicVault.rebasePaused()).to.be.false; + }); + + it(`Should rebase`, async () => { + const { oSonicVault } = fixture; + await oSonicVault.rebase(); + }); + }); + + describe("Capital", () => { + it(`Shouldn't be paused`, async () => { + const { oSonicVault } = fixture; + expect(await oSonicVault.capitalPaused()).to.be.false; + }); + + it("Should allow to mint w/ Wrapped S (wS)", async () => { + const { oSonic, oSonicVault, nick, wS } = fixture; + const balancePreMint = await oSonic + .connect(nick) + .balanceOf(nick.getAddress()); + await oSonicVault.connect(nick).mint(wS.address, parseUnits("1000"), 0); + + const balancePostMint = await oSonic + .connect(nick) + .balanceOf(nick.getAddress()); + + const balanceDiff = balancePostMint.sub(balancePreMint); + expect(balanceDiff).to.approxEqualTolerance(parseUnits("1000"), 1); + }); + + it("should deposit to and withdraw from staking strategy", async () => { + const { oSonicVault, nick, wS, sonicStakingStrategy } = fixture; + await oSonicVault.connect(nick).mint(wS.address, parseUnits("1000"), 0); + const strategistSigner = await impersonateAndFund( + await oSonicVault.strategistAddr() + ); + + await oSonicVault + .connect(strategistSigner) + .depositToStrategy( + sonicStakingStrategy.address, + [wS.address], + [parseUnits("1000")] + ); + + await oSonicVault + .connect(strategistSigner) + .withdrawFromStrategy( + sonicStakingStrategy.address, + [wS.address], + [parseUnits("1000")] + ); + }); + + it("Should have vault buffer disabled", async () => { + const { oSonicVault } = fixture; + expect(await oSonicVault.vaultBuffer()).to.equal("0"); + }); + }); +}); diff --git a/contracts/utils/deploy-l2.js b/contracts/utils/deploy-l2.js index 4a142aaf3e..a1cfdf4568 100644 --- a/contracts/utils/deploy-l2.js +++ b/contracts/utils/deploy-l2.js @@ -219,8 +219,9 @@ function deployOnSonic(opts, fn) { }; if (isFork) { - const { deployerAddr } = await getNamedAccounts(); + const { deployerAddr, governorAddr } = await getNamedAccounts(); await impersonateAndFund(deployerAddr); + await impersonateAndFund(governorAddr); } await fn(tools); From 0b5aea3d30d993159c523a4d0ef18b8d9ae29032 Mon Sep 17 00:00:00 2001 From: Domen Grabec Date: Fri, 10 Jan 2025 12:14:34 +0100 Subject: [PATCH 273/273] remove the depositedWSAccountedFor --- .../strategies/sonic/SonicStakingStrategy.sol | 43 ++----------------- .../sonic/SonicValidatorDelegator.sol | 11 ----- 2 files changed, 4 insertions(+), 50 deletions(-) diff --git a/contracts/contracts/strategies/sonic/SonicStakingStrategy.sol b/contracts/contracts/strategies/sonic/SonicStakingStrategy.sol index b4ae1afb51..a83555e8f3 100644 --- a/contracts/contracts/strategies/sonic/SonicStakingStrategy.sol +++ b/contracts/contracts/strategies/sonic/SonicStakingStrategy.sol @@ -10,17 +10,8 @@ import { SonicValidatorDelegator } from "./SonicValidatorDelegator.sol"; * @author Origin Protocol Inc */ contract SonicStakingStrategy is SonicValidatorDelegator { - /// @dev This contract receives Wrapped S (wS) as the deposit asset, but unlike other strategies doesn't immediately - /// deposit it to an underlying platform. Rather a special privilege account delegates it to the validators. - /// For that reason calling wrappedSonic.balanceOf(this) in a deposit function can contain wS that has just been - /// deposited and also wS that has previously been deposited. To keep a correct count we need to keep track - /// of wS that has already been accounted for. - /// This value represents the amount of wS balance of this contract that has already been accounted for by the - /// deposit events. - uint256 public depositedWSAccountedFor; - // For future use - uint256[49] private __gap; + uint256[50] private __gap; constructor( BaseStrategyConfig memory _baseConfig, @@ -40,7 +31,6 @@ contract SonicStakingStrategy is SonicValidatorDelegator { nonReentrant { require(_asset == wrappedSonic, "Unsupported asset"); - depositedWSAccountedFor += _amount; _deposit(_asset, _amount); } @@ -58,19 +48,12 @@ contract SonicStakingStrategy is SonicValidatorDelegator { /** * @notice Deposit the entire balance of wrapped S in this strategy contract */ - - /// @notice Unlike other strategies, this does not deposit assets into the underlying platform. - /// It just emits the Deposit event. - /// To deposit native S into Sonic validators, `delegate` must be used. - /// Will NOT revert if the strategy is paused from an accounting failure. + /// @notice Deposits the WS asset into the underlying platform function depositAll() external virtual override onlyVault nonReentrant { uint256 wSBalance = IERC20(wrappedSonic).balanceOf(address(this)); - uint256 newWS = wSBalance - depositedWSAccountedFor; - - if (newWS > 0) { - depositedWSAccountedFor = wSBalance; - _deposit(wrappedSonic, newWS); + if (wSBalance > 0) { + _deposit(wrappedSonic, wSBalance); } } @@ -100,8 +83,6 @@ contract SonicStakingStrategy is SonicValidatorDelegator { require(_amount > 0, "Must withdraw something"); require(_recipient != address(0), "Must specify recipient"); - _wSWithdrawn(_amount); - // slither-disable-next-line unchecked-transfer unused-return IERC20(_asset).transfer(_recipient, _amount); @@ -118,22 +99,6 @@ contract SonicStakingStrategy is SonicValidatorDelegator { } } - /// @dev Called when Wrapped S (wS) is withdrawn from the strategy or delegated to a validator so - /// the strategy knows how much wS it has on deposit. - /// This is so it can emit the correct amount in the Deposit event in depositAll(). - function _wSWithdrawn(uint256 _amount) internal override { - /* In an ideal world we wouldn't need to reduce the deduction amount when the - * depositedWSAccountedFor is smaller than the _amount. - * - * The reason this is required is that a malicious actor could sent Wrapped S directly - * to this contract and that would circumvent the increase of depositedWSAccountedFor - * property. When the S would be staked the depositedWSAccountedFor amount could - * be deducted so much that it would be negative. - */ - uint256 deductAmount = Math.min(_amount, depositedWSAccountedFor); - depositedWSAccountedFor -= deductAmount; - } - /** * @dev Returns bool indicating whether asset is supported by strategy * @param _asset Address of the asset diff --git a/contracts/contracts/strategies/sonic/SonicValidatorDelegator.sol b/contracts/contracts/strategies/sonic/SonicValidatorDelegator.sol index 811fac6893..d51f06bb86 100644 --- a/contracts/contracts/strategies/sonic/SonicValidatorDelegator.sol +++ b/contracts/contracts/strategies/sonic/SonicValidatorDelegator.sol @@ -141,8 +141,6 @@ abstract contract SonicValidatorDelegator is InitializableAbstractStrategy { // unwrap Wrapped Sonic (wS) to native Sonic (S) IWrappedSonic(wrappedSonic).withdraw(amount); - _wSWithdrawn(amount); - ISFC(sfc).delegate{ value: amount }(validatorId); emit Delegated(validatorId, amount); @@ -319,13 +317,4 @@ abstract contract SonicValidatorDelegator is InitializableAbstractStrategy { } return false; } - - /*************************************** - Abstract - ****************************************/ - - /// @dev Called when Wrapped S (wS) is withdrawn from the strategy or delegated to a validator so - /// the strategy knows how much wS it has on deposit. - /// This is so it can emit the correct amount in the Deposit event in depositAll(). - function _wSWithdrawn(uint256 _amount) internal virtual; }

    y^|e{KYE|L8$FgQqAwDKicjR`E z9@U2>n-ovy3?r^6}RTr3?t7-oXmfX(?HUmDb|H2 zAUdaXbK}&DACG6ILEbgmYd`IGlQ;q(aw^En3rB^zKLJTKJTD91q0$m4yqQyOk2<&a z39_dh)iI_!-HzJP(lR<(T`s^!irHZxaI*G(kl@@}&0AI}h9>bEXR{51+U)1s%ilRp zEL%o0fIx|Sws*hgWB03-a2q;$K|~1i&w^q{WE{1%>NjsLv+K$j8y$@|$lf=aKlosO zHab)A!mX{2^=kNO^Tms9E%|#T9s8H`_A+CBqGe;MLES*rI!Wh|WuU$=b%6+>`qa8O zLwU!ld%MqHiK4j-Z1W{KSZ#a1cyYy~Z5MxXU~jYZ0efHnCr^44a;1#iztCt?Me1X0}E&SECD zjbZv5$qgPwfF{KI#Jgbyg;&kW`h8jMp-_*J)sLpfkG%8_jsOgvGsgglp6mS_6&;d2 zQ`8$fZzr6(0Bqk)gPy3~EBfbkfYiB!BrDbO##(!>R2g z*r0LoF(=h{tlxp#<{E&)k?9W4j^Gee-`lrfiso0S#MN_bA1w+AH~*`Ir2+uM+xRE`wO{8_zfu$5@+!F*Q&{50u69R|Q`F>&x%XEs^Op1Nr#7E*E%H+bj*D+yk4_B3UyOMQ@0#dm ze>p4AynNS&Ye$@_o^0OhEQJbU=ETu!bqOiKs&bBoqUNIso0aQPv^JT~)9!P<)5_$2 zK)i`Ki?U?ss7;zqjOyL#XiGm)XJ_a2&#l+WL@tIM#{)4vDwTCE5%^|gI@*;o1o*N@ z8aFpLhi`Roc)0i7!^`p#>1EC;WH-MIg^e!5YpgV+)^?ZP^69GC7C+HUa~Y?+Uqgw! zA1%8i0SZ!q;;|HNQ`yMax7?@NcQxHTw)I!|c?Tg|5U~o2ee%NOxp29m>D1G5+yxH= z3vRlv-B7Ov&%=4Azz*$_n=-;ZNYBecCz_5ZyJuEfiYO(H-4eQ1R>V|7>$`Gq=7pOa z!WG-}==Y}af!6T;2peS&y$Z)7$;$+=l|H-0_sl1GFi4fZcCCfRY@770jk`kzY+TO z?ti58m*aVxr&`{+J?Ip~D~YQ1^6;MPWyka8r&{&ceyecPpZ+%XX{}Hepdjq1$*&uE1ZEJJq>7Pxqy^zaqfJObeEcAh}8v)b??;^zQ2f4;V#A}k{l5VL9NA?I6LKhHOK7=HKLxkL85cUWk@R`-7k+zYvR z4lv$;S6}NVCr<)yGufBCPA5}(+NpEJ&wYb^Vt|dlpB2zX-<;s(*_nSYZR(N!zD8!# za)sFaM}J8GyTS7oFK+&`#c%E{;IP2O{bw>jF%B%tUh%UZKI8;EyuSX)3$w+FkzUV^ zoP6tVf7je(%iYuZ|399uue*5l>QRK}Uq+=(-e|M|IDVjST|a9t@TQIzTR1_xrnJtm z0FwY{R?`|dY*!-xZq|z_Ps4701U8`Z?&w_2xBUM0-sk_CTato+qXAoD{;hlRdUNH~ z&!+$F!ascO{U7&ew>JA1;eR3jE=`qep7Z>}#I;3E!0Jf$q--Q`l{Ih?cEVQnu$f2J z#GLjrabP0l+XkK+4Z|e literal 448529 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 &XY>WRi3H@L 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�~?Xd--50R~81Y)VQ>+VEF2 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

  • =ML50e37J{6NCsPTUA~ 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